HDD6330: implement lcd_set_flip() function.
[kugel-rb.git] / firmware / target / arm / philips / hdd6330 / lcd-hdd6330.c
blob86006c9636d7903b6314b39c9aa3cbfe5ea43478
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 /* Used for flip offset correction */
41 static int x_offset;
43 /* wait for LCD */
44 static inline void lcd_wait_write(void)
46 while (LCD2_PORT & LCD2_BUSY_MASK);
49 /* send LCD data */
50 static void lcd_send_data(unsigned data)
52 lcd_wait_write();
53 LCD2_PORT = LCD2_DATA_MASK | (data & 0xff);
56 /* send LCD command */
57 static void lcd_send_reg(unsigned reg)
59 lcd_wait_write();
60 LCD2_PORT = LCD2_CMD_MASK | (reg & 0xff);
61 lcd_wait_write();
64 void lcd_init_device(void)
66 lcd_send_reg(LCD_REG_UNKNOWN_00);
67 lcd_send_data(0x00);
68 lcd_send_reg(LCD_REG_UNKNOWN_01);
69 lcd_send_data(0x48);
70 lcd_send_reg(LCD_REG_UNKNOWN_05);
71 lcd_send_data(0x0f);
73 x_offset = 16;
76 /*** hardware configuration ***/
77 int lcd_default_contrast(void)
79 return DEFAULT_CONTRAST_SETTING;
82 void lcd_set_contrast(int val)
84 (void)val;
87 void lcd_set_invert_display(bool yesno)
89 int invert = (yesno) ? 0x40 : 0x00;
90 lcd_send_reg(LCD_REG_UNKNOWN_00);
91 lcd_send_data(invert);
94 /* turn the display upside down (call lcd_update() afterwards) */
95 void lcd_set_flip(bool yesno)
97 int flip = (yesno) ? 0x88 : 0x48;
98 x_offset = (yesno) ? 4 : 16;
99 lcd_send_reg(LCD_REG_UNKNOWN_01);
100 lcd_send_data(flip);
103 void lcd_yuv_set_options(unsigned options)
105 lcd_yuv_options = options;
108 #define CSUB_X 2
109 #define CSUB_Y 2
111 /* YUV- > RGB565 conversion
112 * |R| |1.000000 -0.000001 1.402000| |Y'|
113 * |G| = |1.000000 -0.334136 -0.714136| |Pb|
114 * |B| |1.000000 1.772000 0.000000| |Pr|
115 * Scaled, normalized, rounded and tweaked to yield RGB 565:
116 * |R| |74 0 101| |Y' - 16| >> 9
117 * |G| = |74 -24 -51| |Cb - 128| >> 8
118 * |B| |74 128 0| |Cr - 128| >> 9
121 extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc,
122 unsigned char const * const usrc,
123 unsigned char const * const vsrc,
124 int width);
126 /* Performance function to blit a YUV bitmap directly to the LCD */
127 void lcd_blit_yuv(unsigned char * const src[3],
128 int src_x, int src_y, int stride,
129 int x, int y, int width, int height)
131 int h;
133 width = (width + 1) & ~1;
135 lcd_send_reg(LCD_REG_HORIZ_ADDR_START);
136 lcd_send_data(y);
138 lcd_send_reg(LCD_REG_HORIZ_ADDR_END);
139 lcd_send_data(y + height - 1);
141 lcd_send_reg(LCD_REG_VERT_ADDR_START);
142 lcd_send_data(x + x_offset);
144 lcd_send_reg(LCD_REG_VERT_ADDR_END);
145 lcd_send_data(x + width - 1 + x_offset);
147 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM);
149 const int stride_div_csub_x = stride/CSUB_X;
151 h=0;
152 while (1)
154 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
155 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
157 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
158 (src_x/CSUB_X);
160 const unsigned char *usrc = src[1] + uvoffset;
161 const unsigned char *vsrc = src[2] + uvoffset;
163 int pixels_to_write;
165 if (h==0)
167 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
168 LCD2_BLOCK_CONFIG = 0;
170 if (height == 0) break;
172 pixels_to_write = (width * height) * 2;
173 h = height;
175 /* calculate how much we can do in one go */
176 if (pixels_to_write > 0x10000)
178 h = (0x10000/2) / width;
179 pixels_to_write = (width * h) * 2;
182 height -= h;
183 LCD2_BLOCK_CTRL = 0x10000080;
184 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
185 LCD2_BLOCK_CTRL = 0x34000000;
188 lcd_yuv_write_inner_loop(ysrc,usrc,vsrc,width);
190 src_y++;
191 h--;
194 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
195 LCD2_BLOCK_CONFIG = 0;
198 /* Update the display.
199 This must be called after all other LCD functions that change the display. */
200 void lcd_update(void)
202 lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
205 /* Update a fraction of the display. */
206 void lcd_update_rect(int x, int y, int width, int height)
208 unsigned long *addr;
209 int new_x, new_width;
211 /* Ensure x and width are both even - so we can read 32-bit aligned
212 data from lcd_framebuffer */
213 new_x = x&~1;
214 new_width = width&~1;
215 if (new_x+new_width < x+width) new_width += 2;
216 x = new_x;
217 width = new_width;
219 if (x + width >= LCD_WIDTH)
220 width = LCD_WIDTH - x;
221 if (y + height >= LCD_HEIGHT)
222 height = LCD_HEIGHT - y;
224 if ((width <= 0) || (height <= 0))
225 return; /* Nothing left to do. */
227 lcd_send_reg(LCD_REG_HORIZ_ADDR_START);
228 lcd_send_data(y);
230 lcd_send_reg(LCD_REG_HORIZ_ADDR_END);
231 lcd_send_data(y + height - 1);
233 lcd_send_reg(LCD_REG_VERT_ADDR_START);
234 lcd_send_data(x + x_offset);
236 lcd_send_reg(LCD_REG_VERT_ADDR_END);
237 lcd_send_data(x + width - 1 + x_offset);
239 lcd_send_reg(LCD_REG_WRITE_DATA_2_GRAM);
241 addr = (unsigned long*)&lcd_framebuffer[y][x];
243 while (height > 0)
245 int c, r;
246 int h, pixels_to_write;
248 pixels_to_write = (width * height) * 2;
249 h = height;
251 /* calculate how much we can do in one go */
252 if (pixels_to_write > 0x10000)
254 h = (0x10000/2) / width;
255 pixels_to_write = (width * h) * 2;
258 LCD2_BLOCK_CTRL = 0x10000080;
259 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
260 LCD2_BLOCK_CTRL = 0x34000000;
262 /* for each row */
263 for (r = 0; r < h; r++)
265 /* for each column */
266 for (c = 0; c < width; c += 2)
268 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK));
270 /* output 2 pixels */
271 LCD2_BLOCK_DATA = *addr++;
273 addr += (LCD_WIDTH - width)/2;
276 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
277 LCD2_BLOCK_CONFIG = 0;
279 height -= h;