From 9737fc7c266bb2a859fd2d03540c2c4a70c74c9a Mon Sep 17 00:00:00 2001 From: Jens Arnold Date: Sun, 6 Apr 2008 23:57:37 +0000 Subject: Iriver remote LCD driver: * Split out assembler parts. * Reintroduced the 2 transfer routine variants (low/high CPU clock), and made the version for high CPU clock a little slower because there were problems reported. The function can be slowed down more if there are still problems. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@17006 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 2 + .../target/coldfire/iriver/lcd-remote-as-iriver.S | 302 +++++++++++++++++++++ .../target/coldfire/iriver/lcd-remote-iriver.c | 211 +------------- 3 files changed, 311 insertions(+), 204 deletions(-) create mode 100644 firmware/target/coldfire/iriver/lcd-remote-as-iriver.S diff --git a/firmware/SOURCES b/firmware/SOURCES index 3864a3478b..915d77875c 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -535,6 +535,7 @@ target/coldfire/ata-as-coldfire.S target/coldfire/pcf50606-coldfire.c target/coldfire/iriver/ata-iriver.c target/coldfire/iriver/lcd-remote-iriver.c +target/coldfire/iriver/lcd-remote-as-iriver.S target/coldfire/iriver/system-iriver.c target/coldfire/iriver/fmradio_i2c-iriver.c target/coldfire/iriver/h300/sw_i2c-h300.c @@ -559,6 +560,7 @@ drivers/sw_i2c.c target/coldfire/ata-as-coldfire.S target/coldfire/iriver/ata-iriver.c target/coldfire/iriver/lcd-remote-iriver.c +target/coldfire/iriver/lcd-remote-as-iriver.S target/coldfire/iriver/system-iriver.c target/coldfire/iriver/fmradio_i2c-iriver.c target/coldfire/iriver/h100/adc-h100.c diff --git a/firmware/target/coldfire/iriver/lcd-remote-as-iriver.S b/firmware/target/coldfire/iriver/lcd-remote-as-iriver.S new file mode 100644 index 0000000000..0325e5176c --- /dev/null +++ b/firmware/target/coldfire/iriver/lcd-remote-as-iriver.S @@ -0,0 +1,302 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2008 by Jens Arnold + * + * 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" + +#define RS_MASK 0x00010000 +#define CLOCK_MASK 0x10000000 +#define GPIO_OUT_ADDR 0x80000004 + +#define CS_MASK 0x00000004 /* used in moveq.l */ +#define DATA_MASK 0x00040000 +#define GPIO1_OUT_ADDR 0x800000b4 + +#define CS_TIMEOUT 10 /* HZ/10 */ + + .extern cpu_frequency /* Global variable from system.c */ + .extern remote_byte_delay /* Global variable from lcd-remote-iriver.c */ + .extern remote_cs_countdown /* Global variable from lcd-remote-iriver.c */ + + .section .icode,"ax",@progbits + + /* Output 8 bits to the LCD. Instruction order is devised to maximize the + * delay between changing the data line and the CLK L->H transition, which + * makes the LCD controller sample DATA. + * Requires CLK = 0 on entry. + * + * Custom calling convention: + * %a0 - GPIO_OUT_ADDR + * %a1 - GPIO1_OUT_ADDR + * %d4 - data byte + * %d6 - DATA_MASK + * Clobbers: + * %d0..%d4 + */ +#ifdef HAVE_REMOTE_LCD_TICKING +.write_byte_delayed: + move.l remote_byte_delay, %d0 +1: + subq.l #1, %d0 + bne.s 1b +#endif + +.write_byte: + move.w %sr, %d3 /* Get current interrupt level */ + move.w #0x2700, %sr /* Disable interrupts */ + + move.l (%a1), %d0 /* Get current state of data port */ + move.l %d0, %d1 + and.l %d6, %d1 /* Check current state of data line */ + beq.s 1f /* and set it as previous-state bit */ + bset #8, %d4 +1: + move.l %d4, %d1 /* Compute the 'bit derivative', i.e. a value */ + lsr.l #1, %d1 /* with 1's where the data changes from the */ + eor.l %d1, %d4 /* previous state, and 0's where it doesn't */ + swap %d4 /* Shift data to upper byte */ + lsl.l #8, %d4 + + move.l (%a0),%d1 /* Get current state of clock port */ + move.l %d1, %d2 /* Precalculate opposite state of clock line */ + eor.l #CLOCK_MASK, %d2 + + lsl.l #1, %d4 /* Invert data line for bit7 ? */ + bcc.s 1f /* no: skip */ + eor.l %d6, %d0 /* invert data bit */ + move.l %d0, (%a1) /* output data bit7 */ + nop +1: + +.macro bit_out + lsl.l #1, %d4 /* Invert data line for bit6 ? */ + bcc.s 1f /* no: skip */ + eor.l %d6, %d0 /* Invert data bit */ + move.l %d2, (%a0) /* Bit7: set CLK = 1 */ + move.l %d1, (%a0) /* set CLK = 0 */ + move.l %d0, (%a1) /* Output data bit6 */ + bra.s 2f /* slower than trapf.l - required here */ +1: /* else */ + move.l %d2, (%a0) /* Bit7: set CLK = 1 */ + move.l %d1, (%a0) /* set CLK = 0 */ +2: +.endm + bit_out + bit_out + bit_out + bit_out + bit_out + bit_out + bit_out + + nop /* Let data line settle */ + move.l %d2, (%a0) /* Bit0: Set CLK = 1 */ + move.l %d1, (%a0) /* Set CLK = 0 */ + + move.w %d3, %sr /* Restore interrupt level */ + rts + + /* Output 8 bits to the LCD as fast as possible. Use only at < 60MHz. + * + * Custom calling convention: + * %a0 - GPIO_OUT_ADDR + * %a1 - GPIO1_OUT_ADDR + * %d4 - data word + * %d6 - DATA_MASK + * Clobbers: + * %d0..%d4 + */ +#ifdef HAVE_REMOTE_LCD_TICKING +.write_byte_fast_delayed: + move.l remote_byte_delay, %d0 +1: + subq.l #1, %d0 + bne.s 1b +#endif + +.write_byte_fast: + move.w %sr, %d3 /* Get current interrupt level */ + move.w #0x2700,%sr /* Disable interrupts */ + + move.l (%a1), %d0 /* Get current state of data port */ + move.l %d0, %d1 + and.l %d6, %d1 /* Check current state of data line */ + beq.s 1f /* and set it as previous-state bit */ + bset #8, %d4 +1: + move.l %d4, %d1 /* Compute the 'bit derivative', i.e. a value */ + lsr.l #1, %d1 /* with 1's where the data changes from the */ + eor.l %d1, %d4 /* previous state, and 0's where it doesn't */ + swap %d4 /* Shift data to upper byte */ + lsl.l #8, %d4 + + move.l (%a0), %d1 /* Get current state of clock port */ + move.l %d1, %d2 /* Precalculate opposite state of clock line */ + eor.l #CLOCK_MASK, %d2 + +.macro bit_out_fast + lsl.l #1,%d4 /* Shift out MSB */ + bcc.s 1f + eor.l %d6, %d0 /* 1: flip data bit */ + move.l %d0, (%a1) /* and output new DATA state */ +1: + move.l %d2, (%a0) /* Set CLK */ + move.l %d1, (%a0) /* Reset CLK */ +.endm + bit_out_fast + bit_out_fast + bit_out_fast + bit_out_fast + bit_out_fast + bit_out_fast + bit_out_fast + bit_out_fast + + move.w %d3, %sr /* Restore interrupt level */ + rts + + + .global lcd_remote_write_command + .type lcd_remote_write_command, @function + +lcd_remote_write_command: + lea.l (-4*4, %sp), %sp + movem.l %d2-%d4/%d6, (%sp) + + move.l (4*4+4, %sp), %d4 /* cmd */ + + lea.l GPIO_OUT_ADDR, %a0 + lea.l GPIO1_OUT_ADDR, %a1 + move.l #DATA_MASK, %d6 + + clr.l remote_cs_countdown + + move.l #~RS_MASK, %d0 + and.l %d0, (%a0) + moveq.l #~CS_MASK, %d0 + and.l %d0, (%a1) + +#ifdef HAVE_REMOTE_LCD_TICKING + tst.l remote_byte_delay + ble.s 1f + bsr.w .write_byte_delayed + bra.s 2f +1: +#endif + bsr.w .write_byte +2: + + moveq.l #CS_TIMEOUT, %d0 + move.l %d0, remote_cs_countdown + + movem.l (%sp), %d2-%d4/%d6 + lea.l (4*4, %sp), %sp + rts + + + .global lcd_remote_write_command_ex + .type lcd_remote_write_command_ex, @function + +lcd_remote_write_command_ex: + lea.l (-4*4, %sp), %sp + movem.l %d2-%d4/%d6, (%sp) + + lea.l GPIO_OUT_ADDR, %a0 + lea.l GPIO1_OUT_ADDR, %a1 + move.l #DATA_MASK, %d6 + + clr.l remote_cs_countdown + + move.l #~RS_MASK, %d0 + and.l %d0, (%a0) + moveq.l #~CS_MASK, %d0 + and.l %d0, (%a1) + + move.l (4*4+4, %sp), %d4 + +#ifdef HAVE_REMOTE_LCD_TICKING + tst.l remote_byte_delay + ble.s 1f + bsr.w .write_byte_delayed + move.l (4*4+8, %sp), %d4 + bsr.w .write_byte_delayed + bra.s 2f +1: +#endif + bsr.w .write_byte + move.l (4*4+8, %sp), %d4 + bsr.w .write_byte +2: + + moveq.l #CS_TIMEOUT, %d0 + move.l %d0, remote_cs_countdown + + movem.l (%sp), %d2-%d4/%d6 + lea.l (4*4, %sp), %sp + rts + + + .global lcd_remote_write_data + .type lcd_remote_write_data, @function + +lcd_remote_write_data: + lea.l (-7*4, %sp), %sp + movem.l %d2-%d6/%a2-%a3, (%sp) + + move.l (7*4+4, %sp), %a2 /* p_bytes */ + move.l (7*4+8, %sp), %d5 /* count */ + + lea.l GPIO_OUT_ADDR, %a0 + lea.l GPIO1_OUT_ADDR, %a1 + move.l #DATA_MASK, %d6 + + lea.l .write_byte, %a3 + move.l cpu_frequency, %d0 + cmp.l #60000000, %d0 + bhi.b 1f + lea.l .write_byte_fast, %a3 +1: + +#ifdef HAVE_REMOTE_LCD_TICKING + tst.l remote_byte_delay + ble.s 1f + moveq.l #(.write_byte_delayed - .write_byte), %d0 + add.l %d0, %a3 +1: +#endif + + clr.l remote_cs_countdown + + move.l #RS_MASK, %d0 + or.l %d0, (%a0) + moveq.l #~CS_MASK, %d0 + and.l %d0, (%a1) + +.wd_loop: + clr.l %d4 + move.b (%a2)+, %d4 + jsr (%a3) + subq.l #1, %d5 + bne.s .wd_loop + + moveq.l #CS_TIMEOUT, %d0 + move.l %d0, remote_cs_countdown + + movem.l (%sp), %d2-%d6/%a2-%a3 + lea.l (7*4, %sp), %sp + rts diff --git a/firmware/target/coldfire/iriver/lcd-remote-iriver.c b/firmware/target/coldfire/iriver/lcd-remote-iriver.c index 6ff76f3dd6..85ba0fef7a 100644 --- a/firmware/target/coldfire/iriver/lcd-remote-iriver.c +++ b/firmware/target/coldfire/iriver/lcd-remote-iriver.c @@ -56,13 +56,13 @@ static int xoffset; /* needed for flip */ /* timeout counter for deasserting /CS after access, <0 means not counting */ -static int cs_countdown IDATA_ATTR = 0; +int remote_cs_countdown IDATA_ATTR = 0; #define CS_TIMEOUT (HZ/10) #ifdef HAVE_REMOTE_LCD_TICKING /* If set to true, will prevent "ticking" to headphones. */ static bool emireduce = false; -static int byte_delay = 0; +int remote_byte_delay = 0; /* used in lcd-remote-as-iriver.S */ #endif bool remote_initialized = false; @@ -74,203 +74,6 @@ static bool cached_flip = false; static int cached_contrast = DEFAULT_REMOTE_CONTRAST_SETTING; -#ifdef HAVE_REMOTE_LCD_TICKING -static inline void _byte_delay(int delay) -{ - asm ( - "move.l %[dly], %%d0 \n" - "ble.s 2f \n" - "1: \n" - "subq.l #1, %%d0 \n" - "bne.s 1b \n" - "2: \n" - : /* outputs */ - : /* inputs */ - [dly]"d"(delay) - : /* clobbers */ - "d0" - ); -} -#endif /* HAVE_REMOTE_LCD_TICKING */ - -/* Low-level byte writer. Instruction order is devised to maximize the delay - * between changing the data line and the CLK L->H transition, which makes - * the LCD controller sample DATA, so it's fast yet usable even when boosted. - * Requires CLK low on entry */ -static inline void _write_byte(unsigned data) -{ - asm volatile ( - "move.w %%sr, %%d3 \n" /* Get current interrupt level */ - "move.w #0x2700, %%sr \n" /* Disable interrupts */ - - "move.l (%[gpo1]), %%d0 \n" /* Get current state of data port */ - "move.l %%d0, %%d1 \n" - "and.l %[dbit], %%d1 \n" /* Check current state of data line */ - "beq.s 1f \n" /* and set it as previous-state bit */ - "bset #8, %[data] \n" - "1: \n" - "move.l %[data], %%d1 \n" /* Compute the 'bit derivative', i.e. a value */ - "lsr.l #1, %%d1 \n" /* with 1's where the data changes from the */ - "eor.l %%d1, %[data] \n" /* previous state, and 0's where it doesn't */ - "swap %[data] \n" /* Shift data to upper byte */ - "lsl.l #8, %[data] \n" - - "move.l (%[gpo0]),%%d1 \n" /* Get current state of clock port */ - "move.l %%d1, %%d2 \n" /* Precalculate opposite state of clock line */ - "eor.l %[cbit], %%d2 \n" - - "lsl.l #1, %[data] \n" /* Invert data line for bit7 ? */ - "bcc.s 1f \n" /* no: skip */ - "eor.l %[dbit], %%d0 \n" /* invert data bit */ - "move.l %%d0, (%[gpo1]) \n" /* output data bit7 */ - "1: \n" - - "lsl.l #1, %[data] \n" /* Invert data line for bit6 ? */ - "bcc.s 1f \n" /* no: skip */ - "eor.l %[dbit], %%d0 \n" /* Invert data bit */ - "move.l %%d2, (%[gpo0]) \n" /* Bit7: set CLK = 1 */ - "move.l %%d1, (%[gpo0]) \n" /* set CLK = 0 */ - "move.l %%d0, (%[gpo1]) \n" /* Output data bit6 */ - ".word 0x51fb \n" /* trapf.l - skip next 2 insns */ - "1: \n" /* else */ - "move.l %%d2, (%[gpo0]) \n" /* Bit7: set CLK = 1 */ - "move.l %%d1, (%[gpo0]) \n" /* set CLK = 0 */ - - "lsl.l #1, %[data] \n" /* Unrolled */ - "bcc.s 1f \n" - "eor.l %[dbit], %%d0 \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - "move.l %%d0, (%[gpo1]) \n" - ".word 0x51fb \n" - "1: \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - - "lsl.l #1, %[data] \n" - "bcc.s 1f \n" - "eor.l %[dbit], %%d0 \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - "move.l %%d0, (%[gpo1]) \n" - ".word 0x51fb \n" - "1: \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - - "lsl.l #1, %[data] \n" - "bcc.s 1f \n" - "eor.l %[dbit], %%d0 \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - "move.l %%d0, (%[gpo1]) \n" - ".word 0x51fb \n" - "1: \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - - "lsl.l #1, %[data] \n" - "bcc.s 1f \n" - "eor.l %[dbit], %%d0 \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - "move.l %%d0, (%[gpo1]) \n" - ".word 0x51fb \n" - "1: \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - - "lsl.l #1, %[data] \n" - "bcc.s 1f \n" - "eor.l %[dbit], %%d0 \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - "move.l %%d0, (%[gpo1]) \n" - ".word 0x51fb \n" - "1: \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - - "lsl.l #1, %[data] \n" - "bcc.s 1f \n" - "eor.l %[dbit], %%d0 \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - "move.l %%d0, (%[gpo1]) \n" - ".word 0x51fb \n" - "1: \n" - "move.l %%d2, (%[gpo0]) \n" - "move.l %%d1, (%[gpo0]) \n" - - "nop \n" /* Let data line settle */ - "move.l %%d2, (%[gpo0]) \n" /* Bit0: Set CLK = 1 */ - "move.l %%d1, (%[gpo0]) \n" /* Set CLK = 0 */ - - "move.w %%d3, %%sr \n" /* Restore interrupt level */ - : /* outputs */ - [data]"+d"(data) - : /* inputs */ - [gpo0]"a"(&GPIO_OUT), - [cbit]"i"(0x10000000), - [gpo1]"a"(&GPIO1_OUT), - [dbit]"d"(0x00040000) - : /* clobbers */ - "d0", "d1", "d2", "d3" - ); -} - -void lcd_remote_write_command(int cmd) -{ - cs_countdown = 0; - RS_LO; - CS_LO; - - _write_byte(cmd); -#ifdef HAVE_REMOTE_LCD_TICKING - _byte_delay(byte_delay); -#endif - - cs_countdown = CS_TIMEOUT; -} - -void lcd_remote_write_command_ex(int cmd, int data) -{ - cs_countdown = 0; - RS_LO; - CS_LO; - - _write_byte(cmd); -#ifdef HAVE_REMOTE_LCD_TICKING - _byte_delay(byte_delay); -#endif - _write_byte(data); -#ifdef HAVE_REMOTE_LCD_TICKING - _byte_delay(byte_delay); -#endif - - cs_countdown = CS_TIMEOUT; -} - -void lcd_remote_write_data(const unsigned char* p_bytes, int count) ICODE_ATTR; -void lcd_remote_write_data(const unsigned char* p_bytes, int count) -{ - const unsigned char *p_end = p_bytes + count; - - cs_countdown = 0; - RS_HI; - CS_LO; - - while (p_bytes < p_end) - { - _write_byte(*p_bytes++); -#ifdef HAVE_REMOTE_LCD_TICKING - _byte_delay(byte_delay); -#endif - } - - cs_countdown = CS_TIMEOUT; -} - /*** hardware configuration ***/ int lcd_remote_default_contrast(void) @@ -448,9 +251,9 @@ static void remote_tick(void) } /* handle chip select timeout */ - if (cs_countdown >= 0) - cs_countdown--; - if (cs_countdown == 0) + if (remote_cs_countdown >= 0) + remote_cs_countdown--; + if (remote_cs_countdown == 0) CS_HI; } #endif @@ -496,7 +299,7 @@ void lcd_remote_update(void) #ifdef HAVE_REMOTE_LCD_TICKING /* Adjust byte delay for emi reduction. */ - byte_delay = emireduce ? cpu_frequency / 192800 - 90: 0; + remote_byte_delay = emireduce ? cpu_frequency / 192800 - 100: 0; #endif /* Copy display bitmap to hardware */ @@ -530,7 +333,7 @@ void lcd_remote_update_rect(int x, int y, int width, int height) #ifdef HAVE_REMOTE_LCD_TICKING /* Adjust byte delay for emi reduction */ - byte_delay = emireduce ? cpu_frequency / 192800 - 90: 0; + remote_byte_delay = emireduce ? cpu_frequency / 192800 - 100: 0; #endif /* Copy specified rectange bitmap to hardware */ -- cgit v1.2.3