Index: firmware/target/coldfire/iaudio/lcd-remote-iaudio.c =================================================================== --- firmware/target/coldfire/iaudio/lcd-remote-iaudio.c (revision 12756) +++ firmware/target/coldfire/iaudio/lcd-remote-iaudio.c (working copy) @@ -58,102 +58,164 @@ bool remote_initialized = false; +static int cs_countdown IDATA_ATTR = 0; +#define CS_TIMEOUT (HZ/10) + static void remote_tick(void); -/* Standard low-level byte writer. Requires CLK high on entry */ +#define NORMAL_DELAY 4 + +#ifdef HAVE_REMOTE_LCD_TICKING +/* If set to true, will prevent "ticking" to headphones. */ +#define NOTICK_DELAY 6 +static bool emireduce = false; +static unsigned flip_delay = 0; + +#define FLIP_DELAY \ + "move.l %[delay], %%d4 \n" \ + "2: \n" \ + "subq.l #1, %%d4 \n" \ + "bhi.s 2b \n" + +#else +#define FLIP_DELAY \ + "moveq.l %[delay], %%d4 \n" \ + "2: \n" \ + "subq.l #1, %%d4 \n" \ + "bhi.s 2b \n" +#endif + +#define FLIP_DELAY_N(n) \ + "moveq.l #" #n ", %%d4 \n" \ + "2: \n" \ + "subq.l #1, %%d4 \n" \ + "bhi.s 2b \n" + static inline void _write_byte(unsigned data) { asm volatile ( - "move.l (%[gpo0]), %%d0 \n" /* Get current state of data line */ - "and.l %[dbit], %%d0 \n" + "move.w %%sr,%%d3 \n" /* Get current interrupt level */ + "move.w #0x2700,%%sr \n" /* Disable interrupts */ + + "move.l (%[gpo0]), %%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" + "bset #8, %[data] \n" "1: \n" - "move.l %[data], %%d0 \n" /* Compute the 'bit derivative', i.e. a value */ - "lsr.l #1, %%d0 \n" /* with 1's where the data changes from the */ - "eor.l %%d0, %[data] \n" /* previous state, and 0's where it doesn't */ + "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 %[cbit], %%d1 \n" /* Prepare mask for flipping CLK */ - "or.l %[dbit], %%d1 \n" /* and DATA at once */ "lsl.l #1,%[data] \n" /* Shift out MSB */ "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" /* 1: Flip both CLK and DATA */ - ".word 0x51fa \n" /* (trapf.w - shadow next insn) */ + "eor.l %[dbit], %%d0 \n" /* 1: Flip data bit */ "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" /* else flip CLK only */ - "eor.l %[cbit], (%[gpo0]) \n" /* Flip CLK again */ + "eor.l %[cbit], %%d0 \n" /* Flip clock bit */ + "move.l %%d0, (%[gpo0]) \n" /* Output new state */ + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" /* Flip clock bit */ + "move.l %%d0, (%[gpo0]) \n" /* Output new state */ + FLIP_DELAY "lsl.l #1,%[data] \n" /* ..unrolled.. */ "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY "lsl.l #1,%[data] \n" "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY "lsl.l #1,%[data] \n" "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY "lsl.l #1,%[data] \n" "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY "lsl.l #1,%[data] \n" "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY "lsl.l #1,%[data] \n" "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY "lsl.l #1,%[data] \n" "bcc.s 1f \n" - "eor.l %%d1, (%[gpo0]) \n" - ".word 0x51fa \n" + "eor.l %[dbit], %%d0 \n" "1: \n" - "eor.l %[cbit], (%[gpo0]) \n" - "eor.l %[cbit], (%[gpo0]) \n" + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + "eor.l %[cbit], %%d0 \n" + "move.l %%d0, (%[gpo0]) \n" + FLIP_DELAY + + "move.w %%d3, %%sr \n" /* Restore interrupt level */ : /* outputs */ [data]"+d"(data) : /* inputs */ [gpo0]"a"(&GPIO_OUT), [cbit]"d"(0x00004000), - [dbit]"d"(0x00002000) + [dbit]"d"(0x00002000), +#ifdef HAVE_REMOTE_LCD_TICKING + [delay]"r"(flip_delay) +#else + [delay]"i"(NORMAL_DELAY) +#endif : /* clobbers */ - "d0", "d1" + "d0", "d1", "d2", "d3", "d4" ); } /* Fast low-level byte writer. Don't use with high CPU clock. - * Requires CLK high on entry */ + * Requires CLK high on entry - inline helps a lot here */ static inline void _write_fast(unsigned data) { asm volatile ( @@ -256,29 +318,52 @@ ); } + void lcd_remote_write_command(int cmd) { + cs_countdown = 0; + RS_LO; +// asm volatile (FLIP_DELAY : : : "d4"); CS_LO; _write_byte(cmd); - CS_HI; +// asm volatile (FLIP_DELAY_N(32) : : : "d4"); +// CS_HI; + + cs_countdown = CS_TIMEOUT; } void lcd_remote_write_command_ex(int cmd, int data) { + cs_countdown = 0; + RS_LO; +// asm volatile (FLIP_DELAY : : : "d4"); CS_LO; _write_byte(cmd); +// asm volatile (FLIP_DELAY_N(32) : : : "d4"); _write_byte(data); - CS_HI; +// asm volatile (FLIP_DELAY_N(32) : : : "d4"); +// CS_HI; + + cs_countdown = CS_TIMEOUT; } void lcd_remote_write_data(const unsigned char* p_bytes, int count) { const unsigned char *p_end = p_bytes + count; + cs_countdown = 0; + +#ifdef HAVE_REMOTE_LCD_TICKING + /* Adjust flip delay for emi reduction */ + flip_delay = emireduce ? NOTICK_DELAY : NORMAL_DELAY; +#endif + RS_HI; + // asm volatile (FLIP_DELAY : : : "d4"); CS_LO; + if (cpu_frequency < 50000000) { while (p_bytes < p_end) @@ -287,9 +372,14 @@ else { while (p_bytes < p_end) + { _write_byte(*p_bytes++); +// asm volatile (FLIP_DELAY_N(32) : : : "d4"); + } } - CS_HI; + + cs_countdown = CS_TIMEOUT; +// CS_HI; } int lcd_remote_default_contrast(void) @@ -297,6 +387,13 @@ return DEFAULT_REMOTE_CONTRAST_SETTING; } +#ifdef HAVE_REMOTE_LCD_TICKING +void lcd_remote_emireduce(bool state) +{ + emireduce = state; +} +#endif + void lcd_remote_powersave(bool on) { if(remote_initialized) { @@ -438,6 +535,12 @@ } } } + + /* handle chip select timeout */ + if (cs_countdown >= 0) + cs_countdown--; + if (cs_countdown == 0) + CS_HI; } /* Update the display. @@ -447,6 +550,10 @@ { int y; if(remote_initialized) { +#ifdef HAVE_REMOTE_LCD_TICKING + /* Adjust flip delay for emi reduction */ + flip_delay = emireduce ? NOTICK_DELAY : NORMAL_DELAY; +#endif for(y = 0;y < LCD_REMOTE_FBHEIGHT;y++) { /* Copy display bitmap to hardware. The COM48-COM63 lines are not connected so we have to skip @@ -478,6 +585,11 @@ if(ymax >= LCD_REMOTE_FBHEIGHT) ymax = LCD_REMOTE_FBHEIGHT-1; +#ifdef HAVE_REMOTE_LCD_TICKING + /* Adjust flip delay for emi reduction */ + flip_delay = emireduce ? NOTICK_DELAY : NORMAL_DELAY; +#endif + /* Copy specified rectangle bitmap to hardware COM48-COM63 are not connected, so we need to skip those */ for (; y <= ymax; y++) Index: firmware/target/coldfire/iaudio/lcd-remote-target.h =================================================================== --- firmware/target/coldfire/iaudio/lcd-remote-target.h (revision 12756) +++ firmware/target/coldfire/iaudio/lcd-remote-target.h (working copy) @@ -29,6 +29,9 @@ bool remote_detect(void); void lcd_remote_powersave(bool on); void lcd_remote_set_contrast(int val); +#ifdef HAVE_REMOTE_LCD_TICKING +void lcd_remote_emireduce(bool state); +#endif void lcd_remote_on(void); void lcd_remote_off(void); void lcd_remote_poweroff(void); /* for when remote is plugged during shutdown*/ Index: firmware/export/config-iaudiox5.h =================================================================== --- firmware/export/config-iaudiox5.h (revision 12756) +++ firmware/export/config-iaudiox5.h (working copy) @@ -49,6 +49,9 @@ #define LCD_REMOTE_PIXELFORMAT VERTICAL_INTERLEAVED +/* Define if we have a hardware defect that causes ticking on the audio line */ +#define HAVE_REMOTE_LCD_TICKING + #define CONFIG_KEYPAD IAUDIO_X5_PAD #define AB_REPEAT_ENABLE 1