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 defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE
35 void xlcd_scroll_left(int count
)
39 if ((unsigned)count
>= LCD_WIDTH
)
41 rb
->lcd_clear_display();
45 length
= (LCD_WIDTH
-count
)*LCD_FBHEIGHT
;
47 rb
->memmove(rb
->lcd_framebuffer
, rb
->lcd_framebuffer
+ LCD_HEIGHT
*count
,
48 length
* sizeof(fb_data
));
50 oldmode
= rb
->lcd_get_drawmode();
51 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
52 rb
->lcd_fillrect(LCD_WIDTH
-count
, 0, count
, LCD_HEIGHT
);
53 rb
->lcd_set_drawmode(oldmode
);
57 void xlcd_scroll_right(int count
)
61 if ((unsigned)count
>= LCD_WIDTH
)
63 rb
->lcd_clear_display();
67 length
= (LCD_WIDTH
-count
)*LCD_FBHEIGHT
;
69 rb
->memmove(rb
->lcd_framebuffer
+ LCD_HEIGHT
*count
,
70 rb
->lcd_framebuffer
, length
* sizeof(fb_data
));
72 oldmode
= rb
->lcd_get_drawmode();
73 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
74 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
75 rb
->lcd_set_drawmode(oldmode
);
79 void xlcd_scroll_up(int count
)
81 int width
, length
, oldmode
;
85 if ((unsigned)count
>= LCD_HEIGHT
)
87 rb
->lcd_clear_display();
91 length
= LCD_HEIGHT
- count
;
94 data
= rb
->lcd_framebuffer
;
97 rb
->memmove(data
,data
+ count
,length
* sizeof(fb_data
));
101 oldmode
= rb
->lcd_get_drawmode();
102 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
103 rb
->lcd_fillrect(0, length
, LCD_WIDTH
, count
);
104 rb
->lcd_set_drawmode(oldmode
);
108 void xlcd_scroll_down(int count
)
110 int width
, length
, oldmode
;
114 if ((unsigned)count
>= LCD_HEIGHT
)
116 rb
->lcd_clear_display();
120 length
= LCD_HEIGHT
- count
;
123 data
= rb
->lcd_framebuffer
;
126 rb
->memmove(data
+ count
, data
, length
* sizeof(fb_data
));
130 oldmode
= rb
->lcd_get_drawmode();
131 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
132 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
133 rb
->lcd_set_drawmode(oldmode
);
137 #if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) && (LCD_DEPTH < 8)
140 void xlcd_scroll_left(int count
)
142 int bitcount
, oldmode
;
143 int blockcount
, blocklen
;
145 if ((unsigned) count
>= LCD_WIDTH
)
147 rb
->lcd_clear_display();
152 blockcount
= count
>> 2;
153 blocklen
= LCD_FBWIDTH
- blockcount
;
154 bitcount
= 2 * (count
& 3);
159 unsigned char *data
= rb
->lcd_framebuffer
;
160 unsigned char *data_end
= data
+ LCD_FBWIDTH
*LCD_HEIGHT
;
164 rb
->memmove(data
, data
+ blockcount
, blocklen
);
167 while (data
< data_end
);
172 unsigned char *addr
= rb
->lcd_framebuffer
+ blocklen
;
174 unsigned fill
= (0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
;
177 for (y
= 0; y
< LCD_HEIGHT
; y
++)
179 unsigned char *row_addr
= addr
;
180 unsigned data
= fill
;
182 for (bx
= 0; bx
< blocklen
; bx
++)
185 data
= (data
>> 8) | (*row_addr
<< bitcount
);
191 oldmode
= rb
->lcd_get_drawmode();
192 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
193 rb
->lcd_fillrect(LCD_WIDTH
- count
, 0, count
, LCD_HEIGHT
);
194 rb
->lcd_set_drawmode(oldmode
);
198 void xlcd_scroll_right(int count
)
200 int bitcount
, oldmode
;
201 int blockcount
, blocklen
;
203 if ((unsigned) count
>= LCD_WIDTH
)
205 rb
->lcd_clear_display();
210 blockcount
= count
>> 2;
211 blocklen
= LCD_FBWIDTH
- blockcount
;
212 bitcount
= 2 * (count
& 3);
217 unsigned char *data
= rb
->lcd_framebuffer
;
218 unsigned char *data_end
= data
+ LCD_FBWIDTH
*LCD_HEIGHT
;
222 rb
->memmove(data
+ blockcount
, data
, blocklen
);
225 while (data
< data_end
);
230 unsigned char *addr
= rb
->lcd_framebuffer
+ blockcount
;
232 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
235 for (y
= 0; y
< LCD_HEIGHT
; y
++)
237 unsigned char *row_addr
= addr
;
238 unsigned data
= fill
;
240 for (bx
= 0; bx
< blocklen
; bx
++)
242 data
= (data
<< 8) | *row_addr
;
243 *row_addr
= data
>> bitcount
;
249 oldmode
= rb
->lcd_get_drawmode();
250 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
251 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
252 rb
->lcd_set_drawmode(oldmode
);
255 #else /* LCD_PIXELFORMAT vertical packed or >= 8bit / pixel */
258 void xlcd_scroll_left(int count
)
260 fb_data
*data
, *data_end
;
263 if ((unsigned)count
>= LCD_WIDTH
)
265 rb
->lcd_clear_display();
269 data
= rb
->lcd_framebuffer
;
270 data_end
= data
+ LCD_WIDTH
*LCD_FBHEIGHT
;
271 length
= LCD_WIDTH
- count
;
275 rb
->memmove(data
, data
+ count
, length
* sizeof(fb_data
));
278 while (data
< data_end
);
280 oldmode
= rb
->lcd_get_drawmode();
281 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
282 rb
->lcd_fillrect(length
, 0, count
, LCD_HEIGHT
);
283 rb
->lcd_set_drawmode(oldmode
);
287 void xlcd_scroll_right(int count
)
289 fb_data
*data
, *data_end
;
292 if ((unsigned)count
>= LCD_WIDTH
)
294 rb
->lcd_clear_display();
298 data
= rb
->lcd_framebuffer
;
299 data_end
= data
+ LCD_WIDTH
*LCD_FBHEIGHT
;
300 length
= LCD_WIDTH
- count
;
304 rb
->memmove(data
+ count
, data
, length
* sizeof(fb_data
));
307 while (data
< data_end
);
309 oldmode
= rb
->lcd_get_drawmode();
310 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
311 rb
->lcd_fillrect(0, 0, count
, LCD_HEIGHT
);
312 rb
->lcd_set_drawmode(oldmode
);
315 #endif /* LCD_PIXELFORMAT, LCD_DEPTH */
317 #if (LCD_PIXELFORMAT == HORIZONTAL_PACKING) || (LCD_DEPTH >= 8)
320 void xlcd_scroll_up(int count
)
324 if ((unsigned)count
>= LCD_HEIGHT
)
326 rb
->lcd_clear_display();
330 length
= LCD_HEIGHT
- count
;
332 rb
->memmove(rb
->lcd_framebuffer
,
333 rb
->lcd_framebuffer
+ count
* LCD_FBWIDTH
,
334 length
* LCD_FBWIDTH
* sizeof(fb_data
));
336 oldmode
= rb
->lcd_get_drawmode();
337 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
338 rb
->lcd_fillrect(0, length
, LCD_WIDTH
, count
);
339 rb
->lcd_set_drawmode(oldmode
);
343 void xlcd_scroll_down(int count
)
347 if ((unsigned)count
>= LCD_HEIGHT
)
349 rb
->lcd_clear_display();
353 length
= LCD_HEIGHT
- count
;
355 rb
->memmove(rb
->lcd_framebuffer
+ count
* LCD_FBWIDTH
,
357 length
* LCD_FBWIDTH
* sizeof(fb_data
));
359 oldmode
= rb
->lcd_get_drawmode();
360 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
361 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
362 rb
->lcd_set_drawmode(oldmode
);
365 #else /* LCD_PIXELFORMAT == VERTICAL_PACKING,
366 LCD_PIXELFORMAT == VERTICAL_INTERLEAVED */
369 void xlcd_scroll_up(int count
)
371 int bitcount
, oldmode
;
372 int blockcount
, blocklen
;
374 if ((unsigned) count
>= LCD_HEIGHT
)
376 rb
->lcd_clear_display();
380 #if (LCD_DEPTH == 1) \
381 || (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
382 blockcount
= count
>> 3;
383 bitcount
= count
& 7;
384 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
385 blockcount
= count
>> 2;
386 bitcount
= 2 * (count
& 3);
388 blocklen
= LCD_FBHEIGHT
- blockcount
;
392 rb
->memmove(rb
->lcd_framebuffer
,
393 rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
,
394 blocklen
* LCD_FBWIDTH
* sizeof(fb_data
));
398 #if LCD_PIXELFORMAT == VERTICAL_PACKING
400 #if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
402 "mov #0,r4 \n" /* x = 0 */
403 "mova .su_shifttbl,r0 \n" /* calculate jump destination for */
404 "mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
405 "bra .su_cloop \n" /* skip table */
409 ".su_shifttbl: \n" /* shift jump offset table */
410 ".byte .su_shift0 - .su_shifttbl \n"
411 ".byte .su_shift1 - .su_shifttbl \n"
412 ".byte .su_shift2 - .su_shifttbl \n"
413 ".byte .su_shift3 - .su_shifttbl \n"
414 ".byte .su_shift4 - .su_shifttbl \n"
415 ".byte .su_shift5 - .su_shifttbl \n"
416 ".byte .su_shift6 - .su_shifttbl \n"
417 ".byte .su_shift7 - .su_shifttbl \n"
419 ".su_cloop: \n" /* repeat for every column */
420 "mov %[addr],r2 \n" /* get start address */
421 "mov #0,r3 \n" /* current_row = 0 */
422 "mov #0,r1 \n" /* fill with zero */
424 ".su_iloop: \n" /* repeat for all rows */
425 "sub %[wide],r2 \n" /* address -= width */
426 "mov.b @r2,r0 \n" /* get data byte */
427 "shll8 r1 \n" /* old data to 2nd byte */
428 "extu.b r0,r0 \n" /* extend unsigned */
429 "or r1,r0 \n" /* combine old data */
430 "jmp @%[cnt] \n" /* jump into shift "path" */
431 "extu.b r0,r1 \n" /* store data for next round */
433 ".su_shift6: \n" /* shift right by 0..7 bits */
452 "mov.b r0,@r2 \n" /* store data */
453 "add #1,r3 \n" /* current_row++ */
454 "cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
457 "add #1,%[addr] \n" /* start_address++ */
458 "add #1,r4 \n" /* x++ */
459 "cmp/hi r4,%[wide] \n" /* x < width ? */
463 [addr
]"r"(rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
),
464 [wide
]"r"(LCD_FBWIDTH
),
468 "r0", "r1", "r2", "r3", "r4"
470 #elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
472 "move.l %[wide],%%d3\n" /* columns = width */
474 ".su_cloop: \n" /* repeat for every column */
475 "move.l %[addr],%%a1\n" /* get start address */
476 "move.l %[rows],%%d2\n" /* rows = row_count */
477 "move.l %[bkg],%%d1 \n" /* fill with background */
479 ".su_iloop: \n" /* repeat for all rows */
480 "sub.l %[wide],%%a1\n" /* address -= width */
482 "lsl.l #8,%%d1 \n" /* old data to 2nd byte */
483 "move.b (%%a1),%%d1 \n" /* combine with new data byte */
484 "move.l %%d1,%%d0 \n" /* keep data for next round */
485 "lsr.l %[cnt],%%d0 \n" /* shift right */
486 "move.b %%d0,(%%a1) \n" /* store data */
488 "subq.l #1,%%d2 \n" /* rows-- */
491 "addq.l #1,%[addr] \n" /* start_address++ */
492 "subq.l #1,%%d3 \n" /* columns-- */
496 [wide
]"r"(LCD_FBWIDTH
),
498 [addr
]"a"(rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
),
500 [bkg
] "d"(0x55 * (~rb
->lcd_get_background() & 3))
502 "a1", "d0", "d1", "d2", "d3"
504 #else /* C version */
506 unsigned char *addr
= rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
;
508 unsigned fill
= 0x55 * (~rb
->lcd_get_background() & 3);
510 const unsigned fill
= 0;
513 for (x
= 0; x
< LCD_WIDTH
; x
++)
515 unsigned char *col_addr
= addr
++;
516 unsigned data
= fill
;
518 for (by
= 0; by
< blocklen
; by
++)
520 col_addr
-= LCD_FBWIDTH
;
521 data
= (data
<< 8) | *col_addr
;
522 *col_addr
= data
>> bitcount
;
525 #endif /* CPU, LCD_DEPTH */
527 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
531 fb_data
*addr
= rb
->lcd_framebuffer
+ blocklen
* LCD_FBWIDTH
;
534 fill
= patterns
[rb
->lcd_get_background() & 3] << 8;
535 mask
= (0xFFu
>> bitcount
) << bitcount
;
538 for (x
= 0; x
< LCD_WIDTH
; x
++)
540 fb_data
*col_addr
= addr
++;
541 unsigned olddata
= fill
;
544 for (by
= 0; by
< blocklen
; by
++)
546 col_addr
-= LCD_FBWIDTH
;
548 *col_addr
= (olddata
^ ((data
^ olddata
) & mask
)) >> bitcount
;
552 #endif /* LCD_DEPTH == 2 */
554 #endif /* LCD_PIXELFORMAT */
556 oldmode
= rb
->lcd_get_drawmode();
557 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
558 rb
->lcd_fillrect(0, LCD_HEIGHT
- count
, LCD_WIDTH
, count
);
559 rb
->lcd_set_drawmode(oldmode
);
563 void xlcd_scroll_down(int count
)
565 int bitcount
, oldmode
;
566 int blockcount
, blocklen
;
568 if ((unsigned) count
>= LCD_HEIGHT
)
570 rb
->lcd_clear_display();
574 #if (LCD_DEPTH == 1) \
575 || (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_INTERLEAVED)
576 blockcount
= count
>> 3;
577 bitcount
= count
& 7;
578 #elif (LCD_DEPTH == 2) && (LCD_PIXELFORMAT == VERTICAL_PACKING)
579 blockcount
= count
>> 2;
580 bitcount
= 2 * (count
& 3);
582 blocklen
= LCD_FBHEIGHT
- blockcount
;
586 rb
->memmove(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
,
588 blocklen
* LCD_FBWIDTH
* sizeof(fb_data
));
592 #if LCD_PIXELFORMAT == VERTICAL_PACKING
594 #if (CONFIG_CPU == SH7034) && (LCD_DEPTH == 1)
596 "mov #0,r4 \n" /* x = 0 */
597 "mova .sd_shifttbl,r0 \n" /* calculate jump destination for */
598 "mov.b @(r0,%[cnt]),%[cnt] \n" /* shift amount from table */
599 "bra .sd_cloop \n" /* skip table */
603 ".sd_shifttbl: \n" /* shift jump offset table */
604 ".byte .sd_shift0 - .sd_shifttbl \n"
605 ".byte .sd_shift1 - .sd_shifttbl \n"
606 ".byte .sd_shift2 - .sd_shifttbl \n"
607 ".byte .sd_shift3 - .sd_shifttbl \n"
608 ".byte .sd_shift4 - .sd_shifttbl \n"
609 ".byte .sd_shift5 - .sd_shifttbl \n"
610 ".byte .sd_shift6 - .sd_shifttbl \n"
611 ".byte .sd_shift7 - .sd_shifttbl \n"
613 ".sd_cloop: \n" /* repeat for every column */
614 "mov %[addr],r2 \n" /* get start address */
615 "mov #0,r3 \n" /* current_row = 0 */
616 "mov #0,r1 \n" /* fill with zero */
618 ".sd_iloop: \n" /* repeat for all rows */
619 "shlr8 r1 \n" /* shift right to get residue */
620 "mov.b @r2,r0 \n" /* get data byte */
621 "jmp @%[cnt] \n" /* jump into shift "path" */
622 "extu.b r0,r0 \n" /* extend unsigned */
624 ".sd_shift6: \n" /* shift left by 0..7 bits */
643 "or r0,r1 \n" /* combine with last residue */
644 "mov.b r1,@r2 \n" /* store data */
645 "add %[wide],r2 \n" /* address += width */
646 "add #1,r3 \n" /* current_row++ */
647 "cmp/hi r3,%[rows] \n" /* current_row < bheight - shift ? */
650 "add #1,%[addr] \n" /* start_address++ */
651 "add #1,r4 \n" /* x++ */
652 "cmp/hi r4,%[wide] \n" /* x < width ? */
656 [addr
]"r"(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
),
657 [wide
]"r"(LCD_WIDTH
),
661 "r0", "r1", "r2", "r3", "r4"
663 #elif defined(CPU_COLDFIRE) && (LCD_DEPTH == 2)
665 "move.l %[wide],%%d3\n" /* columns = width */
667 ".sd_cloop: \n" /* repeat for every column */
668 "move.l %[addr],%%a1\n" /* get start address */
669 "move.l %[rows],%%d2\n" /* rows = row_count */
670 "move.l %[bkg],%%d1 \n" /* fill with background */
672 ".sd_iloop: \n" /* repeat for all rows */
673 "lsr.l #8,%%d1 \n" /* shift right to get residue */
675 "move.b (%%a1),%%d0 \n" /* get data byte */
676 "lsl.l %[cnt],%%d0 \n"
677 "or.l %%d0,%%d1 \n" /* combine with last residue */
678 "move.b %%d1,(%%a1) \n" /* store data */
680 "add.l %[wide],%%a1\n" /* address += width */
681 "subq.l #1,%%d2 \n" /* rows-- */
684 "lea.l (1,%[addr]),%[addr] \n" /* start_address++ */
685 "subq.l #1,%%d3 \n" /* columns-- */
689 [wide
]"r"(LCD_WIDTH
),
691 [addr
]"a"(rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
),
693 [bkg
] "d"((0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
)
695 "a1", "d0", "d1", "d2", "d3"
697 #else /* C version */
699 unsigned char *addr
= rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
;
701 unsigned fill
= (0x55 * (~rb
->lcd_get_background() & 3)) << bitcount
;
703 const unsigned fill
= 0;
706 for (x
= 0; x
< LCD_WIDTH
; x
++)
708 unsigned char *col_addr
= addr
++;
709 unsigned data
= fill
;
711 for (by
= 0; by
< blocklen
; by
++)
713 data
= (data
>> 8) | (*col_addr
<< bitcount
);
715 col_addr
+= LCD_FBWIDTH
;
718 #endif /* CPU, LCD_DEPTH */
720 #elif LCD_PIXELFORMAT == VERTICAL_INTERLEAVED
724 fb_data
*addr
= rb
->lcd_framebuffer
+ blockcount
* LCD_FBWIDTH
;
727 fill
= patterns
[rb
->lcd_get_background() & 3] >> (8 - bitcount
);
728 mask
= (0xFFu
>> bitcount
) << bitcount
;
731 for (x
= 0; x
< LCD_WIDTH
; x
++)
733 fb_data
*col_addr
= addr
++;
734 unsigned olddata
= fill
;
737 for (by
= 0; by
< blocklen
; by
++)
739 data
= *col_addr
<< bitcount
;
740 *col_addr
= olddata
^ ((data
^ olddata
) & mask
);
742 col_addr
+= LCD_FBWIDTH
;
745 #endif /* LCD_DEPTH == 2 */
747 #endif /* LCD_PIXELFORMAT */
749 oldmode
= rb
->lcd_get_drawmode();
750 rb
->lcd_set_drawmode(DRMODE_SOLID
|DRMODE_INVERSEVID
);
751 rb
->lcd_fillrect(0, 0, LCD_WIDTH
, count
);
752 rb
->lcd_set_drawmode(oldmode
);
755 #endif /* LCD_PIXELFORMAT, LCD_DEPTH */
756 #endif /* defined(LCD_STRIDEFORMAT) && LCD_STRIDEFORMAT == VERTICAL_STRIDE */
758 #endif /* HAVE_LCD_BITMAP */