summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Chapman <dave@dchapman.com>2005-11-07 23:07:19 +0000
committerDave Chapman <dave@dchapman.com>2005-11-07 23:07:19 +0000
commit77372d12189c70cb810a7e88bc2ee7a56f64646c (patch)
tree057d0d474042874850b6262b78f80d2335cb0629
parent3cd5c646d03089df8d58b773d4a1bc8323021adc (diff)
downloadrockbox-77372d12189c70cb810a7e88bc2ee7a56f64646c.zip
rockbox-77372d12189c70cb810a7e88bc2ee7a56f64646c.tar.gz
rockbox-77372d12189c70cb810a7e88bc2ee7a56f64646c.tar.bz2
rockbox-77372d12189c70cb810a7e88bc2ee7a56f64646c.tar.xz
Initial commit of work-in-progress iPod port
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@7781 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/SOURCES4
-rw-r--r--firmware/app.lds44
-rw-r--r--firmware/backlight.c10
-rw-r--r--firmware/boot.lds55
-rw-r--r--firmware/crt0.S135
-rw-r--r--firmware/drivers/adc.c14
-rw-r--r--firmware/drivers/ata.c61
-rw-r--r--firmware/drivers/i2c-pp5020.c189
-rw-r--r--firmware/drivers/lcd-16bit.c1266
-rw-r--r--firmware/drivers/power.c9
-rw-r--r--firmware/drivers/serial.c4
-rw-r--r--firmware/export/button.h11
-rw-r--r--firmware/export/config-ipodcolor.h87
-rw-r--r--firmware/export/config-ipodnano.h89
-rw-r--r--firmware/export/config.h35
-rw-r--r--firmware/export/i2c-pp5020.h66
-rw-r--r--firmware/export/kernel.h6
-rw-r--r--firmware/export/lcd.h12
-rw-r--r--firmware/export/system.h44
-rw-r--r--firmware/kernel.c13
-rw-r--r--firmware/rolo.c2
-rw-r--r--firmware/system.c13
-rw-r--r--firmware/thread.c26
-rw-r--r--firmware/usb.c4
24 files changed, 2178 insertions, 21 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index bee9fd5..5a26932 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 5a0db8f..1a12cb5 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 ecd4403..eafa501 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 a693c21..ec8db5b 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 f41b575..62566c8 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 <leachbj@bouncycastle.org>
+ *
+ */
+ .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 3dafb0a..665cd37 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 475b125..6ec414c 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<SECTOR_SIZE/2; i++) {
/* the IDENTIFY words are already swapped, so we need to treat
this info differently that normal sector data */
-#ifdef SWAP_WORDS
- identify_info[i] = ATA_DATA;
+#if defined(ROCKBOX_IS_BIGENDIAN) && !defined(SWAP_WORDS)
+#warning Swapping ATA identify data
+ identify_info[i] = swap16(ATA_DATA);
#else
- identify_info[i] = letoh16(ATA_DATA);
+ identify_info[i] = ATA_DATA;
#endif
}
@@ -1393,6 +1432,9 @@ int ata_init(void)
bool coldstart = (P1 & 0x80) == 0;
#elif CONFIG_CPU == MCF5249
bool coldstart = (GPIO_FUNCTION & 0x00080000) == 0;
+#elif CONFIG_CPU == PP5020
+ bool coldstart = false;
+ #warning Implement coldstart variable
#else
bool coldstart = (PACR2 & 0x4000) != 0;
#endif
@@ -1418,6 +1460,13 @@ int ata_init(void)
or_l(0x00080000, &GPIO_FUNCTION);
/* FYI: The IDECONFIGx registers are set by set_cpu_frequency() */
+#elif CONFIG_CPU == PP5020
+ /* From ipod-ide.c:ipod_ide_register() */
+ outl(inl(0xc3000028) | (1 << 5), 0xc3000028);
+ outl(inl(0xc3000028) & ~0x10000000, 0xc3000028);
+
+ outl(0x10, 0xc3000000);
+ outl(0x80002150, 0xc3000004);
#endif
sleeping = false;
diff --git a/firmware/drivers/i2c-pp5020.c b/firmware/drivers/i2c-pp5020.c
new file mode 100644
index 0000000..c08fad3
--- /dev/null
+++ b/firmware/drivers/i2c-pp5020.c
@@ -0,0 +1,189 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * 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 0000000..f7ea09a
--- /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 <string.h>
+#include <stdlib.h>
+#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<LCD_HEIGHT*LCD_WIDTH;i++) {
+ *(addr++)=bits;
+ }
+ scrolling_lines = 0;
+}
+
+/* Set a single pixel */
+void lcd_drawpixel(int x, int y)
+{
+ if (((unsigned)x < LCD_WIDTH) && ((unsigned)y < LCD_HEIGHT))
+ lcd_pixelfuncs[drawmode](x, y);
+}
+
+/* Draw a line */
+void lcd_drawline(int x1, int y1, int x2, int y2)
+{
+ int numpixels;
+ int i;
+ int deltax, deltay;
+ int d, dinc1, dinc2;
+ int x, xinc1, xinc2;
+ int y, yinc1, yinc2;
+ lcd_pixelfunc_type *pfunc = lcd_pixelfuncs[drawmode];
+
+ deltax = abs(x2 - x1);
+ deltay = abs(y2 - y1);
+ xinc2 = 1;
+ yinc2 = 1;
+
+ if (deltax >= 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;i<height;i++) {
+ for (j=0;j<width;j++) {
+ *(d++)=*(s++);
+ }
+ d+=k;
+ }
+
+//OLD Implementation: lcd_bitmap_part(src, 0, 0, width, x, y, width, height);
+
+}
+
+/* put a string at a given pixel position, skipping first ofs pixel columns */
+static void lcd_putsxyofs(int x, int y, int ofs, const unsigned char *str)
+{
+ int ch;
+ struct font* pf = font_get(curfont);
+
+ if (bidi_support_enabled)
+ str = bidi_l2v(str, 1);
+
+ while ((ch = *str++) != '\0' && x < LCD_WIDTH)
+ {
+ int width;
+ const unsigned char *bits;
+
+ /* check input range */
+ if (ch < pf->firstchar || 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<<y);
+ }
+ else
+ /* force a bit switch-off since it doesn't scroll */
+ scrolling_lines &= ~(1<<y);
+}
+
+static void scroll_thread(void)
+{
+ struct font* pf;
+ struct scrollinfo* s;
+ int index;
+ int xpos, ypos;
+ int lastmode;
+
+ /* initialize scroll struct array */
+ scrolling_lines = 0;
+
+ while ( 1 ) {
+ for ( index = 0; index < SCROLLABLE_LINES; index++ ) {
+ /* really scroll? */
+ if ( !(scrolling_lines&(1<<index)) )
+ continue;
+
+ s = &scroll[index];
+
+ /* check pause */
+ if (TIME_BEFORE(current_tick, s->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 7d45021..c7ef691 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 728bc6f..4c5c5a8 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 e1caa52..61c722b 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 0000000..f30ef28
--- /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 0000000..8ba3cfa
--- /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 66f53eb..41e639f 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 0000000..d26a7fe
--- /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 039af56..ab966da 100644
--- a/firmware/export/kernel.h
+++ b/firmware/export/kernel.h
@@ -20,6 +20,7 @@
#define _KERNEL_H_
#include <stdbool.h>
+#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 c8be1d3..28458fe 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 313a9a8..15c6edb 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 9af4566..215d5de 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 f6fba5f..43f5031 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 d6b4824..7da1034 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 7ee4072..83607ea 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 8a99683..f69df5a 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)