summaryrefslogtreecommitdiff
path: root/firmware/target/arm/ipod/lcd-color_nano.c
diff options
context:
space:
mode:
Diffstat (limited to 'firmware/target/arm/ipod/lcd-color_nano.c')
-rw-r--r--firmware/target/arm/ipod/lcd-color_nano.c230
1 files changed, 78 insertions, 152 deletions
diff --git a/firmware/target/arm/ipod/lcd-color_nano.c b/firmware/target/arm/ipod/lcd-color_nano.c
index e3b9ea8eb6..8cff7bda21 100644
--- a/firmware/target/arm/ipod/lcd-color_nano.c
+++ b/firmware/target/arm/ipod/lcd-color_nano.c
@@ -32,6 +32,9 @@
32#include "system.h" 32#include "system.h"
33#include "hwcompat.h" 33#include "hwcompat.h"
34 34
35/*** macros ***/
36#define SWAP_INT(X,Y) {int tmp=X; X=Y; Y=tmp;}
37
35/* LCD command codes for HD66789R */ 38/* LCD command codes for HD66789R */
36#define LCD_CNTL_RAM_ADDR_SET 0x21 39#define LCD_CNTL_RAM_ADDR_SET 0x21
37#define LCD_CNTL_WRITE_TO_GRAM 0x22 40#define LCD_CNTL_WRITE_TO_GRAM 0x22
@@ -120,25 +123,11 @@ void lcd_init_device(void)
120#endif 123#endif
121} 124}
122 125
123/*** update functions ***/ 126/* Helper function to set up drawing region and start drawing */
124extern void lcd_yuv_write_inner_loop(unsigned char const * const ysrc, 127static void lcd_setup_drawing_region(int x, int y, int width, int height)
125 unsigned char const * const usrc,
126 unsigned char const * const vsrc,
127 int width);
128
129#define CSUB_X 2
130#define CSUB_Y 2
131
132/* Performance function to blit a YUV bitmap directly to the LCD */
133void lcd_blit_yuv(unsigned char * const src[3],
134 int src_x, int src_y, int stride,
135 int x, int y, int width, int height)
136{ 128{
137 int h;
138 int y0, x0, y1, x1; 129 int y0, x0, y1, x1;
139 130
140 width = (width + 1) & ~1;
141
142 /* calculate the drawing region */ 131 /* calculate the drawing region */
143#if CONFIG_LCD == LCD_IPODNANO 132#if CONFIG_LCD == LCD_IPODNANO
144 y0 = x; /* start horiz */ 133 y0 = x; /* start horiz */
@@ -159,21 +148,8 @@ void lcd_blit_yuv(unsigned char * const src[3],
159 lcd_cmd_data(0x15, y1); /* end vert */ 148 lcd_cmd_data(0x15, y1); /* end vert */
160 lcd_cmd_data(0x16, x1); /* end horiz */ 149 lcd_cmd_data(0x16, x1); /* end horiz */
161 } else { 150 } else {
162 /* swap max horiz < start horiz */ 151 if (y1 < y0) SWAP_INT(y0,y1) /* swap max horiz < start horiz */
163 if (y1 < y0) { 152 if (x1 < x0) SWAP_INT(x0,x1) /* swap max vert < start vert */
164 int t;
165 t = y0;
166 y0 = y1;
167 y1 = t;
168 }
169
170 /* swap max vert < start vert */
171 if (x1 < x0) {
172 int t;
173 t = x0;
174 x0 = x1;
175 x1 = t;
176 }
177 153
178 /* max horiz << 8 | start horiz */ 154 /* max horiz << 8 | start horiz */
179 lcd_cmd_data(LCD_CNTL_HORIZ_RAM_ADDR_POS, (y1 << 8) | y0); 155 lcd_cmd_data(LCD_CNTL_HORIZ_RAM_ADDR_POS, (y1 << 8) | y0);
@@ -194,167 +170,117 @@ void lcd_blit_yuv(unsigned char * const src[3],
194 LCD2_PORT = LCD2_CMD_MASK; 170 LCD2_PORT = LCD2_CMD_MASK;
195 LCD2_PORT = (LCD2_CMD_MASK|LCD_CNTL_WRITE_TO_GRAM); 171 LCD2_PORT = (LCD2_CMD_MASK|LCD_CNTL_WRITE_TO_GRAM);
196 } 172 }
173}
197 174
198 const int stride_div_csub_x = stride/CSUB_X; 175/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
199 176extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
200 h=0; 177 const unsigned int lcd_baseadress,
201 while (1) 178 int width,
202 { 179 int stride);
203 /* upsampling, YUV->RGB conversion and reduction to RGB565 in one go */
204 const unsigned char *ysrc = src[0] + stride * src_y + src_x;
205
206 const int uvoffset = stride_div_csub_x * (src_y/CSUB_Y) +
207 (src_x/CSUB_X);
208 180
209 const unsigned char *usrc = src[1] + uvoffset; 181/* Performance function to blit a YUV bitmap directly to the LCD */
210 const unsigned char *vsrc = src[2] + uvoffset; 182void lcd_blit_yuv(unsigned char * const src[3],
183 int src_x, int src_y, int stride,
184 int x, int y, int width, int height)
185{
186 int z;
187 unsigned char const * yuv_src[3];
211 188
212 int pixels_to_write; 189 width = (width + 1) & ~1; /* ensure width is even */
190 height = (height + 1) & ~1; /* ensure height is even */
213 191
214 if (h==0) 192 lcd_setup_drawing_region(x, y, width, height);
215 {
216 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
217 LCD2_BLOCK_CONFIG = 0;
218 193
219 if (height == 0) break; 194 z = stride * src_y;
195 yuv_src[0] = src[0] + z + src_x;
196 yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
197 yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
220 198
221 pixels_to_write = (width * height) * 2; 199 while (height > 0) {
222 h = height; 200 int r, h, pixels_to_write;
223 201
224 /* calculate how much we can do in one go */ 202 pixels_to_write = (width * height) * 2;
225 if (pixels_to_write > 0x10000) 203 h = height;
226 {
227 h = (0x10000/2) / width;
228 pixels_to_write = (width * h) * 2;
229 }
230 204
231 height -= h; 205 /* calculate how much we can do in one go */
232 LCD2_BLOCK_CTRL = 0x10000080; 206 if (pixels_to_write > 0x10000) {
233 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); 207 h = ((0x10000/2) / width) & ~1; /* ensure h is even */
234 LCD2_BLOCK_CTRL = 0x34000000; 208 pixels_to_write = (width * h) * 2;
235 } 209 }
236 210
237 lcd_yuv_write_inner_loop(ysrc,usrc,vsrc,width); 211 LCD2_BLOCK_CTRL = 0x10000080;
238 212 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
239 src_y++; 213 LCD2_BLOCK_CTRL = 0x34000000;
240 h--; 214
215 r = h>>1; /* lcd_write_yuv420_lines writes two lines at once */
216 do {
217 lcd_write_yuv420_lines(yuv_src, LCD2_BASE, width, stride);
218 yuv_src[0] += stride << 1;
219 yuv_src[1] += stride >> 1;
220 yuv_src[2] += stride >> 1;
221 } while (--r > 0);
222
223 /* transfer of pixels_to_write bytes finished */
224 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
225 LCD2_BLOCK_CONFIG = 0;
226
227 height -= h;
241 } 228 }
242
243 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
244 LCD2_BLOCK_CONFIG = 0;
245} 229}
246 230
231/* Helper function writes 'count' consecutive pixels from src to LCD IF */
232static void lcd_write_line(int count, unsigned long *src)
233{
234 do {
235 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); /* FIFO wait */
236 LCD2_BLOCK_DATA = *src++; /* output 2 pixels */
237 count -= 2;
238 } while (count > 0);
239}
247 240
248/* Update a fraction of the display. */ 241/* Update a fraction of the display. */
249void lcd_update_rect(int x, int y, int width, int height) 242void lcd_update_rect(int x, int y, int width, int height)
250{ 243{
251 int y0, x0, y1, x1;
252 int newx,newwidth;
253 unsigned long *addr; 244 unsigned long *addr;
254 245
255 /* Ensure x and width are both even - so we can read 32-bit aligned 246 /* Ensure both x and width are even to be able to read 32-bit aligned
256 data from lcd_framebuffer */ 247 * data from lcd_framebuffer */
257 newx=x&~1; 248 x = x & ~1; /* use the smaller even number */
258 newwidth=width&~1; 249 width = (width + 1) & ~1; /* use the bigger even number */
259 if (newx+newwidth < x+width) { newwidth+=2; }
260 x=newx; width=newwidth;
261 250
262 /* calculate the drawing region */ 251 lcd_setup_drawing_region(x, y, width, height);
263#if CONFIG_LCD == LCD_IPODNANO
264 y0 = x; /* start horiz */
265 x0 = y; /* start vert */
266 y1 = (x + width) - 1; /* max horiz */
267 x1 = (y + height) - 1; /* max vert */
268#elif CONFIG_LCD == LCD_IPODCOLOR
269 y0 = y; /* start vert */
270 x0 = (LCD_WIDTH - 1) - x; /* start horiz */
271 y1 = (y + height) - 1; /* end vert */
272 x1 = (x0 - width) + 1; /* end horiz */
273#endif
274 /* setup the drawing region */
275 if (lcd_type == 0) {
276 lcd_cmd_data(0x12, y0); /* start vert */
277 lcd_cmd_data(0x13, x0); /* start horiz */
278 lcd_cmd_data(0x15, y1); /* end vert */
279 lcd_cmd_data(0x16, x1); /* end horiz */
280 } else {
281 /* swap max horiz < start horiz */
282 if (y1 < y0) {
283 int t;
284 t = y0;
285 y0 = y1;
286 y1 = t;
287 }
288
289 /* swap max vert < start vert */
290 if (x1 < x0) {
291 int t;
292 t = x0;
293 x0 = x1;
294 x1 = t;
295 }
296
297 /* max horiz << 8 | start horiz */
298 lcd_cmd_data(LCD_CNTL_HORIZ_RAM_ADDR_POS, (y1 << 8) | y0);
299 /* max vert << 8 | start vert */
300 lcd_cmd_data(LCD_CNTL_VERT_RAM_ADDR_POS, (x1 << 8) | x0);
301
302 /* start vert = max vert */
303#if CONFIG_LCD == LCD_IPODCOLOR
304 x0 = x1;
305#endif
306
307 /* position cursor (set AD0-AD15) */
308 /* start vert << 8 | start horiz */
309 lcd_cmd_data(LCD_CNTL_RAM_ADDR_SET, ((x0 << 8) | y0));
310
311 /* start drawing */
312 lcd_wait_write();
313 LCD2_PORT = LCD2_CMD_MASK;
314 LCD2_PORT = (LCD2_CMD_MASK|LCD_CNTL_WRITE_TO_GRAM);
315 }
316 252
317 addr = (unsigned long*)&lcd_framebuffer[y][x]; 253 addr = (unsigned long*)&lcd_framebuffer[y][x];
318 254
319 while (height > 0) { 255 while (height > 0) {
320 int c, r; 256 int r, h, pixels_to_write;
321 int h, pixels_to_write;
322 257
323 pixels_to_write = (width * height) * 2; 258 pixels_to_write = (width * height) * 2;
324 h = height; 259 h = height;
325 260
326 /* calculate how much we can do in one go */ 261 /* calculate how much we can do in one go */
327 if (pixels_to_write > 0x10000) { 262 if (pixels_to_write > 0x10000) {
328 h = (0x10000/2) / width; 263 h = ((0x10000/2) / width) & ~1; /* ensure h is even */
329 pixels_to_write = (width * h) * 2; 264 pixels_to_write = (width * h) * 2;
330 } 265 }
331 266
332 LCD2_BLOCK_CTRL = 0x10000080; 267 LCD2_BLOCK_CTRL = 0x10000080;
333 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1); 268 LCD2_BLOCK_CONFIG = 0xc0010000 | (pixels_to_write - 1);
334 LCD2_BLOCK_CTRL = 0x34000000; 269 LCD2_BLOCK_CTRL = 0x34000000;
335 270
336 if (LCD_WIDTH == width) { 271 if (LCD_WIDTH == width) {
337 /* for each row and column in a single loop */ 272 /* for each row and column in a single call */
338 for (r = 0; r < h*width; r += 2) { 273 lcd_write_line(h*width, addr);
339 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK)); 274 addr += LCD_WIDTH/2*h;
340
341 /* output 2 pixels */
342 LCD2_BLOCK_DATA = *addr++;
343 }
344 } else { 275 } else {
345 /* for each row */ 276 /* for each row */
346 for (r = 0; r < h; r++) { 277 for (r = 0; r < h; r++) {
347 /* for each column */ 278 lcd_write_line(width, addr);
348 for (c = 0; c < width; c += 2) { 279 addr += LCD_WIDTH/2;
349 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_TXOK));
350
351 /* output 2 pixels */
352 LCD2_BLOCK_DATA = *addr++;
353 }
354 addr += (LCD_WIDTH - width)/2;
355 } 280 }
356 } 281 }
357 282
283 /* transfer of pixels_to_write bytes finished */
358 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY)); 284 while (!(LCD2_BLOCK_CTRL & LCD2_BLOCK_READY));
359 LCD2_BLOCK_CONFIG = 0; 285 LCD2_BLOCK_CONFIG = 0;
360 286