xref: /rk3399_rockchip-uboot/drivers/video/da8xx-fb.c (revision 1221ce459d04a428f8880f58581f671b736c3c27)
113402868SStefano Babic /*
213402868SStefano Babic  * Porting to u-boot:
313402868SStefano Babic  *
413402868SStefano Babic  * (C) Copyright 2011
513402868SStefano Babic  * Stefano Babic, DENX Software Engineering, sbabic@denx.de.
613402868SStefano Babic  *
713402868SStefano Babic  * Copyright (C) 2008-2009 MontaVista Software Inc.
813402868SStefano Babic  * Copyright (C) 2008-2009 Texas Instruments Inc
913402868SStefano Babic  *
1013402868SStefano Babic  * Based on the LCD driver for TI Avalanche processors written by
1113402868SStefano Babic  * Ajay Singh and Shalom Hai.
1213402868SStefano Babic  *
131a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
1413402868SStefano Babic  */
1513402868SStefano Babic 
1613402868SStefano Babic #include <common.h>
1713402868SStefano Babic #include <malloc.h>
1813402868SStefano Babic #include <video_fb.h>
1913402868SStefano Babic #include <linux/list.h>
2013402868SStefano Babic #include <linux/fb.h>
2113402868SStefano Babic 
22*1221ce45SMasahiro Yamada #include <linux/errno.h>
2313402868SStefano Babic #include <asm/io.h>
2413402868SStefano Babic #include <asm/arch/hardware.h>
2513402868SStefano Babic 
2613402868SStefano Babic #include "videomodes.h"
270017f9eeSHeiko Schocher #include "da8xx-fb.h"
2813402868SStefano Babic 
29765f2f08SHeiko Schocher #if !defined(DA8XX_LCD_CNTL_BASE)
30765f2f08SHeiko Schocher #define DA8XX_LCD_CNTL_BASE	DAVINCI_LCD_CNTL_BASE
31765f2f08SHeiko Schocher #endif
32765f2f08SHeiko Schocher 
3313402868SStefano Babic #define DRIVER_NAME "da8xx_lcdc"
3413402868SStefano Babic 
35765f2f08SHeiko Schocher #define LCD_VERSION_1	1
36765f2f08SHeiko Schocher #define LCD_VERSION_2	2
37765f2f08SHeiko Schocher 
3813402868SStefano Babic /* LCD Status Register */
3913402868SStefano Babic #define LCD_END_OF_FRAME1		(1 << 9)
4013402868SStefano Babic #define LCD_END_OF_FRAME0		(1 << 8)
4113402868SStefano Babic #define LCD_PL_LOAD_DONE		(1 << 6)
4213402868SStefano Babic #define LCD_FIFO_UNDERFLOW		(1 << 5)
4313402868SStefano Babic #define LCD_SYNC_LOST			(1 << 2)
4413402868SStefano Babic 
4513402868SStefano Babic /* LCD DMA Control Register */
4613402868SStefano Babic #define LCD_DMA_BURST_SIZE(x)		((x) << 4)
4713402868SStefano Babic #define LCD_DMA_BURST_1			0x0
4813402868SStefano Babic #define LCD_DMA_BURST_2			0x1
4913402868SStefano Babic #define LCD_DMA_BURST_4			0x2
5013402868SStefano Babic #define LCD_DMA_BURST_8			0x3
5113402868SStefano Babic #define LCD_DMA_BURST_16		0x4
52765f2f08SHeiko Schocher #define LCD_V1_END_OF_FRAME_INT_ENA	(1 << 2)
53765f2f08SHeiko Schocher #define LCD_V2_END_OF_FRAME0_INT_ENA	(1 << 8)
54765f2f08SHeiko Schocher #define LCD_V2_END_OF_FRAME1_INT_ENA	(1 << 9)
5513402868SStefano Babic #define LCD_DUAL_FRAME_BUFFER_ENABLE	(1 << 0)
5613402868SStefano Babic 
57765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_MODE		(1 << 25)
58765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_UNPACK		(1 << 26)
59765f2f08SHeiko Schocher 
6013402868SStefano Babic /* LCD Control Register */
6113402868SStefano Babic #define LCD_CLK_DIVISOR(x)		((x) << 8)
6213402868SStefano Babic #define LCD_RASTER_MODE			0x01
6313402868SStefano Babic 
6413402868SStefano Babic /* LCD Raster Control Register */
6513402868SStefano Babic #define LCD_PALETTE_LOAD_MODE(x)	((x) << 20)
6613402868SStefano Babic #define PALETTE_AND_DATA		0x00
6713402868SStefano Babic #define PALETTE_ONLY			0x01
6813402868SStefano Babic #define DATA_ONLY			0x02
6913402868SStefano Babic 
7013402868SStefano Babic #define LCD_MONO_8BIT_MODE		(1 << 9)
7113402868SStefano Babic #define LCD_RASTER_ORDER		(1 << 8)
7213402868SStefano Babic #define LCD_TFT_MODE			(1 << 7)
73765f2f08SHeiko Schocher #define LCD_V1_UNDERFLOW_INT_ENA	(1 << 6)
74765f2f08SHeiko Schocher #define LCD_V2_UNDERFLOW_INT_ENA	(1 << 5)
75765f2f08SHeiko Schocher #define LCD_V1_PL_INT_ENA		(1 << 4)
76765f2f08SHeiko Schocher #define LCD_V2_PL_INT_ENA		(1 << 6)
7713402868SStefano Babic #define LCD_MONOCHROME_MODE		(1 << 1)
7813402868SStefano Babic #define LCD_RASTER_ENABLE		(1 << 0)
7913402868SStefano Babic #define LCD_TFT_ALT_ENABLE		(1 << 23)
8013402868SStefano Babic #define LCD_STN_565_ENABLE		(1 << 24)
81765f2f08SHeiko Schocher #define LCD_V2_DMA_CLK_EN		(1 << 2)
82765f2f08SHeiko Schocher #define LCD_V2_LIDD_CLK_EN		(1 << 1)
83765f2f08SHeiko Schocher #define LCD_V2_CORE_CLK_EN		(1 << 0)
84765f2f08SHeiko Schocher #define LCD_V2_LPP_B10			26
85765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_MODE		(1 << 25)
86765f2f08SHeiko Schocher #define LCD_V2_TFT_24BPP_UNPACK		(1 << 26)
8713402868SStefano Babic 
8813402868SStefano Babic /* LCD Raster Timing 2 Register */
8913402868SStefano Babic #define LCD_AC_BIAS_TRANSITIONS_PER_INT(x)	((x) << 16)
9013402868SStefano Babic #define LCD_AC_BIAS_FREQUENCY(x)		((x) << 8)
9113402868SStefano Babic #define LCD_SYNC_CTRL				(1 << 25)
9213402868SStefano Babic #define LCD_SYNC_EDGE				(1 << 24)
9313402868SStefano Babic #define LCD_INVERT_PIXEL_CLOCK			(1 << 22)
9413402868SStefano Babic #define LCD_INVERT_LINE_CLOCK			(1 << 21)
9513402868SStefano Babic #define LCD_INVERT_FRAME_CLOCK			(1 << 20)
9613402868SStefano Babic 
97765f2f08SHeiko Schocher /* Clock registers available only on Version 2 */
98765f2f08SHeiko Schocher #define  LCD_CLK_MAIN_RESET			(1 << 3)
9913402868SStefano Babic /* LCD Block */
10013402868SStefano Babic struct da8xx_lcd_regs {
10113402868SStefano Babic 	u32	revid;
10213402868SStefano Babic 	u32	ctrl;
10313402868SStefano Babic 	u32	stat;
10413402868SStefano Babic 	u32	lidd_ctrl;
10513402868SStefano Babic 	u32	lidd_cs0_conf;
10613402868SStefano Babic 	u32	lidd_cs0_addr;
10713402868SStefano Babic 	u32	lidd_cs0_data;
10813402868SStefano Babic 	u32	lidd_cs1_conf;
10913402868SStefano Babic 	u32	lidd_cs1_addr;
11013402868SStefano Babic 	u32	lidd_cs1_data;
11113402868SStefano Babic 	u32	raster_ctrl;
11213402868SStefano Babic 	u32	raster_timing_0;
11313402868SStefano Babic 	u32	raster_timing_1;
11413402868SStefano Babic 	u32	raster_timing_2;
11513402868SStefano Babic 	u32	raster_subpanel;
11613402868SStefano Babic 	u32	reserved;
11713402868SStefano Babic 	u32	dma_ctrl;
11813402868SStefano Babic 	u32	dma_frm_buf_base_addr_0;
11913402868SStefano Babic 	u32	dma_frm_buf_ceiling_addr_0;
12013402868SStefano Babic 	u32	dma_frm_buf_base_addr_1;
12113402868SStefano Babic 	u32	dma_frm_buf_ceiling_addr_1;
122765f2f08SHeiko Schocher 	u32	resv1;
123765f2f08SHeiko Schocher 	u32	raw_stat;
124765f2f08SHeiko Schocher 	u32	masked_stat;
125765f2f08SHeiko Schocher 	u32	int_ena_set;
126765f2f08SHeiko Schocher 	u32	int_ena_clr;
127765f2f08SHeiko Schocher 	u32	end_of_int_ind;
128765f2f08SHeiko Schocher 	/* Clock registers available only on Version 2 */
129765f2f08SHeiko Schocher 	u32	clk_ena;
130765f2f08SHeiko Schocher 	u32	clk_reset;
13113402868SStefano Babic };
13213402868SStefano Babic 
13313402868SStefano Babic #define LCD_NUM_BUFFERS	1
13413402868SStefano Babic 
13513402868SStefano Babic #define WSI_TIMEOUT	50
13613402868SStefano Babic #define PALETTE_SIZE	256
13713402868SStefano Babic #define LEFT_MARGIN	64
13813402868SStefano Babic #define RIGHT_MARGIN	64
13913402868SStefano Babic #define UPPER_MARGIN	32
14013402868SStefano Babic #define LOWER_MARGIN	32
141765f2f08SHeiko Schocher #define WAIT_FOR_FRAME_DONE	true
142765f2f08SHeiko Schocher #define NO_WAIT_FOR_FRAME_DONE	false
14313402868SStefano Babic 
14413402868SStefano Babic #define calc_fbsize() (panel.plnSizeX * panel.plnSizeY * panel.gdfBytesPP)
14513402868SStefano Babic 
14613402868SStefano Babic static struct da8xx_lcd_regs *da8xx_fb_reg_base;
14713402868SStefano Babic 
14813402868SStefano Babic DECLARE_GLOBAL_DATA_PTR;
14913402868SStefano Babic 
15013402868SStefano Babic /* graphics setup */
15113402868SStefano Babic static GraphicDevice gpanel;
15213402868SStefano Babic static const struct da8xx_panel *lcd_panel;
15313402868SStefano Babic static struct fb_info *da8xx_fb_info;
15413402868SStefano Babic static int bits_x_pixel;
155765f2f08SHeiko Schocher static unsigned int lcd_revision;
156765f2f08SHeiko Schocher const struct lcd_ctrl_config *da8xx_lcd_cfg;
15713402868SStefano Babic 
lcdc_read(u32 * addr)15813402868SStefano Babic static inline unsigned int lcdc_read(u32 *addr)
15913402868SStefano Babic {
16013402868SStefano Babic 	return (unsigned int)readl(addr);
16113402868SStefano Babic }
16213402868SStefano Babic 
lcdc_write(unsigned int val,u32 * addr)16313402868SStefano Babic static inline void lcdc_write(unsigned int val, u32 *addr)
16413402868SStefano Babic {
16513402868SStefano Babic 	writel(val, addr);
16613402868SStefano Babic }
16713402868SStefano Babic 
16813402868SStefano Babic struct da8xx_fb_par {
16913402868SStefano Babic 	u32			 p_palette_base;
17013402868SStefano Babic 	unsigned char *v_palette_base;
17113402868SStefano Babic 	dma_addr_t		vram_phys;
17213402868SStefano Babic 	unsigned long		vram_size;
17313402868SStefano Babic 	void			*vram_virt;
17413402868SStefano Babic 	unsigned int		dma_start;
17513402868SStefano Babic 	unsigned int		dma_end;
17613402868SStefano Babic 	struct clk *lcdc_clk;
17713402868SStefano Babic 	int irq;
17813402868SStefano Babic 	unsigned short pseudo_palette[16];
17913402868SStefano Babic 	unsigned int palette_sz;
18013402868SStefano Babic 	unsigned int pxl_clk;
18113402868SStefano Babic 	int blank;
18213402868SStefano Babic 	int			vsync_flag;
18313402868SStefano Babic 	int			vsync_timeout;
18413402868SStefano Babic };
18513402868SStefano Babic 
18613402868SStefano Babic 
18713402868SStefano Babic /* Variable Screen Information */
18813402868SStefano Babic static struct fb_var_screeninfo da8xx_fb_var = {
18913402868SStefano Babic 	.xoffset = 0,
19013402868SStefano Babic 	.yoffset = 0,
19113402868SStefano Babic 	.transp = {0, 0, 0},
19213402868SStefano Babic 	.nonstd = 0,
19313402868SStefano Babic 	.activate = 0,
19413402868SStefano Babic 	.height = -1,
19513402868SStefano Babic 	.width = -1,
19613402868SStefano Babic 	.pixclock = 46666,	/* 46us - AUO display */
19713402868SStefano Babic 	.accel_flags = 0,
19813402868SStefano Babic 	.left_margin = LEFT_MARGIN,
19913402868SStefano Babic 	.right_margin = RIGHT_MARGIN,
20013402868SStefano Babic 	.upper_margin = UPPER_MARGIN,
20113402868SStefano Babic 	.lower_margin = LOWER_MARGIN,
20213402868SStefano Babic 	.sync = 0,
20313402868SStefano Babic 	.vmode = FB_VMODE_NONINTERLACED
20413402868SStefano Babic };
20513402868SStefano Babic 
20613402868SStefano Babic static struct fb_fix_screeninfo da8xx_fb_fix = {
20713402868SStefano Babic 	.id = "DA8xx FB Drv",
20813402868SStefano Babic 	.type = FB_TYPE_PACKED_PIXELS,
20913402868SStefano Babic 	.type_aux = 0,
21013402868SStefano Babic 	.visual = FB_VISUAL_PSEUDOCOLOR,
21113402868SStefano Babic 	.xpanstep = 0,
21213402868SStefano Babic 	.ypanstep = 1,
21313402868SStefano Babic 	.ywrapstep = 0,
21413402868SStefano Babic 	.accel = FB_ACCEL_NONE
21513402868SStefano Babic };
21613402868SStefano Babic 
21713402868SStefano Babic /* Enable the Raster Engine of the LCD Controller */
lcd_enable_raster(void)21813402868SStefano Babic static inline void lcd_enable_raster(void)
21913402868SStefano Babic {
22013402868SStefano Babic 	u32 reg;
22113402868SStefano Babic 
222765f2f08SHeiko Schocher 	/* Put LCDC in reset for several cycles */
223765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_2)
224765f2f08SHeiko Schocher 		lcdc_write(LCD_CLK_MAIN_RESET,
225765f2f08SHeiko Schocher 			   &da8xx_fb_reg_base->clk_reset);
226765f2f08SHeiko Schocher 
227765f2f08SHeiko Schocher 	udelay(1000);
228765f2f08SHeiko Schocher 	/* Bring LCDC out of reset */
229765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_2)
230765f2f08SHeiko Schocher 		lcdc_write(0,
231765f2f08SHeiko Schocher 			   &da8xx_fb_reg_base->clk_reset);
232765f2f08SHeiko Schocher 
233765f2f08SHeiko Schocher 	udelay(1000);
234765f2f08SHeiko Schocher 
23513402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
23613402868SStefano Babic 	if (!(reg & LCD_RASTER_ENABLE))
23713402868SStefano Babic 		lcdc_write(reg | LCD_RASTER_ENABLE,
23813402868SStefano Babic 			&da8xx_fb_reg_base->raster_ctrl);
23913402868SStefano Babic }
24013402868SStefano Babic 
24113402868SStefano Babic /* Disable the Raster Engine of the LCD Controller */
lcd_disable_raster(bool wait_for_frame_done)242765f2f08SHeiko Schocher static inline void lcd_disable_raster(bool wait_for_frame_done)
24313402868SStefano Babic {
24413402868SStefano Babic 	u32 reg;
245765f2f08SHeiko Schocher 	u32 loop_cnt = 0;
246765f2f08SHeiko Schocher 	u32 stat;
247765f2f08SHeiko Schocher 	u32 i = 0;
248765f2f08SHeiko Schocher 
249765f2f08SHeiko Schocher 	if (wait_for_frame_done)
250765f2f08SHeiko Schocher 		loop_cnt = 5000;
25113402868SStefano Babic 
25213402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
25313402868SStefano Babic 	if (reg & LCD_RASTER_ENABLE)
25413402868SStefano Babic 		lcdc_write(reg & ~LCD_RASTER_ENABLE,
25513402868SStefano Babic 			&da8xx_fb_reg_base->raster_ctrl);
256765f2f08SHeiko Schocher 
257765f2f08SHeiko Schocher 	/* Wait for the current frame to complete */
258765f2f08SHeiko Schocher 	do {
259765f2f08SHeiko Schocher 		if (lcd_revision == LCD_VERSION_1)
260765f2f08SHeiko Schocher 			stat = lcdc_read(&da8xx_fb_reg_base->stat);
261765f2f08SHeiko Schocher 		else
262765f2f08SHeiko Schocher 			stat = lcdc_read(&da8xx_fb_reg_base->raw_stat);
263765f2f08SHeiko Schocher 
264765f2f08SHeiko Schocher 		mdelay(1);
265765f2f08SHeiko Schocher 	} while (!(stat & 0x01) && (i++ < loop_cnt));
266765f2f08SHeiko Schocher 
267765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_1)
268765f2f08SHeiko Schocher 		lcdc_write(stat, &da8xx_fb_reg_base->stat);
269765f2f08SHeiko Schocher 	else
270765f2f08SHeiko Schocher 		lcdc_write(stat, &da8xx_fb_reg_base->raw_stat);
271765f2f08SHeiko Schocher 
272765f2f08SHeiko Schocher 	if ((loop_cnt != 0) && (i >= loop_cnt)) {
273765f2f08SHeiko Schocher 		printf("LCD Controller timed out\n");
274765f2f08SHeiko Schocher 		return;
275765f2f08SHeiko Schocher 	}
27613402868SStefano Babic }
27713402868SStefano Babic 
lcd_blit(int load_mode,struct da8xx_fb_par * par)27813402868SStefano Babic static void lcd_blit(int load_mode, struct da8xx_fb_par *par)
27913402868SStefano Babic {
28013402868SStefano Babic 	u32 start;
28113402868SStefano Babic 	u32 end;
28213402868SStefano Babic 	u32 reg_ras;
28313402868SStefano Babic 	u32 reg_dma;
284765f2f08SHeiko Schocher 	u32 reg_int;
28513402868SStefano Babic 
28613402868SStefano Babic 	/* init reg to clear PLM (loading mode) fields */
28713402868SStefano Babic 	reg_ras = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
28813402868SStefano Babic 	reg_ras &= ~(3 << 20);
28913402868SStefano Babic 
29013402868SStefano Babic 	reg_dma  = lcdc_read(&da8xx_fb_reg_base->dma_ctrl);
29113402868SStefano Babic 
29213402868SStefano Babic 	if (load_mode == LOAD_DATA) {
29313402868SStefano Babic 		start    = par->dma_start;
29413402868SStefano Babic 		end      = par->dma_end;
29513402868SStefano Babic 
29613402868SStefano Babic 		reg_ras |= LCD_PALETTE_LOAD_MODE(DATA_ONLY);
297765f2f08SHeiko Schocher 		if (lcd_revision == LCD_VERSION_1) {
298765f2f08SHeiko Schocher 			reg_dma |= LCD_V1_END_OF_FRAME_INT_ENA;
299765f2f08SHeiko Schocher 		} else {
300765f2f08SHeiko Schocher 			reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) |
301765f2f08SHeiko Schocher 				LCD_V2_END_OF_FRAME0_INT_ENA |
302765f2f08SHeiko Schocher 				LCD_V2_END_OF_FRAME1_INT_ENA |
303765f2f08SHeiko Schocher 				LCD_V2_UNDERFLOW_INT_ENA | LCD_SYNC_LOST;
304765f2f08SHeiko Schocher 			lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set);
305765f2f08SHeiko Schocher 		}
30613402868SStefano Babic 
30713402868SStefano Babic #if (LCD_NUM_BUFFERS == 2)
30813402868SStefano Babic 		reg_dma |= LCD_DUAL_FRAME_BUFFER_ENABLE;
30913402868SStefano Babic 		lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
31013402868SStefano Babic 		lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
31113402868SStefano Babic 		lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
31213402868SStefano Babic 		lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
31313402868SStefano Babic #else
31413402868SStefano Babic 		reg_dma &= ~LCD_DUAL_FRAME_BUFFER_ENABLE;
31513402868SStefano Babic 		lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
31613402868SStefano Babic 		lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
31713402868SStefano Babic 		lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
31813402868SStefano Babic 		lcdc_write(0, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
31913402868SStefano Babic #endif
32013402868SStefano Babic 
32113402868SStefano Babic 	} else if (load_mode == LOAD_PALETTE) {
32213402868SStefano Babic 		start    = par->p_palette_base;
32313402868SStefano Babic 		end      = start + par->palette_sz - 1;
32413402868SStefano Babic 
32513402868SStefano Babic 		reg_ras |= LCD_PALETTE_LOAD_MODE(PALETTE_ONLY);
326765f2f08SHeiko Schocher 		if (lcd_revision == LCD_VERSION_1) {
327765f2f08SHeiko Schocher 			reg_ras |= LCD_V1_PL_INT_ENA;
328765f2f08SHeiko Schocher 		} else {
329765f2f08SHeiko Schocher 			reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) |
330765f2f08SHeiko Schocher 				LCD_V2_PL_INT_ENA;
331765f2f08SHeiko Schocher 			lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set);
332765f2f08SHeiko Schocher 		}
33313402868SStefano Babic 
33413402868SStefano Babic 		lcdc_write(start, &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
33513402868SStefano Babic 		lcdc_write(end, &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
33613402868SStefano Babic 	}
33713402868SStefano Babic 
33813402868SStefano Babic 	lcdc_write(reg_dma, &da8xx_fb_reg_base->dma_ctrl);
33913402868SStefano Babic 	lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl);
34013402868SStefano Babic 
34113402868SStefano Babic 	/*
34213402868SStefano Babic 	 * The Raster enable bit must be set after all other control fields are
34313402868SStefano Babic 	 * set.
34413402868SStefano Babic 	 */
34513402868SStefano Babic 	lcd_enable_raster();
34613402868SStefano Babic }
34713402868SStefano Babic 
34813402868SStefano Babic /* Configure the Burst Size of DMA */
lcd_cfg_dma(int burst_size)34913402868SStefano Babic static int lcd_cfg_dma(int burst_size)
35013402868SStefano Babic {
35113402868SStefano Babic 	u32 reg;
35213402868SStefano Babic 
35313402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->dma_ctrl) & 0x00000001;
35413402868SStefano Babic 	switch (burst_size) {
35513402868SStefano Babic 	case 1:
35613402868SStefano Babic 		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_1);
35713402868SStefano Babic 		break;
35813402868SStefano Babic 	case 2:
35913402868SStefano Babic 		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_2);
36013402868SStefano Babic 		break;
36113402868SStefano Babic 	case 4:
36213402868SStefano Babic 		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_4);
36313402868SStefano Babic 		break;
36413402868SStefano Babic 	case 8:
36513402868SStefano Babic 		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_8);
36613402868SStefano Babic 		break;
36713402868SStefano Babic 	case 16:
36813402868SStefano Babic 		reg |= LCD_DMA_BURST_SIZE(LCD_DMA_BURST_16);
36913402868SStefano Babic 		break;
37013402868SStefano Babic 	default:
37113402868SStefano Babic 		return -EINVAL;
37213402868SStefano Babic 	}
37313402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->dma_ctrl);
37413402868SStefano Babic 
37513402868SStefano Babic 	return 0;
37613402868SStefano Babic }
37713402868SStefano Babic 
lcd_cfg_ac_bias(int period,int transitions_per_int)37813402868SStefano Babic static void lcd_cfg_ac_bias(int period, int transitions_per_int)
37913402868SStefano Babic {
38013402868SStefano Babic 	u32 reg;
38113402868SStefano Babic 
382535cce0fSRobert P. J. Day 	/* Set the AC Bias Period and Number of Transitions per Interrupt */
38313402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2) & 0xFFF00000;
38413402868SStefano Babic 	reg |= LCD_AC_BIAS_FREQUENCY(period) |
38513402868SStefano Babic 		LCD_AC_BIAS_TRANSITIONS_PER_INT(transitions_per_int);
38613402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
38713402868SStefano Babic }
38813402868SStefano Babic 
lcd_cfg_horizontal_sync(int back_porch,int pulse_width,int front_porch)38913402868SStefano Babic static void lcd_cfg_horizontal_sync(int back_porch, int pulse_width,
39013402868SStefano Babic 		int front_porch)
39113402868SStefano Babic {
39213402868SStefano Babic 	u32 reg;
39313402868SStefano Babic 
39413402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0) & 0xf;
39513402868SStefano Babic 	reg |= ((back_porch & 0xff) << 24)
39613402868SStefano Babic 	    | ((front_porch & 0xff) << 16)
39713402868SStefano Babic 	    | ((pulse_width & 0x3f) << 10);
39813402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0);
39913402868SStefano Babic }
40013402868SStefano Babic 
lcd_cfg_vertical_sync(int back_porch,int pulse_width,int front_porch)40113402868SStefano Babic static void lcd_cfg_vertical_sync(int back_porch, int pulse_width,
40213402868SStefano Babic 		int front_porch)
40313402868SStefano Babic {
40413402868SStefano Babic 	u32 reg;
40513402868SStefano Babic 
40613402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1) & 0x3ff;
40713402868SStefano Babic 	reg |= ((back_porch & 0xff) << 24)
40813402868SStefano Babic 	    | ((front_porch & 0xff) << 16)
40913402868SStefano Babic 	    | ((pulse_width & 0x3f) << 10);
41013402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1);
41113402868SStefano Babic }
41213402868SStefano Babic 
lcd_cfg_display(const struct lcd_ctrl_config * cfg)41313402868SStefano Babic static int lcd_cfg_display(const struct lcd_ctrl_config *cfg)
41413402868SStefano Babic {
41513402868SStefano Babic 	u32 reg;
416765f2f08SHeiko Schocher 	u32 reg_int;
41713402868SStefano Babic 
41813402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(LCD_TFT_MODE |
41913402868SStefano Babic 						LCD_MONO_8BIT_MODE |
42013402868SStefano Babic 						LCD_MONOCHROME_MODE);
42113402868SStefano Babic 
42213402868SStefano Babic 	switch (cfg->p_disp_panel->panel_shade) {
42313402868SStefano Babic 	case MONOCHROME:
42413402868SStefano Babic 		reg |= LCD_MONOCHROME_MODE;
42513402868SStefano Babic 		if (cfg->mono_8bit_mode)
42613402868SStefano Babic 			reg |= LCD_MONO_8BIT_MODE;
42713402868SStefano Babic 		break;
42813402868SStefano Babic 	case COLOR_ACTIVE:
42913402868SStefano Babic 		reg |= LCD_TFT_MODE;
43013402868SStefano Babic 		if (cfg->tft_alt_mode)
43113402868SStefano Babic 			reg |= LCD_TFT_ALT_ENABLE;
43213402868SStefano Babic 		break;
43313402868SStefano Babic 
43413402868SStefano Babic 	case COLOR_PASSIVE:
43513402868SStefano Babic 		if (cfg->stn_565_mode)
43613402868SStefano Babic 			reg |= LCD_STN_565_ENABLE;
43713402868SStefano Babic 		break;
43813402868SStefano Babic 
43913402868SStefano Babic 	default:
44013402868SStefano Babic 		return -EINVAL;
44113402868SStefano Babic 	}
44213402868SStefano Babic 
44313402868SStefano Babic 	/* enable additional interrupts here */
444765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_1) {
445765f2f08SHeiko Schocher 		reg |= LCD_V1_UNDERFLOW_INT_ENA;
446765f2f08SHeiko Schocher 	} else {
447765f2f08SHeiko Schocher 		reg_int = lcdc_read(&da8xx_fb_reg_base->int_ena_set) |
448765f2f08SHeiko Schocher 			LCD_V2_UNDERFLOW_INT_ENA;
449765f2f08SHeiko Schocher 		lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_set);
450765f2f08SHeiko Schocher 	}
45113402868SStefano Babic 
45213402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl);
45313402868SStefano Babic 
45413402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2);
45513402868SStefano Babic 
45613402868SStefano Babic 	if (cfg->sync_ctrl)
45713402868SStefano Babic 		reg |= LCD_SYNC_CTRL;
45813402868SStefano Babic 	else
45913402868SStefano Babic 		reg &= ~LCD_SYNC_CTRL;
46013402868SStefano Babic 
46113402868SStefano Babic 	if (cfg->sync_edge)
46213402868SStefano Babic 		reg |= LCD_SYNC_EDGE;
46313402868SStefano Babic 	else
46413402868SStefano Babic 		reg &= ~LCD_SYNC_EDGE;
46513402868SStefano Babic 
46613402868SStefano Babic 	if (cfg->invert_line_clock)
46713402868SStefano Babic 		reg |= LCD_INVERT_LINE_CLOCK;
46813402868SStefano Babic 	else
46913402868SStefano Babic 		reg &= ~LCD_INVERT_LINE_CLOCK;
47013402868SStefano Babic 
47113402868SStefano Babic 	if (cfg->invert_frm_clock)
47213402868SStefano Babic 		reg |= LCD_INVERT_FRAME_CLOCK;
47313402868SStefano Babic 	else
47413402868SStefano Babic 		reg &= ~LCD_INVERT_FRAME_CLOCK;
47513402868SStefano Babic 
47613402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
47713402868SStefano Babic 
47813402868SStefano Babic 	return 0;
47913402868SStefano Babic }
48013402868SStefano Babic 
lcd_cfg_frame_buffer(struct da8xx_fb_par * par,u32 width,u32 height,u32 bpp,u32 raster_order)48113402868SStefano Babic static int lcd_cfg_frame_buffer(struct da8xx_fb_par *par, u32 width, u32 height,
48213402868SStefano Babic 		u32 bpp, u32 raster_order)
48313402868SStefano Babic {
48413402868SStefano Babic 	u32 reg;
48513402868SStefano Babic 
48613402868SStefano Babic 	/* Set the Panel Width */
48713402868SStefano Babic 	/* Pixels per line = (PPL + 1)*16 */
488765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_1) {
489765f2f08SHeiko Schocher 		/*
490535cce0fSRobert P. J. Day 		 * 0x3F in bits 4..9 gives max horizontal resolution = 1024
491765f2f08SHeiko Schocher 		 * pixels
492765f2f08SHeiko Schocher 		 */
49313402868SStefano Babic 		width &= 0x3f0;
494765f2f08SHeiko Schocher 	} else {
495765f2f08SHeiko Schocher 		/*
496765f2f08SHeiko Schocher 		 * 0x7F in bits 4..10 gives max horizontal resolution = 2048
497765f2f08SHeiko Schocher 		 * pixels.
498765f2f08SHeiko Schocher 		 */
499765f2f08SHeiko Schocher 		width &= 0x7f0;
500765f2f08SHeiko Schocher 	}
50113402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_0);
50213402868SStefano Babic 	reg &= 0xfffffc00;
503765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_1) {
50413402868SStefano Babic 		reg |= ((width >> 4) - 1) << 4;
505765f2f08SHeiko Schocher 	} else {
506765f2f08SHeiko Schocher 		width = (width >> 4) - 1;
507765f2f08SHeiko Schocher 		reg |= ((width & 0x3f) << 4) | ((width & 0x40) >> 3);
508765f2f08SHeiko Schocher 	}
50913402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_0);
51013402868SStefano Babic 
51113402868SStefano Babic 	/* Set the Panel Height */
512765f2f08SHeiko Schocher 	/* Set bits 9:0 of Lines Per Pixel */
51313402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_1);
51413402868SStefano Babic 	reg = ((height - 1) & 0x3ff) | (reg & 0xfffffc00);
51513402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_1);
51613402868SStefano Babic 
517765f2f08SHeiko Schocher 	/* Set bit 10 of Lines Per Pixel */
518765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_2) {
519765f2f08SHeiko Schocher 		reg = lcdc_read(&da8xx_fb_reg_base->raster_timing_2);
520765f2f08SHeiko Schocher 		reg |= ((height - 1) & 0x400) << 16;
521765f2f08SHeiko Schocher 		lcdc_write(reg, &da8xx_fb_reg_base->raster_timing_2);
522765f2f08SHeiko Schocher 	}
523765f2f08SHeiko Schocher 
52413402868SStefano Babic 	/* Set the Raster Order of the Frame Buffer */
52513402868SStefano Babic 	reg = lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & ~(1 << 8);
52613402868SStefano Babic 	if (raster_order)
52713402868SStefano Babic 		reg |= LCD_RASTER_ORDER;
528765f2f08SHeiko Schocher 
529765f2f08SHeiko Schocher 	if (bpp == 24)
530765f2f08SHeiko Schocher 		reg |= (LCD_TFT_MODE | LCD_V2_TFT_24BPP_MODE);
531765f2f08SHeiko Schocher 	else if (bpp == 32)
532765f2f08SHeiko Schocher 		reg |= (LCD_TFT_MODE | LCD_V2_TFT_24BPP_MODE
533765f2f08SHeiko Schocher 				| LCD_V2_TFT_24BPP_UNPACK);
534765f2f08SHeiko Schocher 
53513402868SStefano Babic 	lcdc_write(reg, &da8xx_fb_reg_base->raster_ctrl);
53613402868SStefano Babic 
53713402868SStefano Babic 	switch (bpp) {
53813402868SStefano Babic 	case 1:
53913402868SStefano Babic 	case 2:
54013402868SStefano Babic 	case 4:
54113402868SStefano Babic 	case 16:
542765f2f08SHeiko Schocher 	case 24:
543765f2f08SHeiko Schocher 	case 32:
54413402868SStefano Babic 		par->palette_sz = 16 * 2;
54513402868SStefano Babic 		break;
54613402868SStefano Babic 
54713402868SStefano Babic 	case 8:
54813402868SStefano Babic 		par->palette_sz = 256 * 2;
54913402868SStefano Babic 		break;
55013402868SStefano Babic 
55113402868SStefano Babic 	default:
55213402868SStefano Babic 		return -EINVAL;
55313402868SStefano Babic 	}
55413402868SStefano Babic 
55513402868SStefano Babic 	return 0;
55613402868SStefano Babic }
55713402868SStefano Babic 
fb_setcolreg(unsigned regno,unsigned red,unsigned green,unsigned blue,unsigned transp,struct fb_info * info)55813402868SStefano Babic static int fb_setcolreg(unsigned regno, unsigned red, unsigned green,
55913402868SStefano Babic 			      unsigned blue, unsigned transp,
56013402868SStefano Babic 			      struct fb_info *info)
56113402868SStefano Babic {
56213402868SStefano Babic 	struct da8xx_fb_par *par = info->par;
56313402868SStefano Babic 	unsigned short *palette = (unsigned short *) par->v_palette_base;
56413402868SStefano Babic 	u_short pal;
56513402868SStefano Babic 	int update_hw = 0;
56613402868SStefano Babic 
56713402868SStefano Babic 	if (regno > 255)
56813402868SStefano Babic 		return 1;
56913402868SStefano Babic 
57013402868SStefano Babic 	if (info->fix.visual == FB_VISUAL_DIRECTCOLOR)
57113402868SStefano Babic 		return 1;
57213402868SStefano Babic 
57313402868SStefano Babic 	if (info->var.bits_per_pixel == 8) {
57413402868SStefano Babic 		red >>= 4;
57513402868SStefano Babic 		green >>= 8;
57613402868SStefano Babic 		blue >>= 12;
57713402868SStefano Babic 
57813402868SStefano Babic 		pal = (red & 0x0f00);
57913402868SStefano Babic 		pal |= (green & 0x00f0);
58013402868SStefano Babic 		pal |= (blue & 0x000f);
58113402868SStefano Babic 
58213402868SStefano Babic 		if (palette[regno] != pal) {
58313402868SStefano Babic 			update_hw = 1;
58413402868SStefano Babic 			palette[regno] = pal;
58513402868SStefano Babic 		}
58613402868SStefano Babic 	} else if ((info->var.bits_per_pixel == 16) && regno < 16) {
58713402868SStefano Babic 		red >>= (16 - info->var.red.length);
58813402868SStefano Babic 		red <<= info->var.red.offset;
58913402868SStefano Babic 
59013402868SStefano Babic 		green >>= (16 - info->var.green.length);
59113402868SStefano Babic 		green <<= info->var.green.offset;
59213402868SStefano Babic 
59313402868SStefano Babic 		blue >>= (16 - info->var.blue.length);
59413402868SStefano Babic 		blue <<= info->var.blue.offset;
59513402868SStefano Babic 
59613402868SStefano Babic 		par->pseudo_palette[regno] = red | green | blue;
59713402868SStefano Babic 
59813402868SStefano Babic 		if (palette[0] != 0x4000) {
59913402868SStefano Babic 			update_hw = 1;
60013402868SStefano Babic 			palette[0] = 0x4000;
60113402868SStefano Babic 		}
602765f2f08SHeiko Schocher 	} else if (((info->var.bits_per_pixel == 32) && regno < 32) ||
603765f2f08SHeiko Schocher 		   ((info->var.bits_per_pixel == 24) && regno < 24)) {
604765f2f08SHeiko Schocher 		red >>= (24 - info->var.red.length);
605765f2f08SHeiko Schocher 		red <<= info->var.red.offset;
606765f2f08SHeiko Schocher 
607765f2f08SHeiko Schocher 		green >>= (24 - info->var.green.length);
608765f2f08SHeiko Schocher 		green <<= info->var.green.offset;
609765f2f08SHeiko Schocher 
610765f2f08SHeiko Schocher 		blue >>= (24 - info->var.blue.length);
611765f2f08SHeiko Schocher 		blue <<= info->var.blue.offset;
612765f2f08SHeiko Schocher 
613765f2f08SHeiko Schocher 		par->pseudo_palette[regno] = red | green | blue;
614765f2f08SHeiko Schocher 
615765f2f08SHeiko Schocher 		if (palette[0] != 0x4000) {
616765f2f08SHeiko Schocher 			update_hw = 1;
617765f2f08SHeiko Schocher 			palette[0] = 0x4000;
618765f2f08SHeiko Schocher 		}
61913402868SStefano Babic 	}
62013402868SStefano Babic 
62113402868SStefano Babic 	/* Update the palette in the h/w as needed. */
62213402868SStefano Babic 	if (update_hw)
62313402868SStefano Babic 		lcd_blit(LOAD_PALETTE, par);
62413402868SStefano Babic 
62513402868SStefano Babic 	return 0;
62613402868SStefano Babic }
62713402868SStefano Babic 
lcd_reset(struct da8xx_fb_par * par)62813402868SStefano Babic static void lcd_reset(struct da8xx_fb_par *par)
62913402868SStefano Babic {
63013402868SStefano Babic 	/* Disable the Raster if previously Enabled */
631765f2f08SHeiko Schocher 	lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
63213402868SStefano Babic 
63313402868SStefano Babic 	/* DMA has to be disabled */
63413402868SStefano Babic 	lcdc_write(0, &da8xx_fb_reg_base->dma_ctrl);
63513402868SStefano Babic 	lcdc_write(0, &da8xx_fb_reg_base->raster_ctrl);
636765f2f08SHeiko Schocher 
637765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_2) {
638765f2f08SHeiko Schocher 		lcdc_write(0, &da8xx_fb_reg_base->int_ena_set);
639765f2f08SHeiko Schocher 		/* Write 1 to reset */
640765f2f08SHeiko Schocher 		lcdc_write(LCD_CLK_MAIN_RESET, &da8xx_fb_reg_base->clk_reset);
641765f2f08SHeiko Schocher 		lcdc_write(0, &da8xx_fb_reg_base->clk_reset);
642765f2f08SHeiko Schocher 	}
64313402868SStefano Babic }
64413402868SStefano Babic 
lcd_calc_clk_divider(struct da8xx_fb_par * par)64513402868SStefano Babic static void lcd_calc_clk_divider(struct da8xx_fb_par *par)
64613402868SStefano Babic {
64713402868SStefano Babic 	unsigned int lcd_clk, div;
64813402868SStefano Babic 
64913402868SStefano Babic 	/* Get clock from sysclk2 */
65013402868SStefano Babic 	lcd_clk = clk_get(2);
65113402868SStefano Babic 
65213402868SStefano Babic 	div = lcd_clk / par->pxl_clk;
653765f2f08SHeiko Schocher 	debug("LCD Clock: %d Divider: %d PixClk: %d\n",
65413402868SStefano Babic 	      lcd_clk, div, par->pxl_clk);
65513402868SStefano Babic 
65613402868SStefano Babic 	/* Configure the LCD clock divisor. */
65713402868SStefano Babic 	lcdc_write(LCD_CLK_DIVISOR(div) |
65813402868SStefano Babic 			(LCD_RASTER_MODE & 0x1), &da8xx_fb_reg_base->ctrl);
659765f2f08SHeiko Schocher 
660765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_2)
661765f2f08SHeiko Schocher 		lcdc_write(LCD_V2_DMA_CLK_EN | LCD_V2_LIDD_CLK_EN |
662765f2f08SHeiko Schocher 				LCD_V2_CORE_CLK_EN,
663765f2f08SHeiko Schocher 				&da8xx_fb_reg_base->clk_ena);
66413402868SStefano Babic }
66513402868SStefano Babic 
lcd_init(struct da8xx_fb_par * par,const struct lcd_ctrl_config * cfg,const struct da8xx_panel * panel)66613402868SStefano Babic static int lcd_init(struct da8xx_fb_par *par, const struct lcd_ctrl_config *cfg,
66713402868SStefano Babic 		const struct da8xx_panel *panel)
66813402868SStefano Babic {
66913402868SStefano Babic 	u32 bpp;
67013402868SStefano Babic 	int ret = 0;
67113402868SStefano Babic 
67213402868SStefano Babic 	lcd_reset(par);
67313402868SStefano Babic 
67413402868SStefano Babic 	/* Calculate the divider */
67513402868SStefano Babic 	lcd_calc_clk_divider(par);
67613402868SStefano Babic 
67713402868SStefano Babic 	if (panel->invert_pxl_clk)
67813402868SStefano Babic 		lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) |
67913402868SStefano Babic 			LCD_INVERT_PIXEL_CLOCK),
68013402868SStefano Babic 			 &da8xx_fb_reg_base->raster_timing_2);
68113402868SStefano Babic 	else
68213402868SStefano Babic 		lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_timing_2) &
68313402868SStefano Babic 			~LCD_INVERT_PIXEL_CLOCK),
68413402868SStefano Babic 			&da8xx_fb_reg_base->raster_timing_2);
68513402868SStefano Babic 
68613402868SStefano Babic 	/* Configure the DMA burst size. */
68713402868SStefano Babic 	ret = lcd_cfg_dma(cfg->dma_burst_sz);
68813402868SStefano Babic 	if (ret < 0)
68913402868SStefano Babic 		return ret;
69013402868SStefano Babic 
69113402868SStefano Babic 	/* Configure the AC bias properties. */
69213402868SStefano Babic 	lcd_cfg_ac_bias(cfg->ac_bias, cfg->ac_bias_intrpt);
69313402868SStefano Babic 
69413402868SStefano Babic 	/* Configure the vertical and horizontal sync properties. */
69513402868SStefano Babic 	lcd_cfg_vertical_sync(panel->vbp, panel->vsw, panel->vfp);
69613402868SStefano Babic 	lcd_cfg_horizontal_sync(panel->hbp, panel->hsw, panel->hfp);
69713402868SStefano Babic 
698535cce0fSRobert P. J. Day 	/* Configure for display */
69913402868SStefano Babic 	ret = lcd_cfg_display(cfg);
70013402868SStefano Babic 	if (ret < 0)
70113402868SStefano Babic 		return ret;
70213402868SStefano Babic 
703765f2f08SHeiko Schocher 	if ((QVGA != cfg->p_disp_panel->panel_type) &&
704765f2f08SHeiko Schocher 	    (WVGA != cfg->p_disp_panel->panel_type))
70513402868SStefano Babic 		return -EINVAL;
70613402868SStefano Babic 
70713402868SStefano Babic 	if (cfg->bpp <= cfg->p_disp_panel->max_bpp &&
70813402868SStefano Babic 	    cfg->bpp >= cfg->p_disp_panel->min_bpp)
70913402868SStefano Babic 		bpp = cfg->bpp;
71013402868SStefano Babic 	else
71113402868SStefano Babic 		bpp = cfg->p_disp_panel->max_bpp;
71213402868SStefano Babic 	if (bpp == 12)
71313402868SStefano Babic 		bpp = 16;
71413402868SStefano Babic 	ret = lcd_cfg_frame_buffer(par, (unsigned int)panel->width,
71513402868SStefano Babic 				(unsigned int)panel->height, bpp,
71613402868SStefano Babic 				cfg->raster_order);
71713402868SStefano Babic 	if (ret < 0)
71813402868SStefano Babic 		return ret;
71913402868SStefano Babic 
72013402868SStefano Babic 	/* Configure FDD */
72113402868SStefano Babic 	lcdc_write((lcdc_read(&da8xx_fb_reg_base->raster_ctrl) & 0xfff00fff) |
72213402868SStefano Babic 		       (cfg->fdd << 12), &da8xx_fb_reg_base->raster_ctrl);
72313402868SStefano Babic 
72413402868SStefano Babic 	return 0;
72513402868SStefano Babic }
72613402868SStefano Babic 
lcdc_dma_start(void)72713402868SStefano Babic static void lcdc_dma_start(void)
72813402868SStefano Babic {
72913402868SStefano Babic 	struct da8xx_fb_par *par = da8xx_fb_info->par;
73013402868SStefano Babic 	lcdc_write(par->dma_start,
73113402868SStefano Babic 		&da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
73213402868SStefano Babic 	lcdc_write(par->dma_end,
73313402868SStefano Babic 		&da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
73413402868SStefano Babic 	lcdc_write(0,
73513402868SStefano Babic 		&da8xx_fb_reg_base->dma_frm_buf_base_addr_1);
73613402868SStefano Babic 	lcdc_write(0,
73713402868SStefano Babic 		&da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_1);
73813402868SStefano Babic }
73913402868SStefano Babic 
lcdc_irq_handler_rev01(void)740765f2f08SHeiko Schocher static u32 lcdc_irq_handler_rev01(void)
74113402868SStefano Babic {
74213402868SStefano Babic 	struct da8xx_fb_par *par = da8xx_fb_info->par;
74313402868SStefano Babic 	u32 stat = lcdc_read(&da8xx_fb_reg_base->stat);
74413402868SStefano Babic 	u32 reg_ras;
74513402868SStefano Babic 
74613402868SStefano Babic 	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
74713402868SStefano Babic 		debug("LCD_SYNC_LOST\n");
748765f2f08SHeiko Schocher 		lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
74913402868SStefano Babic 		lcdc_write(stat, &da8xx_fb_reg_base->stat);
75013402868SStefano Babic 		lcd_enable_raster();
75113402868SStefano Babic 		return LCD_SYNC_LOST;
75213402868SStefano Babic 	} else if (stat & LCD_PL_LOAD_DONE) {
75313402868SStefano Babic 		debug("LCD_PL_LOAD_DONE\n");
75413402868SStefano Babic 		/*
75513402868SStefano Babic 		 * Must disable raster before changing state of any control bit.
75613402868SStefano Babic 		 * And also must be disabled before clearing the PL loading
75713402868SStefano Babic 		 * interrupt via the following write to the status register. If
75813402868SStefano Babic 		 * this is done after then one gets multiple PL done interrupts.
75913402868SStefano Babic 		 */
760765f2f08SHeiko Schocher 		lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
76113402868SStefano Babic 
76213402868SStefano Babic 		lcdc_write(stat, &da8xx_fb_reg_base->stat);
76313402868SStefano Babic 
764535cce0fSRobert P. J. Day 		/* Disable PL completion interrupt */
76513402868SStefano Babic 		reg_ras  = lcdc_read(&da8xx_fb_reg_base->raster_ctrl);
766765f2f08SHeiko Schocher 		reg_ras &= ~LCD_V1_PL_INT_ENA;
76713402868SStefano Babic 		lcdc_write(reg_ras, &da8xx_fb_reg_base->raster_ctrl);
76813402868SStefano Babic 
76913402868SStefano Babic 		/* Setup and start data loading mode */
77013402868SStefano Babic 		lcd_blit(LOAD_DATA, par);
77113402868SStefano Babic 		return LCD_PL_LOAD_DONE;
77213402868SStefano Babic 	} else {
77313402868SStefano Babic 		lcdc_write(stat, &da8xx_fb_reg_base->stat);
77413402868SStefano Babic 
77513402868SStefano Babic 		if (stat & LCD_END_OF_FRAME0)
77613402868SStefano Babic 			debug("LCD_END_OF_FRAME0\n");
77713402868SStefano Babic 
77813402868SStefano Babic 		lcdc_write(par->dma_start,
77913402868SStefano Babic 			&da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
78013402868SStefano Babic 		lcdc_write(par->dma_end,
78113402868SStefano Babic 			&da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
78213402868SStefano Babic 		par->vsync_flag = 1;
78313402868SStefano Babic 		return LCD_END_OF_FRAME0;
78413402868SStefano Babic 	}
78513402868SStefano Babic 	return stat;
78613402868SStefano Babic }
78713402868SStefano Babic 
lcdc_irq_handler_rev02(void)788765f2f08SHeiko Schocher static u32 lcdc_irq_handler_rev02(void)
789765f2f08SHeiko Schocher {
790765f2f08SHeiko Schocher 	struct da8xx_fb_par *par = da8xx_fb_info->par;
791765f2f08SHeiko Schocher 	u32 stat = lcdc_read(&da8xx_fb_reg_base->masked_stat);
792765f2f08SHeiko Schocher 	u32 reg_int;
793765f2f08SHeiko Schocher 
794765f2f08SHeiko Schocher 	if ((stat & LCD_SYNC_LOST) && (stat & LCD_FIFO_UNDERFLOW)) {
795765f2f08SHeiko Schocher 		debug("LCD_SYNC_LOST\n");
796765f2f08SHeiko Schocher 		lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
797765f2f08SHeiko Schocher 		lcdc_write(stat, &da8xx_fb_reg_base->masked_stat);
798765f2f08SHeiko Schocher 		lcd_enable_raster();
799765f2f08SHeiko Schocher 		lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
800765f2f08SHeiko Schocher 		return LCD_SYNC_LOST;
801765f2f08SHeiko Schocher 	} else if (stat & LCD_PL_LOAD_DONE) {
802765f2f08SHeiko Schocher 		debug("LCD_PL_LOAD_DONE\n");
803765f2f08SHeiko Schocher 		/*
804765f2f08SHeiko Schocher 		 * Must disable raster before changing state of any control bit.
805765f2f08SHeiko Schocher 		 * And also must be disabled before clearing the PL loading
806765f2f08SHeiko Schocher 		 * interrupt via the following write to the status register. If
807765f2f08SHeiko Schocher 		 * this is done after then one gets multiple PL done interrupts.
808765f2f08SHeiko Schocher 		 */
809765f2f08SHeiko Schocher 		lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
810765f2f08SHeiko Schocher 
811765f2f08SHeiko Schocher 		lcdc_write(stat, &da8xx_fb_reg_base->masked_stat);
812765f2f08SHeiko Schocher 
813535cce0fSRobert P. J. Day 		/* Disable PL completion interrupt */
814765f2f08SHeiko Schocher 		reg_int  = lcdc_read(&da8xx_fb_reg_base->int_ena_clr) |
815765f2f08SHeiko Schocher 			(LCD_V2_PL_INT_ENA);
816765f2f08SHeiko Schocher 		lcdc_write(reg_int, &da8xx_fb_reg_base->int_ena_clr);
817765f2f08SHeiko Schocher 
818765f2f08SHeiko Schocher 		/* Setup and start data loading mode */
819765f2f08SHeiko Schocher 		lcd_blit(LOAD_DATA, par);
820765f2f08SHeiko Schocher 		lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
821765f2f08SHeiko Schocher 		return LCD_PL_LOAD_DONE;
822765f2f08SHeiko Schocher 	} else {
823765f2f08SHeiko Schocher 		lcdc_write(stat, &da8xx_fb_reg_base->masked_stat);
824765f2f08SHeiko Schocher 
825765f2f08SHeiko Schocher 		if (stat & LCD_END_OF_FRAME0)
826765f2f08SHeiko Schocher 			debug("LCD_END_OF_FRAME0\n");
827765f2f08SHeiko Schocher 
828765f2f08SHeiko Schocher 		lcdc_write(par->dma_start,
829765f2f08SHeiko Schocher 			   &da8xx_fb_reg_base->dma_frm_buf_base_addr_0);
830765f2f08SHeiko Schocher 		lcdc_write(par->dma_end,
831765f2f08SHeiko Schocher 			   &da8xx_fb_reg_base->dma_frm_buf_ceiling_addr_0);
832765f2f08SHeiko Schocher 		par->vsync_flag = 1;
833765f2f08SHeiko Schocher 		lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
834765f2f08SHeiko Schocher 		return LCD_END_OF_FRAME0;
835765f2f08SHeiko Schocher 	}
836765f2f08SHeiko Schocher 	lcdc_write(0, &da8xx_fb_reg_base->end_of_int_ind);
837765f2f08SHeiko Schocher 	return stat;
838765f2f08SHeiko Schocher }
839765f2f08SHeiko Schocher 
lcdc_irq_handler(void)840765f2f08SHeiko Schocher static u32 lcdc_irq_handler(void)
841765f2f08SHeiko Schocher {
842765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_1)
843765f2f08SHeiko Schocher 		return lcdc_irq_handler_rev01();
844765f2f08SHeiko Schocher 	else
845765f2f08SHeiko Schocher 		return lcdc_irq_handler_rev02();
846765f2f08SHeiko Schocher }
847765f2f08SHeiko Schocher 
wait_for_event(u32 event)84813402868SStefano Babic static u32 wait_for_event(u32 event)
84913402868SStefano Babic {
85013402868SStefano Babic 	u32 timeout = 50000;
85113402868SStefano Babic 	u32 ret;
85213402868SStefano Babic 
85313402868SStefano Babic 	do {
85413402868SStefano Babic 		ret = lcdc_irq_handler();
85513402868SStefano Babic 		udelay(1000);
85613402868SStefano Babic 	} while (!(ret & event));
85713402868SStefano Babic 
85813402868SStefano Babic 	if (timeout <= 0) {
85913402868SStefano Babic 		printf("%s: event %d not hit\n", __func__, event);
86013402868SStefano Babic 		return -1;
86113402868SStefano Babic 	}
86213402868SStefano Babic 
86313402868SStefano Babic 	return 0;
86413402868SStefano Babic 
86513402868SStefano Babic }
86613402868SStefano Babic 
video_hw_init(void)86713402868SStefano Babic void *video_hw_init(void)
86813402868SStefano Babic {
86913402868SStefano Babic 	struct da8xx_fb_par *par;
87013402868SStefano Babic 	u32 size;
871765f2f08SHeiko Schocher 	u32 rev;
87213402868SStefano Babic 	char *p;
87313402868SStefano Babic 
87413402868SStefano Babic 	if (!lcd_panel) {
87513402868SStefano Babic 		printf("Display not initialized\n");
87613402868SStefano Babic 		return NULL;
87713402868SStefano Babic 	}
87813402868SStefano Babic 	gpanel.winSizeX = lcd_panel->width;
87913402868SStefano Babic 	gpanel.winSizeY = lcd_panel->height;
88013402868SStefano Babic 	gpanel.plnSizeX = lcd_panel->width;
88113402868SStefano Babic 	gpanel.plnSizeY = lcd_panel->height;
88213402868SStefano Babic 
88313402868SStefano Babic 	switch (bits_x_pixel) {
884765f2f08SHeiko Schocher 	case 32:
885765f2f08SHeiko Schocher 		gpanel.gdfBytesPP = 4;
886765f2f08SHeiko Schocher 		gpanel.gdfIndex = GDF_32BIT_X888RGB;
887765f2f08SHeiko Schocher 		break;
88813402868SStefano Babic 	case 24:
88913402868SStefano Babic 		gpanel.gdfBytesPP = 4;
89013402868SStefano Babic 		gpanel.gdfIndex = GDF_32BIT_X888RGB;
89113402868SStefano Babic 		break;
89213402868SStefano Babic 	case 16:
89313402868SStefano Babic 		gpanel.gdfBytesPP = 2;
89413402868SStefano Babic 		gpanel.gdfIndex = GDF_16BIT_565RGB;
89513402868SStefano Babic 		break;
89613402868SStefano Babic 	default:
89713402868SStefano Babic 		gpanel.gdfBytesPP = 1;
89813402868SStefano Babic 		gpanel.gdfIndex = GDF__8BIT_INDEX;
89913402868SStefano Babic 		break;
90013402868SStefano Babic 	}
90113402868SStefano Babic 
902765f2f08SHeiko Schocher 	da8xx_fb_reg_base = (struct da8xx_lcd_regs *)DA8XX_LCD_CNTL_BASE;
90313402868SStefano Babic 
904765f2f08SHeiko Schocher 	/* Determine LCD IP Version */
905765f2f08SHeiko Schocher 	rev = lcdc_read(&da8xx_fb_reg_base->revid);
906765f2f08SHeiko Schocher 	switch (rev) {
907765f2f08SHeiko Schocher 	case 0x4C100102:
908765f2f08SHeiko Schocher 		lcd_revision = LCD_VERSION_1;
909765f2f08SHeiko Schocher 		break;
910765f2f08SHeiko Schocher 	case 0x4F200800:
911765f2f08SHeiko Schocher 	case 0x4F201000:
912765f2f08SHeiko Schocher 		lcd_revision = LCD_VERSION_2;
913765f2f08SHeiko Schocher 		break;
914765f2f08SHeiko Schocher 	default:
915765f2f08SHeiko Schocher 		printf("Unknown PID Reg value 0x%x, defaulting to LCD revision 1\n",
916765f2f08SHeiko Schocher 		       rev);
917765f2f08SHeiko Schocher 		lcd_revision = LCD_VERSION_1;
918765f2f08SHeiko Schocher 		break;
919765f2f08SHeiko Schocher 	}
920765f2f08SHeiko Schocher 
921765f2f08SHeiko Schocher 	debug("rev: 0x%x Resolution: %dx%d %d\n", rev,
92213402868SStefano Babic 	      gpanel.winSizeX,
92313402868SStefano Babic 	      gpanel.winSizeY,
924765f2f08SHeiko Schocher 	      da8xx_lcd_cfg->bpp);
92513402868SStefano Babic 
92613402868SStefano Babic 	size = sizeof(struct fb_info) + sizeof(struct da8xx_fb_par);
92713402868SStefano Babic 	da8xx_fb_info = malloc(size);
92813402868SStefano Babic 	debug("da8xx_fb_info at %x\n", (unsigned int)da8xx_fb_info);
92913402868SStefano Babic 
93013402868SStefano Babic 	if (!da8xx_fb_info) {
93113402868SStefano Babic 		printf("Memory allocation failed for fb_info\n");
93213402868SStefano Babic 		return NULL;
93313402868SStefano Babic 	}
93413402868SStefano Babic 	memset(da8xx_fb_info, 0, size);
93513402868SStefano Babic 	p = (char *)da8xx_fb_info;
93613402868SStefano Babic 	da8xx_fb_info->par = p +  sizeof(struct fb_info);
93713402868SStefano Babic 	debug("da8xx_par at %x\n", (unsigned int)da8xx_fb_info->par);
93813402868SStefano Babic 
93913402868SStefano Babic 	par = da8xx_fb_info->par;
94013402868SStefano Babic 	par->pxl_clk = lcd_panel->pxl_clk;
94113402868SStefano Babic 
942765f2f08SHeiko Schocher 	if (lcd_init(par, da8xx_lcd_cfg, lcd_panel) < 0) {
94313402868SStefano Babic 		printf("lcd_init failed\n");
94413402868SStefano Babic 		goto err_release_fb;
94513402868SStefano Babic 	}
94613402868SStefano Babic 
94713402868SStefano Babic 	/* allocate frame buffer */
948765f2f08SHeiko Schocher 	par->vram_size = lcd_panel->width * lcd_panel->height *
949765f2f08SHeiko Schocher 			da8xx_lcd_cfg->bpp;
95013402868SStefano Babic 	par->vram_size = par->vram_size * LCD_NUM_BUFFERS / 8;
95113402868SStefano Babic 
95213402868SStefano Babic 	par->vram_virt = malloc(par->vram_size);
95313402868SStefano Babic 
95413402868SStefano Babic 	par->vram_phys = (dma_addr_t) par->vram_virt;
95513402868SStefano Babic 	debug("Requesting 0x%x bytes for framebuffer at 0x%x\n",
95613402868SStefano Babic 		(unsigned int)par->vram_size,
95713402868SStefano Babic 		(unsigned int)par->vram_virt);
95813402868SStefano Babic 	if (!par->vram_virt) {
95913402868SStefano Babic 		printf("GLCD: malloc for frame buffer failed\n");
96013402868SStefano Babic 		goto err_release_fb;
96113402868SStefano Babic 	}
9624e023626SHeiko Schocher 	gd->fb_base = (int)par->vram_virt;
96313402868SStefano Babic 
96413402868SStefano Babic 	gpanel.frameAdrs = (unsigned int)par->vram_virt;
96513402868SStefano Babic 	da8xx_fb_info->screen_base = (char *) par->vram_virt;
96613402868SStefano Babic 	da8xx_fb_fix.smem_start	= gpanel.frameAdrs;
96713402868SStefano Babic 	da8xx_fb_fix.smem_len = par->vram_size;
968765f2f08SHeiko Schocher 	da8xx_fb_fix.line_length = (lcd_panel->width * da8xx_lcd_cfg->bpp) / 8;
96913402868SStefano Babic 
97013402868SStefano Babic 	par->dma_start = par->vram_phys;
97113402868SStefano Babic 	par->dma_end   = par->dma_start + lcd_panel->height *
97213402868SStefano Babic 		da8xx_fb_fix.line_length - 1;
97313402868SStefano Babic 
97413402868SStefano Babic 	/* allocate palette buffer */
97513402868SStefano Babic 	par->v_palette_base = malloc(PALETTE_SIZE);
97613402868SStefano Babic 	if (!par->v_palette_base) {
97713402868SStefano Babic 		printf("GLCD: malloc for palette buffer failed\n");
97813402868SStefano Babic 		goto err_release_fb_mem;
97913402868SStefano Babic 	}
98013402868SStefano Babic 	memset(par->v_palette_base, 0, PALETTE_SIZE);
98113402868SStefano Babic 	par->p_palette_base = (unsigned int)par->v_palette_base;
98213402868SStefano Babic 
98313402868SStefano Babic 	/* Initialize par */
984765f2f08SHeiko Schocher 	da8xx_fb_info->var.bits_per_pixel = da8xx_lcd_cfg->bpp;
98513402868SStefano Babic 
98613402868SStefano Babic 	da8xx_fb_var.xres = lcd_panel->width;
98713402868SStefano Babic 	da8xx_fb_var.xres_virtual = lcd_panel->width;
98813402868SStefano Babic 
98913402868SStefano Babic 	da8xx_fb_var.yres         = lcd_panel->height;
99013402868SStefano Babic 	da8xx_fb_var.yres_virtual = lcd_panel->height * LCD_NUM_BUFFERS;
99113402868SStefano Babic 
99213402868SStefano Babic 	da8xx_fb_var.grayscale =
993765f2f08SHeiko Schocher 	    da8xx_lcd_cfg->p_disp_panel->panel_shade == MONOCHROME ? 1 : 0;
994765f2f08SHeiko Schocher 	da8xx_fb_var.bits_per_pixel = da8xx_lcd_cfg->bpp;
99513402868SStefano Babic 
99613402868SStefano Babic 	da8xx_fb_var.hsync_len = lcd_panel->hsw;
99713402868SStefano Babic 	da8xx_fb_var.vsync_len = lcd_panel->vsw;
99813402868SStefano Babic 
99913402868SStefano Babic 	/* Initialize fbinfo */
100013402868SStefano Babic 	da8xx_fb_info->flags = FBINFO_FLAG_DEFAULT;
100113402868SStefano Babic 	da8xx_fb_info->fix = da8xx_fb_fix;
100213402868SStefano Babic 	da8xx_fb_info->var = da8xx_fb_var;
100313402868SStefano Babic 	da8xx_fb_info->pseudo_palette = par->pseudo_palette;
100413402868SStefano Babic 	da8xx_fb_info->fix.visual = (da8xx_fb_info->var.bits_per_pixel <= 8) ?
100513402868SStefano Babic 				FB_VISUAL_PSEUDOCOLOR : FB_VISUAL_TRUECOLOR;
100613402868SStefano Babic 
100713402868SStefano Babic 	/* Clear interrupt */
100813402868SStefano Babic 	memset((void *)par->vram_virt, 0, par->vram_size);
1009765f2f08SHeiko Schocher 	lcd_disable_raster(NO_WAIT_FOR_FRAME_DONE);
1010765f2f08SHeiko Schocher 	if (lcd_revision == LCD_VERSION_1)
101113402868SStefano Babic 		lcdc_write(0xFFFF, &da8xx_fb_reg_base->stat);
1012765f2f08SHeiko Schocher 	else
1013765f2f08SHeiko Schocher 		lcdc_write(0xFFFF, &da8xx_fb_reg_base->masked_stat);
101413402868SStefano Babic 	debug("Palette at 0x%x size %d\n", par->p_palette_base,
101513402868SStefano Babic 		par->palette_sz);
101613402868SStefano Babic 	lcdc_dma_start();
101713402868SStefano Babic 
101813402868SStefano Babic 	/* Load a default palette */
101913402868SStefano Babic 	fb_setcolreg(0, 0, 0, 0, 0xffff, da8xx_fb_info);
102013402868SStefano Babic 
102113402868SStefano Babic 	/* Check that the palette is loaded */
102213402868SStefano Babic 	wait_for_event(LCD_PL_LOAD_DONE);
102313402868SStefano Babic 
102413402868SStefano Babic 	/* Wait until DMA is working */
102513402868SStefano Babic 	wait_for_event(LCD_END_OF_FRAME0);
102613402868SStefano Babic 
102713402868SStefano Babic 	return (void *)&gpanel;
102813402868SStefano Babic 
102913402868SStefano Babic err_release_fb_mem:
103013402868SStefano Babic 	free(par->vram_virt);
103113402868SStefano Babic 
103213402868SStefano Babic err_release_fb:
103313402868SStefano Babic 	free(da8xx_fb_info);
103413402868SStefano Babic 
103513402868SStefano Babic 	return NULL;
103613402868SStefano Babic }
103713402868SStefano Babic 
da8xx_video_init(const struct da8xx_panel * panel,const struct lcd_ctrl_config * lcd_cfg,int bits_pixel)1038765f2f08SHeiko Schocher void da8xx_video_init(const struct da8xx_panel *panel,
1039765f2f08SHeiko Schocher 		      const struct lcd_ctrl_config *lcd_cfg, int bits_pixel)
104013402868SStefano Babic {
104113402868SStefano Babic 	lcd_panel = panel;
1042765f2f08SHeiko Schocher 	da8xx_lcd_cfg = lcd_cfg;
104313402868SStefano Babic 	bits_x_pixel = bits_pixel;
104413402868SStefano Babic }
1045