summaryrefslogtreecommitdiffstats
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorMichael Sparmann <theseven@rockbox.org>2011-01-02 23:16:27 +0000
committerMichael Sparmann <theseven@rockbox.org>2011-01-02 23:16:27 +0000
commit152847977a420487d9c3728841101ef708e41373 (patch)
treef4113d0d6f60355d1ba00d78fc96e97a98e4d493 /firmware/target/arm
parent6f40387e742322c4860af2f389a4b531e669801f (diff)
downloadrockbox-152847977a420487d9c3728841101ef708e41373.tar.gz
rockbox-152847977a420487d9c3728841101ef708e41373.zip
New port: iPod Classic (also known as iPod 6G/6.5G/7G)
Major known issues: - No bootloader yet - No support for the first-generation 160GB CE-ATA hard disk drive yet - Audio playback is slow, only FLAC seems to reach realtime git-svn-id: svn://svn.rockbox.org/rockbox/trunk@28953 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/mmu-arm.S3
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/piezo-nano2g.c95
-rw-r--r--firmware/target/arm/s5l8700/ipodnano2g/piezo.h24
-rw-r--r--firmware/target/arm/s5l8702/app.lds142
-rw-r--r--firmware/target/arm/s5l8702/boot.lds94
-rw-r--r--firmware/target/arm/s5l8702/crt0.S207
-rw-r--r--firmware/target/arm/s5l8702/debug-s5l8702.c151
-rw-r--r--firmware/target/arm/s5l8702/debug-target.h33
-rw-r--r--firmware/target/arm/s5l8702/i2c-s5l8702.c186
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c39
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/adc-target.h33
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c197
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/ata-target.h47
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c65
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c67
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/backlight-target.h29
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/button-target.h78
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/cscodec-ipod6g.c64
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S295
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c286
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c143
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/pmu-target.h46
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c75
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c88
-rw-r--r--firmware/target/arm/s5l8702/ipod6g/rtc-ipod6g.c72
-rw-r--r--firmware/target/arm/s5l8702/kernel-s5l8702.c56
-rw-r--r--firmware/target/arm/s5l8702/pcm-s5l8702.c219
-rw-r--r--firmware/target/arm/s5l8702/system-s5l8702.c268
-rw-r--r--firmware/target/arm/s5l8702/system-target.h48
-rw-r--r--firmware/target/arm/s5l8702/timer-s5l8702.c94
-rw-r--r--firmware/target/arm/thread-arm.c3
31 files changed, 3245 insertions, 2 deletions
diff --git a/firmware/target/arm/mmu-arm.S b/firmware/target/arm/mmu-arm.S
index 5693ca587b..24abfec1a7 100644
--- a/firmware/target/arm/mmu-arm.S
+++ b/firmware/target/arm/mmu-arm.S
@@ -18,6 +18,7 @@
* KIND, either express or implied.
*
****************************************************************************/
+#define ASM
#include "config.h"
#include "cpu.h"
@@ -27,7 +28,7 @@
/* MMU present but unused */
#define HAVE_TEST_AND_CLEAN_CACHE
-#elif CONFIG_CPU == DM320 || CONFIG_CPU == AS3525v2
+#elif CONFIG_CPU == DM320 || CONFIG_CPU == AS3525v2 || CONFIG_CPU == S5L8702
#define USE_MMU
#define HAVE_TEST_AND_CLEAN_CACHE
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/piezo-nano2g.c b/firmware/target/arm/s5l8700/ipodnano2g/piezo-nano2g.c
new file mode 100644
index 0000000000..b41790833f
--- /dev/null
+++ b/firmware/target/arm/s5l8700/ipodnano2g/piezo-nano2g.c
@@ -0,0 +1,95 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Robert Keevil
+ *
+ * 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 "system.h"
+#include "kernel.h"
+#include "piezo.h"
+
+static unsigned int duration;
+static bool beeping;
+
+void INT_TIMERD(void)
+{
+ /* clear interrupt */
+ TDCON = TDCON;
+ if (!(--duration))
+ {
+ beeping = 0;
+ TDCMD = (1 << 1); /* TD_CLR */
+ }
+}
+
+void piezo_start(unsigned short cycles, unsigned short periods)
+{
+#ifndef SIMULATOR
+ duration = periods;
+ beeping = 1;
+ /* configure timer for 100 kHz */
+ TDCMD = (1 << 1); /* TD_CLR */
+ TDPRE = 30 - 1; /* prescaler */
+ TDCON = (1 << 13) | /* TD_INT1_EN */
+ (0 << 12) | /* TD_INT0_EN */
+ (0 << 11) | /* TD_START */
+ (2 << 8) | /* TD_CS = PCLK / 16 */
+ (1 << 4); /* TD_MODE_SEL = PWM mode */
+ TDDATA0 = cycles; /* set interval period */
+ TDDATA1 = cycles << 1; /* set interval period */
+ TDCMD = (1 << 0); /* TD_EN */
+
+ /* enable timer interrupt */
+ INTMSK |= INTMSK_TIMERD;
+#endif
+}
+
+void piezo_stop(void)
+{
+#ifndef SIMULATOR
+ TDCMD = (1 << 1); /* TD_CLR */
+#endif
+}
+
+void piezo_clear(void)
+{
+ piezo_stop();
+}
+
+bool piezo_busy(void)
+{
+ return beeping;
+}
+
+void piezo_init(void)
+{
+ beeping = 0;
+}
+
+void piezo_button_beep(bool beep, bool force)
+{
+ if (force)
+ while (beeping)
+ yield();
+
+ if (!beeping)
+ {
+ if (beep)
+ piezo_start(22, 457);
+ else
+ piezo_start(40, 4);
+ }
+}
diff --git a/firmware/target/arm/s5l8700/ipodnano2g/piezo.h b/firmware/target/arm/s5l8700/ipodnano2g/piezo.h
new file mode 100644
index 0000000000..d9837cc6a9
--- /dev/null
+++ b/firmware/target/arm/s5l8700/ipodnano2g/piezo.h
@@ -0,0 +1,24 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id$
+ *
+ * Copyright (C) 2006-2007 Robert Keevil
+ *
+ * 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.
+ *
+ ****************************************************************************/
+
+void piezo_init(void);
+void piezo_stop(void);
+void piezo_clear(void);
+bool piezo_busy(void);
+void piezo_button_beep(bool beep, bool force);
diff --git a/firmware/target/arm/s5l8702/app.lds b/firmware/target/arm/s5l8702/app.lds
new file mode 100644
index 0000000000..fafdea4cd9
--- /dev/null
+++ b/firmware/target/arm/s5l8702/app.lds
@@ -0,0 +1,142 @@
+#define ASM
+#include "config.h"
+#include "cpu.h"
+
+ENTRY(start)
+
+OUTPUT_FORMAT(elf32-littlearm)
+OUTPUT_ARCH(arm)
+STARTUP(target/arm/s5l8702/crt0.o)
+
+#define PLUGINSIZE PLUGIN_BUFFER_SIZE
+#define CODECSIZE CODEC_SIZE
+
+#define IRAMORIG 0x0
+#define DRAMORIG 0x08000000
+
+/* End of the audio buffer, where the codec buffer starts */
+#define ENDAUDIOADDR (DRAMORIG + DRAMSIZE)
+
+#define DRAMSIZE (DRAM_SIZE - PLUGINSIZE - CODECSIZE - TTB_SIZE)
+#define CODECORIG (ENDAUDIOADDR)
+#define IRAMSIZE (56*1024) /* 256KB total - 56KB for core, 200KB for codecs */
+
+/* Where the codec buffer ends, and the plugin buffer starts */
+#define ENDADDR (ENDAUDIOADDR + CODECSIZE)
+
+MEMORY
+{
+ IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
+ DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
+}
+
+SECTIONS
+{
+ loadaddress = DRAMORIG;
+
+ .intvect : {
+ _intvectstart = . ;
+ *(.intvect)
+ _intvectend = _newstart ;
+ } >IRAM AT> DRAM
+ _intvectcopy = LOADADDR(.intvect) ;
+
+ .text :
+ {
+ _loadaddress = .;
+ _textstart = .;
+ *(.init.text)
+ *(.text)
+ *(.text*)
+ *(.glue_7)
+ *(.glue_7t)
+ . = ALIGN(0x4);
+ } > DRAM
+
+ .rodata :
+ {
+ *(.rodata*)
+ . = ALIGN(0x4);
+ } > DRAM
+
+ .data :
+ {
+ *(.data*)
+ . = ALIGN(0x4);
+ } > DRAM
+
+ /DISCARD/ :
+ {
+ *(.eh_frame)
+ }
+
+ .iram :
+ {
+ _iramstart = .;
+ *(.icode)
+ *(.irodata)
+ *(.idata)
+ . = ALIGN(0x4);
+ _iramend = .;
+ } > IRAM AT> DRAM
+ _iramcopy = LOADADDR(.iram) ;
+
+ .ibss (NOLOAD) :
+ {
+ _iedata = .;
+ *(.qharray)
+ *(.ibss)
+ . = ALIGN(0x4);
+ _iend = .;
+ } > IRAM
+
+ .stack (NOLOAD) :
+ {
+ *(.stack)
+ stackbegin = .;
+ _stackbegin = .;
+ . += 0x4000;
+ stackend = .;
+ _stackend = .;
+ _irqstackbegin = .;
+ . += 0x400;
+ _irqstackend = .;
+ _fiqstackbegin = .;
+ . += 0x400;
+ _fiqstackend = .;
+ } > IRAM
+
+ .bss (NOLOAD) :
+ {
+ _edata = .;
+ *(.bss*)
+ *(COMMON)
+ . = ALIGN(0x4);
+ _end = .;
+ } > DRAM
+
+ .audiobuf (NOLOAD) :
+ {
+ . = ALIGN(4);
+ _audiobuffer = .;
+ audiobuffer = .;
+ } > DRAM
+
+ .audiobufend ENDAUDIOADDR (NOLOAD) :
+ {
+ audiobufend = .;
+ _audiobufend = .;
+ } > DRAM
+
+ .codec CODECORIG (NOLOAD) :
+ {
+ codecbuf = .;
+ _codecbuf = .;
+ } > DRAM
+
+ .plugin ENDADDR (NOLOAD) :
+ {
+ _pluginbuf = .;
+ pluginbuf = .;
+ }
+}
diff --git a/firmware/target/arm/s5l8702/boot.lds b/firmware/target/arm/s5l8702/boot.lds
new file mode 100644
index 0000000000..9741cee45e
--- /dev/null
+++ b/firmware/target/arm/s5l8702/boot.lds
@@ -0,0 +1,94 @@
+#define ASM
+#include "config.h"
+
+ENTRY(start)
+#ifdef ROCKBOX_LITTLE_ENDIAN
+OUTPUT_FORMAT(elf32-littlearm)
+#else
+OUTPUT_FORMAT(elf32-bigarm)
+#endif
+OUTPUT_ARCH(arm)
+STARTUP(target/arm/s5l8702/crt0.o)
+
+#ifdef IPOD_NANO2G
+#define DRAMORIG 0x08000000 + ((MEMORYSIZE - 1) * 0x100000)
+#define DRAMSIZE 0x00100000
+#else
+#define DRAMORIG 0x08000000
+#define DRAMSIZE (DRAM_SIZE - TTB_SIZE)
+#endif
+
+#define IRAMORIG 0x22000000
+#define IRAMSIZE 256K
+
+MEMORY
+{
+ DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
+ IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
+}
+
+#define LOAD_AREA IRAM
+
+SECTIONS
+{
+#ifdef NEEDS_INTVECT_COPYING
+ .intvect : {
+ _intvectstart = . ;
+ *(.intvect)
+ _intvectend = _newstart ;
+ } >IRAM AT> LOAD_AREA
+ _intvectcopy = LOADADDR(.intvect) ;
+#endif
+
+ .text : {
+#ifndef NEEDS_INTVECT_COPYING
+ *(.intvect)
+#endif
+ *(.init.text)
+ *(.text*)
+ *(.glue_7*)
+ } > LOAD_AREA
+
+ .rodata : {
+ *(.rodata*)
+ . = ALIGN(0x4);
+ } > LOAD_AREA
+
+ .data : {
+ _datastart = . ;
+ *(.irodata)
+ *(.icode)
+ *(.idata)
+ *(.data*)
+ *(.ncdata*);
+ . = ALIGN(0x4);
+ _dataend = . ;
+ } > IRAM AT> LOAD_AREA
+ _datacopy = LOADADDR(.data) ;
+
+ .stack (NOLOAD) :
+ {
+ *(.stack)
+ _stackbegin = .;
+ stackbegin = .;
+ . += 0x2000;
+ _stackend = .;
+ stackend = .;
+ _irqstackbegin = .;
+ . += 0x400;
+ _irqstackend = .;
+ _fiqstackbegin = .;
+ . += 0x400;
+ _fiqstackend = .;
+ } > IRAM
+
+ .bss (NOLOAD) : {
+ _edata = .;
+ *(.bss*);
+ *(.ibss);
+ *(.ncbss*);
+ *(COMMON);
+ . = ALIGN(0x4);
+ _end = .;
+ } > IRAM
+}
diff --git a/firmware/target/arm/s5l8702/crt0.S b/firmware/target/arm/s5l8702/crt0.S
new file mode 100644
index 0000000000..da2f49c971
--- /dev/null
+++ b/firmware/target/arm/s5l8702/crt0.S
@@ -0,0 +1,207 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: crt0.S 18776 2008-10-11 18:32:17Z gevaerts $
+ *
+ * Copyright (C) 2008 by Marcoen Hirschberg
+ * Copyright (C) 2008 by Denes Balatoni
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define ASM
+#include "config.h"
+#include "cpu.h"
+
+#define CACHE_NONE 0
+#define CACHE_ALL 0x0C
+
+ .section .intvect,"ax",%progbits
+ .global start
+ .global _newstart
+ /* Exception vectors */
+start:
+ b _newstart
+ ldr pc, =undef_instr_handler
+ ldr pc, =software_int_handler
+ ldr pc, =prefetch_abort_handler
+ ldr pc, =data_abort_handler
+ ldr pc, =reserved_handler
+ ldr pc, =irq_handler
+ ldr pc, =fiq_handler
+ .ltorg
+_newstart:
+#if !defined(BOOTLOADER)
+ ldr pc, =newstart2 // we do not want to execute from 0x0 as iram will be mapped there
+ .section .init.text,"ax",%progbits
+newstart2:
+#endif
+ msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
+
+#ifdef BOOTLOADER
+ /* Relocate ourself to IRAM - we have been loaded to DRAM */
+ mov r0, #0x08000000 /* source (DRAM) */
+ mov r1, #0x22000000 /* dest (IRAM) */
+ ldr r2, =_dataend
+1:
+ cmp r2, r1
+ ldrhi r3, [r0], #4
+ strhi r3, [r1], #4
+ bhi 1b
+
+ ldr pc, =start_loc /* jump to the relocated start_loc: */
+start_loc:
+#endif
+
+ mrc 15, 0, r0, c1, c0, 0
+ bic r0, r0, #0x1000
+ bic r0, r0, #0x5
+ mcr 15, 0, r0, c1, c0, 0 // disable caches and protection unit
+
+.cleancache:
+ mrc p15, 0, r15,c7,c10,3
+ bne .cleancache
+ mov r0, #0
+ mcr p15, 0, r0,c7,c10,4
+ mcr p15, 0, r0,c7,c5,0
+ bl ttb_init
+
+ mov r0, #0 @ physical address
+ mov r1, #0 @ virtual address
+ mov r2, #0x380 @ size (all memory)
+ mov r3, #CACHE_ALL
+ bl map_section
+
+ mov r0, #0x38000000 @ physical address
+ mov r1, #0x38000000 @ virtual address
+ mov r2, #0x80 @ size (AHB/APB)
+ mov r3, #CACHE_NONE
+ bl map_section
+
+ bl enable_mmu
+
+ mrc 15, 0, r0, c1, c0, 0
+ orr r0, r0, #0x5
+ orr r0, r0, #0x1000
+ mcr 15, 0, r0, c1, c0, 0 // re-enable protection unit and caches
+
+ ldr r1, =0x38e00000
+ add r2, r1, #0x00001000
+ add r3, r1, #0x00002000
+ sub r4, r0, #1
+ str r4, [r1,#0x14]
+ str r4, [r2,#0x14]
+ str r4, [r1,#0xf00]
+ str r4, [r2,#0xf00]
+ str r4, [r3,#0x08]
+ str r4, [r3,#0x0c]
+ str r0, [r1,#0x14]
+ str r0, [r2,#0x14]
+
+#if !defined(BOOTLOADER)
+ /* Copy interrupt vectors to iram */
+ ldr r2, =_intvectstart
+ ldr r3, =_intvectend
+ ldr r4, =_intvectcopy
+1:
+ cmp r3, r2
+ ldrhi r1, [r4], #4
+ strhi r1, [r2], #4
+ bhi 1b
+#endif
+
+ /* Initialise bss section to zero */
+ ldr r2, =_edata
+ ldr r3, =_end
+ mov r4, #0
+1:
+ cmp r3, r2
+ strhi r4, [r2], #4
+ bhi 1b
+
+#ifndef BOOTLOADER
+ /* Copy icode and data to ram */
+ ldr r2, =_iramstart
+ ldr r3, =_iramend
+ ldr r4, =_iramcopy
+1:
+ cmp r3, r2
+ ldrhi r1, [r4], #4
+ strhi r1, [r2], #4
+ bhi 1b
+
+ /* Initialise ibss section to zero */
+ ldr r2, =_iedata
+ ldr r3, =_iend
+ mov r4, #0
+1:
+ cmp r3, r2
+ strhi r4, [r2], #4
+ bhi 1b
+#endif
+
+ /* Set up some stack and munge it with 0xdeadbeef */
+ ldr sp, =stackend
+ ldr r2, =stackbegin
+ ldr r3, =0xdeadbeef
+1:
+ cmp sp, r2
+ strhi r3, [r2], #4
+ bhi 1b
+
+ /* Set up stack for IRQ mode */
+ msr cpsr_c, #0xd2
+ ldr sp, =_irqstackend
+
+ /* Set up stack for FIQ mode */
+ msr cpsr_c, #0xd1
+ ldr sp, =_fiqstackend
+
+ /* Let abort and undefined modes use IRQ stack */
+ msr cpsr_c, #0xd7
+ ldr sp, =_irqstackend
+ msr cpsr_c, #0xdb
+ ldr sp, =_irqstackend
+
+ /* Switch back to supervisor mode */
+ msr cpsr_c, #0xd3
+
+ bl main
+
+ .text
+/* .global UIE*/
+
+/* All illegal exceptions call into UIE with exception address as first
+ * parameter. This is calculated differently depending on which exception
+ * we're in. Second parameter is exception number, used for a string lookup
+ * in UIE. */
+undef_instr_handler:
+ sub r0, lr, #4
+ mov r1, #0
+ b UIE
+
+/* We run supervisor mode most of the time, and should never see a software
+ * exception being thrown. Perhaps make it illegal and call UIE? */
+software_int_handler:
+reserved_handler:
+ movs pc, lr
+
+prefetch_abort_handler:
+ sub r0, lr, #4
+ mov r1, #1
+ b UIE
+
+data_abort_handler:
+ sub r0, lr, #8
+ mov r1, #2
+ b UIE
diff --git a/firmware/target/arm/s5l8702/debug-s5l8702.c b/firmware/target/arm/s5l8702/debug-s5l8702.c
new file mode 100644
index 0000000000..30d97d9203
--- /dev/null
+++ b/firmware/target/arm/s5l8702/debug-s5l8702.c
@@ -0,0 +1,151 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: debug-s5l8700.c 28719 2010-12-01 18:35:01Z Buschel $
+ *
+ * Copyright © 2008 Rafaël Carré
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include <stdbool.h>
+#include "config.h"
+#include "kernel.h"
+#include "debug-target.h"
+#include "button.h"
+#include "lcd.h"
+#include "font.h"
+#include "storage.h"
+#include "power.h"
+#include "pmu-target.h"
+
+/* Skeleton for adding target specific debug info to the debug menu
+ */
+
+#define _DEBUG_PRINTF(a, varargs...) lcd_putsf(0, line++, (a), ##varargs);
+
+bool __dbg_hw_info(void)
+{
+ int line;
+ int i;
+ unsigned int state = 0;
+ const unsigned int max_states=2;
+
+ lcd_clear_display();
+ lcd_setfont(FONT_SYSFIXED);
+
+ state=0;
+ while(1)
+ {
+ lcd_clear_display();
+ line = 0;
+
+ if(state == 0)
+ {
+ _DEBUG_PRINTF("CPU:");
+ _DEBUG_PRINTF("current_tick: %d", (unsigned int)current_tick);
+ line++;
+ }
+ else if(state==1)
+ {
+ _DEBUG_PRINTF("PMU:");
+ for(i=0;i<7;i++)
+ {
+ char *device[] = {"(unknown)",
+ "(unknown)",
+ "(unknown)",
+ "(unknown)",
+ "(unknown)",
+ "(unknown)",
+ "(unknown)"};
+ _DEBUG_PRINTF("ldo%d %s: %dmV %s",i,
+ pmu_read(0x2e + (i << 1))?" on":"off",
+ 900 + pmu_read(0x2d + (i << 1))*100,
+ device[i]);
+ }
+ _DEBUG_PRINTF("cpu voltage: %dmV",625 + pmu_read(0x1e)*25);
+ _DEBUG_PRINTF("memory voltage: %dmV",625 + pmu_read(0x22)*25);
+ line++;
+ _DEBUG_PRINTF("charging: %s", charging_state() ? "true" : "false");
+ _DEBUG_PRINTF("backlight: %s", pmu_read(0x29) ? "on" : "off");
+ _DEBUG_PRINTF("brightness value: %d", pmu_read(0x28));
+ }
+ else
+ {
+ state=0;
+ }
+
+
+ lcd_update();
+ switch(button_get_w_tmo(HZ/20))
+ {
+ case BUTTON_SCROLL_BACK:
+ if(state!=0) state--;
+ break;
+
+ case BUTTON_SCROLL_FWD:
+ if(state!=max_states-1)
+ {
+ state++;
+ }
+ break;
+
+ case DEBUG_CANCEL:
+ case BUTTON_REL:
+ lcd_setfont(FONT_UI);
+ return false;
+ }
+ }
+
+ lcd_setfont(FONT_UI);
+ return false;
+}
+
+bool dbg_ports(void)
+{
+ int line;
+
+ lcd_setfont(FONT_SYSFIXED);
+
+ while(1)
+ {
+ lcd_clear_display();
+ line = 0;
+
+ _DEBUG_PRINTF("GPIO 0: %08x",(unsigned int)PDAT(0));
+ _DEBUG_PRINTF("GPIO 1: %08x",(unsigned int)PDAT(1));
+ _DEBUG_PRINTF("GPIO 2: %08x",(unsigned int)PDAT(2));
+ _DEBUG_PRINTF("GPIO 3: %08x",(unsigned int)PDAT(3));
+ _DEBUG_PRINTF("GPIO 4: %08x",(unsigned int)PDAT(4));
+ _DEBUG_PRINTF("GPIO 5: %08x",(unsigned int)PDAT(5));
+ _DEBUG_PRINTF("GPIO 6: %08x",(unsigned int)PDAT(6));
+ _DEBUG_PRINTF("GPIO 7: %08x",(unsigned int)PDAT(7));
+ _DEBUG_PRINTF("GPIO 8: %08x",(unsigned int)PDAT(8));
+ _DEBUG_PRINTF("GPIO 9: %08x",(unsigned int)PDAT(9));
+ _DEBUG_PRINTF("GPIO 10: %08x",(unsigned int)PDAT(10));
+ _DEBUG_PRINTF("GPIO 11: %08x",(unsigned int)PDAT(11));
+ _DEBUG_PRINTF("GPIO 12: %08x",(unsigned int)PDAT(12));
+ _DEBUG_PRINTF("GPIO 13: %08x",(unsigned int)PDAT(13));
+ _DEBUG_PRINTF("GPIO 14: %08x",(unsigned int)PDAT(14));
+ _DEBUG_PRINTF("GPIO 15: %08x",(unsigned int)PDAT(15));
+ _DEBUG_PRINTF("USEC : %08x",(unsigned int)USEC_TIMER);
+
+ lcd_update();
+ if (button_get_w_tmo(HZ/10) == (DEBUG_CANCEL|BUTTON_REL))
+ break;
+ }
+ lcd_setfont(FONT_UI);
+ return false;
+}
+
diff --git a/firmware/target/arm/s5l8702/debug-target.h b/firmware/target/arm/s5l8702/debug-target.h
new file mode 100644
index 0000000000..79e3115dea
--- /dev/null
+++ b/firmware/target/arm/s5l8702/debug-target.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: debug-target.h 28522 2010-11-06 14:24:25Z wodz $
+ *
+ * Copyright (C) 2007 by Karl Kurbjun
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef _DEBUG_TARGET_H_
+#define _DEBUG_TARGET_H_
+
+#include <stdbool.h>
+
+#define DEBUG_CANCEL BUTTON_MENU
+
+bool __dbg_hw_info(void);
+bool dbg_ports(void);
+
+#endif /* _DEBUG_TARGET_H_ */
+
diff --git a/firmware/target/arm/s5l8702/i2c-s5l8702.c b/firmware/target/arm/s5l8702/i2c-s5l8702.c
new file mode 100644
index 0000000000..be286b34b7
--- /dev/null
+++ b/firmware/target/arm/s5l8702/i2c-s5l8702.c
@@ -0,0 +1,186 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: i2c-s5l8700.c 28589 2010-11-14 15:19:30Z theseven $
+ *
+ * Copyright (C) 2009 by Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "system.h"
+#include "kernel.h"
+#include "i2c-s5l8702.h"
+
+/* Driver for the s5l8700 built-in I2C controller in master mode
+
+ Both the i2c_read and i2c_write function take the following arguments:
+ * slave, the address of the i2c slave device to read from / write to
+ * address, optional sub-address in the i2c slave (unused if -1)
+ * len, number of bytes to be transfered
+ * data, pointer to data to be transfered
+ A return value < 0 indicates an error.
+
+ Note:
+ * blocks the calling thread for the entire duraton of the i2c transfer but
+ uses wakeup_wait/wakeup_signal to allow other threads to run.
+ * ACK from slave is not checked, so functions never return an error
+*/
+
+static struct mutex i2c_mtx[2];
+
+void i2c_init(void)
+{
+ mutex_init(&i2c_mtx[0]);
+ mutex_init(&i2c_mtx[1]);
+
+ /* initial config */
+ IICADD(0) = 0;
+ IICADD(1) = 0;
+ IICCON(0) = (1 << 7) | /* ACK_GEN */
+ (0 << 6) | /* CLKSEL = PCLK/16 */
+ (1 << 5) | /* INT_EN */
+ (1 << 4) | /* IRQ clear */
+ (3 << 0); /* CK_REG */
+ IICCON(1) = (1 << 7) | /* ACK_GEN */
+ (0 << 6) | /* CLKSEL = PCLK/16 */
+ (1 << 5) | /* INT_EN */
+ (1 << 4) | /* IRQ clear */
+ (3 << 0); /* CK_REG */
+
+ /* serial output on */
+ IICSTAT(0) = (1 << 4);
+ IICSTAT(1) = (1 << 4);
+}
+
+int i2c_write(int bus, unsigned char slave, int address, int len, const unsigned char *data)
+{
+ mutex_lock(&i2c_mtx[bus]);
+ long timeout = current_tick + HZ / 50;
+
+ /* START */
+ IICDS(bus) = slave & ~1;
+ IICSTAT(bus) = 0xF0;
+ IICCON(bus) = 0xB3;
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 1;
+ }
+
+
+ if (address >= 0) {
+ /* write address */
+ IICDS(bus) = address;
+ IICCON(bus) = 0xB3;
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 2;
+ }
+ }
+
+ /* write data */
+ while (len--) {
+ IICDS(bus) = *data++;
+ IICCON(bus) = 0xB3;
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 4;
+ }
+ }
+
+ /* STOP */
+ IICSTAT(bus) = 0xD0;
+ IICCON(bus) = 0xB3;
+ while ((IICSTAT(bus) & (1 << 5)) != 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 5;
+ }
+
+ mutex_unlock(&i2c_mtx[bus]);
+ return 0;
+}
+
+int i2c_read(int bus, unsigned char slave, int address, int len, unsigned char *data)
+{
+ mutex_lock(&i2c_mtx[bus]);
+ long timeout = current_tick + HZ / 50;
+
+ if (address >= 0) {
+ /* START */
+ IICDS(bus) = slave & ~1;
+ IICSTAT(bus) = 0xF0;
+ IICCON(bus) = 0xB3;
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 1;
+ }
+
+ /* write address */
+ IICDS(bus) = address;
+ IICCON(bus) = 0xB3;
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 2;
+ }
+ }
+
+ /* (repeated) START */
+ IICDS(bus) = slave | 1;
+ IICSTAT(bus) = 0xB0;
+ IICCON(bus) = 0xB3;
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 3;
+ }
+
+ while (len--) {
+ IICCON(bus) = (len == 0) ? 0x33 : 0xB3; /* NAK or ACK */
+ while ((IICCON(bus) & 0x10) == 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 4;
+ }
+ *data++ = IICDS(bus);
+ }
+
+ /* STOP */
+ IICSTAT(bus) = 0x90;
+ IICCON(bus) = 0xB3;
+ while ((IICSTAT(bus) & (1 << 5)) != 0)
+ if (TIME_AFTER(current_tick, timeout))
+ {
+ mutex_unlock(&i2c_mtx[bus]);
+ return 5;
+ }
+
+ mutex_unlock(&i2c_mtx[bus]);
+ return 0;
+}
+
diff --git a/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c
new file mode 100644
index 0000000000..201af5ee00
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/adc-ipod6g.c
@@ -0,0 +1,39 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: adc-s5l8700.c 21775 2009-07-11 14:12:02Z bertrik $
+ *
+ * Copyright (C) 2009 by Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+
+#include "inttypes.h"
+#include "s5l8702.h"
+#include "adc.h"
+#include "adc-target.h"
+#include "pmu-target.h"
+#include "kernel.h"
+
+unsigned short adc_read(int channel)
+{
+ return pmu_read_adc(channel);
+}
+
+void adc_init(void)
+{
+}
+
diff --git a/firmware/target/arm/s5l8702/ipod6g/adc-target.h b/firmware/target/arm/s5l8702/ipod6g/adc-target.h
new file mode 100644
index 0000000000..d4dce3d31f
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/adc-target.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: adc-target.h 21734 2009-07-09 20:17:47Z bertrik $
+ *
+ * Copyright (C) 2006 by Barry Wardell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _ADC_TARGET_H_
+#define _ADC_TARGET_H_
+
+#define NUM_ADC_CHANNELS 4
+
+#define ADC_UNKNOWN_0 0
+#define ADC_UNKNOWN_1 1
+#define ADC_BATTERY 2
+#define ADC_UNKNOWN_3 3
+
+#define ADC_UNREG_POWER ADC_BATTERY /* For compatibility */
+
+#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c
new file mode 100644
index 0000000000..f1577ee857
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/ata-ipod6g.c
@@ -0,0 +1,197 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: ata-meg-fx.c 27935 2010-08-28 23:12:11Z funman $
+ *
+ * Copyright (C) 2011 by Michael Sparmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * 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 "kernel.h"
+#include "thread.h"
+#include "system.h"
+#include "power.h"
+#include "panic.h"
+#include "pmu-target.h"
+#include "ata.h"
+#include "ata-target.h"
+#include "s5l8702.h"
+
+
+static struct wakeup ata_wakeup;
+
+#ifdef HAVE_ATA_DMA
+static uint32_t ata_dma_flags;
+#endif
+
+
+void ata_reset(void)
+{
+ ATA_SWRST = 1;
+ sleep(HZ / 100);
+ ATA_SWRST = 0;
+ sleep(HZ / 10);
+}
+
+void ata_enable(bool on)
+{
+ if (on)
+ {
+ PWRCON(0) &= ~(1 << 5);
+ ATA_CFG = 0x41;
+ sleep(HZ / 100);
+ ATA_CFG = 0x40;
+ sleep(HZ / 20);
+ ata_reset();
+ ATA_CCONTROL = 1;
+ sleep(HZ / 5);
+ ATA_PIO_TIME = 0x191f7;
+ *ATA_HCYL = 0;
+ while (!(ATA_PIO_READY & 2)) yield();
+ }
+ else
+ {
+ ATA_CCONTROL = 0;
+ while (!(ATA_CCONTROL & 2)) yield();
+ PWRCON(1) |= 1 << 5;
+ }
+}
+
+bool ata_is_coldstart(void)
+{
+ return false;
+}
+
+void ata_device_init(void)
+{
+ VIC0INTENABLE = 1 << IRQ_ATA;
+}
+
+uint16_t ata_read_cbr(uint32_t volatile* reg)
+{
+ while (!(ATA_PIO_READY & 2));
+ volatile uint32_t __attribute__((unused)) dummy = *reg;
+ while (!(ATA_PIO_READY & 1));
+ return ATA_PIO_RDATA;
+}
+
+void ata_write_cbr(uint32_t volatile* reg, uint16_t data)
+{
+ while (!(ATA_PIO_READY & 2));
+ *reg = data;
+}
+
+void ata_set_pio_timings(int mode)
+{
+ if (mode >= 4) ATA_PIO_TIME = 0x7083;
+ if (mode >= 3) ATA_PIO_TIME = 0x2072;
+ else ATA_PIO_TIME = 0x11f3;
+}
+
+#ifdef HAVE_ATA_DMA
+static void ata_set_mdma_timings(unsigned int mode)
+{
+ if (mode >= 2) ATA_MDMA_TIME = 0x5072;
+ if (mode >= 1) ATA_MDMA_TIME = 0x7083;
+ else ATA_MDMA_TIME = 0x1c175;
+}
+
+static void ata_set_udma_timings(unsigned int mode)
+{
+ if (mode >= 4) ATA_UDMA_TIME = 0x2010a52;
+ if (mode >= 3) ATA_UDMA_TIME = 0x2020a52;
+ if (mode >= 2) ATA_UDMA_TIME = 0x3030a52;
+ if (mode >= 1) ATA_UDMA_TIME = 0x3050a52;
+ else ATA_UDMA_TIME = 0x5071152;
+}
+
+void ata_dma_set_mode(unsigned char mode)
+{
+ unsigned int modeidx = mode & 0x07;
+ unsigned int dmamode = mode & 0xf8;
+
+ if (dmamode == 0x40 && modeidx <= ATA_MAX_UDMA)
+ {
+ /* Using Ultra DMA */
+ ata_set_udma_timings(dmamode);
+ ata_dma_flags = 0x60c;
+ }
+ else if (dmamode == 0x20 && modeidx <= ATA_MAX_MWDMA)
+ {
+ /* Using Multiword DMA */
+ ata_set_mdma_timings(dmamode);
+ ata_dma_flags = 0x408;
+ }
+ else
+ {
+ /* Don't understand this - force PIO. */
+ ata_dma_flags = 0;
+ }
+}
+
+bool ata_dma_setup(void *addr, unsigned long bytes, bool write)
+{
+ if ((((int)addr) & 0xf) || (((int)bytes) & 0xf) || !ata_dma_flags)
+ return false;
+
+ if (write) clean_dcache();
+ else invalidate_dcache();
+ ATA_CCOMMAND = 2;
+
+ if (write)
+ {
+ ATA_SBUF_START = addr;
+ ATA_SBUF_SIZE = bytes;
+ ATA_CFG |= 0x10;
+ }
+ else
+ {
+ ATA_TBUF_START = addr;
+ ATA_TBUF_SIZE = bytes;
+ ATA_CFG &= ~0x10;
+ }
+ ATA_XFR_NUM = bytes - 1;
+
+ return true;
+}
+
+bool ata_dma_finish(void)
+{
+ ATA_CFG |= ata_dma_flags;
+ ATA_CFG &= ~0x180;
+ wakeup_wait(&ata_wakeup, TIMEOUT_NOBLOCK);
+ ATA_IRQ = 0x1f;
+ ATA_IRQ_MASK = 1;
+ ATA_CCOMMAND = 1;
+ if (wakeup_wait(&ata_wakeup, HZ / 2) != OBJ_WAIT_SUCCEEDED)
+ {
+ ATA_CCOMMAND = 2;
+ ATA_CFG &= ~0x100c;
+ return false;
+ }
+ ATA_CCOMMAND = 2;
+ ATA_CFG &= ~0x100c;
+ return true;
+}
+#endif /* HAVE_ATA_DMA */
+
+void INT_ATA(void)
+{
+ uint32_t ata_irq = ATA_IRQ;
+ ATA_IRQ = ata_irq;
+ if (ata_irq & ATA_IRQ_MASK) wakeup_signal(&ata_wakeup);
+ ATA_IRQ_MASK = 0;
+}
diff --git a/firmware/target/arm/s5l8702/ipod6g/ata-target.h b/firmware/target/arm/s5l8702/ipod6g/ata-target.h
new file mode 100644
index 0000000000..e2e7bd298c
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/ata-target.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: ata-target.h 25525 2010-04-07 20:01:21Z torne $
+ *
+ * Copyright (C) 2011 by Michael Sparmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef ATA_TARGET_H
+#define ATA_TARGET_H
+
+#include "inttypes.h"
+#include "s5l8702.h"
+
+#ifdef BOOTLOADER
+#define ATA_DRIVER_CLOSE
+#endif
+
+#define ATA_SWAP_IDENTIFY(word) (swap16(word))
+
+void ata_reset(void);
+void ata_device_init(void);
+bool ata_is_coldstart(void);
+uint16_t ata_read_cbr(uint32_t volatile* reg);
+void ata_write_cbr(uint32_t volatile* reg, uint16_t data);
+
+#define ATA_OUT8(reg, data) ata_write_cbr(reg, data)
+#define ATA_OUT16(reg, data) ata_write_cbr(reg, data)
+#define ATA_IN8(reg) ata_read_cbr(reg)
+#define ATA_IN16(reg) ata_read_cbr(reg)
+
+#define ATA_SET_DEVICE_FEATURES
+void ata_set_pio_timings(int mode);
+
+#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c
new file mode 100644
index 0000000000..6ede3d0c30
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/audio-ipod6g.c
@@ -0,0 +1,65 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: audio-nano2g.c 23095 2009-10-11 09:17:12Z dave $
+ *
+ * Copyright (C) 2006 by Michael Sevakis
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "system.h"
+#include "cpu.h"
+#include "audio.h"
+#include "sound.h"
+
+#if INPUT_SRC_CAPS != 0
+void audio_set_output_source(int source)
+{
+ if ((unsigned)source >= AUDIO_NUM_SOURCES)
+ source = AUDIO_SRC_PLAYBACK;
+} /* audio_set_output_source */
+
+void audio_input_mux(int source, unsigned flags)
+{
+ (void)flags;
+ /* Prevent pops from unneeded switching */
+ static int last_source = AUDIO_SRC_PLAYBACK;
+
+ switch (source)
+ {
+ default: /* playback - no recording */
+ source = AUDIO_SRC_PLAYBACK;
+ case AUDIO_SRC_PLAYBACK:
+#ifdef HAVE_RECORDING
+ if (source != last_source)
+ {
+ audiohw_set_monitor(false);
+ audiohw_disable_recording();
+ }
+#endif
+ break;
+#ifdef HAVE_LINE_REC
+ case AUDIO_SRC_LINEIN: /* recording only */
+ if (source != last_source)
+ {
+ audiohw_set_monitor(false);
+ audiohw_enable_recording(false); /* source line */
+ }
+ break;
+#endif
+ } /* end switch */
+
+ last_source = source;
+} /* audio_input_mux */
+#endif /* INPUT_SRC_CAPS != 0 */
diff --git a/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c
new file mode 100644
index 0000000000..dc21d161de
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/backlight-ipod6g.c
@@ -0,0 +1,67 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: backlight-nano2g.c 28601 2010-11-14 20:39:18Z theseven $
+ *
+ * Copyright (C) 2009 by Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdbool.h>
+
+#include "config.h"
+#include "kernel.h"
+#include "backlight.h"
+#include "backlight-target.h"
+#include "pmu-target.h"
+
+#ifdef HAVE_LCD_SLEEP
+bool lcd_active(void);
+void lcd_awake(void);
+void lcd_update(void);
+#endif
+
+void _backlight_set_brightness(int brightness)
+{
+ pmu_write(0x28, brightness);
+}
+
+void _backlight_on(void)
+{
+#ifdef HAVE_LCD_SLEEP
+ if (!lcd_active())
+ {
+ lcd_awake();
+ lcd_update();
+ sleep(HZ/8);
+ }
+#endif
+ pmu_write(0x29, 1);
+}
+
+void _backlight_off(void)
+{
+ pmu_write(0x29, 0);
+}
+
+bool _backlight_init(void)
+{
+ pmu_write(0x2a, 6);
+ pmu_write(0x28, 0x20);
+ pmu_write(0x2b, 20);
+
+ _backlight_on();
+
+ return true;
+}
diff --git a/firmware/target/arm/s5l8702/ipod6g/backlight-target.h b/firmware/target/arm/s5l8702/ipod6g/backlight-target.h
new file mode 100644
index 0000000000..05a8addfea
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/backlight-target.h
@@ -0,0 +1,29 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: backlight-target.h 21478 2009-06-23 18:11:03Z bertrik $
+ *
+ * Copyright (C) 2008 by Marcoen Hirschberg
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef BACKLIGHT_TARGET_H
+#define BACKLIGHT_TARGET_H
+
+bool _backlight_init(void);
+void _backlight_on(void);
+void _backlight_off(void);
+void _backlight_set_brightness(int brightness);
+
+#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/button-target.h b/firmware/target/arm/s5l8702/ipod6g/button-target.h
new file mode 100644
index 0000000000..0bd89d1d2a
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/button-target.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: button-target.h 21828 2009-07-12 22:16:51Z dave $
+ *
+ * Copyright (C) 2006 by Barry Wardell
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef _BUTTON_TARGET_H_
+#define _BUTTON_TARGET_H_
+
+#include <stdbool.h>
+#include "config.h"
+
+#define HAS_BUTTON_HOLD
+
+bool button_hold(void);
+void button_init_device(void);
+int button_read_device(void);
+
+void ipod_mini_button_int(void);
+void ipod_3g_button_int(void);
+void ipod_4g_button_int(void);
+
+/* iPod specific button codes */
+
+#define BUTTON_SELECT 0x00000001
+#define BUTTON_MENU 0x00000002
+
+#define BUTTON_LEFT 0x00000004
+#define BUTTON_RIGHT 0x00000008
+#define BUTTON_SCROLL_FWD 0x00000010
+#define BUTTON_SCROLL_BACK 0x00000020
+
+#define BUTTON_PLAY 0x00000040
+
+#define BUTTON_MAIN (BUTTON_SELECT|BUTTON_MENU\
+ |BUTTON_LEFT|BUTTON_RIGHT|BUTTON_SCROLL_FWD\
+ |BUTTON_SCROLL_BACK|BUTTON_PLAY)
+
+ /* Remote control's buttons */
+#ifdef IPOD_ACCESSORY_PROTOCOL
+#define BUTTON_RC_PLAY 0x00100000
+#define BUTTON_RC_STOP 0x00080000
+
+#define BUTTON_RC_LEFT 0x00040000
+#define BUTTON_RC_RIGHT 0x00020000
+#define BUTTON_RC_VOL_UP 0x00010000
+#define BUTTON_RC_VOL_DOWN 0x00008000
+
+#define BUTTON_REMOTE (BUTTON_RC_PLAY|BUTTON_RC_STOP\
+ |BUTTON_RC_LEFT|BUTTON_RC_RIGHT\
+ |BUTTON_RC_VOL_UP|BUTTON_RC_VOL_DOWN)
+#else
+#define BUTTON_REMOTE 0
+#endif
+
+/* This is for later
+#define BUTTON_SCROLL_TOUCH 0x00000200
+*/
+
+
+#define POWEROFF_BUTTON BUTTON_PLAY
+#define POWEROFF_COUNT 40
+
+#endif /* _BUTTON_TARGET_H_ */
diff --git a/firmware/target/arm/s5l8702/ipod6g/cscodec-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/cscodec-ipod6g.c
new file mode 100644
index 0000000000..460b254730
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/cscodec-ipod6g.c
@@ -0,0 +1,64 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: wmcodec-s5l8700.c 22025 2009-07-25 00:49:13Z dave $
+ *
+ * S5L8702-specific code for Cirrus codecs
+ *
+ * Copyright (c) 2010 Michael Sparmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "system.h"
+#include "audiohw.h"
+#include "i2c-s5l8702.h"
+#include "s5l8702.h"
+#include "cscodec.h"
+
+void audiohw_init(void)
+{
+#ifdef HAVE_CS42L55
+ audiohw_preinit();
+#endif
+}
+
+unsigned char cscodec_read(int reg)
+{
+ unsigned char data;
+ i2c_read(0, 0x94, reg, 1, &data);
+ return data;
+}
+
+void cscodec_write(int reg, unsigned char data)
+{
+ i2c_write(0, 0x94, reg, 1, &data);
+}
+
+void cscodec_power(bool state)
+{
+ (void)state; //TODO: Figure out which LDO this is
+}
+
+void cscodec_reset(bool state)
+{
+ if (state) PDAT(3) &= ~8;
+ else PDAT(3) |= 8;
+}
+
+void cscodec_clock(bool state)
+{
+ if (state) CLKCON0C &= ~0xffff;
+ else CLKCON0C |= 0x8000;
+}
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S
new file mode 100644
index 0000000000..2b170f329b
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/lcd-asm-ipod6g.S
@@ -0,0 +1,295 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: lcd-as-video.S 26756 2010-06-11 04:41:36Z funman $
+ *
+ * Copyright (C) 2010 by Andree Buschmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+/****************************************************************************
+ * #define FORCE_FIFO_WAIT
+ *
+ * This is not needed in YUV blitting when the LCD IF is fast enough. In this
+ * case YUV-to-RGB conversion per pixel needs longer than the transfer of a
+ * pixel via the LCD IF. For iPod nano 2G this is true if the LCD IF is
+ * configured to use LCD_PHTIME = 0x00 (see lcd-nano2g.c).
+ ****************************************************************************/
+
+#include "config.h"
+
+ .section .icode, "ax", %progbits
+
+/****************************************************************************
+ * void lcd_write_line(const fb_data *addr,
+ * int pixelcount,
+ * const unsigned int lcd_base_addr);
+ *
+ * Writes pixelcount pixels from src-pointer (lcd_framebuffer) to LCD dataport.
+ */
+ .align 2
+ .global lcd_write_line
+ .type lcd_write_line, %function
+ /* r0 = addr, must be aligned */
+ /* r1 = pixel count, must be even */
+lcd_write_line: /* r2 = LCD_BASE */
+ stmfd sp!, {r4-r6, lr} /* save non-scratch registers */
+ add r12, r2, #0x40 /* LCD_WDATA = LCD data port */
+
+.loop:
+ ldmia r0!, {r3, r5} /* read 2 pixel (=8 byte) */
+
+ /* wait for FIFO half full */
+.fifo_wait:
+ ldr lr, [r2, #0x1C] /* while (LCD_STATUS & 0x08); */
+ tst lr, #0x8
+ bgt .fifo_wait
+
+ mov r4, r3, asr #16 /* r3 = 1st pixel, r4 = 2nd pixel */
+ mov r6, r5, asr #16 /* r5 = 3rd pixel, r6 = 4th pixel */
+ stmia r12, {r3-r6} /* write pixels (lowest 16 bit used) */
+
+ subs r1, r1, #4
+ bgt .loop
+
+ ldmpc regs=r4-r6
+
+/****************************************************************************
+ * extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
+ * const unsigned LCD_BASE,
+ * int width,
+ * int stride);
+ *
+ * Conversion from Motion JPEG and MPEG Y'PbPr to RGB is:
+ * |R| |1.164 0.000 1.596| |Y' - 16|
+ * |G| = |1.164 -0.391 -0.813| |Pb - 128|
+ * |B| |1.164 2.018 0.000| |Pr - 128|
+ *
+ * Scaled, normalized, rounded and tweaked to yield RGB 565:
+ * |R| |74 0 101| |Y' - 16| >> 9
+ * |G| = |74 -24 -51| |Cb - 128| >> 8
+ * |B| |74 128 0| |Cr - 128| >> 9
+ *
+ * Converts two lines from YUV to RGB565 and writes to LCD at once. First loop
+ * loads Cb/Cr, calculates the chroma offset and saves them to buffer. Within
+ * the second loop these chroma offset are reloaded from buffer. Within each
+ * loop two pixels are calculated and written to LCD.
+ */
+ .align 2
+ .global lcd_write_yuv420_lines
+ .type lcd_write_yuv420_lines, %function
+lcd_write_yuv420_lines:
+ /* r0 = src = yuv_src */
+ /* r1 = dst = LCD_BASE */
+ /* r2 = width */
+ /* r3 = stride */
+ stmfd sp!, { r4-r10, lr } /* save non-scratch */
+ ldmia r0, { r9, r10, r12 } /* r9 = yuv_src[0] = Y'_p */
+ /* r10 = yuv_src[1] = Cb_p */
+ /* r12 = yuv_src[2] = Cr_p */
+ add r3, r9, r3 /* r3 = &ysrc[stride] */
+ add r4, r2, r2, asr #1 /* chroma buffer lenght = width/2 *3 */
+ mov r4, r4, asl #2 /* use words for str/ldm possibility */
+ add r4, r4, #19 /* plus room for 4 additional words, */
+ bic r4, r4, #3 /* rounded up to multiples of 4 byte */
+ sub sp, sp, r4 /* and allocate on stack */
+ stmia sp, {r1-r4} /* LCD_BASE, width, &ysrc[stride], stack_alloc */
+
+ mov r7, r2 /* r7 = loop count */
+ add r8, sp, #16 /* chroma buffer */
+ add lr, r1, #0x40 /* LCD data port = LCD_BASE + 0x40 */
+
+ /* 1st loop start */
+10: /* loop start */
+
+ ldrb r0, [r10], #1 /* r0 = *usrc++ = *Cb_p++ */
+ ldrb r1, [r12], #1 /* r1 = *vsrc++ = *Cr_p++ */
+
+ sub r0, r0, #128 /* r0 = Cb-128 */
+ sub r1, r1, #128 /* r1 = Cr-128 */
+
+ add r2, r1, r1, asl #1 /* r2 = Cr*51 + Cb*24 */
+ add r2, r2, r2, asl #4
+ add r2, r2, r0, asl #3
+ add r2, r2, r0, asl #4
+
+ add r4, r1, r1, asl #2 /* r1 = Cr*101 */
+ add r4, r4, r1, asl #5
+ add r1, r4, r1, asl #6
+
+ add r1, r1, #256 /* r1 = rv = (r1 + 256) >> 9 */
+ mov r1, r1, asr #9
+ rsb r2, r2, #128 /* r2 = guv = (-r2 + 128) >> 8 */
+ mov r2, r2, asr #8
+ add r0, r0, #2 /* r0 = bu = (Cb*128 + 256) >> 9 */
+ mov r0, r0, asr #2
+ stmia r8!, {r0-r2} /* store r0, r1 and r2 to chroma buffer */
+
+ /* 1st loop, first pixel */
+ ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
+ sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
+ add r3, r5, r5, asl #2
+ add r5, r3, r5, asl #5
+
+ add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
+ add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
+ add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
+
+ orr r5, r6, r4 /* check if clamping is needed... */
+ orr r5, r5, r3, asr #1 /* ...at all */
+ cmp r5, #31
+ bls 15f /* -> no clamp */
+ cmp r6, #31 /* clamp r */
+ mvnhi r6, r6, asr #31
+ andhi r6, r6, #31
+ cmp r3, #63 /* clamp g */
+ mvnhi r3, r3, asr #31
+ andhi r3, r3, #63
+ cmp r4, #31 /* clamp b */
+ mvnhi r4, r4, asr #31
+ andhi r4, r4, #31
+15: /* no clamp */
+
+ /* calculate pixel_1 and save to r4 for later pixel packing */
+ orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
+ orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
+
+ /* 1st loop, second pixel */
+ ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
+ sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
+ add r3, r5, r5, asl #2
+ add r5, r3, r5, asl #5
+
+ add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
+ add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
+ add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
+
+ orr r0, r6, r5 /* check if clamping is needed... */
+ orr r0, r0, r3, asr #1 /* ...at all */
+ cmp r0, #31
+ bls 15f /* -> no clamp */
+ cmp r6, #31 /* clamp r */
+ mvnhi r6, r6, asr #31
+ andhi r6, r6, #31
+ cmp r3, #63 /* clamp g */
+ mvnhi r3, r3, asr #31
+ andhi r3, r3, #63
+ cmp r5, #31 /* clamp b */
+ mvnhi r5, r5, asr #31
+ andhi r5, r5, #31
+15: /* no clamp */
+
+ /* calculate pixel_2 and pack with pixel_1 before writing */
+ orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
+ orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
+#ifdef FORCE_FIFO_WAIT
+ /* wait for FIFO half full */
+.fifo_wait1:
+ ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */
+ tst r3, #0x8
+ bgt .fifo_wait1
+#endif
+ stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */
+
+ subs r7, r7, #2 /* check for loop end */
+ bgt 10b /* back to beginning */
+ /* 1st loop end */
+
+ /* Reload several registers for pointer rewinding for next loop */
+ add r8, sp, #16 /* chroma buffer */
+ ldmia sp, { r1, r7, r9} /* r1 = LCD_BASE */
+ /* r7 = loop count */
+ /* r9 = &ysrc[stride] */
+
+ /* 2nd loop start */
+20: /* loop start */
+ /* restore r0 (bu), r1 (rv) and r2 (guv) from chroma buffer */
+ ldmia r8!, {r0-r2}
+
+ /* 2nd loop, first pixel */
+ ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
+ sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
+ add r3, r5, r5, asl #2
+ add r5, r3, r5, asl #5
+
+ add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
+ add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
+ add r4, r0, r5, asr #8 /* r4 = b = (Y >> 9) + bu */
+
+ orr r5, r6, r4 /* check if clamping is needed... */
+ orr r5, r5, r3, asr #1 /* ...at all */
+ cmp r5, #31
+ bls 15f /* -> no clamp */
+ cmp r6, #31 /* clamp r */
+ mvnhi r6, r6, asr #31
+ andhi r6, r6, #31
+ cmp r3, #63 /* clamp g */
+ mvnhi r3, r3, asr #31
+ andhi r3, r3, #63
+ cmp r4, #31 /* clamp b */
+ mvnhi r4, r4, asr #31
+ andhi r4, r4, #31
+15: /* no clamp */
+ /* calculate pixel_1 and save to r4 for later pixel packing */
+ orr r4, r4, r3, lsl #5 /* pixel_1 = r<<11 | g<<5 | b */
+ orr r4, r4, r6, lsl #11 /* r4 = pixel_1 */
+
+ /* 2nd loop, second pixel */
+ ldrb r5, [r9], #1 /* r5 = *ysrc++ = *Y'_p++ */
+ sub r5, r5, #16 /* r5 = (Y'-16) * 74 */
+ add r3, r5, r5, asl #2
+ add r5, r3, r5, asl #5
+
+ add r6, r1, r5, asr #8 /* r6 = r = (Y >> 9) + rv */
+ add r3, r2, r5, asr #7 /* r3 = g = (Y >> 8) + guv */
+ add r5, r0, r5, asr #8 /* r5 = b = (Y >> 9) + bu */
+
+ orr r0, r6, r5 /* check if clamping is needed... */
+ orr r0, r0, r3, asr #1 /* ...at all */
+ cmp r0, #31
+ bls 15f /* -> no clamp */
+ cmp r6, #31 /* clamp r */
+ mvnhi r6, r6, asr #31
+ andhi r6, r6, #31
+ cmp r3, #63 /* clamp g */
+ mvnhi r3, r3, asr #31
+ andhi r3, r3, #63
+ cmp r5, #31 /* clamp b */
+ mvnhi r5, r5, asr #31
+ andhi r5, r5, #31
+15: /* no clamp */
+
+ /* calculate pixel_2 and pack with pixel_1 before writing */
+ orr r5, r5, r3, lsl #5 /* pixel_2 = r<<11 | g<<5 | b */
+ orr r5, r5, r6, lsl #11 /* r5 = pixel_2 */
+#ifdef FORCE_FIFO_WAIT
+ /* wait for FIFO half full */
+.fifo_wait2:
+ ldr r3, [lr, #-0x24] /* while (LCD_STATUS & 0x08); */
+ tst r3, #0x8
+ bgt .fifo_wait2
+#endif
+ stmia lr, {r4,r5} /* write pixel_1 and pixel_2 */
+
+ subs r7, r7, #2 /* check for loop end */
+ bgt 20b /* back to beginning */
+ /* 2nd loop end */
+
+ ldr r3, [sp, #12]
+ add sp, sp, r3 /* deallocate buffer */
+ ldmpc regs=r4-r10 /* restore registers */
+
+ .ltorg
+ .size lcd_write_yuv420_lines, .-lcd_write_yuv420_lines
diff --git a/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c
new file mode 100644
index 0000000000..1de6a8e62f
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/lcd-ipod6g.c
@@ -0,0 +1,286 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: lcd-nano2g.c 28868 2010-12-21 06:59:17Z Buschel $
+ *
+ * Copyright (C) 2009 by Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+
+#include "hwcompat.h"
+#include "kernel.h"
+#include "lcd.h"
+#include "system.h"
+#include "cpu.h"
+#include "pmu-target.h"
+#include "power.h"
+
+
+#define R_HORIZ_GRAM_ADDR_SET 0x200
+#define R_VERT_GRAM_ADDR_SET 0x201
+#define R_WRITE_DATA_TO_GRAM 0x202
+#define R_HORIZ_ADDR_START_POS 0x210
+#define R_HORIZ_ADDR_END_POS 0x211
+#define R_VERT_ADDR_START_POS 0x212
+#define R_VERT_ADDR_END_POS 0x213
+
+
+/* LCD type 1 register defines */
+
+#define R_COLUMN_ADDR_SET 0x2a
+#define R_ROW_ADDR_SET 0x2b
+#define R_MEMORY_WRITE 0x2c
+
+
+/** globals **/
+
+int lcd_type; /* also needed in debug-s5l8702.c */
+
+
+static inline void s5l_lcd_write_cmd_data(int cmd, int data)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd;
+
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data;
+}
+
+static inline void s5l_lcd_write_cmd(unsigned short cmd)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WCMD = cmd;
+}
+
+static inline void s5l_lcd_write_data(unsigned short data)
+{
+ while (LCD_STATUS & 0x10);
+ LCD_WDATA = data;
+}
+
+/*** hardware configuration ***/
+
+int lcd_default_contrast(void)
+{
+ return 0x1f;
+}
+
+void lcd_set_contrast(int val)
+{
+ (void)val;
+}
+
+void lcd_set_invert_display(bool yesno)
+{
+ (void)yesno;
+}
+
+void lcd_set_flip(bool yesno)
+{
+ (void)yesno;
+}
+
+bool lcd_active(void)
+{
+ return true;
+}
+
+void lcd_shutdown(void)
+{
+ pmu_write(0x2b, 0); /* Kill the backlight, instantly. */
+ pmu_write(0x29, 0);
+
+ if (lcd_type == 3)
+ {
+ s5l_lcd_write_cmd_data(0x7, 0x172);
+ s5l_lcd_write_cmd_data(0x30, 0x3ff);
+ sleep(HZ / 10);
+ s5l_lcd_write_cmd_data(0x7, 0x120);
+ s5l_lcd_write_cmd_data(0x30, 0x0);
+ s5l_lcd_write_cmd_data(0x100, 0x780);
+ s5l_lcd_write_cmd_data(0x7, 0x0);
+ s5l_lcd_write_cmd_data(0x101, 0x260);
+ s5l_lcd_write_cmd_data(0x102, 0xa9);
+ sleep(HZ / 30);
+ s5l_lcd_write_cmd_data(0x100, 0x700);
+ s5l_lcd_write_cmd_data(0x100, 0x704);
+ }
+ else if (lcd_type == 1)
+ {
+ s5l_lcd_write_cmd(0x28);
+ s5l_lcd_write_cmd(0x10);
+ sleep(HZ / 10);
+ }
+ else
+ {
+ s5l_lcd_write_cmd(0x28);
+ sleep(HZ / 20);
+ s5l_lcd_write_cmd(0x10);
+ sleep(HZ / 20);
+ }
+}
+
+void lcd_sleep(void)
+{
+ lcd_shutdown();
+}
+
+/* LCD init */
+void lcd_init_device(void)
+{
+ /* Detect lcd type */
+ lcd_type = (PDAT6 & 0x30) >> 4;
+}
+
+/*** Update functions ***/
+
+static inline void lcd_write_pixel(fb_data pixel)
+{
+ LCD_WDATA = pixel;
+}
+
+/* Update the display.
+ This must be called after all other LCD functions that change the display. */
+void lcd_update(void) ICODE_ATTR;
+void lcd_update(void)
+{
+ lcd_update_rect(0, 0, LCD_WIDTH, LCD_HEIGHT);
+}
+
+/* Line write helper function. */
+extern void lcd_write_line(const fb_data *addr,
+ int pixelcount,
+ const unsigned int lcd_base_addr);
+
+/* Update a fraction of the display. */
+void lcd_update_rect(int, int, int, int) ICODE_ATTR;
+void lcd_update_rect(int x, int y, int width, int height)
+{
+ int y0, x0, y1, x1;
+ fb_data* p;
+
+ /* Both x and width need to be preprocessed due to asm optimizations */
+ x = x & ~1; /* ensure x is even */
+ width = (width + 3) & ~3; /* ensure width is a multiple of 4 */
+
+ x0 = x; /* start horiz */
+ y0 = y; /* start vert */
+ x1 = (x + width) - 1; /* max horiz */
+ y1 = (y + height) - 1; /* max vert */
+
+ if (lcd_type & 2) {
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
+
+ s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
+ s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
+
+ s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
+ } else {
+ s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
+ s5l_lcd_write_data(x0 >> 8);
+ s5l_lcd_write_data(x0 & 0xff);
+ s5l_lcd_write_data(x1 >> 8);
+ s5l_lcd_write_data(x1 & 0xff);
+
+ s5l_lcd_write_cmd(R_ROW_ADDR_SET);
+ s5l_lcd_write_data(y0 >> 8);
+ s5l_lcd_write_data(y0 & 0xff);
+ s5l_lcd_write_data(y1 >> 8);
+ s5l_lcd_write_data(y1 & 0xff);
+
+ s5l_lcd_write_cmd(R_MEMORY_WRITE);
+ }
+ for (y = y0; y <= y1; y++)
+ for (x = x0; x <= x1; x++)
+ s5l_lcd_write_data(lcd_framebuffer[y][x]);
+ return;
+
+ /* Copy display bitmap to hardware */
+ p = &lcd_framebuffer[y0][x0];
+ if (LCD_WIDTH == width) {
+ /* Write all lines at once */
+ lcd_write_line(p, height*LCD_WIDTH, LCD_BASE);
+ } else {
+ y1 = height;
+ do {
+ /* Write a single line */
+ lcd_write_line(p, width, LCD_BASE);
+ p += LCD_WIDTH;
+ } while (--y1 > 0 );
+ }
+}
+
+/* Line write helper function for lcd_yuv_blit. Writes two lines of yuv420. */
+extern void lcd_write_yuv420_lines(unsigned char const * const src[3],
+ const unsigned int lcd_baseadress,
+ int width,
+ int stride);
+
+/* Blit a YUV bitmap directly to the LCD */
+void lcd_blit_yuv(unsigned char * const src[3],
+ int src_x, int src_y, int stride,
+ int x, int y, int width, int height)
+{
+ unsigned int z, y0, x0, y1, x1;;
+ unsigned char const * yuv_src[3];
+
+ width = (width + 1) & ~1; /* ensure width is even */
+
+ x0 = x; /* start horiz */
+ y0 = y; /* start vert */
+ x1 = (x + width) - 1; /* max horiz */
+ y1 = (y + height) - 1; /* max vert */
+
+ if (lcd_type & 2) {
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_START_POS, x0);
+ s5l_lcd_write_cmd_data(R_HORIZ_ADDR_END_POS, x1);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_START_POS, y0);
+ s5l_lcd_write_cmd_data(R_VERT_ADDR_END_POS, y1);
+
+ s5l_lcd_write_cmd_data(R_HORIZ_GRAM_ADDR_SET, (x1 << 8) | x0);
+ s5l_lcd_write_cmd_data(R_VERT_GRAM_ADDR_SET, (y1 << 8) | y0);
+
+ s5l_lcd_write_cmd(0);
+ s5l_lcd_write_cmd(R_WRITE_DATA_TO_GRAM);
+ } else {
+ s5l_lcd_write_cmd(R_COLUMN_ADDR_SET);
+ s5l_lcd_write_data(x0); /* Start column */
+ s5l_lcd_write_data(x1); /* End column */
+
+ s5l_lcd_write_cmd(R_ROW_ADDR_SET);
+ s5l_lcd_write_data(y0); /* Start row */
+ s5l_lcd_write_data(y1); /* End row */
+
+ s5l_lcd_write_cmd(R_MEMORY_WRITE);
+ }
+
+ z = stride * src_y;
+ yuv_src[0] = src[0] + z + src_x;
+ yuv_src[1] = src[1] + (z >> 2) + (src_x >> 1);
+ yuv_src[2] = src[2] + (yuv_src[1] - src[1]);
+
+ height >>= 1;
+
+ do {
+ lcd_write_yuv420_lines(yuv_src, LCD_BASE, width, stride);
+ yuv_src[0] += stride << 1;
+ yuv_src[1] += stride >> 1; /* Skip down one chroma line */
+ yuv_src[2] += stride >> 1;
+ } while (--height > 0);
+}
diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c
new file mode 100644
index 0000000000..73d8f98083
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/pmu-ipod6g.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: pmu-nano2g.c 27752 2010-08-08 10:49:32Z bertrik $
+ *
+ * Copyright © 2008 Rafaël Carré
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "kernel.h"
+#include "i2c-s5l8702.h"
+#include "pmu-target.h"
+
+static struct mutex pmu_adc_mutex;
+
+int pmu_read_multiple(int address, int count, unsigned char* buffer)
+{
+ return i2c_read(0, 0xe6, address, count, buffer);
+}
+
+int pmu_write_multiple(int address, int count, unsigned char* buffer)
+{
+ return i2c_write(0, 0xe6, address, count, buffer);
+}
+
+unsigned char pmu_read(int address)
+{
+ unsigned char tmp;
+
+ pmu_read_multiple(address, 1, &tmp);
+
+ return tmp;
+}
+
+int pmu_write(int address, unsigned char val)
+{
+ return pmu_write_multiple(address, 1, &val);
+}
+
+void pmu_init(void)
+{
+ mutex_init(&pmu_adc_mutex);
+}
+
+int pmu_read_adc(unsigned int adc)
+{
+ int data = 0;
+ mutex_lock(&pmu_adc_mutex);
+ pmu_write(0x54, 5 | (adc << 4));
+ while ((data & 0x80) == 0)
+ {
+ yield();
+ data = pmu_read(0x57);
+ }
+ int value = (pmu_read(0x55) << 2) | (data & 3);
+ mutex_unlock(&pmu_adc_mutex);
+ return value;
+}
+
+/* millivolts */
+int pmu_read_battery_voltage(void)
+{
+ return pmu_read_adc(0) * 6;
+}
+
+/* milliamps */
+int pmu_read_battery_current(void)
+{
+// return pmu_read_adc(2);
+ return 0;
+}
+
+void pmu_ldo_on_in_standby(unsigned int ldo, int onoff)
+{
+ if (ldo < 4)
+ {
+ unsigned char newval = pmu_read(0x3B) & ~(1 << (2 * ldo));
+ if (onoff) newval |= 1 << (2 * ldo);
+ pmu_write(0x3B, newval);
+ }
+ else if (ldo < 8)
+ {
+ unsigned char newval = pmu_read(0x3C) & ~(1 << (2 * (ldo - 4)));
+ if (onoff) newval |= 1 << (2 * (ldo - 4));
+ pmu_write(0x3C, newval);
+ }
+}
+
+void pmu_ldo_set_voltage(unsigned int ldo, unsigned char voltage)
+{
+ if (ldo > 6) return;
+ pmu_write(0x2d + (ldo << 1), voltage);
+}
+
+void pmu_hdd_power(bool on)
+{
+ pmu_write(0x1b, on ? 1 : 0);
+}
+
+void pmu_ldo_power_on(unsigned int ldo)
+{
+ if (ldo > 6) return;
+ pmu_write(0x2e + (ldo << 1), 1);
+}
+
+void pmu_ldo_power_off(unsigned int ldo)
+{
+ if (ldo > 6) return;
+ pmu_write(0x2e + (ldo << 1), 0);
+}
+
+void pmu_set_wake_condition(unsigned char condition)
+{
+ pmu_write(0xd, condition);
+}
+
+void pmu_enter_standby(void)
+{
+ pmu_write(0xc, 1);
+}
+
+void pmu_read_rtc(unsigned char* buffer)
+{
+ pmu_read_multiple(0x59, 7, buffer);
+}
+
+void pmu_write_rtc(unsigned char* buffer)
+{
+ pmu_write_multiple(0x59, 7, buffer);
+}
diff --git a/firmware/target/arm/s5l8702/ipod6g/pmu-target.h b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h
new file mode 100644
index 0000000000..a8c7851d97
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/pmu-target.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: pmu-target.h 24721 2010-02-17 15:54:48Z theseven $
+ *
+ * Copyright © 2009 Michael Sparmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#ifndef __PMU_TARGET_H__
+#define __PMU_TARGET_H__
+
+#include <stdbool.h>
+#include "config.h"
+
+unsigned char pmu_read(int address);
+int pmu_write(int address, unsigned char val);
+int pmu_read_multiple(int address, int count, unsigned char* buffer);
+int pmu_write_multiple(int address, int count, unsigned char* buffer);
+int pmu_read_adc(unsigned int adc);
+int pmu_read_battery_voltage(void);
+int pmu_read_battery_current(void);
+void pmu_init(void);
+void pmu_ldo_on_in_standby(unsigned int ldo, int onoff);
+void pmu_ldo_set_voltage(unsigned int ldo, unsigned char voltage);
+void pmu_ldo_power_on(unsigned int ldo);
+void pmu_ldo_power_off(unsigned int ldo);
+void pmu_set_wake_condition(unsigned char condition);
+void pmu_enter_standby(void);
+void pmu_read_rtc(unsigned char* buffer);
+void pmu_write_rtc(unsigned char* buffer);
+void pmu_hdd_power(bool on);
+
+#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c
new file mode 100644
index 0000000000..973e26968f
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/power-ipod6g.c
@@ -0,0 +1,75 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: power-nano2g.c 28190 2010-10-01 18:09:10Z Buschel $
+ *
+ * Copyright © 2009 Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <stdbool.h>
+#include "config.h"
+#include "inttypes.h"
+#include "s5l8702.h"
+#include "power.h"
+#include "panic.h"
+#include "pmu-target.h"
+#include "usb_core.h" /* for usb_charging_maxcurrent_change */
+
+static int idepowered;
+
+void power_off(void)
+{
+ pmu_set_wake_condition(0x42); /* USB inserted or EXTON1 */
+ pmu_enter_standby();
+
+ while(1);
+}
+
+void power_init(void)
+{
+ idepowered = false;
+}
+
+void ide_power_enable(bool on)
+{
+ idepowered = on;
+ pmu_hdd_power(on);
+}
+
+bool ide_powered()
+{
+ return idepowered;
+}
+
+#if CONFIG_CHARGING
+
+#ifdef HAVE_USB_CHARGING_ENABLE
+void usb_charging_maxcurrent_change(int maxcurrent)
+{
+ bool on = (maxcurrent >= 500);
+ GPIOCMD = 0xb060e | (on ? 1 : 0);
+}
+#endif
+
+unsigned int power_input_status(void)
+{
+ return (PDAT(12) & 8) ? POWER_INPUT_NONE : POWER_INPUT_MAIN_CHARGER;
+}
+
+bool charging_state(void)
+{
+ return false; //TODO: Figure out
+}
+#endif /* CONFIG_CHARGING */
diff --git a/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c
new file mode 100644
index 0000000000..3bd3791eeb
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/powermgmt-ipod6g.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: powermgmt-nano2g.c 28159 2010-09-24 22:42:06Z Buschel $
+ *
+ * Copyright © 2008 Rafaël Carré
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "config.h"
+#include "powermgmt.h"
+#include "pmu-target.h"
+#include "power.h"
+#include "audiohw.h"
+
+const unsigned short battery_level_dangerous[BATTERY_TYPES_COUNT] =
+{
+ 3600
+};
+
+const unsigned short battery_level_shutoff[BATTERY_TYPES_COUNT] =
+{
+ 3350
+};
+
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging disabled */
+const unsigned short percent_to_volt_discharge[BATTERY_TYPES_COUNT][11] =
+{
+ { 3550, 3783, 3830, 3882, 3911, 3949, 3996, 4067, 4148, 4228, 4310 }
+};
+
+#if CONFIG_CHARGING
+/* voltages (millivolt) of 0%, 10%, ... 100% when charging enabled */
+const unsigned short percent_to_volt_charge[11] =
+{
+ 3550, 3783, 3830, 3882, 3911, 3949, 3996, 4067, 4148, 4228, 4310
+};
+#endif /* CONFIG_CHARGING */
+
+/* ADC should read 0x3ff=6.00V */
+#define BATTERY_SCALE_FACTOR 6000
+/* full-scale ADC readout (2^10) in millivolt */
+
+
+/* Returns battery voltage from ADC [millivolts] */
+unsigned int battery_adc_voltage(void)
+{
+ int compensation = (10 * (pmu_read_battery_current() - 7)) / 12;
+ if (charging_state()) return pmu_read_battery_voltage() - compensation;
+ return pmu_read_battery_voltage() + compensation;
+}
+
+
+#ifdef HAVE_ACCESSORY_SUPPLY
+void accessory_supply_set(bool enable)
+{
+ if (enable)
+ {
+ /* Accessory voltage supply on */
+//TODO: pmu_ldo_power_on(6);
+ }
+ else
+ {
+ /* Accessory voltage supply off */
+//TODO: pmu_ldo_power_off(6);
+ }
+}
+#endif
+
+#ifdef HAVE_LINEOUT_POWEROFF
+void lineout_set(bool enable)
+{
+ /* Call audio hardware driver implementation */
+ audiohw_enable_lineout(enable);
+}
+#endif
diff --git a/firmware/target/arm/s5l8702/ipod6g/rtc-ipod6g.c b/firmware/target/arm/s5l8702/ipod6g/rtc-ipod6g.c
new file mode 100644
index 0000000000..76ef8ecb00
--- /dev/null
+++ b/firmware/target/arm/s5l8702/ipod6g/rtc-ipod6g.c
@@ -0,0 +1,72 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: rtc-nano2g.c 23114 2009-10-11 18:20:56Z theseven $
+ *
+ * Copyright (C) 2002 by Linus Nielsen Feltzing, Uwe Freese, Laurent Baum
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "rtc.h"
+#include "kernel.h"
+#include "system.h"
+#include "pmu-target.h"
+
+void rtc_init(void)
+{
+}
+
+int rtc_read_datetime(struct tm *tm)
+{
+ unsigned int i;
+ unsigned char buf[7];
+
+ pmu_read_rtc(buf);
+
+ for (i = 0; i < sizeof(buf); i++)
+ buf[i] = BCD2DEC(buf[i]);
+
+ tm->tm_sec = buf[0];
+ tm->tm_min = buf[1];
+ tm->tm_hour = buf[2];
+ tm->tm_wday = buf[3];
+ tm->tm_mday = buf[4];
+ tm->tm_mon = buf[5] - 1;
+ tm->tm_year = buf[6] + 100;
+
+ return 0;
+}
+
+int rtc_write_datetime(const struct tm *tm)
+{
+ unsigned int i;
+ unsigned char buf[7];
+
+ buf[0] = tm->tm_sec;
+ buf[1] = tm->tm_min;
+ buf[2] = tm->tm_hour;
+ buf[3] = tm->tm_wday;
+ buf[4] = tm->tm_mday;
+ buf[5] = tm->tm_mon + 1;
+ buf[6] = tm->tm_year - 100;
+
+ for (i = 0; i < sizeof(buf); i++)
+ buf[i] = DEC2BCD(buf[i]);
+
+ pmu_write_rtc(buf);
+
+ return 0;
+}
+
diff --git a/firmware/target/arm/s5l8702/kernel-s5l8702.c b/firmware/target/arm/s5l8702/kernel-s5l8702.c
new file mode 100644
index 0000000000..67dabd5f3f
--- /dev/null
+++ b/firmware/target/arm/s5l8702/kernel-s5l8702.c
@@ -0,0 +1,56 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: kernel-s5l8700.c 28795 2010-12-11 17:52:52Z Buschel $
+ *
+ * Copyright © 2009 Bertrik Sikken
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include "config.h"
+#include "system.h"
+#include "kernel.h"
+
+/* S5L8702 driver for the kernel timer
+
+ Timer B is configured as a 10 kHz timer
+ */
+
+void INT_TIMERB(void)
+{
+ /* clear interrupt */
+ TBCON = TBCON;
+
+ call_tick_tasks(); /* Run through the list of tick tasks */
+}
+
+void tick_start(unsigned int interval_in_ms)
+{
+ int cycles = 10 * interval_in_ms;
+
+ /* configure timer for 10 kHz */
+ TBCMD = (1 << 1); /* TB_CLR */
+ TBPRE = 208 - 1; /* prescaler */
+ TBCON = (0 << 13) | /* TB_INT1_EN */
+ (1 << 12) | /* TB_INT0_EN */
+ (0 << 11) | /* TB_START */
+ (2 << 8) | /* TB_CS = PCLK / 16 */
+ (0 << 4); /* TB_MODE_SEL = interval mode */
+ TBDATA0 = cycles; /* set interval period */
+ TBCMD = (1 << 0); /* TB_EN */
+
+ /* enable timer interrupt */
+ VIC0INTENABLE = 1 << IRQ_TIMER;
+}
+
diff --git a/firmware/target/arm/s5l8702/pcm-s5l8702.c b/firmware/target/arm/s5l8702/pcm-s5l8702.c
new file mode 100644
index 0000000000..7966eaddbd
--- /dev/null
+++ b/firmware/target/arm/s5l8702/pcm-s5l8702.c
@@ -0,0 +1,219 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: pcm-s5l8700.c 28600 2010-11-14 19:49:20Z Buschel $
+ *
+ * Copyright © 2011 Michael Sparmann
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#include <string.h>
+
+#include "config.h"
+#include "system.h"
+#include "audio.h"
+#include "s5l8702.h"
+#include "panic.h"
+#include "audiohw.h"
+#include "pcm.h"
+#include "pcm_sampr.h"
+#include "mmu-arm.h"
+
+/* S5L8702 PCM driver tunables: */
+#define LLIMAX (2047) /* Maximum number of samples per LLI */
+#define CHUNKSIZE (8700) /* Maximum number of samples to handle with one IRQ */
+ /* (bigger chunks will be segmented internally) */
+#define WATERMARK (512) /* Number of remaining samples to schedule IRQ at */
+
+static volatile int locked = 0;
+static const int zerosample = 0;
+static unsigned char dblbuf[WATERMARK * 4] IBSS_ATTR;
+struct dma_lli lli[(CHUNKSIZE - WATERMARK + LLIMAX - 1) / LLIMAX + 1]
+ __attribute__((aligned(16)));
+static const unsigned char* dataptr;
+static size_t remaining;
+
+/* Mask the DMA interrupt */
+void pcm_play_lock(void)
+{
+ if (locked++ == 0) {
+ //TODO: Urgh, I don't like that at all...
+ VIC0INTENCLEAR = 1 << IRQ_DMAC0;
+ }
+}
+
+/* Unmask the DMA interrupt if enabled */
+void pcm_play_unlock(void)
+{
+ if (--locked == 0) {
+ VIC0INTENABLE = 1 << IRQ_DMAC0;
+ }
+}
+
+void INT_DMAC0C0(void) ICODE_ATTR;
+void INT_DMAC0C0(void)
+{
+ DMAC0INTTCCLR = 1;
+ if (!remaining) pcm_play_get_more_callback((void**)&dataptr, &remaining);
+ if (!remaining)
+ {
+ lli->nextlli = NULL;
+ lli->control = 0x75249000;
+ clean_dcache();
+ return;
+ }
+ uint32_t lastsize = MIN(WATERMARK * 4, remaining);
+ remaining -= lastsize;
+ struct dma_lli* lastlli;
+ if (remaining) lastlli = &lli[ARRAYLEN(lli) - 1];
+ else lastlli = lli;
+ uint32_t chunksize = MIN(CHUNKSIZE * 4 - lastsize, remaining);
+ if (remaining > chunksize && chunksize > remaining - WATERMARK * 4)
+ chunksize = remaining - WATERMARK * 4;
+ remaining -= chunksize;
+ bool last = !chunksize;
+ int i = 0;
+ while (chunksize)
+ {
+ uint32_t thislli = MIN(LLIMAX * 4, chunksize);
+ chunksize -= thislli;
+ lli[i].srcaddr = (void*)dataptr;
+ lli[i].dstaddr = (void*)((int)&I2STXDB0);
+ lli[i].nextlli = chunksize ? &lli[i + 1] : lastlli;
+ lli[i].control = (chunksize ? 0x75249000 : 0xf5249000) | (thislli / 2);
+ dataptr += thislli;
+ i++;
+ }
+ if (!remaining) memcpy(dblbuf, dataptr, lastsize);
+ lastlli->srcaddr = remaining ? dataptr : dblbuf;
+ lastlli->dstaddr = (void*)((int)&I2STXDB0);
+ lastlli->nextlli = last ? NULL : lli;
+ lastlli->control = (last ? 0xf5249000 : 0x75249000) | (lastsize / 2);
+ dataptr += lastsize;
+ clean_dcache();
+ if (!(DMAC0C0CONFIG & 1) && (lli[0].control & 0xfff))
+ {
+ DMAC0C0LLI = lli[0];
+ DMAC0C0CONFIG = 0x8a81;
+ }
+ else DMAC0C0NEXTLLI = lli;
+}
+
+void pcm_play_dma_start(const void* addr, size_t size)
+{
+ dataptr = (const unsigned char*)addr;
+ remaining = size;
+ I2STXCOM = 0xe;
+ DMAC0CONFIG |= 4;
+ INT_DMAC0C0();
+}
+
+void pcm_play_dma_stop(void)
+{
+ DMAC0C0CONFIG = 0x8a80;
+ I2STXCOM = 0xa;
+}
+
+/* pause playback by disabling LRCK */
+void pcm_play_dma_pause(bool pause)
+{
+ if (pause) I2STXCOM |= 1;
+ else I2STXCOM &= ~1;
+}
+
+void pcm_play_dma_init(void)
+{
+ PWRCON(0) &= ~(1 << 4);
+ PWRCON(1) &= ~(1 << 7);
+ I2S40 = 0x110;
+ I2STXCON = 0xb100059;
+ I2SCLKCON = 1;
+ VIC0INTENABLE = 1 << IRQ_DMAC0;
+
+ audiohw_preinit();
+}
+
+void pcm_postinit(void)
+{
+ audiohw_postinit();
+}
+
+void pcm_dma_apply_settings(void)
+{
+}
+
+size_t pcm_get_bytes_waiting(void)
+{
+ int bytes = remaining + (DMAC0C0LLI.control & 0xfff) * 2;
+ const struct dma_lli* lli = DMAC0C0LLI.nextlli;
+ while (lli)
+ {
+ bytes += (lli->control & 0xfff) * 2;
+ lli = lli->nextlli;
+ }
+ return bytes;
+}
+
+const void* pcm_play_dma_get_peak_buffer(int *count)
+{
+ *count = (DMAC0C0LLI.control & 0xfff) * 2;
+ return (void*)(((uint32_t)DMAC0C0LLI.srcaddr) & ~3);
+}
+
+#ifdef HAVE_PCM_DMA_ADDRESS
+void * pcm_dma_addr(void *addr)
+{
+ return addr;
+}
+#endif
+
+
+/****************************************************************************
+ ** Recording DMA transfer
+ **/
+#ifdef HAVE_RECORDING
+void pcm_rec_lock(void)
+{
+}
+
+void pcm_rec_unlock(void)
+{
+}
+
+void pcm_rec_dma_stop(void)
+{
+}
+
+void pcm_rec_dma_start(void *addr, size_t size)
+{
+ (void)addr;
+ (void)size;
+}
+
+void pcm_rec_dma_close(void)
+{
+}
+
+
+void pcm_rec_dma_init(void)
+{
+}
+
+
+const void * pcm_rec_dma_get_peak_buffer(void)
+{
+ return NULL;
+}
+
+#endif /* HAVE_RECORDING */
diff --git a/firmware/target/arm/s5l8702/system-s5l8702.c b/firmware/target/arm/s5l8702/system-s5l8702.c
new file mode 100644
index 0000000000..6973738790
--- /dev/null
+++ b/firmware/target/arm/s5l8702/system-s5l8702.c
@@ -0,0 +1,268 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: system-s5l8700.c 28935 2010-12-30 20:23:46Z Buschel $
+ *
+ * Copyright (C) 2007 by Rob Purchase
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+
+#include "kernel.h"
+#include "system.h"
+#include "panic.h"
+#include "system-target.h"
+#include "pmu-target.h"
+
+#define default_interrupt(name) \
+ extern __attribute__((weak,alias("UIRQ"))) void name (void)
+
+void irq_handler(void) __attribute__((interrupt ("IRQ"), naked));
+void fiq_handler(void) __attribute__((interrupt ("FIQ"), naked, \
+ weak, alias("fiq_dummy")));
+
+default_interrupt(INT_IRQ0);
+default_interrupt(INT_IRQ1);
+default_interrupt(INT_IRQ2);
+default_interrupt(INT_IRQ3);
+default_interrupt(INT_IRQ4);
+default_interrupt(INT_IRQ5);
+default_interrupt(INT_IRQ6);
+default_interrupt(INT_IRQ7);
+default_interrupt(INT_TIMERA);
+default_interrupt(INT_TIMERB);
+default_interrupt(INT_TIMERC);
+default_interrupt(INT_TIMERD);
+default_interrupt(INT_TIMERE);
+default_interrupt(INT_TIMERF);
+default_interrupt(INT_TIMERG);
+default_interrupt(INT_TIMERH);
+default_interrupt(INT_IRQ9);
+default_interrupt(INT_IRQ10);
+default_interrupt(INT_IRQ11);
+default_interrupt(INT_IRQ12);
+default_interrupt(INT_IRQ13);
+default_interrupt(INT_IRQ14);
+default_interrupt(INT_IRQ15);
+default_interrupt(INT_DMAC0C0);
+default_interrupt(INT_DMAC0C1);
+default_interrupt(INT_DMAC0C2);
+default_interrupt(INT_DMAC0C3);
+default_interrupt(INT_DMAC0C4);
+default_interrupt(INT_DMAC0C5);
+default_interrupt(INT_DMAC0C6);
+default_interrupt(INT_DMAC0C7);
+default_interrupt(INT_DMAC1C0);
+default_interrupt(INT_DMAC1C1);
+default_interrupt(INT_DMAC1C2);
+default_interrupt(INT_DMAC1C3);
+default_interrupt(INT_DMAC1C4);
+default_interrupt(INT_DMAC1C5);
+default_interrupt(INT_DMAC1C6);
+default_interrupt(INT_DMAC1C7);
+default_interrupt(INT_IRQ18);
+default_interrupt(INT_USB_FUNC);
+default_interrupt(INT_IRQ20);
+default_interrupt(INT_IRQ21);
+default_interrupt(INT_IRQ22);
+default_interrupt(INT_WHEEL);
+default_interrupt(INT_IRQ24);
+default_interrupt(INT_IRQ25);
+default_interrupt(INT_IRQ26);
+default_interrupt(INT_IRQ27);
+default_interrupt(INT_IRQ28);
+default_interrupt(INT_ATA);
+default_interrupt(INT_IRQ30);
+default_interrupt(INT_IRQ31);
+default_interrupt(INT_IRQ32);
+default_interrupt(INT_IRQ33);
+default_interrupt(INT_IRQ34);
+default_interrupt(INT_IRQ35);
+default_interrupt(INT_IRQ36);
+default_interrupt(INT_IRQ37);
+default_interrupt(INT_IRQ38);
+default_interrupt(INT_IRQ39);
+default_interrupt(INT_IRQ40);
+default_interrupt(INT_IRQ41);
+default_interrupt(INT_IRQ42);
+default_interrupt(INT_IRQ43);
+default_interrupt(INT_IRQ44);
+default_interrupt(INT_IRQ45);
+default_interrupt(INT_IRQ46);
+default_interrupt(INT_IRQ47);
+default_interrupt(INT_IRQ48);
+default_interrupt(INT_IRQ49);
+default_interrupt(INT_IRQ50);
+default_interrupt(INT_IRQ51);
+default_interrupt(INT_IRQ52);
+default_interrupt(INT_IRQ53);
+default_interrupt(INT_IRQ54);
+default_interrupt(INT_IRQ55);
+default_interrupt(INT_IRQ56);
+default_interrupt(INT_IRQ57);
+default_interrupt(INT_IRQ58);
+default_interrupt(INT_IRQ59);
+default_interrupt(INT_IRQ60);
+default_interrupt(INT_IRQ61);
+default_interrupt(INT_IRQ62);
+default_interrupt(INT_IRQ63);
+
+
+int current_irq;
+
+
+void INT_TIMER(void) ICODE_ATTR;
+void INT_TIMER()
+{
+ if (TACON & (TACON >> 4) & 0x7000) INT_TIMERA();
+ if (TBCON & (TBCON >> 4) & 0x7000) INT_TIMERB();
+ if (TCCON & (TCCON >> 4) & 0x7000) INT_TIMERC();
+ if (TDCON & (TDCON >> 4) & 0x7000) INT_TIMERD();
+ if (TFCON & (TFCON >> 4) & 0x7000) INT_TIMERF();
+ if (TGCON & (TGCON >> 4) & 0x7000) INT_TIMERG();
+ if (THCON & (THCON >> 4) & 0x7000) INT_TIMERH();
+}
+
+void INT_DMAC0(void) ICODE_ATTR;
+void INT_DMAC0()
+{
+ uint32_t intsts = DMAC0INTSTS;
+ if (intsts & 1) INT_DMAC0C0();
+ if (intsts & 2) INT_DMAC0C1();
+ if (intsts & 4) INT_DMAC0C2();
+ if (intsts & 8) INT_DMAC0C3();
+ if (intsts & 0x10) INT_DMAC0C4();
+ if (intsts & 0x20) INT_DMAC0C5();
+ if (intsts & 0x40) INT_DMAC0C6();
+ if (intsts & 0x80) INT_DMAC0C7();
+}
+
+void INT_DMAC1(void) ICODE_ATTR;
+void INT_DMAC1()
+{
+ uint32_t intsts = DMAC1INTSTS;
+ if (intsts & 1) INT_DMAC1C0();
+ if (intsts & 2) INT_DMAC1C1();
+ if (intsts & 4) INT_DMAC1C2();
+ if (intsts & 8) INT_DMAC1C3();
+ if (intsts & 0x10) INT_DMAC1C4();
+ if (intsts & 0x20) INT_DMAC1C5();
+ if (intsts & 0x40) INT_DMAC1C6();
+ if (intsts & 0x80) INT_DMAC1C7();
+}
+
+static void (* const irqvector[])(void) =
+{
+ INT_IRQ0,INT_IRQ1,INT_IRQ2,INT_IRQ3,INT_IRQ4,INT_IRQ5,INT_IRQ6,INT_IRQ7,
+ INT_TIMER,INT_IRQ9,INT_IRQ10,INT_IRQ11,INT_IRQ12,INT_IRQ13,INT_IRQ14,INT_IRQ15,
+ INT_DMAC0,INT_DMAC1,INT_IRQ18,INT_USB_FUNC,INT_IRQ20,INT_IRQ21,INT_IRQ22,INT_WHEEL,
+ INT_IRQ24,INT_IRQ25,INT_IRQ26,INT_IRQ27,INT_IRQ28,INT_ATA,INT_IRQ30,INT_IRQ31,
+ INT_IRQ32,INT_IRQ33,INT_IRQ34,INT_IRQ35,INT_IRQ36,INT_IRQ37,INT_IRQ38,INT_IRQ39,
+ INT_IRQ40,INT_IRQ41,INT_IRQ42,INT_IRQ43,INT_IRQ55,INT_IRQ56,INT_IRQ57,INT_IRQ58,
+ INT_IRQ48,INT_IRQ49,INT_IRQ50,INT_IRQ51,INT_IRQ52,INT_IRQ53,INT_IRQ54,INT_IRQ55,
+ INT_IRQ56,INT_IRQ57,INT_IRQ58,INT_IRQ59,INT_IRQ60,INT_IRQ61,INT_IRQ62,INT_IRQ63
+};
+
+static void UIRQ(void)
+{
+ panicf("Unhandled IRQ %d!", current_irq);
+}
+
+void irq_handler(void)
+{
+ /*
+ * Based on: linux/arch/arm/kernel/entry-armv.S and system-meg-fx.c
+ */
+
+ asm volatile( "stmfd sp!, {r0-r7, ip, lr} \n" /* Store context */
+ "sub sp, sp, #8 \n"); /* Reserve stack */
+
+ void* dummy = VIC0ADDRESS;
+ dummy = VIC1ADDRESS;
+ uint32_t irqs0 = VIC0IRQSTATUS;
+ uint32_t irqs1 = VIC1IRQSTATUS;
+ for (current_irq = 0; irqs0; current_irq++, irqs0 >>= 1)
+ if (irqs0 & 1)
+ irqvector[current_irq]();
+ for (current_irq = 32; irqs1; current_irq++, irqs1 >>= 1)
+ if (irqs1 & 1)
+ irqvector[current_irq]();
+ VIC0ADDRESS = NULL;
+ VIC1ADDRESS = NULL;
+
+ asm volatile( "add sp, sp, #8 \n" /* Cleanup stack */
+ "ldmfd sp!, {r0-r7, ip, lr} \n" /* Restore context */
+ "subs pc, lr, #4 \n"); /* Return from IRQ */
+}
+
+void fiq_dummy(void)
+{
+ asm volatile (
+ "subs pc, lr, #4 \r\n"
+ );
+}
+
+
+void system_init(void)
+{
+ pmu_init();
+ VIC0INTENABLE = 1 << IRQ_WHEEL;
+}
+
+void system_reboot(void)
+{
+ /* Reset the SoC */
+ asm volatile("msr CPSR_c, #0xd3 \n"
+ "mov r0, #0x100000 \n"
+ "mov r1, #0x3c800000 \n"
+ "str r0, [r1] \n");
+
+ /* Wait for reboot to kick in */
+ while(1);
+}
+
+//extern void post_mortem_stub(void);
+
+void system_exception_wait(void)
+{
+// post_mortem_stub();
+ while(1);
+}
+
+int system_memory_guard(int newmode)
+{
+ (void)newmode;
+ return 0;
+}
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+
+void set_cpu_frequency(long frequency)
+{
+ if (cpu_frequency == frequency)
+ return;
+
+ if (frequency == CPUFREQ_MAX)
+ {
+ //TODO: Figure out and implement
+ }
+ else
+ {
+ //TODO: Figure out and implement
+ }
+
+ cpu_frequency = frequency;
+}
+
+#endif
diff --git a/firmware/target/arm/s5l8702/system-target.h b/firmware/target/arm/s5l8702/system-target.h
new file mode 100644
index 0000000000..96e0371526
--- /dev/null
+++ b/firmware/target/arm/s5l8702/system-target.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: system-target.h 28791 2010-12-11 09:39:33Z Buschel $
+ *
+ * Copyright (C) 2007 by Dave Chapman
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#ifndef SYSTEM_TARGET_H
+#define SYSTEM_TARGET_H
+
+#include "system-arm.h"
+#include "mmu-arm.h"
+
+//TODO: Figure out
+#define CPUFREQ_SLEEP 32768
+#define CPUFREQ_MAX (1843200 * 4 * 26 / 1) /* 191692800 Hz */
+#define CPUFREQ_DEFAULT (CPUFREQ_MAX/4) /* 47923200 Hz */
+#define CPUFREQ_NORMAL (CPUFREQ_MAX/4)
+
+#define STORAGE_WANTS_ALIGN
+
+#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))
+#define inw(a) (*(volatile unsigned short*) (a))
+#define outw(a,b) (*(volatile unsigned short*) (b) = (a))
+
+static inline void udelay(unsigned usecs)
+{
+ unsigned stop = USEC_TIMER + usecs;
+ while (TIME_BEFORE(USEC_TIMER, stop));
+}
+
+#endif /* SYSTEM_TARGET_H */
diff --git a/firmware/target/arm/s5l8702/timer-s5l8702.c b/firmware/target/arm/s5l8702/timer-s5l8702.c
new file mode 100644
index 0000000000..fb56a9ffcf
--- /dev/null
+++ b/firmware/target/arm/s5l8702/timer-s5l8702.c
@@ -0,0 +1,94 @@
+/***************************************************************************
+* __________ __ ___.
+* Open \______ \ ____ ____ | | _\_ |__ _______ ___
+* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+* \/ \/ \/ \/ \/
+* $Id: timer-s5l8700.c 23103 2009-10-11 11:35:14Z theseven $
+*
+* Copyright (C) 2009 Bertrik Sikken
+*
+* This program is free software; you can redistribute it and/or
+* modify it under the terms of the GNU General Public License
+* as published by the Free Software Foundation; either version 2
+* of the License, or (at your option) any later version.
+*
+* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+* KIND, either express or implied.
+*
+****************************************************************************/
+
+#include "config.h"
+
+#include "inttypes.h"
+#include "s5l8702.h"
+#include "system.h"
+#include "timer.h"
+
+//TODO: This needs calibration once we figure out the clocking
+
+void INT_TIMERC(void)
+{
+ /* clear interrupt */
+ TCCON = TCCON;
+
+ if (pfn_timer != NULL) {
+ pfn_timer();
+ }
+}
+
+bool timer_set(long cycles, bool start)
+{
+ static const int cs_table[] = {1, 2, 4, 6};
+ int prescale, cs;
+ long count;
+
+ /* stop and clear timer */
+ TCCMD = (1 << 1); /* TD_CLR */
+
+ /* optionally unregister any previously registered timer user */
+ if (start) {
+ if (pfn_unregister != NULL) {
+ pfn_unregister();
+ pfn_unregister = NULL;
+ }
+ }
+
+ /* scale the count down with the clock select */
+ for (cs = 0; cs < 4; cs++) {
+ count = cycles >> cs_table[cs];
+ if ((count < 65536) || (cs == 3)) {
+ break;
+ }
+ }
+
+ /* scale the count down with the prescaler */
+ prescale = 1;
+ while (count >= 65536) {
+ count >>= 1;
+ prescale <<= 1;
+ }
+
+ /* configure timer */
+ TCCON = (1 << 12) | /* TD_INT0_EN */
+ (cs << 8) | /* TS_CS */
+ (0 << 4); /* TD_MODE_SEL, 0 = interval mode */
+ TCPRE = prescale - 1;
+ TCDATA0 = count;
+ TCCMD = (1 << 0); /* TD_ENABLE */
+
+ return true;
+}
+
+bool timer_start(void)
+{
+ TCCMD = (1 << 0); /* TD_ENABLE */
+ return true;
+}
+
+void timer_stop(void)
+{
+ TCCMD = (0 << 0); /* TD_ENABLE */
+}
+
diff --git a/firmware/target/arm/thread-arm.c b/firmware/target/arm/thread-arm.c
index 9ea3d0bef9..84a3aecbd7 100644
--- a/firmware/target/arm/thread-arm.c
+++ b/firmware/target/arm/thread-arm.c
@@ -93,7 +93,8 @@ static inline void load_context(const void* addr)
#if defined(CPU_TCC780X) || defined(CPU_TCC77X) /* Single core only for now */ \
|| CONFIG_CPU == IMX31L || CONFIG_CPU == DM320 || CONFIG_CPU == AS3525 \
-|| CONFIG_CPU == S3C2440 || CONFIG_CPU == S5L8701 || CONFIG_CPU == AS3525v2
+|| CONFIG_CPU == S3C2440 || CONFIG_CPU == S5L8701 || CONFIG_CPU == AS3525v2 \
+|| CONFIG_CPU == S5L8702
/* Use the generic ARMv4/v5/v6 wait for IRQ */
static inline void core_sleep(void)
{