summaryrefslogtreecommitdiffstats
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/SOURCES1
-rw-r--r--firmware/target/coldfire/iaudio/x5/lcd-as-x5.S206
-rwxr-xr-xfirmware/target/coldfire/iaudio/x5/lcd-x5.c114
3 files changed, 221 insertions, 100 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index fd83c05982..fda83ee073 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -236,6 +236,7 @@ target/coldfire/iaudio/x5/power-x5.c
#ifndef SIMULATOR
drivers/generic_i2c.c
target/coldfire/iaudio/x5/button-x5.c
+target/coldfire/iaudio/x5/lcd-as-x5.S
target/coldfire/iaudio/x5/lcd-x5.c
target/coldfire/iaudio/x5/pcf50606-x5.c
target/coldfire/iaudio/x5/adc-x5.c
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
new file mode 100644
index 0000000000..323710cc57
--- /dev/null
+++ b/firmware/target/coldfire/iaudio/x5/lcd-as-x5.S
@@ -0,0 +1,206 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006 by Michael Sevakis
+ * Based on lcd_write_data for H300 in lcd.S
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "cpu.h"
+
+ .section .icode,"ax",@progbits
+
+ .align 2
+ .global lcd_write_data
+ .type lcd_write_data,@function
+
+lcd_write_data:
+ move.l (4,%sp),%a0 /* data pointer */
+ move.l (8,%sp),%d0 /* length in words */
+ add.l %d0,%d0 /* words -> bytes */
+ add.l %a0,%d0 /* -> end address */
+ lea.l 0xf0008002,%a1 /* LCD data port */
+
+ lea.l (-24,%sp),%sp /* free up some registers */
+ movem.l %d2-%d6/%a2,(%sp)
+
+ move.l %a0,%d1
+ btst.l #1,%d1 /* already longword aligned? */
+ beq.b .wd_wordl_end /* yes: skip initial word copy */
+ /* transfer initial word */
+ move.w (%a0)+,%d1 /* |????????|????????|rrrrrggg|gggbbbbb| */
+ move.l %d1,%d2
+ and.l #0xfffff800,%d2 /* |????????|????????|rrrrr000|00000000| */
+ add.l %d2,%d1 /* |????????|???????r|rrrr0ggg|gggbbbbb| */
+ move.l %d1,%d2
+ lsr.l #8,%d1 /* |00000000|????????|???????r|rrrr0ggg| */
+ move.w %d1,(%a1)
+ lsl.l #1,%d2 /* |????????|??????rr|rrr0gggg|ggbbbbb0| */
+ move.w %d2,(%a1)
+
+.wd_wordl_end: /* now longword aligned */
+ moveq.l #28,%d1
+ add.l %a0,%d1
+ and.l #0xFFFFFFF0,%d1 /* %d1 = second line bound */
+ cmp.l %d1,%d0 /* at least one full line to send? */
+ blo.w .wd_long2_start /* no: skip to trailing longword handling */
+
+ subq.l #8,%d1
+ subq.l #8,%d1 /* %d1 = first line bound */
+
+ cmp.l %a0,%d1 /* any leading longwords? */
+ bls.b .wd_long1_end /* no: skip leading long loop */
+
+.wd_long1_loop:
+ move.l (%a0)+,%d2 /* read longword */
+ swap %d2 /* unstuff two pixels and correct order */
+ move.l %d2,%d5
+ and.l #0xff00ff00,%d5 /* |rrrrrggg|00000000|rrrrrggg|00000000| */
+ eor.l %d5,%d2 /* |00000000|gggbbbbb|00000000|gggbbbbb| */
+ lsr.l #8,%d5 /* |00000000|rrrrrggg|00000000|rrrrrggg| */
+ move.l %d5,%d6
+ and.l #0x00f800f8,%d5 /* |00000000|rrrrr000|00000000|rrrrr000| */
+ add.l %d6,%d5 /* |0000000r|rrrr0ggg|0000000r|rrrr0ggg| */
+ move.w %d5,(%a1)
+ lsl.l #1,%d2 /* |0000000g|ggbbbbb0|0000000g|ggbbbbb0| */
+ move.w %d2,(%a1)
+ swap %d5
+ move.w %d5,(%a1)
+ swap %d2
+ move.w %d2,(%a1)
+ cmp.l %a0,%d1
+ bhi.b .wd_long1_loop
+
+.wd_long1_end:
+ move.l %d0,%a2
+ lea.l (-14,%a2),%a2
+
+.wd_line_loop:
+ movem.l (%a0),%d1-%d4 /* burst-read eight words */
+ lea.l (16,%a0),%a0 /* increment address */
+
+ /* transfer four pairs of longs to display */
+ /* same procedure for each as in leading long loop */
+ swap %d1
+ move.l %d1,%d5
+ and.l #0xff00ff00,%d5
+ eor.l %d5,%d1
+ lsr.l #8,%d5
+ move.l %d5,%d6
+ and.l #0x00f800f8,%d5
+ add.l %d6,%d5
+ move.w %d5,(%a1)
+ lsl.l #1,%d1
+ move.w %d1,(%a1)
+ swap %d5
+ move.w %d5,(%a1)
+ swap %d1
+ move.w %d1,(%a1)
+
+ swap %d2
+ move.l %d2,%d5
+ and.l #0xff00ff00,%d5
+ eor.l %d5,%d2
+ lsr.l #8,%d5
+ move.l %d5,%d6
+ and.l #0x00f800f8,%d5
+ add.l %d6,%d5
+ move.w %d5,(%a1)
+ lsl.l #1,%d2
+ move.w %d2,(%a1)
+ swap %d5
+ move.w %d5,(%a1)
+ swap %d2
+ move.w %d2,(%a1)
+
+ swap %d3
+ move.l %d3,%d5
+ and.l #0xff00ff00,%d5
+ eor.l %d5,%d3
+ lsr.l #8,%d5
+ move.l %d5,%d6
+ and.l #0x00f800f8,%d5
+ add.l %d6,%d5
+ move.w %d5,(%a1)
+ lsl.l #1,%d3
+ move.w %d3,(%a1)
+ swap %d5
+ move.w %d5,(%a1)
+ swap %d3
+ move.w %d3,(%a1)
+
+ swap %d4
+ move.l %d4,%d5
+ and.l #0xff00ff00,%d5
+ eor.l %d5,%d4
+ lsr.l #8,%d5
+ move.l %d5,%d6
+ and.l #0x00f800f8,%d5
+ add.l %d6,%d5
+ move.w %d5,(%a1)
+ lsl.l #1,%d4
+ move.w %d4,(%a1)
+ swap %d5
+ move.w %d5,(%a1)
+ swap %d4
+ move.w %d4,(%a1)
+
+ cmp.l %a0,%a2 /* run %a0 up to last line bound */
+ bhi.w .wd_line_loop
+
+.wd_long2_start:
+ subq.l #2,%d0 /* account for handling 2 words per loop */
+ cmp.l %a0,%d0 /* any (trailing longwords? */
+ bls.b .wd_long2_end /* no: skip trailing longword loop */
+
+.wd_long2_loop:
+ move.l (%a0)+,%d2 /* read longword */
+ swap %d2
+ move.l %d2,%d5
+ and.l #0xff00ff00,%d5
+ eor.l %d5,%d2
+ lsr.l #8,%d5
+ move.l %d5,%d6
+ and.l #0x00f800f8,%d5
+ add.l %d6,%d5
+ move.w %d5,(%a1)
+ lsl.l #1,%d2
+ move.w %d2,(%a1)
+ swap %d5
+ move.w %d5,(%a1)
+ swap %d2
+ move.w %d2,(%a1)
+ cmp.l %a0,%d0 /* run %a0 up to last long bound */
+ bhi.b .wd_long2_loop
+
+.wd_long2_end:
+ blo.b .wd_word2_end /* no final word: skip */
+
+ move.w (%a0),%d1 /* transfer final word */
+ move.l %d1,%d2
+ and.l #0xfffff800,%d2
+ add.l %d2,%d1
+ move.l %d1,%d2
+ lsr.l #8,%d1
+ move.w %d1,(%a1)
+ lsl.l #1,%d2
+ move.w %d2,(%a1)
+
+.wd_word2_end:
+ movem.l (%sp),%d2-%d6/%a2
+ lea.l (24,%sp),%sp /* restore registers */
+ rts
+/* end lcd_write_data */
diff --git a/firmware/target/coldfire/iaudio/x5/lcd-x5.c b/firmware/target/coldfire/iaudio/x5/lcd-x5.c
index 57b4789070..240b1db586 100755
--- a/firmware/target/coldfire/iaudio/x5/lcd-x5.c
+++ b/firmware/target/coldfire/iaudio/x5/lcd-x5.c
@@ -531,7 +531,7 @@ void lcd_yuv_blit(unsigned char * const src[3],
ysrc += stride;
}
while (++y < y_end);
-}
+} /* lcd_yuv_blit */
/* Update the display.
This must be called after all other LCD functions that change the
@@ -539,9 +539,6 @@ void lcd_yuv_blit(unsigned char * const src[3],
void lcd_update(void) ICODE_ATTR;
void lcd_update(void)
{
- /* Optimized for full-screen write. */
- const unsigned long *ptr, *ptr_end;
-
if (!display_on)
return;
@@ -552,36 +549,16 @@ void lcd_update(void)
lcd_begin_write_gram();
- ptr = (unsigned long *)lcd_framebuffer;
- ptr_end = ptr + LCD_WIDTH*LCD_HEIGHT/2;
-
- do
- {
- /* 16 words per turns out to be about optimal according to
- test_fps. */
- lcd_write_two(*ptr++);
-#ifndef BOOTLOADER
- lcd_write_two(*ptr++);
- lcd_write_two(*ptr++);
- lcd_write_two(*ptr++);
- lcd_write_two(*ptr++);
- lcd_write_two(*ptr++);
- lcd_write_two(*ptr++);
- lcd_write_two(*ptr++);
-#endif
- }
- while (ptr < ptr_end);
+ lcd_write_data((unsigned short *)lcd_framebuffer,
+ LCD_WIDTH*LCD_HEIGHT);
} /* lcd_update */
/* Update a fraction of the display. */
void lcd_update_rect(int, int, int, int) ICODE_ATTR;
void lcd_update_rect(int x, int y, int width, int height)
{
- int y_end;
- int odd_lead, odd_trail;
- int duff;
- const unsigned long *ptr, *duff_end;
- int stride; /* Actually end of currline -> start of next */
+ int ymax;
+ const unsigned short *ptr;
if (!display_on)
return;
@@ -593,12 +570,12 @@ void lcd_update_rect(int x, int y, int width, int height)
if (width <= 0)
return; /* nothing left to do */
- y_end = y + height;
- if (y_end > LCD_HEIGHT)
- y_end = LCD_HEIGHT; /* Clip bottom */
+ ymax = y + height;
+ if (ymax > LCD_HEIGHT)
+ ymax = LCD_HEIGHT; /* Clip bottom */
if (y < 0)
y = 0; /* Clip top */
- if (y >= y_end)
+ if (y >= ymax)
return; /* nothing left to do */
/* Set start position and window */
@@ -608,75 +585,12 @@ void lcd_update_rect(int x, int y, int width, int height)
lcd_begin_write_gram();
- ptr = (unsigned long *)&lcd_framebuffer[y][x];
-
- /* Aligning source reads to long boundaries helps 2% - 3% with IRAM
- buffer. DK with DRAM. */
- odd_lead = x & 1;
-
- if (odd_lead)
- {
- duff = width - 1;
- odd_trail = duff & 1;
- duff >>= 1;
- }
- else
- {
- duff = width >> 1;
- odd_trail = width & 1;
- }
-
- duff_end = ptr + duff;
-#ifndef BOOTLOADER
- duff &= 7;
-#endif
-
- stride = LCD_WIDTH - width + odd_trail; /* See odd_trail below */
+ ptr = (unsigned short *)&lcd_framebuffer[y][x];
do
{
- if (odd_lead)
- {
- /* Write odd start pixel. */
- lcd_write_one(*(unsigned short *)ptr);
- ptr = (unsigned long *)((short *)ptr + 1);
- }
-
- if (ptr < duff_end)
- {
-#ifdef BOOTLOADER
- do
- lcd_write_two(*ptr);
- while (++ptr < duff_end);
-#else
- switch (duff)
- {
- do
- {
- case 0: lcd_write_two(*ptr++);
- case 7: lcd_write_two(*ptr++);
- case 6: lcd_write_two(*ptr++);
- case 5: lcd_write_two(*ptr++);
- case 4: lcd_write_two(*ptr++);
- case 3: lcd_write_two(*ptr++);
- case 2: lcd_write_two(*ptr++);
- case 1: lcd_write_two(*ptr++);
- }
- while (ptr < duff_end);
- } /* end switch */
-#endif /* BOOTLOADER */
-
- duff_end += LCD_WIDTH/2;
- }
-
- if (odd_trail)
- {
- /* Finish remaining odd pixel. */
- lcd_write_one(*(unsigned short *)ptr);
- /* Stride increased by one pixel. */
- }
-
- ptr = (unsigned long *)((short *)ptr + stride);
+ lcd_write_data(ptr, width);
+ ptr += LCD_WIDTH;
}
- while (++y < y_end);
-}
+ while (++y < ymax);
+} /* lcd_update_rect */