From 6d6f0874490f7e7ed16408e5396f655d386edf29 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Fri, 27 Aug 2010 10:15:44 +0000 Subject: fbdev: sh-mobile_hdmi: remove un-necessity settings Current gamut, acp, isrc1, isrc2 settings are wrong, and not necessary for now. Tested-by: Takanari Hayama Signed-off-by: Kuninori Morimoto Tested-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 106 ----------------------------------------- 1 file changed, 106 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 2fde08cc66b..afebe809975 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -518,100 +518,6 @@ static void sh_hdmi_audio_infoframe_setup(struct sh_hdmi *hdmi) hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB10); } -/** - * sh_hdmi_gamut_metadata_setup() - Gamut Metadata Packet of CONTROL PACKET - */ -static void sh_hdmi_gamut_metadata_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* Gamut Metadata Packet */ - hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x0A */ - hdmi_write(hdmi, 0x0A, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* Gamut Packet is not used, so default value */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Gamut Packet is not used, so default value */ - hdmi_write(hdmi, 0x10, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* GBD bytes 0 through 27 */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0_63H - PB27_7EH */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_acp_setup() - Audio Content Protection Packet (ACP) - */ -static void sh_hdmi_acp_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* Audio Content Protection Packet (ACP) */ - hdmi_write(hdmi, 0x01, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x04 */ - hdmi_write(hdmi, 0x04, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* ACP_Type */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* GBD bytes 0 through 27 */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_isrc1_setup() - ISRC1 Packet - */ -static void sh_hdmi_isrc1_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* ISRC1 Packet */ - hdmi_write(hdmi, 0x02, HDMI_CTRL_PKT_BUF_INDEX); - - /* Packet Type = 0x05 */ - hdmi_write(hdmi, 0x05, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* ISRC_Cont, ISRC_Valid, Reserved (0), ISRC_Status */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* PB0 UPC_EAN_ISRC_0-15 */ - /* Bytes PB16-PB27 shall be set to a value of 0. */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - -/** - * sh_hdmi_isrc2_setup() - ISRC2 Packet - */ -static void sh_hdmi_isrc2_setup(struct sh_hdmi *hdmi) -{ - int i; - - /* ISRC2 Packet */ - hdmi_write(hdmi, 0x03, HDMI_CTRL_PKT_BUF_INDEX); - - /* HB0 Packet Type = 0x06 */ - hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_ACCESS_HB0); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB1); - /* Reserved (0) */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_HB2); - - /* PB0 UPC_EAN_ISRC_16-31 */ - /* Bytes PB16-PB27 shall be set to a value of 0. */ - for (i = 0; i <= 27; i++) - /* HDMI_CTRL_PKT_BUF_ACCESS_PB0 - PB27 */ - hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB0 + i); -} - /** * sh_hdmi_configure() - Initialise HDMI for output */ @@ -632,18 +538,6 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) /* Audio InfoFrame */ sh_hdmi_audio_infoframe_setup(hdmi); - /* Gamut Metadata packet */ - sh_hdmi_gamut_metadata_setup(hdmi); - - /* Audio Content Protection (ACP) Packet */ - sh_hdmi_acp_setup(hdmi); - - /* ISRC1 Packet */ - sh_hdmi_isrc1_setup(hdmi); - - /* ISRC2 Packet */ - sh_hdmi_isrc2_setup(hdmi); - /* * Control packet auto send with VSYNC control: auto send * General control, Gamut metadata, ISRC, and ACP packets -- cgit v1.2.3-70-g09d2 From 14177a5e56904a584f3777f36b50c8d7bfde5810 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:19:49 +0000 Subject: fbdev: sh_mobile_lcdcfb: use fb_videomode_to_var() instead of open-coding Use the standard fb_videomode_to_var() instead of filling fb_var_screeninfo fields manually in, also remove a redundant memset(0). Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index d72075a9f01..43132de3882 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -837,7 +837,6 @@ static int sh_mobile_ioctl(struct fb_info *info, unsigned int cmd, return retval; } - static struct fb_ops sh_mobile_lcdc_ops = { .owner = THIS_MODULE, .fb_setcolreg = sh_mobile_lcdc_setcolreg, @@ -1117,21 +1116,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) var = &info->var; lcd_cfg = &cfg->lcd_cfg; info->fbops = &sh_mobile_lcdc_ops; - var->xres = var->xres_virtual = lcd_cfg->xres; - var->yres = lcd_cfg->yres; + fb_videomode_to_var(var, lcd_cfg); /* Default Y virtual resolution is 2x panel size */ var->yres_virtual = var->yres * 2; - var->width = cfg->lcd_size_cfg.width; - var->height = cfg->lcd_size_cfg.height; - var->activate = FB_ACTIVATE_NOW; - var->left_margin = lcd_cfg->left_margin; - var->right_margin = lcd_cfg->right_margin; - var->upper_margin = lcd_cfg->upper_margin; - var->lower_margin = lcd_cfg->lower_margin; - var->hsync_len = lcd_cfg->hsync_len; - var->vsync_len = lcd_cfg->vsync_len; - var->sync = lcd_cfg->sync; - var->pixclock = lcd_cfg->pixclock; error = sh_mobile_lcdc_set_bpp(var, cfg->bpp); if (error) @@ -1161,7 +1148,6 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) break; } - memset(buf, 0, info->fix.smem_len); info->fix.smem_start = priv->ch[i].dma_handle; info->screen_base = buf; info->device = &pdev->dev; -- cgit v1.2.3-70-g09d2 From 6ee4845270d9b1e7ea348f9e3b6347f54f986abb Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:19:53 +0000 Subject: fbdev: sh_mobile_hdmi: simplify the EDID reading procedure The present SH-Mobile HDMI driver reads and parses the EDID block into a variable screeninfo object, but since it is still unable to dynamically reconfigure the framebuffer, it overwrites the EDID information with preset values again. This patch just uses a temporary variable to store the EDID timing information instead. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 23 +++-------------------- 1 file changed, 3 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index afebe809975..a8117c33e75 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -557,10 +557,9 @@ static void sh_hdmi_configure(struct sh_hdmi *hdmi) static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) { - struct fb_var_screeninfo *var = &hdmi->var; - struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; - struct fb_videomode *lcd_cfg = &pdata->lcd_chan->lcd_cfg; - unsigned long height = var->height, width = var->width; + struct fb_var_screeninfo tmpvar; + /* TODO: When we are ready to use EDID, use this to fill &hdmi->var */ + struct fb_var_screeninfo *var = &tmpvar; int i; u8 edid[128]; @@ -586,22 +585,6 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); - /* FIXME: Use user-provided configuration instead of EDID */ - var->width = width; - var->xres = lcd_cfg->xres; - var->xres_virtual = lcd_cfg->xres; - var->left_margin = lcd_cfg->left_margin; - var->right_margin = lcd_cfg->right_margin; - var->hsync_len = lcd_cfg->hsync_len; - var->height = height; - var->yres = lcd_cfg->yres; - var->yres_virtual = lcd_cfg->yres * 2; - var->upper_margin = lcd_cfg->upper_margin; - var->lower_margin = lcd_cfg->lower_margin; - var->vsync_len = lcd_cfg->vsync_len; - var->sync = lcd_cfg->sync; - var->pixclock = lcd_cfg->pixclock; - hdmi_external_video_param(hdmi); } -- cgit v1.2.3-70-g09d2 From 5ef6b505d9df45558402bdb823a078840a6a26c4 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:19:57 +0000 Subject: fbdev: sh_mobile_lcdcfb: fix more error paths This patch fixes the following two erroneous error paths: hw_usecnt is allocated with a value of 0, therefore in an early error case, calling sh_mobile_lcdc_clk_off() will wrongly conclude, that hw_usecnt has already been incremented. Then sh_mobile_lcdc_runtime_suspend() will be called, which will access uninitialised data fields and crash the kernel. sh_mobile_lcdc_stop() can be called before framebuffer has been allocated, then ch->info is NULL and dereferencing it will Oops too. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 43132de3882..295bf4ba184 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -614,7 +614,7 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv) * flush frame, and wait for frame end interrupt * clean up deferred io and enable clock */ - if (ch->info->fbdefio) { + if (ch->info && ch->info->fbdefio) { ch->frame_end = 0; schedule_delayed_work(&ch->info->deferred_work, 0); wait_event(ch->frame_end_wait, ch->frame_end); @@ -704,7 +704,6 @@ static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev, return PTR_ERR(priv->dot_clk); } } - atomic_set(&priv->hw_usecnt, -1); /* Runtime PM support involves two step for this driver: * 1) Enable Runtime PM @@ -1055,6 +1054,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) priv->irq = i; pdata = pdev->dev.platform_data; + atomic_set(&priv->hw_usecnt, -1); j = 0; for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { -- cgit v1.2.3-70-g09d2 From 01ac25b59f08c0bb56dd301f024eabd542205a42 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:00 +0000 Subject: fbdev: sh_mobile_lcdcfb: minor simplifications and clean up Remove an unused variable and simplify several pointer dereferences. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 51 ++++++++++++++++++++-------------------- 1 file changed, 26 insertions(+), 25 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 295bf4ba184..e4f6012fe4e 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -460,7 +460,6 @@ static void sh_mobile_lcdc_geometry(struct sh_mobile_lcdc_chan *ch) static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; - struct fb_videomode *lcd_cfg; struct sh_mobile_lcdc_board_cfg *board_cfg; unsigned long tmp; int k, m; @@ -518,7 +517,6 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) for (k = 0; k < ARRAY_SIZE(priv->ch); k++) { ch = &priv->ch[k]; - lcd_cfg = &ch->cfg.lcd_cfg; if (!ch->enabled) continue; @@ -1018,14 +1016,14 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) { struct fb_info *info; struct sh_mobile_lcdc_priv *priv; - struct sh_mobile_lcdc_info *pdata; + struct sh_mobile_lcdc_info *pdata = pdev->dev.platform_data; struct sh_mobile_lcdc_chan_cfg *cfg; struct resource *res; int error; void *buf; int i, j; - if (!pdev->dev.platform_data) { + if (!pdata) { dev_err(&pdev->dev, "no platform data defined\n"); return -EINVAL; } @@ -1053,32 +1051,33 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) } priv->irq = i; - pdata = pdev->dev.platform_data; atomic_set(&priv->hw_usecnt, -1); j = 0; for (i = 0; i < ARRAY_SIZE(pdata->ch); i++) { - priv->ch[j].lcdc = priv; - memcpy(&priv->ch[j].cfg, &pdata->ch[i], sizeof(pdata->ch[i])); + struct sh_mobile_lcdc_chan *ch = priv->ch + j; - error = sh_mobile_lcdc_check_interface(&priv->ch[j]); + ch->lcdc = priv; + memcpy(&ch->cfg, &pdata->ch[i], sizeof(pdata->ch[i])); + + error = sh_mobile_lcdc_check_interface(ch); if (error) { dev_err(&pdev->dev, "unsupported interface type\n"); goto err1; } - init_waitqueue_head(&priv->ch[j].frame_end_wait); - init_completion(&priv->ch[j].vsync_completion); - priv->ch[j].pan_offset = 0; + init_waitqueue_head(&ch->frame_end_wait); + init_completion(&ch->vsync_completion); + ch->pan_offset = 0; switch (pdata->ch[i].chan) { case LCDC_CHAN_MAINLCD: - priv->ch[j].enabled = 1 << 1; - priv->ch[j].reg_offs = lcdc_offs_mainlcd; + ch->enabled = 1 << 1; + ch->reg_offs = lcdc_offs_mainlcd; j++; break; case LCDC_CHAN_SUBLCD: - priv->ch[j].enabled = 1 << 2; - priv->ch[j].reg_offs = lcdc_offs_sublcd; + ch->enabled = 1 << 2; + ch->reg_offs = lcdc_offs_sublcd; j++; break; } @@ -1102,17 +1101,19 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct fb_var_screeninfo *var; - struct fb_videomode *lcd_cfg; - cfg = &priv->ch[i].cfg; + const struct fb_videomode *lcd_cfg; + struct sh_mobile_lcdc_chan *ch = priv->ch + i; + + cfg = &ch->cfg; - priv->ch[i].info = framebuffer_alloc(0, &pdev->dev); - if (!priv->ch[i].info) { + ch->info = framebuffer_alloc(0, &pdev->dev); + if (!ch->info) { dev_err(&pdev->dev, "unable to allocate fb_info\n"); error = -ENOMEM; break; } - info = priv->ch[i].info; + info = ch->info; var = &info->var; lcd_cfg = &cfg->lcd_cfg; info->fbops = &sh_mobile_lcdc_ops; @@ -1130,28 +1131,28 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) var->yres_virtual; buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, - &priv->ch[i].dma_handle, GFP_KERNEL); + &ch->dma_handle, GFP_KERNEL); if (!buf) { dev_err(&pdev->dev, "unable to allocate buffer\n"); error = -ENOMEM; break; } - info->pseudo_palette = &priv->ch[i].pseudo_palette; + info->pseudo_palette = &ch->pseudo_palette; info->flags = FBINFO_FLAG_DEFAULT; error = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); if (error < 0) { dev_err(&pdev->dev, "unable to allocate cmap\n"); dma_free_coherent(&pdev->dev, info->fix.smem_len, - buf, priv->ch[i].dma_handle); + buf, ch->dma_handle); break; } - info->fix.smem_start = priv->ch[i].dma_handle; + info->fix.smem_start = ch->dma_handle; info->screen_base = buf; info->device = &pdev->dev; - info->par = &priv->ch[i]; + info->par = ch; } if (error) -- cgit v1.2.3-70-g09d2 From 44432407d9f5e4b2e56c7eccb65d98cad4bba191 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:04 +0000 Subject: fbdev: sh_mobile_lcdcfb: Support multiple video modes in platform data This is a preparation for HDMI hotplug support. This patch just moves all platform defined video modes for the sh_mobile_lcdcfb driver to separate arrays and switches all users to use element 0 of that array, so, this patch doesn't introduce any functional changes and as such should not cause any regressions. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- arch/arm/mach-shmobile/board-ap4evb.c | 98 ++++++++++++++++++++--------------- arch/sh/boards/mach-ap325rxa/setup.c | 29 ++++++----- arch/sh/boards/mach-ecovec24/setup.c | 60 ++++++++++++--------- arch/sh/boards/mach-kfr2r09/setup.c | 29 ++++++----- arch/sh/boards/mach-migor/setup.c | 58 +++++++++++---------- arch/sh/boards/mach-se/7724/setup.c | 54 ++++++++++++------- drivers/video/sh_mipi_dsi.c | 32 +++++++----- drivers/video/sh_mobile_hdmi.c | 3 +- drivers/video/sh_mobile_lcdcfb.c | 10 ++-- include/video/sh_mobile_lcdc.h | 3 +- 10 files changed, 219 insertions(+), 157 deletions(-) (limited to 'drivers/video') diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 31e5b28ab9b..4e883e0fb01 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -375,10 +375,40 @@ static struct platform_device usb1_host_device = { .resource = usb1_host_resources, }; +const static struct fb_videomode ap4evb_lcdc_modes[] = { + { +#ifdef CONFIG_AP4EVB_QHD + .name = "R63302(QHD)", + .xres = 544, + .yres = 961, + .left_margin = 72, + .right_margin = 600, + .hsync_len = 16, + .upper_margin = 8, + .lower_margin = 8, + .vsync_len = 2, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, +#else + .name = "WVGA Panel", + .xres = 800, + .yres = 480, + .left_margin = 220, + .right_margin = 110, + .hsync_len = 70, + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + .sync = 0, +#endif + }, +}; + static struct sh_mobile_lcdc_info lcdc_info = { .ch[0] = { .chan = LCDC_CHAN_MAINLCD, .bpp = 16, + .lcd_cfg = ap4evb_lcdc_modes, + .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), } }; @@ -569,6 +599,31 @@ static struct platform_device fsi_device = { }, }; +const static struct fb_videomode ap4evb_hdmi_modes[] = { + { + .name = "HDMI 720p", + .xres = 1280, + .yres = 720, + + /* + * If left and right margins are not multiples of 8, + * LDHAJR will be adjusted accordingly by the LCDC + * driver. Until we start using EDID, these values + * might have to be adjusted for different monitors. + */ + .left_margin = 200, + .right_margin = 88, + .hsync_len = 48, + + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + + .pixclock = 13468, + .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, + }, +}; + static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { @@ -577,26 +632,8 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { .interface_type = RGB24, .clock_divider = 1, .flags = LCDC_FLAGS_DWPOL, - .lcd_cfg = { - .name = "HDMI", - /* So far only 720p is supported */ - .xres = 1280, - .yres = 720, - /* - * If left and right margins are not multiples of 8, - * LDHAJR will be adjusted accordingly by the LCDC - * driver. Until we start using EDID, these values - * might have to be adjusted for different monitors. - */ - .left_margin = 200, - .right_margin = 88, - .hsync_len = 48, - .upper_margin = 20, - .lower_margin = 5, - .vsync_len = 5, - .pixclock = 13468, - .sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT, - }, + .lcd_cfg = ap4evb_hdmi_modes, + .num_cfg = ARRAY_SIZE(ap4evb_hdmi_modes), } }; @@ -960,17 +997,6 @@ static void __init ap4evb_init(void) lcdc_info.ch[0].interface_type = RGB24; lcdc_info.ch[0].clock_divider = 1; lcdc_info.ch[0].flags = LCDC_FLAGS_DWPOL; - lcdc_info.ch[0].lcd_cfg.name = "R63302(QHD)"; - lcdc_info.ch[0].lcd_cfg.xres = 544; - lcdc_info.ch[0].lcd_cfg.yres = 961; - lcdc_info.ch[0].lcd_cfg.left_margin = 72; - lcdc_info.ch[0].lcd_cfg.right_margin = 600; - lcdc_info.ch[0].lcd_cfg.hsync_len = 16; - lcdc_info.ch[0].lcd_cfg.upper_margin = 8; - lcdc_info.ch[0].lcd_cfg.lower_margin = 8; - lcdc_info.ch[0].lcd_cfg.vsync_len = 2; - lcdc_info.ch[0].lcd_cfg.sync = FB_SYNC_VERT_HIGH_ACT | - FB_SYNC_HOR_HIGH_ACT; lcdc_info.ch[0].lcd_size_cfg.width = 44; lcdc_info.ch[0].lcd_size_cfg.height = 79; @@ -1013,16 +1039,6 @@ static void __init ap4evb_init(void) lcdc_info.ch[0].interface_type = RGB18; lcdc_info.ch[0].clock_divider = 2; lcdc_info.ch[0].flags = 0; - lcdc_info.ch[0].lcd_cfg.name = "WVGA Panel"; - lcdc_info.ch[0].lcd_cfg.xres = 800; - lcdc_info.ch[0].lcd_cfg.yres = 480; - lcdc_info.ch[0].lcd_cfg.left_margin = 220; - lcdc_info.ch[0].lcd_cfg.right_margin = 110; - lcdc_info.ch[0].lcd_cfg.hsync_len = 70; - lcdc_info.ch[0].lcd_cfg.upper_margin = 20; - lcdc_info.ch[0].lcd_cfg.lower_margin = 5; - lcdc_info.ch[0].lcd_cfg.vsync_len = 5; - lcdc_info.ch[0].lcd_cfg.sync = 0; lcdc_info.ch[0].lcd_size_cfg.width = 152; lcdc_info.ch[0].lcd_size_cfg.height = 91; diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 3da116f47f0..00553233a7c 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -176,6 +176,21 @@ static void ap320_wvga_power_off(void *board_data) __raw_writew(0, FPGA_LCDREG); } +const static struct fb_videomode ap325rxa_lcdc_modes[] = { + { + .name = "LB070WV1", + .xres = 800, + .yres = 480, + .left_margin = 32, + .right_margin = 160, + .hsync_len = 8, + .upper_margin = 63, + .lower_margin = 80, + .vsync_len = 1, + .sync = 0, /* hsync and vsync are active low */ + }, +}; + static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { @@ -183,18 +198,8 @@ static struct sh_mobile_lcdc_info lcdc_info = { .bpp = 16, .interface_type = RGB18, .clock_divider = 1, - .lcd_cfg = { - .name = "LB070WV1", - .xres = 800, - .yres = 480, - .left_margin = 32, - .right_margin = 160, - .hsync_len = 8, - .upper_margin = 63, - .lower_margin = 80, - .vsync_len = 1, - .sync = 0, /* hsync and vsync are active low */ - }, + .lcd_cfg = ap325rxa_lcdc_modes, + .num_cfg = ARRAY_SIZE(ap325rxa_lcdc_modes), .lcd_size_cfg = { /* 7.0 inch */ .width = 152, .height = 91, diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 1d7b495a7db..feadf5dada7 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -231,14 +231,41 @@ static struct platform_device usb1_common_device = { }; /* LCDC */ +const static struct fb_videomode ecovec_lcd_modes[] = { + { + .name = "Panel", + .xres = 800, + .yres = 480, + .left_margin = 220, + .right_margin = 110, + .hsync_len = 70, + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + .sync = 0, /* hsync and vsync are active low */ + }, +}; + +const static struct fb_videomode ecovec_dvi_modes[] = { + { + .name = "DVI", + .xres = 1280, + .yres = 720, + .left_margin = 220, + .right_margin = 110, + .hsync_len = 40, + .upper_margin = 20, + .lower_margin = 5, + .vsync_len = 5, + .sync = 0, /* hsync and vsync are active low */ + }, +}; + static struct sh_mobile_lcdc_info lcdc_info = { .ch[0] = { .interface_type = RGB18, .chan = LCDC_CHAN_MAINLCD, .bpp = 16, - .lcd_cfg = { - .sync = 0, /* hsync and vsync are active low */ - }, .lcd_size_cfg = { /* 7.0 inch */ .width = 152, .height = 91, @@ -1079,33 +1106,18 @@ static int __init arch_setup(void) if (gpio_get_value(GPIO_PTE6)) { /* DVI */ lcdc_info.clock_source = LCDC_CLK_EXTERNAL; - lcdc_info.ch[0].clock_divider = 1, - lcdc_info.ch[0].lcd_cfg.name = "DVI"; - lcdc_info.ch[0].lcd_cfg.xres = 1280; - lcdc_info.ch[0].lcd_cfg.yres = 720; - lcdc_info.ch[0].lcd_cfg.left_margin = 220; - lcdc_info.ch[0].lcd_cfg.right_margin = 110; - lcdc_info.ch[0].lcd_cfg.hsync_len = 40; - lcdc_info.ch[0].lcd_cfg.upper_margin = 20; - lcdc_info.ch[0].lcd_cfg.lower_margin = 5; - lcdc_info.ch[0].lcd_cfg.vsync_len = 5; + lcdc_info.ch[0].clock_divider = 1; + lcdc_info.ch[0].lcd_cfg = ecovec_dvi_modes; + lcdc_info.ch[0].num_cfg = ARRAY_SIZE(ecovec_dvi_modes); gpio_set_value(GPIO_PTA2, 1); gpio_set_value(GPIO_PTU1, 1); } else { /* Panel */ - lcdc_info.clock_source = LCDC_CLK_PERIPHERAL; - lcdc_info.ch[0].clock_divider = 2, - lcdc_info.ch[0].lcd_cfg.name = "Panel"; - lcdc_info.ch[0].lcd_cfg.xres = 800; - lcdc_info.ch[0].lcd_cfg.yres = 480; - lcdc_info.ch[0].lcd_cfg.left_margin = 220; - lcdc_info.ch[0].lcd_cfg.right_margin = 110; - lcdc_info.ch[0].lcd_cfg.hsync_len = 70; - lcdc_info.ch[0].lcd_cfg.upper_margin = 20; - lcdc_info.ch[0].lcd_cfg.lower_margin = 5; - lcdc_info.ch[0].lcd_cfg.vsync_len = 5; + lcdc_info.ch[0].clock_divider = 2; + lcdc_info.ch[0].lcd_cfg = ecovec_lcd_modes; + lcdc_info.ch[0].num_cfg = ARRAY_SIZE(ecovec_lcd_modes); gpio_set_value(GPIO_PTR1, 1); diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index 68994a163f6..87d4b90e368 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -126,6 +126,21 @@ static struct platform_device kfr2r09_sh_keysc_device = { }, }; +const static struct fb_videomode kfr2r09_lcdc_modes[] = { + { + .name = "TX07D34VM0AAA", + .xres = 240, + .yres = 400, + .left_margin = 0, + .right_margin = 16, + .hsync_len = 8, + .upper_margin = 0, + .lower_margin = 1, + .vsync_len = 1, + .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + }, +}; + static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { @@ -134,18 +149,8 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { .interface_type = SYS18, .clock_divider = 6, .flags = LCDC_FLAGS_DWPOL, - .lcd_cfg = { - .name = "TX07D34VM0AAA", - .xres = 240, - .yres = 400, - .left_margin = 0, - .right_margin = 16, - .hsync_len = 8, - .upper_margin = 0, - .lower_margin = 1, - .vsync_len = 1, - .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - }, + .lcd_cfg = kfr2r09_lcdc_modes, + .num_cfg = ARRAY_SIZE(kfr2r09_lcdc_modes), .lcd_size_cfg = { .width = 35, .height = 58, diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index 662debe4ead..9204cbb8714 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -213,51 +213,55 @@ static struct platform_device migor_nand_flash_device = { } }; +const static struct fb_videomode migor_lcd_modes[] = { + { +#if defined(CONFIG_SH_MIGOR_RTA_WVGA) + .name = "LB070WV1", + .xres = 800, + .yres = 480, + .left_margin = 64, + .right_margin = 16, + .hsync_len = 120, + .sync = 0, +#elif defined(CONFIG_SH_MIGOR_QVGA) + .name = "PH240320T", + .xres = 320, + .yres = 240, + .left_margin = 0, + .right_margin = 16, + .hsync_len = 8, + .sync = FB_SYNC_HOR_HIGH_ACT, +#endif + .upper_margin = 1, + .lower_margin = 17, + .vsync_len = 2, + }, +}; + static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { -#ifdef CONFIG_SH_MIGOR_RTA_WVGA +#if defined(CONFIG_SH_MIGOR_RTA_WVGA) .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, .bpp = 16, .interface_type = RGB16, .clock_divider = 2, - .lcd_cfg = { - .name = "LB070WV1", - .xres = 800, - .yres = 480, - .left_margin = 64, - .right_margin = 16, - .hsync_len = 120, - .upper_margin = 1, - .lower_margin = 17, - .vsync_len = 2, - .sync = 0, - }, + .lcd_cfg = migor_lcd_modes, + .num_cfg = ARRAY_SIZE(migor_lcd_modes), .lcd_size_cfg = { /* 7.0 inch */ .width = 152, .height = 91, }, } -#endif -#ifdef CONFIG_SH_MIGOR_QVGA +#elif defined(CONFIG_SH_MIGOR_QVGA) .clock_source = LCDC_CLK_PERIPHERAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, .bpp = 16, .interface_type = SYS16A, .clock_divider = 10, - .lcd_cfg = { - .name = "PH240320T", - .xres = 320, - .yres = 240, - .left_margin = 0, - .right_margin = 16, - .hsync_len = 8, - .upper_margin = 1, - .lower_margin = 17, - .vsync_len = 2, - .sync = FB_SYNC_HOR_HIGH_ACT, - }, + .lcd_cfg = migor_lcd_modes, + .num_cfg = ARRAY_SIZE(migor_lcd_modes), .lcd_size_cfg = { /* 2.4 inch */ .width = 49, .height = 37, diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index 552ebd9ba82..3099c36759a 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -144,16 +144,42 @@ static struct platform_device nor_flash_device = { }; /* LCDC */ +const static struct fb_videomode lcdc_720p_modes[] = { + { + .name = "LB070WV1", + .sync = 0, /* hsync and vsync are active low */ + .xres = 1280; + .yres = 720; + .left_margin = 220; + .right_margin = 110; + .hsync_len = 40; + .upper_margin = 20; + .lower_margin = 5; + .vsync_len = 5; + }, +}; + +const static struct fb_videomode lcdc_vga_modes[] = { + { + .name = "LB070WV1", + .sync = 0, /* hsync and vsync are active low */ + .xres = 640; + .yres = 480; + .left_margin = 105; + .right_margin = 50; + .hsync_len = 96; + .upper_margin = 33; + .lower_margin = 10; + .vsync_len = 2; + }, +}; + static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, .bpp = 16, .clock_divider = 1, - .lcd_cfg = { - .name = "LB070WV1", - .sync = 0, /* hsync and vsync are active low */ - }, .lcd_size_cfg = { /* 7.0 inch */ .width = 152, .height = 91, @@ -909,24 +935,12 @@ static int __init devices_setup(void) if (sw & SW41_B) { /* 720p */ - lcdc_info.ch[0].lcd_cfg.xres = 1280; - lcdc_info.ch[0].lcd_cfg.yres = 720; - lcdc_info.ch[0].lcd_cfg.left_margin = 220; - lcdc_info.ch[0].lcd_cfg.right_margin = 110; - lcdc_info.ch[0].lcd_cfg.hsync_len = 40; - lcdc_info.ch[0].lcd_cfg.upper_margin = 20; - lcdc_info.ch[0].lcd_cfg.lower_margin = 5; - lcdc_info.ch[0].lcd_cfg.vsync_len = 5; + lcdc_info.ch[0].lcd_cfg = lcdc_720p_modes; + lcdc_info.ch[0].num_cfg = ARRAY_SIZE(lcdc_720p_modes); } else { /* VGA */ - lcdc_info.ch[0].lcd_cfg.xres = 640; - lcdc_info.ch[0].lcd_cfg.yres = 480; - lcdc_info.ch[0].lcd_cfg.left_margin = 105; - lcdc_info.ch[0].lcd_cfg.right_margin = 50; - lcdc_info.ch[0].lcd_cfg.hsync_len = 96; - lcdc_info.ch[0].lcd_cfg.upper_margin = 33; - lcdc_info.ch[0].lcd_cfg.lower_margin = 10; - lcdc_info.ch[0].lcd_cfg.vsync_len = 2; + lcdc_info.ch[0].lcd_cfg = lcdc_vga_modes; + lcdc_info.ch[0].num_cfg = ARRAY_SIZE(lcdc_vga_modes); } if (sw & SW41_A) { diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 5699ce0c178..3f3d431033c 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -123,83 +123,87 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, u32 linelength; bool yuv; - /* Select data format */ + /* + * Select data format. MIPI DSI is not hot-pluggable, so, we just use + * the default videomode. If this ever becomes a problem, We'll have to + * move this to mipi_display_on() above and use info->var.xres + */ switch (pdata->data_format) { case MIPI_RGB888: pctype = 0; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_RGB565: pctype = 1; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = false; break; case MIPI_RGB666_LP: pctype = 2; datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_RGB666: pctype = 3; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; - linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; yuv = false; break; case MIPI_BGR888: pctype = 8; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_24; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_BGR565: pctype = 9; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = false; break; case MIPI_BGR666_LP: pctype = 0xa; datatype = MIPI_DSI_PIXEL_STREAM_3BYTE_18; pixfmt = MIPI_DCS_PIXEL_FMT_24BIT; - linelength = ch->lcd_cfg.xres * 3; + linelength = ch->lcd_cfg[0].xres * 3; yuv = false; break; case MIPI_BGR666: pctype = 0xb; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_18; pixfmt = MIPI_DCS_PIXEL_FMT_18BIT; - linelength = (ch->lcd_cfg.xres * 18 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 18 + 7) / 8; yuv = false; break; case MIPI_YUYV: pctype = 4; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = true; break; case MIPI_UYVY: pctype = 5; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16; pixfmt = MIPI_DCS_PIXEL_FMT_16BIT; - linelength = ch->lcd_cfg.xres * 2; + linelength = ch->lcd_cfg[0].xres * 2; yuv = true; break; case MIPI_YUV420_L: pctype = 6; datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; - linelength = (ch->lcd_cfg.xres * 12 + 7) / 8; + linelength = (ch->lcd_cfg[0].xres * 12 + 7) / 8; yuv = true; break; case MIPI_YUV420: @@ -207,7 +211,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, datatype = MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12; pixfmt = MIPI_DCS_PIXEL_FMT_12BIT; /* Length of U/V line */ - linelength = (ch->lcd_cfg.xres + 1) / 2; + linelength = (ch->lcd_cfg[0].xres + 1) / 2; yuv = true; break; default: @@ -281,7 +285,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, iowrite32(0x00e00000, base + 0x8024); /* VMCTR2 */ /* * 0x660 = 1632 bytes per line (RGB24, 544 pixels: see - * sh_mobile_lcdc_info.ch[0].lcd_cfg.xres), HSALEN = 1 - default + * sh_mobile_lcdc_info.ch[0].lcd_cfg[0].xres), HSALEN = 1 - default * (unused, since VMCTR2[HSABM] = 0) */ iowrite32(1 | (linelength << 16), base + 0x8028); /* VMLEN1 */ diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index a8117c33e75..6608429c0fb 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -777,7 +777,8 @@ static int __init sh_hdmi_probe(struct platform_device *pdev) goto egetclk; } - rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg.pixclock) * 1000; + /* TODO: reconfigure the clock on monitor plug in */ + rate = PICOS2KHZ(pdata->lcd_chan->lcd_cfg[0].pixclock) * 1000; rate = clk_round_rate(hdmi->hdmi_clk, rate); if (rate < 0) { diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index e4f6012fe4e..ce3ed4bc991 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -989,8 +989,8 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, int ret; /* Can we handle this display? */ - if (var->xres > ch->cfg.lcd_cfg.xres || - var->yres > ch->cfg.lcd_cfg.yres) + if (var->xres > ch->cfg.lcd_cfg[0].xres || + var->yres > ch->cfg.lcd_cfg[0].yres) return -ENOMEM; /* Add to the modelist */ @@ -1115,7 +1115,7 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) info = ch->info; var = &info->var; - lcd_cfg = &cfg->lcd_cfg; + lcd_cfg = &cfg->lcd_cfg[0]; info->fbops = &sh_mobile_lcdc_ops; fb_videomode_to_var(var, lcd_cfg); /* Default Y virtual resolution is 2x panel size */ @@ -1187,8 +1187,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? "mainlcd" : "sublcd", - (int) ch->cfg.lcd_cfg.xres, - (int) ch->cfg.lcd_cfg.yres, + (int) ch->cfg.lcd_cfg[0].xres, + (int) ch->cfg.lcd_cfg[0].yres, ch->cfg.bpp); /* deferred io mode: disable clock to save power */ diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 55d700e8566..19c69d788f3 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h @@ -70,7 +70,8 @@ struct sh_mobile_lcdc_chan_cfg { int interface_type; /* selects RGBn or SYSn I/F, see above */ int clock_divider; unsigned long flags; /* LCDC_FLAGS_... */ - struct fb_videomode lcd_cfg; + const struct fb_videomode *lcd_cfg; + int num_cfg; struct sh_mobile_lcdc_lcd_size_cfg lcd_size_cfg; struct sh_mobile_lcdc_board_cfg board_cfg; struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ -- cgit v1.2.3-70-g09d2 From baf163749952ca5e33dd2d6a74da023e385c3a00 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:08 +0000 Subject: fbdev: sh_mobile_lcdcfb: fix notifier callback return codes Notifier callbacks have to return either one of NOTIFY_* codes or a negative errno, converted to a suitable value by the notifier_from_errno() inline, if the notifier chain shall not be continued. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index ce3ed4bc991..2f6e37ea790 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -964,7 +964,7 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, struct fb_var_screeninfo *var; if (&ch->lcdc->notifier != nb) - return 0; + return NOTIFY_DONE; dev_dbg(info->dev, "%s(): action = %lu, data = %p\n", __func__, action, event->data); @@ -991,23 +991,25 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb, /* Can we handle this display? */ if (var->xres > ch->cfg.lcd_cfg[0].xres || var->yres > ch->cfg.lcd_cfg[0].yres) - return -ENOMEM; + /* + * LCDC resume failed, no need to continue with + * the notifier chain + */ + return notifier_from_errno(-ENOMEM); /* Add to the modelist */ fb_var_to_videomode(&mode, var); ret = fb_add_videomode(&mode, &ch->info->modelist); if (ret < 0) - return ret; + return notifier_from_errno(ret); } pm_runtime_get_sync(info->device); sh_mobile_lcdc_geometry(ch); - - break; } - return 0; + return NOTIFY_OK; } static int sh_mobile_lcdc_remove(struct platform_device *pdev); -- cgit v1.2.3-70-g09d2 From 71d3b0fcadf70d0de1ad334f48c9a4060209091a Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:12 +0000 Subject: fbdev: sh_mobile_lcdcfb: allocate memory, sufficient for the biggest mode Now, that we add support for multiple modes to the sh_mobile_lcdcfb driver, it has to allocate memory, sufficient for the biggest of them. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_lcdcfb.c | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index 2f6e37ea790..ddd6c4669bd 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -1103,8 +1103,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) for (i = 0; i < j; i++) { struct fb_var_screeninfo *var; - const struct fb_videomode *lcd_cfg; + const struct fb_videomode *lcd_cfg, *max_cfg = NULL; struct sh_mobile_lcdc_chan *ch = priv->ch + i; + unsigned long max_size = 0; + int k; cfg = &ch->cfg; @@ -1117,9 +1119,8 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) info = ch->info; var = &info->var; - lcd_cfg = &cfg->lcd_cfg[0]; info->fbops = &sh_mobile_lcdc_ops; - fb_videomode_to_var(var, lcd_cfg); + fb_videomode_to_var(var, &cfg->lcd_cfg[0]); /* Default Y virtual resolution is 2x panel size */ var->yres_virtual = var->yres * 2; @@ -1127,10 +1128,23 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) if (error) break; + for (k = 0, lcd_cfg = cfg->lcd_cfg; + k < cfg->num_cfg; + k++, lcd_cfg++) { + unsigned long size = lcd_cfg->yres * lcd_cfg->xres; + + if (size > max_size) { + max_cfg = lcd_cfg; + max_size = size; + } + } + + dev_dbg(&pdev->dev, "Found largest videomode %ux%u\n", + max_cfg->xres, max_cfg->yres); + info->fix = sh_mobile_lcdc_fix; - info->fix.line_length = lcd_cfg->xres * (cfg->bpp / 8); - info->fix.smem_len = info->fix.line_length * - var->yres_virtual; + info->fix.line_length = cfg->lcd_cfg[0].xres * (cfg->bpp / 8); + info->fix.smem_len = max_size * (cfg->bpp / 8) * 2; buf = dma_alloc_coherent(&pdev->dev, info->fix.smem_len, &ch->dma_handle, GFP_KERNEL); -- cgit v1.2.3-70-g09d2 From 6e45746c36d5ab4c3486760e45a555263a0b9fac Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:16 +0000 Subject: fbdev: sh_mobile_hdmi: add initial support for modes, other than 720p To support standard video modes, other than 720p, the HDMI PHY configuration has to be adjusted and the VIC has to be sent to the display. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 82 +++++++++++++++++++++++++++++++----------- 1 file changed, 62 insertions(+), 20 deletions(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 6608429c0fb..27d76bcf8e0 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -381,21 +381,61 @@ static void sh_hdmi_audio_config(struct sh_hdmi *hdmi) } /** - * sh_hdmi_phy_config() + * sh_hdmi_phy_config() - configure the HDMI PHY for the used video mode */ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) { - /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ - hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); - hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); - /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ - hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); - hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); - hdmi_write(hdmi, 0x4A, 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); + if (hdmi->var.yres > 480) { + /* 720p, 8bit, 74.25MHz. Might need to be adjusted for other formats */ + /* + * [1:0] Speed_A + * [3:2] Speed_B + * [4] PLLA_Bypass + * [6] DRV_TEST_EN + * [7] DRV_TEST_IN + */ + hdmi_write(hdmi, 0x19, HDMI_SLIPHDMIT_PARAM_SETTINGS_1); + /* PLLB_CONFIG[17], PLLA_CONFIG[17] - not in PHY datasheet */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_2); + /* + * [2:0] BGR_I_OFFSET + * [6:4] BGR_V_OFFSET + */ + hdmi_write(hdmi, 0x00, HDMI_SLIPHDMIT_PARAM_SETTINGS_3); + /* PLLA_CONFIG[7:0]: VCO gain, VCO offset, LPF resistance[0] */ + hdmi_write(hdmi, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + /* + * PLLA_CONFIG[15:8]: regulator voltage[0], CP current, + * LPF capacitance, LPF resistance[1] + */ + hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + /* PLLB_CONFIG[7:0]: LPF resistance[0], VCO offset, VCO gain */ + hdmi_write(hdmi, 0x4A, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + /* + * PLLB_CONFIG[15:8]: regulator voltage[0], CP current, + * LPF capacitance, LPF resistance[1] + */ + hdmi_write(hdmi, 0x0E, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + /* DRV_CONFIG, PE_CONFIG */ + hdmi_write(hdmi, 0x25, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + /* + * [2:0] AMON_SEL (4 == LPF voltage) + * [4] PLLA_CONFIG[16] + * [5] PLLB_CONFIG[16] + */ + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } else { + /* for 480p8bit 27MHz */ + hdmi_write(hdmi, 0x19, 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, 0x44, HDMI_SLIPHDMIT_PARAM_SETTINGS_5); + hdmi_write(hdmi, 0x32, HDMI_SLIPHDMIT_PARAM_SETTINGS_6); + hdmi_write(hdmi, 0x48, HDMI_SLIPHDMIT_PARAM_SETTINGS_7); + hdmi_write(hdmi, 0x0F, HDMI_SLIPHDMIT_PARAM_SETTINGS_8); + hdmi_write(hdmi, 0x20, HDMI_SLIPHDMIT_PARAM_SETTINGS_9); + hdmi_write(hdmi, 0x04, HDMI_SLIPHDMIT_PARAM_SETTINGS_10); + } } /** @@ -403,6 +443,8 @@ static void sh_hdmi_phy_config(struct sh_hdmi *hdmi) */ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) { + u8 vic; + /* AVI InfoFrame */ hdmi_write(hdmi, 0x06, HDMI_CTRL_PKT_BUF_INDEX); @@ -443,9 +485,15 @@ static void sh_hdmi_avi_infoframe_setup(struct sh_hdmi *hdmi) /* * VIC = 1280 x 720p: ignored if external config is used - * Send 2 for 720 x 480p, 16 for 1080p + * Send 2 for 720 x 480p, 16 for 1080p, ignored in external mode */ - hdmi_write(hdmi, 4, HDMI_CTRL_PKT_BUF_ACCESS_PB4); + if (hdmi->var.yres == 1080 && hdmi->var.xres == 1920) + vic = 16; + else if (hdmi->var.yres == 480 && hdmi->var.xres == 720) + vic = 2; + else + vic = 4; + hdmi_write(hdmi, vic, HDMI_CTRL_PKT_BUF_ACCESS_PB4); /* PR = No Repetition */ hdmi_write(hdmi, 0x00, HDMI_CTRL_PKT_BUF_ACCESS_PB5); @@ -666,12 +714,6 @@ static void hdmi_display_on(void *arg, struct fb_info *info) struct sh_hdmi *hdmi = arg; struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data; - if (info->var.xres != 1280 || info->var.yres != 720) { - dev_warn(info->device, "Unsupported framebuffer geometry %ux%u\n", - info->var.xres, info->var.yres); - return; - } - pr_debug("%s(%p): state %x\n", __func__, pdata->lcd_dev, info->state); /* * FIXME: not a good place to store fb_info. And we cannot nullify it -- cgit v1.2.3-70-g09d2 From 89712699d7bc9cc93602407e0e9bc2490b771400 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:20 +0000 Subject: fbdev: sh_mobile_hdmi: enable "external" mode The SH-Mobile HDMI controller supports two configuration modes: using pre-programmed VICs and the "external" mode - specifying video parameters explicitly. The driver already contains code, necessary to configure HDMI manually, this patch actually enables it. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index 27d76bcf8e0..a8cf9a510f3 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -205,6 +205,7 @@ enum hotplug_state { struct sh_hdmi { void __iomem *base; enum hotplug_state hp_state; + bool preprogrammed_mode; /* use a pre-programmed VIC or the external mode */ struct clk *hdmi_clk; struct device *dev; struct fb_info *info; @@ -282,7 +283,10 @@ static void 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 manual mode */ + /* Set bit 0 of HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS here for external mode */ + if (!hdmi->preprogrammed_mode) + hdmi_write(hdmi, sync | 1 | (voffset << 4), + HDMI_EXTERNAL_VIDEO_PARAM_SETTINGS); } /** @@ -633,6 +637,13 @@ static void sh_hdmi_read_edid(struct sh_hdmi *hdmi) var->upper_margin, var->yres, var->lower_margin, var->vsync_len, PICOS2KHZ(var->pixclock)); + if ((hdmi->var.xres == 720 && hdmi->var.yres == 480) || + (hdmi->var.xres == 1280 && hdmi->var.yres == 720) || + (hdmi->var.xres == 1920 && hdmi->var.yres == 1080)) + hdmi->preprogrammed_mode = true; + else + hdmi->preprogrammed_mode = false; + hdmi_external_video_param(hdmi); } -- cgit v1.2.3-70-g09d2 From 6de9edd5bde0cdfea12e9948690e53ec669c3018 Mon Sep 17 00:00:00 2001 From: Guennadi Liakhovetski Date: Fri, 3 Sep 2010 07:20:23 +0000 Subject: fbdev: sh_mobile_hdmi: implement locking The SH-Mobile HDMI driver runs in several contexts: ISR, delayed work-queue, task context, when called from the sh_mobile_lcdc framebuffer driver. This creates ample race possibilities. Even though most these races are purely theoretical, it is better to close them. To trace fb_info validity we install a notification callback in the HDMI driver, and the only way for it to get to driver internal data is by using struct sh_mobile_lcdc_chan, therefore it had to be extracted into a separate common header. Signed-off-by: Guennadi Liakhovetski Signed-off-by: Paul Mundt --- drivers/video/sh_mobile_hdmi.c | 103 +++++++++++++++++++++++++++++++++------ drivers/video/sh_mobile_lcdcfb.c | 46 ++++++----------- drivers/video/sh_mobile_lcdcfb.h | 37 ++++++++++++++ include/video/sh_mobile_lcdc.h | 2 + 4 files changed, 141 insertions(+), 47 deletions(-) create mode 100644 drivers/video/sh_mobile_lcdcfb.h (limited to 'drivers/video') diff --git a/drivers/video/sh_mobile_hdmi.c b/drivers/video/sh_mobile_hdmi.c index a8cf9a510f3..56e44fd0a3a 100644 --- a/drivers/video/sh_mobile_hdmi.c +++ b/drivers/video/sh_mobile_hdmi.c @@ -26,6 +26,8 @@ #include