Loading drivers/video/sh_mobile_hdmi.c +105 −59 Original line number Diff line number Diff line Loading @@ -209,7 +209,8 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; /* hot-plug status */ bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ u8 preprogrammed_vic; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; struct fb_info *info; Loading Loading @@ -342,7 +343,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ if (!hdmi->preprogrammed_mode) if (!hdmi->preprogrammed_vic) hdmi_write(hdmi, sync | 1 | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } Loading Loading @@ -466,7 +467,18 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { if (hdmi->var.yres > 480) { if (hdmi->var.pixclock < 10000) { /* for 1080p8bit 148MHz */ hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); } else if (hdmi->var.pixclock < 30000) { /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ /* * [1:0] Speed_A Loading Loading @@ -565,13 +577,11 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); /* * VIC = 1280 x 720p: ignored if external config is used * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode * VIC should be ignored if external config is used, so, we could just use 0, * but play safe and use a valid value in any case just in case */ if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) vic = 16; else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) vic = 2; if (hdmi->preprogrammed_vic) vic = hdmi->preprogrammed_vic; else vic = 4; hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); Loading Loading @@ -685,11 +695,21 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) } static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, const struct fb_videomode *mode) const struct fb_videomode *mode, unsigned long *hdmi_rate, unsigned long *parent_rate) { long target = PICOS2KHZ(mode->pixclock) * 1000, rate = clk_round_rate(hdmi->hdmi_clk, target); unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target); if ((long)*hdmi_rate < 0) *hdmi_rate = clk_get_rate(hdmi->hdmi_clk); rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX; if (rate_error && pdata->clk_optimize_parent) rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate); else if (clk_get_parent(hdmi->hdmi_clk)) *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk)); dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", mode->left_margin, mode->xres, Loading @@ -697,14 +717,15 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, mode->upper_margin, mode->yres, mode->lower_margin, mode->vsync_len); dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target, rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, mode->refresh); mode->refresh, *parent_rate); return rate_error; } static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, unsigned long *parent_rate) { struct fb_var_screeninfo tmpvar; struct fb_var_screeninfo *var = &tmpvar; Loading Loading @@ -754,11 +775,14 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) for (i = 0, mode = hdmi->monspec.modedb; f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; i++, mode++) { unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); unsigned long rate_error; /* No interest in unmatching modes */ if (f_width != mode->xres || f_height != mode->yres) continue; rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) /* * Exact match if either the refresh rate matches or it Loading Loading @@ -802,7 +826,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (modelist) { found = &modelist->mode; found_rate_error = sh_hdmi_rate_error(hdmi, found); found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate); } } Loading @@ -810,16 +834,27 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (!found) return -ENXIO; dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", modelist ? "default" : "EDID", found->xres, found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); if ((found->xres == 720 && found->yres == 480) || (found->xres == 1280 && found->yres == 720) || (found->xres == 1920 && found->yres == 1080)) hdmi->preprogrammed_mode = true; if (found->xres == 640 && found->yres == 480 && found->refresh == 60) hdmi->preprogrammed_vic = 1; else if (found->xres == 720 && found->yres == 480 && found->refresh == 60) hdmi->preprogrammed_vic = 2; else if (found->xres == 720 && found->yres == 576 && found->refresh == 50) hdmi->preprogrammed_vic = 17; else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60) hdmi->preprogrammed_vic = 4; else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24) hdmi->preprogrammed_vic = 32; else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50) hdmi->preprogrammed_vic = 31; else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60) hdmi->preprogrammed_vic = 16; else hdmi->preprogrammed_mode = false; hdmi->preprogrammed_vic = 0; dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external", found->xres, found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); fb_videomode_to_var(&hdmi->var, found); sh_hdmi_external_video_param(hdmi); Loading Loading @@ -973,38 +1008,36 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) /** * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock * @hdmi: driver context * @pixclock: pixel clock period in picoseconds * @hdmi_rate: HDMI clock frequency in Hz * @parent_rate: if != 0 - set parent clock rate for optimal precision * return: configured positive rate if successful * 0 if couldn't set the rate, but managed to enable the clock * negative error, if couldn't enable the clock * 0 if couldn't set the rate, but managed to enable the * clock, negative error, if couldn't enable the clock */ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, unsigned long parent_rate) { long rate; int ret; rate = PICOS2KHZ(pixclock) * 1000; rate = clk_round_rate(hdmi->hdmi_clk, rate); if (rate > 0) { ret = clk_set_rate(hdmi->hdmi_clk, rate); if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) { ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate); if (ret < 0) { dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); rate = 0; dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret); hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate); } else { dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate); } } else { rate = 0; dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); } ret = clk_enable(hdmi->hdmi_clk); ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate); if (ret < 0) { dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); return ret; dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret); hdmi_rate = 0; } else { dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate); } return rate; return hdmi_rate; } /* Hotplug interrupt occurred, read EDID */ Loading @@ -1024,16 +1057,17 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { unsigned long parent_rate = 0, hdmi_rate; /* A device has been plugged in */ pm_runtime_get_sync(hdmi->dev); ret = sh_hdmi_read_edid(hdmi); ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); if (ret < 0) goto out; /* Reconfigure the clock */ clk_disable(hdmi->hdmi_clk); ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); if (ret < 0) goto out; Loading Loading @@ -1071,6 +1105,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) if (!hdmi->info) goto out; hdmi->monspec.modedb_len = 0; fb_destroy_modedb(hdmi->monspec.modedb); hdmi->monspec.modedb = NULL; acquire_console_sem(); /* HDMI disconnect */ Loading @@ -1078,7 +1116,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) release_console_sem(); pm_runtime_put(hdmi->dev); fb_destroy_modedb(hdmi->monspec.modedb); } out: Loading Loading @@ -1163,13 +1200,22 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } /* Some arbitrary relaxed pixclock just to get things started */ rate = sh_hdmi_clk_configure(hdmi, 37037); /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); if (rate > 0) rate = sh_hdmi_clk_configure(hdmi, rate, 0); if (rate < 0) { ret = rate; goto erate; } ret = clk_enable(hdmi->hdmi_clk); if (ret < 0) { dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); goto erate; } dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { Loading @@ -1187,10 +1233,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); /* Set up LCDC callbacks */ board_cfg = &pdata->lcd_chan->board_cfg; board_cfg->owner = THIS_MODULE; Loading @@ -1203,6 +1245,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); ret = request_irq(irq, sh_hdmi_hotplug, 0, dev_name(&pdev->dev), hdmi); if (ret < 0) { Loading drivers/video/sh_mobile_lcdcfb.c +20 −27 Original line number Diff line number Diff line Loading @@ -54,8 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) #define DEFAULT_XRES 1280 #define DEFAULT_YRES 1024 #define MAX_XRES 1920 #define MAX_YRES 1080 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, Loading Loading @@ -115,15 +115,16 @@ static const struct fb_videomode default_720p = { .xres = 1280, .yres = 720, .left_margin = 200, .right_margin = 88, .hsync_len = 48, .left_margin = 220, .right_margin = 110, .hsync_len = 40, .upper_margin = 20, .lower_margin = 5, .vsync_len = 5, .pixclock = 13468, .refresh = 60, .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, }; Loading Loading @@ -913,22 +914,12 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in { struct sh_mobile_lcdc_chan *ch = info->par; if (var->xres < 160 || var->xres > 1920 || var->yres < 120 || var->yres > 1080 || var->left_margin < 32 || var->left_margin > 320 || var->right_margin < 12 || var->right_margin > 240 || var->upper_margin < 12 || var->upper_margin > 120 || var->lower_margin < 1 || var->lower_margin > 64 || var->hsync_len < 32 || var->hsync_len > 240 || var->vsync_len < 2 || var->vsync_len > 64 || var->pixclock < 6000 || var->pixclock > 40000 || if (var->xres > MAX_XRES || var->yres > MAX_YRES || var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", var->xres, var->yres, var->left_margin, var->right_margin, var->upper_margin, var->lower_margin, var->hsync_len, var->vsync_len, var->pixclock); dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n", var->left_margin, var->xres, var->right_margin, var->hsync_len, var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); return -EINVAL; } return 0; Loading Loading @@ -1197,6 +1188,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) const struct fb_videomode *mode = cfg->lcd_cfg; unsigned long max_size = 0; int k; int num_cfg; ch->info = framebuffer_alloc(0, &pdev->dev); if (!ch->info) { Loading Loading @@ -1224,7 +1216,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } if (!mode) max_size = DEFAULT_XRES * DEFAULT_YRES; max_size = MAX_XRES * MAX_YRES; else if (max_cfg) dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", max_cfg->xres, max_cfg->yres); Loading @@ -1232,8 +1224,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) info->fix = sh_mobile_lcdc_fix; info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; if (!mode) if (!mode) { mode = &default_720p; num_cfg = 1; } else { num_cfg = ch->cfg.num_cfg; } fb_videomode_to_modelist(mode, num_cfg, &info->modelist); fb_videomode_to_var(var, mode); /* Default Y virtual resolution is 2x panel size */ Loading Loading @@ -1281,10 +1279,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct sh_mobile_lcdc_chan *ch = priv->ch + i; const struct fb_videomode *mode = ch->cfg.lcd_cfg; if (!mode) mode = &default_720p; info = ch->info; Loading @@ -1297,7 +1291,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } } fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist); error = register_framebuffer(info); if (error < 0) goto err1; Loading include/video/sh_mobile_hdmi.h +3 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ struct sh_mobile_lcdc_chan_cfg; struct device; struct clk; /* * flags format Loading @@ -33,6 +34,8 @@ struct sh_mobile_hdmi_info { struct sh_mobile_lcdc_chan_cfg *lcd_chan; struct device *lcd_dev; unsigned int flags; long (*clk_optimize_parent)(unsigned long target, unsigned long *best_freq, unsigned long *parent_freq); }; #endif Loading
drivers/video/sh_mobile_hdmi.c +105 −59 Original line number Diff line number Diff line Loading @@ -209,7 +209,8 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; /* hot-plug status */ bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ u8 preprogrammed_vic; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; struct fb_info *info; Loading Loading @@ -342,7 +343,7 @@ static void sh_hdmi_external_video_param(struct sh_hdmi *hdmi) hdmi_write(hdmi, var->vsync_len, HDMI_EXTERNAL_V_DURATION); /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ if (!hdmi->preprogrammed_mode) if (!hdmi->preprogrammed_vic) hdmi_write(hdmi, sync | 1 | (voffset << 4), HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } Loading Loading @@ -466,7 +467,18 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { if (hdmi->var.yres > 480) { if (hdmi->var.pixclock < 10000) { /* for 1080p8bit 148MHz */ hdmi_write(hdmi, 0x1d, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); hdmi_write(hdmi, 0x4c, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); hdmi_write(hdmi, 0x1e, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); hdmi_write(hdmi, 0x0e, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); } else if (hdmi->var.pixclock < 30000) { /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ /* * [1:0] Speed_A Loading Loading @@ -565,13 +577,11 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB3); /* * VIC = 1280 x 720p: ignored if external config is used * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode * VIC should be ignored if external config is used, so, we could just use 0, * but play safe and use a valid value in any case just in case */ if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) vic = 16; else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) vic = 2; if (hdmi->preprogrammed_vic) vic = hdmi->preprogrammed_vic; else vic = 4; hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); Loading Loading @@ -685,11 +695,21 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) } static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, const struct fb_videomode *mode) const struct fb_videomode *mode, unsigned long *hdmi_rate, unsigned long *parent_rate) { long target = PICOS2KHZ(mode->pixclock) * 1000, rate = clk_round_rate(hdmi->hdmi_clk, target); unsigned long rate_error = rate > 0 ? abs(rate - target) : ULONG_MAX; unsigned long target = PICOS2KHZ(mode->pixclock) * 1000, rate_error; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; *hdmi_rate = clk_round_rate(hdmi->hdmi_clk, target); if ((long)*hdmi_rate < 0) *hdmi_rate = clk_get_rate(hdmi->hdmi_clk); rate_error = (long)*hdmi_rate > 0 ? abs(*hdmi_rate - target) : ULONG_MAX; if (rate_error && pdata->clk_optimize_parent) rate_error = pdata->clk_optimize_parent(target, hdmi_rate, parent_rate); else if (clk_get_parent(hdmi->hdmi_clk)) *parent_rate = clk_get_rate(clk_get_parent(hdmi->hdmi_clk)); dev_dbg(hdmi->dev, "%u-%u-%u-%u x %u-%u-%u-%u\n", mode->left_margin, mode->xres, Loading @@ -697,14 +717,15 @@ static unsigned long sh_hdmi_rate_error(struct sh_hdmi *hdmi, mode->upper_margin, mode->yres, mode->lower_margin, mode->vsync_len); dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz\n", target, dev_dbg(hdmi->dev, "\t@%lu(+/-%lu)Hz, e=%lu / 1000, r=%uHz, p=%luHz\n", target, rate_error, rate_error ? 10000 / (10 * target / rate_error) : 0, mode->refresh); mode->refresh, *parent_rate); return rate_error; } static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) static int sh_hdmi_read_edid(struct sh_hdmi *hdmi, unsigned long *hdmi_rate, unsigned long *parent_rate) { struct fb_var_screeninfo tmpvar; struct fb_var_screeninfo *var = &tmpvar; Loading Loading @@ -754,11 +775,14 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) for (i = 0, mode = hdmi->monspec.modedb; f_width && f_height && i < hdmi->monspec.modedb_len && !exact_match; i++, mode++) { unsigned long rate_error = sh_hdmi_rate_error(hdmi, mode); unsigned long rate_error; /* No interest in unmatching modes */ if (f_width != mode->xres || f_height != mode->yres) continue; rate_error = sh_hdmi_rate_error(hdmi, mode, hdmi_rate, parent_rate); if (f_refresh == mode->refresh || (!f_refresh && !rate_error)) /* * Exact match if either the refresh rate matches or it Loading Loading @@ -802,7 +826,7 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (modelist) { found = &modelist->mode; found_rate_error = sh_hdmi_rate_error(hdmi, found); found_rate_error = sh_hdmi_rate_error(hdmi, found, hdmi_rate, parent_rate); } } Loading @@ -810,16 +834,27 @@ static int sh_hdmi_read_edid(struct sh_hdmi *hdmi) if (!found) return -ENXIO; dev_info(hdmi->dev, "Using %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", modelist ? "default" : "EDID", found->xres, found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); if ((found->xres == 720 && found->yres == 480) || (found->xres == 1280 && found->yres == 720) || (found->xres == 1920 && found->yres == 1080)) hdmi->preprogrammed_mode = true; if (found->xres == 640 && found->yres == 480 && found->refresh == 60) hdmi->preprogrammed_vic = 1; else if (found->xres == 720 && found->yres == 480 && found->refresh == 60) hdmi->preprogrammed_vic = 2; else if (found->xres == 720 && found->yres == 576 && found->refresh == 50) hdmi->preprogrammed_vic = 17; else if (found->xres == 1280 && found->yres == 720 && found->refresh == 60) hdmi->preprogrammed_vic = 4; else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 24) hdmi->preprogrammed_vic = 32; else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 50) hdmi->preprogrammed_vic = 31; else if (found->xres == 1920 && found->yres == 1080 && found->refresh == 60) hdmi->preprogrammed_vic = 16; else hdmi->preprogrammed_mode = false; hdmi->preprogrammed_vic = 0; dev_dbg(hdmi->dev, "Using %s %s mode %ux%u@%uHz (%luHz), clock error %luHz\n", modelist ? "default" : "EDID", hdmi->preprogrammed_vic ? "VIC" : "external", found->xres, found->yres, found->refresh, PICOS2KHZ(found->pixclock) * 1000, found_rate_error); fb_videomode_to_var(&hdmi->var, found); sh_hdmi_external_video_param(hdmi); Loading Loading @@ -973,38 +1008,36 @@ static bool sh_hdmi_must_reconfigure(struct sh_hdmi *hdmi) /** * sh_hdmi_clk_configure() - set HDMI clock frequency and enable the clock * @hdmi: driver context * @pixclock: pixel clock period in picoseconds * @hdmi_rate: HDMI clock frequency in Hz * @parent_rate: if != 0 - set parent clock rate for optimal precision * return: configured positive rate if successful * 0 if couldn't set the rate, but managed to enable the clock * negative error, if couldn't enable the clock * 0 if couldn't set the rate, but managed to enable the * clock, negative error, if couldn't enable the clock */ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long pixclock) static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, unsigned long parent_rate) { long rate; int ret; rate = PICOS2KHZ(pixclock) * 1000; rate = clk_round_rate(hdmi->hdmi_clk, rate); if (rate > 0) { ret = clk_set_rate(hdmi->hdmi_clk, rate); if (parent_rate && clk_get_parent(hdmi->hdmi_clk)) { ret = clk_set_rate(clk_get_parent(hdmi->hdmi_clk), parent_rate); if (ret < 0) { dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", rate, ret); rate = 0; dev_warn(hdmi->dev, "Cannot set parent rate %ld: %d\n", parent_rate, ret); hdmi_rate = clk_round_rate(hdmi->hdmi_clk, hdmi_rate); } else { dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", rate); dev_dbg(hdmi->dev, "HDMI set parent frequency %lu\n", parent_rate); } } else { rate = 0; dev_warn(hdmi->dev, "Cannot get suitable rate: %ld\n", rate); } ret = clk_enable(hdmi->hdmi_clk); ret = clk_set_rate(hdmi->hdmi_clk, hdmi_rate); if (ret < 0) { dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); return ret; dev_warn(hdmi->dev, "Cannot set rate %ld: %d\n", hdmi_rate, ret); hdmi_rate = 0; } else { dev_dbg(hdmi->dev, "HDMI set frequency %lu\n", hdmi_rate); } return rate; return hdmi_rate; } /* Hotplug interrupt occurred, read EDID */ Loading @@ -1024,16 +1057,17 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) mutex_lock(&hdmi->mutex); if (hdmi->hp_state == HDMI_HOTPLUG_EDID_DONE) { unsigned long parent_rate = 0, hdmi_rate; /* A device has been plugged in */ pm_runtime_get_sync(hdmi->dev); ret = sh_hdmi_read_edid(hdmi); ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); if (ret < 0) goto out; /* Reconfigure the clock */ clk_disable(hdmi->hdmi_clk); ret = sh_hdmi_clk_configure(hdmi, hdmi->var.pixclock); ret = sh_hdmi_clk_configure(hdmi, hdmi_rate, parent_rate); if (ret < 0) goto out; Loading Loading @@ -1071,6 +1105,10 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) if (!hdmi->info) goto out; hdmi->monspec.modedb_len = 0; fb_destroy_modedb(hdmi->monspec.modedb); hdmi->monspec.modedb = NULL; acquire_console_sem(); /* HDMI disconnect */ Loading @@ -1078,7 +1116,6 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) release_console_sem(); pm_runtime_put(hdmi->dev); fb_destroy_modedb(hdmi->monspec.modedb); } out: Loading Loading @@ -1163,13 +1200,22 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } /* Some arbitrary relaxed pixclock just to get things started */ rate = sh_hdmi_clk_configure(hdmi, 37037); /* An arbitrary relaxed pixclock just to get things started: from standard 480p */ rate = clk_round_rate(hdmi->hdmi_clk, PICOS2KHZ(37037)); if (rate > 0) rate = sh_hdmi_clk_configure(hdmi, rate, 0); if (rate < 0) { ret = rate; goto erate; } ret = clk_enable(hdmi->hdmi_clk); if (ret < 0) { dev_err(hdmi->dev, "Cannot enable clock: %d\n", ret); goto erate; } dev_dbg(&pdev->dev, "Enabled HDMI clock at %luHz\n", rate); if (!request_mem_region(res->start, resource_size(res), dev_name(&pdev->dev))) { Loading @@ -1187,10 +1233,6 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) platform_set_drvdata(pdev, hdmi); /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); /* Set up LCDC callbacks */ board_cfg = &pdata->lcd_chan->board_cfg; board_cfg->owner = THIS_MODULE; Loading @@ -1203,6 +1245,10 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) pm_runtime_enable(&pdev->dev); pm_runtime_resume(&pdev->dev); /* Product and revision IDs are 0 in sh-mobile version */ dev_info(&pdev->dev, "Detected HDMI controller 0x%x:0x%x\n", hdmi_read(hdmi, HDMI_PRODUCT_ID), hdmi_read(hdmi, HDMI_REVISION_ID)); ret = request_irq(irq, sh_hdmi_hotplug, 0, dev_name(&pdev->dev), hdmi); if (ret < 0) { Loading
drivers/video/sh_mobile_lcdcfb.c +20 −27 Original line number Diff line number Diff line Loading @@ -54,8 +54,8 @@ static int lcdc_shared_regs[] = { }; #define NR_SHARED_REGS ARRAY_SIZE(lcdc_shared_regs) #define DEFAULT_XRES 1280 #define DEFAULT_YRES 1024 #define MAX_XRES 1920 #define MAX_YRES 1080 static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = { [LDDCKPAT1R] = 0x400, Loading Loading @@ -115,15 +115,16 @@ static const struct fb_videomode default_720p = { .xres = 1280, .yres = 720, .left_margin = 200, .right_margin = 88, .hsync_len = 48, .left_margin = 220, .right_margin = 110, .hsync_len = 40, .upper_margin = 20, .lower_margin = 5, .vsync_len = 5, .pixclock = 13468, .refresh = 60, .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, }; Loading Loading @@ -913,22 +914,12 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in { struct sh_mobile_lcdc_chan *ch = info->par; if (var->xres < 160 || var->xres > 1920 || var->yres < 120 || var->yres > 1080 || var->left_margin < 32 || var->left_margin > 320 || var->right_margin < 12 || var->right_margin > 240 || var->upper_margin < 12 || var->upper_margin > 120 || var->lower_margin < 1 || var->lower_margin > 64 || var->hsync_len < 32 || var->hsync_len > 240 || var->vsync_len < 2 || var->vsync_len > 64 || var->pixclock < 6000 || var->pixclock > 40000 || if (var->xres > MAX_XRES || var->yres > MAX_YRES || var->xres * var->yres * (ch->cfg.bpp / 8) * 2 > info->fix.smem_len) { dev_warn(info->dev, "Invalid info: %u %u %u %u %u %u %u %u %u!\n", var->xres, var->yres, var->left_margin, var->right_margin, var->upper_margin, var->lower_margin, var->hsync_len, var->vsync_len, var->pixclock); dev_warn(info->dev, "Invalid info: %u-%u-%u-%u x %u-%u-%u-%u @ %lukHz!\n", var->left_margin, var->xres, var->right_margin, var->hsync_len, var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); return -EINVAL; } return 0; Loading Loading @@ -1197,6 +1188,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) const struct fb_videomode *mode = cfg->lcd_cfg; unsigned long max_size = 0; int k; int num_cfg; ch->info = framebuffer_alloc(0, &pdev->dev); if (!ch->info) { Loading Loading @@ -1224,7 +1216,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } if (!mode) max_size = DEFAULT_XRES * DEFAULT_YRES; max_size = MAX_XRES * MAX_YRES; else if (max_cfg) dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", max_cfg->xres, max_cfg->yres); Loading @@ -1232,8 +1224,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) info->fix = sh_mobile_lcdc_fix; info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; if (!mode) if (!mode) { mode = &default_720p; num_cfg = 1; } else { num_cfg = ch->cfg.num_cfg; } fb_videomode_to_modelist(mode, num_cfg, &info->modelist); fb_videomode_to_var(var, mode); /* Default Y virtual resolution is 2x panel size */ Loading Loading @@ -1281,10 +1279,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct sh_mobile_lcdc_chan *ch = priv->ch + i; const struct fb_videomode *mode = ch->cfg.lcd_cfg; if (!mode) mode = &default_720p; info = ch->info; Loading @@ -1297,7 +1291,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } } fb_videomode_to_modelist(mode, ch->cfg.num_cfg, &info->modelist); error = register_framebuffer(info); if (error < 0) goto err1; Loading
include/video/sh_mobile_hdmi.h +3 −0 Original line number Diff line number Diff line Loading @@ -13,6 +13,7 @@ struct sh_mobile_lcdc_chan_cfg; struct device; struct clk; /* * flags format Loading @@ -33,6 +34,8 @@ struct sh_mobile_hdmi_info { struct sh_mobile_lcdc_chan_cfg *lcd_chan; struct device *lcd_dev; unsigned int flags; long (*clk_optimize_parent)(unsigned long target, unsigned long *best_freq, unsigned long *parent_freq); }; #endif