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 ****************************************************************************/
29 #if (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
30 static const unsigned short patterns
[4] = {0xFFFF, 0xFF00, 0x00FF, 0x0000};
33 #if defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
34 void xlcd_scroll_left(int count
)
38 if ((unsigned)count
>= LCD_WIDTH
)
40 rb
->lcd_clear_display();
44 length
= (LCD_WIDTH
-count
)*LCD_FBHEIGHT
;
46 rb
->memmove(rb
->lcd_framebuffer
, rb
->lcd_framebuffer
+ LCD_HEIGHT
*count
,
47 length
* sizeof(fb_data
));
49 oldmode
= rb
->lcd_get_drawmode();
50 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
51 rb
->lcd_fillrect(LCD_WIDTH
-count
, 0, count
, LCD_HEIGHT
);
52 rb
->lcd_set_drawmode(oldmode
);
56 void xlcd_scroll_right(int count
)
60 if ((unsigned)count
>= LCD_WIDTH
)
62 rb
->lcd_clear_display();
66 length
= (LCD_WIDTH
-count
)*LCD_FBHEIGHT
;
68 rb
->memmove(rb
->lcd_framebuffer
+ LCD_HEIGHT
*count
,
69 rb
->lcd_framebuffer
, length
* sizeof(fb_data
));
71 oldmode
= rb
->lcd_get_drawmode();
72 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
73 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
74 rb
->lcd_set_drawmode(oldmode
);
78 void xlcd_scroll_up(int count
)
80 int width
, length
, oldmode
;
84 if ((unsigned)count
>= LCD_HEIGHT
)
86 rb
->lcd_clear_display();
90 length
= LCD_HEIGHT
- count
;
93 data
= rb
->lcd_framebuffer
;
96 rb
->memmove(data
,data
+ count
,length
* sizeof(fb_data
));
100 oldmode
= rb
->lcd_get_drawmode();
101 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
102 rb
->lcd_fillrect(0, length
, LCD_WIDTH
, count
);
103 rb
->lcd_set_drawmode(oldmode
);
107 void xlcd_scroll_down(int count
)
109 int width
, length
, oldmode
;
113 if ((unsigned)count
>= LCD_HEIGHT
)
115 rb
->lcd_clear_display();
119 length
= LCD_HEIGHT
- count
;
122 data
= rb
->lcd_framebuffer
;
125 rb
->memmove(data
+ count
, data
, length
* sizeof(fb_data
));
129 oldmode
= rb
->lcd_get_drawmode();
130 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
131 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
132 rb
->lcd_set_drawmode(oldmode
);
136 #if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) && (LCD_DEPTH < 8)
139 void xlcd_scroll_left(int count
)
141 int bitcount
, oldmode
;
142 int blockcount
, blocklen
;
144 if ((unsigned) count
>= LCD_WIDTH
)
146 rb
->lcd_clear_display();
151 blockcount
= count
>> 2;
152 blocklen
= LCD_FBWIDTH
- blockcount
;
153 bitcount
= 2 * (count
& 3);
158 unsigned char *data
= rb
->lcd_framebuffer
;
159 unsigned char *data_end
= data
+ LCD_FBWIDTH
*LCD_HEIGHT
;
163 rb
->memmove(data
, data
+ blockcount
, blocklen
);
166 while (data
< data_end
);
171 unsigned char *addr
= rb
->lcd_framebuffer
+ blocklen
;
173 unsigned fill
= (0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
;
176 for (y
= 0; y
< LCD_HEIGHT
; y
++)
178 unsigned char *row_addr
= addr
;
179 unsigned data
= fill
;
181 for (bx
= 0; bx
< blocklen
; bx
++)
184 data
= (data
>> 8) | (*row_addr
<< bitcount
);
190 oldmode
= rb
->lcd_get_drawmode();
191 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
192 rb
->lcd_fillrect(LCD_WIDTH
- count
, 0, count
, LCD_HEIGHT
);
193 rb
->lcd_set_drawmode(oldmode
);
197 void xlcd_scroll_right(int count
)
199 int bitcount
, oldmode
;
200 int blockcount
, blocklen
;
202 if ((unsigned) count
>= LCD_WIDTH
)
204 rb
->lcd_clear_display();
209 blockcount
= count
>> 2;
210 blocklen
= LCD_FBWIDTH
- blockcount
;
211 bitcount
= 2 * (count
& 3);
216 unsigned char *data
= rb
->lcd_framebuffer
;
217 unsigned char *data_end
= data
+ LCD_FBWIDTH
*LCD_HEIGHT
;
221 rb
->memmove(data
+ blockcount
, data
, blocklen
);
224 while (data
< data_end
);
229 unsigned char *addr
= rb
->lcd_framebuffer
+ blockcount
;
231 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
234 for (y
= 0; y
< LCD_HEIGHT
; y
++)
236 unsigned char *row_addr
= addr
;
237 unsigned data
= fill
;
239 for (bx
= 0; bx
< blocklen
; bx
++)
241 data
= (data
<< 8) | *row_addr
;
242 *row_addr
= data
>> bitcount
;
248 oldmode
= rb
->lcd_get_drawmode();
249 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
250 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
251 rb
->lcd_set_drawmode(oldmode
);
254 #else /* LCD_PIXELFORMAT vertical packed or >= 8bit / pixel */
257 void xlcd_scroll_left(int count
)
259 fb_data
*data
, *data_end
;
262 if ((unsigned)count
>= LCD_WIDTH
)
264 rb
->lcd_clear_display();
268 data
= rb
->lcd_framebuffer
;
269 data_end
= data
+ LCD_WIDTH
*LCD_FBHEIGHT
;
270 length
= LCD_WIDTH
- count
;
274 rb
->memmove(data
, data
+ count
, length
* sizeof(fb_data
));
277 while (data
< data_end
);
279 oldmode
= rb
->lcd_get_drawmode();
280 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
281 rb
->lcd_fillrect(length
, 0, count
, LCD_HEIGHT
);
282 rb
->lcd_set_drawmode(oldmode
);
286 void xlcd_scroll_right(int count
)
288 fb_data
*data
, *data_end
;
291 if ((unsigned)count
>= LCD_WIDTH
)
293 rb
->lcd_clear_display();
297 data
= rb
->lcd_framebuffer
;
298 data_end
= data
+ LCD_WIDTH
*LCD_FBHEIGHT
;
299 length
= LCD_WIDTH
- count
;
303 rb
->memmove(data
+ count
, data
, length
* sizeof(fb_data
));
306 while (data
< data_end
);
308 oldmode
= rb
->lcd_get_drawmode();
309 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
310 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
311 rb
->lcd_set_drawmode(oldmode
);
314 #endif /* LCD_PIXELFORMAT, LCD_DEPTH */
316 #if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) || (LCD_DEPTH >= 8)
319 void xlcd_scroll_up(int count
)
323 if ((unsigned)count
>= LCD_HEIGHT
)
325 rb
->lcd_clear_display();
329 length
= LCD_HEIGHT
- count
;
331 rb
->memmove(rb
->lcd_framebuffer
,
332 rb
->lcd_framebuffer
+ count
* LCD_FBWIDTH
,
333 length
* LCD_FBWIDTH
* sizeof(fb_data
));
335 oldmode
= rb
->lcd_get_drawmode();
336 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
337 rb
->lcd_fillrect(0, length
, LCD_WIDTH
, count
);
338 rb
->lcd_set_drawmode(oldmode
);
342 void xlcd_scroll_down(int count
)
346 if ((unsigned)count
>= LCD_HEIGHT
)
348 rb
->lcd_clear_display();
352 length
= LCD_HEIGHT
- count
;
354 rb
->memmove(rb
->lcd_framebuffer
+ count
* LCD_FBWIDTH
,
356 length
* LCD_FBWIDTH
* sizeof(fb_data
));
358 oldmode
= rb
->lcd_get_drawmode();
359 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
360 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
361 rb
->lcd_set_drawmode(oldmode
);
364 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING,
365 LCD_PIXELFORMAT == VERTICAL_INTERLEAVED */
368 void xlcd_scroll_up(int count
)
370 int bitcount
, oldmode
;
371 int blockcount
, blocklen
;
373 if ((unsigned) count
>= LCD_HEIGHT
)
375 rb
->lcd_clear_display();
379 #if (LCD_DEPTH == 1) \
380 || (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
381 blockcount
= count
>> 3;
382 bitcount
= count
& 7;
383 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
384 blockcount
= count
>> 2;
385 bitcount
= 2 * (count
& 3);
387 blocklen
= LCD_FBHEIGHT
- blockcount
;
391 rb
->memmove(rb
->lcd_framebuffer
,
392 rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
,
393 blocklen
* LCD_FBWIDTH
* sizeof(fb_data
));
397 #if LCD_PIXELFORMAT == VERTICAL_PACKING
399 #if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
401 "mov #0,r4 \n" /* x = 0 */
402 "mova .su_shifttbl,r0 \n" /* calculate jump destination for */
403 "mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
404 "bra .su_cloop \n" /* skip table */
408 ".su_shifttbl: \n" /* shift jump offset table */
409 ".byte .su_shift0 - .su_shifttbl \n"
410 ".byte .su_shift1 - .su_shifttbl \n"
411 ".byte .su_shift2 - .su_shifttbl \n"
412 ".byte .su_shift3 - .su_shifttbl \n"
413 ".byte .su_shift4 - .su_shifttbl \n"
414 ".byte .su_shift5 - .su_shifttbl \n"
415 ".byte .su_shift6 - .su_shifttbl \n"
416 ".byte .su_shift7 - .su_shifttbl \n"
418 ".su_cloop: \n" /* repeat for every column */
419 "mov %[addr],r2 \n" /* get start address */
420 "mov #0,r3 \n" /* current_row = 0 */
421 "mov #0,r1 \n" /* fill with zero */
423 ".su_iloop: \n" /* repeat for all rows */
424 "sub %[wide],r2 \n" /* address -= width */
425 "mov.b @r2,r0 \n" /* get data byte */
426 "shll8 r1 \n" /* old data to 2nd byte */
427 "extu.b r0,r0 \n" /* extend unsigned */
428 "or r1,r0 \n" /* combine old data */
429 "jmp @%[cnt] \n" /* jump into shift "path" */
430 "extu.b r0,r1 \n" /* store data for next round */
432 ".su_shift6: \n" /* shift right by 0..7 bits */
451 "mov.b r0,@r2 \n" /* store data */
452 "add #1,r3 \n" /* current_row++ */
453 "cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
456 "add #1,%[addr] \n" /* start_address++ */
457 "add #1,r4 \n" /* x++ */
458 "cmp/hi r4,%[wide] \n" /* x < width ? */
462 [addr
]"r"(rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
),
463 [wide
]"r"(LCD_FBWIDTH
),
467 "r0", "r1", "r2", "r3", "r4"
469 #elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
471 "move.l %[wide],%%d3\n" /* columns = width */
473 ".su_cloop: \n" /* repeat for every column */
474 "move.l %[addr],%%a1\n" /* get start address */
475 "move.l %[rows],%%d2\n" /* rows = row_count */
476 "move.l %[bkg],%%d1 \n" /* fill with background */
478 ".su_iloop: \n" /* repeat for all rows */
479 "sub.l %[wide],%%a1\n" /* address -= width */
481 "lsl.l #8,%%d1 \n" /* old data to 2nd byte */
482 "move.b (%%a1),%%d1 \n" /* combine with new data byte */
483 "move.l %%d1,%%d0 \n" /* keep data for next round */
484 "lsr.l %[cnt],%%d0 \n" /* shift right */
485 "move.b %%d0,(%%a1) \n" /* store data */
487 "subq.l #1,%%d2 \n" /* rows-- */
490 "addq.l #1,%[addr] \n" /* start_address++ */
491 "subq.l #1,%%d3 \n" /* columns-- */
495 [wide
]"r"(LCD_FBWIDTH
),
497 [addr
]"a"(rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
),
499 [bkg
] "d"(0x55 * (~rb
->lcd_get_background() & 3))
501 "a1", "d0", "d1", "d2", "d3"
503 #else /* C version */
505 unsigned char *addr
= rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
;
507 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
509 const unsigned fill
= 0;
512 for (x
= 0; x
< LCD_WIDTH
; x
++)
514 unsigned char *col_addr
= addr
++;
515 unsigned data
= fill
;
517 for (by
= 0; by
< blocklen
; by
++)
519 col_addr
-= LCD_FBWIDTH
;
520 data
= (data
<< 8) | *col_addr
;
521 *col_addr
= data
>> bitcount
;
524 #endif /* CPU, LCD_DEPTH */
526 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
530 fb_data
*addr
= rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
;
533 fill
= patterns
[rb
->lcd_get_background() & 3] << 8;
534 mask
= (0xFFu
>> bitcount
) << bitcount
;
537 for (x
= 0; x
< LCD_WIDTH
; x
++)
539 fb_data
*col_addr
= addr
++;
540 unsigned olddata
= fill
;
543 for (by
= 0; by
< blocklen
; by
++)
545 col_addr
-= LCD_FBWIDTH
;
547 *col_addr
= (olddata
^ ((data
^ olddata
) & mask
)) >> bitcount
;
551 #endif /* LCD_DEPTH == 2 */
553 #endif /* LCD_PIXELFORMAT */
555 oldmode
= rb
->lcd_get_drawmode();
556 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
557 rb
->lcd_fillrect(0, LCD_HEIGHT
- count
, LCD_WIDTH
, count
);
558 rb
->lcd_set_drawmode(oldmode
);
562 void xlcd_scroll_down(int count
)
564 int bitcount
, oldmode
;
565 int blockcount
, blocklen
;
567 if ((unsigned) count
>= LCD_HEIGHT
)
569 rb
->lcd_clear_display();
573 #if (LCD_DEPTH == 1) \
574 || (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
575 blockcount
= count
>> 3;
576 bitcount
= count
& 7;
577 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
578 blockcount
= count
>> 2;
579 bitcount
= 2 * (count
& 3);
581 blocklen
= LCD_FBHEIGHT
- blockcount
;
585 rb
->memmove(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
,
587 blocklen
* LCD_FBWIDTH
* sizeof(fb_data
));
591 #if LCD_PIXELFORMAT == VERTICAL_PACKING
593 #if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
595 "mov #0,r4 \n" /* x = 0 */
596 "mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
597 "mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
598 "bra .sd_cloop \n" /* skip table */
602 ".sd_shifttbl: \n" /* shift jump offset table */
603 ".byte .sd_shift0 - .sd_shifttbl \n"
604 ".byte .sd_shift1 - .sd_shifttbl \n"
605 ".byte .sd_shift2 - .sd_shifttbl \n"
606 ".byte .sd_shift3 - .sd_shifttbl \n"
607 ".byte .sd_shift4 - .sd_shifttbl \n"
608 ".byte .sd_shift5 - .sd_shifttbl \n"
609 ".byte .sd_shift6 - .sd_shifttbl \n"
610 ".byte .sd_shift7 - .sd_shifttbl \n"
612 ".sd_cloop: \n" /* repeat for every column */
613 "mov %[addr],r2 \n" /* get start address */
614 "mov #0,r3 \n" /* current_row = 0 */
615 "mov #0,r1 \n" /* fill with zero */
617 ".sd_iloop: \n" /* repeat for all rows */
618 "shlr8 r1 \n" /* shift right to get residue */
619 "mov.b @r2,r0 \n" /* get data byte */
620 "jmp @%[cnt] \n" /* jump into shift "path" */
621 "extu.b r0,r0 \n" /* extend unsigned */
623 ".sd_shift6: \n" /* shift left by 0..7 bits */
642 "or r0,r1 \n" /* combine with last residue */
643 "mov.b r1,@r2 \n" /* store data */
644 "add %[wide],r2 \n" /* address += width */
645 "add #1,r3 \n" /* current_row++ */
646 "cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
649 "add #1,%[addr] \n" /* start_address++ */
650 "add #1,r4 \n" /* x++ */
651 "cmp/hi r4,%[wide] \n" /* x < width ? */
655 [addr
]"r"(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
),
656 [wide
]"r"(LCD_WIDTH
),
660 "r0", "r1", "r2", "r3", "r4"
662 #elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
664 "move.l %[wide],%%d3\n" /* columns = width */
666 ".sd_cloop: \n" /* repeat for every column */
667 "move.l %[addr],%%a1\n" /* get start address */
668 "move.l %[rows],%%d2\n" /* rows = row_count */
669 "move.l %[bkg],%%d1 \n" /* fill with background */
671 ".sd_iloop: \n" /* repeat for all rows */
672 "lsr.l #8,%%d1 \n" /* shift right to get residue */
674 "move.b (%%a1),%%d0 \n" /* get data byte */
675 "lsl.l %[cnt],%%d0 \n"
676 "or.l %%d0,%%d1 \n" /* combine with last residue */
677 "move.b %%d1,(%%a1) \n" /* store data */
679 "add.l %[wide],%%a1\n" /* address += width */
680 "subq.l #1,%%d2 \n" /* rows-- */
683 "lea.l (1,%[addr]),%[addr] \n" /* start_address++ */
684 "subq.l #1,%%d3 \n" /* columns-- */
688 [wide
]"r"(LCD_WIDTH
),
690 [addr
]"a"(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
),
692 [bkg
] "d"((0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
)
694 "a1", "d0", "d1", "d2", "d3"
696 #else /* C version */
698 unsigned char *addr
= rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
;
700 unsigned fill
= (0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
;
702 const unsigned fill
= 0;
705 for (x
= 0; x
< LCD_WIDTH
; x
++)
707 unsigned char *col_addr
= addr
++;
708 unsigned data
= fill
;
710 for (by
= 0; by
< blocklen
; by
++)
712 data
= (data
>> 8) | (*col_addr
<< bitcount
);
714 col_addr
+= LCD_FBWIDTH
;
717 #endif /* CPU, LCD_DEPTH */
719 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
723 fb_data
*addr
= rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
;
726 fill
= patterns
[rb
->lcd_get_background() & 3] >> (8 - bitcount
);
727 mask
= (0xFFu
>> bitcount
) << bitcount
;
730 for (x
= 0; x
< LCD_WIDTH
; x
++)
732 fb_data
*col_addr
= addr
++;
733 unsigned olddata
= fill
;
736 for (by
= 0; by
< blocklen
; by
++)
738 data
= *col_addr
<< bitcount
;
739 *col_addr
= olddata
^ ((data
^ olddata
) & mask
);
741 col_addr
+= LCD_FBWIDTH
;
744 #endif /* LCD_DEPTH == 2 */
746 #endif /* LCD_PIXELFORMAT */
748 oldmode
= rb
->lcd_get_drawmode();
749 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
750 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
751 rb
->lcd_set_drawmode(oldmode
);
754 #endif /* LCD_PIXELFORMAT, LCD_DEPTH */
755 #endif /* defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE */