From 9250741e5feedb6a5273683a940b339af59a1086 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Nov 2011 20:33:47 -0800 Subject: fbdev: sh_mipi_dsi: tidyup dsip_clk dsipck clock is controled by CLKDEV_ICK_ID() in clock-shxxx. dsi0p_clk/dsi1p_clk naming is not needed. Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Florian Tobias Schandinat --- arch/arm/mach-shmobile/clock-sh7372.c | 4 ++-- arch/arm/mach-shmobile/clock-sh73a0.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'arch/arm/mach-shmobile') diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c index 995a9c3aec8f..1ebab171e4f7 100644 --- a/arch/arm/mach-shmobile/clock-sh7372.c +++ b/arch/arm/mach-shmobile/clock-sh7372.c @@ -612,8 +612,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("hdmi_clk", &div6_reparent_clks[DIV6_HDMI]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), - CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* IIC2 */ diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c index 61a846bb30f2..3da30bac518e 100644 --- a/arch/arm/mach-shmobile/clock-sh73a0.c +++ b/arch/arm/mach-shmobile/clock-sh73a0.c @@ -319,8 +319,8 @@ static struct clk_lookup lookups[] = { CLKDEV_CON_ID("sdhi2_clk", &div6_clks[DIV6_SDHI2]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSIT]), CLKDEV_ICK_ID("dsit_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSIT]), - CLKDEV_ICK_ID("dsi0p_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), - CLKDEV_ICK_ID("dsi1p_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.0", &div6_clks[DIV6_DSI0P]), + CLKDEV_ICK_ID("dsip_clk", "sh-mipi-dsi.1", &div6_clks[DIV6_DSI1P]), /* MSTP32 clocks */ CLKDEV_DEV_ID("i2c-sh_mobile.2", &mstp_clks[MSTP001]), /* I2C2 */ -- cgit v1.2.3 From 26c3d7ac219e74ab3939048a32d6bd3b4a16798a Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Nov 2011 20:34:43 -0800 Subject: fbdev: sh_mipi_dsi: add lane control support SH MIPI DSI can use 0-4 lane Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Florian Tobias Schandinat --- arch/arm/mach-shmobile/board-ag5evm.c | 1 + arch/arm/mach-shmobile/board-ap4evb.c | 1 + drivers/video/sh_mipi_dsi.c | 10 +++++++++- include/video/sh_mipi_dsi.h | 1 + 4 files changed, 12 insertions(+), 1 deletion(-) (limited to 'arch/arm/mach-shmobile') diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index b862e9f81e3e..e969fe91e505 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -324,6 +324,7 @@ static struct resource mipidsi0_resources[] = { static struct sh_mipi_dsi_info mipidsi0_info = { .data_format = MIPI_RGB888, .lcd_chan = &lcdc0_info.ch[0], + .lane = 2, .vsynw_offset = 20, .clksrc = 1, .flags = SH_MIPI_DSI_HSABM, diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 4c865ece9ac4..b7d006fd0461 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -580,6 +580,7 @@ static struct resource mipidsi0_resources[] = { static struct sh_mipi_dsi_info mipidsi0_info = { .data_format = MIPI_RGB888, .lcd_chan = &lcdc_info.ch[0], + .lane = 2, .vsynw_offset = 17, }; diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index dfd51541e24c..af6bec24effb 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -8,6 +8,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -153,6 +154,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000; bool yuv; + u32 tmp; /* * Select data format. MIPI DSI is not hot-pluggable, so, we just use @@ -253,6 +255,9 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, (!yuv && ch->interface_type != RGB24)) return -EINVAL; + if (!pdata->lane) + return -EINVAL; + /* reset DSI link */ iowrite32(0x00000001, base + SYSCTRL); /* Hold reset for 100 cycles of the slowest of bus, HS byte and LP clock */ @@ -269,7 +274,10 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, * ECC check enable * additionally enable first two lanes */ - iowrite32(0x00003703, base + SYSCONF); + bitmap_fill((unsigned long *)&tmp, pdata->lane); + tmp |= 0x00003700; + iowrite32(tmp, base + SYSCONF); + /* * T_wakeup = 0x7000 * T_hs-trail = 3 diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h index 58b78f8c0abd..3d0ec500d896 100644 --- a/include/video/sh_mipi_dsi.h +++ b/include/video/sh_mipi_dsi.h @@ -35,6 +35,7 @@ struct sh_mobile_lcdc_chan_cfg; struct sh_mipi_dsi_info { enum sh_mipi_dsi_data_fmt data_format; struct sh_mobile_lcdc_chan_cfg *lcd_chan; + int lane; unsigned long flags; u32 clksrc; unsigned int vsynw_offset; -- cgit v1.2.3 From f832906a56bcf9c597589e9a7898c1dd2f0513b9 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Nov 2011 20:34:55 -0800 Subject: fbdev: sh_mipi_dsi: add sync_pulses/sync_events/burst mode Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Florian Tobias Schandinat --- arch/arm/mach-shmobile/board-ag5evm.c | 3 ++- arch/arm/mach-shmobile/board-ap4evb.c | 1 + drivers/video/sh_mipi_dsi.c | 9 ++++++++- include/video/sh_mipi_dsi.h | 9 +++++++++ 4 files changed, 20 insertions(+), 2 deletions(-) (limited to 'arch/arm/mach-shmobile') diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index e969fe91e505..6993844424c6 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -327,7 +327,8 @@ static struct sh_mipi_dsi_info mipidsi0_info = { .lane = 2, .vsynw_offset = 20, .clksrc = 1, - .flags = SH_MIPI_DSI_HSABM, + .flags = SH_MIPI_DSI_HSABM | + SH_MIPI_DSI_SYNC_PULSES_MODE, }; static struct platform_device mipidsi0_device = { diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index b7d006fd0461..b2e32c8c9e54 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -582,6 +582,7 @@ static struct sh_mipi_dsi_info mipidsi0_info = { .lcd_chan = &lcdc_info.ch[0], .lane = 2, .vsynw_offset = 17, + .flags = SH_MIPI_DSI_SYNC_PULSES_MODE, }; static struct platform_device mipidsi0_device = { diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index af6bec24effb..b8c4873df710 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -152,7 +152,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, { void __iomem *base = mipi->base; struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; - u32 pctype, datatype, pixfmt, linelength, vmctr2 = 0x00e00000; + u32 pctype, datatype, pixfmt, linelength, vmctr2; bool yuv; u32 tmp; @@ -324,6 +324,13 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, * Non-burst mode with sync pulses: VSE and HSE are output, * HSA period allowed, no commands in LP */ + vmctr2 = 0; + if (pdata->flags & SH_MIPI_DSI_VSEE) + vmctr2 |= 1 << 23; + if (pdata->flags & SH_MIPI_DSI_HSEE) + vmctr2 |= 1 << 22; + if (pdata->flags & SH_MIPI_DSI_HSAE) + vmctr2 |= 1 << 21; if (pdata->flags & SH_MIPI_DSI_BL2E) vmctr2 |= 1 << 17; if (pdata->flags & SH_MIPI_DSI_HSABM) diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h index 3d0ec500d896..c8225b4fe8e6 100644 --- a/include/video/sh_mipi_dsi.h +++ b/include/video/sh_mipi_dsi.h @@ -31,6 +31,15 @@ struct sh_mobile_lcdc_chan_cfg; #define SH_MIPI_DSI_HBPBM (1 << 1) #define SH_MIPI_DSI_HFPBM (1 << 2) #define SH_MIPI_DSI_BL2E (1 << 3) +#define SH_MIPI_DSI_VSEE (1 << 4) +#define SH_MIPI_DSI_HSEE (1 << 5) +#define SH_MIPI_DSI_HSAE (1 << 6) + +#define SH_MIPI_DSI_SYNC_PULSES_MODE (SH_MIPI_DSI_VSEE | \ + SH_MIPI_DSI_HSEE | \ + SH_MIPI_DSI_HSAE) +#define SH_MIPI_DSI_SYNC_EVENTS_MODE (0) +#define SH_MIPI_DSI_SYNC_BURST_MODE (SH_MIPI_DSI_BL2E) struct sh_mipi_dsi_info { enum sh_mipi_dsi_data_fmt data_format; -- cgit v1.2.3 From 5e47431aabf716c9ad9eacf1a966e1fc1469c809 Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Nov 2011 20:35:14 -0800 Subject: fbdev: sh_mipi_dsi: add set_dot_clock() for each platform Dot clock of SH MIPI are depends on each platform board. This patch adds set_dot_clock() function for it. Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Florian Tobias Schandinat --- arch/arm/mach-shmobile/board-ag5evm.c | 36 ++++++++++++++++++++++++---- arch/arm/mach-shmobile/board-ap4evb.c | 25 +++++++++++++++++++ drivers/video/sh_mipi_dsi.c | 45 +++++++++-------------------------- include/video/sh_mipi_dsi.h | 3 +++ 4 files changed, 70 insertions(+), 39 deletions(-) (limited to 'arch/arm/mach-shmobile') diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 6993844424c6..15072c51e035 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -321,6 +321,36 @@ static struct resource mipidsi0_resources[] = { }, }; +#define DSI0PHYCR 0xe615006c +static int sh_mipi_set_dot_clock(struct platform_device *pdev, + void __iomem *base, + int enable) +{ + struct clk *pck; + int ret; + + pck = clk_get(&pdev->dev, "dsip_clk"); + if (IS_ERR(pck)) { + ret = PTR_ERR(pck); + goto sh_mipi_set_dot_clock_pck_err; + } + + if (enable) { + clk_set_rate(pck, clk_round_rate(pck, 24000000)); + __raw_writel(0x2a809010, DSI0PHYCR); + clk_enable(pck); + } else { + clk_disable(pck); + } + + ret = 0; + + clk_put(pck); + +sh_mipi_set_dot_clock_pck_err: + return ret; +} + static struct sh_mipi_dsi_info mipidsi0_info = { .data_format = MIPI_RGB888, .lcd_chan = &lcdc0_info.ch[0], @@ -329,6 +359,7 @@ static struct sh_mipi_dsi_info mipidsi0_info = { .clksrc = 1, .flags = SH_MIPI_DSI_HSABM | SH_MIPI_DSI_SYNC_PULSES_MODE, + .set_dot_clock = sh_mipi_set_dot_clock, }; static struct platform_device mipidsi0_device = { @@ -476,8 +507,6 @@ static void __init ag5evm_map_io(void) shmobile_setup_console(); } -#define DSI0PHYCR 0xe615006c - static void __init ag5evm_init(void) { sh73a0_pinmux_init(); @@ -558,9 +587,6 @@ static void __init ag5evm_init(void) gpio_direction_output(GPIO_PORT235, 0); lcd_backlight_reset(); - /* MIPI-DSI clock setup */ - __raw_writel(0x2a809010, DSI0PHYCR); - /* enable SDHI0 on CN15 [SD I/F] */ gpio_request(GPIO_FN_SDHICD0, NULL); gpio_request(GPIO_FN_SDHIWP0, NULL); diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index b2e32c8c9e54..73503ed8bde2 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -564,6 +564,30 @@ static struct platform_device keysc_device = { }; /* MIPI-DSI */ +#define PHYCTRL 0x0070 +static int sh_mipi_set_dot_clock(struct platform_device *pdev, + void __iomem *base, + int enable) +{ + struct clk *pck = clk_get(&pdev->dev, "dsip_clk"); + void __iomem *phy = base + PHYCTRL; + + if (IS_ERR(pck)) + return PTR_ERR(pck); + + if (enable) { + clk_set_rate(pck, clk_round_rate(pck, 24000000)); + iowrite32(ioread32(phy) | (0xb << 8), phy); + clk_enable(pck); + } else { + clk_disable(pck); + } + + clk_put(pck); + + return 0; +} + static struct resource mipidsi0_resources[] = { [0] = { .start = 0xffc60000, @@ -583,6 +607,7 @@ static struct sh_mipi_dsi_info mipidsi0_info = { .lane = 2, .vsynw_offset = 17, .flags = SH_MIPI_DSI_SYNC_PULSES_MODE, + .set_dot_clock = sh_mipi_set_dot_clock, }; static struct platform_device mipidsi0_device = { diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 190e941cf25d..77743f4388a0 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -53,7 +53,6 @@ struct sh_mipi { void __iomem *base; void __iomem *linkbase; struct clk *dsit_clk; - struct clk *dsip_clk; struct device *dev; void *next_board_data; @@ -307,8 +306,8 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, /* DSI-Tx bias on */ iowrite32(0x00000001, base + PHYCTRL); udelay(200); - /* Deassert resets, power on, set multiplier */ - iowrite32(0x03070b01, base + PHYCTRL); + /* Deassert resets, power on */ + iowrite32(0x03070001, base + PHYCTRL); /* setup l-bridge */ @@ -421,6 +420,9 @@ static int __init sh_mipi_probe(struct platform_device *pdev) if (!res || !res2 || idx >= ARRAY_SIZE(mipi_dsi) || !pdata) return -ENODEV; + if (!pdata->set_dot_clock) + return -EINVAL; + mutex_lock(&array_lock); if (idx < 0) for (idx = 0; idx < ARRAY_SIZE(mipi_dsi) && mipi_dsi[idx]; idx++) @@ -481,34 +483,10 @@ static int __init sh_mipi_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "DSI-T clk %lu -> %lu\n", f_current, rate); - mipi->dsip_clk = clk_get(&pdev->dev, "dsip_clk"); - if (IS_ERR(mipi->dsip_clk)) { - ret = PTR_ERR(mipi->dsip_clk); - goto eclkpget; - } - - f_current = clk_get_rate(mipi->dsip_clk); - /* Between 10 and 50MHz */ - rate = clk_round_rate(mipi->dsip_clk, 24000000); - if (rate > 0 && rate != f_current) - ret = clk_set_rate(mipi->dsip_clk, rate); - else - ret = rate; - if (ret < 0) - goto esetprate; - - dev_dbg(&pdev->dev, "DSI-P clk %lu -> %lu\n", f_current, rate); - - msleep(10); - ret = clk_enable(mipi->dsit_clk); if (ret < 0) goto eclkton; - ret = clk_enable(mipi->dsip_clk); - if (ret < 0) - goto eclkpon; - mipi_dsi[idx] = mipi; pm_runtime_enable(&pdev->dev); @@ -518,6 +496,10 @@ static int __init sh_mipi_probe(struct platform_device *pdev) if (ret < 0) goto emipisetup; + ret = pdata->set_dot_clock(pdev, mipi->base, 1); + if (ret < 0) + goto emipisetup; + mutex_unlock(&array_lock); platform_set_drvdata(pdev, mipi); @@ -537,13 +519,8 @@ static int __init sh_mipi_probe(struct platform_device *pdev) emipisetup: mipi_dsi[idx] = NULL; pm_runtime_disable(&pdev->dev); - clk_disable(mipi->dsip_clk); -eclkpon: clk_disable(mipi->dsit_clk); eclkton: -esetprate: - clk_put(mipi->dsip_clk); -eclkpget: esettrate: clk_put(mipi->dsit_clk); eclktget: @@ -594,10 +571,10 @@ static int __exit sh_mipi_remove(struct platform_device *pdev) pdata->lcd_chan->board_cfg.board_data = NULL; pm_runtime_disable(&pdev->dev); - clk_disable(mipi->dsip_clk); clk_disable(mipi->dsit_clk); clk_put(mipi->dsit_clk); - clk_put(mipi->dsip_clk); + pdata->set_dot_clock(pdev, mipi->base, 0); + iounmap(mipi->linkbase); if (res2) release_mem_region(res2->start, resource_size(res2)); diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h index c8225b4fe8e6..310b883bb312 100644 --- a/include/video/sh_mipi_dsi.h +++ b/include/video/sh_mipi_dsi.h @@ -48,6 +48,9 @@ struct sh_mipi_dsi_info { unsigned long flags; u32 clksrc; unsigned int vsynw_offset; + int (*set_dot_clock)(struct platform_device *pdev, + void __iomem *base, + int enable); }; #endif -- cgit v1.2.3 From a2e6297153f8fc7185d119c59d8eed1ee7d4c74f Mon Sep 17 00:00:00 2001 From: Kuninori Morimoto Date: Tue, 8 Nov 2011 20:35:27 -0800 Subject: fbdev: sh_mipi_dsi: add HSxxCLK support SH MIPI manual explains the calculation method of HBP/HFP. it is based on HSbyteCLK settings. SH73a0 chip can use HS6divCLK/HS4divCLK for it. This patch has compatibility to SH7372 mipi Signed-off-by: Kuninori Morimoto Acked-by: Magnus Damm Signed-off-by: Florian Tobias Schandinat --- arch/arm/mach-shmobile/board-ag5evm.c | 5 +++-- arch/arm/mach-shmobile/board-ap4evb.c | 3 ++- drivers/video/sh_mipi_dsi.c | 14 ++++++++++---- include/video/sh_mipi_dsi.h | 4 ++++ 4 files changed, 19 insertions(+), 7 deletions(-) (limited to 'arch/arm/mach-shmobile') diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 15072c51e035..7e3dd7326827 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -357,8 +357,9 @@ static struct sh_mipi_dsi_info mipidsi0_info = { .lane = 2, .vsynw_offset = 20, .clksrc = 1, - .flags = SH_MIPI_DSI_HSABM | - SH_MIPI_DSI_SYNC_PULSES_MODE, + .flags = SH_MIPI_DSI_HSABM | + SH_MIPI_DSI_SYNC_PULSES_MODE | + SH_MIPI_DSI_HSbyteCLK, .set_dot_clock = sh_mipi_set_dot_clock, }; diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 73503ed8bde2..904b608d1aa3 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -606,7 +606,8 @@ static struct sh_mipi_dsi_info mipidsi0_info = { .lcd_chan = &lcdc_info.ch[0], .lane = 2, .vsynw_offset = 17, - .flags = SH_MIPI_DSI_SYNC_PULSES_MODE, + .flags = SH_MIPI_DSI_SYNC_PULSES_MODE | + SH_MIPI_DSI_HSbyteCLK, .set_dot_clock = sh_mipi_set_dot_clock, }; diff --git a/drivers/video/sh_mipi_dsi.c b/drivers/video/sh_mipi_dsi.c index 77743f4388a0..b8aea8c60bc7 100644 --- a/drivers/video/sh_mipi_dsi.c +++ b/drivers/video/sh_mipi_dsi.c @@ -153,7 +153,7 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, void __iomem *base = mipi->base; struct sh_mobile_lcdc_chan_cfg *ch = pdata->lcd_chan; u32 pctype, datatype, pixfmt, linelength, vmctr2; - u32 tmp, top, bottom, delay; + u32 tmp, top, bottom, delay, div; bool yuv; int bpp; @@ -364,17 +364,23 @@ static int __init sh_mipi_setup(struct sh_mipi *mipi, bottom = 0x00000001; delay = 0; + div = 1; /* HSbyteCLK is calculation base + * HS4divCLK = HSbyteCLK/2 + * HS6divCLK is not supported for now */ + if (pdata->flags & SH_MIPI_DSI_HS4divCLK) + div = 2; + if (pdata->flags & SH_MIPI_DSI_HFPBM) { /* HBPLEN */ top = ch->lcd_cfg[0].hsync_len + ch->lcd_cfg[0].left_margin; - top = ((pdata->lane * top) - 10) << 16; + top = ((pdata->lane * top / div) - 10) << 16; } if (pdata->flags & SH_MIPI_DSI_HBPBM) { /* HFPLEN */ bottom = ch->lcd_cfg[0].right_margin; - bottom = (pdata->lane * bottom) - 12; + bottom = (pdata->lane * bottom / div) - 12; } bpp = linelength / ch->lcd_cfg[0].xres; /* byte / pixel */ - if (pdata->lane > bpp) { + if ((pdata->lane / div) > bpp) { tmp = ch->lcd_cfg[0].xres / bpp; /* output cycle */ tmp = ch->lcd_cfg[0].xres - tmp; /* (input - output) cycle */ delay = (pdata->lane * tmp); diff --git a/include/video/sh_mipi_dsi.h b/include/video/sh_mipi_dsi.h index 310b883bb312..434d56b4a1a5 100644 --- a/include/video/sh_mipi_dsi.h +++ b/include/video/sh_mipi_dsi.h @@ -35,6 +35,10 @@ struct sh_mobile_lcdc_chan_cfg; #define SH_MIPI_DSI_HSEE (1 << 5) #define SH_MIPI_DSI_HSAE (1 << 6) +#define SH_MIPI_DSI_HSbyteCLK (1 << 24) +#define SH_MIPI_DSI_HS6divCLK (1 << 25) +#define SH_MIPI_DSI_HS4divCLK (1 << 26) + #define SH_MIPI_DSI_SYNC_PULSES_MODE (SH_MIPI_DSI_VSEE | \ SH_MIPI_DSI_HSEE | \ SH_MIPI_DSI_HSAE) -- cgit v1.2.3 From edd153a3e4f7346551f98014b3ccf0494219a9d1 Mon Sep 17 00:00:00 2001 From: Laurent Pinchart Date: Tue, 13 Dec 2011 14:02:28 +0100 Subject: fbdev: sh_mobile_lcdc: Support FOURCC-based format API Signed-off-by: Laurent Pinchart Signed-off-by: Florian Tobias Schandinat --- arch/arm/mach-shmobile/board-ag5evm.c | 2 +- arch/arm/mach-shmobile/board-ap4evb.c | 4 +- arch/arm/mach-shmobile/board-mackerel.c | 4 +- arch/sh/boards/mach-ap325rxa/setup.c | 2 +- arch/sh/boards/mach-ecovec24/setup.c | 2 +- arch/sh/boards/mach-kfr2r09/setup.c | 2 +- arch/sh/boards/mach-migor/setup.c | 4 +- arch/sh/boards/mach-se/7724/setup.c | 2 +- drivers/video/sh_mobile_lcdcfb.c | 360 +++++++++++++++++++++----------- include/video/sh_mobile_lcdc.h | 4 +- 10 files changed, 253 insertions(+), 133 deletions(-) (limited to 'arch/arm/mach-shmobile') diff --git a/arch/arm/mach-shmobile/board-ag5evm.c b/arch/arm/mach-shmobile/board-ag5evm.c index 7e3dd7326827..80319f214765 100644 --- a/arch/arm/mach-shmobile/board-ag5evm.c +++ b/arch/arm/mach-shmobile/board-ag5evm.c @@ -271,7 +271,7 @@ static struct sh_mobile_lcdc_info lcdc0_info = { .flags = LCDC_FLAGS_DWPOL, .lcd_size_cfg.width = 44, .lcd_size_cfg.height = 79, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_cfg = lcdc0_modes, .num_cfg = ARRAY_SIZE(lcdc0_modes), .board_cfg = { diff --git a/arch/arm/mach-shmobile/board-ap4evb.c b/arch/arm/mach-shmobile/board-ap4evb.c index 904b608d1aa3..42b4dda57a79 100644 --- a/arch/arm/mach-shmobile/board-ap4evb.c +++ b/arch/arm/mach-shmobile/board-ap4evb.c @@ -491,7 +491,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .meram_dev = &meram_info, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_cfg = ap4evb_lcdc_modes, .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes), .meram_cfg = &lcd_meram_cfg, @@ -813,7 +813,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = { .meram_dev = &meram_info, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB24, .clock_divider = 1, .flags = LCDC_FLAGS_DWPOL, diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c index 9c5e598e0e3d..7db6a1712af5 100644 --- a/arch/arm/mach-shmobile/board-mackerel.c +++ b/arch/arm/mach-shmobile/board-mackerel.c @@ -388,7 +388,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_cfg = mackerel_lcdc_modes, .num_cfg = ARRAY_SIZE(mackerel_lcdc_modes), .interface_type = RGB24, @@ -451,7 +451,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB24, .clock_divider = 1, .flags = LCDC_FLAGS_DWPOL, diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c index 7030f4c8cf11..7977911e72cf 100644 --- a/arch/sh/boards/mach-ap325rxa/setup.c +++ b/arch/sh/boards/mach-ap325rxa/setup.c @@ -207,7 +207,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB18, .clock_divider = 1, .lcd_cfg = ap325rxa_lcdc_modes, diff --git a/arch/sh/boards/mach-ecovec24/setup.c b/arch/sh/boards/mach-ecovec24/setup.c index 92ddce4b3456..1d4a706ed6ef 100644 --- a/arch/sh/boards/mach-ecovec24/setup.c +++ b/arch/sh/boards/mach-ecovec24/setup.c @@ -330,7 +330,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .ch[0] = { .interface_type = RGB18, .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .lcd_size_cfg = { /* 7.0 inch */ .width = 152, .height = 91, diff --git a/arch/sh/boards/mach-kfr2r09/setup.c b/arch/sh/boards/mach-kfr2r09/setup.c index f65271a8d075..208c9b040263 100644 --- a/arch/sh/boards/mach-kfr2r09/setup.c +++ b/arch/sh/boards/mach-kfr2r09/setup.c @@ -146,7 +146,7 @@ static struct sh_mobile_lcdc_info kfr2r09_sh_lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = SYS18, .clock_divider = 6, .flags = LCDC_FLAGS_DWPOL, diff --git a/arch/sh/boards/mach-migor/setup.c b/arch/sh/boards/mach-migor/setup.c index e4c81195929c..ccf61fb99853 100644 --- a/arch/sh/boards/mach-migor/setup.c +++ b/arch/sh/boards/mach-migor/setup.c @@ -244,7 +244,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { .clock_source = LCDC_CLK_BUS, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = RGB16, .clock_divider = 2, .lcd_cfg = migor_lcd_modes, @@ -258,7 +258,7 @@ static struct sh_mobile_lcdc_info sh_mobile_lcdc_info = { .clock_source = LCDC_CLK_PERIPHERAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .interface_type = SYS16A, .clock_divider = 10, .lcd_cfg = migor_lcd_modes, diff --git a/arch/sh/boards/mach-se/7724/setup.c b/arch/sh/boards/mach-se/7724/setup.c index b747c0ab9264..3aab70cd39e3 100644 --- a/arch/sh/boards/mach-se/7724/setup.c +++ b/arch/sh/boards/mach-se/7724/setup.c @@ -179,7 +179,7 @@ static struct sh_mobile_lcdc_info lcdc_info = { .clock_source = LCDC_CLK_EXTERNAL, .ch[0] = { .chan = LCDC_CHAN_MAINLCD, - .bpp = 16, + .fourcc = V4L2_PIX_FMT_RGB565, .clock_divider = 1, .lcd_size_cfg = { /* 7.0 inch */ .width = 152, diff --git a/drivers/video/sh_mobile_lcdcfb.c b/drivers/video/sh_mobile_lcdcfb.c index a264ebf971a0..aac5b369d73c 100644 --- a/drivers/video/sh_mobile_lcdcfb.c +++ b/drivers/video/sh_mobile_lcdcfb.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -102,7 +103,7 @@ struct sh_mobile_lcdc_priv { struct sh_mobile_lcdc_chan ch[2]; struct notifier_block notifier; int started; - int forced_bpp; /* 2 channel LCDC must share bpp setting */ + int forced_fourcc; /* 2 channel LCDC must share fourcc setting */ struct sh_mobile_meram_info *meram_dev; }; @@ -215,6 +216,47 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = { lcdc_sys_read_data, }; +static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var) +{ + if (var->grayscale > 1) + return var->grayscale; + + switch (var->bits_per_pixel) { + case 16: + return V4L2_PIX_FMT_RGB565; + case 24: + return V4L2_PIX_FMT_BGR24; + case 32: + return V4L2_PIX_FMT_BGR32; + default: + return 0; + } +} + +static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var) +{ + return var->grayscale > 1; +} + +static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var) +{ + if (var->grayscale <= 1) + return false; + + switch (var->grayscale) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + return true; + + default: + return false; + } +} + static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv) { if (atomic_inc_and_test(&priv->hw_usecnt)) { @@ -435,7 +477,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) { struct sh_mobile_lcdc_chan *ch; unsigned long tmp; - int bpp = 0; int k, m; /* Enable LCDC channels. Read data from external memory, avoid using the @@ -454,9 +495,6 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) if (!ch->enabled) continue; - if (!bpp) - bpp = ch->info->var.bits_per_pixel; - /* Power supply */ lcdc_write_chan(ch, LDPMR, 0); @@ -487,31 +525,37 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) sh_mobile_lcdc_geometry(ch); - if (ch->info->var.nonstd) { - tmp = (ch->info->var.nonstd << 16); - switch (ch->info->var.bits_per_pixel) { - case 12: - tmp |= LDDFR_YF_420; - break; - case 16: - tmp |= LDDFR_YF_422; - break; - case 24: - default: - tmp |= LDDFR_YF_444; - break; - } - } else { - switch (ch->info->var.bits_per_pixel) { - case 16: - tmp = LDDFR_PKF_RGB16; - break; - case 24: - tmp = LDDFR_PKF_RGB24; + switch (sh_mobile_format_fourcc(&ch->info->var)) { + case V4L2_PIX_FMT_RGB565: + tmp = LDDFR_PKF_RGB16; + break; + case V4L2_PIX_FMT_BGR24: + tmp = LDDFR_PKF_RGB24; + break; + case V4L2_PIX_FMT_BGR32: + tmp = LDDFR_PKF_ARGB32; + break; + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + tmp = LDDFR_CC | LDDFR_YF_420; + break; + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + tmp = LDDFR_CC | LDDFR_YF_422; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + tmp = LDDFR_CC | LDDFR_YF_444; + break; + } + + if (sh_mobile_format_is_yuv(&ch->info->var)) { + switch (ch->info->var.colorspace) { + case V4L2_COLORSPACE_REC709: + tmp |= LDDFR_CF1; break; - case 32: - default: - tmp = LDDFR_PKF_ARGB32; + case V4L2_COLORSPACE_JPEG: + tmp |= LDDFR_CF0; break; } } @@ -519,7 +563,7 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) lcdc_write_chan(ch, LDDFR, tmp); lcdc_write_chan(ch, LDMLSR, ch->pitch); lcdc_write_chan(ch, LDSA1R, ch->base_addr_y); - if (ch->info->var.nonstd) + if (sh_mobile_format_is_yuv(&ch->info->var)) lcdc_write_chan(ch, LDSA2R, ch->base_addr_c); /* When using deferred I/O mode, configure the LCDC for one-shot @@ -536,21 +580,23 @@ static void __sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) } /* Word and long word swap. */ - if (priv->ch[0].info->var.nonstd) + switch (sh_mobile_format_fourcc(&priv->ch[0].info->var)) { + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV61: + case V4L2_PIX_FMT_NV42: + tmp = LDDDSR_LS | LDDDSR_WS; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV24: tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - else { - switch (bpp) { - case 16: - tmp = LDDDSR_LS | LDDDSR_WS; - break; - case 24: - tmp = LDDDSR_LS | LDDDSR_WS | LDDDSR_BS; - break; - case 32: - default: - tmp = LDDDSR_LS; - break; - } + break; + case V4L2_PIX_FMT_BGR32: + default: + tmp = LDDDSR_LS; + break; } lcdc_write(priv, _LDDDSR, tmp); @@ -622,12 +668,24 @@ static int sh_mobile_lcdc_start(struct sh_mobile_lcdc_priv *priv) ch->meram_enabled = 0; } - if (!ch->info->var.nonstd) - pixelformat = SH_MOBILE_MERAM_PF_RGB; - else if (ch->info->var.bits_per_pixel == 24) - pixelformat = SH_MOBILE_MERAM_PF_NV24; - else + switch (sh_mobile_format_fourcc(&ch->info->var)) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: pixelformat = SH_MOBILE_MERAM_PF_NV; + break; + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + pixelformat = SH_MOBILE_MERAM_PF_NV24; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_BGR32: + default: + pixelformat = SH_MOBILE_MERAM_PF_RGB; + break; + } ret = mdev->ops->meram_register(mdev, cfg, ch->pitch, ch->info->var.yres, pixelformat, @@ -845,6 +903,7 @@ static struct fb_fix_screeninfo sh_mobile_lcdc_fix = { .xpanstep = 0, .ypanstep = 1, .ywrapstep = 0, + .capabilities = FB_CAP_FOURCC, }; static void sh_mobile_lcdc_fillrect(struct fb_info *info, @@ -877,8 +936,9 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, unsigned long new_pan_offset; unsigned long base_addr_y, base_addr_c; unsigned long c_offset; + bool yuv = sh_mobile_format_is_yuv(&info->var); - if (!info->var.nonstd) + if (!yuv) new_pan_offset = var->yoffset * info->fix.line_length + var->xoffset * (info->var.bits_per_pixel / 8); else @@ -892,7 +952,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, /* Set the source address for the next refresh */ base_addr_y = ch->dma_handle + new_pan_offset; - if (info->var.nonstd) { + if (yuv) { /* Set y offset */ c_offset = var->yoffset * info->fix.line_length * (info->var.bits_per_pixel - 8) / 8; @@ -900,7 +960,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, + info->var.xres * info->var.yres_virtual + c_offset; /* Set x offset */ - if (info->var.bits_per_pixel == 24) + if (sh_mobile_format_fourcc(&info->var) == V4L2_PIX_FMT_NV24) base_addr_c += 2 * var->xoffset; else base_addr_c += var->xoffset; @@ -924,7 +984,7 @@ static int sh_mobile_fb_pan_display(struct fb_var_screeninfo *var, ch->base_addr_c = base_addr_c; lcdc_write_chan_mirror(ch, LDSA1R, base_addr_y); - if (info->var.nonstd) + if (yuv) lcdc_write_chan_mirror(ch, LDSA2R, base_addr_c); if (lcdc_chan_is_sublcd(ch)) @@ -1100,51 +1160,84 @@ static int sh_mobile_check_var(struct fb_var_screeninfo *var, struct fb_info *in if (var->yres_virtual < var->yres) var->yres_virtual = var->yres; - if (var->bits_per_pixel <= 16) { /* RGB 565 */ - var->bits_per_pixel = 16; - var->red.offset = 11; - var->red.length = 5; - var->green.offset = 5; - var->green.length = 6; - var->blue.offset = 0; - var->blue.length = 5; - var->transp.offset = 0; - var->transp.length = 0; - } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ - var->bits_per_pixel = 24; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 0; - var->transp.length = 0; - } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ - var->bits_per_pixel = 32; - var->red.offset = 16; - var->red.length = 8; - var->green.offset = 8; - var->green.length = 8; - var->blue.offset = 0; - var->blue.length = 8; - var->transp.offset = 24; - var->transp.length = 8; - } else - return -EINVAL; + if (sh_mobile_format_is_fourcc(var)) { + switch (var->grayscale) { + case V4L2_PIX_FMT_NV12: + case V4L2_PIX_FMT_NV21: + var->bits_per_pixel = 12; + break; + case V4L2_PIX_FMT_RGB565: + case V4L2_PIX_FMT_NV16: + case V4L2_PIX_FMT_NV61: + var->bits_per_pixel = 16; + break; + case V4L2_PIX_FMT_BGR24: + case V4L2_PIX_FMT_NV24: + case V4L2_PIX_FMT_NV42: + var->bits_per_pixel = 24; + break; + case V4L2_PIX_FMT_BGR32: + var->bits_per_pixel = 32; + break; + default: + return -EINVAL; + } + + /* Default to RGB and JPEG color-spaces for RGB and YUV formats + * respectively. + */ + if (!sh_mobile_format_is_yuv(var)) + var->colorspace = V4L2_COLORSPACE_SRGB; + else if (var->colorspace != V4L2_COLORSPACE_REC709) + var->colorspace = V4L2_COLORSPACE_JPEG; + } else { + if (var->bits_per_pixel <= 16) { /* RGB 565 */ + var->bits_per_pixel = 16; + var->red.offset = 11; + var->red.length = 5; + var->green.offset = 5; + var->green.length = 6; + var->blue.offset = 0; + var->blue.length = 5; + var->transp.offset = 0; + var->transp.length = 0; + } else if (var->bits_per_pixel <= 24) { /* RGB 888 */ + var->bits_per_pixel = 24; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 0; + var->transp.length = 0; + } else if (var->bits_per_pixel <= 32) { /* RGBA 888 */ + var->bits_per_pixel = 32; + var->red.offset = 16; + var->red.length = 8; + var->green.offset = 8; + var->green.length = 8; + var->blue.offset = 0; + var->blue.length = 8; + var->transp.offset = 24; + var->transp.length = 8; + } else + return -EINVAL; - var->red.msb_right = 0; - var->green.msb_right = 0; - var->blue.msb_right = 0; - var->transp.msb_right = 0; + var->red.msb_right = 0; + var->green.msb_right = 0; + var->blue.msb_right = 0; + var->transp.msb_right = 0; + } /* Make sure we don't exceed our allocated memory. */ if (var->xres_virtual * var->yres_virtual * var->bits_per_pixel / 8 > info->fix.smem_len) return -EINVAL; - /* only accept the forced_bpp for dual channel configurations */ - if (p->forced_bpp && p->forced_bpp != var->bits_per_pixel) + /* only accept the forced_fourcc for dual channel configurations */ + if (p->forced_fourcc && + p->forced_fourcc != sh_mobile_format_fourcc(var)) return -EINVAL; return 0; @@ -1158,7 +1251,7 @@ static int sh_mobile_set_par(struct fb_info *info) sh_mobile_lcdc_stop(ch->lcdc); - if (info->var.nonstd) + if (sh_mobile_format_is_yuv(&info->var)) info->fix.line_length = info->var.xres; else info->fix.line_length = info->var.xres @@ -1170,6 +1263,14 @@ static int sh_mobile_set_par(struct fb_info *info) info->fix.line_length = line_length; } + if (sh_mobile_format_is_fourcc(&info->var)) { + info->fix.type = FB_TYPE_FOURCC; + info->fix.visual = FB_VISUAL_FOURCC; + } else { + info->fix.type = FB_TYPE_PACKED_PIXELS; + info->fix.visual = FB_VISUAL_TRUECOLOR; + } + return ret; } @@ -1464,9 +1565,9 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, for (i = 0, mode = cfg->lcd_cfg; i < cfg->num_cfg; i++, mode++) { unsigned int size = mode->yres * mode->xres; - /* NV12 buffers must have even number of lines */ - if ((cfg->nonstd) && cfg->bpp == 12 && - (mode->yres & 0x1)) { + /* NV12/NV21 buffers must have even number of lines */ + if ((cfg->fourcc == V4L2_PIX_FMT_NV12 || + cfg->fourcc == V4L2_PIX_FMT_NV21) && (mode->yres & 0x1)) { dev_err(dev, "yres must be multiple of 2 for YCbCr420 " "mode.\n"); return -EINVAL; @@ -1484,14 +1585,6 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, dev_dbg(dev, "Found largest videomode %ux%u\n", max_mode->xres, max_mode->yres); - /* Initialize fixed screen information. Restrict pan to 2 lines steps - * for NV12. - */ - info->fix = sh_mobile_lcdc_fix; - info->fix.smem_len = max_size * 2 * cfg->bpp / 8; - if (cfg->nonstd && cfg->bpp == 12) - info->fix.ypanstep = 2; - /* Create the mode list. */ if (cfg->lcd_cfg == NULL) { mode = &default_720p; @@ -1509,19 +1602,38 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, */ var = &info->var; fb_videomode_to_var(var, mode); - var->bits_per_pixel = cfg->bpp; var->width = cfg->lcd_size_cfg.width; var->height = cfg->lcd_size_cfg.height; var->yres_virtual = var->yres * 2; var->activate = FB_ACTIVATE_NOW; + switch (cfg->fourcc) { + case V4L2_PIX_FMT_RGB565: + var->bits_per_pixel = 16; + break; + case V4L2_PIX_FMT_BGR24: + var->bits_per_pixel = 24; + break; + case V4L2_PIX_FMT_BGR32: + var->bits_per_pixel = 32; + break; + default: + var->grayscale = cfg->fourcc; + break; + } + + /* Make sure the memory size check won't fail. smem_len is initialized + * later based on var. + */ + info->fix.smem_len = UINT_MAX; ret = sh_mobile_check_var(var, info); if (ret) return ret; + max_size = max_size * var->bits_per_pixel / 8 * 2; + /* Allocate frame buffer memory and color map. */ - buf = dma_alloc_coherent(dev, info->fix.smem_len, &ch->dma_handle, - GFP_KERNEL); + buf = dma_alloc_coherent(dev, max_size, &ch->dma_handle, GFP_KERNEL); if (!buf) { dev_err(dev, "unable to allocate buffer\n"); return -ENOMEM; @@ -1530,16 +1642,27 @@ static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch, ret = fb_alloc_cmap(&info->cmap, PALETTE_NR, 0); if (ret < 0) { dev_err(dev, "unable to allocate cmap\n"); - dma_free_coherent(dev, info->fix.smem_len, - buf, ch->dma_handle); + dma_free_coherent(dev, max_size, buf, ch->dma_handle); return ret; } + /* Initialize fixed screen information. Restrict pan to 2 lines steps + * for NV12 and NV21. + */ + info->fix = sh_mobile_lcdc_fix; info->fix.smem_start = ch->dma_handle; - if (var->nonstd) + info->fix.smem_len = max_size; + if (cfg->fourcc == V4L2_PIX_FMT_NV12 || + cfg->fourcc == V4L2_PIX_FMT_NV21) + info->fix.ypanstep = 2; + + if (sh_mobile_format_is_yuv(var)) { info->fix.line_length = var->xres; - else - info->fix.line_length = var->xres * (cfg->bpp / 8); + info->fix.visual = FB_VISUAL_FOURCC; + } else { + info->fix.line_length = var->xres * var->bits_per_pixel / 8; + info->fix.visual = FB_VISUAL_TRUECOLOR; + } info->screen_base = buf; info->device = dev; @@ -1626,9 +1749,9 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) goto err1; } - /* for dual channel LCDC (MAIN + SUB) force shared bpp setting */ + /* for dual channel LCDC (MAIN + SUB) force shared format setting */ if (num_channels == 2) - priv->forced_bpp = pdata->ch[0].bpp; + priv->forced_fourcc = pdata->ch[0].fourcc; priv->base = ioremap_nocache(res->start, resource_size(res)); if (!priv->base) @@ -1675,13 +1798,10 @@ static int __devinit sh_mobile_lcdc_probe(struct platform_device *pdev) if (error < 0) goto err1; - dev_info(info->dev, - "registered %s/%s as %dx%d %dbpp.\n", - pdev->name, - (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? - "mainlcd" : "sublcd", - info->var.xres, info->var.yres, - ch->cfg.bpp); + dev_info(info->dev, "registered %s/%s as %dx%d %dbpp.\n", + pdev->name, (ch->cfg.chan == LCDC_CHAN_MAINLCD) ? + "mainlcd" : "sublcd", info->var.xres, info->var.yres, + info->var.bits_per_pixel); /* deferred io mode: disable clock to save power */ if (info->fbdefio || info->state == FBINFO_STATE_SUSPENDED) diff --git a/include/video/sh_mobile_lcdc.h b/include/video/sh_mobile_lcdc.h index 8101b726b48a..fe30b759c51e 100644 --- a/include/video/sh_mobile_lcdc.h +++ b/include/video/sh_mobile_lcdc.h @@ -174,7 +174,8 @@ struct sh_mobile_lcdc_bl_info { struct sh_mobile_lcdc_chan_cfg { int chan; - int bpp; + int fourcc; + int colorspace; int interface_type; /* selects RGBn or SYSn I/F, see above */ int clock_divider; unsigned long flags; /* LCDC_FLAGS_... */ @@ -184,7 +185,6 @@ struct sh_mobile_lcdc_chan_cfg { struct sh_mobile_lcdc_board_cfg board_cfg; struct sh_mobile_lcdc_bl_info bl_info; struct sh_mobile_lcdc_sys_bus_cfg sys_bus_cfg; /* only for SYSn I/F */ - int nonstd; struct sh_mobile_meram_cfg *meram_cfg; }; -- cgit v1.2.3