diff --git a/firmware/target/arm/as3525/dbop-as3525.c b/firmware/target/arm/as3525/dbop-as3525.c index 938eee2fb1..b54ad17a6c 100644 --- a/firmware/target/arm/as3525/dbop-as3525.c +++ b/firmware/target/arm/as3525/dbop-as3525.c @@ -20,6 +20,7 @@ ****************************************************************************/ #include "config.h" +#include #include "as3525.h" #include "dbop-as3525.h" @@ -75,3 +76,50 @@ unsigned short dbop_debug(void) { return dbop_input_value; } + +static inline void dbop_set_mode(int mode) +{ + int delay = 10; + if (mode == 32 && (!(DBOP_CTRL & (1<<13|1<<14)))) + DBOP_CTRL |= (1<<13|1<<14); + else if (mode == 16 && (DBOP_CTRL & (1<<13|1<<14))) + DBOP_CTRL &= ~(1<<14|1<<13); + else + return; + while(delay--) asm volatile("nop"); +} + +void dbop_write_data(const int16_t* p_bytes, int count) +{ + + const int32_t *data; + if ((intptr_t)p_bytes & 0x3 || count == 1) + { /* need to do a single 16bit write beforehand if the address is + * not word aligned or count is 1, switch to 16bit mode if needed */ + dbop_set_mode(16); + DBOP_DOUT16 = *p_bytes++; + if (!(--count)) + return; + } + /* from here, 32bit transfers are save + * set it to transfer 4*(outputwidth) units at a time, + * if bit 12 is set it only does 2 halfwords though (we never set it) + * switch to 32bit output if needed */ + dbop_set_mode(32); + data = (int32_t*)p_bytes; + while (count > 1) + { + DBOP_DOUT32 = *data++; + count -= 2; + + /* Wait if push fifo is full */ + while ((DBOP_STAT & (1<<6)) != 0); + } + /* While push fifo is not empty */ + while ((DBOP_STAT & (1<<10)) == 0); + + /* due to the 32bit alignment requirement or uneven count, + * we possibly need to do a 16bit transfer at the end also */ + if (count > 0) + dbop_write_data((int16_t*)data, 1); +} diff --git a/firmware/target/arm/as3525/dbop-as3525.h b/firmware/target/arm/as3525/dbop-as3525.h index 63156031c4..3db62bd3e1 100644 --- a/firmware/target/arm/as3525/dbop-as3525.h +++ b/firmware/target/arm/as3525/dbop-as3525.h @@ -19,5 +19,17 @@ * ****************************************************************************/ + +#ifndef __DBOP_AS3525_H__ +#define __DBOP_AS3525_H__ +#include unsigned short int dbop_read_input(void); unsigned short dbop_debug(void); + +/* + * Write any data to dbop + * switches to 32bit transfers if possible, + * for best performance pre-align count and data + **/ +void dbop_write_data(const int16_t *data, int count); +#endif diff --git a/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c b/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c index f4d1a7cf56..54aa22e398 100644 --- a/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c +++ b/firmware/target/arm/as3525/sansa-e200v2/lcd-e200v2.c @@ -120,19 +120,11 @@ static void as3525_dbop_init(void) /* TODO: The OF calls some other functions here, but maybe not important */ } -static void lcd_write_value16(unsigned short value) -{ - DBOP_CTRL &= ~(1<<14|1<<13); - lcd_delay(10); - DBOP_DOUT16 = value; - while ((DBOP_STAT & (1<<10)) == 0); -} - -static void lcd_write_cmd(int cmd) +static void lcd_write_cmd(short cmd) { /* Write register */ DBOP_TIMPOL_23 = 0xa167006e; - lcd_write_value16(cmd); + dbop_write_data(&cmd, 1); /* Wait for fifo to empty */ while ((DBOP_STAT & (1<<10)) == 0); @@ -144,43 +136,13 @@ static void lcd_write_cmd(int cmd) DBOP_TIMPOL_23 = 0xa167e06f; } -void lcd_write_data(const fb_data* p_bytes, int count) -{ - const long *data; - if ((int)p_bytes & 0x3) - { /* need to do a single 16bit write beforehand if the address is - * not word aligned */ - lcd_write_value16(*p_bytes); - count--;p_bytes++; - } - /* from here, 32bit transfers are save - * set it to transfer 4*(outputwidth) units at a time, - * if bit 12 is set it only does 2 halfwords though */ - DBOP_CTRL |= (1<<13|1<<14); - data = (long*)p_bytes; - while (count > 1) - { - DBOP_DOUT32 = *data++; - count -= 2; - - /* Wait if push fifo is full */ - while ((DBOP_STAT & (1<<6)) != 0); - } - /* While push fifo is not empty */ - while ((DBOP_STAT & (1<<10)) == 0); - - /* due to the 32bit alignment requirement or uneven count, - * we possibly need to do a 16bit transfer at the end also */ - if (count > 0) - lcd_write_value16(*(fb_data*)data); -} static void lcd_write_reg(int reg, int value) { - fb_data data = value; + unsigned short data = value; lcd_write_cmd(reg); - lcd_write_value16(data); + dbop_write_data(&data, 1); } /*** hardware configuration ***/ @@ -486,7 +448,7 @@ void lcd_update(void) lcd_write_cmd(R_WRITE_DATA_2_GRAM); - lcd_write_data((fb_data*)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT); + dbop_write_data((fb_data*)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT); } /* Update a fraction of the display. */ @@ -526,7 +488,7 @@ void lcd_update_rect(int x, int y, int width, int height) do { - lcd_write_data(ptr, width); + dbop_write_data(ptr, width); ptr += LCD_WIDTH; } while (--height > 0); diff --git a/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c b/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c index 3332e0c78c..bdf1c704e0 100644 --- a/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c +++ b/firmware/target/arm/as3525/sansa-fuze/lcd-fuze.c @@ -124,66 +124,23 @@ static void as3525_dbop_init(void) /* TODO: The OF calls some other functions here, but maybe not important */ } -static void lcd_write_value16(unsigned short value) -{ - DBOP_CTRL &= ~(1<<14|1<<13); - lcd_delay(10); - DBOP_DOUT16 = value; - while ((DBOP_STAT & (1<<10)) == 0); -} - -static void lcd_write_cmd(int cmd) +static void lcd_write_cmd(short cmd) { /* Write register */ DBOP_TIMPOL_23 = 0xa167006e; - lcd_write_value16(cmd); - - /* Wait for fifo to empty */ - while ((DBOP_STAT & (1<<10)) == 0); + dbop_write_data(&cmd, 1); lcd_delay(4); DBOP_TIMPOL_23 = 0xa167e06f; } -void lcd_write_data(const fb_data* p_bytes, int count) -{ - const long *data; - if ((int)p_bytes & 0x3) - { /* need to do a single 16bit write beforehand if the address is - * not word aligned */ - lcd_write_value16(*p_bytes); - count--;p_bytes++; - } - /* from here, 32bit transfers are save - * set it to transfer 4*(outputwidth) units at a time, - * if bit 12 is set it only does 2 halfwords though */ - DBOP_CTRL |= (1<<13|1<<14); - lcd_delay(10); - data = (long*)p_bytes; - while (count > 1) - { - DBOP_DOUT32 = *data++; - count -= 2; - - /* Wait if push fifo is full */ - while ((DBOP_STAT & (1<<6)) != 0); - } - /* While push fifo is not empty */ - while ((DBOP_STAT & (1<<10)) == 0); - - /* due to the 32bit alignment requirement or uneven count, - * we possibly need to do a 16bit transfer at the end also */ - if (count > 0) - lcd_write_value16(*(fb_data*)data); -} - static void lcd_write_reg(int reg, int value) { - fb_data data = value; + int16_t data = value; lcd_write_cmd(reg); - lcd_write_value16(data); + dbop_write_data(&data, 1); } /*** hardware configuration ***/ @@ -437,7 +394,7 @@ void lcd_update(void) lcd_write_cmd(R_WRITE_DATA_2_GRAM); - lcd_write_data((fb_data*)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT); + dbop_write_data((fb_data*)lcd_framebuffer, LCD_WIDTH*LCD_HEIGHT); } /* Update a fraction of the display. */ @@ -470,6 +427,10 @@ void lcd_update_rect(int x, int y, int width, int height) lcd_write_reg(R_ENTRY_MODE, r_entry_mode); + /* we need to make x and width even to enable 32bit transfers */ + width = (width + (x & 1) + 1) & ~1; + x &= ~1; + lcd_window_x(x, x + width - 1); lcd_window_y(y, y + height -1); @@ -479,7 +440,7 @@ void lcd_update_rect(int x, int y, int width, int height) do { - lcd_write_data(ptr, width); + dbop_write_data(ptr, width); ptr += LCD_WIDTH; } while (--height > 0);