www.pudn.com > ucosii_core.rar > lcd.c, change:2007-06-21,size:11147b


#include <sysdefs.h>
#include <regs.h>
#include <ops.h>

#include "clock.h"

#ifdef UNCACHED
#undef UNCACHED
#endif
#define UNCACHED(addr)	((unsigned int)(addr) | 0x20000000)

#define STATIC_MALLOC

#define MODE_MASK		0x0f
#define MODE_TFT_GEN		0x00
#define MODE_TFT_SHARP		0x01
#define MODE_TFT_CASIO		0x02
#define MODE_TFT_SAMSUNG	0x03
#define MODE_CCIR656_NONINT	0x04
#define MODE_CCIR656_INT	0x05
#define MODE_STN_COLOR_SINGLE	0x08
#define MODE_STN_MONO_SINGLE	0x09
#define MODE_STN_COLOR_DUAL	0x0a
#define MODE_STN_MONO_DUAL	0x0b

#define STN_DAT_PIN1	(0x00 << 4)
#define STN_DAT_PIN2	(0x01 << 4)
#define STN_DAT_PIN4	(0x02 << 4)
#define STN_DAT_PIN8	(0x03 << 4)
#define STN_DAT_PINMASK	STN_DAT_PIN8

#define STFT_PSHI	(1 << 15)
#define STFT_CLSHI	(1 << 14)
#define STFT_SPLHI	(1 << 13)
#define STFT_REVHI	(1 << 12)

#define SYNC_MASTER	(0 << 16)
#define SYNC_SLAVE	(1 << 16)

#define DE_P		(0 << 9)
#define DE_N		(1 << 9)

#define PCLK_P		(0 << 10)
#define PCLK_N		(1 << 10)

#define HSYNC_P		(0 << 11)
#define HSYNC_N		(1 << 11)

#define VSYNC_P		(0 << 8)
#define VSYNC_N		(1 << 8)

#define DATA_NORMAL	(0 << 17)
#define DATA_INVERSE	(1 << 17)

#ifndef u8
#define u8	unsigned char
#endif

#ifndef u16
#define u16	unsigned short
#endif

#ifndef u32
#define u32	unsigned int
#endif

#ifndef NULL
#define NULL	0
#endif

#define dprintf(x...)

#define NR_PALETTE	256

struct lcd_desc {
	u32 next;
	u32 buf;
	u32 id;
	u32 cmd;
};

struct jzfb_info {

	u32 cfg;	/* panel mode and pin usage etc. */
	u32 w;
	u32 h;
	u32 bpp;	/* bit per pixel */
	u32 fclk;	/* frame clk */
	u32 hsw;	/* hsync width, in pclk */
	u32 vsw;	/* vsync width, in line count */
	u32 elw;	/* end of line, in pclk */
	u32 blw;	/* begin of line, in pclk */
	u32 efw;	/* end of frame, in line count */
	u32 bfw;	/* begin of frame, in line count */

	u8 *cpal;	/* Cacheable Palette Buffer */
	u8 *pal;	/* Non-cacheable Palette Buffer */
	u8 *cframe;	/* Cacheable Frame Buffer */
	u8 *frame;	/* Non-cacheable Frame Buffer */

	struct {
		u8 red, green, blue;
	} palette[NR_PALETTE];
};

struct jzfb_info jzfb = {
#if 0
	MODE_TFT_GEN | HSYNC_N | VSYNC_N,
	480, 272, 16, 60, 41, 10, 2, 2, 2, 2
#else
	MODE_TFT_GEN | HSYNC_N | VSYNC_N | PCLK_N,
	320, 240, 16, 60, 30, 3, 38, 20, 11, 8
#endif
};

u32 lcd_get_width(void) {return jzfb.w;}
u32 lcd_get_height(void) {return jzfb.h;}
u32 lcd_get_bpp(void) {return jzfb.bpp;}
u8* lcd_get_frame(void) {return jzfb.frame;}
u8* lcd_get_cframe(void) {return jzfb.cframe;}

static struct lcd_desc lcd_palette_desc __attribute__ ((aligned (16)));
static struct lcd_desc lcd_frame_desc0 __attribute__ ((aligned (16)));
static struct lcd_desc lcd_frame_desc1 __attribute__ ((aligned (16)));

static int jzfb_setcolreg(u32 regno, u8 red, u8 green, u8 blue)
{
	u16 *ptr, ctmp;

	if (regno >= NR_PALETTE)
		return 1;

	red	&= 0xff;
	green	&= 0xff;
	blue	&= 0xff;
	
	jzfb.palette[regno].red		= red ;
	jzfb.palette[regno].green	= green;
	jzfb.palette[regno].blue	= blue;
	
	if (jzfb.bpp <= 8) {
		if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||
		    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) {
			ctmp = (77L * red + 150L * green + 29L * blue) >> 8;
			ctmp = ((ctmp >> 3) << 11) | ((ctmp >> 2) << 5) |
				(ctmp >> 3);
		} else {
			/* RGB 565 */
			if (((red >> 3) == 0) && ((red >> 2) != 0))
				red = 1 << 3;
			if (((blue >> 3) == 0) && ((blue >> 2) != 0))
				blue = 1 << 3;
			ctmp = ((red >> 3) << 11) 
				| ((green >> 2) << 5) | (blue >> 3);
		}

		ptr = (u16 *)jzfb.pal;
		ptr[regno] = ctmp;
		REG_LCD_DA0 = PHYS(&lcd_palette_desc);
	} else
		printf("No palette used.\n");

	return 0;
}


#ifdef STATIC_MALLOC
static u8 lcd_heap[1024*1024*2];
#endif

/*
 * Map screen memory
 */
static int fb_malloc(void)
{
	struct page * map = NULL;
	u8 *tmp;
	u32 page_shift, needroom, t;

	if (jzfb.bpp == 15)
		t = 16;
	else
		t = jzfb.bpp;

	needroom = ((jzfb.w * t + 7) >> 3) * jzfb.h;

#ifndef STATIC_MALLOC
	jzfb.cpal = (u8 *)malloc(512+0x1000);
	jzfb.cpal = (u8 *)((u32)jzfb.cpal & ~0xfff);	/* 4KB aligned */
	jzfb.cframe = (u8 *)malloc(needroom+0x1000);
	jzfb.cframe = (u8 *)((u32)jzfb.cframe & ~0xfff);/* 4KB aligned */
#else
	jzfb.cpal = (u8 *)(((u32)lcd_heap+0x1000) & ~0xfff);
	jzfb.cframe = (u8 *)((u32)jzfb.cpal + 0x1000);
#endif

	jzfb.pal = (u8 *)UNCACHED(jzfb.cpal);
	jzfb.frame = (u8 *)UNCACHED(jzfb.cframe);

	if ((!jzfb.cpal) || (!jzfb.cframe))
		return -1;	/* No memory */

	memset(jzfb.cpal, 0, 512);
	memset(jzfb.cframe, 0, needroom);

	return 0;
}

static void lcd_descriptor_init(void)
{
	int i;
	unsigned int pal_size;
	unsigned int frm_size, ln_size;
	unsigned char dual_panel = 0;
	struct lcd_desc *pal_desc, *frame_desc0, *frame_desc1;

	pal_desc	= &lcd_palette_desc;
	frame_desc0	= &lcd_frame_desc0;
	frame_desc1	= &lcd_frame_desc1;

	i = jzfb.bpp;
	if (i == 15)
		i = 16;
	frm_size = (jzfb.w*jzfb.h*i)>>3;
	ln_size = (jzfb.w*i)>>3;

	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL)) {
		dual_panel = 1;
		frm_size >>= 1;
	}

	frm_size = frm_size / 4;
	ln_size = ln_size / 4;

	switch (jzfb.bpp) {
	case 1:
		pal_size = 4;
		break;
	case 2:
		pal_size = 8;
		break;
	case 4:
		pal_size = 32;
		break;
	case 8:
	default:
		pal_size = 512;
		break;
	}

	pal_size /= 4;

	/* Palette Descriptor */
	pal_desc->next	= PHYS(frame_desc0);
	pal_desc->buf	= PHYS(jzfb.pal);
	pal_desc->id	= 0xdeadbeaf;
	pal_desc->cmd	= pal_size|LCD_CMD_PAL; /* Palette Descriptor */

	/* Frame Descriptor 0 */
	frame_desc0->next	= PHYS(frame_desc0);
	frame_desc0->buf	= PHYS(jzfb.frame);
	frame_desc0->id		= 0xbeafbeaf;
	frame_desc0->cmd	= LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size;

	if (!(dual_panel))
		return;

	/* Frame Descriptor 1 */
	frame_desc1->next	= PHYS(frame_desc1);
	frame_desc1->buf	= PHYS(jzfb.frame) + frm_size * 4;
	frame_desc1->id		= 0xdeaddead;
	frame_desc1->cmd	 = LCD_CMD_SOFINT | LCD_CMD_EOFINT | frm_size;

}

static int controller_init(void)
{
	unsigned int val = 0;
	unsigned int pclk;
	unsigned int stnH;
	int ret = 0;

	/* Setting Control register */
	switch (jzfb.bpp) {
	case 1:
		val |= LCD_CTRL_BPP_1;
		break;
	case 2:
		val |= LCD_CTRL_BPP_2;
		break;
	case 4:
		val |= LCD_CTRL_BPP_4;
		break;
	case 8:
		val |= LCD_CTRL_BPP_8;
		break;
	case 15:
		val |= LCD_CTRL_RGB555;
	case 16:
		val |= LCD_CTRL_BPP_16;
		break;
	default:
		printf("The BPP %d is not supported\n", jzfb.bpp);
		val |= LCD_CTRL_BPP_16;
		break;
	}

	switch (jzfb.cfg & MODE_MASK) {
	case MODE_STN_MONO_DUAL:
	case MODE_STN_COLOR_DUAL:
	case MODE_STN_MONO_SINGLE:
	case MODE_STN_COLOR_SINGLE:
		switch (jzfb.bpp) {
		case 1:
//			val |= LCD_CTRL_PEDN;
		case 2:
			val |= LCD_CTRL_FRC_2;
			break;
		case 4:
			val |= LCD_CTRL_FRC_4;
			break;
		case 8:
		default:
			val |= LCD_CTRL_FRC_16;
			break;
		}
		break;
	}

	val |= LCD_CTRL_BST_16;		/* Burst Length is 16WORD=64Byte */

	switch (jzfb.cfg & MODE_MASK) {
	case MODE_STN_MONO_DUAL:
	case MODE_STN_COLOR_DUAL:
	case MODE_STN_MONO_SINGLE:
	case MODE_STN_COLOR_SINGLE:
		switch (jzfb.cfg & STN_DAT_PINMASK) {
#define align2(n) (n)=((((n)+1)>>1)<<1)
#define align4(n) (n)=((((n)+3)>>2)<<2)
#define align8(n) (n)=((((n)+7)>>3)<<3)
		case STN_DAT_PIN1:
			/* Do not adjust the hori-param value. */
			break;
		case STN_DAT_PIN2:
			align2(jzfb.hsw);
			align2(jzfb.elw);
			align2(jzfb.blw);
			break;
		case STN_DAT_PIN4:
			align4(jzfb.hsw);
			align4(jzfb.elw);
			align4(jzfb.blw);
			break;
		case STN_DAT_PIN8:
			align8(jzfb.hsw);
			align8(jzfb.elw);
			align8(jzfb.blw);
			break;
		}
		break;
	}

	REG_LCD_CTRL = val;

	switch (jzfb.cfg & MODE_MASK) {
	case MODE_STN_MONO_DUAL:
	case MODE_STN_COLOR_DUAL:
	case MODE_STN_MONO_SINGLE:
	case MODE_STN_COLOR_SINGLE:
		if (((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL) ||
		    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
			stnH = jzfb.h >> 1;
		else
			stnH = jzfb.h;

		REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
		REG_LCD_HSYNC = ((jzfb.blw+jzfb.w) << 16) | (jzfb.blw+jzfb.w+jzfb.hsw);

		/* Screen setting */
		REG_LCD_VAT = ((jzfb.blw + jzfb.w + jzfb.hsw + jzfb.elw) << 16) | (stnH + jzfb.vsw + jzfb.bfw + jzfb.efw);
		REG_LCD_DAH = (jzfb.blw << 16) | (jzfb.blw + jzfb.w);
		REG_LCD_DAV = (0 << 16) | (stnH);

		/* AC BIAs signal */
		REG_LCD_PS = (0 << 16) | (stnH+jzfb.vsw+jzfb.efw+jzfb.bfw);

		break;

	case MODE_TFT_GEN:
	case MODE_TFT_SHARP:
	case MODE_TFT_CASIO:
	case MODE_TFT_SAMSUNG:
		REG_LCD_VSYNC = (0 << 16) | jzfb.vsw;
		REG_LCD_DAV = ((jzfb.vsw + jzfb.bfw) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h);
		REG_LCD_VAT = (((jzfb.blw + jzfb.w + jzfb.elw + jzfb.hsw)) << 16) | (jzfb.vsw + jzfb.bfw + jzfb.h + jzfb.efw);
		REG_LCD_HSYNC = (0 << 16) | jzfb.hsw;
		REG_LCD_DAH = ((jzfb.hsw + jzfb.blw) << 16) | (jzfb.hsw + jzfb.blw + jzfb.w);
		break;
	}

	switch (jzfb.cfg & MODE_MASK) {
	case MODE_TFT_SAMSUNG:
	case MODE_TFT_SHARP:
	case MODE_TFT_CASIO:
		printf("LCD DOES NOT supported.\n");
		break;
	}

	/* Configure the LCD panel */
	REG_LCD_CFG = jzfb.cfg;

	/* Timing setting */
	__cpm_stop_lcd();

	val = jzfb.fclk; /* frame clk */
	pclk = val * (jzfb.w + jzfb.hsw + jzfb.elw + jzfb.blw) *
	       (jzfb.h + jzfb.vsw + jzfb.efw + jzfb.bfw); /* Pixclk */

	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL))
		pclk = (pclk * 3);

	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_SINGLE) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_SINGLE) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
		pclk = pclk >> ((jzfb.cfg & STN_DAT_PINMASK) >> 4);

	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
		pclk >>= 1;

	val = __cpm_get_pllout() / pclk;
	REG_CPM_CFCR2 = val - 1;
	val = __cpm_get_pllout() / (pclk * 4);
	val = __cpm_divisor_encode(val);
	__cpm_set_lcdclk_div(val);
	REG_CPM_CFCR |= CPM_CFCR_UPE;

	printf("LCDC: PixClock:%d LcdClock:%d\n",
		__cpm_get_pixclk(), __cpm_get_lcdclk());

	__cpm_start_lcd();
	udelay(1000);
	return ret;
}

static void lcd_interrupt_handler(u32 irq)
{
	u32 state;

	state = REG_LCD_STATE;

	if (state & LCD_STATE_EOF) /* End of frame */
		REG_LCD_STATE = state & ~LCD_STATE_EOF;

	if (state & LCD_STATE_IFU0) {
		dprintf("InFiFo0 underrun\n");
		REG_LCD_STATE = state & ~LCD_STATE_IFU0;
	}

	if (state & LCD_STATE_OFU) { /* Out fifo underrun */
		dprintf("Out FiFo underrun.\n");
		REG_LCD_STATE = state & ~LCD_STATE_OFU;
	}
}

static int hw_init(void)
{
	lcd_board_init();

	if (controller_init() < 0)
		return -1;

	if (jzfb.bpp <= 8)
		REG_LCD_DA0 = PHYS(&lcd_palette_desc);
	else
		REG_LCD_DA0 = PHYS(&lcd_frame_desc0);

	if (((jzfb.cfg & MODE_MASK) == MODE_STN_COLOR_DUAL) ||
	    ((jzfb.cfg & MODE_MASK) == MODE_STN_MONO_DUAL))
		REG_LCD_DA1 = PHYS(&lcd_frame_desc1);

	__lcd_set_ena();

	return 0;
}

int jzlcd_init(void)
{
	int err = 0;

	err = fb_malloc();
	if (err) 
		goto failed;

	lcd_descriptor_init();

	__dcache_writeback_all();

	if (hw_init() < 0)
		goto failed;

	request_irq(IRQ_LCD, lcd_interrupt_handler, 0);

	__lcd_enable_ofu_intr();
	__lcd_enable_ifu0_intr();

	return 0;

failed:
	return err;

}