Rockchip rk27xx port initial commit. This is still work in progress.
[kugel-rb.git] / firmware / target / arm / rk27xx / lcd-rk27xx.c
blobbb714581958ffee00a237880318844cfac85e6e3
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2011 Marcin Bukat
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include "config.h"
23 #include "kernel.h"
24 #include "lcd.h"
25 #include "system.h"
26 #include "cpu.h"
27 #include "spfd5420a.h"
29 static inline void delay_nop(int cycles)
31 asm volatile ("1: subs %[n], %[n], #1 \n\t"
32 " bne 1b"
34 : [n] "r" (cycles));
37 static unsigned int lcd_data_transform(unsigned int data)
39 /* 18 bit interface */
40 unsigned int r, g, b;
41 r = (data & 0x0000fc00)<<8;
42 /* g = ((data & 0x00000300) >> 2) | ((data & 0x000000e0) >> 3); */
43 g = ((data & 0x00000300) << 6) | ((data & 0x000000e0) << 5);
44 b = (data & 0x00000001f) << 3;
46 return (r | g | b);
49 /* converts RGB565 pixel into internal lcd bus format */
50 static unsigned int lcd_pixel_transform(unsigned short rgb565)
52 unsigned int r, g, b;
53 b = rgb565 & 0x1f;
54 g = (rgb565 >> 5) & 0x3f;
55 r = (rgb565 >> 11) & 0x1f;
57 return r<<19 | g<<10 | b<<3;
60 static void lcd_cmd(unsigned int cmd)
62 LCD_COMMAND = lcd_data_transform(cmd);
65 static void lcd_data(unsigned int data)
67 LCD_DATA = lcd_data_transform(data);
70 static void lcd_write_reg(unsigned int reg, unsigned int val)
72 lcd_cmd(reg);
73 lcd_data(val);
76 static void lcdctrl_bypass(unsigned int on_off)
78 while (!(LCDC_STA & LCDC_MCU_IDLE));
80 if (on_off)
81 MCU_CTRL |= MCU_CTRL_BYPASS;
82 else
83 MCU_CTRL &= ~MCU_CTRL_BYPASS;
86 /* This part is unclear. I am unable to use buffered/FIFO based writes
87 * to lcd. Depending on settings of IF I get various patterns on display
88 * but not what I want to display apparently.
90 static void lcdctrl_init(void)
92 /* alpha b111
93 * stop at current frame complete
94 * MCU mode
95 * 24b RGB
97 LCDC_CTRL = ALPHA(7) | LCDC_STOP | LCDC_MCU | RGB24B;
98 MCU_CTRL = ALPHA_BASE(0x3f) | MCU_CTRL_BYPASS;
100 HOR_ACT = 400 + 3; /* define horizonatal active region */
101 VERT_ACT = 240; /* define vertical active region */
102 VERT_PERIOD = 0xfff; /* CSn/WEn/RDn signal timings */
104 LINE0_YADDR = LINE_ALPHA_EN | 0x7fe;
105 LINE1_YADDR = LINE_ALPHA_EN | ((1 * 400) - 2);
106 LINE2_YADDR = LINE_ALPHA_EN | ((2 * 400) - 2);
107 LINE3_YADDR = LINE_ALPHA_EN | ((3 * 400) - 2);
109 LINE0_UVADDR = 0x7fe + 1;
110 LINE1_UVADDR = ((1 * 400) - 2 + 1);
111 LINE2_UVADDR = ((2 * 400) - 2 + 1);
112 LINE3_UVADDR = ((3 * 400) - 2 + 1);
114 #if 0
115 LINE0_YADDR = 0;
116 LINE1_YADDR = (1 * 400);
117 LINE2_YADDR = (2 * 400);
118 LINE3_YADDR = (3 * 400);
120 LINE0_UVADDR = 1;
121 LINE1_UVADDR = (1 * 400) + 1;
122 LINE2_UVADDR = (2 * 400) + 1;
123 LINE3_UVADDR = (3 * 400) + 1;
125 START_X = 0;
126 START_Y = 0;
127 DELTA_X = 0x200; /* no scaling */
128 DELTA_Y = 0x200; /* no scaling */
129 #endif
130 LCDC_INTR_MASK = INTR_MASK_LINE; /* INTR_MASK_EVENLINE; */
133 /* configure pins to drive lcd in 18bit mode */
134 static void iomux_lcd(void)
136 unsigned long muxa;
138 muxa = SCU_IOMUXA_CON & ~(IOMUX_LCD_VSYNC|IOMUX_LCD_DEN|0xff);
139 muxa |= IOMUX_LCD_D18|IOMUX_LCD_D20|IOMUX_LCD_D22|IOMUX_LCD_D17|IOMUX_LCD_D16;
141 SCU_IOMUXA_CON = muxa;
142 SCU_IOMUXB_CON |= IOMUX_LCD_D815;
145 /* not tested */
146 static void lcd_sleep(unsigned int sleep)
148 if (sleep)
150 /* enter sleep mode */
151 lcd_write_reg(DISPLAY_CTRL1, 0x0170);
152 delay_nop(50);
153 lcd_write_reg(DISPLAY_CTRL1, 0x0000);
154 delay_nop(50);
155 lcd_write_reg(PWR_CTRL1, 0x14B4);
157 else
159 /* return to normal operation */
160 lcd_write_reg(PWR_CTRL1, 0x14B0);
161 delay_nop(50);
162 lcd_write_reg(DISPLAY_CTRL1, 0x0173);
165 lcd_cmd(GRAM_WRITE);
168 void lcd_init_device()
170 unsigned int x, y;
172 iomux_lcd(); /* setup pins for 18bit lcd interface */
173 lcdctrl_init(); /* basic lcdc module configuration */
175 lcdctrl_bypass(1); /* run in bypass mode - all writes goes directly to lcd controller */
177 lcd_write_reg(RESET, 0x0001);
178 delay_nop(10000);
179 lcd_write_reg(RESET, 0x0000);
180 delay_nop(10000);
181 lcd_write_reg(IF_ENDIAN, 0x0000); /* order of receiving data */
182 lcd_write_reg(DRIVER_OUT_CTRL, 0x0000);
183 lcd_write_reg(ENTRY_MODE, 0x1038);
184 lcd_write_reg(WAVEFORM_CTRL, 0x0100);
185 lcd_write_reg(SHAPENING_CTRL, 0x0000);
186 lcd_write_reg(DISPLAY_CTRL2, 0x0808);
187 lcd_write_reg(LOW_PWR_CTRL1, 0x0001);
188 lcd_write_reg(LOW_PWR_CTRL2, 0x0010);
189 lcd_write_reg(EXT_DISP_CTRL1, 0x0000);
190 lcd_write_reg(EXT_DISP_CTRL2, 0x0000);
191 lcd_write_reg(BASE_IMG_SIZE, 0x3100);
192 lcd_write_reg(BASE_IMG_CTRL, 0x0001);
193 lcd_write_reg(VSCROLL_CTRL, 0x0000);
194 lcd_write_reg(PART1_POS, 0x0000);
195 lcd_write_reg(PART1_START, 0x0000);
196 lcd_write_reg(PART1_END, 0x018F);
197 lcd_write_reg(PART2_POS, 0x0000);
198 lcd_write_reg(PART2_START, 0x0000);
199 lcd_write_reg(PART2_END, 0x0000);
201 lcd_write_reg(PANEL_IF_CTRL1, 0x0011);
202 delay_nop(10000);
203 lcd_write_reg(PANEL_IF_CTRL2, 0x0202);
204 lcd_write_reg(PANEL_IF_CTRL3, 0x0300);
205 delay_nop(10000);
206 lcd_write_reg(PANEL_IF_CTRL4, 0x021E);
207 lcd_write_reg(PANEL_IF_CTRL5, 0x0202);
208 lcd_write_reg(PANEL_IF_CTRL6, 0x0100);
209 lcd_write_reg(FRAME_MKR_CTRL, 0x0000);
210 lcd_write_reg(MDDI_CTRL, 0x0000);
212 lcd_write_reg(GAMMA_CTRL1, 0x0101);
213 lcd_write_reg(GAMMA_CTRL2, 0x0000);
214 lcd_write_reg(GAMMA_CTRL3, 0x0016);
215 lcd_write_reg(GAMMA_CTRL4, 0x2913);
216 lcd_write_reg(GAMMA_CTRL5, 0x260B);
217 lcd_write_reg(GAMMA_CTRL6, 0x0101);
218 lcd_write_reg(GAMMA_CTRL7, 0x1204);
219 lcd_write_reg(GAMMA_CTRL8, 0x0415);
220 lcd_write_reg(GAMMA_CTRL9, 0x0205);
221 lcd_write_reg(GAMMA_CTRL10, 0x0303);
222 lcd_write_reg(GAMMA_CTRL11, 0x0E05);
223 lcd_write_reg(GAMMA_CTRL12, 0x0D01);
224 lcd_write_reg(GAMMA_CTRL13, 0x010D);
225 lcd_write_reg(GAMMA_CTRL14, 0x050E);
226 lcd_write_reg(GAMMA_CTRL15, 0x0303);
227 lcd_write_reg(GAMMA_CTRL16, 0x0502);
229 /* power on */
230 lcd_write_reg(DISPLAY_CTRL1, 0x0001);
231 lcd_write_reg(PWR_CTRL6, 0x0001);
232 lcd_write_reg(PWR_CTRL7, 0x0060);
233 delay_nop(50000);
234 lcd_write_reg(PWR_CTRL1, 0x16B0);
235 delay_nop(10000);
236 lcd_write_reg(PWR_CTRL2, 0x0147);
237 delay_nop(10000);
238 lcd_write_reg(PWR_CTRL3, 0x0117);
239 delay_nop(10000);
240 lcd_write_reg(PWR_CTRL4, 0x2F00);
241 delay_nop(50000);
242 lcd_write_reg(VCOM_HV2, 0x0000); /* src 0x0090 */
243 delay_nop(10000);
244 lcd_write_reg(VCOM_HV1, 0x0008); /* src 0x000A */
245 lcd_write_reg(PWR_CTRL3, 0x01BE);
246 delay_nop(10000);
248 /* addresses setup */
249 lcd_write_reg(WINDOW_H_START, 0x0000);
250 lcd_write_reg(WINDOW_H_END, 0x00EF); /* 239 */
251 lcd_write_reg(WINDOW_V_START, 0x0000);
252 lcd_write_reg(WINDOW_V_END, 0x018F); /* 399 */
253 lcd_write_reg(GRAM_H_ADDR, 0x0000);
254 lcd_write_reg(GRAM_V_ADDR, 0x0000);
256 /* display on */
257 lcd_write_reg(DISPLAY_CTRL1, 0x0021);
258 delay_nop(40000);
259 lcd_write_reg(DISPLAY_CTRL1, 0x0061);
260 delay_nop(100000);
261 lcd_write_reg(DISPLAY_CTRL1, 0x0173);
262 delay_nop(300000);
265 /* clear screen */
266 lcd_cmd(GRAM_WRITE);
268 for (x=0; x<400; x++)
269 for(y=0; y<240; y++)
270 lcd_data(0x000000);
272 lcd_sleep(0);
275 /* This is ugly hack. We drive lcd in bypass mode
276 * where all writes goes directly to lcd controller.
277 * This is suboptimal at best. IF module povides
278 * FIFO, internal sram buffer, hardware scaller,
279 * DMA signals, hardware alpha blending and more.
280 * BUT the fact is that I have no idea how to use
281 * this modes. Datasheet floating around is very
282 * unclean in this regard and OF uses ackward
283 * lcd update routines which are hard to understand.
284 * Moreover OF sets some bits in IF module registers
285 * which are referred as reseved in datasheet.
287 void lcd_update()
289 unsigned int x,y;
291 for (y=0; y<240; y++)
292 for (x=0; x<400; x++)
293 LCD_DATA = lcd_pixel_transform(lcd_framebuffer[y][x]);
296 /* not implemented yet */
297 void lcd_update_rect(int x, int y, int width, int height)
299 (void)x;
300 (void)y;
301 (void)width;
302 (void)height;
303 lcd_update();