1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Additional LCD routines not present in the rockbox core
13 * Copyright (C) 2005 Jens Arnold
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
27 #ifdef HAVE_LCD_BITMAP
30 #if (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
31 static const unsigned short patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
34 #if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) && (LCD_DEPTH < 8)
37 void xlcd_scroll_left(int count
)
39 int bitcount
, oldmode
;
40 int blockcount
, blocklen
;
42 if ((unsigned) count
>= LCD_WIDTH
)
46 blockcount
= count
>> 2;
47 blocklen
= LCD_FBWIDTH
- blockcount
;
48 bitcount
= 2 * (count
& 3);
53 unsigned char *data
= rb
->lcd_framebuffer
;
54 unsigned char *data_end
= data
+ LCD_FBWIDTH
*LCD_HEIGHT
;
58 rb
->memmove(data
, data
+ blockcount
, blocklen
);
61 while (data
< data_end
);
66 unsigned char *addr
= rb
->lcd_framebuffer
+ blocklen
;
68 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
71 for (y
= 0; y
< LCD_HEIGHT
; y
++)
73 unsigned char *row_addr
= addr
;
76 for (bx
= 0; bx
< blocklen
; bx
++)
79 data
= (data
>> 8) | (*row_addr
<< bitcount
);
85 oldmode
= rb
->lcd_get_drawmode();
86 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
87 rb
->lcd_fillrect(LCD_WIDTH
- count
, 0, count
, LCD_HEIGHT
);
88 rb
->lcd_set_drawmode(oldmode
);
92 void xlcd_scroll_right(int count
)
94 int bitcount
, oldmode
;
95 int blockcount
, blocklen
;
97 if ((unsigned) count
>= LCD_WIDTH
)
101 blockcount
= count
>> 2;
102 blocklen
= LCD_FBWIDTH
- blockcount
;
103 bitcount
= 2 * (count
& 3);
108 unsigned char *data
= rb
->lcd_framebuffer
;
109 unsigned char *data_end
= data
+ LCD_FBWIDTH
*LCD_HEIGHT
;
113 rb
->memmove(data
+ blockcount
, data
, blocklen
);
116 while (data
< data_end
);
121 unsigned char *addr
= rb
->lcd_framebuffer
+ blockcount
;
123 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
126 for (y
= 0; y
< LCD_HEIGHT
; y
++)
128 unsigned char *row_addr
= addr
;
129 unsigned data
= fill
;
131 for (bx
= 0; bx
< blocklen
; bx
++)
133 data
= (data
<< 8) | *row_addr
;
134 *row_addr
= data
>> bitcount
;
140 oldmode
= rb
->lcd_get_drawmode();
141 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
142 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
143 rb
->lcd_set_drawmode(oldmode
);
146 #else /* LCD_PIXELFORMAT vertical packed or >= 8bit / pixel */
149 void xlcd_scroll_left(int count
)
151 fb_data
*data
, *data_end
;
154 if ((unsigned)count
>= LCD_WIDTH
)
157 data
= rb
->lcd_framebuffer
;
158 data_end
= data
+ LCD_WIDTH
*LCD_FBHEIGHT
;
159 length
= LCD_WIDTH
- count
;
163 rb
->memmove(data
, data
+ count
, length
* sizeof(fb_data
));
166 while (data
< data_end
);
168 oldmode
= rb
->lcd_get_drawmode();
169 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
170 rb
->lcd_fillrect(length
, 0, count
, LCD_HEIGHT
);
171 rb
->lcd_set_drawmode(oldmode
);
175 void xlcd_scroll_right(int count
)
177 fb_data
*data
, *data_end
;
180 if ((unsigned)count
>= LCD_WIDTH
)
183 data
= rb
->lcd_framebuffer
;
184 data_end
= data
+ LCD_WIDTH
*LCD_FBHEIGHT
;
185 length
= LCD_WIDTH
- count
;
189 rb
->memmove(data
+ count
, data
, length
* sizeof(fb_data
));
192 while (data
< data_end
);
194 oldmode
= rb
->lcd_get_drawmode();
195 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
196 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
197 rb
->lcd_set_drawmode(oldmode
);
200 #endif /* LCD_PIXELFORMAT, LCD_DEPTH */
202 #if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) || (LCD_DEPTH >= 8)
205 void xlcd_scroll_up(int count
)
209 if ((unsigned)count
>= LCD_HEIGHT
)
212 length
= LCD_HEIGHT
- count
;
214 rb
->memmove(rb
->lcd_framebuffer
,
215 rb
->lcd_framebuffer
+ count
* LCD_FBWIDTH
,
216 length
* LCD_FBWIDTH
* sizeof(fb_data
));
218 oldmode
= rb
->lcd_get_drawmode();
219 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
220 rb
->lcd_fillrect(0, length
, LCD_WIDTH
, count
);
221 rb
->lcd_set_drawmode(oldmode
);
225 void xlcd_scroll_down(int count
)
229 if ((unsigned)count
>= LCD_HEIGHT
)
232 length
= LCD_HEIGHT
- count
;
234 rb
->memmove(rb
->lcd_framebuffer
+ count
* LCD_FBWIDTH
,
236 length
* LCD_FBWIDTH
* sizeof(fb_data
));
238 oldmode
= rb
->lcd_get_drawmode();
239 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
240 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
241 rb
->lcd_set_drawmode(oldmode
);
244 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING,
245 LCD_PIXELFORMAT == VERTICAL_INTERLEAVED */
248 void xlcd_scroll_up(int count
)
250 int bitcount
, oldmode
;
251 int blockcount
, blocklen
;
253 if ((unsigned) count
>= LCD_HEIGHT
)
256 #if (LCD_DEPTH == 1) \
257 || (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
258 blockcount
= count
>> 3;
259 bitcount
= count
& 7;
260 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
261 blockcount
= count
>> 2;
262 bitcount
= 2 * (count
& 3);
264 blocklen
= LCD_FBHEIGHT
- blockcount
;
268 rb
->memmove(rb
->lcd_framebuffer
,
269 rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
,
270 blocklen
* LCD_FBWIDTH
* sizeof(fb_data
));
274 #if LCD_PIXELFORMAT == VERTICAL_PACKING
276 #if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
278 "mov #0,r4 \n" /* x = 0 */
279 "mova .su_shifttbl,r0 \n" /* calculate jump destination for */
280 "mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
281 "bra .su_cloop \n" /* skip table */
285 ".su_shifttbl: \n" /* shift jump offset table */
286 ".byte .su_shift0 - .su_shifttbl \n"
287 ".byte .su_shift1 - .su_shifttbl \n"
288 ".byte .su_shift2 - .su_shifttbl \n"
289 ".byte .su_shift3 - .su_shifttbl \n"
290 ".byte .su_shift4 - .su_shifttbl \n"
291 ".byte .su_shift5 - .su_shifttbl \n"
292 ".byte .su_shift6 - .su_shifttbl \n"
293 ".byte .su_shift7 - .su_shifttbl \n"
295 ".su_cloop: \n" /* repeat for every column */
296 "mov %[addr],r2 \n" /* get start address */
297 "mov #0,r3 \n" /* current_row = 0 */
298 "mov #0,r1 \n" /* fill with zero */
300 ".su_iloop: \n" /* repeat for all rows */
301 "sub %[wide],r2 \n" /* address -= width */
302 "mov.b @r2,r0 \n" /* get data byte */
303 "shll8 r1 \n" /* old data to 2nd byte */
304 "extu.b r0,r0 \n" /* extend unsigned */
305 "or r1,r0 \n" /* combine old data */
306 "jmp @%[cnt] \n" /* jump into shift "path" */
307 "extu.b r0,r1 \n" /* store data for next round */
309 ".su_shift6: \n" /* shift right by 0..7 bits */
328 "mov.b r0,@r2 \n" /* store data */
329 "add #1,r3 \n" /* current_row++ */
330 "cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
333 "add #1,%[addr] \n" /* start_address++ */
334 "add #1,r4 \n" /* x++ */
335 "cmp/hi r4,%[wide] \n" /* x < width ? */
339 [addr
]"r"(rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
),
340 [wide
]"r"(LCD_FBWIDTH
),
344 "r0", "r1", "r2", "r3", "r4"
346 #elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
348 "move.l %[wide],%%d3\n" /* columns = width */
350 ".su_cloop: \n" /* repeat for every column */
351 "move.l %[addr],%%a1\n" /* get start address */
352 "move.l %[rows],%%d2\n" /* rows = row_count */
353 "move.l %[bkg],%%d1 \n" /* fill with background */
355 ".su_iloop: \n" /* repeat for all rows */
356 "sub.l %[wide],%%a1\n" /* address -= width */
359 "move.b (%%a1),%%d0 \n" /* get data byte */
360 "lsl.l #8,%%d1 \n" /* old data to 2nd byte */
361 "or.l %%d1,%%d0 \n" /* combine old data */
363 "move.b %%d0,%%d1 \n" /* keep data for next round */
364 "lsr.l %[cnt],%%d0 \n" /* shift right */
365 "move.b %%d0,(%%a1) \n" /* store data */
367 "subq.l #1,%%d2 \n" /* rows-- */
370 "addq.l #1,%[addr] \n" /* start_address++ */
371 "subq.l #1,%%d3 \n" /* columns-- */
375 [wide
]"r"(LCD_FBWIDTH
),
377 [addr
]"a"(rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
),
379 [bkg
] "d"(0x55 * (~rb
->lcd_get_background() & 3))
381 "a1", "d0", "d1", "d2", "d3"
383 #else /* C version */
385 unsigned char *addr
= rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
;
387 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
389 const unsigned fill
= 0;
392 for (x
= 0; x
< LCD_WIDTH
; x
++)
394 unsigned char *col_addr
= addr
++;
395 unsigned data
= fill
;
397 for (by
= 0; by
< blocklen
; by
++)
399 col_addr
-= LCD_FBWIDTH
;
400 data
= (data
<< 8) | *col_addr
;
401 *col_addr
= data
>> bitcount
;
404 #endif /* CPU, LCD_DEPTH */
406 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
410 fb_data
*addr
= rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
;
413 fill
= patterns
[rb
->lcd_get_background() & 3] << 8;
414 mask
= (0xFFu
>> bitcount
) << bitcount
;
417 for (x
= 0; x
< LCD_WIDTH
; x
++)
419 fb_data
*col_addr
= addr
++;
420 unsigned olddata
= fill
;
423 for (by
= 0; by
< blocklen
; by
++)
425 col_addr
-= LCD_FBWIDTH
;
427 *col_addr
= (olddata
^ ((data
^ olddata
) & mask
)) >> bitcount
;
431 #endif /* LCD_DEPTH == 2 */
433 #endif /* LCD_PIXELFORMAT */
435 oldmode
= rb
->lcd_get_drawmode();
436 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
437 rb
->lcd_fillrect(0, LCD_HEIGHT
- count
, LCD_WIDTH
, count
);
438 rb
->lcd_set_drawmode(oldmode
);
442 void xlcd_scroll_down(int count
)
444 int bitcount
, oldmode
;
445 int blockcount
, blocklen
;
447 if ((unsigned) count
>= LCD_HEIGHT
)
450 #if (LCD_DEPTH == 1) \
451 || (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
452 blockcount
= count
>> 3;
453 bitcount
= count
& 7;
454 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
455 blockcount
= count
>> 2;
456 bitcount
= 2 * (count
& 3);
458 blocklen
= LCD_FBHEIGHT
- blockcount
;
462 rb
->memmove(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
,
464 blocklen
* LCD_FBWIDTH
* sizeof(fb_data
));
468 #if LCD_PIXELFORMAT == VERTICAL_PACKING
470 #if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
472 "mov #0,r4 \n" /* x = 0 */
473 "mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
474 "mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
475 "bra .sd_cloop \n" /* skip table */
479 ".sd_shifttbl: \n" /* shift jump offset table */
480 ".byte .sd_shift0 - .sd_shifttbl \n"
481 ".byte .sd_shift1 - .sd_shifttbl \n"
482 ".byte .sd_shift2 - .sd_shifttbl \n"
483 ".byte .sd_shift3 - .sd_shifttbl \n"
484 ".byte .sd_shift4 - .sd_shifttbl \n"
485 ".byte .sd_shift5 - .sd_shifttbl \n"
486 ".byte .sd_shift6 - .sd_shifttbl \n"
487 ".byte .sd_shift7 - .sd_shifttbl \n"
489 ".sd_cloop: \n" /* repeat for every column */
490 "mov %[addr],r2 \n" /* get start address */
491 "mov #0,r3 \n" /* current_row = 0 */
492 "mov #0,r1 \n" /* fill with zero */
494 ".sd_iloop: \n" /* repeat for all rows */
495 "shlr8 r1 \n" /* shift right to get residue */
496 "mov.b @r2,r0 \n" /* get data byte */
497 "jmp @%[cnt] \n" /* jump into shift "path" */
498 "extu.b r0,r0 \n" /* extend unsigned */
500 ".sd_shift6: \n" /* shift left by 0..7 bits */
519 "or r0,r1 \n" /* combine with last residue */
520 "mov.b r1,@r2 \n" /* store data */
521 "add %[wide],r2 \n" /* address += width */
522 "add #1,r3 \n" /* current_row++ */
523 "cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
526 "add #1,%[addr] \n" /* start_address++ */
527 "add #1,r4 \n" /* x++ */
528 "cmp/hi r4,%[wide] \n" /* x < width ? */
532 [addr
]"r"(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
),
533 [wide
]"r"(LCD_WIDTH
),
537 "r0", "r1", "r2", "r3", "r4"
539 #elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
541 "move.l %[wide],%%d3\n" /* columns = width */
543 ".sd_cloop: \n" /* repeat for every column */
544 "move.l %[addr],%%a1\n" /* get start address */
545 "move.l %[rows],%%d2\n" /* rows = row_count */
546 "move.l %[bkg],%%d1 \n" /* fill with background */
548 ".sd_iloop: \n" /* repeat for all rows */
549 "lsr.l #8,%%d1 \n" /* shift right to get residue */
551 "move.b (%%a1),%%d0 \n" /* get data byte */
552 "lsl.l %[cnt],%%d0 \n"
553 "or.l %%d0,%%d1 \n" /* combine with last residue */
554 "move.b %%d1,(%%a1) \n" /* store data */
556 "add.l %[wide],%%a1\n" /* address += width */
557 "subq.l #1,%%d2 \n" /* rows-- */
560 "lea.l (1,%[addr]),%[addr] \n" /* start_address++ */
561 "subq.l #1,%%d3 \n" /* columns-- */
565 [wide
]"r"(LCD_WIDTH
),
567 [addr
]"a"(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
),
569 [bkg
] "d"((0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
)
571 "a1", "d0", "d1", "d2", "d3"
573 #else /* C version */
575 unsigned char *addr
= rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
;
577 unsigned fill
= (0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
;
579 const unsigned fill
= 0;
582 for (x
= 0; x
< LCD_WIDTH
; x
++)
584 unsigned char *col_addr
= addr
++;
585 unsigned data
= fill
;
587 for (by
= 0; by
< blocklen
; by
++)
589 data
= (data
>> 8) | (*col_addr
<< bitcount
);
591 col_addr
+= LCD_FBWIDTH
;
594 #endif /* CPU, LCD_DEPTH */
596 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
600 fb_data
*addr
= rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
;
603 fill
= patterns
[rb
->lcd_get_background() & 3] >> (8 - bitcount
);
604 mask
= (0xFFu
>> bitcount
) << bitcount
;
607 for (x
= 0; x
< LCD_WIDTH
; x
++)
609 fb_data
*col_addr
= addr
++;
610 unsigned olddata
= fill
;
613 for (by
= 0; by
< blocklen
; by
++)
615 data
= *col_addr
<< bitcount
;
616 *col_addr
= olddata
^ ((data
^ olddata
) & mask
);
618 col_addr
+= LCD_FBWIDTH
;
621 #endif /* LCD_DEPTH == 2 */
623 #endif /* LCD_PIXELFORMAT */
625 oldmode
= rb
->lcd_get_drawmode();
626 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
627 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
628 rb
->lcd_set_drawmode(oldmode
);
631 #endif /* LCD_PIXELFORMAT, LCD_DEPTH */
633 #endif /* HAVE_LCD_BITMAP */