* [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This series contain DCU framebuffer driver for Freescale Vybrid VF610 platform. The Display Controller Unit (DCU) module is a system master that fetches graphics stored in internal or external memory and displays them on a TFT LCD panel. A wide range of panel sizes is supported and the timing of the interface signals is highly configurable. Graphics are read directly from memory and then blended in real-time, which allows for dynamic content creation with minimal CPU intervention. The features: (1) Full RGB888 output to TFT LCD panel. (2) For the current LCD panel, WQVGA "480x272" is tested. (3) Blending of each pixel using up to 4 source layers dependent on size of panel. (4) Each graphic layer can be placed with one pixel resolution in either axis. (5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel and BGRA8888 direct colors with an alpha channel. (6) Each graphic layer support alpha blending with 8-bit resolution. Changes in v2: - Add a document for DCU framebuffer driver under Documentation/devicetree/bindings/fb/. ---------------------------------------------------------------- Alison Wang (5): ARM: dts: vf610: Add DCU and TCON nodes ARM: dts: vf610-twr: Enable DCU and TCON devices ARM: clk: vf610: Add DCU and TCON clock support fb: Add DCU framebuffer driver for Vybrid VF610 platform Documentation: DT: Add DCU framebuffer driver Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++ arch/arm/boot/dts/vf610-twr.dts | 10 + arch/arm/boot/dts/vf610.dtsi | 19 +- arch/arm/mach-imx/clk-vf610.c | 5 + drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/vf610-clock.h | 3 +- 8 files changed, 1172 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt create mode 100644 drivers/video/fsl-dcu-fb.c ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This series contain DCU framebuffer driver for Freescale Vybrid VF610 platform. The Display Controller Unit (DCU) module is a system master that fetches graphics stored in internal or external memory and displays them on a TFT LCD panel. A wide range of panel sizes is supported and the timing of the interface signals is highly configurable. Graphics are read directly from memory and then blended in real-time, which allows for dynamic content creation with minimal CPU intervention. The features: (1) Full RGB888 output to TFT LCD panel. (2) For the current LCD panel, WQVGA "480x272" is tested. (3) Blending of each pixel using up to 4 source layers dependent on size of panel. (4) Each graphic layer can be placed with one pixel resolution in either axis. (5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel and BGRA8888 direct colors with an alpha channel. (6) Each graphic layer support alpha blending with 8-bit resolution. Changes in v2: - Add a document for DCU framebuffer driver under Documentation/devicetree/bindings/fb/. ---------------------------------------------------------------- Alison Wang (5): ARM: dts: vf610: Add DCU and TCON nodes ARM: dts: vf610-twr: Enable DCU and TCON devices ARM: clk: vf610: Add DCU and TCON clock support fb: Add DCU framebuffer driver for Vybrid VF610 platform Documentation: DT: Add DCU framebuffer driver Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++ arch/arm/boot/dts/vf610-twr.dts | 10 + arch/arm/boot/dts/vf610.dtsi | 19 +- arch/arm/mach-imx/clk-vf610.c | 5 + drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/dt-bindings/clock/vf610-clock.h | 3 +- 8 files changed, 1172 insertions(+), 2 deletions(-) create mode 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt create mode 100644 drivers/video/fsl-dcu-fb.c ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 1/5] ARM: dts: vf610: Add DCU and TCON nodes 2013-07-12 6:07 ` Alison Wang @ 2013-07-12 6:07 ` Alison Wang -1 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch adds DCU and TCON nodes in SoC level DTS for Freescale Vybrid VF610. It also removes useless pin for DCU0 pinctrl. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None arch/arm/boot/dts/vf610.dtsi | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index e1eb7da..037e8f1 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -140,6 +140,14 @@ clock-names = "pit"; }; + tcon0: tcon@4003d000 { + compatible = "fsl,vf610-tcon"; + reg = <0x4003d000 0x1000>; + clocks = <&clks VF610_CLK_TCON0>; + clock-names = "tcon"; + status = "disabled"; + }; + wdog@4003e000 { compatible = "fsl,vf610-wdt", "fsl,imx21-wdt"; reg = <0x4003e000 0x1000>; @@ -169,7 +177,6 @@ dcu0 { pinctrl_dcu0_1: dcu0grp_1 { fsl,pins = < - VF610_PAD_PTB8__GPIO_30 0x42 VF610_PAD_PTE0__DCU0_HSYNC 0x42 VF610_PAD_PTE1__DCU0_VSYNC 0x42 VF610_PAD_PTE2__DCU0_PCLK 0x42 @@ -395,6 +402,16 @@ reg = <0x40050000 0x1000>; }; + dcu0: dcu@40058000 { + compatible = "fsl,vf610-dcu"; + reg = <0x40058000 0x1200>; + interrupts = <0 30 0x04>; + clocks = <&clks VF610_CLK_DCU0>; + clock-names = "dcu"; + tcon-controller = <&tcon0>; + status = "disabled"; + }; + i2c0: i2c@40066000 { #address-cells = <1>; #size-cells = <0>; -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 1/5] ARM: dts: vf610: Add DCU and TCON nodes @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch adds DCU and TCON nodes in SoC level DTS for Freescale Vybrid VF610. It also removes useless pin for DCU0 pinctrl. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None arch/arm/boot/dts/vf610.dtsi | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi index e1eb7da..037e8f1 100644 --- a/arch/arm/boot/dts/vf610.dtsi +++ b/arch/arm/boot/dts/vf610.dtsi @@ -140,6 +140,14 @@ clock-names = "pit"; }; + tcon0: tcon at 4003d000 { + compatible = "fsl,vf610-tcon"; + reg = <0x4003d000 0x1000>; + clocks = <&clks VF610_CLK_TCON0>; + clock-names = "tcon"; + status = "disabled"; + }; + wdog at 4003e000 { compatible = "fsl,vf610-wdt", "fsl,imx21-wdt"; reg = <0x4003e000 0x1000>; @@ -169,7 +177,6 @@ dcu0 { pinctrl_dcu0_1: dcu0grp_1 { fsl,pins = < - VF610_PAD_PTB8__GPIO_30 0x42 VF610_PAD_PTE0__DCU0_HSYNC 0x42 VF610_PAD_PTE1__DCU0_VSYNC 0x42 VF610_PAD_PTE2__DCU0_PCLK 0x42 @@ -395,6 +402,16 @@ reg = <0x40050000 0x1000>; }; + dcu0: dcu at 40058000 { + compatible = "fsl,vf610-dcu"; + reg = <0x40058000 0x1200>; + interrupts = <0 30 0x04>; + clocks = <&clks VF610_CLK_DCU0>; + clock-names = "dcu"; + tcon-controller = <&tcon0>; + status = "disabled"; + }; + i2c0: i2c at 40066000 { #address-cells = <1>; #size-cells = <0>; -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 2/5] ARM: dts: vf610-twr: Enable DCU and TCON devices 2013-07-12 6:07 ` Alison Wang @ 2013-07-12 6:07 ` Alison Wang -1 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch enables DCU and TCON devices for Vybrid VF610 TOWER board. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None arch/arm/boot/dts/vf610-twr.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts index b3905f5..605fb04 100644 --- a/arch/arm/boot/dts/vf610-twr.dts +++ b/arch/arm/boot/dts/vf610-twr.dts @@ -36,6 +36,12 @@ }; +&dcu0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dcu0_1>; + status = "okay"; +}; + &fec0 { phy-mode = "rmii"; pinctrl-names = "default"; @@ -50,6 +56,10 @@ status = "okay"; }; +&tcon0 { + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1_1>; -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 2/5] ARM: dts: vf610-twr: Enable DCU and TCON devices @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch enables DCU and TCON devices for Vybrid VF610 TOWER board. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None arch/arm/boot/dts/vf610-twr.dts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts index b3905f5..605fb04 100644 --- a/arch/arm/boot/dts/vf610-twr.dts +++ b/arch/arm/boot/dts/vf610-twr.dts @@ -36,6 +36,12 @@ }; +&dcu0 { + pinctrl-names = "default"; + pinctrl-0 = <&pinctrl_dcu0_1>; + status = "okay"; +}; + &fec0 { phy-mode = "rmii"; pinctrl-names = "default"; @@ -50,6 +56,10 @@ status = "okay"; }; +&tcon0 { + status = "okay"; +}; + &uart1 { pinctrl-names = "default"; pinctrl-0 = <&pinctrl_uart1_1>; -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 3/5] ARM: clk: vf610: Add DCU and TCON clock support 2013-07-12 6:07 ` Alison Wang @ 2013-07-12 6:07 ` Alison Wang -1 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch adds DCU and TCON clock support for Vybrid VF610 platform. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None arch/arm/mach-imx/clk-vf610.c | 5 +++++ include/dt-bindings/clock/vf610-clock.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c index d617c0b..c4dbe32 100644 --- a/arch/arm/mach-imx/clk-vf610.c +++ b/arch/arm/mach-imx/clk-vf610.c @@ -245,6 +245,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3); clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4); clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30); clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4); @@ -311,6 +313,9 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]); clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]); + clk_set_parent(clk[VF610_CLK_DCU0_SEL], clk[VF610_CLK_PLL1_PFD2]); + clk_set_rate(clk[VF610_CLK_DCU0_DIV], 113200000); + /* Add the clocks to provider list */ clk_data.clks = clk; clk_data.clk_num = ARRAY_SIZE(clk); diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index 15e997f..a2fc6d9 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -158,6 +158,7 @@ #define VF610_CLK_GPU_SEL 145 #define VF610_CLK_GPU_EN 146 #define VF610_CLK_GPU2D 147 -#define VF610_CLK_END 148 +#define VF610_CLK_TCON0 148 +#define VF610_CLK_END 149 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 3/5] ARM: clk: vf610: Add DCU and TCON clock support @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch adds DCU and TCON clock support for Vybrid VF610 platform. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None arch/arm/mach-imx/clk-vf610.c | 5 +++++ include/dt-bindings/clock/vf610-clock.h | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c index d617c0b..c4dbe32 100644 --- a/arch/arm/mach-imx/clk-vf610.c +++ b/arch/arm/mach-imx/clk-vf610.c @@ -245,6 +245,8 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk[VF610_CLK_DCU1_DIV] = imx_clk_divider("dcu1_div", "dcu1_en", CCM_CSCDR3, 20, 3); clk[VF610_CLK_DCU1] = imx_clk_gate2("dcu1", "dcu1_div", CCM_CCGR9, CCM_CCGRx_CGn(8)); + clk[VF610_CLK_TCON0] = imx_clk_gate2("tcon0", "platform_bus", CCM_CCGR1, CCM_CCGRx_CGn(13)); + clk[VF610_CLK_ESAI_SEL] = imx_clk_mux("esai_sel", CCM_CSCMR1, 20, 2, esai_sels, 4); clk[VF610_CLK_ESAI_EN] = imx_clk_gate("esai_en", "esai_sel", CCM_CSCDR2, 30); clk[VF610_CLK_ESAI_DIV] = imx_clk_divider("esai_div", "esai_en", CCM_CSCDR2, 24, 4); @@ -311,6 +313,9 @@ static void __init vf610_clocks_init(struct device_node *ccm_node) clk_set_parent(clk[VF610_CLK_SAI2_SEL], clk[VF610_CLK_AUDIO_EXT]); clk_set_parent(clk[VF610_CLK_SAI3_SEL], clk[VF610_CLK_AUDIO_EXT]); + clk_set_parent(clk[VF610_CLK_DCU0_SEL], clk[VF610_CLK_PLL1_PFD2]); + clk_set_rate(clk[VF610_CLK_DCU0_DIV], 113200000); + /* Add the clocks to provider list */ clk_data.clks = clk; clk_data.clk_num = ARRAY_SIZE(clk); diff --git a/include/dt-bindings/clock/vf610-clock.h b/include/dt-bindings/clock/vf610-clock.h index 15e997f..a2fc6d9 100644 --- a/include/dt-bindings/clock/vf610-clock.h +++ b/include/dt-bindings/clock/vf610-clock.h @@ -158,6 +158,7 @@ #define VF610_CLK_GPU_SEL 145 #define VF610_CLK_GPU_EN 146 #define VF610_CLK_GPU2D 147 -#define VF610_CLK_END 148 +#define VF610_CLK_TCON0 148 +#define VF610_CLK_END 149 #endif /* __DT_BINDINGS_CLOCK_VF610_H */ -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-12 6:07 ` Alison Wang @ 2013-07-12 6:07 ` Alison Wang -1 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel The Display Controller Unit (DCU) module is a system master that fetches graphics stored in internal or external memory and displays them on a TFT LCD panel. A wide range of panel sizes is supported and the timing of the interface signals is highly configurable. Graphics are read directly from memory and then blended in real-time, which allows for dynamic content creation with minimal CPU intervention. The features: (1) Full RGB888 output to TFT LCD panel. (2) For the current LCD panel, WQVGA "480x272" is tested. (3) Blending of each pixel using up to 4 source layers dependent on size of panel. (4) Each graphic layer can be placed with one pixel resolution in either axis. (5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel and BGRA8888 direct colors with an alpha channel. (6) Each graphic layer support alpha blending with 8-bit resolution. This driver has been tested on Vybrid VF610 TOWER board. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1101 insertions(+) create mode 100644 drivers/video/fsl-dcu-fb.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 46544d0..32dc1f8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1978,6 +1978,15 @@ config FB_FSL_DIU ---help--- Framebuffer driver for the Freescale SoC DIU +config FB_FSL_DCU + tristate "Freescale DCU framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Framebuffer driver for the Freescale SoC DCU + config FB_W100 tristate "W100 frame buffer support" depends on FB && ARCH_PXA diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e8bae8d..3707a7d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -129,6 +129,7 @@ obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C) += s3c-fb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o +obj-$(CONFIG_FB_FSL_DCU) += fsl-dcu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o diff --git a/drivers/video/fsl-dcu-fb.c b/drivers/video/fsl-dcu-fb.c new file mode 100644 index 0000000..5571dde --- /dev/null +++ b/drivers/video/fsl-dcu-fb.c @@ -0,0 +1,1091 @@ +/* + * Copyright 2012-2013 Freescale Semiconductor, Inc. + * + * Freescale DCU Frame Buffer device driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/uaccess.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#define DRIVER_NAME "fsl-dcu-fb" + +#define DCU_DCU_MODE 0x0010 +#define DCU_MODE_BLEND_ITER(x) (x << 20) +#define DCU_MODE_RASTER_EN (1 << 14) +#define DCU_MODE_DCU_MODE(x) (x) +#define DCU_MODE_DCU_MODE_MASK 0x03 +#define DCU_MODE_OFF 0 +#define DCU_MODE_NORMAL 1 +#define DCU_MODE_TEST 2 +#define DCU_MODE_COLORBAR 3 + +#define DCU_BGND 0x0014 +#define DCU_BGND_R(x) (x << 16) +#define DCU_BGND_G(x) (x << 8) +#define DCU_BGND_B(x) (x) + +#define DCU_DISP_SIZE 0x0018 +#define DCU_DISP_SIZE_DELTA_Y(x) (x << 16) +#define DCU_DISP_SIZE_DELTA_X(x) (x) + +#define DCU_HSYN_PARA 0x001c +#define DCU_HSYN_PARA_BP(x) (x << 22) +#define DCU_HSYN_PARA_PW(x) (x << 11) +#define DCU_HSYN_PARA_FP(x) (x) + +#define DCU_VSYN_PARA 0x0020 +#define DCU_VSYN_PARA_BP(x) (x << 22) +#define DCU_VSYN_PARA_PW(x) (x << 11) +#define DCU_VSYN_PARA_FP(x) (x) + +#define DCU_SYN_POL 0x0024 +#define DCU_SYN_POL_INV_PXCK_FALL (0 << 6) +#define DCU_SYN_POL_NEG_REMAIN (0 << 5) +#define DCU_SYN_POL_INV_VS_LOW (1 << 1) +#define DCU_SYN_POL_INV_HS_LOW (1) + +#define DCU_THRESHOLD 0x0028 +#define DCU_THRESHOLD_LS_BF_VS(x) (x << 16) +#define DCU_THRESHOLD_OUT_BUF_HIGH(x) (x << 8) +#define DCU_THRESHOLD_OUT_BUF_LOW(x) (x) + +#define DCU_INT_STATUS 0x002C +#define DCU_INT_STATUS_UNDRUN (1 << 1) + +#define DCU_INT_MASK 0x0030 +#define DCU_INT_MASK_UNDRUN (1 << 1) + +#define DCU_DIV_RATIO 0x0054 + +#define DCU_UPDATE_MODE 0x00cc +#define DCU_UPDATE_MODE_MODE (1 << 31) +#define DCU_UPDATE_MODE_READREG (1 << 30) + +#define DCU_CTRLDESCLN_1(x) (0x200 + (x) * 0x40) +#define DCU_CTRLDESCLN_1_HEIGHT(x) (x << 16) +#define DCU_CTRLDESCLN_1_WIDTH(x) (x) + +#define DCU_CTRLDESCLN_2(x) (0x204 + (x) * 0x40) +#define DCU_CTRLDESCLN_2_POSY(x) (x << 16) +#define DCU_CTRLDESCLN_2_POSX(x) (x) + +#define DCU_CTRLDESCLN_3(x) (0x208 + (x) * 0x40) + +#define DCU_CTRLDESCLN_4(x) (0x20c + (x) * 0x40) +#define DCU_CTRLDESCLN_4_EN (1 << 31) +#define DCU_CTRLDESCLN_4_TILE_EN (1 << 30) +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT (1 << 29) +#define DCU_CTRLDESCLN_4_SAFETY_EN (1 << 28) +#define DCU_CTRLDESCLN_4_TRANS(x) (x << 20) +#define DCU_CTRLDESCLN_4_BPP(x) (x << 16) +#define DCU_CTRLDESCLN_4_RLE_EN (1 << 15) +#define DCU_CTRLDESCLN_4_LUOFFS(x) (x << 4) +#define DCU_CTRLDESCLN_4_BB_ON (1 << 2) +#define DCU_CTRLDESCLN_4_AB(x) (x) + +#define DCU_CTRLDESCLN_5(x) (0x210 + (x) * 0x40) +#define DCU_CTRLDESCLN_5_CKMAX_R(x) (x << 16) +#define DCU_CTRLDESCLN_5_CKMAX_G(x) (x << 8) +#define DCU_CTRLDESCLN_5_CKMAX_B(x) (x) + +#define DCU_CTRLDESCLN_6(x) (0x214 + (x) * 0x40) +#define DCU_CTRLDESCLN_6_CKMIN_R(x) (x << 16) +#define DCU_CTRLDESCLN_6_CKMIN_G(x) (x << 8) +#define DCU_CTRLDESCLN_6_CKMIN_B(x) (x) + +#define DCU_CTRLDESCLN_7(x) (0x218 + (x) * 0x40) +#define DCU_CTRLDESCLN_7_TILE_VER(x) (x << 16) +#define DCU_CTRLDESCLN_7_TILE_HOR(x) (x) + +#define DCU_CTRLDESCLN_8(x) (0x21c + (x) * 0x40) +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x) (x) + +#define DCU_CTRLDESCLN_9(x) (0x220 + (x) * 0x40) +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x) (x) + +#define DCU_TOTAL_LAYER_NUM 64 +#define DCU_LAYER_NUM_MAX 6 +#define DCU_LAYER_NUM 4 + +#define BPP_16_RGB565 4 +#define BPP_24_RGB888 5 +#define BPP_32_ARGB8888 6 + +#define TCON_CTRL1 0x0000 +#define TCON_BYPASS_ENABLE (1 << 29) + +#define MFB_SET_ALPHA _IOW('M', 0, __u8) +#define MFB_GET_ALPHA _IOR('M', 0, __u8) +#define MFB_SET_LAYER _IOW('M', 4, struct layer_display_offset) +#define MFB_GET_LAYER _IOR('M', 4, struct layer_display_offset) + +static char *fb_mode; +static unsigned int default_bpp = 24; + +static struct fb_videomode dcu_mode_db[] = { + { + .name = "480x272", + .refresh = 75, + .xres = 480, + .yres = 272, + .pixclock = 91996, + .left_margin = 2, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 1, + .hsync_len = 41, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; + +/* DCU framebuffer data structure */ +struct dcu_fb_data { + struct fb_info *fsl_dcu_info[DCU_LAYER_NUM]; + void __iomem *reg_base; + unsigned int irq; + struct clk *clk; +}; + +struct layer_display_offset { + int x_layer_d; + int y_layer_d; +}; + +struct mfb_info { + int index; + char *id; + unsigned long pseudo_palette[16]; + unsigned char alpha; + unsigned char blend; + unsigned int count; + int x_layer_d; /* layer display x offset to physical screen */ + int y_layer_d; /* layer display y offset to physical screen */ + struct dcu_fb_data *parent; +}; + +enum mfb_index { + LAYER0 = 0, + LAYER1, + LAYER2, + LAYER3, +}; + +static struct mfb_info mfb_template[] = { + { + .index = LAYER0, + .id = "Layer0", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 0, + .y_layer_d = 0, + }, + { + .index = LAYER1, + .id = "Layer1", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 50, + .y_layer_d = 50, + }, + { + .index = LAYER2, + .id = "Layer2", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 100, + .y_layer_d = 100, + }, + { + .index = LAYER3, + .id = "Layer3", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 150, + .y_layer_d = 150, + }, +}; + +static int enable_panel(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned int bpp; + + writel(DCU_CTRLDESCLN_1_HEIGHT(var->yres) | + DCU_CTRLDESCLN_1_WIDTH(var->xres), + dcufb->reg_base + DCU_CTRLDESCLN_1(mfbi->index)); + writel(DCU_CTRLDESCLN_2_POSY(mfbi->y_layer_d) | + DCU_CTRLDESCLN_2_POSX(mfbi->x_layer_d), + dcufb->reg_base + DCU_CTRLDESCLN_2(mfbi->index)); + + writel(info->fix.smem_start, + dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index)); + + switch (var->bits_per_pixel) { + case 16: + bpp = BPP_16_RGB565; + break; + case 24: + bpp = BPP_24_RGB888; + break; + case 32: + bpp = BPP_32_ARGB8888; + break; + default: + printk(KERN_ERR "unsupported color depth: %u\n", + var->bits_per_pixel); + return -EINVAL; + } + + writel(DCU_CTRLDESCLN_4_EN | + DCU_CTRLDESCLN_4_TRANS(mfbi->alpha) | + DCU_CTRLDESCLN_4_BPP(bpp) | + DCU_CTRLDESCLN_4_AB(mfbi->blend), + dcufb->reg_base + DCU_CTRLDESCLN_4(mfbi->index)); + + writel(DCU_CTRLDESCLN_5_CKMAX_R(0xff) | + DCU_CTRLDESCLN_5_CKMAX_G(0xff) | + DCU_CTRLDESCLN_5_CKMAX_B(0xff), + dcufb->reg_base + DCU_CTRLDESCLN_5(mfbi->index)); + writel(DCU_CTRLDESCLN_6_CKMIN_R(0) | + DCU_CTRLDESCLN_6_CKMIN_G(0) | + DCU_CTRLDESCLN_6_CKMIN_B(0), + dcufb->reg_base + DCU_CTRLDESCLN_6(mfbi->index)); + + writel(DCU_CTRLDESCLN_7_TILE_VER(0) | DCU_CTRLDESCLN_7_TILE_HOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_7(mfbi->index)); + + writel(DCU_CTRLDESCLN_8_FG_FCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_8(mfbi->index)); + writel(DCU_CTRLDESCLN_9_BG_BCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_9(mfbi->index)); + + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); + return 0; +} + +static int disable_panel(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + + writel(DCU_CTRLDESCLN_1_HEIGHT(0) | + DCU_CTRLDESCLN_1_WIDTH(0), + dcufb->reg_base + DCU_CTRLDESCLN_1(mfbi->index)); + writel(DCU_CTRLDESCLN_2_POSY(0) | DCU_CTRLDESCLN_2_POSX(0), + dcufb->reg_base + DCU_CTRLDESCLN_2(mfbi->index)); + + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_4(mfbi->index)); + + writel(DCU_CTRLDESCLN_5_CKMAX_R(0) | + DCU_CTRLDESCLN_5_CKMAX_G(0) | + DCU_CTRLDESCLN_5_CKMAX_B(0), + dcufb->reg_base + DCU_CTRLDESCLN_5(mfbi->index)); + writel(DCU_CTRLDESCLN_6_CKMIN_R(0) | + DCU_CTRLDESCLN_6_CKMIN_G(0) | + DCU_CTRLDESCLN_6_CKMIN_B(0), + dcufb->reg_base + DCU_CTRLDESCLN_6(mfbi->index)); + + writel(DCU_CTRLDESCLN_7_TILE_VER(0) | DCU_CTRLDESCLN_7_TILE_HOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_7(mfbi->index)); + + writel(DCU_CTRLDESCLN_8_FG_FCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_8(mfbi->index)); + writel(DCU_CTRLDESCLN_9_BG_BCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_9(mfbi->index)); + + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); + return 0; +} + +static void enable_controller(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned int dcu_mode; + + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), + dcufb->reg_base + DCU_DCU_MODE); +} + +static void disable_controller(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + + writel(DCU_MODE_DCU_MODE(DCU_MODE_OFF), + dcufb->reg_base + DCU_DCU_MODE); +} + +static int fsl_dcu_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xoffset < 0) + var->xoffset = 0; + + if (var->yoffset < 0) + var->yoffset = 0; + + if (var->xoffset + info->var.xres > info->var.xres_virtual) + var->xoffset = info->var.xres_virtual - info->var.xres; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + var->yoffset = info->var.yres_virtual - info->var.yres; + + if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && + (var->bits_per_pixel != 16)) + var->bits_per_pixel = default_bpp; + + switch (var->bits_per_pixel) { + case 16: + var->red.length = 5; + var->red.offset = 11; + var->red.msb_right = 0; + + var->green.length = 6; + var->green.offset = 5; + var->green.msb_right = 0; + + var->blue.length = 5; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 24: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 32: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 8; + var->transp.offset = 24; + var->transp.msb_right = 0; + break; + default: + printk(KERN_ERR "unsupported color depth: %u\n", + var->bits_per_pixel); + return -EINVAL; + } + + return 0; +} + +static int calc_div_ratio(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned long dcu_clk; + unsigned long long tmp; + + dcu_clk = clk_get_rate(dcufb->clk); + tmp = info->var.pixclock * (unsigned long long)dcu_clk; + + do_div(tmp, 1000000); + + if (do_div(tmp, 1000000) > 500000) + tmp++; + + tmp = tmp - 1; + return tmp; +} + +static void update_controller(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned int ratio; + + ratio = calc_div_ratio(info); + writel(ratio, dcufb->reg_base + DCU_DIV_RATIO); + + writel(DCU_DISP_SIZE_DELTA_Y(var->yres) | + DCU_DISP_SIZE_DELTA_X(var->xres / 16), + dcufb->reg_base + DCU_DISP_SIZE); + + /* Horizontal and vertical sync parameter */ + writel(DCU_HSYN_PARA_BP(var->left_margin) | + DCU_HSYN_PARA_PW(var->hsync_len) | + DCU_HSYN_PARA_FP(var->right_margin), + dcufb->reg_base + DCU_HSYN_PARA); + + writel(DCU_VSYN_PARA_BP(var->upper_margin) | + DCU_VSYN_PARA_PW(var->vsync_len) | + DCU_VSYN_PARA_FP(var->lower_margin), + dcufb->reg_base + DCU_VSYN_PARA); + + writel(DCU_SYN_POL_INV_PXCK_FALL | DCU_SYN_POL_NEG_REMAIN | + DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW, + dcufb->reg_base + DCU_SYN_POL); + + writel(DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0), + dcufb->reg_base + DCU_BGND); + + writel(DCU_MODE_BLEND_ITER(DCU_LAYER_NUM_MAX) | DCU_MODE_RASTER_EN, + dcufb->reg_base + DCU_DCU_MODE); + + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD); + + enable_controller(info); +} + +static int map_video_memory(struct fb_info *info) +{ + u32 smem_len = info->fix.line_length * info->var.yres_virtual; + + info->fix.smem_len = smem_len; + + info->screen_base = dma_alloc_coherent(info->device, info->fix.smem_len, + (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); + if (!info->screen_base) { + printk(KERN_ERR "unable to allocate fb memory\n"); + return -ENOMEM; + } + + memset(info->screen_base, 0, info->fix.smem_len); + + return 0; +} + +static void unmap_video_memory(struct fb_info *info) +{ + if (!info->screen_base) + return; + + dma_free_coherent(info->device, info->fix.smem_len, + info->screen_base, info->fix.smem_start); + + info->screen_base = NULL; + info->fix.smem_start = 0; + info->fix.smem_len = 0; +} + +static int fsl_dcu_set_layer(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct fb_var_screeninfo *var = &info->var; + struct dcu_fb_data *dcufb = mfbi->parent; + int pixel_offset; + unsigned long addr; + + pixel_offset = (var->yoffset * var->xres_virtual) + var->xoffset; + addr = info->fix.smem_start + + (pixel_offset * (var->bits_per_pixel >> 3)); + + writel(addr, dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index)); + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); + + return 0; +} + +static int fsl_dcu_set_par(struct fb_info *info) +{ + unsigned long len; + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct mfb_info *mfbi = info->par; + + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + + len = info->var.yres_virtual * info->fix.line_length; + if (len != info->fix.smem_len) { + if (info->fix.smem_start) + unmap_video_memory(info); + + if (map_video_memory(info)) { + printk(KERN_ERR "unable to allocate fb memory\n"); + return -ENOMEM; + } + } + + /* Only layer 0 could update LCD controller */ + if (mfbi->index = LAYER0) + update_controller(info); + + enable_panel(info); + return 0; +} + +static inline __u32 CNVT_TOHW(__u32 val, __u32 width) +{ + return ((val<<width) + 0x7FFF - val) >> 16; +} + +static int fsl_dcu_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + unsigned int val; + int ret = -EINVAL; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + + val = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + pal[regno] = val; + ret = 0; + } + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + + return ret; +} + +static int fsl_dcu_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if ((info->var.xoffset = var->xoffset) && + (info->var.yoffset = var->yoffset)) + return 0; + + if (var->xoffset < 0 || var->yoffset < 0 + || var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + + fsl_dcu_set_layer(info); + + return 0; +} + +static int fsl_dcu_blank(int blank_mode, struct fb_info *info) +{ + switch (blank_mode) { + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + disable_panel(info); + break; + case FB_BLANK_POWERDOWN: + disable_controller(info); + break; + case FB_BLANK_UNBLANK: + enable_panel(info); + break; + } + + return 0; +} + +static int fsl_dcu_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct mfb_info *mfbi = info->par; + struct layer_display_offset layer_d; + void __user *buf = (void __user *)arg; + unsigned char alpha; + + switch (cmd) { + case MFB_SET_LAYER: + if (copy_from_user(&layer_d, buf, sizeof(layer_d))) + return -EFAULT; + mfbi->x_layer_d = layer_d.x_layer_d; + mfbi->y_layer_d = layer_d.y_layer_d; + fsl_dcu_set_par(info); + break; + case MFB_GET_LAYER: + layer_d.x_layer_d = mfbi->x_layer_d; + layer_d.y_layer_d = mfbi->y_layer_d; + if (copy_to_user(buf, &layer_d, sizeof(layer_d))) + return -EFAULT; + break; + case MFB_GET_ALPHA: + alpha = mfbi->alpha; + if (copy_to_user(buf, &alpha, sizeof(alpha))) + return -EFAULT; + break; + case MFB_SET_ALPHA: + if (copy_from_user(&alpha, buf, sizeof(alpha))) + return -EFAULT; + mfbi->blend = 1; + mfbi->alpha = alpha; + fsl_dcu_set_par(info); + break; + default: + printk(KERN_ERR "unknown ioctl command (0x%08X)\n", cmd); + return -ENOIOCTLCMD; + } + + return 0; +} + +static void enable_interrupts(struct dcu_fb_data *dcufb) +{ + u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK); + + writel(int_mask & ~DCU_INT_MASK_UNDRUN, dcufb->reg_base + DCU_INT_MASK); +} + +static void reset_layers(struct dcu_fb_data *dcufb) +{ + int i; + + for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) { + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_1(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_2(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_3(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_4(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_5(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_6(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_7(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_8(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_9(i)); + } + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); +} + +static int fsl_dcu_open(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int ret = 0; + + mfbi->index = info->node; + + mfbi->count++; + if (mfbi->count = 1) { + fsl_dcu_check_var(&info->var, info); + ret = fsl_dcu_set_par(info); + if (ret < 0) + mfbi->count--; + else + enable_interrupts(mfbi->parent); + } + + return ret; +} + +static int fsl_dcu_release(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int ret = 0; + + mfbi->count--; + if (mfbi->count = 0) { + ret = disable_panel(info); + if (ret < 0) + mfbi->count++; + } + + return ret; +} + +static struct fb_ops fsl_dcu_ops = { + .owner = THIS_MODULE, + .fb_check_var = fsl_dcu_check_var, + .fb_set_par = fsl_dcu_set_par, + .fb_setcolreg = fsl_dcu_setcolreg, + .fb_blank = fsl_dcu_blank, + .fb_pan_display = fsl_dcu_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_ioctl = fsl_dcu_ioctl, + .fb_open = fsl_dcu_open, + .fb_release = fsl_dcu_release, +}; + +static int install_framebuffer(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct fb_videomode *db = dcu_mode_db; + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); + int ret; + + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_dcu_ops; + info->flags = FBINFO_FLAG_DEFAULT; + info->pseudo_palette = &mfbi->pseudo_palette; + + fb_alloc_cmap(&info->cmap, 16, 0); + + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, + NULL, default_bpp); + + if (fsl_dcu_check_var(&info->var, info)) { + ret = -EINVAL; + goto failed_checkvar; + } + + if (register_framebuffer(info) < 0) { + ret = -EINVAL; + goto failed_register_framebuffer; + } + + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", + info->node, info->fix.id); + return 0; + +failed_checkvar: + fb_dealloc_cmap(&info->cmap); +failed_register_framebuffer: + unmap_video_memory(info); + fb_dealloc_cmap(&info->cmap); + return ret; +} + +static void uninstall_framebuffer(struct fb_info *info) +{ + unregister_framebuffer(info); + unmap_video_memory(info); + + if (&info->cmap) + fb_dealloc_cmap(&info->cmap); +} + +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) +{ + struct dcu_fb_data *dcufb = dev_id; + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); + u32 dcu_mode; + + if (status) { + if (status & DCU_INT_STATUS_UNDRUN) { + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), + dcufb->reg_base + DCU_DCU_MODE); + udelay(1); + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), + dcufb->reg_base + DCU_DCU_MODE); + } + writel(status, dcufb->reg_base + DCU_INT_STATUS); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +#ifdef CONFIG_PM +static int fsl_dcu_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); + + clk_disable_unprepare(dcufb->clk); + return 0; +} + +static int fsl_dcu_resume(struct platform_device *pdev) +{ + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); + + clk_prepare_enable(dcufb->clk); + return 0; +} +#else +#define fsl_dcu_suspend NULL +#define fsl_dcu_resume NULL +#endif + +static int bypass_tcon(struct device_node *np) +{ + struct device_node *tcon_np; + struct platform_device *tcon_pdev; + struct clk *tcon_clk; + void __iomem *tcon_reg; + int ret = 0; + + tcon_np = of_parse_phandle(np, "tcon-controller", 0); + if (!tcon_np) + return -EINVAL; + + tcon_pdev = of_find_device_by_node(tcon_np); + if (!tcon_pdev) + return -EINVAL; + + tcon_clk = devm_clk_get(&tcon_pdev->dev, "tcon"); + if (IS_ERR(tcon_clk)) { + ret = PTR_ERR(tcon_clk); + goto failed_getclock; + } + clk_prepare_enable(tcon_clk); + + tcon_reg = of_iomap(tcon_np, 0); + if (!tcon_reg) { + ret = -ENOMEM; + goto failed_ioremap; + } + writel(TCON_BYPASS_ENABLE, tcon_reg + TCON_CTRL1); + + return 0; + +failed_ioremap: + clk_disable_unprepare(tcon_clk); +failed_getclock: + of_node_put(tcon_np); + return ret; +} + +static int fsl_dcu_probe(struct platform_device *pdev) +{ + struct dcu_fb_data *dcufb; + struct mfb_info *mfbi; + struct resource *res; + int ret = 0; + int i; + + dcufb = devm_kzalloc(&pdev->dev, + sizeof(struct dcu_fb_data), GFP_KERNEL); + if (!dcufb) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "could not get memory IO resource\n"); + return -ENODEV; + } + + dcufb->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dcufb->reg_base)) { + ret = PTR_ERR(dcufb->reg_base); + goto failed_ioremap; + } + + dcufb->irq = platform_get_irq(pdev, 0); + if (!dcufb->irq) { + ret = -EINVAL; + goto failed_getirq; + } + + ret = request_irq(dcufb->irq, fsl_dcu_irq, 0, DRIVER_NAME, dcufb); + if (ret) { + dev_err(&pdev->dev, "could not request irq\n"); + goto failed_requestirq; + } + + /* Put TCON in bypass mode, so the input signals from DCU are passed + * through TCON unchanged */ + ret = bypass_tcon(pdev->dev.of_node); + if (ret) { + dev_err(&pdev->dev, "could not bypass TCON\n"); + goto failed_bypasstcon; + } + + dcufb->clk = devm_clk_get(&pdev->dev, "dcu"); + if (IS_ERR(dcufb->clk)) { + dev_err(&pdev->dev, "could not get clock\n"); + goto failed_getclock; + } + clk_prepare_enable(dcufb->clk); + + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { + dcufb->fsl_dcu_info[i] + framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); + if (!dcufb->fsl_dcu_info[i]) { + ret = ENOMEM; + goto failed_alloc_framebuffer; + } + + dcufb->fsl_dcu_info[i]->fix.smem_start = 0; + + mfbi = dcufb->fsl_dcu_info[i]->par; + memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); + mfbi->parent = dcufb; + + ret = install_framebuffer(dcufb->fsl_dcu_info[i]); + if (ret) { + dev_err(&pdev->dev, + "could not register framebuffer %d\n", i); + goto failed_register_framebuffer; + } + } + + reset_layers(mfbi->parent); + + dev_set_drvdata(&pdev->dev, dcufb); + return 0; + +failed_register_framebuffer: + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { + if (dcufb->fsl_dcu_info[i]) + framebuffer_release(dcufb->fsl_dcu_info[i]); + } +failed_alloc_framebuffer: +failed_getclock: +failed_bypasstcon: + free_irq(dcufb->irq, dcufb); +failed_requestirq: +failed_getirq: + iounmap(dcufb->reg_base); +failed_ioremap: + kfree(dcufb); + return ret; +} + +static int fsl_dcu_remove(struct platform_device *pdev) +{ + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); + int i; + + disable_controller(dcufb->fsl_dcu_info[0]); + + clk_disable_unprepare(dcufb->clk); + free_irq(dcufb->irq, dcufb); + + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { + uninstall_framebuffer(dcufb->fsl_dcu_info[i]); + framebuffer_release(dcufb->fsl_dcu_info[i]); + } + + return 0; +} + +static int fsl_dcu_setup(void) +{ +#ifndef MODULE + char *opt, *options = NULL; + unsigned long val; + + if (fb_get_options("fslfb", &options)) + return -ENODEV; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "bpp=", 4)) { + if (!strict_strtoul(opt + 4, 10, &val)) + default_bpp = val; + } else { + fb_mode = opt; + } + } +#endif + return 0; +} + +static struct of_device_id fsl_dcu_dt_ids[] = { + { + .compatible = "fsl,vf610-dcu", + }, + {} +}; + +static struct platform_driver fsl_dcu_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = fsl_dcu_dt_ids, + }, + .probe = fsl_dcu_probe, + .remove = fsl_dcu_remove, + .suspend = fsl_dcu_suspend, + .resume = fsl_dcu_resume, +}; + +static int __init fsl_dcu_init(void) +{ + int ret = fsl_dcu_setup(); + + if (ret < 0) + return ret; + + return platform_driver_register(&fsl_dcu_driver); +} + +static void __exit fsl_dcu_exit(void) +{ + platform_driver_unregister(&fsl_dcu_driver); +} + +module_init(fsl_dcu_init); +module_exit(fsl_dcu_exit); + +MODULE_AUTHOR("Alison Wang"); +MODULE_DESCRIPTION("Freescale DCU framebuffer driver"); +MODULE_LICENSE("GPL v2"); -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel The Display Controller Unit (DCU) module is a system master that fetches graphics stored in internal or external memory and displays them on a TFT LCD panel. A wide range of panel sizes is supported and the timing of the interface signals is highly configurable. Graphics are read directly from memory and then blended in real-time, which allows for dynamic content creation with minimal CPU intervention. The features: (1) Full RGB888 output to TFT LCD panel. (2) For the current LCD panel, WQVGA "480x272" is tested. (3) Blending of each pixel using up to 4 source layers dependent on size of panel. (4) Each graphic layer can be placed with one pixel resolution in either axis. (5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel and BGRA8888 direct colors with an alpha channel. (6) Each graphic layer support alpha blending with 8-bit resolution. This driver has been tested on Vybrid VF610 TOWER board. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: None drivers/video/Kconfig | 9 + drivers/video/Makefile | 1 + drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 1101 insertions(+) create mode 100644 drivers/video/fsl-dcu-fb.c diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 46544d0..32dc1f8 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig @@ -1978,6 +1978,15 @@ config FB_FSL_DIU ---help--- Framebuffer driver for the Freescale SoC DIU +config FB_FSL_DCU + tristate "Freescale DCU framebuffer support" + depends on FB + select FB_CFB_FILLRECT + select FB_CFB_COPYAREA + select FB_CFB_IMAGEBLIT + ---help--- + Framebuffer driver for the Freescale SoC DCU + config FB_W100 tristate "W100 frame buffer support" depends on FB && ARCH_PXA diff --git a/drivers/video/Makefile b/drivers/video/Makefile index e8bae8d..3707a7d 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile @@ -129,6 +129,7 @@ obj-$(CONFIG_FB_IMX) += imxfb.o obj-$(CONFIG_FB_S3C) += s3c-fb.o obj-$(CONFIG_FB_S3C2410) += s3c2410fb.o obj-$(CONFIG_FB_FSL_DIU) += fsl-diu-fb.o +obj-$(CONFIG_FB_FSL_DCU) += fsl-dcu-fb.o obj-$(CONFIG_FB_COBALT) += cobalt_lcdfb.o obj-$(CONFIG_FB_IBM_GXT4500) += gxt4500.o obj-$(CONFIG_FB_PS3) += ps3fb.o diff --git a/drivers/video/fsl-dcu-fb.c b/drivers/video/fsl-dcu-fb.c new file mode 100644 index 0000000..5571dde --- /dev/null +++ b/drivers/video/fsl-dcu-fb.c @@ -0,0 +1,1091 @@ +/* + * Copyright 2012-2013 Freescale Semiconductor, Inc. + * + * Freescale DCU Frame Buffer device driver + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/fb.h> +#include <linux/clk.h> +#include <linux/of.h> +#include <linux/of_address.h> +#include <linux/of_platform.h> +#include <linux/uaccess.h> +#include <linux/delay.h> +#include <linux/platform_device.h> + +#define DRIVER_NAME "fsl-dcu-fb" + +#define DCU_DCU_MODE 0x0010 +#define DCU_MODE_BLEND_ITER(x) (x << 20) +#define DCU_MODE_RASTER_EN (1 << 14) +#define DCU_MODE_DCU_MODE(x) (x) +#define DCU_MODE_DCU_MODE_MASK 0x03 +#define DCU_MODE_OFF 0 +#define DCU_MODE_NORMAL 1 +#define DCU_MODE_TEST 2 +#define DCU_MODE_COLORBAR 3 + +#define DCU_BGND 0x0014 +#define DCU_BGND_R(x) (x << 16) +#define DCU_BGND_G(x) (x << 8) +#define DCU_BGND_B(x) (x) + +#define DCU_DISP_SIZE 0x0018 +#define DCU_DISP_SIZE_DELTA_Y(x) (x << 16) +#define DCU_DISP_SIZE_DELTA_X(x) (x) + +#define DCU_HSYN_PARA 0x001c +#define DCU_HSYN_PARA_BP(x) (x << 22) +#define DCU_HSYN_PARA_PW(x) (x << 11) +#define DCU_HSYN_PARA_FP(x) (x) + +#define DCU_VSYN_PARA 0x0020 +#define DCU_VSYN_PARA_BP(x) (x << 22) +#define DCU_VSYN_PARA_PW(x) (x << 11) +#define DCU_VSYN_PARA_FP(x) (x) + +#define DCU_SYN_POL 0x0024 +#define DCU_SYN_POL_INV_PXCK_FALL (0 << 6) +#define DCU_SYN_POL_NEG_REMAIN (0 << 5) +#define DCU_SYN_POL_INV_VS_LOW (1 << 1) +#define DCU_SYN_POL_INV_HS_LOW (1) + +#define DCU_THRESHOLD 0x0028 +#define DCU_THRESHOLD_LS_BF_VS(x) (x << 16) +#define DCU_THRESHOLD_OUT_BUF_HIGH(x) (x << 8) +#define DCU_THRESHOLD_OUT_BUF_LOW(x) (x) + +#define DCU_INT_STATUS 0x002C +#define DCU_INT_STATUS_UNDRUN (1 << 1) + +#define DCU_INT_MASK 0x0030 +#define DCU_INT_MASK_UNDRUN (1 << 1) + +#define DCU_DIV_RATIO 0x0054 + +#define DCU_UPDATE_MODE 0x00cc +#define DCU_UPDATE_MODE_MODE (1 << 31) +#define DCU_UPDATE_MODE_READREG (1 << 30) + +#define DCU_CTRLDESCLN_1(x) (0x200 + (x) * 0x40) +#define DCU_CTRLDESCLN_1_HEIGHT(x) (x << 16) +#define DCU_CTRLDESCLN_1_WIDTH(x) (x) + +#define DCU_CTRLDESCLN_2(x) (0x204 + (x) * 0x40) +#define DCU_CTRLDESCLN_2_POSY(x) (x << 16) +#define DCU_CTRLDESCLN_2_POSX(x) (x) + +#define DCU_CTRLDESCLN_3(x) (0x208 + (x) * 0x40) + +#define DCU_CTRLDESCLN_4(x) (0x20c + (x) * 0x40) +#define DCU_CTRLDESCLN_4_EN (1 << 31) +#define DCU_CTRLDESCLN_4_TILE_EN (1 << 30) +#define DCU_CTRLDESCLN_4_DATA_SEL_CLUT (1 << 29) +#define DCU_CTRLDESCLN_4_SAFETY_EN (1 << 28) +#define DCU_CTRLDESCLN_4_TRANS(x) (x << 20) +#define DCU_CTRLDESCLN_4_BPP(x) (x << 16) +#define DCU_CTRLDESCLN_4_RLE_EN (1 << 15) +#define DCU_CTRLDESCLN_4_LUOFFS(x) (x << 4) +#define DCU_CTRLDESCLN_4_BB_ON (1 << 2) +#define DCU_CTRLDESCLN_4_AB(x) (x) + +#define DCU_CTRLDESCLN_5(x) (0x210 + (x) * 0x40) +#define DCU_CTRLDESCLN_5_CKMAX_R(x) (x << 16) +#define DCU_CTRLDESCLN_5_CKMAX_G(x) (x << 8) +#define DCU_CTRLDESCLN_5_CKMAX_B(x) (x) + +#define DCU_CTRLDESCLN_6(x) (0x214 + (x) * 0x40) +#define DCU_CTRLDESCLN_6_CKMIN_R(x) (x << 16) +#define DCU_CTRLDESCLN_6_CKMIN_G(x) (x << 8) +#define DCU_CTRLDESCLN_6_CKMIN_B(x) (x) + +#define DCU_CTRLDESCLN_7(x) (0x218 + (x) * 0x40) +#define DCU_CTRLDESCLN_7_TILE_VER(x) (x << 16) +#define DCU_CTRLDESCLN_7_TILE_HOR(x) (x) + +#define DCU_CTRLDESCLN_8(x) (0x21c + (x) * 0x40) +#define DCU_CTRLDESCLN_8_FG_FCOLOR(x) (x) + +#define DCU_CTRLDESCLN_9(x) (0x220 + (x) * 0x40) +#define DCU_CTRLDESCLN_9_BG_BCOLOR(x) (x) + +#define DCU_TOTAL_LAYER_NUM 64 +#define DCU_LAYER_NUM_MAX 6 +#define DCU_LAYER_NUM 4 + +#define BPP_16_RGB565 4 +#define BPP_24_RGB888 5 +#define BPP_32_ARGB8888 6 + +#define TCON_CTRL1 0x0000 +#define TCON_BYPASS_ENABLE (1 << 29) + +#define MFB_SET_ALPHA _IOW('M', 0, __u8) +#define MFB_GET_ALPHA _IOR('M', 0, __u8) +#define MFB_SET_LAYER _IOW('M', 4, struct layer_display_offset) +#define MFB_GET_LAYER _IOR('M', 4, struct layer_display_offset) + +static char *fb_mode; +static unsigned int default_bpp = 24; + +static struct fb_videomode dcu_mode_db[] = { + { + .name = "480x272", + .refresh = 75, + .xres = 480, + .yres = 272, + .pixclock = 91996, + .left_margin = 2, + .right_margin = 2, + .upper_margin = 1, + .lower_margin = 1, + .hsync_len = 41, + .vsync_len = 2, + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, + .vmode = FB_VMODE_NONINTERLACED, + }, +}; + +/* DCU framebuffer data structure */ +struct dcu_fb_data { + struct fb_info *fsl_dcu_info[DCU_LAYER_NUM]; + void __iomem *reg_base; + unsigned int irq; + struct clk *clk; +}; + +struct layer_display_offset { + int x_layer_d; + int y_layer_d; +}; + +struct mfb_info { + int index; + char *id; + unsigned long pseudo_palette[16]; + unsigned char alpha; + unsigned char blend; + unsigned int count; + int x_layer_d; /* layer display x offset to physical screen */ + int y_layer_d; /* layer display y offset to physical screen */ + struct dcu_fb_data *parent; +}; + +enum mfb_index { + LAYER0 = 0, + LAYER1, + LAYER2, + LAYER3, +}; + +static struct mfb_info mfb_template[] = { + { + .index = LAYER0, + .id = "Layer0", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 0, + .y_layer_d = 0, + }, + { + .index = LAYER1, + .id = "Layer1", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 50, + .y_layer_d = 50, + }, + { + .index = LAYER2, + .id = "Layer2", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 100, + .y_layer_d = 100, + }, + { + .index = LAYER3, + .id = "Layer3", + .alpha = 0xff, + .blend = 0, + .count = 0, + .x_layer_d = 150, + .y_layer_d = 150, + }, +}; + +static int enable_panel(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned int bpp; + + writel(DCU_CTRLDESCLN_1_HEIGHT(var->yres) | + DCU_CTRLDESCLN_1_WIDTH(var->xres), + dcufb->reg_base + DCU_CTRLDESCLN_1(mfbi->index)); + writel(DCU_CTRLDESCLN_2_POSY(mfbi->y_layer_d) | + DCU_CTRLDESCLN_2_POSX(mfbi->x_layer_d), + dcufb->reg_base + DCU_CTRLDESCLN_2(mfbi->index)); + + writel(info->fix.smem_start, + dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index)); + + switch (var->bits_per_pixel) { + case 16: + bpp = BPP_16_RGB565; + break; + case 24: + bpp = BPP_24_RGB888; + break; + case 32: + bpp = BPP_32_ARGB8888; + break; + default: + printk(KERN_ERR "unsupported color depth: %u\n", + var->bits_per_pixel); + return -EINVAL; + } + + writel(DCU_CTRLDESCLN_4_EN | + DCU_CTRLDESCLN_4_TRANS(mfbi->alpha) | + DCU_CTRLDESCLN_4_BPP(bpp) | + DCU_CTRLDESCLN_4_AB(mfbi->blend), + dcufb->reg_base + DCU_CTRLDESCLN_4(mfbi->index)); + + writel(DCU_CTRLDESCLN_5_CKMAX_R(0xff) | + DCU_CTRLDESCLN_5_CKMAX_G(0xff) | + DCU_CTRLDESCLN_5_CKMAX_B(0xff), + dcufb->reg_base + DCU_CTRLDESCLN_5(mfbi->index)); + writel(DCU_CTRLDESCLN_6_CKMIN_R(0) | + DCU_CTRLDESCLN_6_CKMIN_G(0) | + DCU_CTRLDESCLN_6_CKMIN_B(0), + dcufb->reg_base + DCU_CTRLDESCLN_6(mfbi->index)); + + writel(DCU_CTRLDESCLN_7_TILE_VER(0) | DCU_CTRLDESCLN_7_TILE_HOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_7(mfbi->index)); + + writel(DCU_CTRLDESCLN_8_FG_FCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_8(mfbi->index)); + writel(DCU_CTRLDESCLN_9_BG_BCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_9(mfbi->index)); + + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); + return 0; +} + +static int disable_panel(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + + writel(DCU_CTRLDESCLN_1_HEIGHT(0) | + DCU_CTRLDESCLN_1_WIDTH(0), + dcufb->reg_base + DCU_CTRLDESCLN_1(mfbi->index)); + writel(DCU_CTRLDESCLN_2_POSY(0) | DCU_CTRLDESCLN_2_POSX(0), + dcufb->reg_base + DCU_CTRLDESCLN_2(mfbi->index)); + + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_4(mfbi->index)); + + writel(DCU_CTRLDESCLN_5_CKMAX_R(0) | + DCU_CTRLDESCLN_5_CKMAX_G(0) | + DCU_CTRLDESCLN_5_CKMAX_B(0), + dcufb->reg_base + DCU_CTRLDESCLN_5(mfbi->index)); + writel(DCU_CTRLDESCLN_6_CKMIN_R(0) | + DCU_CTRLDESCLN_6_CKMIN_G(0) | + DCU_CTRLDESCLN_6_CKMIN_B(0), + dcufb->reg_base + DCU_CTRLDESCLN_6(mfbi->index)); + + writel(DCU_CTRLDESCLN_7_TILE_VER(0) | DCU_CTRLDESCLN_7_TILE_HOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_7(mfbi->index)); + + writel(DCU_CTRLDESCLN_8_FG_FCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_8(mfbi->index)); + writel(DCU_CTRLDESCLN_9_BG_BCOLOR(0), + dcufb->reg_base + DCU_CTRLDESCLN_9(mfbi->index)); + + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); + return 0; +} + +static void enable_controller(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned int dcu_mode; + + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), + dcufb->reg_base + DCU_DCU_MODE); +} + +static void disable_controller(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + + writel(DCU_MODE_DCU_MODE(DCU_MODE_OFF), + dcufb->reg_base + DCU_DCU_MODE); +} + +static int fsl_dcu_check_var(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if (var->xres_virtual < var->xres) + var->xres_virtual = var->xres; + if (var->yres_virtual < var->yres) + var->yres_virtual = var->yres; + + if (var->xoffset < 0) + var->xoffset = 0; + + if (var->yoffset < 0) + var->yoffset = 0; + + if (var->xoffset + info->var.xres > info->var.xres_virtual) + var->xoffset = info->var.xres_virtual - info->var.xres; + + if (var->yoffset + info->var.yres > info->var.yres_virtual) + var->yoffset = info->var.yres_virtual - info->var.yres; + + if ((var->bits_per_pixel != 32) && (var->bits_per_pixel != 24) && + (var->bits_per_pixel != 16)) + var->bits_per_pixel = default_bpp; + + switch (var->bits_per_pixel) { + case 16: + var->red.length = 5; + var->red.offset = 11; + var->red.msb_right = 0; + + var->green.length = 6; + var->green.offset = 5; + var->green.msb_right = 0; + + var->blue.length = 5; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 24: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 0; + var->transp.offset = 0; + var->transp.msb_right = 0; + break; + case 32: + var->red.length = 8; + var->red.offset = 16; + var->red.msb_right = 0; + + var->green.length = 8; + var->green.offset = 8; + var->green.msb_right = 0; + + var->blue.length = 8; + var->blue.offset = 0; + var->blue.msb_right = 0; + + var->transp.length = 8; + var->transp.offset = 24; + var->transp.msb_right = 0; + break; + default: + printk(KERN_ERR "unsupported color depth: %u\n", + var->bits_per_pixel); + return -EINVAL; + } + + return 0; +} + +static int calc_div_ratio(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned long dcu_clk; + unsigned long long tmp; + + dcu_clk = clk_get_rate(dcufb->clk); + tmp = info->var.pixclock * (unsigned long long)dcu_clk; + + do_div(tmp, 1000000); + + if (do_div(tmp, 1000000) > 500000) + tmp++; + + tmp = tmp - 1; + return tmp; +} + +static void update_controller(struct fb_info *info) +{ + struct fb_var_screeninfo *var = &info->var; + struct mfb_info *mfbi = info->par; + struct dcu_fb_data *dcufb = mfbi->parent; + unsigned int ratio; + + ratio = calc_div_ratio(info); + writel(ratio, dcufb->reg_base + DCU_DIV_RATIO); + + writel(DCU_DISP_SIZE_DELTA_Y(var->yres) | + DCU_DISP_SIZE_DELTA_X(var->xres / 16), + dcufb->reg_base + DCU_DISP_SIZE); + + /* Horizontal and vertical sync parameter */ + writel(DCU_HSYN_PARA_BP(var->left_margin) | + DCU_HSYN_PARA_PW(var->hsync_len) | + DCU_HSYN_PARA_FP(var->right_margin), + dcufb->reg_base + DCU_HSYN_PARA); + + writel(DCU_VSYN_PARA_BP(var->upper_margin) | + DCU_VSYN_PARA_PW(var->vsync_len) | + DCU_VSYN_PARA_FP(var->lower_margin), + dcufb->reg_base + DCU_VSYN_PARA); + + writel(DCU_SYN_POL_INV_PXCK_FALL | DCU_SYN_POL_NEG_REMAIN | + DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW, + dcufb->reg_base + DCU_SYN_POL); + + writel(DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0), + dcufb->reg_base + DCU_BGND); + + writel(DCU_MODE_BLEND_ITER(DCU_LAYER_NUM_MAX) | DCU_MODE_RASTER_EN, + dcufb->reg_base + DCU_DCU_MODE); + + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD); + + enable_controller(info); +} + +static int map_video_memory(struct fb_info *info) +{ + u32 smem_len = info->fix.line_length * info->var.yres_virtual; + + info->fix.smem_len = smem_len; + + info->screen_base = dma_alloc_coherent(info->device, info->fix.smem_len, + (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); + if (!info->screen_base) { + printk(KERN_ERR "unable to allocate fb memory\n"); + return -ENOMEM; + } + + memset(info->screen_base, 0, info->fix.smem_len); + + return 0; +} + +static void unmap_video_memory(struct fb_info *info) +{ + if (!info->screen_base) + return; + + dma_free_coherent(info->device, info->fix.smem_len, + info->screen_base, info->fix.smem_start); + + info->screen_base = NULL; + info->fix.smem_start = 0; + info->fix.smem_len = 0; +} + +static int fsl_dcu_set_layer(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct fb_var_screeninfo *var = &info->var; + struct dcu_fb_data *dcufb = mfbi->parent; + int pixel_offset; + unsigned long addr; + + pixel_offset = (var->yoffset * var->xres_virtual) + var->xoffset; + addr = info->fix.smem_start + + (pixel_offset * (var->bits_per_pixel >> 3)); + + writel(addr, dcufb->reg_base + DCU_CTRLDESCLN_3(mfbi->index)); + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); + + return 0; +} + +static int fsl_dcu_set_par(struct fb_info *info) +{ + unsigned long len; + struct fb_var_screeninfo *var = &info->var; + struct fb_fix_screeninfo *fix = &info->fix; + struct mfb_info *mfbi = info->par; + + fix->line_length = var->xres_virtual * var->bits_per_pixel / 8; + fix->type = FB_TYPE_PACKED_PIXELS; + fix->accel = FB_ACCEL_NONE; + fix->visual = FB_VISUAL_TRUECOLOR; + fix->xpanstep = 1; + fix->ypanstep = 1; + + len = info->var.yres_virtual * info->fix.line_length; + if (len != info->fix.smem_len) { + if (info->fix.smem_start) + unmap_video_memory(info); + + if (map_video_memory(info)) { + printk(KERN_ERR "unable to allocate fb memory\n"); + return -ENOMEM; + } + } + + /* Only layer 0 could update LCD controller */ + if (mfbi->index == LAYER0) + update_controller(info); + + enable_panel(info); + return 0; +} + +static inline __u32 CNVT_TOHW(__u32 val, __u32 width) +{ + return ((val<<width) + 0x7FFF - val) >> 16; +} + +static int fsl_dcu_setcolreg(unsigned regno, unsigned red, unsigned green, + unsigned blue, unsigned transp, struct fb_info *info) +{ + unsigned int val; + int ret = -EINVAL; + + /* + * If greyscale is true, then we convert the RGB value + * to greyscale no matter what visual we are using. + */ + if (info->var.grayscale) + red = green = blue = (19595 * red + 38470 * green + + 7471 * blue) >> 16; + switch (info->fix.visual) { + case FB_VISUAL_TRUECOLOR: + /* + * 16-bit True Colour. We encode the RGB value + * according to the RGB bitfield information. + */ + if (regno < 16) { + u32 *pal = info->pseudo_palette; + + red = CNVT_TOHW(red, info->var.red.length); + green = CNVT_TOHW(green, info->var.green.length); + blue = CNVT_TOHW(blue, info->var.blue.length); + transp = CNVT_TOHW(transp, info->var.transp.length); + + val = (red << info->var.red.offset) | + (green << info->var.green.offset) | + (blue << info->var.blue.offset) | + (transp << info->var.transp.offset); + + pal[regno] = val; + ret = 0; + } + break; + case FB_VISUAL_STATIC_PSEUDOCOLOR: + case FB_VISUAL_PSEUDOCOLOR: + break; + } + + return ret; +} + +static int fsl_dcu_pan_display(struct fb_var_screeninfo *var, + struct fb_info *info) +{ + if ((info->var.xoffset == var->xoffset) && + (info->var.yoffset == var->yoffset)) + return 0; + + if (var->xoffset < 0 || var->yoffset < 0 + || var->xoffset + info->var.xres > info->var.xres_virtual + || var->yoffset + info->var.yres > info->var.yres_virtual) + return -EINVAL; + + info->var.xoffset = var->xoffset; + info->var.yoffset = var->yoffset; + + if (var->vmode & FB_VMODE_YWRAP) + info->var.vmode |= FB_VMODE_YWRAP; + else + info->var.vmode &= ~FB_VMODE_YWRAP; + + fsl_dcu_set_layer(info); + + return 0; +} + +static int fsl_dcu_blank(int blank_mode, struct fb_info *info) +{ + switch (blank_mode) { + case FB_BLANK_VSYNC_SUSPEND: + case FB_BLANK_HSYNC_SUSPEND: + case FB_BLANK_NORMAL: + disable_panel(info); + break; + case FB_BLANK_POWERDOWN: + disable_controller(info); + break; + case FB_BLANK_UNBLANK: + enable_panel(info); + break; + } + + return 0; +} + +static int fsl_dcu_ioctl(struct fb_info *info, unsigned int cmd, + unsigned long arg) +{ + struct mfb_info *mfbi = info->par; + struct layer_display_offset layer_d; + void __user *buf = (void __user *)arg; + unsigned char alpha; + + switch (cmd) { + case MFB_SET_LAYER: + if (copy_from_user(&layer_d, buf, sizeof(layer_d))) + return -EFAULT; + mfbi->x_layer_d = layer_d.x_layer_d; + mfbi->y_layer_d = layer_d.y_layer_d; + fsl_dcu_set_par(info); + break; + case MFB_GET_LAYER: + layer_d.x_layer_d = mfbi->x_layer_d; + layer_d.y_layer_d = mfbi->y_layer_d; + if (copy_to_user(buf, &layer_d, sizeof(layer_d))) + return -EFAULT; + break; + case MFB_GET_ALPHA: + alpha = mfbi->alpha; + if (copy_to_user(buf, &alpha, sizeof(alpha))) + return -EFAULT; + break; + case MFB_SET_ALPHA: + if (copy_from_user(&alpha, buf, sizeof(alpha))) + return -EFAULT; + mfbi->blend = 1; + mfbi->alpha = alpha; + fsl_dcu_set_par(info); + break; + default: + printk(KERN_ERR "unknown ioctl command (0x%08X)\n", cmd); + return -ENOIOCTLCMD; + } + + return 0; +} + +static void enable_interrupts(struct dcu_fb_data *dcufb) +{ + u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK); + + writel(int_mask & ~DCU_INT_MASK_UNDRUN, dcufb->reg_base + DCU_INT_MASK); +} + +static void reset_layers(struct dcu_fb_data *dcufb) +{ + int i; + + for (i = 1; i < DCU_TOTAL_LAYER_NUM; i++) { + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_1(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_2(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_3(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_4(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_5(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_6(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_7(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_8(i)); + writel(0, dcufb->reg_base + DCU_CTRLDESCLN_9(i)); + } + writel(DCU_UPDATE_MODE_READREG, dcufb->reg_base + DCU_UPDATE_MODE); +} + +static int fsl_dcu_open(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int ret = 0; + + mfbi->index = info->node; + + mfbi->count++; + if (mfbi->count == 1) { + fsl_dcu_check_var(&info->var, info); + ret = fsl_dcu_set_par(info); + if (ret < 0) + mfbi->count--; + else + enable_interrupts(mfbi->parent); + } + + return ret; +} + +static int fsl_dcu_release(struct fb_info *info, int user) +{ + struct mfb_info *mfbi = info->par; + int ret = 0; + + mfbi->count--; + if (mfbi->count == 0) { + ret = disable_panel(info); + if (ret < 0) + mfbi->count++; + } + + return ret; +} + +static struct fb_ops fsl_dcu_ops = { + .owner = THIS_MODULE, + .fb_check_var = fsl_dcu_check_var, + .fb_set_par = fsl_dcu_set_par, + .fb_setcolreg = fsl_dcu_setcolreg, + .fb_blank = fsl_dcu_blank, + .fb_pan_display = fsl_dcu_pan_display, + .fb_fillrect = cfb_fillrect, + .fb_copyarea = cfb_copyarea, + .fb_imageblit = cfb_imageblit, + .fb_ioctl = fsl_dcu_ioctl, + .fb_open = fsl_dcu_open, + .fb_release = fsl_dcu_release, +}; + +static int install_framebuffer(struct fb_info *info) +{ + struct mfb_info *mfbi = info->par; + struct fb_videomode *db = dcu_mode_db; + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); + int ret; + + info->var.activate = FB_ACTIVATE_NOW; + info->fbops = &fsl_dcu_ops; + info->flags = FBINFO_FLAG_DEFAULT; + info->pseudo_palette = &mfbi->pseudo_palette; + + fb_alloc_cmap(&info->cmap, 16, 0); + + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, + NULL, default_bpp); + + if (fsl_dcu_check_var(&info->var, info)) { + ret = -EINVAL; + goto failed_checkvar; + } + + if (register_framebuffer(info) < 0) { + ret = -EINVAL; + goto failed_register_framebuffer; + } + + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", + info->node, info->fix.id); + return 0; + +failed_checkvar: + fb_dealloc_cmap(&info->cmap); +failed_register_framebuffer: + unmap_video_memory(info); + fb_dealloc_cmap(&info->cmap); + return ret; +} + +static void uninstall_framebuffer(struct fb_info *info) +{ + unregister_framebuffer(info); + unmap_video_memory(info); + + if (&info->cmap) + fb_dealloc_cmap(&info->cmap); +} + +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) +{ + struct dcu_fb_data *dcufb = dev_id; + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); + u32 dcu_mode; + + if (status) { + if (status & DCU_INT_STATUS_UNDRUN) { + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), + dcufb->reg_base + DCU_DCU_MODE); + udelay(1); + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), + dcufb->reg_base + DCU_DCU_MODE); + } + writel(status, dcufb->reg_base + DCU_INT_STATUS); + return IRQ_HANDLED; + } + return IRQ_NONE; +} + +#ifdef CONFIG_PM +static int fsl_dcu_suspend(struct platform_device *pdev, + pm_message_t state) +{ + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); + + clk_disable_unprepare(dcufb->clk); + return 0; +} + +static int fsl_dcu_resume(struct platform_device *pdev) +{ + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); + + clk_prepare_enable(dcufb->clk); + return 0; +} +#else +#define fsl_dcu_suspend NULL +#define fsl_dcu_resume NULL +#endif + +static int bypass_tcon(struct device_node *np) +{ + struct device_node *tcon_np; + struct platform_device *tcon_pdev; + struct clk *tcon_clk; + void __iomem *tcon_reg; + int ret = 0; + + tcon_np = of_parse_phandle(np, "tcon-controller", 0); + if (!tcon_np) + return -EINVAL; + + tcon_pdev = of_find_device_by_node(tcon_np); + if (!tcon_pdev) + return -EINVAL; + + tcon_clk = devm_clk_get(&tcon_pdev->dev, "tcon"); + if (IS_ERR(tcon_clk)) { + ret = PTR_ERR(tcon_clk); + goto failed_getclock; + } + clk_prepare_enable(tcon_clk); + + tcon_reg = of_iomap(tcon_np, 0); + if (!tcon_reg) { + ret = -ENOMEM; + goto failed_ioremap; + } + writel(TCON_BYPASS_ENABLE, tcon_reg + TCON_CTRL1); + + return 0; + +failed_ioremap: + clk_disable_unprepare(tcon_clk); +failed_getclock: + of_node_put(tcon_np); + return ret; +} + +static int fsl_dcu_probe(struct platform_device *pdev) +{ + struct dcu_fb_data *dcufb; + struct mfb_info *mfbi; + struct resource *res; + int ret = 0; + int i; + + dcufb = devm_kzalloc(&pdev->dev, + sizeof(struct dcu_fb_data), GFP_KERNEL); + if (!dcufb) + return -ENOMEM; + + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(&pdev->dev, "could not get memory IO resource\n"); + return -ENODEV; + } + + dcufb->reg_base = devm_ioremap_resource(&pdev->dev, res); + if (IS_ERR(dcufb->reg_base)) { + ret = PTR_ERR(dcufb->reg_base); + goto failed_ioremap; + } + + dcufb->irq = platform_get_irq(pdev, 0); + if (!dcufb->irq) { + ret = -EINVAL; + goto failed_getirq; + } + + ret = request_irq(dcufb->irq, fsl_dcu_irq, 0, DRIVER_NAME, dcufb); + if (ret) { + dev_err(&pdev->dev, "could not request irq\n"); + goto failed_requestirq; + } + + /* Put TCON in bypass mode, so the input signals from DCU are passed + * through TCON unchanged */ + ret = bypass_tcon(pdev->dev.of_node); + if (ret) { + dev_err(&pdev->dev, "could not bypass TCON\n"); + goto failed_bypasstcon; + } + + dcufb->clk = devm_clk_get(&pdev->dev, "dcu"); + if (IS_ERR(dcufb->clk)) { + dev_err(&pdev->dev, "could not get clock\n"); + goto failed_getclock; + } + clk_prepare_enable(dcufb->clk); + + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { + dcufb->fsl_dcu_info[i] = + framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); + if (!dcufb->fsl_dcu_info[i]) { + ret = ENOMEM; + goto failed_alloc_framebuffer; + } + + dcufb->fsl_dcu_info[i]->fix.smem_start = 0; + + mfbi = dcufb->fsl_dcu_info[i]->par; + memcpy(mfbi, &mfb_template[i], sizeof(struct mfb_info)); + mfbi->parent = dcufb; + + ret = install_framebuffer(dcufb->fsl_dcu_info[i]); + if (ret) { + dev_err(&pdev->dev, + "could not register framebuffer %d\n", i); + goto failed_register_framebuffer; + } + } + + reset_layers(mfbi->parent); + + dev_set_drvdata(&pdev->dev, dcufb); + return 0; + +failed_register_framebuffer: + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { + if (dcufb->fsl_dcu_info[i]) + framebuffer_release(dcufb->fsl_dcu_info[i]); + } +failed_alloc_framebuffer: +failed_getclock: +failed_bypasstcon: + free_irq(dcufb->irq, dcufb); +failed_requestirq: +failed_getirq: + iounmap(dcufb->reg_base); +failed_ioremap: + kfree(dcufb); + return ret; +} + +static int fsl_dcu_remove(struct platform_device *pdev) +{ + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); + int i; + + disable_controller(dcufb->fsl_dcu_info[0]); + + clk_disable_unprepare(dcufb->clk); + free_irq(dcufb->irq, dcufb); + + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { + uninstall_framebuffer(dcufb->fsl_dcu_info[i]); + framebuffer_release(dcufb->fsl_dcu_info[i]); + } + + return 0; +} + +static int fsl_dcu_setup(void) +{ +#ifndef MODULE + char *opt, *options = NULL; + unsigned long val; + + if (fb_get_options("fslfb", &options)) + return -ENODEV; + + if (!options || !*options) + return 0; + + while ((opt = strsep(&options, ",")) != NULL) { + if (!*opt) + continue; + if (!strncmp(opt, "bpp=", 4)) { + if (!strict_strtoul(opt + 4, 10, &val)) + default_bpp = val; + } else { + fb_mode = opt; + } + } +#endif + return 0; +} + +static struct of_device_id fsl_dcu_dt_ids[] = { + { + .compatible = "fsl,vf610-dcu", + }, + {} +}; + +static struct platform_driver fsl_dcu_driver = { + .driver = { + .name = DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = fsl_dcu_dt_ids, + }, + .probe = fsl_dcu_probe, + .remove = fsl_dcu_remove, + .suspend = fsl_dcu_suspend, + .resume = fsl_dcu_resume, +}; + +static int __init fsl_dcu_init(void) +{ + int ret = fsl_dcu_setup(); + + if (ret < 0) + return ret; + + return platform_driver_register(&fsl_dcu_driver); +} + +static void __exit fsl_dcu_exit(void) +{ + platform_driver_unregister(&fsl_dcu_driver); +} + +module_init(fsl_dcu_init); +module_exit(fsl_dcu_exit); + +MODULE_AUTHOR("Alison Wang"); +MODULE_DESCRIPTION("Freescale DCU framebuffer driver"); +MODULE_LICENSE("GPL v2"); -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-12 6:07 ` Alison Wang @ 2013-07-29 11:14 ` Sascha Hauer -1 siblings, 0 replies; 38+ messages in thread From: Sascha Hauer @ 2013-07-29 11:14 UTC (permalink / raw) To: linux-arm-kernel On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > The Display Controller Unit (DCU) module is a system master that > fetches graphics stored in internal or external memory and displays > them on a TFT LCD panel. A wide range of panel sizes is supported > and the timing of the interface signals is highly configurable. > Graphics are read directly from memory and then blended in real-time, > which allows for dynamic content creation with minimal CPU intervention. Only a review of the code inline. Maybe the real question is whether we want to introduce another framebuffer driver at all instead of making it a DRM driver. > + > +#define DRIVER_NAME "fsl-dcu-fb" > + > +#define DCU_DCU_MODE 0x0010 > +#define DCU_MODE_BLEND_ITER(x) (x << 20) What's the result of DCU_MODE_BLEND_ITER(1 + 1)? > +static struct fb_videomode dcu_mode_db[] = { > + { > + .name = "480x272", > + .refresh = 75, > + .xres = 480, > + .yres = 272, > + .pixclock = 91996, > + .left_margin = 2, > + .right_margin = 2, > + .upper_margin = 1, > + .lower_margin = 1, > + .hsync_len = 41, > + .vsync_len = 2, > + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}; We have ways to describe a panel in dt. Use them. > + > +static struct mfb_info mfb_template[] = { > + { > + .index = LAYER0, > + .id = "Layer0", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 0, > + .y_layer_d = 0, > + }, Wrong indentation. > + default: > + printk(KERN_ERR "unsupported color depth: %u\n", > + var->bits_per_pixel); Use dev_* for printing messages in drivers. > +static int fsl_dcu_check_var(struct fb_var_screeninfo *var, > + struct fb_info *info) > +{ > + if (var->xres_virtual < var->xres) > + var->xres_virtual = var->xres; > + if (var->yres_virtual < var->yres) > + var->yres_virtual = var->yres; > + > + if (var->xoffset < 0) > + var->xoffset = 0; > + > + if (var->yoffset < 0) > + var->yoffset = 0; Ever seen an unsigned value going below zero? > + default: > + printk(KERN_ERR "unsupported color depth: %u\n", > + var->bits_per_pixel); BUG(). This can't happen since you make that sure above. > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int calc_div_ratio(struct fb_info *info) > +{ Use a consistent namespace for function names (fsl_dcu_) > + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | > + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD); > + > + enable_controller(info); > +} Make your functions symmetric. If there's update_controller(), the function should do exactly that, it should *not* enable the controller. Call this from the users of this function if necessary. > + if (copy_to_user(buf, &alpha, sizeof(alpha))) > + return -EFAULT; > + break; > + case MFB_SET_ALPHA: > + if (copy_from_user(&alpha, buf, sizeof(alpha))) > + return -EFAULT; > + mfbi->blend = 1; > + mfbi->alpha = alpha; > + fsl_dcu_set_par(info); > + break; Is it still state of the art to introduce ioctls in the fb framework without any kind of documentation? > + default: > + printk(KERN_ERR "unknown ioctl command (0x%08X)\n", cmd); What shall a reader of the kernel log do with a message like this? It's utterly useless when he doesn't even now which device failed here. Just drop this. > +static void enable_interrupts(struct dcu_fb_data *dcufb) > +{ > + u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK); > + > + writel(int_mask & ~DCU_INT_MASK_UNDRUN, dcufb->reg_base + DCU_INT_MASK); > +} Inline this code where you need it. Introducing a function for a single register write seems quite useless. > +static int install_framebuffer(struct fb_info *info) > +{ > + struct mfb_info *mfbi = info->par; > + struct fb_videomode *db = dcu_mode_db; > + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); > + int ret; > + > + info->var.activate = FB_ACTIVATE_NOW; > + info->fbops = &fsl_dcu_ops; > + info->flags = FBINFO_FLAG_DEFAULT; > + info->pseudo_palette = &mfbi->pseudo_palette; > + > + fb_alloc_cmap(&info->cmap, 16, 0); > + > + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, > + NULL, default_bpp); > + > + if (fsl_dcu_check_var(&info->var, info)) { > + ret = -EINVAL; Propagate the error. > + goto failed_checkvar; > + } > + > + if (register_framebuffer(info) < 0) { > + ret = -EINVAL; ditto > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) > +{ > + struct dcu_fb_data *dcufb = dev_id; > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > + u32 dcu_mode; > + > + if (status) { Save indendation level by bailing out early. > + if (status & DCU_INT_STATUS_UNDRUN) { > + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); > + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), > + dcufb->reg_base + DCU_DCU_MODE); > + udelay(1); > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), > + dcufb->reg_base + DCU_DCU_MODE); > + } > + writel(status, dcufb->reg_base + DCU_INT_STATUS); > + return IRQ_HANDLED; > + } > + return IRQ_NONE; > +} > + > + if (IS_ERR(tcon_clk)) { > + ret = PTR_ERR(tcon_clk); > + goto failed_getclock; > + } > + clk_prepare_enable(tcon_clk); > + > + tcon_reg = of_iomap(tcon_np, 0); Use devm_* > + dcufb->irq = platform_get_irq(pdev, 0); > + if (!dcufb->irq) { > + ret = -EINVAL; > + goto failed_getirq; > + } > + > + ret = request_irq(dcufb->irq, fsl_dcu_irq, 0, DRIVER_NAME, dcufb); Use devm_request_irq > + if (ret) { > + dev_err(&pdev->dev, "could not request irq\n"); > + goto failed_requestirq; > + } > + > + /* Put TCON in bypass mode, so the input signals from DCU are passed > + * through TCON unchanged */ > + ret = bypass_tcon(pdev->dev.of_node); > + if (ret) { > + dev_err(&pdev->dev, "could not bypass TCON\n"); > + goto failed_bypasstcon; > + } > + > + dcufb->clk = devm_clk_get(&pdev->dev, "dcu"); > + if (IS_ERR(dcufb->clk)) { > + dev_err(&pdev->dev, "could not get clock\n"); > + goto failed_getclock; You will return 0 here. > + } > + clk_prepare_enable(dcufb->clk); > + > + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { > + dcufb->fsl_dcu_info[i] > + framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); > + if (!dcufb->fsl_dcu_info[i]) { > + ret = ENOMEM; -ENOMEM > +failed_alloc_framebuffer: > +failed_getclock: > +failed_bypasstcon: > + free_irq(dcufb->irq, dcufb); > +failed_requestirq: > +failed_getirq: > + iounmap(dcufb->reg_base); You used devm_ioremap, so drop this. > +failed_ioremap: > + kfree(dcufb); This is allocated with devm_*. Drop this. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-07-29 11:14 ` Sascha Hauer 0 siblings, 0 replies; 38+ messages in thread From: Sascha Hauer @ 2013-07-29 11:14 UTC (permalink / raw) To: linux-arm-kernel On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > The Display Controller Unit (DCU) module is a system master that > fetches graphics stored in internal or external memory and displays > them on a TFT LCD panel. A wide range of panel sizes is supported > and the timing of the interface signals is highly configurable. > Graphics are read directly from memory and then blended in real-time, > which allows for dynamic content creation with minimal CPU intervention. Only a review of the code inline. Maybe the real question is whether we want to introduce another framebuffer driver at all instead of making it a DRM driver. > + > +#define DRIVER_NAME "fsl-dcu-fb" > + > +#define DCU_DCU_MODE 0x0010 > +#define DCU_MODE_BLEND_ITER(x) (x << 20) What's the result of DCU_MODE_BLEND_ITER(1 + 1)? > +static struct fb_videomode dcu_mode_db[] = { > + { > + .name = "480x272", > + .refresh = 75, > + .xres = 480, > + .yres = 272, > + .pixclock = 91996, > + .left_margin = 2, > + .right_margin = 2, > + .upper_margin = 1, > + .lower_margin = 1, > + .hsync_len = 41, > + .vsync_len = 2, > + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}; We have ways to describe a panel in dt. Use them. > + > +static struct mfb_info mfb_template[] = { > + { > + .index = LAYER0, > + .id = "Layer0", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 0, > + .y_layer_d = 0, > + }, Wrong indentation. > + default: > + printk(KERN_ERR "unsupported color depth: %u\n", > + var->bits_per_pixel); Use dev_* for printing messages in drivers. > +static int fsl_dcu_check_var(struct fb_var_screeninfo *var, > + struct fb_info *info) > +{ > + if (var->xres_virtual < var->xres) > + var->xres_virtual = var->xres; > + if (var->yres_virtual < var->yres) > + var->yres_virtual = var->yres; > + > + if (var->xoffset < 0) > + var->xoffset = 0; > + > + if (var->yoffset < 0) > + var->yoffset = 0; Ever seen an unsigned value going below zero? > + default: > + printk(KERN_ERR "unsupported color depth: %u\n", > + var->bits_per_pixel); BUG(). This can't happen since you make that sure above. > + return -EINVAL; > + } > + > + return 0; > +} > + > +static int calc_div_ratio(struct fb_info *info) > +{ Use a consistent namespace for function names (fsl_dcu_) > + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | > + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD); > + > + enable_controller(info); > +} Make your functions symmetric. If there's update_controller(), the function should do exactly that, it should *not* enable the controller. Call this from the users of this function if necessary. > + if (copy_to_user(buf, &alpha, sizeof(alpha))) > + return -EFAULT; > + break; > + case MFB_SET_ALPHA: > + if (copy_from_user(&alpha, buf, sizeof(alpha))) > + return -EFAULT; > + mfbi->blend = 1; > + mfbi->alpha = alpha; > + fsl_dcu_set_par(info); > + break; Is it still state of the art to introduce ioctls in the fb framework without any kind of documentation? > + default: > + printk(KERN_ERR "unknown ioctl command (0x%08X)\n", cmd); What shall a reader of the kernel log do with a message like this? It's utterly useless when he doesn't even now which device failed here. Just drop this. > +static void enable_interrupts(struct dcu_fb_data *dcufb) > +{ > + u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK); > + > + writel(int_mask & ~DCU_INT_MASK_UNDRUN, dcufb->reg_base + DCU_INT_MASK); > +} Inline this code where you need it. Introducing a function for a single register write seems quite useless. > +static int install_framebuffer(struct fb_info *info) > +{ > + struct mfb_info *mfbi = info->par; > + struct fb_videomode *db = dcu_mode_db; > + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); > + int ret; > + > + info->var.activate = FB_ACTIVATE_NOW; > + info->fbops = &fsl_dcu_ops; > + info->flags = FBINFO_FLAG_DEFAULT; > + info->pseudo_palette = &mfbi->pseudo_palette; > + > + fb_alloc_cmap(&info->cmap, 16, 0); > + > + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, > + NULL, default_bpp); > + > + if (fsl_dcu_check_var(&info->var, info)) { > + ret = -EINVAL; Propagate the error. > + goto failed_checkvar; > + } > + > + if (register_framebuffer(info) < 0) { > + ret = -EINVAL; ditto > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) > +{ > + struct dcu_fb_data *dcufb = dev_id; > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > + u32 dcu_mode; > + > + if (status) { Save indendation level by bailing out early. > + if (status & DCU_INT_STATUS_UNDRUN) { > + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); > + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), > + dcufb->reg_base + DCU_DCU_MODE); > + udelay(1); > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), > + dcufb->reg_base + DCU_DCU_MODE); > + } > + writel(status, dcufb->reg_base + DCU_INT_STATUS); > + return IRQ_HANDLED; > + } > + return IRQ_NONE; > +} > + > + if (IS_ERR(tcon_clk)) { > + ret = PTR_ERR(tcon_clk); > + goto failed_getclock; > + } > + clk_prepare_enable(tcon_clk); > + > + tcon_reg = of_iomap(tcon_np, 0); Use devm_* > + dcufb->irq = platform_get_irq(pdev, 0); > + if (!dcufb->irq) { > + ret = -EINVAL; > + goto failed_getirq; > + } > + > + ret = request_irq(dcufb->irq, fsl_dcu_irq, 0, DRIVER_NAME, dcufb); Use devm_request_irq > + if (ret) { > + dev_err(&pdev->dev, "could not request irq\n"); > + goto failed_requestirq; > + } > + > + /* Put TCON in bypass mode, so the input signals from DCU are passed > + * through TCON unchanged */ > + ret = bypass_tcon(pdev->dev.of_node); > + if (ret) { > + dev_err(&pdev->dev, "could not bypass TCON\n"); > + goto failed_bypasstcon; > + } > + > + dcufb->clk = devm_clk_get(&pdev->dev, "dcu"); > + if (IS_ERR(dcufb->clk)) { > + dev_err(&pdev->dev, "could not get clock\n"); > + goto failed_getclock; You will return 0 here. > + } > + clk_prepare_enable(dcufb->clk); > + > + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { > + dcufb->fsl_dcu_info[i] = > + framebuffer_alloc(sizeof(struct mfb_info), &pdev->dev); > + if (!dcufb->fsl_dcu_info[i]) { > + ret = ENOMEM; -ENOMEM > +failed_alloc_framebuffer: > +failed_getclock: > +failed_bypasstcon: > + free_irq(dcufb->irq, dcufb); > +failed_requestirq: > +failed_getirq: > + iounmap(dcufb->reg_base); You used devm_ioremap, so drop this. > +failed_ioremap: > + kfree(dcufb); This is allocated with devm_*. Drop this. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-29 11:14 ` Sascha Hauer @ 2013-08-05 9:51 ` Wang Huan-B18965 -1 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-05 9:51 UTC (permalink / raw) To: linux-arm-kernel SGksIFNhc2NoYSwNCg0KPiBPbiBGcmksIEp1bCAxMiwgMjAxMyBhdCAwMjowNzo1NVBNICswODAw LCBBbGlzb24gV2FuZyB3cm90ZToNCj4gPiBUaGUgRGlzcGxheSBDb250cm9sbGVyIFVuaXQgKERD VSkgbW9kdWxlIGlzIGEgc3lzdGVtIG1hc3RlciB0aGF0DQo+ID4gZmV0Y2hlcyBncmFwaGljcyBz dG9yZWQgaW4gaW50ZXJuYWwgb3IgZXh0ZXJuYWwgbWVtb3J5IGFuZCBkaXNwbGF5cw0KPiA+IHRo ZW0gb24gYSBURlQgTENEIHBhbmVsLiBBIHdpZGUgcmFuZ2Ugb2YgcGFuZWwgc2l6ZXMgaXMgc3Vw cG9ydGVkIGFuZA0KPiA+IHRoZSB0aW1pbmcgb2YgdGhlIGludGVyZmFjZSBzaWduYWxzIGlzIGhp Z2hseSBjb25maWd1cmFibGUuDQo+ID4gR3JhcGhpY3MgYXJlIHJlYWQgZGlyZWN0bHkgZnJvbSBt ZW1vcnkgYW5kIHRoZW4gYmxlbmRlZCBpbiByZWFsLXRpbWUsDQo+ID4gd2hpY2ggYWxsb3dzIGZv ciBkeW5hbWljIGNvbnRlbnQgY3JlYXRpb24gd2l0aCBtaW5pbWFsIENQVQ0KPiBpbnRlcnZlbnRp b24uDQo+IA0KPiBPbmx5IGEgcmV2aWV3IG9mIHRoZSBjb2RlIGlubGluZS4NCj4gDQo+IE1heWJl IHRoZSByZWFsIHF1ZXN0aW9uIGlzIHdoZXRoZXIgd2Ugd2FudCB0byBpbnRyb2R1Y2UgYW5vdGhl cg0KPiBmcmFtZWJ1ZmZlciBkcml2ZXIgYXQgYWxsIGluc3RlYWQgb2YgbWFraW5nIGl0IGEgRFJN IGRyaXZlci4NCltBbGlzb24gV2FuZ10gSSB0aGluayBEQ1UgbW9kdWxlIGlzIG1vcmUgc3VpdGFi bGUgdG8gYmUgZGVzaWduZWQgYXMgYSBmcmFtZWJ1ZmZlciBkcml2ZXIgdGhhbiBhIERSTSBkcml2 ZXIuIEp1c3QgbGlrZSBESVUgZnJhbWVidWZmZXIgZHJpdmVyIGZvciBQb3dlclBDLg0KPiANCj4g PiArDQo+ID4gKyNkZWZpbmUgRFJJVkVSX05BTUUJCQkiZnNsLWRjdS1mYiINCj4gPiArDQo+ID4g KyNkZWZpbmUgRENVX0RDVV9NT0RFCQkJMHgwMDEwDQo+ID4gKyNkZWZpbmUgRENVX01PREVfQkxF TkRfSVRFUih4KQkJKHggPDwgMjApDQo+IA0KPiBXaGF0J3MgdGhlIHJlc3VsdCBvZiBEQ1VfTU9E RV9CTEVORF9JVEVSKDEgKyAxKT8NCltBbGlzb24gV2FuZ10gSXMgaXQgcmVhbGx5IG5lY2Vzc2Fy eT8gSSBkb24ndCB1c2UgdGhpcyBtYWNybyBsaWtlIERDVV9NT0RFX0JMRU5EX0lURVIoMSArIDEp LCBqdXN0IHVzZSBEQ1VfTU9ERV9CTEVORF9JVEVSKDIpLg0KPiANCj4gPiArc3RhdGljIHN0cnVj dCBmYl92aWRlb21vZGUgZGN1X21vZGVfZGJbXSA9IHsNCj4gPiArCXsNCj4gPiArCQkubmFtZQkJ PSAiNDgweDI3MiIsDQo+ID4gKwkJLnJlZnJlc2gJPSA3NSwNCj4gPiArCQkueHJlcwkJPSA0ODAs DQo+ID4gKwkJLnlyZXMJCT0gMjcyLA0KPiA+ICsJCS5waXhjbG9jawk9IDkxOTk2LA0KPiA+ICsJ CS5sZWZ0X21hcmdpbgk9IDIsDQo+ID4gKwkJLnJpZ2h0X21hcmdpbgk9IDIsDQo+ID4gKwkJLnVw cGVyX21hcmdpbgk9IDEsDQo+ID4gKwkJLmxvd2VyX21hcmdpbgk9IDEsDQo+ID4gKwkJLmhzeW5j X2xlbgk9IDQxLA0KPiA+ICsJCS52c3luY19sZW4JPSAyLA0KPiA+ICsJCS5zeW5jCQk9IEZCX1NZ TkNfQ09NUF9ISUdIX0FDVCB8IEZCX1NZTkNfVkVSVF9ISUdIX0FDVCwNCj4gPiArCQkudm1vZGUJ CT0gRkJfVk1PREVfTk9OSU5URVJMQUNFRCwNCj4gPiArCX0sDQo+ID4gK307DQo+IA0KPiBXZSBo YXZlIHdheXMgdG8gZGVzY3JpYmUgYSBwYW5lbCBpbiBkdC4gVXNlIHRoZW0uDQpbQWxpc29uIFdh bmddIE9rLiBJIGRvbid0IGtub3cgaXQgaXMgY29tbW9uIHRvIGRlc2NyaWJlIHRoZSBwYW5lbCBp biBkdHMgZm9yIHRoZSBsYXRlc3Qga2VybmVsLiBUaGFua3MuDQo+IA0KPiA+ICsNCj4gPiArc3Rh dGljIHN0cnVjdCBtZmJfaW5mbyBtZmJfdGVtcGxhdGVbXSA9IHsNCj4gPiArCXsNCj4gPiArCS5p bmRleCA9IExBWUVSMCwNCj4gPiArCS5pZCA9ICJMYXllcjAiLA0KPiA+ICsJLmFscGhhID0gMHhm ZiwNCj4gPiArCS5ibGVuZCA9IDAsDQo+ID4gKwkuY291bnQgPSAwLA0KPiA+ICsJLnhfbGF5ZXJf ZCA9IDAsDQo+ID4gKwkueV9sYXllcl9kID0gMCwNCj4gPiArCX0sDQo+IA0KPiBXcm9uZyBpbmRl bnRhdGlvbi4NCltBbGlzb24gV2FuZ10gSSB3aWxsIGZpeCBpdCBpbiBuZXh0IHZlcnNpb24uDQo+ IA0KPiA+ICsJZGVmYXVsdDoNCj4gPiArCQlwcmludGsoS0VSTl9FUlIgInVuc3VwcG9ydGVkIGNv bG9yIGRlcHRoOiAldVxuIiwNCj4gPiArCQkJdmFyLT5iaXRzX3Blcl9waXhlbCk7DQo+IA0KPiBV c2UgZGV2XyogZm9yIHByaW50aW5nIG1lc3NhZ2VzIGluIGRyaXZlcnMuDQpbQWxpc29uIFdhbmdd IE9rLg0KPiANCj4gPiArc3RhdGljIGludCBmc2xfZGN1X2NoZWNrX3ZhcihzdHJ1Y3QgZmJfdmFy X3NjcmVlbmluZm8gKnZhciwNCj4gPiArCQlzdHJ1Y3QgZmJfaW5mbyAqaW5mbykNCj4gPiArew0K PiA+ICsJaWYgKHZhci0+eHJlc192aXJ0dWFsIDwgdmFyLT54cmVzKQ0KPiA+ICsJCXZhci0+eHJl c192aXJ0dWFsID0gdmFyLT54cmVzOw0KPiA+ICsJaWYgKHZhci0+eXJlc192aXJ0dWFsIDwgdmFy LT55cmVzKQ0KPiA+ICsJCXZhci0+eXJlc192aXJ0dWFsID0gdmFyLT55cmVzOw0KPiA+ICsNCj4g PiArCWlmICh2YXItPnhvZmZzZXQgPCAwKQ0KPiA+ICsJCXZhci0+eG9mZnNldCA9IDA7DQo+ID4g Kw0KPiA+ICsJaWYgKHZhci0+eW9mZnNldCA8IDApDQo+ID4gKwkJdmFyLT55b2Zmc2V0ID0gMDsN Cj4gDQo+IEV2ZXIgc2VlbiBhbiB1bnNpZ25lZCB2YWx1ZSBnb2luZyBiZWxvdyB6ZXJvPw0KW0Fs aXNvbiBXYW5nXSBZb3UgYXJlIHJpZ2h0LCBJIHdpbGwgcmVtb3ZlIHRoZW0gaW4gbmV4dCB2ZXJz aW9uLg0KPiANCj4gPiArCWRlZmF1bHQ6DQo+ID4gKwkJcHJpbnRrKEtFUk5fRVJSICJ1bnN1cHBv cnRlZCBjb2xvciBkZXB0aDogJXVcbiIsDQo+ID4gKwkJCXZhci0+Yml0c19wZXJfcGl4ZWwpOw0K PiANCj4gQlVHKCkuIFRoaXMgY2FuJ3QgaGFwcGVuIHNpbmNlIHlvdSBtYWtlIHRoYXQgc3VyZSBh Ym92ZS4NCltBbGlzb24gV2FuZ10gWW91IGFyZSByaWdodCwgSSB3aWxsIHJlbW92ZSBpdCBpbiBu ZXh0IHZlcnNpb24uDQo+IA0KPiA+ICsJCXJldHVybiAtRUlOVkFMOw0KPiA+ICsJfQ0KPiA+ICsN Cj4gPiArCXJldHVybiAwOw0KPiA+ICt9DQo+ID4gKw0KPiA+ICtzdGF0aWMgaW50IGNhbGNfZGl2 X3JhdGlvKHN0cnVjdCBmYl9pbmZvICppbmZvKSB7DQo+IA0KPiBVc2UgYSBjb25zaXN0ZW50IG5h bWVzcGFjZSBmb3IgZnVuY3Rpb24gbmFtZXMgKGZzbF9kY3VfKQ0KW0FsaXNvbiBXYW5nXSBJcyBp dCBuZWNlc3NhcnkgdG8gdXNlIGEgY29uc2lzdGVudCBuYW1lc3BhY2UgZm9yIHRoaXMgZ2VuZXJp YyBmdW5jdGlvbj8gSSB0aGluayBpdCBpcyBuZWNlc3NhcnkgdG8gdXNlIGEgY29uc2lzdGVudCBu YW1lc3BhY2UgKGZzbF9kY3VfKSBmb3IgdGhlIGZ1bmN0aW9uIG5hbWVzIGluIHN0cnVjdHVyZSBm c2xfZGN1X29wcy4NCj4gDQo+ID4gKwl3cml0ZWwoRENVX1RIUkVTSE9MRF9MU19CRl9WUygweDMp IHwNCj4gRENVX1RIUkVTSE9MRF9PVVRfQlVGX0hJR0goMHg3OCkgfA0KPiA+ICsJCURDVV9USFJF U0hPTERfT1VUX0JVRl9MT1coMCksIGRjdWZiLT5yZWdfYmFzZSArDQo+IERDVV9USFJFU0hPTEQp Ow0KPiA+ICsNCj4gPiArCWVuYWJsZV9jb250cm9sbGVyKGluZm8pOw0KPiA+ICt9DQo+IA0KPiBN YWtlIHlvdXIgZnVuY3Rpb25zIHN5bW1ldHJpYy4gSWYgdGhlcmUncyB1cGRhdGVfY29udHJvbGxl cigpLCB0aGUNCj4gZnVuY3Rpb24gc2hvdWxkIGRvIGV4YWN0bHkgdGhhdCwgaXQgc2hvdWxkICpu b3QqIGVuYWJsZSB0aGUgY29udHJvbGxlci4NCj4gQ2FsbCB0aGlzIGZyb20gdGhlIHVzZXJzIG9m IHRoaXMgZnVuY3Rpb24gaWYgbmVjZXNzYXJ5Lg0KW0FsaXNvbiBXYW5nXSBPaywgSSB3aWxsIG1v dmUgdGhpcyBmdW5jdGlvbiBvdXQsIGFuZCBhZGQgaXQgaGVyZS4NCmlmIChtZmJpLT5pbmRleCA9 PSBMQVlFUjApIHsNCgl1cGRhdGVfY29udHJvbGxlcihpbmZvKTsNCisJZW5hYmxlX2NvbnRyb2xs ZXIoaW5mbyk7DQp9DQo+IA0KPiA+ICsJCWlmIChjb3B5X3RvX3VzZXIoYnVmLCAmYWxwaGEsIHNp emVvZihhbHBoYSkpKQ0KPiA+ICsJCQlyZXR1cm4gLUVGQVVMVDsNCj4gPiArCQlicmVhazsNCj4g PiArCWNhc2UgTUZCX1NFVF9BTFBIQToNCj4gPiArCQlpZiAoY29weV9mcm9tX3VzZXIoJmFscGhh LCBidWYsIHNpemVvZihhbHBoYSkpKQ0KPiA+ICsJCQlyZXR1cm4gLUVGQVVMVDsNCj4gPiArCQlt ZmJpLT5ibGVuZCA9IDE7DQo+ID4gKwkJbWZiaS0+YWxwaGEgPSBhbHBoYTsNCj4gPiArCQlmc2xf ZGN1X3NldF9wYXIoaW5mbyk7DQo+ID4gKwkJYnJlYWs7DQo+IA0KPiBJcyBpdCBzdGlsbCBzdGF0 ZSBvZiB0aGUgYXJ0IHRvIGludHJvZHVjZSBpb2N0bHMgaW4gdGhlIGZiIGZyYW1ld29yaw0KPiB3 aXRob3V0IGFueSBraW5kIG9mIGRvY3VtZW50YXRpb24/DQpbQWxpc29uIFdhbmddIERvIHlvdSBt ZWFuIEkgbmVlZCB0byBhZGQgYSBkb2N1bWVudGF0aW9uIGluIERvY3VtZW50YXRpb24vZmIvPw0K PiANCj4gPiArCWRlZmF1bHQ6DQo+ID4gKwkJcHJpbnRrKEtFUk5fRVJSICJ1bmtub3duIGlvY3Rs IGNvbW1hbmQgKDB4JTA4WClcbiIsIGNtZCk7DQo+IA0KPiBXaGF0IHNoYWxsIGEgcmVhZGVyIG9m IHRoZSBrZXJuZWwgbG9nIGRvIHdpdGggYSBtZXNzYWdlIGxpa2UgdGhpcz8gSXQncw0KPiB1dHRl cmx5IHVzZWxlc3Mgd2hlbiBoZSBkb2Vzbid0IGV2ZW4gbm93IHdoaWNoIGRldmljZSBmYWlsZWQg aGVyZS4gSnVzdA0KPiBkcm9wIHRoaXMuDQpbQWxpc29uIFdhbmddIE9rLg0KPiANCj4gPiArc3Rh dGljIHZvaWQgZW5hYmxlX2ludGVycnVwdHMoc3RydWN0IGRjdV9mYl9kYXRhICpkY3VmYikgew0K PiA+ICsJdTMyIGludF9tYXNrID0gcmVhZGwoZGN1ZmItPnJlZ19iYXNlICsgRENVX0lOVF9NQVNL KTsNCj4gPiArDQo+ID4gKwl3cml0ZWwoaW50X21hc2sgJiB+RENVX0lOVF9NQVNLX1VORFJVTiwg ZGN1ZmItPnJlZ19iYXNlICsNCj4gPiArRENVX0lOVF9NQVNLKTsgfQ0KPiANCj4gSW5saW5lIHRo aXMgY29kZSB3aGVyZSB5b3UgbmVlZCBpdC4gSW50cm9kdWNpbmcgYSBmdW5jdGlvbiBmb3IgYSBz aW5nbGUNCj4gcmVnaXN0ZXIgd3JpdGUgc2VlbXMgcXVpdGUgdXNlbGVzcy4NCltBbGlzb24gV2Fu Z10gT2ssIEkgd2lsbCBpbmxpbmUgaXQuDQo+IA0KPiA+ICtzdGF0aWMgaW50IGluc3RhbGxfZnJh bWVidWZmZXIoc3RydWN0IGZiX2luZm8gKmluZm8pIHsNCj4gPiArCXN0cnVjdCBtZmJfaW5mbyAq bWZiaSA9IGluZm8tPnBhcjsNCj4gPiArCXN0cnVjdCBmYl92aWRlb21vZGUgKmRiID0gZGN1X21v ZGVfZGI7DQo+ID4gKwl1bnNpZ25lZCBpbnQgZGJzaXplID0gQVJSQVlfU0laRShkY3VfbW9kZV9k Yik7DQo+ID4gKwlpbnQgcmV0Ow0KPiA+ICsNCj4gPiArCWluZm8tPnZhci5hY3RpdmF0ZSA9IEZC X0FDVElWQVRFX05PVzsNCj4gPiArCWluZm8tPmZib3BzID0gJmZzbF9kY3Vfb3BzOw0KPiA+ICsJ aW5mby0+ZmxhZ3MgPSBGQklORk9fRkxBR19ERUZBVUxUOw0KPiA+ICsJaW5mby0+cHNldWRvX3Bh bGV0dGUgPSAmbWZiaS0+cHNldWRvX3BhbGV0dGU7DQo+ID4gKw0KPiA+ICsJZmJfYWxsb2NfY21h cCgmaW5mby0+Y21hcCwgMTYsIDApOw0KPiA+ICsNCj4gPiArCXJldCA9IGZiX2ZpbmRfbW9kZSgm aW5mby0+dmFyLCBpbmZvLCBmYl9tb2RlLCBkYiwgZGJzaXplLA0KPiA+ICsJCQlOVUxMLCBkZWZh dWx0X2JwcCk7DQo+ID4gKw0KPiA+ICsJaWYgKGZzbF9kY3VfY2hlY2tfdmFyKCZpbmZvLT52YXIs IGluZm8pKSB7DQo+ID4gKwkJcmV0ID0gLUVJTlZBTDsNCj4gDQo+IFByb3BhZ2F0ZSB0aGUgZXJy b3IuDQpbQWxpc29uIFdhbmddIEkgd2lsbCBmaXggaW4gbmV4dCB2ZXJzaW9uLg0KPiANCj4gPiAr CQlnb3RvIGZhaWxlZF9jaGVja3ZhcjsNCj4gPiArCX0NCj4gPiArDQo+ID4gKwlpZiAocmVnaXN0 ZXJfZnJhbWVidWZmZXIoaW5mbykgPCAwKSB7DQo+ID4gKwkJcmV0ID0gLUVJTlZBTDsNCj4gDQo+ IGRpdHRvDQpbQWxpc29uIFdhbmddIEkgd2lsbCBmaXggaW4gbmV4dCB2ZXJzaW9uLg0KPiANCj4g PiArc3RhdGljIGlycXJldHVybl90IGZzbF9kY3VfaXJxKGludCBpcnEsIHZvaWQgKmRldl9pZCkg ew0KPiA+ICsJc3RydWN0IGRjdV9mYl9kYXRhICpkY3VmYiA9IGRldl9pZDsNCj4gPiArCXVuc2ln bmVkIGludCBzdGF0dXMgPSByZWFkbChkY3VmYi0+cmVnX2Jhc2UgKyBEQ1VfSU5UX1NUQVRVUyk7 DQo+ID4gKwl1MzIgZGN1X21vZGU7DQo+ID4gKw0KPiA+ICsJaWYgKHN0YXR1cykgew0KPiANCj4g U2F2ZSBpbmRlbmRhdGlvbiBsZXZlbCBieSBiYWlsaW5nIG91dCBlYXJseS4NCltBbGlzb24gV2Fu Z10gV2hhdCBkbyB5b3UgbWVhbj8NCj4gDQo+ID4gKwkJaWYgKHN0YXR1cyAmIERDVV9JTlRfU1RB VFVTX1VORFJVTikgew0KPiA+ICsJCQlkY3VfbW9kZSA9IHJlYWRsKGRjdWZiLT5yZWdfYmFzZSAr IERDVV9EQ1VfTU9ERSk7DQo+ID4gKwkJCWRjdV9tb2RlICY9IH5EQ1VfTU9ERV9EQ1VfTU9ERV9N QVNLOw0KPiA+ICsJCQl3cml0ZWwoZGN1X21vZGUgfCBEQ1VfTU9ERV9EQ1VfTU9ERShEQ1VfTU9E RV9PRkYpLA0KPiA+ICsJCQkJZGN1ZmItPnJlZ19iYXNlICsgRENVX0RDVV9NT0RFKTsNCj4gPiAr CQkJdWRlbGF5KDEpOw0KPiA+ICsJCQl3cml0ZWwoZGN1X21vZGUgfCBEQ1VfTU9ERV9EQ1VfTU9E RShEQ1VfTU9ERV9OT1JNQUwpLA0KPiA+ICsJCQkJZGN1ZmItPnJlZ19iYXNlICsgRENVX0RDVV9N T0RFKTsNCj4gPiArCQl9DQo+ID4gKwkJd3JpdGVsKHN0YXR1cywgZGN1ZmItPnJlZ19iYXNlICsg RENVX0lOVF9TVEFUVVMpOw0KPiA+ICsJCXJldHVybiBJUlFfSEFORExFRDsNCj4gPiArCX0NCj4g PiArCXJldHVybiBJUlFfTk9ORTsNCj4gPiArfQ0KPiA+ICsNCj4gPiArCWlmIChJU19FUlIodGNv bl9jbGspKSB7DQo+ID4gKwkJcmV0ID0gUFRSX0VSUih0Y29uX2Nsayk7DQo+ID4gKwkJZ290byBm YWlsZWRfZ2V0Y2xvY2s7DQo+ID4gKwl9DQo+ID4gKwljbGtfcHJlcGFyZV9lbmFibGUodGNvbl9j bGspOw0KPiA+ICsNCj4gPiArCXRjb25fcmVnID0gb2ZfaW9tYXAodGNvbl9ucCwgMCk7DQo+IA0K PiBVc2UgZGV2bV8qDQpbQWxpc29uIFdhbmddIE9rLg0KPiANCj4gPiArCWRjdWZiLT5pcnEgPSBw bGF0Zm9ybV9nZXRfaXJxKHBkZXYsIDApOw0KPiA+ICsJaWYgKCFkY3VmYi0+aXJxKSB7DQo+ID4g KwkJcmV0ID0gLUVJTlZBTDsNCj4gPiArCQlnb3RvIGZhaWxlZF9nZXRpcnE7DQo+ID4gKwl9DQo+ ID4gKw0KPiA+ICsJcmV0ID0gcmVxdWVzdF9pcnEoZGN1ZmItPmlycSwgZnNsX2RjdV9pcnEsIDAs IERSSVZFUl9OQU1FLCBkY3VmYik7DQo+IA0KPiBVc2UgZGV2bV9yZXF1ZXN0X2lycQ0KW0FsaXNv biBXYW5nXSBPay4NCj4gDQo+ID4gKwlpZiAocmV0KSB7DQo+ID4gKwkJZGV2X2VycigmcGRldi0+ ZGV2LCAiY291bGQgbm90IHJlcXVlc3QgaXJxXG4iKTsNCj4gPiArCQlnb3RvIGZhaWxlZF9yZXF1 ZXN0aXJxOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCS8qIFB1dCBUQ09OIGluIGJ5cGFzcyBtb2Rl LCBzbyB0aGUgaW5wdXQgc2lnbmFscyBmcm9tIERDVSBhcmUNCj4gcGFzc2VkDQo+ID4gKwkgKiB0 aHJvdWdoIFRDT04gdW5jaGFuZ2VkICovDQo+ID4gKwlyZXQgPSBieXBhc3NfdGNvbihwZGV2LT5k ZXYub2Zfbm9kZSk7DQo+ID4gKwlpZiAocmV0KSB7DQo+ID4gKwkJZGV2X2VycigmcGRldi0+ZGV2 LCAiY291bGQgbm90IGJ5cGFzcyBUQ09OXG4iKTsNCj4gPiArCQlnb3RvIGZhaWxlZF9ieXBhc3N0 Y29uOw0KPiA+ICsJfQ0KPiA+ICsNCj4gPiArCWRjdWZiLT5jbGsgPSBkZXZtX2Nsa19nZXQoJnBk ZXYtPmRldiwgImRjdSIpOw0KPiA+ICsJaWYgKElTX0VSUihkY3VmYi0+Y2xrKSkgew0KPiA+ICsJ CWRldl9lcnIoJnBkZXYtPmRldiwgImNvdWxkIG5vdCBnZXQgY2xvY2tcbiIpOw0KPiA+ICsJCWdv dG8gZmFpbGVkX2dldGNsb2NrOw0KPiANCj4gWW91IHdpbGwgcmV0dXJuIDAgaGVyZS4NCltBbGlz b24gV2FuZ10gWW91IGFyZSByaWdodCwgSSB3aWxsIGZpeCBpdCBpbiBuZXh0IHZlcnNpb24uDQo+ IA0KPiA+ICsJfQ0KPiA+ICsJY2xrX3ByZXBhcmVfZW5hYmxlKGRjdWZiLT5jbGspOw0KPiA+ICsN Cj4gPiArCWZvciAoaSA9IDA7IGkgPCBBUlJBWV9TSVpFKGRjdWZiLT5mc2xfZGN1X2luZm8pOyBp KyspIHsNCj4gPiArCQlkY3VmYi0+ZnNsX2RjdV9pbmZvW2ldID0NCj4gPiArCQkJZnJhbWVidWZm ZXJfYWxsb2Moc2l6ZW9mKHN0cnVjdCBtZmJfaW5mbyksICZwZGV2LQ0KPiA+ZGV2KTsNCj4gPiAr CQlpZiAoIWRjdWZiLT5mc2xfZGN1X2luZm9baV0pIHsNCj4gPiArCQkJcmV0ID0gRU5PTUVNOw0K PiANCj4gLUVOT01FTQ0KPiANCj4gPiArZmFpbGVkX2FsbG9jX2ZyYW1lYnVmZmVyOg0KPiA+ICtm YWlsZWRfZ2V0Y2xvY2s6DQo+ID4gK2ZhaWxlZF9ieXBhc3N0Y29uOg0KPiA+ICsJZnJlZV9pcnEo ZGN1ZmItPmlycSwgZGN1ZmIpOw0KPiA+ICtmYWlsZWRfcmVxdWVzdGlycToNCj4gPiArZmFpbGVk X2dldGlycToNCj4gPiArCWlvdW5tYXAoZGN1ZmItPnJlZ19iYXNlKTsNCj4gDQo+IFlvdSB1c2Vk IGRldm1faW9yZW1hcCwgc28gZHJvcCB0aGlzLg0KW0FsaXNvbiBXYW5nXSBPay4NCj4gDQo+ID4g K2ZhaWxlZF9pb3JlbWFwOg0KPiA+ICsJa2ZyZWUoZGN1ZmIpOw0KPiANCj4gVGhpcyBpcyBhbGxv Y2F0ZWQgd2l0aCBkZXZtXyouIERyb3AgdGhpcy4NCltBbGlzb24gV2FuZ10gT2suDQoNClRoYW5r cyBmb3IgeW91ciBjb21tZW50cy4NCg0KDQpCZXN0IFJlZ2FyZHMsDQpBbGlzb24gV2FuZw0KDQoN Cg= ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-05 9:51 ` Wang Huan-B18965 0 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-05 9:51 UTC (permalink / raw) To: linux-arm-kernel Hi, Sascha, > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > The Display Controller Unit (DCU) module is a system master that > > fetches graphics stored in internal or external memory and displays > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > the timing of the interface signals is highly configurable. > > Graphics are read directly from memory and then blended in real-time, > > which allows for dynamic content creation with minimal CPU > intervention. > > Only a review of the code inline. > > Maybe the real question is whether we want to introduce another > framebuffer driver at all instead of making it a DRM driver. [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. > > > + > > +#define DRIVER_NAME "fsl-dcu-fb" > > + > > +#define DCU_DCU_MODE 0x0010 > > +#define DCU_MODE_BLEND_ITER(x) (x << 20) > > What's the result of DCU_MODE_BLEND_ITER(1 + 1)? [Alison Wang] Is it really necessary? I don't use this macro like DCU_MODE_BLEND_ITER(1 + 1), just use DCU_MODE_BLEND_ITER(2). > > > +static struct fb_videomode dcu_mode_db[] = { > > + { > > + .name = "480x272", > > + .refresh = 75, > > + .xres = 480, > > + .yres = 272, > > + .pixclock = 91996, > > + .left_margin = 2, > > + .right_margin = 2, > > + .upper_margin = 1, > > + .lower_margin = 1, > > + .hsync_len = 41, > > + .vsync_len = 2, > > + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, > > + .vmode = FB_VMODE_NONINTERLACED, > > + }, > > +}; > > We have ways to describe a panel in dt. Use them. [Alison Wang] Ok. I don't know it is common to describe the panel in dts for the latest kernel. Thanks. > > > + > > +static struct mfb_info mfb_template[] = { > > + { > > + .index = LAYER0, > > + .id = "Layer0", > > + .alpha = 0xff, > > + .blend = 0, > > + .count = 0, > > + .x_layer_d = 0, > > + .y_layer_d = 0, > > + }, > > Wrong indentation. [Alison Wang] I will fix it in next version. > > > + default: > > + printk(KERN_ERR "unsupported color depth: %u\n", > > + var->bits_per_pixel); > > Use dev_* for printing messages in drivers. [Alison Wang] Ok. > > > +static int fsl_dcu_check_var(struct fb_var_screeninfo *var, > > + struct fb_info *info) > > +{ > > + if (var->xres_virtual < var->xres) > > + var->xres_virtual = var->xres; > > + if (var->yres_virtual < var->yres) > > + var->yres_virtual = var->yres; > > + > > + if (var->xoffset < 0) > > + var->xoffset = 0; > > + > > + if (var->yoffset < 0) > > + var->yoffset = 0; > > Ever seen an unsigned value going below zero? [Alison Wang] You are right, I will remove them in next version. > > > + default: > > + printk(KERN_ERR "unsupported color depth: %u\n", > > + var->bits_per_pixel); > > BUG(). This can't happen since you make that sure above. [Alison Wang] You are right, I will remove it in next version. > > > + return -EINVAL; > > + } > > + > > + return 0; > > +} > > + > > +static int calc_div_ratio(struct fb_info *info) { > > Use a consistent namespace for function names (fsl_dcu_) [Alison Wang] Is it necessary to use a consistent namespace for this generic function? I think it is necessary to use a consistent namespace (fsl_dcu_) for the function names in structure fsl_dcu_ops. > > > + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | > DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | > > + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + > DCU_THRESHOLD); > > + > > + enable_controller(info); > > +} > > Make your functions symmetric. If there's update_controller(), the > function should do exactly that, it should *not* enable the controller. > Call this from the users of this function if necessary. [Alison Wang] Ok, I will move this function out, and add it here. if (mfbi->index == LAYER0) { update_controller(info); + enable_controller(info); } > > > + if (copy_to_user(buf, &alpha, sizeof(alpha))) > > + return -EFAULT; > > + break; > > + case MFB_SET_ALPHA: > > + if (copy_from_user(&alpha, buf, sizeof(alpha))) > > + return -EFAULT; > > + mfbi->blend = 1; > > + mfbi->alpha = alpha; > > + fsl_dcu_set_par(info); > > + break; > > Is it still state of the art to introduce ioctls in the fb framework > without any kind of documentation? [Alison Wang] Do you mean I need to add a documentation in Documentation/fb/? > > > + default: > > + printk(KERN_ERR "unknown ioctl command (0x%08X)\n", cmd); > > What shall a reader of the kernel log do with a message like this? It's > utterly useless when he doesn't even now which device failed here. Just > drop this. [Alison Wang] Ok. > > > +static void enable_interrupts(struct dcu_fb_data *dcufb) { > > + u32 int_mask = readl(dcufb->reg_base + DCU_INT_MASK); > > + > > + writel(int_mask & ~DCU_INT_MASK_UNDRUN, dcufb->reg_base + > > +DCU_INT_MASK); } > > Inline this code where you need it. Introducing a function for a single > register write seems quite useless. [Alison Wang] Ok, I will inline it. > > > +static int install_framebuffer(struct fb_info *info) { > > + struct mfb_info *mfbi = info->par; > > + struct fb_videomode *db = dcu_mode_db; > > + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); > > + int ret; > > + > > + info->var.activate = FB_ACTIVATE_NOW; > > + info->fbops = &fsl_dcu_ops; > > + info->flags = FBINFO_FLAG_DEFAULT; > > + info->pseudo_palette = &mfbi->pseudo_palette; > > + > > + fb_alloc_cmap(&info->cmap, 16, 0); > > + > > + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, > > + NULL, default_bpp); > > + > > + if (fsl_dcu_check_var(&info->var, info)) { > > + ret = -EINVAL; > > Propagate the error. [Alison Wang] I will fix in next version. > > > + goto failed_checkvar; > > + } > > + > > + if (register_framebuffer(info) < 0) { > > + ret = -EINVAL; > > ditto [Alison Wang] I will fix in next version. > > > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) { > > + struct dcu_fb_data *dcufb = dev_id; > > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > > + u32 dcu_mode; > > + > > + if (status) { > > Save indendation level by bailing out early. [Alison Wang] What do you mean? > > > + if (status & DCU_INT_STATUS_UNDRUN) { > > + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); > > + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; > > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), > > + dcufb->reg_base + DCU_DCU_MODE); > > + udelay(1); > > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), > > + dcufb->reg_base + DCU_DCU_MODE); > > + } > > + writel(status, dcufb->reg_base + DCU_INT_STATUS); > > + return IRQ_HANDLED; > > + } > > + return IRQ_NONE; > > +} > > + > > + if (IS_ERR(tcon_clk)) { > > + ret = PTR_ERR(tcon_clk); > > + goto failed_getclock; > > + } > > + clk_prepare_enable(tcon_clk); > > + > > + tcon_reg = of_iomap(tcon_np, 0); > > Use devm_* [Alison Wang] Ok. > > > + dcufb->irq = platform_get_irq(pdev, 0); > > + if (!dcufb->irq) { > > + ret = -EINVAL; > > + goto failed_getirq; > > + } > > + > > + ret = request_irq(dcufb->irq, fsl_dcu_irq, 0, DRIVER_NAME, dcufb); > > Use devm_request_irq [Alison Wang] Ok. > > > + if (ret) { > > + dev_err(&pdev->dev, "could not request irq\n"); > > + goto failed_requestirq; > > + } > > + > > + /* Put TCON in bypass mode, so the input signals from DCU are > passed > > + * through TCON unchanged */ > > + ret = bypass_tcon(pdev->dev.of_node); > > + if (ret) { > > + dev_err(&pdev->dev, "could not bypass TCON\n"); > > + goto failed_bypasstcon; > > + } > > + > > + dcufb->clk = devm_clk_get(&pdev->dev, "dcu"); > > + if (IS_ERR(dcufb->clk)) { > > + dev_err(&pdev->dev, "could not get clock\n"); > > + goto failed_getclock; > > You will return 0 here. [Alison Wang] You are right, I will fix it in next version. > > > + } > > + clk_prepare_enable(dcufb->clk); > > + > > + for (i = 0; i < ARRAY_SIZE(dcufb->fsl_dcu_info); i++) { > > + dcufb->fsl_dcu_info[i] = > > + framebuffer_alloc(sizeof(struct mfb_info), &pdev- > >dev); > > + if (!dcufb->fsl_dcu_info[i]) { > > + ret = ENOMEM; > > -ENOMEM > > > +failed_alloc_framebuffer: > > +failed_getclock: > > +failed_bypasstcon: > > + free_irq(dcufb->irq, dcufb); > > +failed_requestirq: > > +failed_getirq: > > + iounmap(dcufb->reg_base); > > You used devm_ioremap, so drop this. [Alison Wang] Ok. > > > +failed_ioremap: > > + kfree(dcufb); > > This is allocated with devm_*. Drop this. [Alison Wang] Ok. Thanks for your comments. Best Regards, Alison Wang ^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-08-05 9:51 ` Wang Huan-B18965 @ 2013-08-05 10:06 ` Sascha Hauer -1 siblings, 0 replies; 38+ messages in thread From: Sascha Hauer @ 2013-08-05 10:06 UTC (permalink / raw) To: linux-arm-kernel On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > Hi, Sascha, > > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > The Display Controller Unit (DCU) module is a system master that > > > fetches graphics stored in internal or external memory and displays > > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > > the timing of the interface signals is highly configurable. > > > Graphics are read directly from memory and then blended in real-time, > > > which allows for dynamic content creation with minimal CPU > > intervention. > > > > Only a review of the code inline. > > > > Maybe the real question is whether we want to introduce another > > framebuffer driver at all instead of making it a DRM driver. > [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. > > > > > + > > > +#define DRIVER_NAME "fsl-dcu-fb" > > > + > > > +#define DCU_DCU_MODE 0x0010 > > > +#define DCU_MODE_BLEND_ITER(x) (x << 20) > > > > What's the result of DCU_MODE_BLEND_ITER(1 + 1)? > [Alison Wang] Is it really necessary? I don't use this macro like DCU_MODE_BLEND_ITER(1 + 1), just use DCU_MODE_BLEND_ITER(2). <irony> No it's not necessary. We can just add incorrect macros everywhere and fix them as necessary after a long bug squashing session </irony> YES! This is necessary. > > > + return 0; > > > +} > > > + > > > +static int calc_div_ratio(struct fb_info *info) { > > > > Use a consistent namespace for function names (fsl_dcu_) > [Alison Wang] Is it necessary to use a consistent namespace for this generic function? I think it is necessary to use a consistent namespace (fsl_dcu_) for the function names in structure fsl_dcu_ops. This function calculates some divider out of a struct fb_info. This is by no means generic. > > > + if (copy_to_user(buf, &alpha, sizeof(alpha))) > > > + return -EFAULT; > > > + break; > > > + case MFB_SET_ALPHA: > > > + if (copy_from_user(&alpha, buf, sizeof(alpha))) > > > + return -EFAULT; > > > + mfbi->blend = 1; > > > + mfbi->alpha = alpha; > > > + fsl_dcu_set_par(info); > > > + break; > > > > Is it still state of the art to introduce ioctls in the fb framework > > without any kind of documentation? > [Alison Wang] Do you mean I need to add a documentation in Documentation/fb/? This was more a question to the fb maintainers. > > > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) { > > > + struct dcu_fb_data *dcufb = dev_id; > > > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > > > + u32 dcu_mode; > > > + > > > + if (status) { > > > > Save indendation level by bailing out early. > [Alison Wang] What do you mean? Instead of doing: if (bla) { dothis(); dothat(); return; } return; it's easier to read: if (!bla) return; dothis(); dothat(); return; Note that dothis() and dothat() are one indentation level to the left and thus have more space per line. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-05 10:06 ` Sascha Hauer 0 siblings, 0 replies; 38+ messages in thread From: Sascha Hauer @ 2013-08-05 10:06 UTC (permalink / raw) To: linux-arm-kernel On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > Hi, Sascha, > > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > The Display Controller Unit (DCU) module is a system master that > > > fetches graphics stored in internal or external memory and displays > > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > > the timing of the interface signals is highly configurable. > > > Graphics are read directly from memory and then blended in real-time, > > > which allows for dynamic content creation with minimal CPU > > intervention. > > > > Only a review of the code inline. > > > > Maybe the real question is whether we want to introduce another > > framebuffer driver at all instead of making it a DRM driver. > [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. > > > > > + > > > +#define DRIVER_NAME "fsl-dcu-fb" > > > + > > > +#define DCU_DCU_MODE 0x0010 > > > +#define DCU_MODE_BLEND_ITER(x) (x << 20) > > > > What's the result of DCU_MODE_BLEND_ITER(1 + 1)? > [Alison Wang] Is it really necessary? I don't use this macro like DCU_MODE_BLEND_ITER(1 + 1), just use DCU_MODE_BLEND_ITER(2). <irony> No it's not necessary. We can just add incorrect macros everywhere and fix them as necessary after a long bug squashing session </irony> YES! This is necessary. > > > + return 0; > > > +} > > > + > > > +static int calc_div_ratio(struct fb_info *info) { > > > > Use a consistent namespace for function names (fsl_dcu_) > [Alison Wang] Is it necessary to use a consistent namespace for this generic function? I think it is necessary to use a consistent namespace (fsl_dcu_) for the function names in structure fsl_dcu_ops. This function calculates some divider out of a struct fb_info. This is by no means generic. > > > + if (copy_to_user(buf, &alpha, sizeof(alpha))) > > > + return -EFAULT; > > > + break; > > > + case MFB_SET_ALPHA: > > > + if (copy_from_user(&alpha, buf, sizeof(alpha))) > > > + return -EFAULT; > > > + mfbi->blend = 1; > > > + mfbi->alpha = alpha; > > > + fsl_dcu_set_par(info); > > > + break; > > > > Is it still state of the art to introduce ioctls in the fb framework > > without any kind of documentation? > [Alison Wang] Do you mean I need to add a documentation in Documentation/fb/? This was more a question to the fb maintainers. > > > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) { > > > + struct dcu_fb_data *dcufb = dev_id; > > > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > > > + u32 dcu_mode; > > > + > > > + if (status) { > > > > Save indendation level by bailing out early. > [Alison Wang] What do you mean? Instead of doing: if (bla) { dothis(); dothat(); return; } return; it's easier to read: if (!bla) return; dothis(); dothat(); return; Note that dothis() and dothat() are one indentation level to the left and thus have more space per line. Sascha -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-08-05 10:06 ` Sascha Hauer @ 2013-08-06 3:42 ` Wang Huan-B18965 -1 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-06 3:42 UTC (permalink / raw) To: linux-arm-kernel PiBPbiBNb24sIEF1ZyAwNSwgMjAxMyBhdCAwOTo1MTo0MEFNICswMDAwLCBXYW5nIEh1YW4tQjE4 OTY1IHdyb3RlOg0KPiA+IEhpLCBTYXNjaGEsDQo+ID4NCj4gPiA+IE9uIEZyaSwgSnVsIDEyLCAy MDEzIGF0IDAyOjA3OjU1UE0gKzA4MDAsIEFsaXNvbiBXYW5nIHdyb3RlOg0KPiA+ID4gPiBUaGUg RGlzcGxheSBDb250cm9sbGVyIFVuaXQgKERDVSkgbW9kdWxlIGlzIGEgc3lzdGVtIG1hc3RlciB0 aGF0DQo+ID4gPiA+IGZldGNoZXMgZ3JhcGhpY3Mgc3RvcmVkIGluIGludGVybmFsIG9yIGV4dGVy bmFsIG1lbW9yeSBhbmQNCj4gPiA+ID4gZGlzcGxheXMgdGhlbSBvbiBhIFRGVCBMQ0QgcGFuZWwu IEEgd2lkZSByYW5nZSBvZiBwYW5lbCBzaXplcyBpcw0KPiA+ID4gPiBzdXBwb3J0ZWQgYW5kIHRo ZSB0aW1pbmcgb2YgdGhlIGludGVyZmFjZSBzaWduYWxzIGlzIGhpZ2hseQ0KPiBjb25maWd1cmFi bGUuDQo+ID4gPiA+IEdyYXBoaWNzIGFyZSByZWFkIGRpcmVjdGx5IGZyb20gbWVtb3J5IGFuZCB0 aGVuIGJsZW5kZWQgaW4NCj4gPiA+ID4gcmVhbC10aW1lLCB3aGljaCBhbGxvd3MgZm9yIGR5bmFt aWMgY29udGVudCBjcmVhdGlvbiB3aXRoIG1pbmltYWwNCj4gPiA+ID4gQ1BVDQo+ID4gPiBpbnRl cnZlbnRpb24uDQo+ID4gPg0KPiA+ID4gT25seSBhIHJldmlldyBvZiB0aGUgY29kZSBpbmxpbmUu DQo+ID4gPg0KPiA+ID4gTWF5YmUgdGhlIHJlYWwgcXVlc3Rpb24gaXMgd2hldGhlciB3ZSB3YW50 IHRvIGludHJvZHVjZSBhbm90aGVyDQo+ID4gPiBmcmFtZWJ1ZmZlciBkcml2ZXIgYXQgYWxsIGlu c3RlYWQgb2YgbWFraW5nIGl0IGEgRFJNIGRyaXZlci4NCj4gPiBbQWxpc29uIFdhbmddIEkgdGhp bmsgRENVIG1vZHVsZSBpcyBtb3JlIHN1aXRhYmxlIHRvIGJlIGRlc2lnbmVkIGFzIGENCj4gZnJh bWVidWZmZXIgZHJpdmVyIHRoYW4gYSBEUk0gZHJpdmVyLiBKdXN0IGxpa2UgRElVIGZyYW1lYnVm ZmVyIGRyaXZlcg0KPiBmb3IgUG93ZXJQQy4NCj4gPiA+DQo+ID4gPiA+ICsNCj4gPiA+ID4gKyNk ZWZpbmUgRFJJVkVSX05BTUUJCQkiZnNsLWRjdS1mYiINCj4gPiA+ID4gKw0KPiA+ID4gPiArI2Rl ZmluZSBEQ1VfRENVX01PREUJCQkweDAwMTANCj4gPiA+ID4gKyNkZWZpbmUgRENVX01PREVfQkxF TkRfSVRFUih4KQkJKHggPDwgMjApDQo+ID4gPg0KPiA+ID4gV2hhdCdzIHRoZSByZXN1bHQgb2Yg RENVX01PREVfQkxFTkRfSVRFUigxICsgMSk/DQo+ID4gW0FsaXNvbiBXYW5nXSBJcyBpdCByZWFs bHkgbmVjZXNzYXJ5PyBJIGRvbid0IHVzZSB0aGlzIG1hY3JvIGxpa2UNCj4gRENVX01PREVfQkxF TkRfSVRFUigxICsgMSksIGp1c3QgdXNlIERDVV9NT0RFX0JMRU5EX0lURVIoMikuDQo+IA0KPiA8 aXJvbnk+DQo+IE5vIGl0J3Mgbm90IG5lY2Vzc2FyeS4gV2UgY2FuIGp1c3QgYWRkIGluY29ycmVj dCBtYWNyb3MgZXZlcnl3aGVyZSBhbmQNCj4gZml4IHRoZW0gYXMgbmVjZXNzYXJ5IGFmdGVyIGEg bG9uZyBidWcgc3F1YXNoaW5nIHNlc3Npb24gPC9pcm9ueT4NCj4gDQo+IFlFUyEgVGhpcyBpcyBu ZWNlc3NhcnkuDQpbQWxpc29uIFdhbmddIE9rLCBJIHdpbGwgY2hhbmdlIGl0IGFzIGZvbGxvd3Mu DQojZGVmaW5lIERDVV9NT0RFX0JMRU5EX0lURVIoeCkJKCh4KSA8PCAyMCkNCj4gDQo+ID4gPiA+ ICsJcmV0dXJuIDA7DQo+ID4gPiA+ICt9DQo+ID4gPiA+ICsNCj4gPiA+ID4gK3N0YXRpYyBpbnQg Y2FsY19kaXZfcmF0aW8oc3RydWN0IGZiX2luZm8gKmluZm8pIHsNCj4gPiA+DQo+ID4gPiBVc2Ug YSBjb25zaXN0ZW50IG5hbWVzcGFjZSBmb3IgZnVuY3Rpb24gbmFtZXMgKGZzbF9kY3VfKQ0KPiA+ IFtBbGlzb24gV2FuZ10gSXMgaXQgbmVjZXNzYXJ5IHRvIHVzZSBhIGNvbnNpc3RlbnQgbmFtZXNw YWNlIGZvciB0aGlzDQo+IGdlbmVyaWMgZnVuY3Rpb24/IEkgdGhpbmsgaXQgaXMgbmVjZXNzYXJ5 IHRvIHVzZSBhIGNvbnNpc3RlbnQgbmFtZXNwYWNlDQo+IChmc2xfZGN1XykgZm9yIHRoZSBmdW5j dGlvbiBuYW1lcyBpbiBzdHJ1Y3R1cmUgZnNsX2RjdV9vcHMuDQo+IA0KPiBUaGlzIGZ1bmN0aW9u IGNhbGN1bGF0ZXMgc29tZSBkaXZpZGVyIG91dCBvZiBhIHN0cnVjdCBmYl9pbmZvLiBUaGlzIGlz DQo+IGJ5IG5vIG1lYW5zIGdlbmVyaWMuDQpbQWxpc29uIFdhbmddIE9rLCBJIHdpbGwgdXNlIGEg Y29uc2lzdGVudCBuYW1lc3BhY2UgZm9yIHRoaXMgZnVuY3Rpb24uDQo+IA0KPiA+ID4gPiArCQlp ZiAoY29weV90b191c2VyKGJ1ZiwgJmFscGhhLCBzaXplb2YoYWxwaGEpKSkNCj4gPiA+ID4gKwkJ CXJldHVybiAtRUZBVUxUOw0KPiA+ID4gPiArCQlicmVhazsNCj4gPiA+ID4gKwljYXNlIE1GQl9T RVRfQUxQSEE6DQo+ID4gPiA+ICsJCWlmIChjb3B5X2Zyb21fdXNlcigmYWxwaGEsIGJ1Ziwgc2l6 ZW9mKGFscGhhKSkpDQo+ID4gPiA+ICsJCQlyZXR1cm4gLUVGQVVMVDsNCj4gPiA+ID4gKwkJbWZi aS0+YmxlbmQgPSAxOw0KPiA+ID4gPiArCQltZmJpLT5hbHBoYSA9IGFscGhhOw0KPiA+ID4gPiAr CQlmc2xfZGN1X3NldF9wYXIoaW5mbyk7DQo+ID4gPiA+ICsJCWJyZWFrOw0KPiA+ID4NCj4gPiA+ IElzIGl0IHN0aWxsIHN0YXRlIG9mIHRoZSBhcnQgdG8gaW50cm9kdWNlIGlvY3RscyBpbiB0aGUg ZmINCj4gZnJhbWV3b3JrDQo+ID4gPiB3aXRob3V0IGFueSBraW5kIG9mIGRvY3VtZW50YXRpb24/ DQo+ID4gW0FsaXNvbiBXYW5nXSBEbyB5b3UgbWVhbiBJIG5lZWQgdG8gYWRkIGEgZG9jdW1lbnRh dGlvbiBpbg0KPiBEb2N1bWVudGF0aW9uL2ZiLz8NCj4gDQo+IFRoaXMgd2FzIG1vcmUgYSBxdWVz dGlvbiB0byB0aGUgZmIgbWFpbnRhaW5lcnMuDQo+IA0KPiA+ID4gPiArc3RhdGljIGlycXJldHVy bl90IGZzbF9kY3VfaXJxKGludCBpcnEsIHZvaWQgKmRldl9pZCkgew0KPiA+ID4gPiArCXN0cnVj dCBkY3VfZmJfZGF0YSAqZGN1ZmIgPSBkZXZfaWQ7DQo+ID4gPiA+ICsJdW5zaWduZWQgaW50IHN0 YXR1cyA9IHJlYWRsKGRjdWZiLT5yZWdfYmFzZSArDQo+IERDVV9JTlRfU1RBVFVTKTsNCj4gPiA+ ID4gKwl1MzIgZGN1X21vZGU7DQo+ID4gPiA+ICsNCj4gPiA+ID4gKwlpZiAoc3RhdHVzKSB7DQo+ ID4gPg0KPiA+ID4gU2F2ZSBpbmRlbmRhdGlvbiBsZXZlbCBieSBiYWlsaW5nIG91dCBlYXJseS4N Cj4gPiBbQWxpc29uIFdhbmddIFdoYXQgZG8geW91IG1lYW4/DQo+IA0KPiANCj4gSW5zdGVhZCBv ZiBkb2luZzoNCj4gDQo+IAlpZiAoYmxhKSB7DQo+IAkJZG90aGlzKCk7DQo+IAkJZG90aGF0KCk7 DQo+IAkJcmV0dXJuOw0KPiAJfQ0KPiANCj4gCXJldHVybjsNCj4gDQo+IGl0J3MgZWFzaWVyIHRv IHJlYWQ6DQo+IA0KPiAJaWYgKCFibGEpDQo+IAkJcmV0dXJuOw0KPiANCj4gCWRvdGhpcygpOw0K PiAJZG90aGF0KCk7DQo+IAlyZXR1cm47DQo+IA0KPiBOb3RlIHRoYXQgZG90aGlzKCkgYW5kIGRv dGhhdCgpIGFyZSBvbmUgaW5kZW50YXRpb24gbGV2ZWwgdG8gdGhlIGxlZnQNCj4gYW5kIHRodXMg aGF2ZSBtb3JlIHNwYWNlIHBlciBsaW5lLg0KW0FsaXNvbiBXYW5nXSBJIHNlZS4gVGhhbmtzLg0K DQoNCkJlc3QgUmVnYXJkcywNCkFsaXNvbiBXYW5nDQo ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-06 3:42 ` Wang Huan-B18965 0 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-06 3:42 UTC (permalink / raw) To: linux-arm-kernel > On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > > Hi, Sascha, > > > > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > > The Display Controller Unit (DCU) module is a system master that > > > > fetches graphics stored in internal or external memory and > > > > displays them on a TFT LCD panel. A wide range of panel sizes is > > > > supported and the timing of the interface signals is highly > configurable. > > > > Graphics are read directly from memory and then blended in > > > > real-time, which allows for dynamic content creation with minimal > > > > CPU > > > intervention. > > > > > > Only a review of the code inline. > > > > > > Maybe the real question is whether we want to introduce another > > > framebuffer driver at all instead of making it a DRM driver. > > [Alison Wang] I think DCU module is more suitable to be designed as a > framebuffer driver than a DRM driver. Just like DIU framebuffer driver > for PowerPC. > > > > > > > + > > > > +#define DRIVER_NAME "fsl-dcu-fb" > > > > + > > > > +#define DCU_DCU_MODE 0x0010 > > > > +#define DCU_MODE_BLEND_ITER(x) (x << 20) > > > > > > What's the result of DCU_MODE_BLEND_ITER(1 + 1)? > > [Alison Wang] Is it really necessary? I don't use this macro like > DCU_MODE_BLEND_ITER(1 + 1), just use DCU_MODE_BLEND_ITER(2). > > <irony> > No it's not necessary. We can just add incorrect macros everywhere and > fix them as necessary after a long bug squashing session </irony> > > YES! This is necessary. [Alison Wang] Ok, I will change it as follows. #define DCU_MODE_BLEND_ITER(x) ((x) << 20) > > > > > + return 0; > > > > +} > > > > + > > > > +static int calc_div_ratio(struct fb_info *info) { > > > > > > Use a consistent namespace for function names (fsl_dcu_) > > [Alison Wang] Is it necessary to use a consistent namespace for this > generic function? I think it is necessary to use a consistent namespace > (fsl_dcu_) for the function names in structure fsl_dcu_ops. > > This function calculates some divider out of a struct fb_info. This is > by no means generic. [Alison Wang] Ok, I will use a consistent namespace for this function. > > > > > + if (copy_to_user(buf, &alpha, sizeof(alpha))) > > > > + return -EFAULT; > > > > + break; > > > > + case MFB_SET_ALPHA: > > > > + if (copy_from_user(&alpha, buf, sizeof(alpha))) > > > > + return -EFAULT; > > > > + mfbi->blend = 1; > > > > + mfbi->alpha = alpha; > > > > + fsl_dcu_set_par(info); > > > > + break; > > > > > > Is it still state of the art to introduce ioctls in the fb > framework > > > without any kind of documentation? > > [Alison Wang] Do you mean I need to add a documentation in > Documentation/fb/? > > This was more a question to the fb maintainers. > > > > > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) { > > > > + struct dcu_fb_data *dcufb = dev_id; > > > > + unsigned int status = readl(dcufb->reg_base + > DCU_INT_STATUS); > > > > + u32 dcu_mode; > > > > + > > > > + if (status) { > > > > > > Save indendation level by bailing out early. > > [Alison Wang] What do you mean? > > > Instead of doing: > > if (bla) { > dothis(); > dothat(); > return; > } > > return; > > it's easier to read: > > if (!bla) > return; > > dothis(); > dothat(); > return; > > Note that dothis() and dothat() are one indentation level to the left > and thus have more space per line. [Alison Wang] I see. Thanks. Best Regards, Alison Wang ^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-08-05 9:51 ` Wang Huan-B18965 @ 2013-08-05 13:09 ` Robert Schwebel -1 siblings, 0 replies; 38+ messages in thread From: Robert Schwebel @ 2013-08-05 13:09 UTC (permalink / raw) To: linux-arm-kernel On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > The Display Controller Unit (DCU) module is a system master that > > > fetches graphics stored in internal or external memory and displays > > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > > the timing of the interface signals is highly configurable. > > > Graphics are read directly from memory and then blended in real-time, > > > which allows for dynamic content creation with minimal CPU > > intervention. > > > > Only a review of the code inline. > > > > Maybe the real question is whether we want to introduce another > > framebuffer driver at all instead of making it a DRM driver. > [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. We looked at the Vybrid datasheet and it's DCU section last week, and with its 64 planes, the controller really wants to get a DRM driver. rsc -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-05 13:09 ` Robert Schwebel 0 siblings, 0 replies; 38+ messages in thread From: Robert Schwebel @ 2013-08-05 13:09 UTC (permalink / raw) To: linux-arm-kernel On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > The Display Controller Unit (DCU) module is a system master that > > > fetches graphics stored in internal or external memory and displays > > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > > the timing of the interface signals is highly configurable. > > > Graphics are read directly from memory and then blended in real-time, > > > which allows for dynamic content creation with minimal CPU > > intervention. > > > > Only a review of the code inline. > > > > Maybe the real question is whether we want to introduce another > > framebuffer driver at all instead of making it a DRM driver. > [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. We looked at the Vybrid datasheet and it's DCU section last week, and with its 64 planes, the controller really wants to get a DRM driver. rsc -- Pengutronix e.K. | | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-0 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-08-05 13:09 ` Robert Schwebel @ 2013-08-05 14:18 ` Lucas Stach -1 siblings, 0 replies; 38+ messages in thread From: Lucas Stach @ 2013-08-05 14:18 UTC (permalink / raw) To: linux-arm-kernel Am Montag, den 05.08.2013, 15:09 +0200 schrieb Robert Schwebel: > On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > > The Display Controller Unit (DCU) module is a system master that > > > > fetches graphics stored in internal or external memory and displays > > > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > > > the timing of the interface signals is highly configurable. > > > > Graphics are read directly from memory and then blended in real-time, > > > > which allows for dynamic content creation with minimal CPU > > > intervention. > > > > > > Only a review of the code inline. > > > > > > Maybe the real question is whether we want to introduce another > > > framebuffer driver at all instead of making it a DRM driver. > > [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. > > We looked at the Vybrid datasheet and it's DCU section last week, and > with its 64 planes, the controller really wants to get a DRM driver. > Exactly, with it's extensive hardware composition capabilities the controller begs for being driven by a proper DRM driver. There is no way in fbdev to properly support all those hardware planes without introducing a lot of non standard ioctls, which in turn will force you into writing a lot of custom userspace code instead of running proven technology that sits on top of KMS. Doing things in DRM might be slightly more work for the initial bring up, but will pay off in the long run when you are going to really use the hardware caps of the controller. Regards, Lucas -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-05 14:18 ` Lucas Stach 0 siblings, 0 replies; 38+ messages in thread From: Lucas Stach @ 2013-08-05 14:18 UTC (permalink / raw) To: linux-arm-kernel Am Montag, den 05.08.2013, 15:09 +0200 schrieb Robert Schwebel: > On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > > The Display Controller Unit (DCU) module is a system master that > > > > fetches graphics stored in internal or external memory and displays > > > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > > > the timing of the interface signals is highly configurable. > > > > Graphics are read directly from memory and then blended in real-time, > > > > which allows for dynamic content creation with minimal CPU > > > intervention. > > > > > > Only a review of the code inline. > > > > > > Maybe the real question is whether we want to introduce another > > > framebuffer driver at all instead of making it a DRM driver. > > [Alison Wang] I think DCU module is more suitable to be designed as a framebuffer driver than a DRM driver. Just like DIU framebuffer driver for PowerPC. > > We looked at the Vybrid datasheet and it's DCU section last week, and > with its 64 planes, the controller really wants to get a DRM driver. > Exactly, with it's extensive hardware composition capabilities the controller begs for being driven by a proper DRM driver. There is no way in fbdev to properly support all those hardware planes without introducing a lot of non standard ioctls, which in turn will force you into writing a lot of custom userspace code instead of running proven technology that sits on top of KMS. Doing things in DRM might be slightly more work for the initial bring up, but will pay off in the long run when you are going to really use the hardware caps of the controller. Regards, Lucas -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-08-05 14:18 ` Lucas Stach @ 2013-08-06 7:20 ` Wang Huan-B18965 -1 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-06 7:20 UTC (permalink / raw) To: linux-arm-kernel SGksDQoNCj4gQW0gTW9udGFnLCBkZW4gMDUuMDguMjAxMywgMTU6MDkgKzAyMDAgc2NocmllYiBS b2JlcnQgU2Nod2ViZWw6DQo+ID4gT24gTW9uLCBBdWcgMDUsIDIwMTMgYXQgMDk6NTE6NDBBTSAr MDAwMCwgV2FuZyBIdWFuLUIxODk2NSB3cm90ZToNCj4gPiA+ID4gT24gRnJpLCBKdWwgMTIsIDIw MTMgYXQgMDI6MDc6NTVQTSArMDgwMCwgQWxpc29uIFdhbmcgd3JvdGU6DQo+ID4gPiA+ID4gVGhl IERpc3BsYXkgQ29udHJvbGxlciBVbml0IChEQ1UpIG1vZHVsZSBpcyBhIHN5c3RlbSBtYXN0ZXIN Cj4gdGhhdA0KPiA+ID4gPiA+IGZldGNoZXMgZ3JhcGhpY3Mgc3RvcmVkIGluIGludGVybmFsIG9y IGV4dGVybmFsIG1lbW9yeSBhbmQNCj4gPiA+ID4gPiBkaXNwbGF5cyB0aGVtIG9uIGEgVEZUIExD RCBwYW5lbC4gQSB3aWRlIHJhbmdlIG9mIHBhbmVsIHNpemVzDQo+IGlzDQo+ID4gPiA+ID4gc3Vw cG9ydGVkIGFuZCB0aGUgdGltaW5nIG9mIHRoZSBpbnRlcmZhY2Ugc2lnbmFscyBpcyBoaWdobHkN Cj4gY29uZmlndXJhYmxlLg0KPiA+ID4gPiA+IEdyYXBoaWNzIGFyZSByZWFkIGRpcmVjdGx5IGZy b20gbWVtb3J5IGFuZCB0aGVuIGJsZW5kZWQgaW4NCj4gPiA+ID4gPiByZWFsLXRpbWUsIHdoaWNo IGFsbG93cyBmb3IgZHluYW1pYyBjb250ZW50IGNyZWF0aW9uIHdpdGgNCj4gPiA+ID4gPiBtaW5p bWFsIENQVQ0KPiA+ID4gPiBpbnRlcnZlbnRpb24uDQo+ID4gPiA+DQo+ID4gPiA+IE9ubHkgYSBy ZXZpZXcgb2YgdGhlIGNvZGUgaW5saW5lLg0KPiA+ID4gPg0KPiA+ID4gPiBNYXliZSB0aGUgcmVh bCBxdWVzdGlvbiBpcyB3aGV0aGVyIHdlIHdhbnQgdG8gaW50cm9kdWNlIGFub3RoZXINCj4gPiA+ ID4gZnJhbWVidWZmZXIgZHJpdmVyIGF0IGFsbCBpbnN0ZWFkIG9mIG1ha2luZyBpdCBhIERSTSBk cml2ZXIuDQo+ID4gPiBbQWxpc29uIFdhbmddIEkgdGhpbmsgRENVIG1vZHVsZSBpcyBtb3JlIHN1 aXRhYmxlIHRvIGJlIGRlc2lnbmVkIGFzDQo+IGEgZnJhbWVidWZmZXIgZHJpdmVyIHRoYW4gYSBE Uk0gZHJpdmVyLiBKdXN0IGxpa2UgRElVIGZyYW1lYnVmZmVyDQo+IGRyaXZlciBmb3IgUG93ZXJQ Qy4NCj4gPg0KPiA+IFdlIGxvb2tlZCBhdCB0aGUgVnlicmlkIGRhdGFzaGVldCBhbmQgaXQncyBE Q1Ugc2VjdGlvbiBsYXN0IHdlZWssIGFuZA0KPiA+IHdpdGggaXRzIDY0IHBsYW5lcywgdGhlIGNv bnRyb2xsZXIgcmVhbGx5IHdhbnRzIHRvIGdldCBhIERSTSBkcml2ZXIuDQo+ID4NCj4gRXhhY3Rs eSwgd2l0aCBpdCdzIGV4dGVuc2l2ZSBoYXJkd2FyZSBjb21wb3NpdGlvbiBjYXBhYmlsaXRpZXMg dGhlDQo+IGNvbnRyb2xsZXIgYmVncyBmb3IgYmVpbmcgZHJpdmVuIGJ5IGEgcHJvcGVyIERSTSBk cml2ZXIuIFRoZXJlIGlzIG5vDQo+IHdheSBpbiBmYmRldiB0byBwcm9wZXJseSBzdXBwb3J0IGFs bCB0aG9zZSBoYXJkd2FyZSBwbGFuZXMgd2l0aG91dA0KPiBpbnRyb2R1Y2luZyBhIGxvdCBvZiBu b24gc3RhbmRhcmQgaW9jdGxzLCB3aGljaCBpbiB0dXJuIHdpbGwgZm9yY2UgeW91DQo+IGludG8g d3JpdGluZyBhIGxvdCBvZiBjdXN0b20gdXNlcnNwYWNlIGNvZGUgaW5zdGVhZCBvZiBydW5uaW5n IHByb3Zlbg0KPiB0ZWNobm9sb2d5IHRoYXQgc2l0cyBvbiB0b3Agb2YgS01TLg0KPiANCj4gRG9p bmcgdGhpbmdzIGluIERSTSBtaWdodCBiZSBzbGlnaHRseSBtb3JlIHdvcmsgZm9yIHRoZSBpbml0 aWFsIGJyaW5nDQo+IHVwLCBidXQgd2lsbCBwYXkgb2ZmIGluIHRoZSBsb25nIHJ1biB3aGVuIHlv dSBhcmUgZ29pbmcgdG8gcmVhbGx5IHVzZQ0KPiB0aGUgaGFyZHdhcmUgY2FwcyBvZiB0aGUgY29u dHJvbGxlci4NCj4gDQpbQWxpc29uIFdhbmddIFRoYW5rcyBmb3IgeW91ciBjb21tZW50cyBhbmQg ZXhwbGFuYXRpb25zLiBJIHVuZGVyc3RhbmQgeW91ciBjb25zaWRlcmF0aW9ucy4NCg0KSW4gRENV IG1vZHVsZSwgdGhlcmUgYXJlIDY0IGdyYXBoaWNzIGxheWVycywgYnV0IHRoZSBtYXhpbXVtIHNv dXJjZSBsYXllcnMgZm9yIGJsZW5kaW5nIG9mIGVhY2ggcGl4ZWwgaXMgb25seSA2LiBUaGUgZmIg ZHJpdmVyIGNvdWxkIHNhdGlzZnkgdGhlIGN1cnJlbnQgYXBwbGljYXRpb24gcmVxdWlyZW1lbnRz Lg0KDQpTbyBJIHdpbGwgcHVzaCBvdXQgdGhpcyBmYiBkcml2ZXIgZmlyc3QsIGFuZCB0aGVuIEkg d2lsbCBhZGQgYSBEUk0gZHJpdmVyIGZvciBtb3JlIGFkdmFuY2VkIHJlcXVpcmVtZW50cy4NCg0K RG8geW91IGhhdmUgbW9yZSBjb21tZW50cz8NCg0KDQpCZXN0IFJlZ2FyZHMsDQpBbGlzb24gV2Fu Zw0K ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-06 7:20 ` Wang Huan-B18965 0 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-06 7:20 UTC (permalink / raw) To: linux-arm-kernel Hi, > Am Montag, den 05.08.2013, 15:09 +0200 schrieb Robert Schwebel: > > On Mon, Aug 05, 2013 at 09:51:40AM +0000, Wang Huan-B18965 wrote: > > > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > > > > > The Display Controller Unit (DCU) module is a system master > that > > > > > fetches graphics stored in internal or external memory and > > > > > displays them on a TFT LCD panel. A wide range of panel sizes > is > > > > > supported and the timing of the interface signals is highly > configurable. > > > > > Graphics are read directly from memory and then blended in > > > > > real-time, which allows for dynamic content creation with > > > > > minimal CPU > > > > intervention. > > > > > > > > Only a review of the code inline. > > > > > > > > Maybe the real question is whether we want to introduce another > > > > framebuffer driver at all instead of making it a DRM driver. > > > [Alison Wang] I think DCU module is more suitable to be designed as > a framebuffer driver than a DRM driver. Just like DIU framebuffer > driver for PowerPC. > > > > We looked at the Vybrid datasheet and it's DCU section last week, and > > with its 64 planes, the controller really wants to get a DRM driver. > > > Exactly, with it's extensive hardware composition capabilities the > controller begs for being driven by a proper DRM driver. There is no > way in fbdev to properly support all those hardware planes without > introducing a lot of non standard ioctls, which in turn will force you > into writing a lot of custom userspace code instead of running proven > technology that sits on top of KMS. > > Doing things in DRM might be slightly more work for the initial bring > up, but will pay off in the long run when you are going to really use > the hardware caps of the controller. > [Alison Wang] Thanks for your comments and explanations. I understand your considerations. In DCU module, there are 64 graphics layers, but the maximum source layers for blending of each pixel is only 6. The fb driver could satisfy the current application requirements. So I will push out this fb driver first, and then I will add a DRM driver for more advanced requirements. Do you have more comments? Best Regards, Alison Wang ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-29 11:14 ` Sascha Hauer (?) (?) @ 2014-01-06 18:50 ` Bill Pringlemeir 2014-01-07 9:18 ` Lucas Stach -1 siblings, 1 reply; 38+ messages in thread From: Bill Pringlemeir @ 2014-01-06 18:50 UTC (permalink / raw) To: linux-arm-kernel > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: >> The Display Controller Unit (DCU) module is a system master that >> fetches graphics stored in internal or external memory and displays >> them on a TFT LCD panel. A wide range of panel sizes is supported >> and the timing of the interface signals is highly configurable. >> Graphics are read directly from memory and then blended in real-time, >> which allows for dynamic content creation with minimal CPU intervention. On 29 Jul 2013, s.hauer at pengutronix.de wrote: > Maybe the real question is whether we want to introduce another > framebuffer driver at all instead of making it a DRM driver. I didn't understand this comment at first. I thought that the DRM infra-structure had changed or something. I see a recent post on IMX-DRM and I think there is a mis-conception on the Vybrid SOC. At first, Freescale was to incorporate a Vivante GC355 GPU for OpenVG. However, this was removed from the design and is only present on some 'Automotive' parts, and not the VF610 nor the Tower boards. These SOCs only have a multi-level framebuffer with alpha blending. Was it meant that this be part of the DRM? It seems that the hardware without the 'Vivante GC355 GPU' is best served by an fb driver. Certainly, there are very few Vybrid chips with this OpenVG on board. I am also not really certain what sort of user space code would use it. Most graphics stacks seems to want OpenGL; of course that is not a reason not to put it in the kernel, but I don't think any Linux Vybrid devices will actually have an OpenVG register set on board? The majority will have none. Fwiw, Bill Pringlemeir. ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2014-01-06 18:50 ` Bill Pringlemeir @ 2014-01-07 9:18 ` Lucas Stach 2014-01-07 20:52 ` Bill Pringlemeir 0 siblings, 1 reply; 38+ messages in thread From: Lucas Stach @ 2014-01-07 9:18 UTC (permalink / raw) To: linux-arm-kernel Am Montag, den 06.01.2014, 13:50 -0500 schrieb Bill Pringlemeir: > > On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: > >> The Display Controller Unit (DCU) module is a system master that > >> fetches graphics stored in internal or external memory and displays > >> them on a TFT LCD panel. A wide range of panel sizes is supported > >> and the timing of the interface signals is highly configurable. > >> Graphics are read directly from memory and then blended in real-time, > >> which allows for dynamic content creation with minimal CPU intervention. > > On 29 Jul 2013, s.hauer at pengutronix.de wrote: > > > Maybe the real question is whether we want to introduce another > > framebuffer driver at all instead of making it a DRM driver. > > I didn't understand this comment at first. I thought that the DRM > infra-structure had changed or something. I see a recent post on > IMX-DRM and I think there is a mis-conception on the Vybrid SOC. > > At first, Freescale was to incorporate a Vivante GC355 GPU for OpenVG. > However, this was removed from the design and is only present on some > 'Automotive' parts, and not the VF610 nor the Tower boards. These SOCs > only have a multi-level framebuffer with alpha blending. Was it meant > that this be part of the DRM? It seems that the hardware without the > 'Vivante GC355 GPU' is best served by an fb driver. Exactly the multi-level part of the hardware should preferably be programmed through the standardized plane stuff in the KMS userspace interface, which is part of DRM. Regards, Lucas -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2014-01-07 9:18 ` Lucas Stach @ 2014-01-07 20:52 ` Bill Pringlemeir 2014-01-07 21:00 ` Bill Pringlemeir 0 siblings, 1 reply; 38+ messages in thread From: Bill Pringlemeir @ 2014-01-07 20:52 UTC (permalink / raw) To: linux-arm-kernel >>> On Fri, Jul 12, 2013 at 02:07:55PM +0800, Alison Wang wrote: >>>> The Display Controller Unit (DCU) module is a system master that >>>> fetches graphics stored in internal or external memory and displays >>>> them on a TFT LCD panel. A wide range of panel sizes is supported >>>> and the timing of the interface signals is highly configurable. >>>> Graphics are read directly from memory and then blended in real-time, >>>> which allows for dynamic content creation with minimal CPU intervention. >> On 29 Jul 2013, s.hauer at pengutronix.de wrote: >>> Maybe the real question is whether we want to introduce another >>> framebuffer driver at all instead of making it a DRM driver. > Am Montag, den 06.01.2014, 13:50 -0500 schrieb Bill Pringlemeir: >> I didn't understand this comment at first. I thought that the DRM >> infra-structure had changed or something. I see a recent post on >> IMX-DRM and I think there is a mis-conception on the Vybrid SOC. >> At first, Freescale was to incorporate a Vivante GC355 GPU for OpenVG. >> However, this was removed from the design and is only present on some >> 'Automotive' parts, and not the VF610 nor the Tower boards. These SOCs >> only have a multi-level framebuffer with alpha blending. Was it meant >> that this be part of the DRM? It seems that the hardware without the >> 'Vivante GC355 GPU' is best served by an fb driver. On 7 Jan 2014, l.stach at pengutronix.de wrote: > Exactly the multi-level part of the hardware should preferably be > programmed through the standardized plane stuff in the KMS userspace > interface, which is part of DRM. Ok, that makes sense. The IMX25 also has the double frame buffer and is part of the IMX family but was not converted, so that mis-lead me. I guess it is/was grand-fathered. The DRM API (GEM document, etc) for DRM seem to lead to acceleration. I will look at the KMS stuff. Is there a sample driver where multiple alpha-blended buffers are implemented? I guess 'git grep dumb_create'? The directory 'gpu' is misleading. All of the current drivers look like they are GPU driven? Is this something that no one has ever done before? Thanks, Bill Pringlemeir. ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2014-01-07 20:52 ` Bill Pringlemeir @ 2014-01-07 21:00 ` Bill Pringlemeir 0 siblings, 0 replies; 38+ messages in thread From: Bill Pringlemeir @ 2014-01-07 21:00 UTC (permalink / raw) To: linux-arm-kernel On 7 Jan 2014, bpringlemeir at nbsps.com wrote: > I guess 'git grep dumb_create'? The directory 'gpu' is misleading. All > of the current drivers look like they are GPU driven? Is this something > that no one has ever done before? It looks like the Armada driver is the best match? Thanks, Bill Pringlemeir. ^ permalink raw reply [flat|nested] 38+ messages in thread
* Re: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-12 6:07 ` Alison Wang @ 2013-08-06 8:47 ` Lucas Stach -1 siblings, 0 replies; 38+ messages in thread From: Lucas Stach @ 2013-08-06 8:47 UTC (permalink / raw) To: linux-arm-kernel Am Freitag, den 12.07.2013, 14:07 +0800 schrieb Alison Wang: > The Display Controller Unit (DCU) module is a system master that > fetches graphics stored in internal or external memory and displays > them on a TFT LCD panel. A wide range of panel sizes is supported > and the timing of the interface signals is highly configurable. > Graphics are read directly from memory and then blended in real-time, > which allows for dynamic content creation with minimal CPU intervention. > > The features: > > (1) Full RGB888 output to TFT LCD panel. > (2) For the current LCD panel, WQVGA "480x272" is tested. > (3) Blending of each pixel using up to 4 source layers dependent on size of panel. > (4) Each graphic layer can be placed with one pixel resolution in either axis. > (5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel > and BGRA8888 direct colors with an alpha channel. > (6) Each graphic layer support alpha blending with 8-bit resolution. > > This driver has been tested on Vybrid VF610 TOWER board. > > Signed-off-by: Alison Wang <b18965@freescale.com> > --- > Changes in v2: None > > drivers/video/Kconfig | 9 + > drivers/video/Makefile | 1 + > drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 1101 insertions(+) > create mode 100644 drivers/video/fsl-dcu-fb.c > [...] > + > +static struct fb_videomode dcu_mode_db[] = { > + { > + .name = "480x272", > + .refresh = 75, > + .xres = 480, > + .yres = 272, > + .pixclock = 91996, > + .left_margin = 2, > + .right_margin = 2, > + .upper_margin = 1, > + .lower_margin = 1, > + .hsync_len = 41, > + .vsync_len = 2, > + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}; Don't hardcode panel data in the driver. Use the videomode helpers to get the relevant data from devicetree. > + > +/* DCU framebuffer data structure */ > +struct dcu_fb_data { > + struct fb_info *fsl_dcu_info[DCU_LAYER_NUM]; > + void __iomem *reg_base; > + unsigned int irq; > + struct clk *clk; > +}; > + > +struct layer_display_offset { > + int x_layer_d; > + int y_layer_d; > +}; > + > +struct mfb_info { > + int index; > + char *id; > + unsigned long pseudo_palette[16]; > + unsigned char alpha; > + unsigned char blend; > + unsigned int count; > + int x_layer_d; /* layer display x offset to physical screen */ > + int y_layer_d; /* layer display y offset to physical screen */ > + struct dcu_fb_data *parent; > +}; > + > +enum mfb_index { > + LAYER0 = 0, > + LAYER1, > + LAYER2, > + LAYER3, > +}; Why are there only 4 layers here? I thought the controller supports at least 6 simultaneous layers? > + > +static struct mfb_info mfb_template[] = { > + { > + .index = LAYER0, > + .id = "Layer0", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 0, > + .y_layer_d = 0, > + }, > + { > + .index = LAYER1, > + .id = "Layer1", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 50, > + .y_layer_d = 50, > + }, > + { > + .index = LAYER2, > + .id = "Layer2", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 100, > + .y_layer_d = 100, > + }, > + { > + .index = LAYER3, > + .id = "Layer3", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 150, > + .y_layer_d = 150, > + }, > +}; [...] > + > +static int calc_div_ratio(struct fb_info *info) > +{ > + struct mfb_info *mfbi = info->par; > + struct dcu_fb_data *dcufb = mfbi->parent; > + unsigned long dcu_clk; > + unsigned long long tmp; > + > + dcu_clk = clk_get_rate(dcufb->clk); > + tmp = info->var.pixclock * (unsigned long long)dcu_clk; > + > + do_div(tmp, 1000000); > + > + if (do_div(tmp, 1000000) > 500000) > + tmp++; Urgh, you are changing the value of tmp inside the if clause. This isn't nice. This function as a a whole looks really odd. > + > + tmp = tmp - 1; > + return tmp; > +} > + > +static void update_controller(struct fb_info *info) > +{ > + struct fb_var_screeninfo *var = &info->var; > + struct mfb_info *mfbi = info->par; > + struct dcu_fb_data *dcufb = mfbi->parent; > + unsigned int ratio; > + > + ratio = calc_div_ratio(info); > + writel(ratio, dcufb->reg_base + DCU_DIV_RATIO); > + > + writel(DCU_DISP_SIZE_DELTA_Y(var->yres) | > + DCU_DISP_SIZE_DELTA_X(var->xres / 16), > + dcufb->reg_base + DCU_DISP_SIZE); > + > + /* Horizontal and vertical sync parameter */ > + writel(DCU_HSYN_PARA_BP(var->left_margin) | > + DCU_HSYN_PARA_PW(var->hsync_len) | > + DCU_HSYN_PARA_FP(var->right_margin), > + dcufb->reg_base + DCU_HSYN_PARA); > + > + writel(DCU_VSYN_PARA_BP(var->upper_margin) | > + DCU_VSYN_PARA_PW(var->vsync_len) | > + DCU_VSYN_PARA_FP(var->lower_margin), > + dcufb->reg_base + DCU_VSYN_PARA); > + > + writel(DCU_SYN_POL_INV_PXCK_FALL | DCU_SYN_POL_NEG_REMAIN | > + DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW, > + dcufb->reg_base + DCU_SYN_POL); > + > + writel(DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0), > + dcufb->reg_base + DCU_BGND); > + > + writel(DCU_MODE_BLEND_ITER(DCU_LAYER_NUM_MAX) | DCU_MODE_RASTER_EN, > + dcufb->reg_base + DCU_DCU_MODE); > + > + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | > + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD); > + > + enable_controller(info); > +} > + > +static int map_video_memory(struct fb_info *info) > +{ > + u32 smem_len = info->fix.line_length * info->var.yres_virtual; > + > + info->fix.smem_len = smem_len; > + > + info->screen_base = dma_alloc_coherent(info->device, info->fix.smem_len, You are setting up an uncached mapping here. Use a writecombined mapping to help performance. It's still coherent, but allows at least write to be fast. > + (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); > + if (!info->screen_base) { > + printk(KERN_ERR "unable to allocate fb memory\n"); > + return -ENOMEM; > + } > + > + memset(info->screen_base, 0, info->fix.smem_len); > + > + return 0; > +} > + > +static void unmap_video_memory(struct fb_info *info) > +{ > + if (!info->screen_base) > + return; > + > + dma_free_coherent(info->device, info->fix.smem_len, > + info->screen_base, info->fix.smem_start); > + > + info->screen_base = NULL; > + info->fix.smem_start = 0; > + info->fix.smem_len = 0; > +} [...] > + > +static int fsl_dcu_open(struct fb_info *info, int user) > +{ > + struct mfb_info *mfbi = info->par; > + int ret = 0; > + > + mfbi->index = info->node; > + > + mfbi->count++; > + if (mfbi->count = 1) { > + fsl_dcu_check_var(&info->var, info); > + ret = fsl_dcu_set_par(info); > + if (ret < 0) > + mfbi->count--; > + else > + enable_interrupts(mfbi->parent); > + } > + > + return ret; > +} > + > +static int fsl_dcu_release(struct fb_info *info, int user) > +{ > + struct mfb_info *mfbi = info->par; > + int ret = 0; > + > + mfbi->count--; > + if (mfbi->count = 0) { > + ret = disable_panel(info); > + if (ret < 0) > + mfbi->count++; > + } > + > + return ret; > +} Could this be replaced by runtime pm? > + > +static struct fb_ops fsl_dcu_ops = { > + .owner = THIS_MODULE, > + .fb_check_var = fsl_dcu_check_var, > + .fb_set_par = fsl_dcu_set_par, > + .fb_setcolreg = fsl_dcu_setcolreg, > + .fb_blank = fsl_dcu_blank, > + .fb_pan_display = fsl_dcu_pan_display, > + .fb_fillrect = cfb_fillrect, > + .fb_copyarea = cfb_copyarea, > + .fb_imageblit = cfb_imageblit, > + .fb_ioctl = fsl_dcu_ioctl, > + .fb_open = fsl_dcu_open, > + .fb_release = fsl_dcu_release, > +}; > + > +static int install_framebuffer(struct fb_info *info) > +{ > + struct mfb_info *mfbi = info->par; > + struct fb_videomode *db = dcu_mode_db; > + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); > + int ret; > + > + info->var.activate = FB_ACTIVATE_NOW; > + info->fbops = &fsl_dcu_ops; > + info->flags = FBINFO_FLAG_DEFAULT; > + info->pseudo_palette = &mfbi->pseudo_palette; > + > + fb_alloc_cmap(&info->cmap, 16, 0); > + > + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, > + NULL, default_bpp); > + > + if (fsl_dcu_check_var(&info->var, info)) { > + ret = -EINVAL; > + goto failed_checkvar; > + } > + > + if (register_framebuffer(info) < 0) { > + ret = -EINVAL; > + goto failed_register_framebuffer; > + } > + > + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", > + info->node, info->fix.id); > + return 0; > + > +failed_checkvar: > + fb_dealloc_cmap(&info->cmap); > +failed_register_framebuffer: > + unmap_video_memory(info); > + fb_dealloc_cmap(&info->cmap); > + return ret; > +} > + > +static void uninstall_framebuffer(struct fb_info *info) > +{ > + unregister_framebuffer(info); > + unmap_video_memory(info); > + > + if (&info->cmap) > + fb_dealloc_cmap(&info->cmap); > +} > + > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) > +{ > + struct dcu_fb_data *dcufb = dev_id; > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > + u32 dcu_mode; > + > + if (status) { > + if (status & DCU_INT_STATUS_UNDRUN) { > + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); > + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), > + dcufb->reg_base + DCU_DCU_MODE); > + udelay(1); > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), > + dcufb->reg_base + DCU_DCU_MODE); > + } > + writel(status, dcufb->reg_base + DCU_INT_STATUS); > + return IRQ_HANDLED; > + } > + return IRQ_NONE; > +} > + > +#ifdef CONFIG_PM > +static int fsl_dcu_suspend(struct platform_device *pdev, > + pm_message_t state) > +{ > + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); > + > + clk_disable_unprepare(dcufb->clk); > + return 0; > +} > + > +static int fsl_dcu_resume(struct platform_device *pdev) > +{ > + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); > + > + clk_prepare_enable(dcufb->clk); > + return 0; > +} > +#else > +#define fsl_dcu_suspend NULL > +#define fsl_dcu_resume NULL > +#endif > + Could this be replaced by runtime pm? > +static int bypass_tcon(struct device_node *np) > +{ > + struct device_node *tcon_np; > + struct platform_device *tcon_pdev; > + struct clk *tcon_clk; > + void __iomem *tcon_reg; > + int ret = 0; > + > + tcon_np = of_parse_phandle(np, "tcon-controller", 0); > + if (!tcon_np) > + return -EINVAL; > + > + tcon_pdev = of_find_device_by_node(tcon_np); > + if (!tcon_pdev) > + return -EINVAL; > + > + tcon_clk = devm_clk_get(&tcon_pdev->dev, "tcon"); > + if (IS_ERR(tcon_clk)) { > + ret = PTR_ERR(tcon_clk); > + goto failed_getclock; > + } > + clk_prepare_enable(tcon_clk); > + > + tcon_reg = of_iomap(tcon_np, 0); > + if (!tcon_reg) { > + ret = -ENOMEM; > + goto failed_ioremap; > + } > + writel(TCON_BYPASS_ENABLE, tcon_reg + TCON_CTRL1); > + > + return 0; > + > +failed_ioremap: > + clk_disable_unprepare(tcon_clk); > +failed_getclock: > + of_node_put(tcon_np); > + return ret; > +} > + Is the framebuffer driver the only user of tcon? If not you should not map the memory here, but rather use something like regmap syscon. [...] Regards, Lucas -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-06 8:47 ` Lucas Stach 0 siblings, 0 replies; 38+ messages in thread From: Lucas Stach @ 2013-08-06 8:47 UTC (permalink / raw) To: linux-arm-kernel Am Freitag, den 12.07.2013, 14:07 +0800 schrieb Alison Wang: > The Display Controller Unit (DCU) module is a system master that > fetches graphics stored in internal or external memory and displays > them on a TFT LCD panel. A wide range of panel sizes is supported > and the timing of the interface signals is highly configurable. > Graphics are read directly from memory and then blended in real-time, > which allows for dynamic content creation with minimal CPU intervention. > > The features: > > (1) Full RGB888 output to TFT LCD panel. > (2) For the current LCD panel, WQVGA "480x272" is tested. > (3) Blending of each pixel using up to 4 source layers dependent on size of panel. > (4) Each graphic layer can be placed with one pixel resolution in either axis. > (5) Each graphic layer support RGB565 and RGB888 direct colors without alpha channel > and BGRA8888 direct colors with an alpha channel. > (6) Each graphic layer support alpha blending with 8-bit resolution. > > This driver has been tested on Vybrid VF610 TOWER board. > > Signed-off-by: Alison Wang <b18965@freescale.com> > --- > Changes in v2: None > > drivers/video/Kconfig | 9 + > drivers/video/Makefile | 1 + > drivers/video/fsl-dcu-fb.c | 1091 ++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 1101 insertions(+) > create mode 100644 drivers/video/fsl-dcu-fb.c > [...] > + > +static struct fb_videomode dcu_mode_db[] = { > + { > + .name = "480x272", > + .refresh = 75, > + .xres = 480, > + .yres = 272, > + .pixclock = 91996, > + .left_margin = 2, > + .right_margin = 2, > + .upper_margin = 1, > + .lower_margin = 1, > + .hsync_len = 41, > + .vsync_len = 2, > + .sync = FB_SYNC_COMP_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, > + .vmode = FB_VMODE_NONINTERLACED, > + }, > +}; Don't hardcode panel data in the driver. Use the videomode helpers to get the relevant data from devicetree. > + > +/* DCU framebuffer data structure */ > +struct dcu_fb_data { > + struct fb_info *fsl_dcu_info[DCU_LAYER_NUM]; > + void __iomem *reg_base; > + unsigned int irq; > + struct clk *clk; > +}; > + > +struct layer_display_offset { > + int x_layer_d; > + int y_layer_d; > +}; > + > +struct mfb_info { > + int index; > + char *id; > + unsigned long pseudo_palette[16]; > + unsigned char alpha; > + unsigned char blend; > + unsigned int count; > + int x_layer_d; /* layer display x offset to physical screen */ > + int y_layer_d; /* layer display y offset to physical screen */ > + struct dcu_fb_data *parent; > +}; > + > +enum mfb_index { > + LAYER0 = 0, > + LAYER1, > + LAYER2, > + LAYER3, > +}; Why are there only 4 layers here? I thought the controller supports at least 6 simultaneous layers? > + > +static struct mfb_info mfb_template[] = { > + { > + .index = LAYER0, > + .id = "Layer0", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 0, > + .y_layer_d = 0, > + }, > + { > + .index = LAYER1, > + .id = "Layer1", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 50, > + .y_layer_d = 50, > + }, > + { > + .index = LAYER2, > + .id = "Layer2", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 100, > + .y_layer_d = 100, > + }, > + { > + .index = LAYER3, > + .id = "Layer3", > + .alpha = 0xff, > + .blend = 0, > + .count = 0, > + .x_layer_d = 150, > + .y_layer_d = 150, > + }, > +}; [...] > + > +static int calc_div_ratio(struct fb_info *info) > +{ > + struct mfb_info *mfbi = info->par; > + struct dcu_fb_data *dcufb = mfbi->parent; > + unsigned long dcu_clk; > + unsigned long long tmp; > + > + dcu_clk = clk_get_rate(dcufb->clk); > + tmp = info->var.pixclock * (unsigned long long)dcu_clk; > + > + do_div(tmp, 1000000); > + > + if (do_div(tmp, 1000000) > 500000) > + tmp++; Urgh, you are changing the value of tmp inside the if clause. This isn't nice. This function as a a whole looks really odd. > + > + tmp = tmp - 1; > + return tmp; > +} > + > +static void update_controller(struct fb_info *info) > +{ > + struct fb_var_screeninfo *var = &info->var; > + struct mfb_info *mfbi = info->par; > + struct dcu_fb_data *dcufb = mfbi->parent; > + unsigned int ratio; > + > + ratio = calc_div_ratio(info); > + writel(ratio, dcufb->reg_base + DCU_DIV_RATIO); > + > + writel(DCU_DISP_SIZE_DELTA_Y(var->yres) | > + DCU_DISP_SIZE_DELTA_X(var->xres / 16), > + dcufb->reg_base + DCU_DISP_SIZE); > + > + /* Horizontal and vertical sync parameter */ > + writel(DCU_HSYN_PARA_BP(var->left_margin) | > + DCU_HSYN_PARA_PW(var->hsync_len) | > + DCU_HSYN_PARA_FP(var->right_margin), > + dcufb->reg_base + DCU_HSYN_PARA); > + > + writel(DCU_VSYN_PARA_BP(var->upper_margin) | > + DCU_VSYN_PARA_PW(var->vsync_len) | > + DCU_VSYN_PARA_FP(var->lower_margin), > + dcufb->reg_base + DCU_VSYN_PARA); > + > + writel(DCU_SYN_POL_INV_PXCK_FALL | DCU_SYN_POL_NEG_REMAIN | > + DCU_SYN_POL_INV_VS_LOW | DCU_SYN_POL_INV_HS_LOW, > + dcufb->reg_base + DCU_SYN_POL); > + > + writel(DCU_BGND_R(0) | DCU_BGND_G(0) | DCU_BGND_B(0), > + dcufb->reg_base + DCU_BGND); > + > + writel(DCU_MODE_BLEND_ITER(DCU_LAYER_NUM_MAX) | DCU_MODE_RASTER_EN, > + dcufb->reg_base + DCU_DCU_MODE); > + > + writel(DCU_THRESHOLD_LS_BF_VS(0x3) | DCU_THRESHOLD_OUT_BUF_HIGH(0x78) | > + DCU_THRESHOLD_OUT_BUF_LOW(0), dcufb->reg_base + DCU_THRESHOLD); > + > + enable_controller(info); > +} > + > +static int map_video_memory(struct fb_info *info) > +{ > + u32 smem_len = info->fix.line_length * info->var.yres_virtual; > + > + info->fix.smem_len = smem_len; > + > + info->screen_base = dma_alloc_coherent(info->device, info->fix.smem_len, You are setting up an uncached mapping here. Use a writecombined mapping to help performance. It's still coherent, but allows at least write to be fast. > + (dma_addr_t *)&info->fix.smem_start, GFP_KERNEL); > + if (!info->screen_base) { > + printk(KERN_ERR "unable to allocate fb memory\n"); > + return -ENOMEM; > + } > + > + memset(info->screen_base, 0, info->fix.smem_len); > + > + return 0; > +} > + > +static void unmap_video_memory(struct fb_info *info) > +{ > + if (!info->screen_base) > + return; > + > + dma_free_coherent(info->device, info->fix.smem_len, > + info->screen_base, info->fix.smem_start); > + > + info->screen_base = NULL; > + info->fix.smem_start = 0; > + info->fix.smem_len = 0; > +} [...] > + > +static int fsl_dcu_open(struct fb_info *info, int user) > +{ > + struct mfb_info *mfbi = info->par; > + int ret = 0; > + > + mfbi->index = info->node; > + > + mfbi->count++; > + if (mfbi->count == 1) { > + fsl_dcu_check_var(&info->var, info); > + ret = fsl_dcu_set_par(info); > + if (ret < 0) > + mfbi->count--; > + else > + enable_interrupts(mfbi->parent); > + } > + > + return ret; > +} > + > +static int fsl_dcu_release(struct fb_info *info, int user) > +{ > + struct mfb_info *mfbi = info->par; > + int ret = 0; > + > + mfbi->count--; > + if (mfbi->count == 0) { > + ret = disable_panel(info); > + if (ret < 0) > + mfbi->count++; > + } > + > + return ret; > +} Could this be replaced by runtime pm? > + > +static struct fb_ops fsl_dcu_ops = { > + .owner = THIS_MODULE, > + .fb_check_var = fsl_dcu_check_var, > + .fb_set_par = fsl_dcu_set_par, > + .fb_setcolreg = fsl_dcu_setcolreg, > + .fb_blank = fsl_dcu_blank, > + .fb_pan_display = fsl_dcu_pan_display, > + .fb_fillrect = cfb_fillrect, > + .fb_copyarea = cfb_copyarea, > + .fb_imageblit = cfb_imageblit, > + .fb_ioctl = fsl_dcu_ioctl, > + .fb_open = fsl_dcu_open, > + .fb_release = fsl_dcu_release, > +}; > + > +static int install_framebuffer(struct fb_info *info) > +{ > + struct mfb_info *mfbi = info->par; > + struct fb_videomode *db = dcu_mode_db; > + unsigned int dbsize = ARRAY_SIZE(dcu_mode_db); > + int ret; > + > + info->var.activate = FB_ACTIVATE_NOW; > + info->fbops = &fsl_dcu_ops; > + info->flags = FBINFO_FLAG_DEFAULT; > + info->pseudo_palette = &mfbi->pseudo_palette; > + > + fb_alloc_cmap(&info->cmap, 16, 0); > + > + ret = fb_find_mode(&info->var, info, fb_mode, db, dbsize, > + NULL, default_bpp); > + > + if (fsl_dcu_check_var(&info->var, info)) { > + ret = -EINVAL; > + goto failed_checkvar; > + } > + > + if (register_framebuffer(info) < 0) { > + ret = -EINVAL; > + goto failed_register_framebuffer; > + } > + > + printk(KERN_INFO "fb%d: %s fb device registered successfully.\n", > + info->node, info->fix.id); > + return 0; > + > +failed_checkvar: > + fb_dealloc_cmap(&info->cmap); > +failed_register_framebuffer: > + unmap_video_memory(info); > + fb_dealloc_cmap(&info->cmap); > + return ret; > +} > + > +static void uninstall_framebuffer(struct fb_info *info) > +{ > + unregister_framebuffer(info); > + unmap_video_memory(info); > + > + if (&info->cmap) > + fb_dealloc_cmap(&info->cmap); > +} > + > +static irqreturn_t fsl_dcu_irq(int irq, void *dev_id) > +{ > + struct dcu_fb_data *dcufb = dev_id; > + unsigned int status = readl(dcufb->reg_base + DCU_INT_STATUS); > + u32 dcu_mode; > + > + if (status) { > + if (status & DCU_INT_STATUS_UNDRUN) { > + dcu_mode = readl(dcufb->reg_base + DCU_DCU_MODE); > + dcu_mode &= ~DCU_MODE_DCU_MODE_MASK; > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_OFF), > + dcufb->reg_base + DCU_DCU_MODE); > + udelay(1); > + writel(dcu_mode | DCU_MODE_DCU_MODE(DCU_MODE_NORMAL), > + dcufb->reg_base + DCU_DCU_MODE); > + } > + writel(status, dcufb->reg_base + DCU_INT_STATUS); > + return IRQ_HANDLED; > + } > + return IRQ_NONE; > +} > + > +#ifdef CONFIG_PM > +static int fsl_dcu_suspend(struct platform_device *pdev, > + pm_message_t state) > +{ > + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); > + > + clk_disable_unprepare(dcufb->clk); > + return 0; > +} > + > +static int fsl_dcu_resume(struct platform_device *pdev) > +{ > + struct dcu_fb_data *dcufb = dev_get_drvdata(&pdev->dev); > + > + clk_prepare_enable(dcufb->clk); > + return 0; > +} > +#else > +#define fsl_dcu_suspend NULL > +#define fsl_dcu_resume NULL > +#endif > + Could this be replaced by runtime pm? > +static int bypass_tcon(struct device_node *np) > +{ > + struct device_node *tcon_np; > + struct platform_device *tcon_pdev; > + struct clk *tcon_clk; > + void __iomem *tcon_reg; > + int ret = 0; > + > + tcon_np = of_parse_phandle(np, "tcon-controller", 0); > + if (!tcon_np) > + return -EINVAL; > + > + tcon_pdev = of_find_device_by_node(tcon_np); > + if (!tcon_pdev) > + return -EINVAL; > + > + tcon_clk = devm_clk_get(&tcon_pdev->dev, "tcon"); > + if (IS_ERR(tcon_clk)) { > + ret = PTR_ERR(tcon_clk); > + goto failed_getclock; > + } > + clk_prepare_enable(tcon_clk); > + > + tcon_reg = of_iomap(tcon_np, 0); > + if (!tcon_reg) { > + ret = -ENOMEM; > + goto failed_ioremap; > + } > + writel(TCON_BYPASS_ENABLE, tcon_reg + TCON_CTRL1); > + > + return 0; > + > +failed_ioremap: > + clk_disable_unprepare(tcon_clk); > +failed_getclock: > + of_node_put(tcon_np); > + return ret; > +} > + Is the framebuffer driver the only user of tcon? If not you should not map the memory here, but rather use something like regmap syscon. [...] Regards, Lucas -- Pengutronix e.K. | Lucas Stach | Industrial Linux Solutions | http://www.pengutronix.de/ | Peiner Str. 6-8, 31137 Hildesheim, Germany | Phone: +49-5121-206917-5076 | Amtsgericht Hildesheim, HRA 2686 | Fax: +49-5121-206917-5555 | ^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform 2013-08-06 8:47 ` Lucas Stach @ 2013-08-07 8:07 ` Wang Huan-B18965 -1 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-07 8:07 UTC (permalink / raw) To: linux-arm-kernel DQo+IEFtIEZyZWl0YWcsIGRlbiAxMi4wNy4yMDEzLCAxNDowNyArMDgwMCBzY2hyaWViIEFsaXNv biBXYW5nOg0KPiA+IFRoZSBEaXNwbGF5IENvbnRyb2xsZXIgVW5pdCAoRENVKSBtb2R1bGUgaXMg YSBzeXN0ZW0gbWFzdGVyIHRoYXQNCj4gPiBmZXRjaGVzIGdyYXBoaWNzIHN0b3JlZCBpbiBpbnRl cm5hbCBvciBleHRlcm5hbCBtZW1vcnkgYW5kIGRpc3BsYXlzDQo+ID4gdGhlbSBvbiBhIFRGVCBM Q0QgcGFuZWwuIEEgd2lkZSByYW5nZSBvZiBwYW5lbCBzaXplcyBpcyBzdXBwb3J0ZWQgYW5kDQo+ ID4gdGhlIHRpbWluZyBvZiB0aGUgaW50ZXJmYWNlIHNpZ25hbHMgaXMgaGlnaGx5IGNvbmZpZ3Vy YWJsZS4NCj4gPiBHcmFwaGljcyBhcmUgcmVhZCBkaXJlY3RseSBmcm9tIG1lbW9yeSBhbmQgdGhl biBibGVuZGVkIGluIHJlYWwtdGltZSwNCj4gPiB3aGljaCBhbGxvd3MgZm9yIGR5bmFtaWMgY29u dGVudCBjcmVhdGlvbiB3aXRoIG1pbmltYWwgQ1BVDQo+IGludGVydmVudGlvbi4NCj4gPg0KPiA+ IFRoZSBmZWF0dXJlczoNCj4gPg0KPiA+ICgxKSBGdWxsIFJHQjg4OCBvdXRwdXQgdG8gVEZUIExD RCBwYW5lbC4NCj4gPiAoMikgRm9yIHRoZSBjdXJyZW50IExDRCBwYW5lbCwgV1FWR0EgIjQ4MHgy NzIiIGlzIHRlc3RlZC4NCj4gPiAoMykgQmxlbmRpbmcgb2YgZWFjaCBwaXhlbCB1c2luZyB1cCB0 byA0IHNvdXJjZSBsYXllcnMgZGVwZW5kZW50IG9uDQo+IHNpemUgb2YgcGFuZWwuDQo+ID4gKDQp IEVhY2ggZ3JhcGhpYyBsYXllciBjYW4gYmUgcGxhY2VkIHdpdGggb25lIHBpeGVsIHJlc29sdXRp b24gaW4NCj4gZWl0aGVyIGF4aXMuDQo+ID4gKDUpIEVhY2ggZ3JhcGhpYyBsYXllciBzdXBwb3J0 IFJHQjU2NSBhbmQgUkdCODg4IGRpcmVjdCBjb2xvcnMNCj4gd2l0aG91dA0KPiA+IGFscGhhIGNo YW5uZWwgYW5kIEJHUkE4ODg4IGRpcmVjdCBjb2xvcnMgd2l0aCBhbiBhbHBoYSBjaGFubmVsLg0K PiA+ICg2KSBFYWNoIGdyYXBoaWMgbGF5ZXIgc3VwcG9ydCBhbHBoYSBibGVuZGluZyB3aXRoIDgt Yml0IHJlc29sdXRpb24uDQo+ID4NCj4gPiBUaGlzIGRyaXZlciBoYXMgYmVlbiB0ZXN0ZWQgb24g VnlicmlkIFZGNjEwIFRPV0VSIGJvYXJkLg0KPiA+DQo+ID4gU2lnbmVkLW9mZi1ieTogQWxpc29u IFdhbmcgPGIxODk2NUBmcmVlc2NhbGUuY29tPg0KPiA+IC0tLQ0KPiA+IENoYW5nZXMgaW4gdjI6 IE5vbmUNCj4gPg0KPiA+ICBkcml2ZXJzL3ZpZGVvL0tjb25maWcgICAgICB8ICAgIDkgKw0KPiA+ ICBkcml2ZXJzL3ZpZGVvL01ha2VmaWxlICAgICB8ICAgIDEgKw0KPiA+ICBkcml2ZXJzL3ZpZGVv L2ZzbC1kY3UtZmIuYyB8IDEwOTENCj4gPiArKysrKysrKysrKysrKysrKysrKysrKysrKysrKysr KysrKysrKysrKysrKw0KPiA+ICAzIGZpbGVzIGNoYW5nZWQsIDExMDEgaW5zZXJ0aW9ucygrKQ0K PiA+ICBjcmVhdGUgbW9kZSAxMDA2NDQgZHJpdmVycy92aWRlby9mc2wtZGN1LWZiLmMNCj4gPg0K PiBbLi4uXQ0KPiA+ICtlbnVtIG1mYl9pbmRleCB7DQo+ID4gKwlMQVlFUjAgPSAwLA0KPiA+ICsJ TEFZRVIxLA0KPiA+ICsJTEFZRVIyLA0KPiA+ICsJTEFZRVIzLA0KPiA+ICt9Ow0KPiBXaHkgYXJl IHRoZXJlIG9ubHkgNCBsYXllcnMgaGVyZT8gSSB0aG91Z2h0IHRoZSBjb250cm9sbGVyIHN1cHBv cnRzIGF0DQo+IGxlYXN0IDYgc2ltdWx0YW5lb3VzIGxheWVycz8NCltBbGlzb24gV2FuZ10gSSB1 c2VkIDQgbGF5ZXJzIGZvciB0aGUgY3VzdG9tZXIncyByZXF1aXJlbWVudCBiZWZvcmUuIEFueXdh eSwgSSB3aWxsIGNoYW5nZSBpdCB0byA2IGluIG5leHQgdmVyc2lvbi4NCkJUVywgYWNjb3JkaW5n IHRvIHRoZSBSTSwgaXQgc2FpZCAiQmxlbmRpbmcgb2YgZWFjaCBwaXhlbCB1c2luZyB1cCB0byA2 IHNvdXJjZSBsYXllcnMgZGVwZW5kZW50IG9uIHNpemUgb2YgcGFuZWwiLiBTbyBJIHRoaW5rIHRo ZSBtb3N0IHNpbXVsdGFuZW91cyBsYXllcnMgaXMgNi4NCj4gDQo+ID4gKw0KPiA+ICtzdGF0aWMg c3RydWN0IG1mYl9pbmZvIG1mYl90ZW1wbGF0ZVtdID0gew0KPiA+ICsJew0KPiA+ICsJLmluZGV4 ID0gTEFZRVIwLA0KPiA+ICsJLmlkID0gIkxheWVyMCIsDQo+ID4gKwkuYWxwaGEgPSAweGZmLA0K PiA+ICsJLmJsZW5kID0gMCwNCj4gPiArCS5jb3VudCA9IDAsDQo+ID4gKwkueF9sYXllcl9kID0g MCwNCj4gPiArCS55X2xheWVyX2QgPSAwLA0KPiA+ICsJfSwNCj4gPiArCXsNCj4gPiArCS5pbmRl eCA9IExBWUVSMSwNCj4gPiArCS5pZCA9ICJMYXllcjEiLA0KPiA+ICsJLmFscGhhID0gMHhmZiwN Cj4gPiArCS5ibGVuZCA9IDAsDQo+ID4gKwkuY291bnQgPSAwLA0KPiA+ICsJLnhfbGF5ZXJfZCA9 IDUwLA0KPiA+ICsJLnlfbGF5ZXJfZCA9IDUwLA0KPiA+ICsJfSwNCj4gPiArCXsNCj4gPiArCS5p bmRleCA9IExBWUVSMiwNCj4gPiArCS5pZCA9ICJMYXllcjIiLA0KPiA+ICsJLmFscGhhID0gMHhm ZiwNCj4gPiArCS5ibGVuZCA9IDAsDQo+ID4gKwkuY291bnQgPSAwLA0KPiA+ICsJLnhfbGF5ZXJf ZCA9IDEwMCwNCj4gPiArCS55X2xheWVyX2QgPSAxMDAsDQo+ID4gKwl9LA0KPiA+ICsJew0KPiA+ ICsJLmluZGV4ID0gTEFZRVIzLA0KPiA+ICsJLmlkID0gIkxheWVyMyIsDQo+ID4gKwkuYWxwaGEg PSAweGZmLA0KPiA+ICsJLmJsZW5kID0gMCwNCj4gPiArCS5jb3VudCA9IDAsDQo+ID4gKwkueF9s YXllcl9kID0gMTUwLA0KPiA+ICsJLnlfbGF5ZXJfZCA9IDE1MCwNCj4gPiArCX0sDQo+ID4gK307 DQo+IFsuLi5dDQo+ID4gK3N0YXRpYyBpbnQgZnNsX2RjdV9yZWxlYXNlKHN0cnVjdCBmYl9pbmZv ICppbmZvLCBpbnQgdXNlcikgew0KPiA+ICsJc3RydWN0IG1mYl9pbmZvICptZmJpID0gaW5mby0+ cGFyOw0KPiA+ICsJaW50IHJldCA9IDA7DQo+ID4gKw0KPiA+ICsJbWZiaS0+Y291bnQtLTsNCj4g PiArCWlmIChtZmJpLT5jb3VudCA9PSAwKSB7DQo+ID4gKwkJcmV0ID0gZGlzYWJsZV9wYW5lbChp bmZvKTsNCj4gPiArCQlpZiAocmV0IDwgMCkNCj4gPiArCQkJbWZiaS0+Y291bnQrKzsNCj4gPiAr CX0NCj4gPiArDQo+ID4gKwlyZXR1cm4gcmV0Ow0KPiA+ICt9DQo+IENvdWxkIHRoaXMgYmUgcmVw bGFjZWQgYnkgcnVudGltZSBwbT8NCltBbGlzb24gV2FuZ10gWWVzLCBJIHdpbGwgdXNlIHJ1bnRp bWUgcG0uDQo+IFsuLi5dDQo+ID4gK3N0YXRpYyBpbnQgYnlwYXNzX3Rjb24oc3RydWN0IGRldmlj ZV9ub2RlICpucCkgew0KPiA+ICsJc3RydWN0IGRldmljZV9ub2RlICp0Y29uX25wOw0KPiA+ICsJ c3RydWN0IHBsYXRmb3JtX2RldmljZSAqdGNvbl9wZGV2Ow0KPiA+ICsJc3RydWN0IGNsayAqdGNv bl9jbGs7DQo+ID4gKwl2b2lkIF9faW9tZW0gKnRjb25fcmVnOw0KPiA+ICsJaW50IHJldCA9IDA7 DQo+ID4gKw0KPiA+ICsJdGNvbl9ucCA9IG9mX3BhcnNlX3BoYW5kbGUobnAsICJ0Y29uLWNvbnRy b2xsZXIiLCAwKTsNCj4gPiArCWlmICghdGNvbl9ucCkNCj4gPiArCQlyZXR1cm4gLUVJTlZBTDsN Cj4gPiArDQo+ID4gKwl0Y29uX3BkZXYgPSBvZl9maW5kX2RldmljZV9ieV9ub2RlKHRjb25fbnAp Ow0KPiA+ICsJaWYgKCF0Y29uX3BkZXYpDQo+ID4gKwkJcmV0dXJuIC1FSU5WQUw7DQo+ID4gKw0K PiA+ICsJdGNvbl9jbGsgPSBkZXZtX2Nsa19nZXQoJnRjb25fcGRldi0+ZGV2LCAidGNvbiIpOw0K PiA+ICsJaWYgKElTX0VSUih0Y29uX2NsaykpIHsNCj4gPiArCQlyZXQgPSBQVFJfRVJSKHRjb25f Y2xrKTsNCj4gPiArCQlnb3RvIGZhaWxlZF9nZXRjbG9jazsNCj4gPiArCX0NCj4gPiArCWNsa19w cmVwYXJlX2VuYWJsZSh0Y29uX2Nsayk7DQo+ID4gKw0KPiA+ICsJdGNvbl9yZWcgPSBvZl9pb21h cCh0Y29uX25wLCAwKTsNCj4gPiArCWlmICghdGNvbl9yZWcpIHsNCj4gPiArCQlyZXQgPSAtRU5P TUVNOw0KPiA+ICsJCWdvdG8gZmFpbGVkX2lvcmVtYXA7DQo+ID4gKwl9DQo+ID4gKwl3cml0ZWwo VENPTl9CWVBBU1NfRU5BQkxFLCB0Y29uX3JlZyArIFRDT05fQ1RSTDEpOw0KPiA+ICsNCj4gPiAr CXJldHVybiAwOw0KPiA+ICsNCj4gPiArZmFpbGVkX2lvcmVtYXA6DQo+ID4gKwljbGtfZGlzYWJs ZV91bnByZXBhcmUodGNvbl9jbGspOw0KPiA+ICtmYWlsZWRfZ2V0Y2xvY2s6DQo+ID4gKwlvZl9u b2RlX3B1dCh0Y29uX25wKTsNCj4gPiArCXJldHVybiByZXQ7DQo+ID4gK30NCj4gPiArDQo+IElz IHRoZSBmcmFtZWJ1ZmZlciBkcml2ZXIgdGhlIG9ubHkgdXNlciBvZiB0Y29uPyBJZiBub3QgeW91 IHNob3VsZCBub3QNCj4gbWFwIHRoZSBtZW1vcnkgaGVyZSwgYnV0IHJhdGhlciB1c2Ugc29tZXRo aW5nIGxpa2UgcmVnbWFwIHN5c2Nvbi4NCltBbGlzb24gV2FuZ10gWWVzLCB0aGUgZmIgZHJpdmVy IGlzIHRoZSBvbmx5IHVzZXIgb2YgdGNvbi4NCg0KVGhhbmtzIGZvciB5b3VyIGNvbW1lbnRzIQ0K DQoNCkJlc3QgUmVnYXJkcywNCkFsaXNvbiBXYW5nDQoNCg0KDQo ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-08-07 8:07 ` Wang Huan-B18965 0 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-08-07 8:07 UTC (permalink / raw) To: linux-arm-kernel > Am Freitag, den 12.07.2013, 14:07 +0800 schrieb Alison Wang: > > The Display Controller Unit (DCU) module is a system master that > > fetches graphics stored in internal or external memory and displays > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > the timing of the interface signals is highly configurable. > > Graphics are read directly from memory and then blended in real-time, > > which allows for dynamic content creation with minimal CPU > intervention. > > > > The features: > > > > (1) Full RGB888 output to TFT LCD panel. > > (2) For the current LCD panel, WQVGA "480x272" is tested. > > (3) Blending of each pixel using up to 4 source layers dependent on > size of panel. > > (4) Each graphic layer can be placed with one pixel resolution in > either axis. > > (5) Each graphic layer support RGB565 and RGB888 direct colors > without > > alpha channel and BGRA8888 direct colors with an alpha channel. > > (6) Each graphic layer support alpha blending with 8-bit resolution. > > > > This driver has been tested on Vybrid VF610 TOWER board. > > > > Signed-off-by: Alison Wang <b18965@freescale.com> > > --- > > Changes in v2: None > > > > drivers/video/Kconfig | 9 + > > drivers/video/Makefile | 1 + > > drivers/video/fsl-dcu-fb.c | 1091 > > ++++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 1101 insertions(+) > > create mode 100644 drivers/video/fsl-dcu-fb.c > > > [...] > > +enum mfb_index { > > + LAYER0 = 0, > > + LAYER1, > > + LAYER2, > > + LAYER3, > > +}; > Why are there only 4 layers here? I thought the controller supports at > least 6 simultaneous layers? [Alison Wang] I used 4 layers for the customer's requirement before. Anyway, I will change it to 6 in next version. BTW, according to the RM, it said "Blending of each pixel using up to 6 source layers dependent on size of panel". So I think the most simultaneous layers is 6. > > > + > > +static struct mfb_info mfb_template[] = { > > + { > > + .index = LAYER0, > > + .id = "Layer0", > > + .alpha = 0xff, > > + .blend = 0, > > + .count = 0, > > + .x_layer_d = 0, > > + .y_layer_d = 0, > > + }, > > + { > > + .index = LAYER1, > > + .id = "Layer1", > > + .alpha = 0xff, > > + .blend = 0, > > + .count = 0, > > + .x_layer_d = 50, > > + .y_layer_d = 50, > > + }, > > + { > > + .index = LAYER2, > > + .id = "Layer2", > > + .alpha = 0xff, > > + .blend = 0, > > + .count = 0, > > + .x_layer_d = 100, > > + .y_layer_d = 100, > > + }, > > + { > > + .index = LAYER3, > > + .id = "Layer3", > > + .alpha = 0xff, > > + .blend = 0, > > + .count = 0, > > + .x_layer_d = 150, > > + .y_layer_d = 150, > > + }, > > +}; > [...] > > +static int fsl_dcu_release(struct fb_info *info, int user) { > > + struct mfb_info *mfbi = info->par; > > + int ret = 0; > > + > > + mfbi->count--; > > + if (mfbi->count == 0) { > > + ret = disable_panel(info); > > + if (ret < 0) > > + mfbi->count++; > > + } > > + > > + return ret; > > +} > Could this be replaced by runtime pm? [Alison Wang] Yes, I will use runtime pm. > [...] > > +static int bypass_tcon(struct device_node *np) { > > + struct device_node *tcon_np; > > + struct platform_device *tcon_pdev; > > + struct clk *tcon_clk; > > + void __iomem *tcon_reg; > > + int ret = 0; > > + > > + tcon_np = of_parse_phandle(np, "tcon-controller", 0); > > + if (!tcon_np) > > + return -EINVAL; > > + > > + tcon_pdev = of_find_device_by_node(tcon_np); > > + if (!tcon_pdev) > > + return -EINVAL; > > + > > + tcon_clk = devm_clk_get(&tcon_pdev->dev, "tcon"); > > + if (IS_ERR(tcon_clk)) { > > + ret = PTR_ERR(tcon_clk); > > + goto failed_getclock; > > + } > > + clk_prepare_enable(tcon_clk); > > + > > + tcon_reg = of_iomap(tcon_np, 0); > > + if (!tcon_reg) { > > + ret = -ENOMEM; > > + goto failed_ioremap; > > + } > > + writel(TCON_BYPASS_ENABLE, tcon_reg + TCON_CTRL1); > > + > > + return 0; > > + > > +failed_ioremap: > > + clk_disable_unprepare(tcon_clk); > > +failed_getclock: > > + of_node_put(tcon_np); > > + return ret; > > +} > > + > Is the framebuffer driver the only user of tcon? If not you should not > map the memory here, but rather use something like regmap syscon. [Alison Wang] Yes, the fb driver is the only user of tcon. Thanks for your comments! Best Regards, Alison Wang ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH 5/5] Documentation: DT: Add DCU framebuffer driver 2013-07-12 6:07 ` Alison Wang @ 2013-07-12 6:07 ` Alison Wang -1 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch adds the document for DCU framebuffer driver under Documentation/devicetree/bindings/fb/. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: New - Add this document for DCU framebuffer driver. .../devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt diff --git a/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt b/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt new file mode 100644 index 0000000..231bda7 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt @@ -0,0 +1,36 @@ +* Freescale Display Control Unit (DCU) + +Required properties: +- compatible: Should be "fsl,vf610-dcu". Supported chips include + Vybrid VF610. +- reg: Address and length of the register set for DCU. +- interrupts: Should contain DCU interrupts. +- clocks: From common clock binding: handle to DCU clock. +- clock-names: From common clock binding: Shall be "dcu". +- tcon-controller: The phandle of TCON controller. + +For the DCU initialization, we read data from TCON node. +Required properties for TCON: +- compatible: Should be "fsl,vf610-tcon". Supported chips include + Vybrid VF610. +- reg: Address and length of the register set for TCON. +- clocks: From common clock binding: handle to TCON clock. +- clock-names: From common clock binding: Shall be "tcon". + +Examples: + +dcu0: dcu@40058000 { + compatible = "fsl,vf610-dcu"; + reg = <0x40058000 0x1200>; + interrupts = <0 30 0x04>; + clocks = <&clks VF610_CLK_DCU0>; + clock-names = "dcu"; + tcon-controller = <&tcon0>; +}; + +tcon0: tcon@4003d000 { + compatible = "fsl,vf610-tcon"; + reg = <0x4003d000 0x1000>; + clocks = <&clks VF610_CLK_TCON0>; + clock-names = "tcon"; +}; -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* [PATCH 5/5] Documentation: DT: Add DCU framebuffer driver @ 2013-07-12 6:07 ` Alison Wang 0 siblings, 0 replies; 38+ messages in thread From: Alison Wang @ 2013-07-12 6:07 UTC (permalink / raw) To: linux-arm-kernel This patch adds the document for DCU framebuffer driver under Documentation/devicetree/bindings/fb/. Signed-off-by: Alison Wang <b18965@freescale.com> --- Changes in v2: New - Add this document for DCU framebuffer driver. .../devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt diff --git a/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt b/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt new file mode 100644 index 0000000..231bda7 --- /dev/null +++ b/Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt @@ -0,0 +1,36 @@ +* Freescale Display Control Unit (DCU) + +Required properties: +- compatible: Should be "fsl,vf610-dcu". Supported chips include + Vybrid VF610. +- reg: Address and length of the register set for DCU. +- interrupts: Should contain DCU interrupts. +- clocks: From common clock binding: handle to DCU clock. +- clock-names: From common clock binding: Shall be "dcu". +- tcon-controller: The phandle of TCON controller. + +For the DCU initialization, we read data from TCON node. +Required properties for TCON: +- compatible: Should be "fsl,vf610-tcon". Supported chips include + Vybrid VF610. +- reg: Address and length of the register set for TCON. +- clocks: From common clock binding: handle to TCON clock. +- clock-names: From common clock binding: Shall be "tcon". + +Examples: + +dcu0: dcu at 40058000 { + compatible = "fsl,vf610-dcu"; + reg = <0x40058000 0x1200>; + interrupts = <0 30 0x04>; + clocks = <&clks VF610_CLK_DCU0>; + clock-names = "dcu"; + tcon-controller = <&tcon0>; +}; + +tcon0: tcon at 4003d000 { + compatible = "fsl,vf610-tcon"; + reg = <0x4003d000 0x1000>; + clocks = <&clks VF610_CLK_TCON0>; + clock-names = "tcon"; +}; -- 1.8.0 ^ permalink raw reply related [flat|nested] 38+ messages in thread
* RE: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-12 6:07 ` Alison Wang @ 2013-07-19 3:49 ` Wang Huan-B18965 -1 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-07-19 3:49 UTC (permalink / raw) To: linux-arm-kernel Hi, Jean-Christophe, Could you please help to review these patches? Thanks a lot! Best Regards, Alison Wang > -----Original Message----- > From: linux-arm-kernel [mailto:linux-arm-kernel- > bounces@lists.infradead.org] On Behalf Of Alison Wang > Sent: Friday, July 12, 2013 2:08 PM > To: plagnioj@jcrosoft.com; tomi.valkeinen@ti.com; shawn.guo@linaro.org; > Estevam Fabio-R49496; linux-fbdev@vger.kernel.org; linux-arm- > kernel@lists.infradead.org > Cc: Jin Zhengxiong-R64188 > Subject: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for > Vybrid VF610 platform > > This series contain DCU framebuffer driver for Freescale Vybrid VF610 > platform. > > The Display Controller Unit (DCU) module is a system master that > fetches graphics stored in internal or external memory and displays > them on a TFT LCD panel. A wide range of panel sizes is supported and > the timing of the interface signals is highly configurable. > Graphics are read directly from memory and then blended in real-time, > which allows for dynamic content creation with minimal CPU intervention. > > The features: > > (1) Full RGB888 output to TFT LCD panel. > (2) For the current LCD panel, WQVGA "480x272" is tested. > (3) Blending of each pixel using up to 4 source layers dependent on > size of panel. > (4) Each graphic layer can be placed with one pixel resolution in > either axis. > (5) Each graphic layer support RGB565 and RGB888 direct colors without > alpha channel and BGRA8888 direct colors with an alpha channel. > (6) Each graphic layer support alpha blending with 8-bit resolution. > > Changes in v2: > - Add a document for DCU framebuffer driver under > Documentation/devicetree/bindings/fb/. > > ---------------------------------------------------------------- > Alison Wang (5): > ARM: dts: vf610: Add DCU and TCON nodes > ARM: dts: vf610-twr: Enable DCU and TCON devices > ARM: clk: vf610: Add DCU and TCON clock support > fb: Add DCU framebuffer driver for Vybrid VF610 platform > Documentation: DT: Add DCU framebuffer driver > > Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++ > arch/arm/boot/dts/vf610-twr.dts | 10 + > arch/arm/boot/dts/vf610.dtsi | 19 +- > arch/arm/mach-imx/clk-vf610.c | 5 + > drivers/video/Kconfig | 9 + > drivers/video/Makefile | 1 + > drivers/video/fsl-dcu-fb.c | 1091 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++ > include/dt-bindings/clock/vf610-clock.h | 3 +- > 8 files changed, 1172 insertions(+), 2 deletions(-) create mode > 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt > create mode 100644 drivers/video/fsl-dcu-fb.c > > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-07-19 3:49 ` Wang Huan-B18965 0 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-07-19 3:49 UTC (permalink / raw) To: linux-arm-kernel Hi, Jean-Christophe, Could you please help to review these patches? Thanks a lot! Best Regards, Alison Wang > -----Original Message----- > From: linux-arm-kernel [mailto:linux-arm-kernel- > bounces at lists.infradead.org] On Behalf Of Alison Wang > Sent: Friday, July 12, 2013 2:08 PM > To: plagnioj at jcrosoft.com; tomi.valkeinen at ti.com; shawn.guo at linaro.org; > Estevam Fabio-R49496; linux-fbdev at vger.kernel.org; linux-arm- > kernel at lists.infradead.org > Cc: Jin Zhengxiong-R64188 > Subject: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for > Vybrid VF610 platform > > This series contain DCU framebuffer driver for Freescale Vybrid VF610 > platform. > > The Display Controller Unit (DCU) module is a system master that > fetches graphics stored in internal or external memory and displays > them on a TFT LCD panel. A wide range of panel sizes is supported and > the timing of the interface signals is highly configurable. > Graphics are read directly from memory and then blended in real-time, > which allows for dynamic content creation with minimal CPU intervention. > > The features: > > (1) Full RGB888 output to TFT LCD panel. > (2) For the current LCD panel, WQVGA "480x272" is tested. > (3) Blending of each pixel using up to 4 source layers dependent on > size of panel. > (4) Each graphic layer can be placed with one pixel resolution in > either axis. > (5) Each graphic layer support RGB565 and RGB888 direct colors without > alpha channel and BGRA8888 direct colors with an alpha channel. > (6) Each graphic layer support alpha blending with 8-bit resolution. > > Changes in v2: > - Add a document for DCU framebuffer driver under > Documentation/devicetree/bindings/fb/. > > ---------------------------------------------------------------- > Alison Wang (5): > ARM: dts: vf610: Add DCU and TCON nodes > ARM: dts: vf610-twr: Enable DCU and TCON devices > ARM: clk: vf610: Add DCU and TCON clock support > fb: Add DCU framebuffer driver for Vybrid VF610 platform > Documentation: DT: Add DCU framebuffer driver > > Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++ > arch/arm/boot/dts/vf610-twr.dts | 10 + > arch/arm/boot/dts/vf610.dtsi | 19 +- > arch/arm/mach-imx/clk-vf610.c | 5 + > drivers/video/Kconfig | 9 + > drivers/video/Makefile | 1 + > drivers/video/fsl-dcu-fb.c | 1091 > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > +++++++++++++++++++++++++ > include/dt-bindings/clock/vf610-clock.h | 3 +- > 8 files changed, 1172 insertions(+), 2 deletions(-) create mode > 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt > create mode 100644 drivers/video/fsl-dcu-fb.c > > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 38+ messages in thread
* RE: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform 2013-07-19 3:49 ` Wang Huan-B18965 @ 2013-07-29 6:13 ` Wang Huan-B18965 -1 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-07-29 6:13 UTC (permalink / raw) To: linux-arm-kernel Hi, Jean-Christophe, Tomi, Do you have any comments for these patches? Thanks! Best Regards, Alison Wang > -----Original Message----- > From: linux-arm-kernel [mailto:linux-arm-kernel- > bounces@lists.infradead.org] On Behalf Of Wang Huan-B18965 > Sent: Friday, July 19, 2013 11:49 AM > To: plagnioj@jcrosoft.com; tomi.valkeinen@ti.com; shawn.guo@linaro.org; > Estevam Fabio-R49496; linux-fbdev@vger.kernel.org; linux-arm- > kernel@lists.infradead.org > Cc: Jin Zhengxiong-R64188 > Subject: RE: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for > Vybrid VF610 platform > > Hi, Jean-Christophe, > > Could you please help to review these patches? > > Thanks a lot! > > > Best Regards, > Alison Wang > > > -----Original Message----- > > From: linux-arm-kernel [mailto:linux-arm-kernel- > > bounces@lists.infradead.org] On Behalf Of Alison Wang > > Sent: Friday, July 12, 2013 2:08 PM > > To: plagnioj@jcrosoft.com; tomi.valkeinen@ti.com; > > shawn.guo@linaro.org; Estevam Fabio-R49496; > > linux-fbdev@vger.kernel.org; linux-arm- kernel@lists.infradead.org > > Cc: Jin Zhengxiong-R64188 > > Subject: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for > > Vybrid VF610 platform > > > > This series contain DCU framebuffer driver for Freescale Vybrid VF610 > > platform. > > > > The Display Controller Unit (DCU) module is a system master that > > fetches graphics stored in internal or external memory and displays > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > the timing of the interface signals is highly configurable. > > Graphics are read directly from memory and then blended in real-time, > > which allows for dynamic content creation with minimal CPU > intervention. > > > > The features: > > > > (1) Full RGB888 output to TFT LCD panel. > > (2) For the current LCD panel, WQVGA "480x272" is tested. > > (3) Blending of each pixel using up to 4 source layers dependent on > > size of panel. > > (4) Each graphic layer can be placed with one pixel resolution in > > either axis. > > (5) Each graphic layer support RGB565 and RGB888 direct colors > without > > alpha channel and BGRA8888 direct colors with an alpha channel. > > (6) Each graphic layer support alpha blending with 8-bit resolution. > > > > Changes in v2: > > - Add a document for DCU framebuffer driver under > > Documentation/devicetree/bindings/fb/. > > > > ---------------------------------------------------------------- > > Alison Wang (5): > > ARM: dts: vf610: Add DCU and TCON nodes > > ARM: dts: vf610-twr: Enable DCU and TCON devices > > ARM: clk: vf610: Add DCU and TCON clock support > > fb: Add DCU framebuffer driver for Vybrid VF610 platform > > Documentation: DT: Add DCU framebuffer driver > > > > Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++ > > arch/arm/boot/dts/vf610-twr.dts | 10 + > > arch/arm/boot/dts/vf610.dtsi | 19 +- > > arch/arm/mach-imx/clk-vf610.c | 5 + > > drivers/video/Kconfig | 9 + > > drivers/video/Makefile | 1 + > > drivers/video/fsl-dcu-fb.c | 1091 > > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > +++++++++++++++++++++++++ > > include/dt-bindings/clock/vf610-clock.h | 3 +- > > 8 files changed, 1172 insertions(+), 2 deletions(-) create mode > > 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt > > create mode 100644 drivers/video/fsl-dcu-fb.c > > > > > > > > _______________________________________________ > > linux-arm-kernel mailing list > > linux-arm-kernel@lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel > > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 38+ messages in thread
* [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform @ 2013-07-29 6:13 ` Wang Huan-B18965 0 siblings, 0 replies; 38+ messages in thread From: Wang Huan-B18965 @ 2013-07-29 6:13 UTC (permalink / raw) To: linux-arm-kernel Hi, Jean-Christophe, Tomi, Do you have any comments for these patches? Thanks! Best Regards, Alison Wang > -----Original Message----- > From: linux-arm-kernel [mailto:linux-arm-kernel- > bounces at lists.infradead.org] On Behalf Of Wang Huan-B18965 > Sent: Friday, July 19, 2013 11:49 AM > To: plagnioj at jcrosoft.com; tomi.valkeinen at ti.com; shawn.guo at linaro.org; > Estevam Fabio-R49496; linux-fbdev at vger.kernel.org; linux-arm- > kernel at lists.infradead.org > Cc: Jin Zhengxiong-R64188 > Subject: RE: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for > Vybrid VF610 platform > > Hi, Jean-Christophe, > > Could you please help to review these patches? > > Thanks a lot! > > > Best Regards, > Alison Wang > > > -----Original Message----- > > From: linux-arm-kernel [mailto:linux-arm-kernel- > > bounces at lists.infradead.org] On Behalf Of Alison Wang > > Sent: Friday, July 12, 2013 2:08 PM > > To: plagnioj at jcrosoft.com; tomi.valkeinen at ti.com; > > shawn.guo at linaro.org; Estevam Fabio-R49496; > > linux-fbdev at vger.kernel.org; linux-arm- kernel at lists.infradead.org > > Cc: Jin Zhengxiong-R64188 > > Subject: [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for > > Vybrid VF610 platform > > > > This series contain DCU framebuffer driver for Freescale Vybrid VF610 > > platform. > > > > The Display Controller Unit (DCU) module is a system master that > > fetches graphics stored in internal or external memory and displays > > them on a TFT LCD panel. A wide range of panel sizes is supported and > > the timing of the interface signals is highly configurable. > > Graphics are read directly from memory and then blended in real-time, > > which allows for dynamic content creation with minimal CPU > intervention. > > > > The features: > > > > (1) Full RGB888 output to TFT LCD panel. > > (2) For the current LCD panel, WQVGA "480x272" is tested. > > (3) Blending of each pixel using up to 4 source layers dependent on > > size of panel. > > (4) Each graphic layer can be placed with one pixel resolution in > > either axis. > > (5) Each graphic layer support RGB565 and RGB888 direct colors > without > > alpha channel and BGRA8888 direct colors with an alpha channel. > > (6) Each graphic layer support alpha blending with 8-bit resolution. > > > > Changes in v2: > > - Add a document for DCU framebuffer driver under > > Documentation/devicetree/bindings/fb/. > > > > ---------------------------------------------------------------- > > Alison Wang (5): > > ARM: dts: vf610: Add DCU and TCON nodes > > ARM: dts: vf610-twr: Enable DCU and TCON devices > > ARM: clk: vf610: Add DCU and TCON clock support > > fb: Add DCU framebuffer driver for Vybrid VF610 platform > > Documentation: DT: Add DCU framebuffer driver > > > > Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt | 36 ++++ > > arch/arm/boot/dts/vf610-twr.dts | 10 + > > arch/arm/boot/dts/vf610.dtsi | 19 +- > > arch/arm/mach-imx/clk-vf610.c | 5 + > > drivers/video/Kconfig | 9 + > > drivers/video/Makefile | 1 + > > drivers/video/fsl-dcu-fb.c | 1091 > > > +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ > > +++++++++++++++++++++++++ > > include/dt-bindings/clock/vf610-clock.h | 3 +- > > 8 files changed, 1172 insertions(+), 2 deletions(-) create mode > > 100644 Documentation/devicetree/bindings/fb/fsl-dcu-fb.txt > > create mode 100644 drivers/video/fsl-dcu-fb.c > > > > > > > > _______________________________________________ > > linux-arm-kernel mailing list > > linux-arm-kernel at lists.infradead.org > > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel > > > > _______________________________________________ > linux-arm-kernel mailing list > linux-arm-kernel at lists.infradead.org > http://lists.infradead.org/mailman/listinfo/linux-arm-kernel ^ permalink raw reply [flat|nested] 38+ messages in thread
end of thread, other threads:[~2014-01-07 21:00 UTC | newest] Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2013-07-12 6:07 [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform Alison Wang 2013-07-12 6:07 ` Alison Wang 2013-07-12 6:07 ` [PATCH 1/5] ARM: dts: vf610: Add DCU and TCON nodes Alison Wang 2013-07-12 6:07 ` Alison Wang 2013-07-12 6:07 ` [PATCH 2/5] ARM: dts: vf610-twr: Enable DCU and TCON devices Alison Wang 2013-07-12 6:07 ` Alison Wang 2013-07-12 6:07 ` [PATCH 3/5] ARM: clk: vf610: Add DCU and TCON clock support Alison Wang 2013-07-12 6:07 ` Alison Wang 2013-07-12 6:07 ` [PATCH 4/5] fb: Add DCU framebuffer driver for Vybrid VF610 platform Alison Wang 2013-07-12 6:07 ` Alison Wang 2013-07-29 11:14 ` Sascha Hauer 2013-07-29 11:14 ` Sascha Hauer 2013-08-05 9:51 ` Wang Huan-B18965 2013-08-05 9:51 ` Wang Huan-B18965 2013-08-05 10:06 ` Sascha Hauer 2013-08-05 10:06 ` Sascha Hauer 2013-08-06 3:42 ` Wang Huan-B18965 2013-08-06 3:42 ` Wang Huan-B18965 2013-08-05 13:09 ` Robert Schwebel 2013-08-05 13:09 ` Robert Schwebel 2013-08-05 14:18 ` Lucas Stach 2013-08-05 14:18 ` Lucas Stach 2013-08-06 7:20 ` Wang Huan-B18965 2013-08-06 7:20 ` Wang Huan-B18965 2014-01-06 18:50 ` Bill Pringlemeir 2014-01-07 9:18 ` Lucas Stach 2014-01-07 20:52 ` Bill Pringlemeir 2014-01-07 21:00 ` Bill Pringlemeir 2013-08-06 8:47 ` Lucas Stach 2013-08-06 8:47 ` Lucas Stach 2013-08-07 8:07 ` Wang Huan-B18965 2013-08-07 8:07 ` Wang Huan-B18965 2013-07-12 6:07 ` [PATCH 5/5] Documentation: DT: Add DCU framebuffer driver Alison Wang 2013-07-12 6:07 ` Alison Wang 2013-07-19 3:49 ` [PATCH v2 0/5] ARM: vf610: Add DCU framebuffer driver for Vybrid VF610 platform Wang Huan-B18965 2013-07-19 3:49 ` Wang Huan-B18965 2013-07-29 6:13 ` Wang Huan-B18965 2013-07-29 6:13 ` Wang Huan-B18965
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.