diff --git a/firmware/SOURCES b/firmware/SOURCES index 5a26932ce0..0582c70b61 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -61,6 +61,9 @@ drivers/lcd-recorder.c drivers/lcd-16bit.c #endif #endif +#if CONFIG_LCD==LCD_IPODNANO || CONFIG_LCD==LCD_IPODCOLOR +drivers/lcd-ipod.c +#endif drivers/power.c #ifdef CONFIG_LED drivers/led.c diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c index 62f7fa2714..760e40987d 100644 --- a/firmware/drivers/lcd-16bit.c +++ b/firmware/drivers/lcd-16bit.c @@ -11,8 +11,6 @@ * * Rockbox driver for 16-bit colour LCDs * - * iPod driver based on code from ipodlinux - http://ipodlinux.org - * * 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. * @@ -34,35 +32,6 @@ #include "font.h" #include "bidi.h" -/*** definitions ***/ - -#define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084))) - -/* LCD command codes */ -#define LCD_CNTL_POWER_CONTROL 0x25 -#define LCD_CNTL_VOLTAGE_SELECT 0x2b -#define LCD_CNTL_LINE_INVERT_DRIVE 0x36 -#define LCD_CNTL_GRAY_SCALE_PATTERN 0x39 -#define LCD_CNTL_TEMP_GRADIENT_SELECT 0x4e -#define LCD_CNTL_OSC_FREQUENCY 0x5f -#define LCD_CNTL_ON_OFF 0xae -#define LCD_CNTL_OSC_ON_OFF 0xaa -#define LCD_CNTL_OFF_MODE 0xbe -#define LCD_CNTL_REVERSE 0xa6 -#define LCD_CNTL_ALL_LIGHTING 0xa4 -#define LCD_CNTL_COMMON_OUTPUT_STATUS 0xc4 -#define LCD_CNTL_COLUMN_ADDRESS_DIR 0xa0 -#define LCD_CNTL_NLINE_ON_OFF 0xe4 -#define LCD_CNTL_DISPLAY_MODE 0x66 -#define LCD_CNTL_DUTY_SET 0x6d -#define LCD_CNTL_ELECTRONIC_VOLUME 0x81 -#define LCD_CNTL_DATA_INPUT_DIR 0x84 -#define LCD_CNTL_DISPLAY_START_LINE 0x8a - -#define LCD_CNTL_PAGE 0xb1 -#define LCD_CNTL_COLUMN 0x13 -#define LCD_CNTL_DATA_WRITE 0x1d - #define SCROLLABLE_LINES 26 #define RGB_PACK(r,g,b) (swap16(((r>>3)<<11)|((g>>2)<<5)|(b>>3))) @@ -76,13 +45,12 @@ static int drawmode = DRMODE_SOLID; static int xmargin = 0; static int ymargin = 0; static int curfont = FONT_SYSFIXED; -static int lcd_type = 1; /* 0 = "old" Color/Photo, 1 = "new" Color & Nano */ /* scrolling */ -static volatile int scrolling_lines=0; /* Bitpattern of which lines are scrolling */ -static void scroll_thread(void); +static volatile int scrolling_lines = 0; /* Bitpattern of which lines are scrolling */ static long scroll_stack[DEFAULT_STACK_SIZE/sizeof(long)]; static const char scroll_name[] = "scroll"; +static void scroll_thread(void); static int scroll_ticks = 12; /* # of ticks between updates*/ static int scroll_delay = HZ/2; /* ticks delay before start */ static int scroll_step = 6; /* pixels per scroll step */ @@ -95,303 +63,16 @@ static const char scroll_tick_table[16] = { 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3 }; -#ifdef IRIVER_H300_SERIES -static void lcd_cmd_data(int cmd, int data) -{ -} - -static void lcd_send_lo(int v) -{ -} - -static void lcd_send_hi(int v) -{ -} - -#define outl(a, v) -#define inl(x) 0 - -#else -#define IPOD_PP5020_RTC 0x60005010 - -#define LCD_DATA 0x10 -#define LCD_CMD 0x08 - -#define IPOD_LCD_BASE 0x70008a0c -#define IPOD_LCD_BUSY_MASK 0x80000000 - -static int timer_get_current(void) -{ - return inl(IPOD_PP5020_RTC); -} - -/* check if number of useconds has past */ -static int timer_check(int clock_start, int usecs) -{ - unsigned long clock; - clock = inl(IPOD_PP5020_RTC); - - if ( (clock - clock_start) >= usecs ) { - return 1; - } else { - return 0; - } -} - -static void lcd_wait_write(void) -{ - if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) != 0) { - int start = timer_get_current(); - - do { - if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) == 0) break; - } while (timer_check(start, 1000) == 0); - } -} - -static void lcd_send_lo(int v) -{ - lcd_wait_write(); - outl(v | 0x80000000, 0x70008A0C); -} - -static void lcd_send_hi(int v) -{ - lcd_wait_write(); - outl(v | 0x81000000, 0x70008A0C); -} - -static void lcd_cmd_data(int cmd, int data) -{ - if (lcd_type == 0) { - lcd_send_lo(cmd); - lcd_send_lo(data); - } else { - lcd_send_lo(0x0); - lcd_send_lo(cmd); - lcd_send_hi((data >> 8) & 0xff); - lcd_send_hi(data & 0xff); - } -} -#endif - -/*** hardware configuration ***/ - -int lcd_default_contrast(void) -{ - return 28; -} - -#ifndef SIMULATOR - -void lcd_set_contrast(int val) -{ - #warning: Implement lcd_set_contrast() -} - -void lcd_set_invert_display(bool yesno) -{ - #warning: Implement lcd_set_invert_display() -} - -/* turn the display upside down (call lcd_update() afterwards) */ -void lcd_set_flip(bool yesno) -{ -#warning: Implement lcd_set_flip() -} - -/* Rolls up the lcd display by the specified amount of lines. - * Lines that are rolled out over the top of the screen are - * rolled in from the bottom again. This is a hardware - * remapping only and all operations on the lcd are affected. - * -> - * @param int lines - The number of lines that are rolled. - * The value must be 0 <= pixels < LCD_HEIGHT. */ -void lcd_roll(int lines) -{ - lines &= LCD_HEIGHT-1; -#warning: To do: Implement lcd_roll() -} - -#endif /* !SIMULATOR */ - /* LCD init */ void lcd_init(void) -{ +{ lcd_clear_display(); - -#ifndef SIMULATOR -#if CONFIG_LCD == LCD_IPODCOLOR - if (IPOD_HW_REVISION == 0x60000) { - lcd_type = 0; - } else { - int gpio_a01, gpio_a04; - - /* A01 */ - gpio_a01 = (inl(0x6000D030) & 0x2) >> 1; - /* A04 */ - gpio_a04 = (inl(0x6000D030) & 0x10) >> 4; - - if (((gpio_a01 << 1) | gpio_a04) == 0 || ((gpio_a01 << 1) | gpio_a04) == 2) { - lcd_type = 0; - } else { - lcd_type = 1; - } - } - - outl(inl(0x6000d004) | 0x4, 0x6000d004); /* B02 enable */ - outl(inl(0x6000d004) | 0x8, 0x6000d004); /* B03 enable */ - outl(inl(0x70000084) | 0x2000000, 0x70000084); /* D01 enable */ - outl(inl(0x70000080) | 0x2000000, 0x70000080); /* D01 =1 */ - - outl(inl(0x6000600c) | 0x20000, 0x6000600c); /* PWM enable */ - - if (lcd_type == 0) { - lcd_cmd_data(0xef, 0x0); - lcd_cmd_data(0x1, 0x0); - lcd_cmd_data(0x80, 0x1); - lcd_cmd_data(0x10, 0x8); - lcd_cmd_data(0x18, 0x6); - lcd_cmd_data(0x7e, 0x4); - lcd_cmd_data(0x7e, 0x5); - lcd_cmd_data(0x7f, 0x1); - } -#elif CONFIG_LCD == LCD_IPODNANO - /* iPodLinux doesn't appear have any LCD init code for the Nano */ -#endif - -#endif - + /* Call device specific init */ + lcd_init_device(); create_thread(scroll_thread, scroll_stack, sizeof(scroll_stack), scroll_name); } - -#ifndef SIMULATOR -/*** update functions ***/ - -/* Performance function that works with an external buffer - note that by and bheight are in 4-pixel units! */ -void lcd_blit(const unsigned char* data, int x, int by, int width, - int bheight, int stride) -{ - #warning Implement lcd_blit() -} - -/* Update a fraction of the display. */ -void lcd_update_rect(int x, int y, int width, int height) -{ - int rect1, rect2, rect3, rect4; - - unsigned short *addr = (unsigned short *)lcd_framebuffer; - - /* calculate the drawing region */ - #if CONFIG_LCD == LCD_IPODCOLOR - rect1 = x; /* start vert */ - rect2 = (LCD_WIDTH - 1) - y; /* start horiz */ - rect3 = (x + height) - 1; /* end vert */ - rect4 = (rect2 - width) + 1; /* end horiz */ - #else - rect1 = y; /* start horiz */ - rect2 = x; /* start vert */ - rect3 = (y + width) - 1; /* max horiz */ - rect4 = (x + height) - 1; /* max vert */ - #endif - /* setup the drawing region */ - if (lcd_type == 0) { - lcd_cmd_data(0x12, rect1); /* start vert */ - lcd_cmd_data(0x13, rect2); /* start horiz */ - lcd_cmd_data(0x15, rect3); /* end vert */ - lcd_cmd_data(0x16, rect4); /* end horiz */ - } else { - /* swap max horiz < start horiz */ - if (rect3 < rect1) { - int t; - t = rect1; - rect1 = rect3; - rect3 = t; - } - - /* swap max vert < start vert */ - if (rect4 < rect2) { - int t; - t = rect2; - rect2 = rect4; - rect4 = t; - } - - /* max horiz << 8 | start horiz */ - lcd_cmd_data(0x44, (rect3 << 8) | rect1); - /* max vert << 8 | start vert */ - lcd_cmd_data(0x45, (rect4 << 8) | rect2); - - /* start vert = max vert */ - #if CONFIG_LCD == LCD_IPODCOLOR - rect2 = rect4; - #endif - - /* position cursor (set AD0-AD15) */ - /* start vert << 8 | start horiz */ - lcd_cmd_data(0x21, (rect2 << 8) | rect1); - - /* start drawing */ - lcd_send_lo(0x0); - lcd_send_lo(0x22); - } - - addr += x * LCD_WIDTH + y; - - while (height > 0) { - int c, r; - int h, pixels_to_write; - - pixels_to_write = (width * height) * 2; - - /* calculate how much we can do in one go */ - h = height; - if (pixels_to_write > 64000) { - h = (64000/2) / width; - pixels_to_write = (width * h) * 2; - } - - outl(0x10000080, 0x70008a20); - outl((pixels_to_write - 1) | 0xc0010000, 0x70008a24); - outl(0x34000000, 0x70008a20); - - /* for each row */ - for (r = 0; r < h; r++) { - /* for each column */ - for (c = 0; c < width; c += 2) { - unsigned two_pixels; - - two_pixels = addr[0] | (addr[1] << 16); - addr += 2; - - while ((inl(0x70008a20) & 0x1000000) == 0); - - /* output 2 pixels */ - outl(two_pixels, 0x70008b00); - } - - addr += LCD_WIDTH - width; - } - - while ((inl(0x70008a20) & 0x4000000) == 0); - - outl(0x0, 0x70008a24); - - height = height - h; - } -} - -/* Update the display. - This must be called after all other LCD functions that change the display. */ -void lcd_update(void) -{ - lcd_update_rect(0,0,LCD_WIDTH,LCD_HEIGHT); -} -#endif /* !SIMULATOR */ - /*** parameter handling ***/ void lcd_set_drawmode(int mode) @@ -1220,7 +901,7 @@ void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style) scrolling_lines &= ~(1< ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Dave Chapman + * + * Rockbox driver for iPod LCDs + * + * Based on code from ipodlinux - http://ipodlinux.org + * + * 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" +#include "lcd.h" +#include "kernel.h" +#include "system.h" + +/*** definitions ***/ +#define IPOD_HW_REVISION (*((volatile unsigned long*)(0x00002084))) + +/* LCD command codes */ +#define LCD_CNTL_POWER_CONTROL 0x25 +#define LCD_CNTL_VOLTAGE_SELECT 0x2b +#define LCD_CNTL_LINE_INVERT_DRIVE 0x36 +#define LCD_CNTL_GRAY_SCALE_PATTERN 0x39 +#define LCD_CNTL_TEMP_GRADIENT_SELECT 0x4e +#define LCD_CNTL_OSC_FREQUENCY 0x5f +#define LCD_CNTL_ON_OFF 0xae +#define LCD_CNTL_OSC_ON_OFF 0xaa +#define LCD_CNTL_OFF_MODE 0xbe +#define LCD_CNTL_REVERSE 0xa6 +#define LCD_CNTL_ALL_LIGHTING 0xa4 +#define LCD_CNTL_COMMON_OUTPUT_STATUS 0xc4 +#define LCD_CNTL_COLUMN_ADDRESS_DIR 0xa0 +#define LCD_CNTL_NLINE_ON_OFF 0xe4 +#define LCD_CNTL_DISPLAY_MODE 0x66 +#define LCD_CNTL_DUTY_SET 0x6d +#define LCD_CNTL_ELECTRONIC_VOLUME 0x81 +#define LCD_CNTL_DATA_INPUT_DIR 0x84 +#define LCD_CNTL_DISPLAY_START_LINE 0x8a + +#define LCD_CNTL_PAGE 0xb1 +#define LCD_CNTL_COLUMN 0x13 +#define LCD_CNTL_DATA_WRITE 0x1d + +/*** globals ***/ +static int lcd_type = 1; /* 0 = "old" Color/Photo, 1 = "new" Color & Nano */ + +#define IPOD_PP5020_RTC 0x60005010 + +#define LCD_DATA 0x10 +#define LCD_CMD 0x08 + +#define IPOD_LCD_BASE 0x70008a0c +#define IPOD_LCD_BUSY_MASK 0x80000000 + +static int timer_get_current(void) +{ + return inl(IPOD_PP5020_RTC); +} + +/* check if number of useconds has past */ +static int timer_check(int clock_start, int usecs) +{ + unsigned long clock; + clock = inl(IPOD_PP5020_RTC); + + if ( (clock - clock_start) >= usecs ) { + return 1; + } else { + return 0; + } +} + +static void lcd_wait_write(void) +{ + if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) != 0) { + int start = timer_get_current(); + + do { + if ((inl(IPOD_LCD_BASE) & IPOD_LCD_BUSY_MASK) == 0) break; + } while (timer_check(start, 1000) == 0); + } +} + +static void lcd_send_lo(int v) +{ + lcd_wait_write(); + outl(v | 0x80000000, 0x70008A0C); +} + +static void lcd_send_hi(int v) +{ + lcd_wait_write(); + outl(v | 0x81000000, 0x70008A0C); +} + +static void lcd_cmd_data(int cmd, int data) +{ + if (lcd_type == 0) { + lcd_send_lo(cmd); + lcd_send_lo(data); + } else { + lcd_send_lo(0x0); + lcd_send_lo(cmd); + lcd_send_hi((data >> 8) & 0xff); + lcd_send_hi(data & 0xff); + } +} + +/*** hardware configuration ***/ +int lcd_default_contrast(void) +{ + return 28; +} + +void lcd_set_contrast(int val) +{ + #warning: Implement lcd_set_contrast() +} + +void lcd_set_invert_display(bool yesno) +{ + #warning: Implement lcd_set_invert_display() +} + +/* turn the display upside down (call lcd_update() afterwards) */ +void lcd_set_flip(bool yesno) +{ +#warning: Implement lcd_set_flip() +} + +/* Rolls up the lcd display by the specified amount of lines. + * Lines that are rolled out over the top of the screen are + * rolled in from the bottom again. This is a hardware + * remapping only and all operations on the lcd are affected. + * -> + * @param int lines - The number of lines that are rolled. + * The value must be 0 <= pixels < LCD_HEIGHT. */ +void lcd_roll(int lines) +{ + lines &= LCD_HEIGHT-1; +#warning: To do: Implement lcd_roll() +} + +/* LCD init */ +void lcd_init_device(void) +{ +#if CONFIG_LCD == LCD_IPODCOLOR + if (IPOD_HW_REVISION == 0x60000) { + lcd_type = 0; + } else { + int gpio_a01, gpio_a04; + + /* A01 */ + gpio_a01 = (inl(0x6000D030) & 0x2) >> 1; + /* A04 */ + gpio_a04 = (inl(0x6000D030) & 0x10) >> 4; + + if (((gpio_a01 << 1) | gpio_a04) == 0 || ((gpio_a01 << 1) | gpio_a04) == 2) { + lcd_type = 0; + } else { + lcd_type = 1; + } + } + + outl(inl(0x6000d004) | 0x4, 0x6000d004); /* B02 enable */ + outl(inl(0x6000d004) | 0x8, 0x6000d004); /* B03 enable */ + outl(inl(0x70000084) | 0x2000000, 0x70000084); /* D01 enable */ + outl(inl(0x70000080) | 0x2000000, 0x70000080); /* D01 =1 */ + + outl(inl(0x6000600c) | 0x20000, 0x6000600c); /* PWM enable */ + + if (lcd_type == 0) { + lcd_cmd_data(0xef, 0x0); + lcd_cmd_data(0x1, 0x0); + lcd_cmd_data(0x80, 0x1); + lcd_cmd_data(0x10, 0x8); + lcd_cmd_data(0x18, 0x6); + lcd_cmd_data(0x7e, 0x4); + lcd_cmd_data(0x7e, 0x5); + lcd_cmd_data(0x7f, 0x1); + } +#elif CONFIG_LCD == LCD_IPODNANO + /* iPodLinux doesn't appear have any LCD init code for the Nano */ +#endif +} + +/*** update functions ***/ + +/* Performance function that works with an external buffer + note that by and bheight are in 4-pixel units! */ +void lcd_blit(const unsigned char* data, int x, int by, int width, + int bheight, int stride) +{ + #warning Implement lcd_blit() +} + +/* Update a fraction of the display. */ +void lcd_update_rect(int x, int y, int width, int height) +{ + int rect1, rect2, rect3, rect4; + + unsigned short *addr = (unsigned short *)lcd_framebuffer; + + /* calculate the drawing region */ +#if CONFIG_LCD == LCD_IPODCOLOR + rect1 = x; /* start vert */ + rect2 = (LCD_WIDTH - 1) - y; /* start horiz */ + rect3 = (x + height) - 1; /* end vert */ + rect4 = (rect2 - width) + 1; /* end horiz */ +#else + rect1 = y; /* start horiz */ + rect2 = x; /* start vert */ + rect3 = (y + width) - 1; /* max horiz */ + rect4 = (x + height) - 1; /* max vert */ +#endif + /* setup the drawing region */ + if (lcd_type == 0) { + lcd_cmd_data(0x12, rect1); /* start vert */ + lcd_cmd_data(0x13, rect2); /* start horiz */ + lcd_cmd_data(0x15, rect3); /* end vert */ + lcd_cmd_data(0x16, rect4); /* end horiz */ + } else { + /* swap max horiz < start horiz */ + if (rect3 < rect1) { + int t; + t = rect1; + rect1 = rect3; + rect3 = t; + } + + /* swap max vert < start vert */ + if (rect4 < rect2) { + int t; + t = rect2; + rect2 = rect4; + rect4 = t; + } + + /* max horiz << 8 | start horiz */ + lcd_cmd_data(0x44, (rect3 << 8) | rect1); + /* max vert << 8 | start vert */ + lcd_cmd_data(0x45, (rect4 << 8) | rect2); + + /* start vert = max vert */ +#if CONFIG_LCD == LCD_IPODCOLOR + rect2 = rect4; +#endif + + /* position cursor (set AD0-AD15) */ + /* start vert << 8 | start horiz */ + lcd_cmd_data(0x21, (rect2 << 8) | rect1); + + /* start drawing */ + lcd_send_lo(0x0); + lcd_send_lo(0x22); + } + + addr += x * LCD_WIDTH + y; + + while (height > 0) { + int c, r; + int h, pixels_to_write; + + pixels_to_write = (width * height) * 2; + + /* calculate how much we can do in one go */ + h = height; + if (pixels_to_write > 64000) { + h = (64000/2) / width; + pixels_to_write = (width * h) * 2; + } + + outl(0x10000080, 0x70008a20); + outl((pixels_to_write - 1) | 0xc0010000, 0x70008a24); + outl(0x34000000, 0x70008a20); + + /* for each row */ + for (r = 0; r < h; r++) { + /* for each column */ + for (c = 0; c < width; c += 2) { + unsigned two_pixels; + + two_pixels = addr[0] | (addr[1] << 16); + addr += 2; + + while ((inl(0x70008a20) & 0x1000000) == 0); + + /* output 2 pixels */ + outl(two_pixels, 0x70008b00); + } + + addr += LCD_WIDTH - width; + } + + while ((inl(0x70008a20) & 0x4000000) == 0); + + outl(0x0, 0x70008a24); + + height = height - h; + } +} + +/* Update the display. + This must be called after all other LCD functions that change the display. */ +void lcd_update(void) +{ + lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT); +} + diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index 88bbfe1615..1e9cc733db 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -39,6 +39,12 @@ extern void lcd_write_command(int byte); extern void lcd_write_command_ex(int cmd, int data1, int data2); extern void lcd_write_data(const unsigned char* p_bytes, int count); extern void lcd_init(void); +#ifdef SIMULATOR +/* Define a dummy device specific init for the sims */ +#define lcd_init_device() +#else +extern void lcd_init_device(void); +#endif extern void lcd_backlight(bool on); extern int lcd_default_contrast(void); extern void lcd_set_contrast(int val);