HDD6330: implement initialization and inversion of lcd.
[kugel-rb.git] / firmware / target / arm / philips / hdd6330 / lcd-hdd6330.c
blob4549f09d2afe0e4215ed9d9f00cec83771b21884
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2009 by Mark Arigo
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 Philips LCD 220x176x16 - model: LPH9165-2 */
28 #define LCD_REG_UNKNOWN_00 0x00
29 #define LCD_REG_UNKNOWN_01 0x01
30 #define LCD_REG_UNKNOWN_05 0x05
31 #define LCD_REG_WRITE_DATA_2_GRAM 0x06
32 #define LCD_REG_HORIZ_ADDR_START 0x08
33 #define LCD_REG_HORIZ_ADDR_END 0x09
34 #define LCD_REG_VERT_ADDR_START 0x0a
35 #define LCD_REG_VERT_ADDR_END 0x0b
37 /* Display status */
38 static unsigned lcd_yuv_options SHAREDBSS_ATTR = 0;
40 /* wait for LCD */
41 static inline void lcd_wait_write(void)
43 while (LCD2_PORT & LCD2_BUSY_MASK);
46 /* send LCD data */
47 static void lcd_send_data(unsigned data)
49 lcd_wait_write();
50 LCD2_PORT = LCD2_DATA_MASK | (data & 0xff);
53 /* send LCD command */
54 static void lcd_send_reg(unsigned reg)
56 lcd_wait_write();
57 LCD2_PORT = LCD2_CMD_MASK | (reg & 0xff);
58 lcd_wait_write();
61 void lcd_init_device(void)
63 lcd_send_reg(LCD_REG_UNKNOWN_00);
64 lcd_send_data(0x00);
65 lcd_send_reg(LCD_REG_UNKNOWN_01);
66 lcd_send_data(0x48);
67 lcd_send_reg(LCD_REG_UNKNOWN_05);
68 lcd_send_data(0x0f);
71 /*** hardware configuration ***/
72 int lcd_default_contrast(void)
74 return DEFAULT_CONTRAST_SETTING;
77 void lcd_set_contrast(int val)
79 (void)val;
82 void lcd_set_invert_display(bool yesno)
84 int invert = (yesno) ? 0x40 : 0x00;
85 lcd_send_reg(LCD_REG_UNKNOWN_00);
86 lcd_send_data(invert);
89 /* turn the display upside down (call lcd_update() afterwards) */
90 void lcd_set_flip(bool yesno)
92 (void)yesno;
95 void lcd_yuv_set_options(unsigned options)
97 lcd_yuv_options = options;
100 #define CSUB_X 2
101 #define CSUB_Y 2
103 /* YUV- > RGB565 conversion
104 * |R| |1.000000 -0.000001 1.402000| |Y'|
105 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
106 * |B| |1.000000 1.772000 0.000000| |Pr|
107 * Scaled, normalized, rounded and tweaked to yield RGB 565:
108 * |R| |74 0 101| |Y' - 16| >> 9
109 * |G| = |74 -24 -51| |Cb - 128| >> 8
110 * |B| |74 128 0| |Cr - 128| >> 9
113 extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc,
114 unsigned char const * const usrc,
115 unsigned char const * const vsrc,
116 int width);
118 /* Performance function to blit a YUV bitmap directly to the LCD */
119 void lcd_blit_yuv(unsigned char * const src[3],
120 int src_x, int src_y, int stride,
121 int x, int y, int width, int height)
123 int h;
125 width = (width + 1) & ~1;
127 lcd_send_reg(LCD_REG_HORIZ_ADDR_START);
128 lcd_send_data(y);
130 lcd_send_reg(LCD_REG_HORIZ_ADDR_END);
131 lcd_send_data(y + height - 1);
133 lcd_send_reg(LCD_REG_VERT_ADDR_START);
134 lcd_send_data(x + 16);
136 lcd_send_reg(LCD_REG_VERT_ADDR_END);
137 lcd_send_data(x + width - 1 + 16);
139 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM);
141 const int stride_div_csub_x = stride/CSUB_X;
143 h=0;
144 while (1)
146 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
147 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
149 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
150 (src_x/CSUB_X);
152 const unsigned char *usrc = src[1] + uvoffset;
153 const unsigned char *vsrc = src[2] + uvoffset;
155 int pixels_to_write;
157 if (h==0)
159 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
160 LCD2_BLOCK_CONFIG = 0;
162 if (height == 0) break;
164 pixels_to_write = (width * height) * 2;
165 h = height;
167 /* calculate how much we can do in one go */
168 if (pixels_to_write > 0x10000)
170 h = (0x10000/2) / width;
171 pixels_to_write = (width * h) * 2;
174 height -= h;
175 LCD2_BLOCK_CTRL = 0x10000080;
176 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
177 LCD2_BLOCK_CTRL = 0x34000000;
180 lcd_yuv_write_inner_loop(ysrc,usrc,vsrc,width);
182 src_y++;
183 h--;
186 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
187 LCD2_BLOCK_CONFIG = 0;
190 /* Update the display.
191 This must be called after all other LCD functions that change the display. */
192 void lcd_update(void)
194 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
197 /* Update a fraction of the display. */
198 void lcd_update_rect(int x, int y, int width, int height)
200 unsigned long *addr;
201 int new_x, new_width;
203 /* Ensure x and width are both even - so we can read 32-bit aligned
204 data from lcd_framebuffer */
205 new_x = x&~1;
206 new_width = width&~1;
207 if (new_x+new_width < x+width) new_width += 2;
208 x = new_x;
209 width = new_width;
211 if (x + width >= LCD_WIDTH)
212 width = LCD_WIDTH - x;
213 if (y + height >= LCD_HEIGHT)
214 height = LCD_HEIGHT - y;
216 if ((width <= 0) || (height <= 0))
217 return; /* Nothing left to do. */
219 lcd_send_reg(LCD_REG_HORIZ_ADDR_START);
220 lcd_send_data(y);
222 lcd_send_reg(LCD_REG_HORIZ_ADDR_END);
223 lcd_send_data(y + height - 1);
225 lcd_send_reg(LCD_REG_VERT_ADDR_START);
226 lcd_send_data(x + 16);
228 lcd_send_reg(LCD_REG_VERT_ADDR_END);
229 lcd_send_data(x + width - 1 + 16);
231 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM);
233 addr = (unsigned long*)&lcd_framebuffer[y][x];
235 while (height > 0)
237 int c, r;
238 int h, pixels_to_write;
240 pixels_to_write = (width * height) * 2;
241 h = height;
243 /* calculate how much we can do in one go */
244 if (pixels_to_write > 0x10000)
246 h = (0x10000/2) / width;
247 pixels_to_write = (width * h) * 2;
250 LCD2_BLOCK_CTRL = 0x10000080;
251 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
252 LCD2_BLOCK_CTRL = 0x34000000;
254 /* for each row */
255 for (r = 0; r < h; r++)
257 /* for each column */
258 for (c = 0; c < width; c += 2)
260 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK));
262 /* output 2 pixels */
263 LCD2_BLOCK_DATA = *addr++;
265 addr += (LCD_WIDTH - width)/2;
268 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
269 LCD2_BLOCK_CONFIG = 0;
271 height -= h;