All of lore.kernel.org
 help / color / mirror / Atom feed
* [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

* [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

* 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  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 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 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

* 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 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

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.