[RFC PATCH 0/3] amba-clcd: add device tree support

STALE5073d

8 messages, 4 authors, 2012-10-10 · open the first message on its own page

[RFC PATCH 0/3] amba-clcd: add device tree support

From: Ryan Harkin <hidden>
Date: 2012-09-19 16:04:23

Hi all,

The first patch adds device tree support to the amba-clcd video driver.

The next two modify the Versatile Express platform to use device tree for CLCD.

I've tested this code on Versatile Express A5, A9, A15-TC1, A15-A7-TC2 Core
Tiles and on RTSM.

I'd appreciate it if users of this driver and vexpress could please review
these patches and provide feedback.  I'd like to get them into shape so that
I can upstream in a format suitable for all users of the driver.

Regards,
Ryan.

Ryan Harkin (3):
  amba-clcd: Add Device Tree support to amba-clcd driver
  ARM: vexpress: Add device tree support for CLCD driver
  ARM: vexpress: configure CLCD driver device tree support for A9
    CoreTile

 arch/arm/boot/dts/clcd-panels.dtsi      |   52 +++++++
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |    8 +-
 arch/arm/boot/dts/vexpress-v2m.dtsi     |    8 +-
 arch/arm/boot/dts/vexpress-v2p-ca9.dts  |    6 +
 arch/arm/mach-vexpress/v2m.c            |   58 +++++++
 drivers/video/amba-clcd.c               |  253 +++++++++++++++++++++++++++++++
 6 files changed, 373 insertions(+), 12 deletions(-)
 create mode 100644 arch/arm/boot/dts/clcd-panels.dtsi

-- 
1.7.9.5

[RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver

From: Ryan Harkin <hidden>
Date: 2012-09-19 16:04:24

Add support to parse the display configuration from device tree.

If the board does not provide platform specific functions in the struct
clcd_board contained with the amba device info, then defaults are provided
by the driver.

The device tree configuration can either ask for a DMA setup or provide a
framebuffer address to be remapped into the driver.

Signed-off-by: Ryan Harkin <redacted>
---
 drivers/video/amba-clcd.c |  253 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 253 insertions(+)
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0a2cce7..01dbad1 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -16,7 +16,10 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
+#include <linux/of.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -391,6 +394,19 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
 	}
 	return 0;
 }
+int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+	return dma_mmap_writecombine(&fb->dev->dev, vma,
+				     fb->fb.screen_base,
+				     fb->fb.fix.smem_start,
+				     fb->fb.fix.smem_len);
+}
+
+void clcdfb_remove_dma(struct clcd_fb *fb)
+{
+	dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+			      fb->fb.screen_base, fb->fb.fix.smem_start);
+}
 
 static int clcdfb_mmap(struct fb_info *info,
 		       struct vm_area_struct *vma)
@@ -542,12 +558,249 @@ static int clcdfb_register(struct clcd_fb *fb)
 	return ret;
 }
 
+struct string_lookup {
+	const char *string;
+	const u32	val;
+};
+
+static struct string_lookup vmode_lookups[] = {
+	{ "FB_VMODE_NONINTERLACED", FB_VMODE_NONINTERLACED},
+	{ "FB_VMODE_INTERLACED",    FB_VMODE_INTERLACED},
+	{ "FB_VMODE_DOUBLE",        FB_VMODE_DOUBLE},
+	{ "FB_VMODE_ODD_FLD_FIRST", FB_VMODE_ODD_FLD_FIRST},
+	{ NULL, 0 },
+};
+
+static struct string_lookup tim2_lookups[] = {
+	{ "TIM2_CLKSEL", TIM2_CLKSEL},
+	{ "TIM2_IVS",    TIM2_IVS},
+	{ "TIM2_IHS",    TIM2_IHS},
+	{ "TIM2_IPC",    TIM2_IPC},
+	{ "TIM2_IOE",    TIM2_IOE},
+	{ "TIM2_BCD",    TIM2_BCD},
+	{ NULL, 0},
+};
+static struct string_lookup cntl_lookups[] = {
+	{"CNTL_LCDEN",        CNTL_LCDEN},
+	{"CNTL_LCDBPP1",      CNTL_LCDBPP1},
+	{"CNTL_LCDBPP2",      CNTL_LCDBPP2},
+	{"CNTL_LCDBPP4",      CNTL_LCDBPP4},
+	{"CNTL_LCDBPP8",      CNTL_LCDBPP8},
+	{"CNTL_LCDBPP16",     CNTL_LCDBPP16},
+	{"CNTL_LCDBPP16_565", CNTL_LCDBPP16_565},
+	{"CNTL_LCDBPP16_444", CNTL_LCDBPP16_444},
+	{"CNTL_LCDBPP24",     CNTL_LCDBPP24},
+	{"CNTL_LCDBW",        CNTL_LCDBW},
+	{"CNTL_LCDTFT",       CNTL_LCDTFT},
+	{"CNTL_LCDMONO8",     CNTL_LCDMONO8},
+	{"CNTL_LCDDUAL",      CNTL_LCDDUAL},
+	{"CNTL_BGR",          CNTL_BGR},
+	{"CNTL_BEBO",         CNTL_BEBO},
+	{"CNTL_BEPO",         CNTL_BEPO},
+	{"CNTL_LCDPWR",       CNTL_LCDPWR},
+	{"CNTL_LCDVCOMP(1)",  CNTL_LCDVCOMP(1)},
+	{"CNTL_LCDVCOMP(2)",  CNTL_LCDVCOMP(2)},
+	{"CNTL_LCDVCOMP(3)",  CNTL_LCDVCOMP(3)},
+	{"CNTL_LCDVCOMP(4)",  CNTL_LCDVCOMP(4)},
+	{"CNTL_LCDVCOMP(5)",  CNTL_LCDVCOMP(5)},
+	{"CNTL_LCDVCOMP(6)",  CNTL_LCDVCOMP(6)},
+	{"CNTL_LCDVCOMP(7)",  CNTL_LCDVCOMP(7)},
+	{"CNTL_LDMAFIFOTIME", CNTL_LDMAFIFOTIME},
+	{"CNTL_WATERMARK",    CNTL_WATERMARK},
+	{ NULL, 0},
+};
+static struct string_lookup caps_lookups[] = {
+	{"CLCD_CAP_RGB444",  CLCD_CAP_RGB444},
+	{"CLCD_CAP_RGB5551", CLCD_CAP_RGB5551},
+	{"CLCD_CAP_RGB565",  CLCD_CAP_RGB565},
+	{"CLCD_CAP_RGB888",  CLCD_CAP_RGB888},
+	{"CLCD_CAP_BGR444",  CLCD_CAP_BGR444},
+	{"CLCD_CAP_BGR5551", CLCD_CAP_BGR5551},
+	{"CLCD_CAP_BGR565",  CLCD_CAP_BGR565},
+	{"CLCD_CAP_BGR888",  CLCD_CAP_BGR888},
+	{"CLCD_CAP_444",     CLCD_CAP_444},
+	{"CLCD_CAP_5551",    CLCD_CAP_5551},
+	{"CLCD_CAP_565",     CLCD_CAP_565},
+	{"CLCD_CAP_888",     CLCD_CAP_888},
+	{"CLCD_CAP_RGB",     CLCD_CAP_RGB},
+	{"CLCD_CAP_BGR",     CLCD_CAP_BGR},
+	{"CLCD_CAP_ALL",     CLCD_CAP_ALL},
+	{ NULL, 0},
+};
+
+u32 parse_setting(struct string_lookup *lookup, const char *name)
+{
+	int i = 0;
+	while (lookup[i].string != NULL) {
+		if (strcmp(lookup[i].string, name) = 0)
+			return lookup[i].val;
+		++i;
+	}
+	return -EINVAL;
+}
+
+u32 get_string_lookup(struct device_node *node, const char *name,
+		      struct string_lookup *lookup)
+{
+	const char *string;
+	int count, i, ret = 0;
+
+	count = of_property_count_strings(node, name);
+	if (count >= 0)
+		for (i = 0; i < count; i++)
+			if (of_property_read_string_index(node, name, i,
+					&string) = 0)
+				ret |= parse_setting(lookup, string);
+	return ret;
+}
+
+int get_val(struct device_node *node, const char *string)
+{
+	u32 ret = 0;
+
+	if (of_property_read_u32(node, string, &ret))
+		ret = -1;
+	return ret;
+}
+
+struct clcd_panel *getPanel(struct device_node *node)
+{
+	static struct clcd_panel panel;
+
+	panel.mode.refresh      = get_val(node, "refresh");
+	panel.mode.xres         = get_val(node, "xres");
+	panel.mode.yres         = get_val(node, "yres");
+	panel.mode.pixclock     = get_val(node, "pixclock");
+	panel.mode.left_margin  = get_val(node, "left_margin");
+	panel.mode.right_margin = get_val(node, "right_margin");
+	panel.mode.upper_margin = get_val(node, "upper_margin");
+	panel.mode.lower_margin = get_val(node, "lower_margin");
+	panel.mode.hsync_len    = get_val(node, "hsync_len");
+	panel.mode.vsync_len    = get_val(node, "vsync_len");
+	panel.mode.sync         = get_val(node, "sync");
+	panel.bpp               = get_val(node, "bpp");
+	panel.width             = (signed short) get_val(node, "width");
+	panel.height            = (signed short) get_val(node, "height");
+
+	panel.mode.vmode = get_string_lookup(node, "vmode", vmode_lookups);
+	panel.tim2       = get_string_lookup(node, "tim2",  tim2_lookups);
+	panel.cntl       = get_string_lookup(node, "cntl",  cntl_lookups);
+	panel.caps       = get_string_lookup(node, "caps",  caps_lookups);
+
+	return &panel;
+}
+
+struct clcd_panel *clcdfb_get_panel(const char *name)
+{
+	struct device_node *node = NULL;
+	const char *mode;
+	struct clcd_panel *panel = NULL;
+
+	do {
+		node = of_find_compatible_node(node, NULL, "panel");
+		if (node)
+			if (of_property_read_string(node, "mode", &mode) = 0)
+				if (strcmp(mode, name) = 0) {
+					panel = getPanel(node);
+					panel->mode.name = name;
+				}
+	} while (node != NULL);
+
+	return panel;
+}
+
+#ifdef CONFIG_OF
+static int clcdfb_dt_init(struct clcd_fb *fb)
+{
+	int err = 0;
+	struct device_node *node;
+	const char *mode;
+	dma_addr_t dma;
+	u32 use_dma;
+	const __be32 *prop;
+	int len, na, ns;
+	phys_addr_t fb_base, fb_size;
+
+	node = fb->dev->dev.of_node;
+	if (!node)
+		return -ENODEV;
+
+	na = of_n_addr_cells(node);
+	ns = of_n_size_cells(node);
+
+	if (WARN_ON(of_property_read_string(node, "mode", &mode)))
+		return -ENODEV;
+
+	fb->panel = clcdfb_get_panel(mode);
+	if (!fb->panel)
+		return -EINVAL;
+	fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 2;
+
+	if (of_property_read_u32(node, "use_dma", &use_dma))
+		use_dma = 0;
+	if (use_dma) {
+		fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+			fb->fb.fix.smem_len, &dma, GFP_KERNEL);
+		if (!fb->fb.screen_base) {
+			pr_err("CLCD: unable to map framebuffer\n");
+			err = -ENOMEM;
+		} else
+			fb->fb.fix.smem_start	= dma;
+	} else {
+		prop = of_get_property(node, "framebuffer", &len);
+		if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+			return -EINVAL;
+		fb_base = of_read_number(prop, na);
+		fb_size = of_read_number(prop + na, ns);
+
+		if (memblock_remove(fb_base, fb_size) != 0)
+			return -EINVAL;
+
+		fb->fb.fix.smem_start = fb_base;
+		fb->fb.screen_base = ioremap_wc(fb->fb.fix.smem_start, fb_size);
+	}
+	return err;
+}
+#endif /* CONFIG_OF */
+
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
 	struct clcd_board *board = dev->dev.platform_data;
 	struct clcd_fb *fb;
 	int ret;
 
+#ifdef CONFIG_OF
+	if (dev->dev.of_node) {
+		const __be32 *prop;
+		int len, na, ns;
+		phys_addr_t reg_base;
+
+		na = of_n_addr_cells(dev->dev.of_node);
+		ns = of_n_size_cells(dev->dev.of_node);
+
+		prop = of_get_property(dev->dev.of_node, "reg", &len);
+		if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+			return -EINVAL;
+		reg_base = of_read_number(prop, na);
+
+		if (dev->res.start != reg_base)
+			return -EINVAL;
+
+		if (!board) {
+			board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
+			if (!board)
+				return -EINVAL;
+			board->name    = "Device Tree CLCD PL111";
+			board->caps    = CLCD_CAP_5551 | CLCD_CAP_565;
+			board->check   = clcdfb_check;
+			board->decode  = clcdfb_decode;
+			board->setup   = clcdfb_dt_init;
+			board->mmap    = clcdfb_mmap_dma;
+			board->remove  = clcdfb_remove_dma;
+		}
+	}
+#endif /* CONFIG_OF */
+
 	if (!board)
 		return -EINVAL;
 
-- 
1.7.9.5

[RFC PATCH 2/3] ARM: vexpress: Add device tree support for CLCD driver

From: Ryan Harkin <hidden>
Date: 2012-09-19 16:04:25

Add support for device tree in the amba-clcd PL111 video driver.

Special case support is added for the A9 CoreTile which uses the "legacy"
address map and has a PL111 device on-board.  The default case is to configure
the device on the motherboard.

Oscillator support is added for the A9 CoreTile's CLCD driver.

Signed-off-by: Ryan Harkin <redacted>
---
 arch/arm/mach-vexpress/v2m.c |   58 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 37608f2..799e00e 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -3,6 +3,7 @@
  */
 #include <linux/device.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
 #include <linux/amba/mmci.h>
 #include <linux/io.h>
 #include <linux/init.h>
@@ -37,6 +38,7 @@
 #include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
 
+#include <plat/clcd.h>
 #include <plat/sched_clock.h>
 
 #include "core.h"
@@ -541,6 +543,54 @@ MACHINE_END
 
 #if defined(CONFIG_ARCH_VEXPRESS_DT)
 
+static struct v2m_osc v2m_dt_clcd_osc = {
+	.rate_min = 10000000,
+	.rate_max = 165000000,
+	.rate_default = 23750000,
+};
+
+static int v2m_dt_clcd_init(void)
+{
+	struct device_node *node;
+	u32 osc;
+	u32 clcd_site;
+	u32 dvimode;
+	const __be32 *prop;
+	int len, na, ns;
+	phys_addr_t reg_base;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,pl111");
+	if (!node)
+		return -ENODEV;
+
+	na = of_n_addr_cells(node);
+	ns = of_n_size_cells(node);
+
+	prop = of_get_property(node, "reg", &len);
+	if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+		return -EINVAL;
+	reg_base = of_read_number(prop, na);
+
+	switch (reg_base) {
+	case CT_CA9X4_CLCDC:
+		clcd_site = v2m_get_master_site();
+		dvimode = 2;
+		break;
+	default:
+		clcd_site = SYS_CFG_SITE_MB;
+		dvimode = 0;
+		break;
+	}
+
+	if (of_property_read_u32(node, "arm,vexpress-osc", &osc) != 0)
+		return -EINVAL;
+	v2m_dt_clcd_osc.site = clcd_site;
+	v2m_dt_clcd_osc.osc = osc;
+	v2m_cfg_write(SYS_CFG_MUXFPGA | clcd_site, clcd_site);
+	v2m_cfg_write(SYS_CFG_DVIMODE | clcd_site, dvimode);
+	return 0;
+}
+
 static struct map_desc v2m_rs1_io_desc __initdata = {
 	.virtual	= V2M_PERIPH,
 	.pfn		= __phys_to_pfn(0x1c000000),
@@ -598,6 +648,8 @@ void __init v2m_dt_init_early(void)
 			pr_warning("vexpress: DT HBI (%x) is not matching "
 					"hardware (%x)!\n", dt_hbi, hbi);
 	}
+
+	v2m_dt_clcd_init();
 }
 
 static  struct of_device_id vexpress_irq_match[] __initdata = {
@@ -631,6 +683,12 @@ static void __init v2m_dt_timer_init(void)
 
 	if (arch_timer_sched_clock_init() != 0)
 		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+
+	if (v2m_dt_clcd_osc.site) {
+		/* core tile clcd controller for A9 */
+		clk = v2m_osc_register("10020000.clcd", &v2m_dt_clcd_osc);
+		clk_register_clkdev(clk, NULL, "10020000.clcd");
+	}
 }
 
 static struct sys_timer v2m_dt_timer = {
-- 
1.7.9.5

[RFC PATCH 3/3] ARM: vexpress: configure CLCD driver device tree support for A9 CoreTile

From: Ryan Harkin <hidden>
Date: 2012-09-19 16:04:26

Configuration for the amba-clcd PL111 driver is added to the A9 CoreTile's DTS
file.

Configuration of the motherboard CLCD driver is removed from the DTSI files to
prevent duplicate CLCD drivers being registered.

A generic set of CLCD panel descriptions has been split into its own DTSI file.
Currently, only XVGA and VGA monitors are described.

Signed-off-by: Ryan Harkin <redacted>
---
 arch/arm/boot/dts/clcd-panels.dtsi      |   52 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |    8 ++---
 arch/arm/boot/dts/vexpress-v2m.dtsi     |    8 ++---
 arch/arm/boot/dts/vexpress-v2p-ca9.dts  |    6 ++++
 4 files changed, 62 insertions(+), 12 deletions(-)
diff --git a/arch/arm/boot/dts/clcd-panels.dtsi b/arch/arm/boot/dts/clcd-panels.dtsi
new file mode 100644
index 0000000..0b0ff6e
--- /dev/null
+++ b/arch/arm/boot/dts/clcd-panels.dtsi
@@ -0,0 +1,52 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ */
+
+/ {
+	panels {
+		panel@0 {
+			compatible	= "panel";
+			mode		= "VGA";
+			refresh		= <60>;
+			xres		= <640>;
+			yres		= <480>;
+			pixclock	= <39721>;
+			left_margin	= <40>;
+			right_margin	= <24>;
+			upper_margin	= <32>;
+			lower_margin	= <11>;
+			hsync_len	= <96>;
+			vsync_len	= <2>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+
+		panel@1 {
+			compatible	= "panel";
+			mode		= "XVGA";
+			refresh		= <60>;
+			xres		= <1024>;
+			yres		= <768>;
+			pixclock	= <15748>;
+			left_margin	= <152>;
+			right_margin	= <48>;
+			upper_margin	= <23>;
+			lower_margin	= <3>;
+			hsync_len	= <104>;
+			vsync_len	= <4>;
+			sync		= <0>;
+			vmode		= "FB_VMODE_NONINTERLACED";
+
+			tim2		= "TIM2_BCD", "TIM2_IPC";
+			cntl		= "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+			caps		= "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+			bpp		= <16>;
+		};
+	};
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index d8a827b..301d3f6 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -17,6 +17,8 @@
  * CHANGES TO vexpress-v2m.dtsi!
  */
 
+/include/ "clcd-panels.dtsi"
+
 / {
 	aliases {
 		arm,v2m_timer = &v2m_timer01;
@@ -193,12 +195,6 @@
 				       0x1a0100 0xf00>;
 				reg-shift = <2>;
 			};
-
-			clcd@1f0000 {
-				compatible = "arm,pl111", "arm,primecell";
-				reg = <0x1f0000 0x1000>;
-				interrupts = <14>;
-			};
 		};
 
 		v2m_fixed_3v3: fixedregulator@0 {
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index dba53fd..43cd86f 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -17,6 +17,8 @@
  * CHANGES TO vexpress-v2m-rs1.dtsi!
  */
 
+/include/ "clcd-panels.dtsi"
+
 / {
 	aliases {
 		arm,v2m_timer = &v2m_timer01;
@@ -192,12 +194,6 @@
 				       0x1a100 0xf00>;
 				reg-shift = <2>;
 			};
-
-			clcd@1f000 {
-				compatible = "arm,pl111", "arm,primecell";
-				reg = <0x1f000 0x1000>;
-				interrupts = <14>;
-			};
 		};
 
 		v2m_fixed_3v3: fixedregulator@0 {
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 3f0c736..2ebb132 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -9,6 +9,8 @@
 
 /dts-v1/;
 
+/memreserve/ 0x9f000000 0x01000000;
+
 / {
 	model = "V2P-CA9";
 	arm,hbi = <0x191>;
@@ -70,6 +72,10 @@
 		compatible = "arm,pl111", "arm,primecell";
 		reg = <0x10020000 0x1000>;
 		interrupts = <0 44 4>;
+		mode = "XVGA";
+		arm,vexpress-osc = <1>;
+		use_dma = <1>;
+		framebuffer = <0x9f000000 0x01000000>;
 	};
 
 	memory-controller@100e0000 {
-- 
1.7.9.5

Re: [RFC PATCH 2/3] ARM: vexpress: Add device tree support for CLCD driver

From: Pawel Moll <hidden>
Date: 2012-09-19 16:11:33

On Wed, 2012-09-19 at 17:04 +0100, Ryan Harkin wrote:
quoted hunk
Add support for device tree in the amba-clcd PL111 video driver.

Special case support is added for the A9 CoreTile which uses the "legacy"
address map and has a PL111 device on-board.  The default case is to configure
the device on the motherboard.

Oscillator support is added for the A9 CoreTile's CLCD driver.

Signed-off-by: Ryan Harkin <redacted>
---
 arch/arm/mach-vexpress/v2m.c |   58 ++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 37608f2..799e00e 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -3,6 +3,7 @@
  */
 #include <linux/device.h>
 #include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
 #include <linux/amba/mmci.h>
 #include <linux/io.h>
 #include <linux/init.h>
@@ -37,6 +38,7 @@
 #include <mach/ct-ca9x4.h>
 #include <mach/motherboard.h>
 
+#include <plat/clcd.h>
 #include <plat/sched_clock.h>
 
 #include "core.h"
@@ -541,6 +543,54 @@ MACHINE_END
 
 #if defined(CONFIG_ARCH_VEXPRESS_DT)
 
+static struct v2m_osc v2m_dt_clcd_osc = {
+	.rate_min = 10000000,
+	.rate_max = 165000000,
+	.rate_default = 23750000,
+};
+
+static int v2m_dt_clcd_init(void)
+{
+	struct device_node *node;
+	u32 osc;
+	u32 clcd_site;
+	u32 dvimode;
+	const __be32 *prop;
+	int len, na, ns;
+	phys_addr_t reg_base;
+
+	node = of_find_compatible_node(NULL, NULL, "arm,pl111");
+	if (!node)
+		return -ENODEV;
+
+	na = of_n_addr_cells(node);
+	ns = of_n_size_cells(node);
+
+	prop = of_get_property(node, "reg", &len);
+	if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+		return -EINVAL;
+	reg_base = of_read_number(prop, na);
+
+	switch (reg_base) {
+	case CT_CA9X4_CLCDC:
+		clcd_site = v2m_get_master_site();
+		dvimode = 2;
+		break;
+	default:
+		clcd_site = SYS_CFG_SITE_MB;
+		dvimode = 0;
+		break;
+	}
+
+	if (of_property_read_u32(node, "arm,vexpress-osc", &osc) != 0)
+		return -EINVAL;
+	v2m_dt_clcd_osc.site = clcd_site;
+	v2m_dt_clcd_osc.osc = osc;
+	v2m_cfg_write(SYS_CFG_MUXFPGA | clcd_site, clcd_site);
+	v2m_cfg_write(SYS_CFG_DVIMODE | clcd_site, dvimode);
+	return 0;
+}
+
 static struct map_desc v2m_rs1_io_desc __initdata = {
 	.virtual	= V2M_PERIPH,
 	.pfn		= __phys_to_pfn(0x1c000000),
@@ -598,6 +648,8 @@ void __init v2m_dt_init_early(void)
 			pr_warning("vexpress: DT HBI (%x) is not matching "
 					"hardware (%x)!\n", dt_hbi, hbi);
 	}
+
+	v2m_dt_clcd_init();
 }
 
 static  struct of_device_id vexpress_irq_match[] __initdata = {
@@ -631,6 +683,12 @@ static void __init v2m_dt_timer_init(void)
 
 	if (arch_timer_sched_clock_init() != 0)
 		versatile_sched_clock_init(v2m_sysreg_base + V2M_SYS_24MHZ, 24000000);
+
+	if (v2m_dt_clcd_osc.site) {
+		/* core tile clcd controller for A9 */
+		clk = v2m_osc_register("10020000.clcd", &v2m_dt_clcd_osc);
+		clk_register_clkdev(clk, NULL, "10020000.clcd");
+	}
 }
 
 static struct sys_timer v2m_dt_timer = {
When (if ;-) the changes I proposed recently make their way into
mainline, all this stuff will not be necessary - both clocking and
display control are sorted there.

Pawel

Re: [RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver

From: Liviu Dudau <Liviu.Dudau@arm.com>
Date: 2012-09-20 10:24:53

On Wed, Sep 19, 2012 at 05:04:24PM +0100, Ryan Harkin wrote:
quoted hunk
Add support to parse the display configuration from device tree.

If the board does not provide platform specific functions in the struct
clcd_board contained with the amba device info, then defaults are provided
by the driver.

The device tree configuration can either ask for a DMA setup or provide a
framebuffer address to be remapped into the driver.

Signed-off-by: Ryan Harkin <redacted>
---
 drivers/video/amba-clcd.c |  253 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 253 insertions(+)
diff --git a/drivers/video/amba-clcd.c b/drivers/video/amba-clcd.c
index 0a2cce7..01dbad1 100644
--- a/drivers/video/amba-clcd.c
+++ b/drivers/video/amba-clcd.c
@@ -16,7 +16,10 @@
 #include <linux/string.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/memblock.h>
 #include <linux/mm.h>
+#include <linux/of.h>
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/ioport.h>
@@ -391,6 +394,19 @@ static int clcdfb_blank(int blank_mode, struct fb_info *info)
      }
      return 0;
 }
+int clcdfb_mmap_dma(struct clcd_fb *fb, struct vm_area_struct *vma)
+{
+     return dma_mmap_writecombine(&fb->dev->dev, vma,
+                                  fb->fb.screen_base,
+                                  fb->fb.fix.smem_start,
+                                  fb->fb.fix.smem_len);
+}
+
+void clcdfb_remove_dma(struct clcd_fb *fb)
+{
+     dma_free_writecombine(&fb->dev->dev, fb->fb.fix.smem_len,
+                           fb->fb.screen_base, fb->fb.fix.smem_start);
+}

 static int clcdfb_mmap(struct fb_info *info,
                     struct vm_area_struct *vma)
@@ -542,12 +558,249 @@ static int clcdfb_register(struct clcd_fb *fb)
      return ret;
 }

+struct string_lookup {
+     const char *string;
+     const u32       val;
+};
+
+static struct string_lookup vmode_lookups[] = {
+     { "FB_VMODE_NONINTERLACED", FB_VMODE_NONINTERLACED},
+     { "FB_VMODE_INTERLACED",    FB_VMODE_INTERLACED},
+     { "FB_VMODE_DOUBLE",        FB_VMODE_DOUBLE},
+     { "FB_VMODE_ODD_FLD_FIRST", FB_VMODE_ODD_FLD_FIRST},
+     { NULL, 0 },
+};
+
+static struct string_lookup tim2_lookups[] = {
+     { "TIM2_CLKSEL", TIM2_CLKSEL},
+     { "TIM2_IVS",    TIM2_IVS},
+     { "TIM2_IHS",    TIM2_IHS},
+     { "TIM2_IPC",    TIM2_IPC},
+     { "TIM2_IOE",    TIM2_IOE},
+     { "TIM2_BCD",    TIM2_BCD},
+     { NULL, 0},
+};
+static struct string_lookup cntl_lookups[] = {
+     {"CNTL_LCDEN",        CNTL_LCDEN},
+     {"CNTL_LCDBPP1",      CNTL_LCDBPP1},
+     {"CNTL_LCDBPP2",      CNTL_LCDBPP2},
+     {"CNTL_LCDBPP4",      CNTL_LCDBPP4},
+     {"CNTL_LCDBPP8",      CNTL_LCDBPP8},
+     {"CNTL_LCDBPP16",     CNTL_LCDBPP16},
+     {"CNTL_LCDBPP16_565", CNTL_LCDBPP16_565},
+     {"CNTL_LCDBPP16_444", CNTL_LCDBPP16_444},
+     {"CNTL_LCDBPP24",     CNTL_LCDBPP24},
+     {"CNTL_LCDBW",        CNTL_LCDBW},
+     {"CNTL_LCDTFT",       CNTL_LCDTFT},
+     {"CNTL_LCDMONO8",     CNTL_LCDMONO8},
+     {"CNTL_LCDDUAL",      CNTL_LCDDUAL},
+     {"CNTL_BGR",          CNTL_BGR},
+     {"CNTL_BEBO",         CNTL_BEBO},
+     {"CNTL_BEPO",         CNTL_BEPO},
+     {"CNTL_LCDPWR",       CNTL_LCDPWR},
+     {"CNTL_LCDVCOMP(1)",  CNTL_LCDVCOMP(1)},
+     {"CNTL_LCDVCOMP(2)",  CNTL_LCDVCOMP(2)},
+     {"CNTL_LCDVCOMP(3)",  CNTL_LCDVCOMP(3)},
+     {"CNTL_LCDVCOMP(4)",  CNTL_LCDVCOMP(4)},
+     {"CNTL_LCDVCOMP(5)",  CNTL_LCDVCOMP(5)},
+     {"CNTL_LCDVCOMP(6)",  CNTL_LCDVCOMP(6)},
+     {"CNTL_LCDVCOMP(7)",  CNTL_LCDVCOMP(7)},
+     {"CNTL_LDMAFIFOTIME", CNTL_LDMAFIFOTIME},
+     {"CNTL_WATERMARK",    CNTL_WATERMARK},
+     { NULL, 0},
+};
+static struct string_lookup caps_lookups[] = {
+     {"CLCD_CAP_RGB444",  CLCD_CAP_RGB444},
+     {"CLCD_CAP_RGB5551", CLCD_CAP_RGB5551},
+     {"CLCD_CAP_RGB565",  CLCD_CAP_RGB565},
+     {"CLCD_CAP_RGB888",  CLCD_CAP_RGB888},
+     {"CLCD_CAP_BGR444",  CLCD_CAP_BGR444},
+     {"CLCD_CAP_BGR5551", CLCD_CAP_BGR5551},
+     {"CLCD_CAP_BGR565",  CLCD_CAP_BGR565},
+     {"CLCD_CAP_BGR888",  CLCD_CAP_BGR888},
+     {"CLCD_CAP_444",     CLCD_CAP_444},
+     {"CLCD_CAP_5551",    CLCD_CAP_5551},
+     {"CLCD_CAP_565",     CLCD_CAP_565},
+     {"CLCD_CAP_888",     CLCD_CAP_888},
+     {"CLCD_CAP_RGB",     CLCD_CAP_RGB},
+     {"CLCD_CAP_BGR",     CLCD_CAP_BGR},
+     {"CLCD_CAP_ALL",     CLCD_CAP_ALL},
+     { NULL, 0},
+};
+
+u32 parse_setting(struct string_lookup *lookup, const char *name)
+{
+     int i = 0;
+     while (lookup[i].string != NULL) {
+             if (strcmp(lookup[i].string, name) = 0)
+                     return lookup[i].val;
+             ++i;
+     }
+     return -EINVAL;
+}
+
+u32 get_string_lookup(struct device_node *node, const char *name,
+                   struct string_lookup *lookup)
+{
I have this feeling that swapping the names of the two functions above
would reflect better their actual functionality.
+     const char *string;
+     int count, i, ret = 0;
+
+     count = of_property_count_strings(node, name);
+     if (count >= 0)
+             for (i = 0; i < count; i++)
+                     if (of_property_read_string_index(node, name, i,
+                                     &string) = 0)
+                             ret |= parse_setting(lookup, string);
+     return ret;
+}
+
+int get_val(struct device_node *node, const char *string)
+{
+     u32 ret = 0;
+
+     if (of_property_read_u32(node, string, &ret))
+             ret = -1;
+     return ret;
+}
+
+struct clcd_panel *getPanel(struct device_node *node)
+{
+     static struct clcd_panel panel;
+
+     panel.mode.refresh      = get_val(node, "refresh");
+     panel.mode.xres         = get_val(node, "xres");
+     panel.mode.yres         = get_val(node, "yres");
+     panel.mode.pixclock     = get_val(node, "pixclock");
+     panel.mode.left_margin  = get_val(node, "left_margin");
+     panel.mode.right_margin = get_val(node, "right_margin");
+     panel.mode.upper_margin = get_val(node, "upper_margin");
+     panel.mode.lower_margin = get_val(node, "lower_margin");
+     panel.mode.hsync_len    = get_val(node, "hsync_len");
+     panel.mode.vsync_len    = get_val(node, "vsync_len");
+     panel.mode.sync         = get_val(node, "sync");
+     panel.bpp               = get_val(node, "bpp");
+     panel.width             = (signed short) get_val(node, "width");
+     panel.height            = (signed short) get_val(node, "height");
+
+     panel.mode.vmode = get_string_lookup(node, "vmode", vmode_lookups);
+     panel.tim2       = get_string_lookup(node, "tim2",  tim2_lookups);
+     panel.cntl       = get_string_lookup(node, "cntl",  cntl_lookups);
+     panel.caps       = get_string_lookup(node, "caps",  caps_lookups);
+
+     return &panel;
+}
+
+struct clcd_panel *clcdfb_get_panel(const char *name)
+{
+     struct device_node *node = NULL;
+     const char *mode;
+     struct clcd_panel *panel = NULL;
+
+     do {
+             node = of_find_compatible_node(node, NULL, "panel");
+             if (node)
+                     if (of_property_read_string(node, "mode", &mode) = 0)
+                             if (strcmp(mode, name) = 0) {
+                                     panel = getPanel(node);
+                                     panel->mode.name = name;
+                             }
+     } while (node != NULL);
+
+     return panel;
+}
+
+#ifdef CONFIG_OF
shouldn't this #ifdef be earlier? you are calling of_property_read_string()
and while there are empty definitions if CONFIG_OF is not defined, the code
will do nothing in that case. Is that intended? The clcdfb_get_panel()
function only gets called if CONFIG_OF *is* defined.

+static int clcdfb_dt_init(struct clcd_fb *fb)
+{
+     int err = 0;
+     struct device_node *node;
+     const char *mode;
+     dma_addr_t dma;
+     u32 use_dma;
+     const __be32 *prop;
+     int len, na, ns;
+     phys_addr_t fb_base, fb_size;
+
+     node = fb->dev->dev.of_node;
+     if (!node)
+             return -ENODEV;
+
+     na = of_n_addr_cells(node);
+     ns = of_n_size_cells(node);
+
+     if (WARN_ON(of_property_read_string(node, "mode", &mode)))
+             return -ENODEV;
+
+     fb->panel = clcdfb_get_panel(mode);
+     if (!fb->panel)
+             return -EINVAL;
+     fb->fb.fix.smem_len = fb->panel->mode.xres * fb->panel->mode.yres * 2;
+
+     if (of_property_read_u32(node, "use_dma", &use_dma))
I haven't seen any documentation for this property. What's the intended use?
+             use_dma = 0;
+     if (use_dma) {
+             fb->fb.screen_base = dma_alloc_writecombine(&fb->dev->dev,
+                     fb->fb.fix.smem_len, &dma, GFP_KERNEL);
+             if (!fb->fb.screen_base) {
+                     pr_err("CLCD: unable to map framebuffer\n");
+                     err = -ENOMEM;
+             } else
+                     fb->fb.fix.smem_start   = dma;
+     } else {
+             prop = of_get_property(node, "framebuffer", &len);
+             if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+                     return -EINVAL;
+             fb_base = of_read_number(prop, na);
+             fb_size = of_read_number(prop + na, ns);
+
+             if (memblock_remove(fb_base, fb_size) != 0)
+                     return -EINVAL;
+
+             fb->fb.fix.smem_start = fb_base;
+             fb->fb.screen_base = ioremap_wc(fb->fb.fix.smem_start, fb_size);
+     }
+     return err;
+}
+#endif /* CONFIG_OF */
+
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
      struct clcd_board *board = dev->dev.platform_data;
      struct clcd_fb *fb;
      int ret;

+#ifdef CONFIG_OF
+     if (dev->dev.of_node) {
+             const __be32 *prop;
+             int len, na, ns;
+             phys_addr_t reg_base;
+
+             na = of_n_addr_cells(dev->dev.of_node);
+             ns = of_n_size_cells(dev->dev.of_node);
+
+             prop = of_get_property(dev->dev.of_node, "reg", &len);
+             if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+                     return -EINVAL;
+             reg_base = of_read_number(prop, na);
+
+             if (dev->res.start != reg_base)
+                     return -EINVAL;
+
+             if (!board) {
+                     board = kzalloc(sizeof(struct clcd_board), GFP_KERNEL);
+                     if (!board)
+                             return -EINVAL;
+                     board->name    = "Device Tree CLCD PL111";
+                     board->caps    = CLCD_CAP_5551 | CLCD_CAP_565;
+                     board->check   = clcdfb_check;
+                     board->decode  = clcdfb_decode;
+                     board->setup   = clcdfb_dt_init;
+                     board->mmap    = clcdfb_mmap_dma;
+                     board->remove  = clcdfb_remove_dma;
+             }
+     }
+#endif /* CONFIG_OF */
+
      if (!board)
              return -EINVAL;

--
1.7.9.5
--
==========
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium.  Thank you.

Re: [RFC PATCH 3/3] ARM: vexpress: configure CLCD driver device tree support for A9 CoreTile

From: Liviu Dudau <Liviu.Dudau@arm.com>
Date: 2012-09-20 10:29:44

On Wed, Sep 19, 2012 at 05:04:26PM +0100, Ryan Harkin wrote:
Configuration for the amba-clcd PL111 driver is added to the A9 CoreTile's DTS
file.

Configuration of the motherboard CLCD driver is removed from the DTSI files to
prevent duplicate CLCD drivers being registered.

A generic set of CLCD panel descriptions has been split into its own DTSI file.
Currently, only XVGA and VGA monitors are described.
Hi Ryan,

For this and [2/3] patch:

Reviewed-by: Liviu Dudau <Liviu.Dudau@arm.com>

quoted hunk
Signed-off-by: Ryan Harkin <redacted>
---
 arch/arm/boot/dts/clcd-panels.dtsi      |   52 +++++++++++++++++++++++++++++++
 arch/arm/boot/dts/vexpress-v2m-rs1.dtsi |    8 ++---
 arch/arm/boot/dts/vexpress-v2m.dtsi     |    8 ++---
 arch/arm/boot/dts/vexpress-v2p-ca9.dts  |    6 ++++
 4 files changed, 62 insertions(+), 12 deletions(-)
diff --git a/arch/arm/boot/dts/clcd-panels.dtsi b/arch/arm/boot/dts/clcd-panels.dtsi
new file mode 100644
index 0000000..0b0ff6e
--- /dev/null
+++ b/arch/arm/boot/dts/clcd-panels.dtsi
@@ -0,0 +1,52 @@
+/*
+ * ARM Ltd. Versatile Express
+ *
+ */
+
+/ {
+     panels {
+             panel@0 {
+                     compatible      = "panel";
+                     mode            = "VGA";
+                     refresh         = <60>;
+                     xres            = <640>;
+                     yres            = <480>;
+                     pixclock        = <39721>;
+                     left_margin     = <40>;
+                     right_margin    = <24>;
+                     upper_margin    = <32>;
+                     lower_margin    = <11>;
+                     hsync_len       = <96>;
+                     vsync_len       = <2>;
+                     sync            = <0>;
+                     vmode           = "FB_VMODE_NONINTERLACED";
+
+                     tim2            = "TIM2_BCD", "TIM2_IPC";
+                     cntl            = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+                     caps            = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+                     bpp             = <16>;
+             };
+
+             panel@1 {
+                     compatible      = "panel";
+                     mode            = "XVGA";
+                     refresh         = <60>;
+                     xres            = <1024>;
+                     yres            = <768>;
+                     pixclock        = <15748>;
+                     left_margin     = <152>;
+                     right_margin    = <48>;
+                     upper_margin    = <23>;
+                     lower_margin    = <3>;
+                     hsync_len       = <104>;
+                     vsync_len       = <4>;
+                     sync            = <0>;
+                     vmode           = "FB_VMODE_NONINTERLACED";
+
+                     tim2            = "TIM2_BCD", "TIM2_IPC";
+                     cntl            = "CNTL_LCDTFT", "CNTL_BGR", "CNTL_LCDVCOMP(1)";
+                     caps            = "CLCD_CAP_5551", "CLCD_CAP_565", "CLCD_CAP_888";
+                     bpp             = <16>;
+             };
+     };
+};
diff --git a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
index d8a827b..301d3f6 100644
--- a/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m-rs1.dtsi
@@ -17,6 +17,8 @@
  * CHANGES TO vexpress-v2m.dtsi!
  */

+/include/ "clcd-panels.dtsi"
+
 / {
      aliases {
              arm,v2m_timer = &v2m_timer01;
@@ -193,12 +195,6 @@
                                     0x1a0100 0xf00>;
                              reg-shift = <2>;
                      };
-
-                     clcd@1f0000 {
-                             compatible = "arm,pl111", "arm,primecell";
-                             reg = <0x1f0000 0x1000>;
-                             interrupts = <14>;
-                     };
              };

              v2m_fixed_3v3: fixedregulator@0 {
diff --git a/arch/arm/boot/dts/vexpress-v2m.dtsi b/arch/arm/boot/dts/vexpress-v2m.dtsi
index dba53fd..43cd86f 100644
--- a/arch/arm/boot/dts/vexpress-v2m.dtsi
+++ b/arch/arm/boot/dts/vexpress-v2m.dtsi
@@ -17,6 +17,8 @@
  * CHANGES TO vexpress-v2m-rs1.dtsi!
  */

+/include/ "clcd-panels.dtsi"
+
 / {
      aliases {
              arm,v2m_timer = &v2m_timer01;
@@ -192,12 +194,6 @@
                                     0x1a100 0xf00>;
                              reg-shift = <2>;
                      };
-
-                     clcd@1f000 {
-                             compatible = "arm,pl111", "arm,primecell";
-                             reg = <0x1f000 0x1000>;
-                             interrupts = <14>;
-                     };
              };

              v2m_fixed_3v3: fixedregulator@0 {
diff --git a/arch/arm/boot/dts/vexpress-v2p-ca9.dts b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
index 3f0c736..2ebb132 100644
--- a/arch/arm/boot/dts/vexpress-v2p-ca9.dts
+++ b/arch/arm/boot/dts/vexpress-v2p-ca9.dts
@@ -9,6 +9,8 @@

 /dts-v1/;

+/memreserve/ 0x9f000000 0x01000000;
+
 / {
      model = "V2P-CA9";
      arm,hbi = <0x191>;
@@ -70,6 +72,10 @@
              compatible = "arm,pl111", "arm,primecell";
              reg = <0x10020000 0x1000>;
              interrupts = <0 44 4>;
+             mode = "XVGA";
+             arm,vexpress-osc = <1>;
+             use_dma = <1>;
+             framebuffer = <0x9f000000 0x01000000>;
      };

      memory-controller@100e0000 {
--
1.7.9.5
--
==========
| I would like to |
| fix the world,  |
| but they're not |
| giving me the   |
 \ source code!  /
  ---------------
    ¯\_(ツ)_/¯

-- IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium.  Thank you.

Re: [RFC PATCH 1/3] amba-clcd: Add Device Tree support to amba-clcd driver

From: Jon Medhurst (Tixy) <hidden>
Date: 2012-10-10 10:13:26

On Wed, 2012-09-19 at 17:04 +0100, Ryan Harkin wrote:
Add support to parse the display configuration from device tree.

If the board does not provide platform specific functions in the struct
clcd_board contained with the amba device info, then defaults are provided
by the driver.

The device tree configuration can either ask for a DMA setup or provide a
framebuffer address to be remapped into the driver.

Signed-off-by: Ryan Harkin <redacted>
---
<big snip>
 static int clcdfb_probe(struct amba_device *dev, const struct amba_id *id)
 {
 	struct clcd_board *board = dev->dev.platform_data;
 	struct clcd_fb *fb;
 	int ret;
 
+#ifdef CONFIG_OF
+	if (dev->dev.of_node) {
+		const __be32 *prop;
+		int len, na, ns;
+		phys_addr_t reg_base;
+
+		na = of_n_addr_cells(dev->dev.of_node);
+		ns = of_n_size_cells(dev->dev.of_node);
+
+		prop = of_get_property(dev->dev.of_node, "reg", &len);
+		if (WARN_ON(!prop || len < (na + ns) * sizeof(*prop)))
+			return -EINVAL;
+		reg_base = of_read_number(prop, na);
+
+		if (dev->res.start != reg_base)
+			return -EINVAL;
When the motherboard CLCD is used, the CLCD node is under the iofga node
and has a reg value equal to the offset from the start of the iofgpa,
however dev->res.start holds the calculated address of the start of the
iofga region plus the offset of the clcd, this means that the above
check fails.

The question is, what is the purpose of this check? Can't we rely on the
value of dev->res.start being consistent with dev->dev.of_node and so
just drop all the above code from "const __be32 *prop" onwards?

-- 
Tixy
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help