lcd drivers: Convert lcd_[remote_]framebuffer to a pointer
[maemo-rb.git] / firmware / target / arm / iriver / h10 / lcd-h10_5gb.c
blob5e1ad9ce2364bff73ad1fed769b0d2ea58eeca29
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 by Barry Wardell
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 ****************************************************************************/
21 #include "config.h"
22 #include "cpu.h"
23 #include "lcd.h"
24 #include "kernel.h"
25 #include "system.h"
27 /* register defines for TL1771 */
28 #define R_START_OSC 0x00
29 #define R_DEVICE_CODE_READ 0x00
30 #define R_DRV_OUTPUT_CONTROL 0x01
31 #define R_DRV_AC_CONTROL 0x02
32 #define R_ENTRY_MODE 0x03
33 #define R_DISP_CONTROL1 0x07
34 #define R_DISP_CONTROL2 0x08
35 #define R_FRAME_CYCLE_CONTROL 0x0b
36 #define R_POWER_CONTROL1 0x10
37 #define R_POWER_CONTROL2 0x11
38 #define R_POWER_CONTROL3 0x12
39 #define R_POWER_CONTROL4 0x13
40 #define R_POWER_CONTROL5 0x14
41 #define R_RAM_ADDR_SET 0x21
42 #define R_WRITE_DATA_2_GRAM 0x22
43 #define R_GAMMA_FINE_ADJ_POS1 0x30
44 #define R_GAMMA_FINE_ADJ_POS2 0x31
45 #define R_GAMMA_FINE_ADJ_POS3 0x32
46 #define R_GAMMA_GRAD_ADJ_POS 0x33
47 #define R_GAMMA_FINE_ADJ_NEG1 0x34
48 #define R_GAMMA_FINE_ADJ_NEG2 0x35
49 #define R_GAMMA_FINE_ADJ_NEG3 0x36
50 #define R_GAMMA_GRAD_ADJ_NEG 0x37
51 #define R_POWER_CONTROL6 0x38
52 #define R_GATE_SCAN_START_POS 0x40
53 #define R_1ST_SCR_DRV_POS 0x42
54 #define R_2ND_SCR_DRV_POS 0x43
55 #define R_HORIZ_RAM_ADDR_POS 0x44
56 #define R_VERT_RAM_ADDR_POS 0x45
58 static inline void lcd_wait_write(void)
60 while (LCD2_PORT & LCD2_BUSY_MASK);
63 /* Send command */
64 static inline void lcd_send_cmd(unsigned v)
66 lcd_wait_write();
67 LCD2_PORT = LCD2_CMD_MASK;
68 LCD2_PORT = LCD2_CMD_MASK | v;
71 /* Send 16-bit data */
72 static inline void lcd_send_data(unsigned v)
74 lcd_wait_write();
75 LCD2_PORT = LCD2_DATA_MASK | (v >> 8); /* Send MSB first */
76 LCD2_PORT = LCD2_DATA_MASK | (v & 0xff);
79 /* Write value to register */
80 static void lcd_write_reg(int reg, int val)
82 lcd_send_cmd(reg);
83 lcd_send_data(val);
87 /*** hardware configuration ***/
89 void lcd_set_contrast(int val)
91 /* TODO: Implement lcd_set_contrast() */
92 (void)val;
95 void lcd_set_invert_display(bool yesno)
97 /* TODO: Implement lcd_set_invert_display() */
98 (void)yesno;
101 /* turn the display upside down (call lcd_update() afterwards) */
102 void lcd_set_flip(bool yesno)
104 /* TODO: Implement lcd_set_flip() */
105 (void)yesno;
108 /* LCD init */
109 void lcd_init_device(void)
111 #ifndef BOOTLOADER
112 /* The OF won't boot if this is done in the bootloader - ideally we should
113 tweak the lcd controller speed settings but this will do for now */
114 CLCD_CLOCK_SRC |= 0xc0000000; /* Set LCD interface clock to PLL */
115 #endif
116 /* H10 LCD is initialised by the bootloader */
119 /*** update functions ***/
121 #define CSUB_X 2
122 #define CSUB_Y 2
124 #define RYFAC (31*257)
125 #define GYFAC (31*257)
126 #define BYFAC (31*257)
127 #define RVFAC 11170 /* 31 * 257 * 1.402 */
128 #define GVFAC (-5690) /* 31 * 257 * -0.714136 */
129 #define GUFAC (-2742) /* 31 * 257 * -0.344136 */
130 #define BUFAC 14118 /* 31 * 257 * 1.772 */
132 #define ROUNDOFFS (127*257)
133 #define ROUNDOFFSG (63*257)
135 /* Performance function to blit a YUV bitmap directly to the LCD */
136 void lcd_blit_yuv(unsigned char * const src[3],
137 int src_x, int src_y, int stride,
138 int x, int y, int width, int height)
140 int y0, x0, y1, x1;
141 int ymax;
143 width = (width + 1) & ~1;
145 /* calculate the drawing region */
146 x0 = x;
147 x1 = x + width - 1;
148 y0 = y;
149 y1 = y + height - 1;
151 /* max horiz << 8 | start horiz */
152 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (x1 << 8) | x0);
154 /* max vert << 8 | start vert */
155 lcd_write_reg(R_VERT_RAM_ADDR_POS, (y1 << 8) | y0);
157 /* start vert << 8 | start horiz */
158 lcd_write_reg(R_RAM_ADDR_SET, (y0 << 8) | x0);
160 /* start drawing */
161 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
163 ymax = y + height - 1 ;
165 const int stride_div_csub_x = stride/CSUB_X;
167 for (; y <= ymax ; y++)
169 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
170 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
172 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
173 (src_x/CSUB_X);
175 const unsigned char *usrc = src[1] + uvoffset;
176 const unsigned char *vsrc = src[2] + uvoffset;
177 const unsigned char *row_end = ysrc + width;
179 int y, u, v;
180 int red1, green1, blue1;
181 int red2, green2, blue2;
182 unsigned rbits, gbits, bbits;
184 int rc, gc, bc;
188 u = *usrc++ - 128;
189 v = *vsrc++ - 128;
190 rc = RVFAC * v + ROUNDOFFS;
191 gc = GVFAC * v + GUFAC * u + ROUNDOFFSG;
192 bc = BUFAC * u + ROUNDOFFS;
194 /* Pixel 1 */
195 y = *ysrc++;
197 red1 = RYFAC * y + rc;
198 green1 = GYFAC * y + gc;
199 blue1 = BYFAC * y + bc;
201 /* Pixel 2 */
202 y = *ysrc++;
203 red2 = RYFAC * y + rc;
204 green2 = GYFAC * y + gc;
205 blue2 = BYFAC * y + bc;
207 /* Since out of bounds errors are relatively rare, we check two
208 pixels at once to see if any components are out of bounds, and
209 then fix whichever is broken. This works due to high values and
210 negative values both becoming larger than the cutoff when
211 casted to unsigned. And ORing them together checks all of them
212 simultaneously. */
213 if (((unsigned)(red1 | green1 | blue1 |
214 red2 | green2 | blue2)) > (RYFAC*255+ROUNDOFFS)) {
215 if (((unsigned)(red1 | green1 | blue1)) >
216 (RYFAC*255+ROUNDOFFS)) {
217 if ((unsigned)red1 > (RYFAC*255+ROUNDOFFS))
219 if (red1 < 0)
220 red1 = 0;
221 else
222 red1 = (RYFAC*255+ROUNDOFFS);
224 if ((unsigned)green1 > (GYFAC*255+ROUNDOFFSG))
226 if (green1 < 0)
227 green1 = 0;
228 else
229 green1 = (GYFAC*255+ROUNDOFFSG);
231 if ((unsigned)blue1 > (BYFAC*255+ROUNDOFFS))
233 if (blue1 < 0)
234 blue1 = 0;
235 else
236 blue1 = (BYFAC*255+ROUNDOFFS);
240 if (((unsigned)(red2 | green2 | blue2)) >
241 (RYFAC*255+ROUNDOFFS)) {
242 if ((unsigned)red2 > (RYFAC*255+ROUNDOFFS))
244 if (red2 < 0)
245 red2 = 0;
246 else
247 red2 = (RYFAC*255+ROUNDOFFS);
249 if ((unsigned)green2 > (GYFAC*255+ROUNDOFFSG))
251 if (green2 < 0)
252 green2 = 0;
253 else
254 green2 = (GYFAC*255+ROUNDOFFSG);
256 if ((unsigned)blue2 > (BYFAC*255+ROUNDOFFS))
258 if (blue2 < 0)
259 blue2 = 0;
260 else
261 blue2 = (BYFAC*255+ROUNDOFFS);
266 rbits = red1 >> 16 ;
267 gbits = green1 >> 15 ;
268 bbits = blue1 >> 16 ;
269 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
271 rbits = red2 >> 16 ;
272 gbits = green2 >> 15 ;
273 bbits = blue2 >> 16 ;
274 lcd_send_data((rbits << 11) | (gbits << 5) | bbits);
276 while (ysrc < row_end);
278 src_y++;
283 /* Update a fraction of the display. */
284 void lcd_update_rect(int x0, int y0, int width, int height)
286 int x1, y1;
287 int newx,newwidth;
288 unsigned long *addr;
290 /* Ensure x and width are both even - so we can read 32-bit aligned
291 data from lcd_framebuffer */
292 newx=x0&~1;
293 newwidth=width&~1;
294 if (newx+newwidth < x0+width) { newwidth+=2; }
295 x0=newx; width=newwidth;
297 /* calculate the drawing region */
298 y1 = (y0 + height) - 1; /* max vert */
299 x1 = (x0 + width) - 1; /* max horiz */
302 /* swap max horiz < start horiz */
303 if (y1 < y0) {
304 int t;
305 t = y0;
306 y0 = y1;
307 y1 = t;
310 /* swap max vert < start vert */
311 if (x1 < x0) {
312 int t;
313 t = x0;
314 x0 = x1;
315 x1 = t;
318 /* max horiz << 8 | start horiz */
319 lcd_write_reg(R_HORIZ_RAM_ADDR_POS, (x1 << 8) | x0);
321 /* max vert << 8 | start vert */
322 lcd_write_reg(R_VERT_RAM_ADDR_POS, (y1 << 8) | y0);
324 /* start vert << 8 | start horiz */
325 lcd_write_reg(R_RAM_ADDR_SET, (y0 << 8) | x0);
327 /* start drawing */
328 lcd_send_cmd(R_WRITE_DATA_2_GRAM);
330 addr = (unsigned long*)FBADDR(x0,y0);
332 while (height > 0) {
333 int c, r;
334 int h, pixels_to_write;
336 pixels_to_write = (width * height) * 2;
337 h = height;
339 /* calculate how much we can do in one go */
340 if (pixels_to_write > 0x10000) {
341 h = (0x10000/2) / width;
342 pixels_to_write = (width * h) * 2;
345 LCD2_BLOCK_CTRL = 0x10000080;
346 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
347 LCD2_BLOCK_CTRL = 0x34000000;
349 /* for each row */
350 for (r = 0; r < h; r++) {
351 /* for each column */
352 for (c = 0; c < width; c += 2) {
353 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK));
355 /* output 2 pixels */
356 LCD2_BLOCK_DATA = *addr++;
358 addr += (LCD_WIDTH - width)/2;
361 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
362 LCD2_BLOCK_CONFIG = 0;
364 height -= h;
368 /* Update the display.
369 This must be called after all other LCD functions that change the display. */
370 void lcd_update(void)
372 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);