xref: /rk3399_rockchip-uboot/drivers/video/atmel_hlcdfb.c (revision f6b690e65c0aa5f3da22546ac597d9f01cff2e4e)
1*f6b690e6SBo Shen /*
2*f6b690e6SBo Shen  * Driver for AT91/AT32 MULTI LAYER LCD Controller
3*f6b690e6SBo Shen  *
4*f6b690e6SBo Shen  * Copyright (C) 2012 Atmel Corporation
5*f6b690e6SBo Shen  *
6*f6b690e6SBo Shen  * See file CREDITS for list of people who contributed to this
7*f6b690e6SBo Shen  * project.
8*f6b690e6SBo Shen  *
9*f6b690e6SBo Shen  * This program is free software; you can redistribute it and/or
10*f6b690e6SBo Shen  * modify it under the terms of the GNU General Public License as
11*f6b690e6SBo Shen  * published by the Free Software Foundation; either version 2 of
12*f6b690e6SBo Shen  * the License, or (at your option) any later version.
13*f6b690e6SBo Shen  *
14*f6b690e6SBo Shen  * This program is distributed in the hope that it will be useful,
15*f6b690e6SBo Shen  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16*f6b690e6SBo Shen  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
17*f6b690e6SBo Shen  * GNU General Public License for more details.
18*f6b690e6SBo Shen  *
19*f6b690e6SBo Shen  * You should have received a copy of the GNU General Public License
20*f6b690e6SBo Shen  * along with this program; if not, write to the Free Software
21*f6b690e6SBo Shen  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
22*f6b690e6SBo Shen  * MA 02111-1307 USA
23*f6b690e6SBo Shen  */
24*f6b690e6SBo Shen 
25*f6b690e6SBo Shen #include <common.h>
26*f6b690e6SBo Shen #include <asm/io.h>
27*f6b690e6SBo Shen #include <asm/arch/gpio.h>
28*f6b690e6SBo Shen #include <asm/arch/clk.h>
29*f6b690e6SBo Shen #include <lcd.h>
30*f6b690e6SBo Shen #include <atmel_hlcdc.h>
31*f6b690e6SBo Shen 
32*f6b690e6SBo Shen int lcd_line_length;
33*f6b690e6SBo Shen int lcd_color_fg;
34*f6b690e6SBo Shen int lcd_color_bg;
35*f6b690e6SBo Shen 
36*f6b690e6SBo Shen void *lcd_base;				/* Start of framebuffer memory	*/
37*f6b690e6SBo Shen void *lcd_console_address;		/* Start of console buffer	*/
38*f6b690e6SBo Shen 
39*f6b690e6SBo Shen short console_col;
40*f6b690e6SBo Shen short console_row;
41*f6b690e6SBo Shen 
42*f6b690e6SBo Shen /* configurable parameters */
43*f6b690e6SBo Shen #define ATMEL_LCDC_CVAL_DEFAULT		0xc8
44*f6b690e6SBo Shen #define ATMEL_LCDC_DMA_BURST_LEN	8
45*f6b690e6SBo Shen #ifndef ATMEL_LCDC_GUARD_TIME
46*f6b690e6SBo Shen #define ATMEL_LCDC_GUARD_TIME		1
47*f6b690e6SBo Shen #endif
48*f6b690e6SBo Shen 
49*f6b690e6SBo Shen #define ATMEL_LCDC_FIFO_SIZE		512
50*f6b690e6SBo Shen 
51*f6b690e6SBo Shen #define lcdc_readl(reg)		__raw_readl((reg))
52*f6b690e6SBo Shen #define lcdc_writel(reg, val)	__raw_writel((val), (reg))
53*f6b690e6SBo Shen 
54*f6b690e6SBo Shen void lcd_ctrl_init(void *lcdbase)
55*f6b690e6SBo Shen {
56*f6b690e6SBo Shen 	unsigned long value;
57*f6b690e6SBo Shen 	struct lcd_dma_desc *desc;
58*f6b690e6SBo Shen 	struct atmel_hlcd_regs *regs;
59*f6b690e6SBo Shen 
60*f6b690e6SBo Shen 	if (!has_lcdc())
61*f6b690e6SBo Shen 		return;     /* No lcdc */
62*f6b690e6SBo Shen 
63*f6b690e6SBo Shen 	regs = (struct atmel_hlcd_regs *)panel_info.mmio;
64*f6b690e6SBo Shen 
65*f6b690e6SBo Shen 	/* Disable DISP signal */
66*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_DISPDIS);
67*f6b690e6SBo Shen 	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
68*f6b690e6SBo Shen 		udelay(1);
69*f6b690e6SBo Shen 	/* Disable synchronization */
70*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_SYNCDIS);
71*f6b690e6SBo Shen 	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
72*f6b690e6SBo Shen 		udelay(1);
73*f6b690e6SBo Shen 	/* Disable pixel clock */
74*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_CLKDIS);
75*f6b690e6SBo Shen 	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
76*f6b690e6SBo Shen 		udelay(1);
77*f6b690e6SBo Shen 	/* Disable PWM */
78*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcddis, LCDC_LCDDIS_PWMDIS);
79*f6b690e6SBo Shen 	while ((lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
80*f6b690e6SBo Shen 		udelay(1);
81*f6b690e6SBo Shen 
82*f6b690e6SBo Shen 	/* Set pixel clock */
83*f6b690e6SBo Shen 	value = get_lcdc_clk_rate(0) / panel_info.vl_clk;
84*f6b690e6SBo Shen 	if (get_lcdc_clk_rate(0) % panel_info.vl_clk)
85*f6b690e6SBo Shen 		value++;
86*f6b690e6SBo Shen 
87*f6b690e6SBo Shen 	if (value < 1) {
88*f6b690e6SBo Shen 		/* Using system clock as pixel clock */
89*f6b690e6SBo Shen 		lcdc_writel(&regs->lcdc_lcdcfg0,
90*f6b690e6SBo Shen 					LCDC_LCDCFG0_CLKDIV(0)
91*f6b690e6SBo Shen 					| LCDC_LCDCFG0_CGDISHCR
92*f6b690e6SBo Shen 					| LCDC_LCDCFG0_CGDISHEO
93*f6b690e6SBo Shen 					| LCDC_LCDCFG0_CGDISOVR1
94*f6b690e6SBo Shen 					| LCDC_LCDCFG0_CGDISBASE
95*f6b690e6SBo Shen 					| panel_info.vl_clk_pol
96*f6b690e6SBo Shen 					| LCDC_LCDCFG0_CLKSEL);
97*f6b690e6SBo Shen 
98*f6b690e6SBo Shen 	} else {
99*f6b690e6SBo Shen 		lcdc_writel(&regs->lcdc_lcdcfg0,
100*f6b690e6SBo Shen 				LCDC_LCDCFG0_CLKDIV(value - 2)
101*f6b690e6SBo Shen 				| LCDC_LCDCFG0_CGDISHCR
102*f6b690e6SBo Shen 				| LCDC_LCDCFG0_CGDISHEO
103*f6b690e6SBo Shen 				| LCDC_LCDCFG0_CGDISOVR1
104*f6b690e6SBo Shen 				| LCDC_LCDCFG0_CGDISBASE
105*f6b690e6SBo Shen 				| panel_info.vl_clk_pol);
106*f6b690e6SBo Shen 	}
107*f6b690e6SBo Shen 
108*f6b690e6SBo Shen 	/* Initialize control register 5 */
109*f6b690e6SBo Shen 	value = 0;
110*f6b690e6SBo Shen 
111*f6b690e6SBo Shen 	value |= panel_info.vl_sync;
112*f6b690e6SBo Shen 
113*f6b690e6SBo Shen #ifndef LCD_OUTPUT_BPP
114*f6b690e6SBo Shen 	/* Output is 24bpp */
115*f6b690e6SBo Shen 	value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
116*f6b690e6SBo Shen #else
117*f6b690e6SBo Shen 	switch (LCD_OUTPUT_BPP) {
118*f6b690e6SBo Shen 	case 12:
119*f6b690e6SBo Shen 		value |= LCDC_LCDCFG5_MODE_OUTPUT_12BPP;
120*f6b690e6SBo Shen 		break;
121*f6b690e6SBo Shen 	case 16:
122*f6b690e6SBo Shen 		value |= LCDC_LCDCFG5_MODE_OUTPUT_16BPP;
123*f6b690e6SBo Shen 		break;
124*f6b690e6SBo Shen 	case 18:
125*f6b690e6SBo Shen 		value |= LCDC_LCDCFG5_MODE_OUTPUT_18BPP;
126*f6b690e6SBo Shen 		break;
127*f6b690e6SBo Shen 	case 24:
128*f6b690e6SBo Shen 		value |= LCDC_LCDCFG5_MODE_OUTPUT_24BPP;
129*f6b690e6SBo Shen 		break;
130*f6b690e6SBo Shen 	default:
131*f6b690e6SBo Shen 		BUG();
132*f6b690e6SBo Shen 		break;
133*f6b690e6SBo Shen 	}
134*f6b690e6SBo Shen #endif
135*f6b690e6SBo Shen 
136*f6b690e6SBo Shen 	value |= LCDC_LCDCFG5_GUARDTIME(ATMEL_LCDC_GUARD_TIME);
137*f6b690e6SBo Shen 	value |= (LCDC_LCDCFG5_DISPDLY | LCDC_LCDCFG5_VSPDLYS);
138*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcdcfg5, value);
139*f6b690e6SBo Shen 
140*f6b690e6SBo Shen 	/* Vertical & Horizontal Timing */
141*f6b690e6SBo Shen 	value = LCDC_LCDCFG1_VSPW(panel_info.vl_vsync_len - 1);
142*f6b690e6SBo Shen 	value |= LCDC_LCDCFG1_HSPW(panel_info.vl_hsync_len - 1);
143*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcdcfg1, value);
144*f6b690e6SBo Shen 
145*f6b690e6SBo Shen 	value = LCDC_LCDCFG2_VBPW(panel_info.vl_lower_margin);
146*f6b690e6SBo Shen 	value |= LCDC_LCDCFG2_VFPW(panel_info.vl_upper_margin - 1);
147*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcdcfg2, value);
148*f6b690e6SBo Shen 
149*f6b690e6SBo Shen 	value = LCDC_LCDCFG3_HBPW(panel_info.vl_right_margin - 1);
150*f6b690e6SBo Shen 	value |= LCDC_LCDCFG3_HFPW(panel_info.vl_left_margin - 1);
151*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcdcfg3, value);
152*f6b690e6SBo Shen 
153*f6b690e6SBo Shen 	/* Display size */
154*f6b690e6SBo Shen 	value = LCDC_LCDCFG4_RPF(panel_info.vl_row - 1);
155*f6b690e6SBo Shen 	value |= LCDC_LCDCFG4_PPL(panel_info.vl_col - 1);
156*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcdcfg4, value);
157*f6b690e6SBo Shen 
158*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basecfg0,
159*f6b690e6SBo Shen 			LCDC_BASECFG0_BLEN_AHB_INCR4 | LCDC_BASECFG0_DLBO);
160*f6b690e6SBo Shen 
161*f6b690e6SBo Shen 	switch (NBITS(panel_info.vl_bpix)) {
162*f6b690e6SBo Shen 	case 16:
163*f6b690e6SBo Shen 		lcdc_writel(&regs->lcdc_basecfg1,
164*f6b690e6SBo Shen 			LCDC_BASECFG1_RGBMODE_16BPP_RGB_565);
165*f6b690e6SBo Shen 		break;
166*f6b690e6SBo Shen 	default:
167*f6b690e6SBo Shen 		BUG();
168*f6b690e6SBo Shen 		break;
169*f6b690e6SBo Shen 	}
170*f6b690e6SBo Shen 
171*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basecfg2, LCDC_BASECFG2_XSTRIDE(0));
172*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basecfg3, 0);
173*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basecfg4, LCDC_BASECFG4_DMA);
174*f6b690e6SBo Shen 
175*f6b690e6SBo Shen 	/* Disable all interrupts */
176*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcdidr, ~0UL);
177*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_baseidr, ~0UL);
178*f6b690e6SBo Shen 
179*f6b690e6SBo Shen 	/* Setup the DMA descriptor, this descriptor will loop to itself */
180*f6b690e6SBo Shen 	desc = (struct lcd_dma_desc *)(lcdbase - 16);
181*f6b690e6SBo Shen 
182*f6b690e6SBo Shen 	desc->address = (u32)lcdbase;
183*f6b690e6SBo Shen 	/* Disable DMA transfer interrupt & descriptor loaded interrupt. */
184*f6b690e6SBo Shen 	desc->control = LCDC_BASECTRL_ADDIEN | LCDC_BASECTRL_DSCRIEN
185*f6b690e6SBo Shen 			| LCDC_BASECTRL_DMAIEN | LCDC_BASECTRL_DFETCH;
186*f6b690e6SBo Shen 	desc->next = (u32)desc;
187*f6b690e6SBo Shen 
188*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_baseaddr, desc->address);
189*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basectrl, desc->control);
190*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basenext, desc->next);
191*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_basecher, LCDC_BASECHER_CHEN |
192*f6b690e6SBo Shen 					  LCDC_BASECHER_UPDATEEN);
193*f6b690e6SBo Shen 
194*f6b690e6SBo Shen 	/* Enable LCD */
195*f6b690e6SBo Shen 	value = lcdc_readl(&regs->lcdc_lcden);
196*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_CLKEN);
197*f6b690e6SBo Shen 	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_CLKSTS))
198*f6b690e6SBo Shen 		udelay(1);
199*f6b690e6SBo Shen 	value = lcdc_readl(&regs->lcdc_lcden);
200*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_SYNCEN);
201*f6b690e6SBo Shen 	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_LCDSTS))
202*f6b690e6SBo Shen 		udelay(1);
203*f6b690e6SBo Shen 	value = lcdc_readl(&regs->lcdc_lcden);
204*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_DISPEN);
205*f6b690e6SBo Shen 	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_DISPSTS))
206*f6b690e6SBo Shen 		udelay(1);
207*f6b690e6SBo Shen 	value = lcdc_readl(&regs->lcdc_lcden);
208*f6b690e6SBo Shen 	lcdc_writel(&regs->lcdc_lcden, value | LCDC_LCDEN_PWMEN);
209*f6b690e6SBo Shen 	while (!(lcdc_readl(&regs->lcdc_lcdsr) & LCDC_LCDSR_PWMSTS))
210*f6b690e6SBo Shen 		udelay(1);
211*f6b690e6SBo Shen }
212