From 77372d12189c70cb810a7e88bc2ee7a56f64646c Mon Sep 17 00:00:00 2001 From: Dave Chapman Date: Mon, 7 Nov 2005 23:07:19 +0000 Subject: [PATCH] Initial commit of work-in-progress iPod port git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7781 a1c6a512-1295-4272-9138-f99709370657 --- firmware/SOURCES | 4 + firmware/app.lds | 44 +- firmware/backlight.c | 10 + firmware/boot.lds | 55 +- firmware/crt0.S | 135 ++- firmware/drivers/adc.c | 14 + firmware/drivers/ata.c | 61 +- firmware/drivers/i2c-pp5020.c | 189 +++++ firmware/drivers/lcd-16bit.c | 1266 ++++++++++++++++++++++++++++ firmware/drivers/power.c | 9 + firmware/drivers/serial.c | 4 +- firmware/export/button.h | 11 + firmware/export/config-ipodcolor.h | 87 ++ firmware/export/config-ipodnano.h | 89 ++ firmware/export/config.h | 35 +- firmware/export/i2c-pp5020.h | 66 ++ firmware/export/kernel.h | 6 + firmware/export/lcd.h | 12 + firmware/export/system.h | 44 + firmware/kernel.c | 13 + firmware/rolo.c | 2 +- firmware/system.c | 13 + firmware/thread.c | 26 +- firmware/usb.c | 4 + 24 files changed, 2178 insertions(+), 21 deletions(-) create mode 100644 firmware/drivers/i2c-pp5020.c create mode 100644 firmware/drivers/lcd-16bit.c create mode 100644 firmware/export/config-ipodcolor.h create mode 100644 firmware/export/config-ipodnano.h create mode 100644 firmware/export/i2c-pp5020.h diff --git a/firmware/SOURCES b/firmware/SOURCES index bee9fd5acc..5a26932ce0 100644 --- a/firmware/SOURCES +++ b/firmware/SOURCES @@ -57,6 +57,8 @@ bidi.c drivers/lcd-h100.c #elif LCD_DEPTH == 1 drivers/lcd-recorder.c +#elif LCD_DEPTH == 16 +drivers/lcd-16bit.c #endif #endif drivers/power.c @@ -85,6 +87,8 @@ tuner_philips.c #endif #if CONFIG_I2C == I2C_COLDFIRE drivers/i2c-coldfire.c +#elif CONFIG_I2C == I2C_PP5020 +drivers/i2c-pp5020.c #else drivers/i2c.c #endif diff --git a/firmware/app.lds b/firmware/app.lds index 5a0db8f8e3..1a12cb5230 100644 --- a/firmware/app.lds +++ b/firmware/app.lds @@ -3,12 +3,17 @@ ENTRY(start) #ifdef CPU_COLDFIRE OUTPUT_FORMAT(elf32-m68k) +INPUT(crt0.o) #elif CONFIG_CPU == TCC730 OUTPUT_FORMAT(elf32-calmrisc16) +INPUT(crt0.o) +#elif CONFIG_CPU == PP5020 +OUTPUT_FORMAT(elf32-littlearm) +OUTPUT_ARCH(arm) #else OUTPUT_FORMAT(elf32-sh) -#endif INPUT(crt0.o) +#endif #if CONFIG_CPU == TCC730 MEMORY @@ -98,7 +103,44 @@ _audiobufend = 0; _pluginbuf = 0; } +#elif CONFIG_CPU==PP5020 +SECTIONS +{ + . = 0x10000000; + .text : { + *(.init.text) + *(.text) + } + + __data_start__ = . ; + .data : { *(.data) } + __data_end__ = . ; + + __stack_start__ = .; + .stack : + { + *(.stack) + _stackbegin = .; + stackbegin = .; + . += 0x2000; + _stackend = .; + stackend = .; + } + + /* The bss section is too large for IRAM - we just move it at the + end of the regular RAM. */ + + . = 0x11c00000; + __bss_start__ = .; + .bss : { + *(.bss); + __bss_end__ = . ; + } + + + +} #else #define PLUGINSIZE PLUGIN_BUFFER_SIZE diff --git a/firmware/backlight.c b/firmware/backlight.c index ecd4403d88..eafa501d11 100644 --- a/firmware/backlight.c +++ b/firmware/backlight.c @@ -212,6 +212,10 @@ static void __backlight_off(void) and_b(~0x40, &PADRH); /* drive it low */ #elif CONFIG_BACKLIGHT == BL_GMINI P1 &= ~0x10; +#elif CONFIG_BACKLIGHT == BL_IPOD4G + /* fades backlight off on 4g */ + outl(inl(0x70000084) & ~0x2000000, 0x70000084); + outl(0x80000000, 0x7000a010); #endif } @@ -235,6 +239,12 @@ static void __backlight_on(void) or_b(0x40, &PADRH); /* drive it high */ #elif CONFIG_BACKLIGHT == BL_GMINI P1 |= 0x10; +#elif CONFIG_BACKLIGHT == BL_IPOD4G + /* brightness full */ + outl(0x80000000 | (0xff << 16), 0x7000a010); + + /* set port b bit 3 on */ + outl(((0x100 | 1) << 3), 0x6000d824); #endif } diff --git a/firmware/boot.lds b/firmware/boot.lds index a693c2149b..ec8db5ba90 100644 --- a/firmware/boot.lds +++ b/firmware/boot.lds @@ -3,10 +3,14 @@ ENTRY(start) #ifdef CPU_COLDFIRE OUTPUT_FORMAT(elf32-m68k) +INPUT(crt0.o) +#elif CONFIG_CPU == PP5020 +OUTPUT_FORMAT(elf32-littlearm) +OUTPUT_ARCH(arm) #else OUTPUT_FORMAT(elf32-sh) -#endif INPUT(crt0.o) +#endif #if MEMORYSIZE >= 32 #define PLUGINSIZE 0xC0000 @@ -22,6 +26,12 @@ INPUT(crt0.o) #define IRAMSIZE 0x18000 #define FLASHORIG 0x001f0000 #define FLASHSIZE 2M +#elif CONFIG_CPU == PP5020 +#define DRAMORIG 0x10000000 +#define IRAMORIG 0x40000000 +#define IRAMSIZE 0x18000 +#define FLASHORIG 0x001f0000 +#define FLASHSIZE 2M #else #define DRAMORIG 0x09000000 #define IRAMORIG 0x0f000000 @@ -32,13 +42,55 @@ INPUT(crt0.o) #define ENDADDR (IRAMORIG + IRAMSIZE) +#if CONFIG_CPU!=PP5020 MEMORY { DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE FLASH : ORIGIN = FLASHORIG, LENGTH = FLASHSIZE } +#endif + SECTIONS +#if CONFIG_CPU==PP5020 +{ + . = IRAMORIG; + + .text : { + *(.init.text) + *(.text) + } + + .data : { + *(.icode) + *(.irodata) + *(.idata) + *(.data) + _dataend = . ; + } + + .stack : + { + *(.stack) + _stackbegin = .; + stackbegin = .; + . += 0x2000; + _stackend = .; + stackend = .; + } + + /* The bss section is too large for IRAM - we just move it near the + end of the regular RAM. */ + + . = 0x11c00000; + .bss : { + _bssstart = .; + *(.bss); + *(.ibss); + _bssend = . ; + } +} +#else { .vectors : { @@ -114,3 +166,4 @@ SECTIONS _pluginbuf = .; } } +#endif diff --git a/firmware/crt0.S b/firmware/crt0.S index f41b57554b..62566c8065 100644 --- a/firmware/crt0.S +++ b/firmware/crt0.S @@ -19,10 +19,136 @@ #include "config.h" #include "cpu.h" +#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) + .section .init.text +#else .section .init.text,"ax",@progbits +#endif .global start start: -#if CONFIG_CPU == TCC730 +#if (CONFIG_CPU == PP5002) || (CONFIG_CPU == PP5020) + +/* Based on startup.s from the iPodLinux loader + * + * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org) + * Copyright (c) 2005, Bernard Leach + * + */ + .equ PP5002_PROC_ID, 0xc4000000 + .equ PP5002COP_CTRL, 0xcf004058 + .equ PP5020_PROC_ID, 0x60000000 + .equ PP5020_COP_CTRL, 0x60007004 + +start: + /* get the high part of our execute address */ + ldr r0, =0xff000000 + and r8, pc, r0 @ r8 is used later + +#if CONFIG_CPU==PP5002 + mov r0, #PP5002_PROC_ID +#else + mov r0, #PP5020_PROC_ID +#endif + ldr r0, [r0] + and r0, r0, #0xff + cmp r0, #0x55 + beq 1f + + /* put us (co-processor) to sleep */ +#if CONFIG_CPU==PP5002 + ldr r4, =PP5002_COP_CTRL + mov r3, #0xca +#else + ldr r4, =PP5020_COP_CTRL + mov r3, #0x80000000 +#endif + str r3, [r4] + + ldr pc, =cop_wake_start + +cop_wake_start: + /* jump the COP to startup */ + ldr r0, =startup_loc + ldr pc, [r0] + +1: + /* setup some stack */ + ldr sp, = _stackbegin + + /* get the high part of our execute address */ + ldr r2, =0xffffff00 + and r4, pc, r2 + + /* Copy bootloader to safe area - 0x40000000 */ + mov r5, #0x40000000 + ldr r6, = _dataend + sub r0, r6, r5 /* length of loader */ + add r0, r4, r0 /* r0 points to start of loader */ +1: + cmp r5, r6 + ldrcc r2, [r4], #4 + strcc r2, [r5], #4 + bcc 1b + + ldr pc, =start_loc /* jump to the relocated start_loc: */ + +start_loc: + /* Initialise bss section to zero */ + ldr r3, =_bssstart + ldr r1, =_bssend + mov r2, #0x0 + +1: + cmp r3, r1 + strcc r2, [r3], #4 + bcc 1b + + /* execute the loader - this will load an image to 0x10000000 */ + bl main + + /* save the startup address for the COP */ + ldr r1, =startup_loc + str r0, [r1] + +#if CONFIG_CPU==PP5002 + /* make sure COP is sleeping */ + ldr r4, =0xcf004050 +1: + ldr r3, [r4] + ands r3, r3, #0x4000 + beq 1b + + /* wake up COP */ + ldr r4, =PP5002_COP_CTRL + mov r3, #0xce + strh r3, [r4] +#else + /* make sure COP is sleeping */ + ldr r4, =PP5020_COP_CTRL +1: + ldr r3, [r4] + ands r3, r3, #0x80000000 + beq 1b + + /* wake up COP */ + @ ldr r4, =PP5020_COP_CTRL + mov r3, #0x0 + str r3, [r4] +#endif + + /* jump to start location */ + mov pc, r0 + +startup_loc: + .word 0x0 + +.align 8 /* starts at 0x100 */ +.global boot_table +boot_table: + /* here comes the boot table, don't move its offset */ + .space 400 + +#elif CONFIG_CPU == TCC730 /* Platform: Gmini 120/SP */ ;; disable all interrupts clrsr fe @@ -331,6 +457,13 @@ vectors: /* Platform: iRiver H320/H340 */ /* Fill in code here */ +#elif CONFIG_CPU == PP5020 + /* Platform: iPod */ + +#warning TODO: Implement crt0.S + + /* Fill in code here */ + #else /* Platform: Archos Jukebox */ diff --git a/firmware/drivers/adc.c b/firmware/drivers/adc.c index 3dafb0a916..665cd37f81 100644 --- a/firmware/drivers/adc.c +++ b/firmware/drivers/adc.c @@ -254,4 +254,18 @@ void adc_init(void) sleep(2); /* Ensure valid readings when adc_init returns */ } +#elif CONFIG_CPU == PP5020 + +#warning Implement adc.c + +unsigned short adc_read(int channel) +{ + return 0; +} + +void adc_init(void) +{ + +} + #endif diff --git a/firmware/drivers/ata.c b/firmware/drivers/ata.c index 475b1257a6..6ec414c5b8 100644 --- a/firmware/drivers/ata.c +++ b/firmware/drivers/ata.c @@ -71,6 +71,43 @@ #define SET_REG(reg,val) reg = ((val) << 8) #define SET_16BITREG(reg,val) reg = (val) +#elif CONFIG_CPU == PP5020 + +/* don't use sh7034 assembler routines */ +#define PREFER_C_READING +#define PREFER_C_WRITING + +#define ATA_IOBASE 0xc30001e0 +#define ATA_DATA (*((volatile unsigned short*)(ATA_IOBASE))) +#define ATA_ERROR (*((volatile unsigned char*)(ATA_IOBASE + 0x04))) +#define ATA_NSECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x08))) +#define ATA_SECTOR (*((volatile unsigned char*)(ATA_IOBASE + 0x0c))) +#define ATA_LCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x10))) +#define ATA_HCYL (*((volatile unsigned char*)(ATA_IOBASE + 0x14))) +#define ATA_SELECT (*((volatile unsigned char*)(ATA_IOBASE + 0x18))) +#define ATA_COMMAND (*((volatile unsigned char*)(ATA_IOBASE + 0x1c))) +#define ATA_CONTROL (*((volatile unsigned char*)(0xc30003f8))) + +#define STATUS_BSY 0x80 +#define STATUS_RDY 0x40 +#define STATUS_DF 0x20 +#define STATUS_DRQ 0x08 +#define STATUS_ERR 0x01 +#define ERROR_ABRT 0x04 + +#define WRITE_PATTERN1 0xa5 +#define WRITE_PATTERN2 0x5a +#define WRITE_PATTERN3 0xaa +#define WRITE_PATTERN4 0x55 + +#define READ_PATTERN1 0xa5 +#define READ_PATTERN2 0x5a +#define READ_PATTERN3 0xaa +#define READ_PATTERN4 0x55 + +#define SET_REG(reg,val) reg = (val) +#define SET_16BITREG(reg,val) reg = (val) + #elif CONFIG_CPU == SH7034 #define SWAP_WORDS @@ -362,7 +399,7 @@ static void copy_read_sectors(unsigned char* buf, int wordcount) { /* loop compiles to 7 assembler instructions */ /* takes 12 clock cycles (2 pipeline stalls, 1 wait) */ #ifdef SWAP_WORDS - *wbuf = letoh16(ATA_DATA); + *wbuf = swap16(ATA_DATA); #else *wbuf = ATA_DATA; #endif @@ -677,7 +714,7 @@ static void copy_write_sectors(const unsigned char* buf, int wordcount) #ifdef SWAP_WORDS /* loop compiles to 6 assembler instructions */ /* takes 10 clock cycles (2 pipeline stalls) */ - SET_16BITREG(ATA_DATA, htole16(*wbuf)); + SET_16BITREG(ATA_DATA, swap16(*wbuf)); #else SET_16BITREG(ATA_DATA, *wbuf); #endif @@ -1242,6 +1279,8 @@ void ata_enable(bool on) or_l(0x00040000, &GPIO_FUNCTION); #elif CONFIG_CPU == TCC730 +#elif CONFIG_CPU == PP5020 + #warning Implement ata_enable() #endif } @@ -1255,7 +1294,6 @@ static int identify(void) DEBUGF("identify() - not RDY\n"); return -1; } - SET_REG(ATA_COMMAND, CMD_IDENTIFY); if (!wait_for_start_of_transfer()) @@ -1267,10 +1305,11 @@ static int identify(void) for (i=0; i ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Dave Chapman + * + * 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 "cpu.h" +#include "kernel.h" +#include "logf.h" +#include "system.h" +#include "i2c-pp5020.h" + +#define I2C_DEVICE_1 ((volatile unsigned char *)0) +#define I2C_DEVICE_2 ((volatile unsigned char *)0) + +/* Local functions definitions */ + +static int i2c_write_byte(int device, unsigned char data); +static int i2c_gen_start(int device); +static void i2c_gen_stop(int device); +static volatile unsigned char *i2c_get_addr(int device); + +#define IPOD_I2C_BASE 0x7000c000 +#define IPOD_I2C_CTRL (IPOD_I2C_BASE+0x00) +#define IPOD_I2C_ADDR (IPOD_I2C_BASE+0x04) +#define IPOD_I2C_DATA0 (IPOD_I2C_BASE+0x0c) +#define IPOD_I2C_DATA1 (IPOD_I2C_BASE+0x10) +#define IPOD_I2C_DATA2 (IPOD_I2C_BASE+0x14) +#define IPOD_I2C_DATA3 (IPOD_I2C_BASE+0x18) +#define IPOD_I2C_STATUS (IPOD_I2C_BASE+0x1c) + +/* IPOD_I2C_CTRL bit definitions */ +#define IPOD_I2C_SEND 0x80 + +/* IPOD_I2C_STATUS bit definitions */ +#define IPOD_I2C_BUSY (1<<6) + +#define POLL_TIMEOUT (HZ) + +static int +ipod_i2c_wait_not_busy(void) +{ + unsigned long timeout; +#if 0 + timeout = jiffies + POLL_TIMEOUT; + while (time_before(jiffies, timeout)) { + if (!(inb(IPOD_I2C_STATUS) & IPOD_I2C_BUSY)) { + return 0; + } + yield(); + } + + return -ETIMEDOUT; +#endif +} + + +/* Public functions */ + +void i2c_init(void) +{ + /* From ipodlinux */ + + outl(inl(0x6000600c) | 0x1000, 0x6000600c); /* enable 12 */ + outl(inl(0x60006004) | 0x1000, 0x60006004); /* start reset 12 */ + outl(inl(0x60006004) & ~0x1000, 0x60006004); /* end reset 12 */ + + outl(0x0, 0x600060a4); + outl(0x80 | (0 << 8), 0x600060a4); + + i2c_readbyte(0x8, 0); + +} + +void i2c_close(void) +{ + +} + +/** + * Writes bytes to the selected device. + * + * Returns number of bytes successfully send or -1 if START failed + */ +int i2c_write(int device, unsigned char *buf, int count) +{ + /* From ipodlinux */ + int data_addr; + int i; + + if (count < 1 || count > 4) { + return -2; + } + + if (ipod_i2c_wait_not_busy() < 0) { + return -1; + } + + // clear top 15 bits, left shift 1 + outb((device << 17) >> 16, IPOD_I2C_ADDR); + + outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL); + + data_addr = IPOD_I2C_DATA0; + for ( i = 0; i < count; i++ ) { + outb(*buf++, data_addr); + + data_addr += 4; + } + + outb((inb(IPOD_I2C_CTRL) & ~0x26) | ((count-1) << 1), IPOD_I2C_CTRL); + + outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); + + return 0x0; + + return count; +} + +/* Write a byte to the interface, returns 0 on success, -1 otherwise. */ +int i2c_write_byte(int device, unsigned char data) +{ + if (ipod_i2c_wait_not_busy() < 0) { + return -2; + } + + // clear top 15 bits, left shift 1 + outb((device << 17) >> 16, IPOD_I2C_ADDR); + + outb(inb(IPOD_I2C_CTRL) & ~0x20, IPOD_I2C_CTRL); + + outb(data, IPOD_I2C_DATA0); + + outb((inb(IPOD_I2C_CTRL) & ~0x26), IPOD_I2C_CTRL); + + outb(inb(IPOD_I2C_CTRL) | IPOD_I2C_SEND, IPOD_I2C_CTRL); + + return 0; +} + + +/* Returns 0 on success, -1 on failure */ +int i2c_gen_start(int device) +{ + volatile unsigned char *regs = i2c_get_addr(device); + long count = 0; + + /* Wait for bus to become free */ + while ((regs[O_MBSR] & IBB) && (count < MAX_LOOP)) + { + yield(); + count++; + } + + if (count >= MAX_LOOP) + return -1; + + regs[O_MBCR] |= MSTA | MTX; /* Generate START */ + + return 0; +} + +void i2c_gen_stop(int device) +{ + volatile unsigned char *regs = i2c_get_addr(device); + regs[O_MBCR] &= ~MSTA; /* Clear MSTA to generate STOP */ +} + + +volatile unsigned char *i2c_get_addr(int device) +{ + if (device == 1) + return I2C_DEVICE_1; + + return I2C_DEVICE_2; +} diff --git a/firmware/drivers/lcd-16bit.c b/firmware/drivers/lcd-16bit.c new file mode 100644 index 0000000000..f7ea09ab98 --- /dev/null +++ b/firmware/drivers/lcd-16bit.c @@ -0,0 +1,1266 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2005 by Dave Chapman + * + * 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. + * + * 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 "thread.h" +#include +#include +#include "file.h" +#include "debug.h" +#include "system.h" +#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))) + +/*** globals ***/ +unsigned char lcd_framebuffer[LCD_HEIGHT][LCD_WIDTH*2] __attribute__ ((aligned (2))); + +static unsigned fg_pattern = 0x0000; /* Black */ +static unsigned bg_pattern = 0xbc2d; /* "Rockbox blue" */ +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 long scroll_stack[DEFAULT_STACK_SIZE/sizeof(long)]; +static const char scroll_name[] = "scroll"; +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 */ +static int bidir_limit = 50; /* percent */ +static struct scrollinfo scroll[SCROLLABLE_LINES]; + +static const char scroll_tick_table[16] = { + /* Hz values: + 1, 1.25, 1.55, 2, 2.5, 3.12, 4, 5, 6.25, 8.33, 10, 12.5, 16.7, 20, 25, 33 */ + 100, 80, 64, 50, 40, 32, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3 +}; + +#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; +} + +#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 + + 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 */ + rect1 = x; /* start vert */ + rect2 = (LCD_WIDTH - 1) - y; /* start horiz */ + rect3 = (x + height) - 1; /* end vert */ + rect4 = (rect2 - width) + 1; /* end horiz */ + + /* 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 */ + rect2 = rect4; + + /* 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) +{ + drawmode = mode & (DRMODE_SOLID|DRMODE_INVERSEVID); +} + +int lcd_get_drawmode(void) +{ + return drawmode; +} + +void lcd_set_foreground(struct rgb color) +{ + fg_pattern=RGB_PACK(color.red,color.green,color.blue); +} + +struct rgb lcd_get_foreground(void) +{ + struct rgb colour; + + colour.red=((fg_pattern&0xf800)>>11)<<3; + colour.green=((fg_pattern&0x03e0)>>5)<<2; + colour.blue=(fg_pattern&0x1f)<<3; + + return colour; +} + +void lcd_set_background(struct rgb color) +{ + bg_pattern=RGB_PACK(color.red,color.green,color.blue); +} + + +struct rgb lcd_get_background(void) +{ + struct rgb colour; + + colour.red=((bg_pattern&0xf800)>>11)<<3; + colour.green=((bg_pattern&0x03e0)>>5)<<2; + colour.blue=(bg_pattern&0x1f)<<3; + return colour; +} + +void lcd_set_drawinfo(int mode, struct rgb fg_color, + struct rgb bg_color) +{ + lcd_set_drawmode(mode); + lcd_set_foreground(fg_color); + lcd_set_background(bg_color); +} + +void lcd_setmargins(int x, int y) +{ + xmargin = x; + ymargin = y; +} + +int lcd_getxmargin(void) +{ + return xmargin; +} + +int lcd_getymargin(void) +{ + return ymargin; +} + +void lcd_setfont(int newfont) +{ + curfont = newfont; +} + +int lcd_getstringsize(const unsigned char *str, int *w, int *h) +{ + return font_getstringsize(str, w, h, curfont); +} + +/*** low-level drawing functions ***/ + +static void setpixel(int x, int y) +{ + unsigned short *data = &lcd_framebuffer[y][x*2]; + *data = fg_pattern; +} + +static void clearpixel(int x, int y) +{ + unsigned short *data = &lcd_framebuffer[y][x*2]; + *data = bg_pattern; +} + +static void flippixel(int x, int y) +{ + /* What should this do on a color display? */ +} + +static void nopixel(int x, int y) +{ + (void)x; + (void)y; +} + +lcd_pixelfunc_type* const lcd_pixelfuncs[8] = { + flippixel, nopixel, setpixel, setpixel, + nopixel, clearpixel, nopixel, clearpixel +}; + +/* 'mask' and 'bits' contain 2 bits per pixel */ +static void flipblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void flipblock(unsigned short *address, unsigned mask, unsigned bits) +{ + *address ^= bits & mask; +} + +static void bgblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void bgblock(unsigned short *address, unsigned mask, unsigned bits) +{ + if (mask > 0) { + *address = bg_pattern; + } else { + *address = fg_pattern; + } +} + +static void fgblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void fgblock(unsigned short *address, unsigned mask, unsigned bits) +{ + if (mask > 0) { + *address = fg_pattern; + } else { + *address = bg_pattern; + } +} + +static void solidblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void solidblock(unsigned short *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (bits & mask & fg_pattern) + | (~bits & mask & bg_pattern); +} + +static void flipinvblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void flipinvblock(unsigned short *address, unsigned mask, unsigned bits) +{ + *address ^= ~bits & mask; +} + +static void bginvblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void bginvblock(unsigned short *address, unsigned mask, unsigned bits) +{ + mask &= bits; + *address = (*address & ~mask) | (bg_pattern & mask); +} + +static void fginvblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void fginvblock(unsigned short *address, unsigned mask, unsigned bits) +{ + mask &= ~bits; + *address = (*address & ~mask) | (fg_pattern & mask); +} + +static void solidinvblock(unsigned short *address, unsigned mask, unsigned bits) + ICODE_ATTR; +static void solidinvblock(unsigned short *address, unsigned mask, unsigned bits) +{ + *address = (*address & ~mask) | (~bits & mask & fg_pattern) + | (bits & mask & bg_pattern); +} + +lcd_blockfunc_type* const lcd_blockfuncs[8] = { + flipblock, bgblock, fgblock, solidblock, + flipinvblock, bginvblock, fginvblock, solidinvblock +}; + +/*** drawing functions ***/ + +/* Clear the whole display */ +void lcd_clear_display(void) +{ + int i; + unsigned short bits = (drawmode & DRMODE_INVERSEVID) ? fg_pattern : bg_pattern; + unsigned short* addr = (unsigned short*)lcd_framebuffer; + + for (i=0;i= deltay) + { + numpixels = deltax; + d = 2 * deltay - deltax; + dinc1 = deltay * 2; + dinc2 = (deltay - deltax) * 2; + xinc1 = 1; + yinc1 = 0; + } + else + { + numpixels = deltay; + d = 2 * deltax - deltay; + dinc1 = deltax * 2; + dinc2 = (deltax - deltay) * 2; + xinc1 = 0; + yinc1 = 1; + } + numpixels++; /* include endpoints */ + + if (x1 > x2) + { + xinc1 = -xinc1; + xinc2 = -xinc2; + } + + if (y1 > y2) + { + yinc1 = -yinc1; + yinc2 = -yinc2; + } + + x = x1; + y = y1; + + for (i = 0; i < numpixels; i++) + { + if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT)) + pfunc(x, y); + + if (d < 0) + { + d += dinc1; + x += xinc1; + y += yinc1; + } + else + { + d += dinc2; + x += xinc2; + y += yinc2; + } + } +} + +/* Draw a horizontal line (optimised) */ +void lcd_hline(int x1, int x2, int y) +{ + int x; + unsigned char *dst, *dst_end; + unsigned mask; + lcd_blockfunc_type *bfunc; + + /* direction flip */ + if (x2 < x1) + { + x = x1; + x1 = x2; + x2 = x; + } + + /* nothing to draw? */ + if (((unsigned)y >= LCD_HEIGHT) || (x1 >= LCD_WIDTH) || (x2 < 0)) + return; + + /* clipping */ + if (x1 < 0) + x1 = 0; + if (x2 >= LCD_WIDTH) + x2 = LCD_WIDTH-1; + + bfunc = lcd_blockfuncs[drawmode]; + dst = &lcd_framebuffer[y>>2][x1]; + mask = 3 << (2 * (y & 3)); + + dst_end = dst + x2 - x1; + do + bfunc(dst++, mask, 0xFFu); + while (dst <= dst_end); +} + +/* Draw a vertical line (optimised) */ +void lcd_vline(int x, int y1, int y2) +{ + int ny; + unsigned char *dst; + unsigned mask, mask_bottom; + lcd_blockfunc_type *bfunc; + + /* direction flip */ + if (y2 < y1) + { + ny = y1; + y1 = y2; + y2 = ny; + } + + /* nothing to draw? */ + if (((unsigned)x >= LCD_WIDTH) || (y1 >= LCD_HEIGHT) || (y2 < 0)) + return; + + /* clipping */ + if (y1 < 0) + y1 = 0; + if (y2 >= LCD_HEIGHT) + y2 = LCD_HEIGHT-1; + + bfunc = lcd_blockfuncs[drawmode]; + dst = &lcd_framebuffer[y1>>2][x]; + ny = y2 - (y1 & ~3); + mask = 0xFFu << (2 * (y1 & 3)); + mask_bottom = 0xFFu >> (2 * (~ny & 3)); + + for (; ny >= 4; ny -= 4) + { + bfunc(dst, mask, 0xFFu); + dst += LCD_WIDTH; + mask = 0xFFu; + } + mask &= mask_bottom; + bfunc(dst, mask, 0xFFu); +} + +/* Draw a rectangular box */ +void lcd_drawrect(int x, int y, int width, int height) +{ + if ((width <= 0) || (height <= 0)) + return; + + int x2 = x + width - 1; + int y2 = y + height - 1; + + lcd_vline(x, y, y2); + lcd_vline(x2, y, y2); + lcd_hline(x, x2, y); + lcd_hline(x, x2, y2); +} + +/* Fill a rectangular area */ +void lcd_fillrect(int x, int y, int width, int height) +{ + int ny; + unsigned char *dst, *dst_end; + unsigned mask, mask_bottom; + unsigned bits = fg_pattern; + lcd_blockfunc_type *bfunc; + bool fillopt; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + x = 0; + } + if (y < 0) + { + height += y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; + + fillopt = (drawmode & DRMODE_INVERSEVID) ? + (drawmode & DRMODE_BG) : (drawmode & DRMODE_FG); + if (fillopt &&(drawmode & DRMODE_INVERSEVID)) + bits = bg_pattern; + bfunc = lcd_blockfuncs[drawmode]; + dst = &lcd_framebuffer[y>>2][x]; + ny = height - 1 + (y & 3); + mask = 0xFFu << (2 * (y & 3)); + mask_bottom = 0xFFu >> (2 * (~ny & 3)); + + for (; ny >= 4; ny -= 4) + { + if (fillopt && (mask == 0xFFu)) + memset(dst, bits, width); + else + { + unsigned char *dst_row = dst; + + dst_end = dst_row + width; + do + bfunc(dst_row++, mask, 0xFFu); + while (dst_row < dst_end); + } + + dst += LCD_WIDTH; + mask = 0xFFu; + } + mask &= mask_bottom; + + if (fillopt && (mask == 0xFFu)) + memset(dst, bits, width); + else + { + dst_end = dst + width; + do + bfunc(dst++, mask, 0xFFu); + while (dst < dst_end); + } +} + +/* About Rockbox' internal monochrome bitmap format: + * + * A bitmap contains one bit for every pixel that defines if that pixel is + * black (1) or white (0). Bits within a byte are arranged vertically, LSB + * at top. + * The bytes are stored in row-major order, with byte 0 being top left, + * byte 1 2nd from left etc. The first row of bytes defines pixel rows + * 0..7, the second row defines pixel row 8..15 etc. + * + * This is similar to the internal lcd hw format. */ + +static unsigned char masks[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; + +/* Draw a partial monochrome bitmap */ +void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) + ICODE_ATTR; +void lcd_mono_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + int in_x,in_y; + int out_x; + int out_y; + unsigned char pixel; + int src_width=src_x+width+stride; + unsigned short* addr; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; + +// src += stride * (src_y >> 3) + src_x; /* move starting point */ + + /* Copying from src_x,src_y to (x,y). Size is width,height */ + in_x=src_x; + for (out_x=x;out_x<(x+width);out_x++) { + in_y=src_y; + for (out_y=y;out_y<(y+height);out_y++) { + pixel=(*src)&masks[in_y]; + addr=(unsigned short*)&lcd_framebuffer[out_y][out_x*2]; + if (pixel > 0) { + *addr=fg_pattern; + } else { + *addr=bg_pattern; + } + in_y++; + } + in_x++; + src++; + } +} + +/* Draw a full monochrome bitmap */ +void lcd_mono_bitmap(const unsigned char *src, int x, int y, int width, int height) +{ + lcd_mono_bitmap_part(src, 0, 0, width, x, y, width, height); +} + +/* Draw a partial native bitmap */ +void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) + ICODE_ATTR; +void lcd_bitmap_part(const unsigned char *src, int src_x, int src_y, + int stride, int x, int y, int width, int height) +{ + int shift, ny; + unsigned char *dst, *dst_end; + unsigned mask, mask_bottom; + lcd_blockfunc_type *bfunc; + + /* nothing to draw? */ + if ((width <= 0) || (height <= 0) || (x >= LCD_WIDTH) || (y >= LCD_HEIGHT) + || (x + width <= 0) || (y + height <= 0)) + return; + + /* clipping */ + if (x < 0) + { + width += x; + src_x -= x; + x = 0; + } + if (y < 0) + { + height += y; + src_y -= y; + y = 0; + } + if (x + width > LCD_WIDTH) + width = LCD_WIDTH - x; + if (y + height > LCD_HEIGHT) + height = LCD_HEIGHT - y; + + src += stride * (src_y >> 2) + src_x; /* move starting point */ + src_y &= 3; + y -= src_y; + dst = &lcd_framebuffer[y>>2][x]; + shift = y & 3; + ny = height - 1 + shift + src_y; + + bfunc = lcd_blockfuncs[drawmode]; + mask = 0xFFu << (2 * (shift + src_y)); + mask_bottom = 0xFFu >> (2 * (~ny & 3)); + + if (shift == 0) + { + for (; ny >= 4; ny -= 4) + { + if (mask == 0xFFu) + memcpy(dst, src, width); + else + { + const unsigned char *src_row = src; + unsigned char *dst_row = dst; + + dst_end = dst_row + width; + do + bfunc(dst_row++, mask, *src_row++); + while (dst_row < dst_end); + } + + src += stride; + dst += LCD_WIDTH; + mask = 0xFFu; + } + mask &= mask_bottom; + + if (mask == 0xFFu) + memcpy(dst, src, width); + else + { + dst_end = dst + width; + do + bfunc(dst++, mask, *src++); + while (dst < dst_end); + } + } + else + { + shift *= 2; + dst_end = dst + width; + do + { + const unsigned char *src_col = src++; + unsigned char *dst_col = dst++; + unsigned mask_col = mask; + unsigned data = 0; + + for (y = ny; y >= 4; y -= 4) + { + data |= *src_col << shift; + + if (mask_col & 0xFFu) + { + bfunc(dst_col, mask_col, data); + mask_col = 0xFFu; + } + else + mask_col >>= 8; + + src_col += stride; + dst_col += LCD_WIDTH; + data >>= 8; + } + data |= *src_col << shift; + bfunc(dst_col, mask_col & mask_bottom, data); + } + while (dst < dst_end); + } +} + +/* Draw a full native bitmap */ +void lcd_bitmap(const unsigned char *src, int x, int y, int width, int height) +{ + unsigned short* s=src; + unsigned short* d=(unsigned short*)&lcd_framebuffer[y][x*2]; + int k=LCD_WIDTH-width; + int i,j; + + for (i=0;ifirstchar || ch >= pf->firstchar+pf->size) + ch = pf->defaultchar; + ch -= pf->firstchar; + + /* get proportional width and glyph bits */ + width = pf->width ? pf->width[ch] : pf->maxwidth; + + if (ofs > width) + { + ofs -= width; + continue; + } + + bits = pf->bits + (pf->offset ? + pf->offset[ch] : ((pf->height + 7) / 8 * pf->maxwidth * ch)); + + lcd_mono_bitmap_part(bits, ofs, 0, width, x, y, width - ofs, pf->height); + + x += width - ofs; + ofs = 0; + } +} + +/* put a string at a given pixel position */ +void lcd_putsxy(int x, int y, const unsigned char *str) +{ + lcd_putsxyofs(x, y, 0, str); +} + +/*** line oriented text output ***/ + +void lcd_puts_style(int x, int y, const unsigned char *str, int style) +{ + int xpos,ypos,w,h; + int lastmode = drawmode; + + /* make sure scrolling is turned off on the line we are updating */ + scrolling_lines &= ~(1 << y); + + if(!str || !str[0]) + return; + + lcd_getstringsize(str, &w, &h); + xpos = xmargin + x*w / strlen(str); + ypos = ymargin + y*h; + lcd_putsxy(xpos, ypos, str); +#if 0 + drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); + lcd_fillrect(xpos + w, ypos, LCD_WIDTH - (xpos + w), h); + if (style & STYLE_INVERT) + { + drawmode = DRMODE_COMPLEMENT; + lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, h); + } + drawmode = lastmode; +#endif +} + +/* put a string at a given char position */ +void lcd_puts(int x, int y, const unsigned char *str) +{ + lcd_puts_style(x, y, str, STYLE_DEFAULT); +} + +/*** scrolling ***/ + +/* Reverse the invert setting of the scrolling line (if any) at given char + position. Setting will go into affect next time line scrolls. */ +void lcd_invertscroll(int x, int y) +{ + struct scrollinfo* s; + + (void)x; + + s = &scroll[y]; + s->invert = !s->invert; +} + +void lcd_stop_scroll(void) +{ + scrolling_lines=0; +} + +void lcd_scroll_speed(int speed) +{ + scroll_ticks = scroll_tick_table[speed]; +} + +void lcd_scroll_step(int step) +{ + scroll_step = step; +} + +void lcd_scroll_delay(int ms) +{ + scroll_delay = ms / (HZ / 10); +} + +void lcd_bidir_scroll(int percent) +{ + bidir_limit = percent; +} + +void lcd_puts_scroll(int x, int y, const unsigned char *string) +{ + lcd_puts_scroll_style(x, y, string, STYLE_DEFAULT); +} + +void lcd_puts_scroll_style(int x, int y, const unsigned char *string, int style) +{ + struct scrollinfo* s; + int w, h; + + s = &scroll[y]; + + s->start_tick = current_tick + scroll_delay; + s->invert = false; + if (style & STYLE_INVERT) { + s->invert = true; + lcd_puts_style(x,y,string,STYLE_INVERT); + } + else + lcd_puts(x,y,string); + + lcd_getstringsize(string, &w, &h); + + if (LCD_WIDTH - x * 8 - xmargin < w) { + /* prepare scroll line */ + char *end; + + memset(s->line, 0, sizeof s->line); + strcpy(s->line, string); + + /* get width */ + s->width = lcd_getstringsize(s->line, &w, &h); + + /* scroll bidirectional or forward only depending on the string + width */ + if ( bidir_limit ) { + s->bidir = s->width < (LCD_WIDTH - xmargin) * + (100 + bidir_limit) / 100; + } + else + s->bidir = false; + + if (!s->bidir) { /* add spaces if scrolling in the round */ + strcat(s->line, " "); + /* get new width incl. spaces */ + s->width = lcd_getstringsize(s->line, &w, &h); + } + + end = strchr(s->line, '\0'); + strncpy(end, string, LCD_WIDTH/2); + + s->len = strlen(string); + s->offset = 0; + s->startx = x; + s->backward = false; + scrolling_lines |= (1<start_tick)) + continue; + + if (s->backward) + s->offset -= scroll_step; + else + s->offset += scroll_step; + + pf = font_get(curfont); + xpos = xmargin + s->startx * s->width / s->len; + ypos = ymargin + index * pf->height; + + if (s->bidir) { /* scroll bidirectional */ + if (s->offset <= 0) { + /* at beginning of line */ + s->offset = 0; + s->backward = false; + s->start_tick = current_tick + scroll_delay * 2; + } + if (s->offset >= s->width - (LCD_WIDTH - xpos)) { + /* at end of line */ + s->offset = s->width - (LCD_WIDTH - xpos); + s->backward = true; + s->start_tick = current_tick + scroll_delay * 2; + } + } + else { + /* scroll forward the whole time */ + if (s->offset >= s->width) + s->offset %= s->width; + } + + lastmode = drawmode; + drawmode = (DRMODE_SOLID|DRMODE_INVERSEVID); + lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + drawmode = DRMODE_SOLID; + lcd_putsxyofs(xpos, ypos, s->offset, s->line); + if (s->invert) + { + drawmode = DRMODE_COMPLEMENT; + lcd_fillrect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + } + drawmode = lastmode; + lcd_update_rect(xpos, ypos, LCD_WIDTH - xpos, pf->height); + } + + sleep(scroll_ticks); + } +} + diff --git a/firmware/drivers/power.c b/firmware/drivers/power.c index 7d45021cab..c7ef691f91 100644 --- a/firmware/drivers/power.c +++ b/firmware/drivers/power.c @@ -73,6 +73,8 @@ void power_init(void) #ifdef HAVE_SPDIF_POWER spdif_power_enable(false); #endif +#elif CONFIG_CPU == PP5020 +#warning Implement power_init() #else #ifdef HAVE_POWEROFF_ON_PB5 PBCR2 &= ~0x0c00; /* GPIO for PB5 */ @@ -163,6 +165,8 @@ void ide_power_enable(bool on) and_l(~0x80000000, &GPIO_OUT); else or_l(0x80000000, &GPIO_OUT); +#elif CONFIG_CPU == PP5020 +#warning Implement ide_power_enable() #elif defined(GMINI_ARCH) if(on) P1 |= 0x08; @@ -213,6 +217,9 @@ bool ide_powered(void) { #if CONFIG_CPU == MCF5249 return (GPIO_OUT & 0x80000000)?false:true; +#elif CONFIG_CPU == PP5020 +#warning Implement ide_powered() + return true; #elif defined(GMINI_ARCH) return (P1 & 0x08?true:false); #else /* SH1 based archos */ @@ -244,6 +251,8 @@ void power_off(void) set_irq_level(HIGHEST_IRQ_LEVEL); #if CONFIG_CPU == MCF5249 and_l(~0x00080000, &GPIO1_OUT); +#elif CONFIG_CPU == PP5020 +#warning Implement power_off() #elif defined(GMINI_ARCH) P1 &= ~1; P1CON &= ~1; diff --git a/firmware/drivers/serial.c b/firmware/drivers/serial.c index 728bc6f45f..4c5c5a8172 100644 --- a/firmware/drivers/serial.c +++ b/firmware/drivers/serial.c @@ -27,8 +27,8 @@ #include "lcd.h" #include "serial.h" -#if (CONFIG_CPU != MCF5249) && (CONFIG_CPU != TCC730) -/* FIX: this doesn't work on iRiver or Gmini yet */ +#if (CONFIG_CPU != MCF5249) && (CONFIG_CPU != TCC730) && (CONFIG_CPU != PP5020) +/* FIX: this doesn't work on iRiver or Gmini or iPod yet */ #ifndef HAVE_MMC /* MMC takes serial port 1, so don't mess with it */ diff --git a/firmware/export/button.h b/firmware/export/button.h index e1caa52b54..61c722bfb2 100644 --- a/firmware/export/button.h +++ b/firmware/export/button.h @@ -144,6 +144,17 @@ bool remote_button_hold(void); #define BUTTON_DOWN 0x0020 #define BUTTON_MENU 0x0100 +#elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_NANO_PAD) + +#warning Correct the IPOD definitions + +#define BUTTON_ON 0x0001 +#define BUTTON_OFF 0x0002 +#define BUTTON_PLAY 0x0004 +#define BUTTON_UP 0x0010 +#define BUTTON_DOWN 0x0020 +#define BUTTON_MENU 0x0100 + #endif /* RECORDER/PLAYER/ONDIO/GMINI KEYPAD */ #endif /* _BUTTON_H_ */ diff --git a/firmware/export/config-ipodcolor.h b/firmware/export/config-ipodcolor.h new file mode 100644 index 0000000000..f30ef28398 --- /dev/null +++ b/firmware/export/config-ipodcolor.h @@ -0,0 +1,87 @@ +/* For Rolo and boot loader */ +#define MODEL_NUMBER 3 + +/* define this if you have recording possibility */ +/*#define HAVE_RECORDING 1*/ + +/* define this if you have a bitmap LCD display */ +#define HAVE_LCD_BITMAP 1 + +/* define this if you have a colour LCD */ +#define HAVE_LCD_COLOR 1 + +/* LCD dimensions */ +#define LCD_WIDTH 220 +#define LCD_HEIGHT 176 +#define LCD_DEPTH 16 /* 65536 colours */ + +#define CONFIG_KEYPAD IPOD_4G_PAD + +/* Define this if you do software codec */ +#define CONFIG_CODEC SWCODEC + +/* Define this if you have a software controlled poweroff */ +#define HAVE_SW_POWEROFF + +/* The number of bytes reserved for loadable codecs */ +#define CODEC_SIZE 0x40000 + +/* The number of bytes reserved for loadable plugins */ +#define PLUGIN_BUFFER_SIZE 0xC0000 + +//#define HAVE_UDA1380 + +#ifndef SIMULATOR + +/* Define this if you have a PortalPlayer PP5020 */ +#define CONFIG_CPU PP5020 + +/* Define this if you want to use the PP5020 i2c interface */ +#define CONFIG_I2C I2C_PP5020 + +/* Type of mobile power */ +//#define CONFIG_BATTERY BATT_LIPOL1300 + +#define BATTERY_SCALE_FACTOR 16665 /* FIX: this value is picked at random */ + +/* Define this if the platform can charge batteries */ +//#define HAVE_CHARGING 1 + +/* define this if the hardware can be powered off while charging */ +//#define HAVE_POWEROFF_WHILE_CHARGING + +/* The start address index for ROM builds */ +#define ROM_START 0x00000000 + +/* Define this for LCD backlight available */ +#define CONFIG_BACKLIGHT BL_IPOD4G /* port controlled */ + +/* Define this to the CPU frequency */ +#define CPU_FREQ 11289600 + +/* Define this if you have ATA power-off control */ +#define HAVE_ATA_POWER_OFF + +#define CONFIG_LCD LCD_IPODCOLOR + +/* Offset ( in the firmware file's header ) to the file length */ +#define FIRMWARE_OFFSET_FILE_LENGTH 0 + +/* Offset ( in the firmware file's header ) to the file CRC */ +#define FIRMWARE_OFFSET_FILE_CRC 0 + +/* Offset ( in the firmware file's header ) to the real data */ +#define FIRMWARE_OFFSET_FILE_DATA 8 + +#define USB_IPODSTYLE + +/* Virtual LED (icon) */ +#define CONFIG_LED LED_VIRTUAL + +/* Define this if you have adjustable CPU frequency */ +//#define HAVE_ADJUSTABLE_CPU_FREQ + +#define BOOTFILE_EXT "ipodcolor" +#define BOOTFILE "rockbox." BOOTFILE_EXT + +#endif diff --git a/firmware/export/config-ipodnano.h b/firmware/export/config-ipodnano.h new file mode 100644 index 0000000000..8ba3cfae01 --- /dev/null +++ b/firmware/export/config-ipodnano.h @@ -0,0 +1,89 @@ +/* For Rolo and boot loader */ +#define MODEL_NUMBER 4 + +/* define this if you have recording possibility */ +/*#define HAVE_RECORDING 1*/ + +/* define this if you have a bitmap LCD display */ +#define HAVE_LCD_BITMAP 1 + +/* define this if you have a colour LCD */ +#define HAVE_LCD_COLOR 1 + +/* LCD dimensions */ +#define LCD_WIDTH 176 +#define LCD_HEIGHT 132 +#define LCD_DEPTH 16 /* 65536 colours */ + +#define CONFIG_KEYPAD IPOD_NANO_PAD + +/* Define this if you do software codec */ +#define CONFIG_CODEC SWCODEC + +/* Define this if you have a software controlled poweroff */ +#define HAVE_SW_POWEROFF + +/* The number of bytes reserved for loadable codecs */ +#define CODEC_SIZE 0x40000 + +/* The number of bytes reserved for loadable plugins */ +#define PLUGIN_BUFFER_SIZE 0xC0000 + +//#define HAVE_UDA1380 + +#ifndef SIMULATOR + +/* The Nano actually has a PP5021 - but it's register compatible with + the 5020 so Rockbox doesn't care. */ +/* Define this if you have a PortalPlayer PP5020 */ +#define CONFIG_CPU PP5020 + +/* Define this if you want to use the PP5020 i2c interface */ +#define CONFIG_I2C I2C_PP5020 + +/* Type of mobile power */ +//#define CONFIG_BATTERY BATT_LIPOL1300 + +#define BATTERY_SCALE_FACTOR 16665 /* FIX: this value is picked at random */ + +/* Define this if the platform can charge batteries */ +//#define HAVE_CHARGING 1 + +/* define this if the hardware can be powered off while charging */ +//#define HAVE_POWEROFF_WHILE_CHARGING + +/* The start address index for ROM builds */ +#define ROM_START 0x00000000 + +/* Define this for LCD backlight available */ +#define CONFIG_BACKLIGHT BL_IPODNANO /* port controlled */ + +/* Define this to the CPU frequency */ +#define CPU_FREQ 11289600 + +/* Define this if you have ATA power-off control */ +#define HAVE_ATA_POWER_OFF + +#define CONFIG_LCD LCD_IPODCOLOR + +/* Offset ( in the firmware file's header ) to the file length */ +#define FIRMWARE_OFFSET_FILE_LENGTH 0 + +/* Offset ( in the firmware file's header ) to the file CRC */ +#define FIRMWARE_OFFSET_FILE_CRC 0 + +/* Offset ( in the firmware file's header ) to the real data */ +#define FIRMWARE_OFFSET_FILE_DATA 8 + +#define USB_IPODSTYLE + +/* Virtual LED (icon) */ +#define CONFIG_LED LED_VIRTUAL + +/* Define this if you have adjustable CPU frequency */ +//#define HAVE_ADJUSTABLE_CPU_FREQ + +#define BOOTFILE_EXT "ipod" +#define BOOTFILE "rockbox." BOOTFILE_EXT + +#endif diff --git a/firmware/export/config.h b/firmware/export/config.h index 66f53eb0ed..41e639f125 100644 --- a/firmware/export/config.h +++ b/firmware/export/config.h @@ -39,6 +39,8 @@ #define MCF5249 5249 #define MCF5250 5250 #define TCC730 730 /* lacking a proper abbrivation */ +#define PP5002 5002 +#define PP5020 5020 /* CONFIG_KEYPAD */ #define PLAYER_PAD 0 @@ -48,6 +50,8 @@ #define GMINI100_PAD 4 #define IRIVER_H300_PAD 5 #define IAUDIO_X5_PAD 6 +#define IPOD_4G_PAD 7 +#define IPOD_NANO_PAD 8 /* CONFIG_REMOTE_KEYPAD */ #define H100_REMOTE 1 @@ -61,14 +65,16 @@ #define BATT_LIPOL1300 1300 /* the type used in iRiver h1x0 models */ /* CONFIG_LCD */ -#define LCD_GMINI100 0 -#define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ -#define LCD_SSD1801 2 /* as used by Archos Player/Studio */ -#define LCD_S1D15E06 3 /* as used by iRiver H100 series */ -#define LCD_H300 4 /* as used by iRiver H300 series, exact model name is - unknown at the time of this writing */ -#define LCD_X5 5 /* as used by iAudio X5 series, exact model name is +#define LCD_GMINI100 0 +#define LCD_SSD1815 1 /* as used by Archos Recorders and Ondios */ +#define LCD_SSD1801 2 /* as used by Archos Player/Studio */ +#define LCD_S1D15E06 3 /* as used by iRiver H100 series */ +#define LCD_H300 4 /* as used by iRiver H300 series, exact model name is + unknown at the time of this writing */ +#define LCD_X5 5 /* as used by iAudio X5 series, exact model name is unknown at the time of this writing */ +#define LCD_IPODCOLOR 6 /* as used by iPod Color/Photo */ +#define LCD_IPODNANO 7 /* as used by iPod Nano */ /* CONFIG_BACKLIGHT */ #define BL_PA14_LO 0 /* Player, PA14 low active */ @@ -76,12 +82,15 @@ #define BL_PA14_HI 2 /* Ondio, PA14 high active */ #define BL_IRIVER 3 /* IRiver GPIO */ #define BL_GMINI 4 /* Archos GMini */ +#define BL_IPOD4G 5 /* Apple iPod 4G */ +#define BL_IPODNANO 6 /* Apple iPod Nano */ /* CONFIG_I2C */ #define I2C_PLAYREC 0 /* Archos Player/Recorder style */ #define I2C_ONDIO 1 /* Ondio style */ #define I2C_GMINI 2 /* Gmini style */ #define I2C_COLDFIRE 3 /* Coldfire style */ +#define I2C_PP5020 4 /* PP5020 style */ /* CONFIG_LED */ #define LED_REAL 1 /* SW controlled LED (Archos recorders, player, Gmini) */ @@ -113,6 +122,10 @@ #include "config-gminisp.h" #elif defined(IAUDIO_X5) #include "config-iaudiox5.h" +#elif defined(IPOD_COLOR) +#include "config-ipodcolor.h" +#elif defined(IPOD_NANO) +#include "config-ipodnano.h" #else /* no known platform */ #endif @@ -129,6 +142,11 @@ #define CPU_COLDFIRE #endif +/* define for all cpus from ARM family */ +#if (CONFIG_CPU == PP5020) +#define CPU_ARM +#endif + #ifndef CODEC_SIZE #define CODEC_SIZE 0 #endif @@ -137,7 +155,8 @@ #if !defined(SIMULATOR) && /* Not for simulators */ \ (((CONFIG_CPU == SH7034) && !defined(PLUGIN)) || /* SH1 archos: core only */ \ (CONFIG_CPU == MCF5249) || /* Coldfire: core, plugins, codecs */ \ - (CONFIG_CPU == TCC730)) /* CalmRISC16: core, (plugins, codecs) */ + (CONFIG_CPU == PP5020) || /* iPod: core, plugins, codecs */ \ + (CONFIG_CPU == TCC730)) /* CalmRISC16: core, (plugins, codecs) */ #define ICODE_ATTR __attribute__ ((section(".icode"))) #define ICONST_ATTR __attribute__ ((section(".irodata"))) #define IDATA_ATTR __attribute__ ((section(".idata"))) diff --git a/firmware/export/i2c-pp5020.h b/firmware/export/i2c-pp5020.h new file mode 100644 index 0000000000..d26a7feab5 --- /dev/null +++ b/firmware/export/i2c-pp5020.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * 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. + * + ****************************************************************************/ + +/* + * Driver for ARM i2c driver + * + * + */ + +#ifndef _I2C_ARM_H +#define _I2C_ARM_H + +#warning Implement: i2c-pp5020.h + +void i2c_init(void); +int i2c_write(int device, unsigned char *buf, int count); +void i2c_close(void); + + +#define MAX_LOOP 0x100 /* TODO: select a better value */ + +/* PLLCR control */ +#define QSPISEL (1 << 11) /* Selects QSPI or I2C interface */ + +/* Offsets to I2C registers from base address */ +#define O_MADR 0x00 /* Slave Address */ +#define O_MFDR 0x04 /* Frequency divider */ +#define O_MBCR 0x08 /* Control register */ +#define O_MBSR 0x0c /* Status register */ +#define O_MBDR 0x10 /* Data register */ + +/* MBSR - Status register */ +#define ICF (1 << 7) /* Transfer Complete */ +#define IAAS (1 << 6) /* Addressed As Alave */ +#define IBB (1 << 5) /* Bus Busy */ +#define IAL (1 << 4) /* Arbitration Lost */ +#define SRW (1 << 2) /* Slave R/W */ +#define IFF (1 << 1) /* I2C Interrupt */ +#define RXAK (1 << 0) /* No Ack bit */ + +/* MBCR - Control register */ +#define IEN (1 << 7) /* I2C Enable */ +#define IIEN (1 << 6) /* Interrupt Enable */ +#define MSTA (1 << 5) /* Master/Slave select */ +#define MTX (1 << 4) /* Transmit/Receive */ +#define TXAK (1 << 3) /* Transfer ACK */ +#define RSTA (1 << 2) /* Restart.. */ + + +#endif diff --git a/firmware/export/kernel.h b/firmware/export/kernel.h index 039af56586..ab966da78f 100644 --- a/firmware/export/kernel.h +++ b/firmware/export/kernel.h @@ -20,6 +20,7 @@ #define _KERNEL_H_ #include +#include "config.h" /* wrap-safe macros for tick comparison */ #define TIME_AFTER(a,b) ((long)(b) - (long)(a) < 0) @@ -65,7 +66,12 @@ struct mutex }; /* global tick variable */ +#if (CONFIG_CPU==PP5020) +/* A temporary hack until timer interrupt is enabled - use the RTC */ +#define current_tick ((*((volatile unsigned long*)0x60005010))/10000) +#else extern long current_tick; +#endif #ifdef SIMULATOR #define sleep(x) sim_sleep(x) diff --git a/firmware/export/lcd.h b/firmware/export/lcd.h index c8be1d34f6..28458fedb2 100644 --- a/firmware/export/lcd.h +++ b/firmware/export/lcd.h @@ -122,14 +122,24 @@ extern void lcd_jump_scroll_delay(int ms); /* Low-level drawing function types */ typedef void lcd_pixelfunc_type(int x, int y); +#if LCD_DEPTH==16 typedef void lcd_blockfunc_type(unsigned char *address, unsigned mask, unsigned bits); +#else +typedef void lcd_blockfunc_type(unsigned char *address, unsigned mask, unsigned bits); +#endif #ifdef HAVE_LCD_BITMAP #ifdef HAVE_LCD_COLOR +#if LCD_DEPTH == 16 +#define LCD_MAX_RED ((1 << 5) - 1) +#define LCD_MAX_GREEN ((1 << 6) - 1) +#define LCD_MAX_BLUE ((1 << 5) - 1) +#else #define LCD_MAX_RED ((1 << (LCD_DEPTH/3)) - 1) #define LCD_MAX_GREEN ((1 << (LCD_DEPTH/3)) - 1) #define LCD_MAX_BLUE ((1 << (LCD_DEPTH/3)) - 1) +#endif struct rgb { unsigned char red; unsigned char green; @@ -148,6 +158,8 @@ struct rgb { extern unsigned char lcd_framebuffer[LCD_HEIGHT/8][LCD_WIDTH]; #elif LCD_DEPTH == 2 extern unsigned char lcd_framebuffer[LCD_HEIGHT/4][LCD_WIDTH]; +#elif LCD_DEPTH == 16 +extern unsigned char lcd_framebuffer[LCD_HEIGHT][LCD_WIDTH*2]; #endif extern void lcd_set_invert_display(bool yesno); diff --git a/firmware/export/system.h b/firmware/export/system.h index 313a9a8e4c..15c6edb00e 100644 --- a/firmware/export/system.h +++ b/firmware/export/system.h @@ -29,6 +29,13 @@ extern void system_init(void); extern long cpu_frequency; +#if CONFIG_CPU==PP5020 +#define inl(a) (*(volatile unsigned long *) (a)) +#define outl(a,b) (*(volatile unsigned long *) (b) = (a)) +#define inb(a) (*(volatile unsigned char *) (a)) +#define outb(a,b) (*(volatile unsigned char *) (b) = (a)) +#endif + #ifdef HAVE_ADJUSTABLE_CPU_FREQ #define FREQ cpu_frequency void set_cpu_frequency(long frequency); @@ -285,6 +292,43 @@ static inline void invalidate_icache(void) #define CPUFREQ_MAX_MULT 11 #define CPUFREQ_MAX (CPUFREQ_MAX_MULT * CPU_FREQ) +#elif CONFIG_CPU == PP5020 + +#warning Implement set_irq_level and check CPU frequencies + +#define CPUFREQ_DEFAULT CPU_FREQ +#define CPUFREQ_NORMAL 37500000 +#define CPUFREQ_MAX 75000000 + +static inline unsigned short swap16(unsigned short value) + /* + result[15..8] = value[ 7..0]; + result[ 7..0] = value[15..8]; + */ +{ + return (value >> 8) | (value << 8); +} + +static inline unsigned long swap32(unsigned long value) + /* + result[31..24] = value[ 7.. 0]; + result[23..16] = value[15.. 8]; + result[15.. 8] = value[23..16]; + result[ 7.. 0] = value[31..24]; + */ +{ + unsigned long hi = swap16(value >> 16); + unsigned long lo = swap16(value & 0xffff); + return (lo << 16) | hi; +} + +#define HIGHEST_IRQ_LEVEL (1) +static inline int set_irq_level(int level) +{ + int result=level; + return result; +} + #elif CONFIG_CPU == TCC730 extern int smsc_version(void); diff --git a/firmware/kernel.c b/firmware/kernel.c index 9af4566662..215d5de46b 100644 --- a/firmware/kernel.c +++ b/firmware/kernel.c @@ -25,7 +25,9 @@ #include "system.h" #include "panic.h" +#if (CONFIG_CPU != PP5020) long current_tick = 0; +#endif static void (*tick_funcs[MAX_NUM_TICK_TASKS])(void); @@ -65,6 +67,11 @@ void sleep(int ticks) void yield(void) { +#if CONFIG_CPU == PP5020 + /* Threading not yet implemented */ + #warning Enable yield() + return; +#endif switch_thread(); wake_up_thread(); } @@ -315,6 +322,12 @@ void tick_start(unsigned int interval_in_ms) IMR0 |= (1<<2); } +#elif CONFIG_CPU == PP5020 + +void tick_start(unsigned int interval_in_ms) { +#warning Implement tick_start +} + #endif int tick_add_task(void (*f)(void)) diff --git a/firmware/rolo.c b/firmware/rolo.c index f6fba5f840..43f5031146 100644 --- a/firmware/rolo.c +++ b/firmware/rolo.c @@ -143,7 +143,7 @@ int rolo_load(const char* filename) lcd_update(); set_irq_level(HIGHEST_IRQ_LEVEL); -#else +#elif CONFIG_CPU == SH7034 /* Read file length from header and compare to real file length */ lseek(fd, FIRMWARE_OFFSET_FILE_LENGTH, SEEK_SET); if(read(fd, &file_length, 4) != 4) { diff --git a/firmware/system.c b/firmware/system.c index d6b48247ea..7da1034739 100644 --- a/firmware/system.c +++ b/firmware/system.c @@ -1094,5 +1094,18 @@ int system_memory_guard(int newmode) return oldmode; } +#elif CONFIG_CPU==PP5020 + +#warning TODO: Implement system.c + +void system_init(void) { + +} + +void system_reboot(void) { + +} + + #endif /* CONFIG_CPU */ diff --git a/firmware/thread.c b/firmware/thread.c index 7ee4072895..83607ea964 100644 --- a/firmware/thread.c +++ b/firmware/thread.c @@ -41,6 +41,14 @@ struct regs void *pr; /* Procedure register */ void *start; /* Thread start address, or NULL when started */ }; +#elif CONFIG_CPU == PP5020 +#warning TODO: define struct regs +struct regs +{ + void *sp; /* Stack pointer (a15) */ + void *start; /* Thread start address */ + int started; /* 0 when not started */ +}; #elif CONFIG_CPU == TCC730 struct regs { @@ -70,7 +78,21 @@ void switch_thread(void) ICODE_ATTR; static inline void store_context(void* addr) __attribute__ ((always_inline)); static inline void load_context(const void* addr) __attribute__ ((always_inline)); -#ifdef CPU_COLDFIRE +#if CONFIG_CPU == PP5020 + +#warning TODO: Implement store_context and load_context + +static inline void store_context(void* addr) +{ +} + +static inline void load_context(const void* addr) +{ + +} + + +#elif defined(CPU_COLDFIRE) /*--------------------------------------------------------------------------- * Store non-volatile context. *--------------------------------------------------------------------------- @@ -341,6 +363,8 @@ void init_threads(void) thread_contexts[0].start = 0; /* thread 0 already running */ #elif CONFIG_CPU == TCC730 thread_contexts[0].started = 1; +#elif CONFIG_CPU == PP5020 + thread_contexts[0].start = 0; /* thread 0 already running */ #endif num_sleepers = 0; } diff --git a/firmware/usb.c b/firmware/usb.c index 8a99683a25..f69df5a87d 100644 --- a/firmware/usb.c +++ b/firmware/usb.c @@ -145,6 +145,10 @@ static void usb_enable(bool on) and_l(~0x01000000, &GPIO_OUT); } +#elif defined(USB_IPODSTYLE) + +#warning Implement USB_IPODSTYLE + #else #ifdef HAVE_LCD_BITMAP if(read_hw_mask() & USB_ACTIVE_HIGH)