/*
* 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/init.h>
#include <linux/gfp.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/mach/time.h>
#include <asm/irq.h>
#include <asm/mach/irq.h>
#include <asm/system.h>
#include <mach/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, \
.init_name = 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);
}
}