[ARM] 3404/1: lpd7a40x: AMBA CLCD support

Patch from Marc Singer

Board support and LCD panel configurations to integrate lh7a40x's with
the amba clcd driver.

Signed-off-by: Marc Singer <elf@buici.com>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
diff --git a/arch/arm/mach-lh7a40x/clcd.c b/arch/arm/mach-lh7a40x/clcd.c
new file mode 100644
index 0000000..93751fe
--- /dev/null
+++ b/arch/arm/mach-lh7a40x/clcd.c
@@ -0,0 +1,241 @@
+/*
+ *  arch/arm/mach-lh7a40x/clcd.c
+ *
+ *  Copyright (C) 2004 Marc Singer
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License
+ *  version 2 as published by the Free Software Foundation.
+ *
+ */
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/sysdev.h>
+#include <linux/interrupt.h>
+
+//#include <linux/module.h>
+//#include <linux/time.h>
+//#include <asm/hardware.h>
+
+//#include <asm/mach/time.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+#include <asm/system.h>
+#include <asm/hardware.h>
+#include <linux/amba/bus.h>
+#include <linux/amba/clcd.h>
+
+#define HRTFTC_HRSETUP		__REG(HRTFTC_PHYS + 0x00)
+#define HRTFTC_HRCON		__REG(HRTFTC_PHYS + 0x04)
+#define HRTFTC_HRTIMING1	__REG(HRTFTC_PHYS + 0x08)
+#define HRTFTC_HRTIMING2	__REG(HRTFTC_PHYS + 0x0c)
+
+#define ALI_SETUP		__REG(ALI_PHYS + 0x00)
+#define ALI_CONTROL		__REG(ALI_PHYS + 0x04)
+#define ALI_TIMING1		__REG(ALI_PHYS + 0x08)
+#define ALI_TIMING2		__REG(ALI_PHYS + 0x0c)
+
+#include "lcd-panel.h"
+
+static void lh7a40x_clcd_disable (struct clcd_fb *fb)
+{
+#if defined (CONFIG_MACH_LPD7A400)
+	CPLD_CONTROL &= ~(1<<1);	/* Disable LCD Vee */
+#endif
+
+#if defined (CONFIG_MACH_LPD7A404)
+	GPIO_PCD  &= ~(1<<3);		/* Disable LCD Vee */
+#endif
+
+#if defined (CONFIG_ARCH_LH7A400)
+	HRTFTC_HRSETUP &= ~(1<<13);	/* Disable HRTFT controller */
+#endif
+
+#if defined (CONFIG_ARCH_LH7A404)
+	ALI_SETUP &= ~(1<<13);		/* Disable ALI */
+#endif
+}
+
+static void lh7a40x_clcd_enable (struct clcd_fb *fb)
+{
+	struct clcd_panel_extra* extra
+		= (struct clcd_panel_extra*) fb->board_data;
+
+#if defined (CONFIG_MACH_LPD7A400)
+	CPLD_CONTROL |= (1<<1);		/* Enable LCD Vee */
+#endif
+
+#if defined (CONFIG_MACH_LPD7A404)
+	GPIO_PCDD &= ~(1<<3);		/* Enable LCD Vee */
+	GPIO_PCD  |=  (1<<3);
+#endif
+
+#if defined (CONFIG_ARCH_LH7A400)
+
+	if (extra) {
+		HRTFTC_HRSETUP
+			= (1 << 13)
+			| ((fb->fb.var.xres - 1) << 4)
+			| 0xc
+			| (extra->hrmode ? 1 : 0);
+		HRTFTC_HRCON
+			= ((extra->clsen ? 1 : 0) << 1)
+			| ((extra->spsen ? 1 : 0) << 0);
+		HRTFTC_HRTIMING1
+			= (extra->pcdel << 8)
+			| (extra->revdel << 4)
+			| (extra->lpdel << 0);
+		HRTFTC_HRTIMING2
+			= (extra->spldel << 9)
+			| (extra->pc2del << 0);
+	}
+	else
+		HRTFTC_HRSETUP
+			= (1 << 13)
+			| 0xc;
+#endif
+
+#if defined (CONFIG_ARCH_LH7A404)
+
+	if (extra) {
+		ALI_SETUP
+			= (1 << 13)
+			| ((fb->fb.var.xres - 1) << 4)
+			| 0xc
+			| (extra->hrmode ? 1 : 0);
+		ALI_CONTROL
+			= ((extra->clsen ? 1 : 0) << 1)
+			| ((extra->spsen ? 1 : 0) << 0);
+		ALI_TIMING1
+			= (extra->pcdel << 8)
+			| (extra->revdel << 4)
+			| (extra->lpdel << 0);
+		ALI_TIMING2
+			= (extra->spldel << 9)
+			| (extra->pc2del << 0);
+	}
+	else
+		ALI_SETUP
+			= (1 << 13)
+			| 0xc;
+#endif
+
+}
+
+#define FRAMESIZE(s) (((s) + PAGE_SIZE - 1)&PAGE_MASK)
+
+static int lh7a40x_clcd_setup (struct clcd_fb *fb)
+{
+	dma_addr_t dma;
+	u32 len = FRAMESIZE (lcd_panel.mode.xres*lcd_panel.mode.yres
+			     *(lcd_panel.bpp/8));
+
+	fb->panel = &lcd_panel;
+
+		/* Enforce the sync polarity defaults */
+	if (!(fb->panel->tim2 & TIM2_IHS))
+		fb->fb.var.sync |= FB_SYNC_HOR_HIGH_ACT;
+	if (!(fb->panel->tim2 & TIM2_IVS))
+		fb->fb.var.sync |= FB_SYNC_VERT_HIGH_ACT;
+
+#if defined (HAS_LCD_PANEL_EXTRA)
+	fb->board_data = &lcd_panel_extra;
+#endif
+
+	fb->fb.screen_base
+		= dma_alloc_writecombine (&fb->dev->dev, len,
+					  &dma, GFP_KERNEL);
+	printk ("CLCD: LCD setup fb virt 0x%p phys 0x%p l %x io 0x%p \n",
+		fb->fb.screen_base, (void*) dma, len,
+		(void*) io_p2v (CLCDC_PHYS));
+	printk ("CLCD: pixclock %d\n", lcd_panel.mode.pixclock);
+
+	if (!fb->fb.screen_base) {
+		printk(KERN_ERR "CLCD: unable to map framebuffer\n");
+		return -ENOMEM;
+	}
+
+#if defined (USE_RGB555)
+	fb->fb.var.green.length = 5; /* Panel uses RGB 5:5:5 */
+#endif
+
+	fb->fb.fix.smem_start = dma;
+	fb->fb.fix.smem_len = len;
+
+		/* Drive PE4 high to prevent CPLD crash */
+	GPIO_PEDD |= (1<<4);
+	GPIO_PED  |= (1<<4);
+
+	GPIO_PINMUX |= (1<<1) | (1<<0); /* LCDVD[15:4] */
+
+//	fb->fb.fbops->fb_check_var (&fb->fb.var, &fb->fb);
+//	fb->fb.fbops->fb_set_par (&fb->fb);
+
+	return 0;
+}
+
+static int lh7a40x_clcd_mmap (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);
+}
+
+static void lh7a40x_clcd_remove (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 struct clcd_board clcd_platform_data = {
+	.name		= "lh7a40x FB",
+	.check		= clcdfb_check,
+	.decode		= clcdfb_decode,
+	.enable		= lh7a40x_clcd_enable,
+	.setup		= lh7a40x_clcd_setup,
+	.mmap		= lh7a40x_clcd_mmap,
+	.remove		= lh7a40x_clcd_remove,
+	.disable	= lh7a40x_clcd_disable,
+};
+
+#define IRQ_CLCDC (IRQ_LCDINTR)
+
+#define AMBA_DEVICE(name,busid,base,plat,pid)			\
+static struct amba_device name##_device = {			\
+	.dev = {						\
+		.coherent_dma_mask = ~0,			\
+		.bus_id	= busid,				\
+		.platform_data = plat,				\
+		},						\
+	.res = {						\
+		.start	= base##_PHYS,				\
+		.end	= (base##_PHYS) + (4*1024) - 1,		\
+		.flags	= IORESOURCE_MEM,			\
+		},						\
+	.dma_mask	= ~0,					\
+	.irq		= { IRQ_##base, },			\
+	/* .dma		= base##_DMA,*/				\
+	.periphid = pid,					\
+}
+
+AMBA_DEVICE(clcd,  "cldc-lh7a40x",  CLCDC,     &clcd_platform_data, 0x41110);
+
+static struct amba_device *amba_devs[] __initdata = {
+	&clcd_device,
+};
+
+void __init lh7a40x_clcd_init (void)
+{
+	int i;
+	int result;
+	printk ("CLCD: registering amba devices\n");
+	for (i = 0; i < ARRAY_SIZE(amba_devs); i++) {
+		struct amba_device *d = amba_devs[i];
+		result = amba_device_register(d, &iomem_resource);
+		printk ("  %d -> %d\n", i ,result);
+	}
+}