summaryrefslogtreecommitdiff
path: root/firmware
diff options
context:
space:
mode:
Diffstat (limited to 'firmware')
-rw-r--r--firmware/SOURCES5
-rw-r--r--firmware/app.lds2
-rw-r--r--firmware/export/config-ifp7xx.h4
-rw-r--r--firmware/export/pnx0101.h143
-rw-r--r--firmware/export/system.h7
-rw-r--r--firmware/export/timer.h2
-rw-r--r--firmware/kernel.c20
-rw-r--r--firmware/system.c87
-rw-r--r--firmware/target/arm/crt0-pnx0101.S229
-rw-r--r--firmware/target/arm/crt0.S24
-rw-r--r--firmware/target/arm/system-pnx0101.c351
-rw-r--r--firmware/timer.c48
12 files changed, 795 insertions, 127 deletions
diff --git a/firmware/SOURCES b/firmware/SOURCES
index d83f626977..65ae84b45d 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -278,6 +278,9 @@ drivers/i2c-pnx0101.c
#elif CONFIG_I2C == I2C_S3C2440
/* no i2c driver yet */
#endif
+#if CONFIG_CPU == PNX0101
+target/arm/system-pnx0101.c
+#endif
#if defined(CPU_PP)
#ifdef BOOTLOADER
target/arm/crt0-pp-bl.S
@@ -286,6 +289,8 @@ target/arm/pcm-pp.c
target/arm/audio-pp.c
target/arm/crt0-pp.S
#endif
+#elif CONFIG_CPU == PNX0101
+target/arm/crt0-pnx0101.S
#elif defined(CPU_ARM)
target/arm/crt0.S
#endif /* defined(CPU_*) */
diff --git a/firmware/app.lds b/firmware/app.lds
index eb63fd8195..f1a02b56d7 100644
--- a/firmware/app.lds
+++ b/firmware/app.lds
@@ -9,6 +9,8 @@ OUTPUT_FORMAT(elf32-littlearm)
OUTPUT_ARCH(arm)
#ifdef CPU_PP
INPUT(target/arm/crt0-pp.o)
+#elif CONFIG_CPU == PNX0101
+INPUT(target/arm/crt0-pnx0101.o)
#elif defined(CPU_ARM)
INPUT(target/arm/crt0.o)
#endif
diff --git a/firmware/export/config-ifp7xx.h b/firmware/export/config-ifp7xx.h
index d9c7590c0b..575571eb97 100644
--- a/firmware/export/config-ifp7xx.h
+++ b/firmware/export/config-ifp7xx.h
@@ -80,7 +80,7 @@
#define CONFIG_BACKLIGHT BL_IRIVER_IFP7XX /* port controlled */
/* Define this to the CPU frequency */
-#define CPU_FREQ 30000000
+#define CPU_FREQ 48000000
#define CONFIG_LCD LCD_IFP7XX
@@ -98,7 +98,7 @@
#define HAVE_GDB_API
/* Define this if you have adjustable CPU frequency */
-//#define HAVE_ADJUSTABLE_CPU_FREQ
+#define HAVE_ADJUSTABLE_CPU_FREQ
#define BOOTFILE_EXT "iriver"
#define BOOTFILE "rockbox." BOOTFILE_EXT
diff --git a/firmware/export/pnx0101.h b/firmware/export/pnx0101.h
index 4867c6b25d..8ff42de57a 100644
--- a/firmware/export/pnx0101.h
+++ b/firmware/export/pnx0101.h
@@ -78,4 +78,147 @@
#define CODECVOL (*(volatile unsigned long *)0x80200398)
+#ifndef ASM
+
+/* Clock generation unit */
+
+struct pnx0101_cgu {
+ unsigned long base_scr[12];
+ unsigned long base_fs1[12];
+ unsigned long base_fs2[12];
+ unsigned long base_ssr[12];
+ unsigned long clk_pcr[73];
+ unsigned long clk_psr[73];
+ unsigned long clk_esr[67];
+ unsigned long base_bcr[3];
+ unsigned long base_fdc[18];
+};
+
+#define CGU (*(volatile struct pnx0101_cgu *)0x80004000)
+
+#define PNX0101_SEL_STAGE_SYS 0
+#define PNX0101_SEL_STAGE_APB0 1
+#define PNX0101_SEL_STAGE_APB1 2
+#define PNX0101_SEL_STAGE_APB3 3
+#define PNX0101_SEL_STAGE_DAIO 9
+
+#define PNX0101_HIPREC_FDC 16
+
+#define PNX0101_FIRST_DIV_SYS 0
+#define PNX0101_N_DIV_SYS 7
+#define PNX0101_FIRST_DIV_APB0 7
+#define PNX0101_N_DIV_APB0 2
+#define PNX0101_FIRST_DIV_APB1 9
+#define PNX0101_N_DIV_APB1 1
+#define PNX0101_FIRST_DIV_APB3 10
+#define PNX0101_N_DIV_APB3 1
+#define PNX0101_FIRST_DIV_DAIO 12
+#define PNX0101_N_DIV_DAIO 6
+
+#define PNX0101_BCR_SYS 0
+#define PNX0101_BCR_APB0 1
+#define PNX0101_BCR_DAIO 2
+
+#define PNX0101_FIRST_ESR_SYS 0
+#define PNX0101_N_ESR_SYS 28
+#define PNX0101_FIRST_ESR_APB0 28
+#define PNX0101_N_ESR_APB0 9
+#define PNX0101_FIRST_ESR_APB1 37
+#define PNX0101_N_ESR_APB1 4
+#define PNX0101_FIRST_ESR_APB3 41
+#define PNX0101_N_ESR_APB3 16
+#define PNX0101_FIRST_ESR_DAIO 58
+#define PNX0101_N_ESR_DAIO 9
+
+#define PNX0101_ESR_APB1 0x25
+#define PNX0101_ESR_T0 0x26
+#define PNX0101_ESR_T1 0x27
+#define PNX0101_ESR_I2C 0x28
+
+#define PNX0101_CLOCK_APB1 0x25
+#define PNX0101_CLOCK_T0 0x26
+#define PNX0101_CLOCK_T1 0x27
+#define PNX0101_CLOCK_I2C 0x28
+
+#define PNX0101_MAIN_CLOCK_FAST 1
+#define PNX0101_MAIN_CLOCK_MAIN_PLL 9
+
+struct pnx0101_pll {
+ unsigned long hpfin;
+ unsigned long hpmdec;
+ unsigned long hpndec;
+ unsigned long hppdec;
+ unsigned long hpmode;
+ unsigned long hpstat;
+ unsigned long hpack;
+ unsigned long hpreq;
+ unsigned long hppad1;
+ unsigned long hppad2;
+ unsigned long hppad3;
+ unsigned long hpselr;
+ unsigned long hpseli;
+ unsigned long hpselp;
+ unsigned long lpfin;
+ unsigned long lppdn;
+ unsigned long lpmbyp;
+ unsigned long lplock;
+ unsigned long lpdbyp;
+ unsigned long lpmsel;
+ unsigned long lppsel;
+};
+
+#define PLL (*(volatile struct pnx0101_pll *)0x80004cac)
+
+struct pnx0101_emc {
+ unsigned long control;
+ unsigned long status;
+};
+
+#define EMC (*(volatile struct pnx0101_emc *)0x80008000)
+
+struct pnx0101_emcstatic {
+ unsigned long config;
+ unsigned long waitwen;
+ unsigned long waitoen;
+ unsigned long waitrd;
+ unsigned long waitpage;
+ unsigned long waitwr;
+ unsigned long waitturn;
+};
+
+#define EMCSTATIC0 (*(volatile struct pnx0101_emcstatic *)0x80008200)
+#define EMCSTATIC1 (*(volatile struct pnx0101_emcstatic *)0x80008220)
+#define EMCSTATIC2 (*(volatile struct pnx0101_emcstatic *)0x80008240)
+
+/* Timers */
+
+struct pnx0101_timer {
+ unsigned long load;
+ unsigned long value;
+ unsigned long ctrl;
+ unsigned long clr;
+};
+
+#define TIMER0 (*(volatile struct pnx0101_timer *)0x80020000)
+#define TIMER1 (*(volatile struct pnx0101_timer *)0x80020400)
+
+/* Interrupt controller */
+
+#define IRQ_TIMER0 5
+#define IRQ_TIMER1 6
+#define IRQ_DMA 28
+
+#define INTPRIOMASK ((volatile unsigned long *)0x80300000)
+#define INTVECTOR ((volatile unsigned long *)0x80300100)
+#define INTPENDING (*(volatile unsigned long *)0x80300200)
+#define INTFEATURES (*(volatile unsigned long *)0x80300300)
+#define INTREQ ((volatile unsigned long *)0x80300400)
+
+#define INTREQ_WEPRIO 0x10000000
+#define INTREQ_WETARGET 0x08000000
+#define INTREQ_WEENABLE 0x04000000
+#define INTREQ_WEACTVLO 0x02000000
+
+#endif /* ASM */
+
#endif
diff --git a/firmware/export/system.h b/firmware/export/system.h
index 32a26a9bf5..184e4fe45a 100644
--- a/firmware/export/system.h
+++ b/firmware/export/system.h
@@ -296,6 +296,12 @@ static inline unsigned long swap32(unsigned long value)
#define CPUFREQ_NORMAL 98784000
#define CPUFREQ_MAX 296352000
+#elif CONFIG_CPU == PNX0101
+
+#define CPUFREQ_DEFAULT 12000000
+#define CPUFREQ_NORMAL 48000000
+#define CPUFREQ_MAX 60000000
+
#else
#define CPUFREQ_DEFAULT_MULT 8
@@ -385,6 +391,7 @@ typedef void (*interrupt_handler_t)(void);
void irq_set_int_handler(int n, interrupt_handler_t handler);
void irq_enable_int(int n);
+void irq_disable_int(int n);
#endif
#endif
diff --git a/firmware/export/timer.h b/firmware/export/timer.h
index f32a8a1790..35994ce5f2 100644
--- a/firmware/export/timer.h
+++ b/firmware/export/timer.h
@@ -32,6 +32,8 @@
#elif defined(CPU_COLDFIRE)
/* timer is based on busclk == cpuclk/2 */
#define TIMER_FREQ (CPU_FREQ/2)
+#elif CONFIG_CPU == PNX0101
+ #define TIMER_FREQ 3000000
#else
#define TIMER_FREQ CPU_FREQ
#endif
diff --git a/firmware/kernel.c b/firmware/kernel.c
index 192728bdb2..c5e47a81ff 100644
--- a/firmware/kernel.c
+++ b/firmware/kernel.c
@@ -594,23 +594,21 @@ void timer_handler(void)
current_tick++;
- TIMERR0C = 1;
+ TIMER0.clr = 0;
}
void tick_start(unsigned int interval_in_ms)
{
- TIMERR08 &= ~0x80;
- TIMERR0C = 1;
- TIMERR08 &= ~0x80;
- TIMERR08 |= 0x40;
- TIMERR00 = 3000000 * interval_in_ms / 1000;
- TIMERR08 &= ~0xc;
- TIMERR0C = 1;
+ TIMER0.ctrl &= ~0x80; /* Disable the counter */
+ TIMER0.ctrl |= 0x40; /* Reload after counting down to zero */
+ TIMER0.load = 3000000 * interval_in_ms / 1000;
+ TIMER0.ctrl &= ~0xc; /* No prescaler */
+ TIMER0.clr = 1; /* Clear the interrupt request */
- irq_set_int_handler(4, timer_handler);
- irq_enable_int(4);
+ irq_set_int_handler(IRQ_TIMER0, timer_handler);
+ irq_enable_int(IRQ_TIMER0);
- TIMERR08 |= 0x80;
+ TIMER0.ctrl |= 0x80; /* Enable the counter */
}
#elif CONFIG_CPU == S3C2440
void tick_start(unsigned int interval_in_ms)
diff --git a/firmware/system.c b/firmware/system.c
index a9c9d9e350..f233376219 100644
--- a/firmware/system.c
+++ b/firmware/system.c
@@ -982,93 +982,6 @@ int system_memory_guard(int newmode)
return 0;
}
-#elif CONFIG_CPU==PNX0101
-
-interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
-
-#define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg)))
-
-static inline unsigned long irq_read(int reg)
-{
- unsigned long v, v2;
- do
- {
- v = IRQ_REG(reg);
- v2 = IRQ_REG(reg);
- } while (v != v2);
- return v;
-}
-
-#define IRQ_WRITE_WAIT(reg, val, cond) \
- do { unsigned long v, v2; \
- do { \
- IRQ_REG(reg) = (val); \
- v = IRQ_REG(reg); \
- v2 = IRQ_REG(reg); \
- } while ((v != v2) || !(cond)); \
- } while (0);
-
-static void undefined_int(void)
-{
-}
-
-void irq(void)
-{
- int n = irq_read(0x100) >> 3;
- (*(interrupt_vector[n]))();
-}
-
-void fiq(void)
-{
-}
-
-void irq_enable_int(int n)
-{
- IRQ_WRITE_WAIT(0x404 + n * 4, 0x4010000, v & 0x10000);
-}
-
-void irq_set_int_handler(int n, interrupt_handler_t handler)
-{
- interrupt_vector[n + 1] = handler;
-}
-
-void system_init(void)
-{
- int i;
-
- /* turn off watchdog */
- (*(volatile unsigned long *)0x80002804) = 0;
-
- /*
- IRQ_WRITE_WAIT(0x100, 0, v == 0);
- IRQ_WRITE_WAIT(0x104, 0, v == 0);
- IRQ_WRITE_WAIT(0, 0, v == 0);
- IRQ_WRITE_WAIT(4, 0, v == 0);
- */
-
- for (i = 0; i < 0x1c; i++)
- {
- IRQ_WRITE_WAIT(0x404 + i * 4, 0x1e000001, (v & 0x3010f) == 1);
- IRQ_WRITE_WAIT(0x404 + i * 4, 0x4000000, (v & 0x10000) == 0);
- IRQ_WRITE_WAIT(0x404 + i * 4, 0x10000001, (v & 0xf) == 1);
- interrupt_vector[i + 1] = undefined_int;
- }
- interrupt_vector[0] = undefined_int;
-}
-
-
-void system_reboot(void)
-{
- (*(volatile unsigned long *)0x80002804) = 1;
- while (1);
-}
-
-int system_memory_guard(int newmode)
-{
- (void)newmode;
- return 0;
-}
-
#endif /* CPU_ARM */
#endif /* CONFIG_CPU */
diff --git a/firmware/target/arm/crt0-pnx0101.S b/firmware/target/arm/crt0-pnx0101.S
new file mode 100644
index 0000000000..d11546edaa
--- /dev/null
+++ b/firmware/target/arm/crt0-pnx0101.S
@@ -0,0 +1,229 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: crt0.S 11850 2006-12-29 02:49:12Z markun $
+ *
+ * Copyright (C) 2002 by Linus Nielsen Feltzing
+ *
+ * All files in this archive are subject to the GNU General Public License.
+ * See the file COPYING in the source tree root for full license agreement.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ****************************************************************************/
+#define ASM /* do not include structure definitions from pnx0101.h */
+
+#include "config.h"
+#include "cpu.h"
+
+ .section .init.text,"ax",%progbits
+
+ .global start
+start:
+
+/* Arm bootloader and startup code based on startup.s from the iPodLinux loader
+ *
+ * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org)
+ * Copyright (c) 2005, Bernard Leach <leachbj@bouncycastle.org>
+ *
+ */
+
+ msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */
+
+#ifndef BOOTLOADER
+#ifndef DEBUG
+ ldr r0, =0x80105000
+ mov r1, #1
+ str r1, [r0, #4]
+ mov r1, #0
+ str r1, [r0, #4]
+1: ldr r1, [r0]
+ cmp r1, #0
+ bne 1b
+ mov r1, #0x74
+ str r1, [r0, #8]
+ mov r1, #2
+ str r1, [r0, #0x18]
+ mov r1, #2
+ str r1, [r0, #0x20]
+ mov r1, #82
+ str r1, [r0, #0x28]
+ mov r1, #100
+ str r1, [r0, #0x2c]
+ mov r1, #0x120
+ str r1, [r0, #0x30]
+ mov r1, #6
+ str r1, [r0, #4]
+ ldr r0, =1f
+ mov r15, r0
+1:
+#endif /* !DEBUG */
+
+#ifndef DEBUG
+ /* Copy exception handler code to address 0 */
+ ldr r2, =_vectorsstart
+ ldr r3, =_vectorsend
+ ldr r4, =_vectorscopy
+1:
+ cmp r3, r2
+ ldrhi r5, [r4], #4
+ strhi r5, [r2], #4
+ bhi 1b
+#else
+ ldr r1, =vectors
+ ldr r0, =irq_handler
+ str r0, [r1, #24]
+ ldr r0, =fiq_handler
+ str r0, [r1, #28]
+#endif
+
+#ifndef STUB
+ /* Zero out IBSS */
+ ldr r2, =_iedata
+ ldr r3, =_iend
+ mov r4, #0
+1:
+ cmp r3, r2
+ strhi r4, [r2], #4
+ bhi 1b
+
+ /* Copy the IRAM */
+ ldr r2, =_iramcopy
+ ldr r3, =_iramstart
+ ldr r4, =_iramend
+1:
+ cmp r4, r3
+ ldrhi r5, [r2], #4
+ strhi r5, [r3], #4
+ bhi 1b
+#endif /* !STUB */
+#endif /* !BOOTLOADER */
+
+ /* Initialise bss section to zero */
+ ldr r2, =_edata
+ ldr r3, =_end
+ mov r4, #0
+1:
+ cmp r3, r2
+ strhi r4, [r2], #4
+ bhi 1b
+
+ /* Set up some stack and munge it with 0xdeadbeef */
+ ldr sp, =stackend
+ mov r3, sp
+ ldr r2, =stackbegin
+ ldr r4, =0xdeadbeef
+1:
+ cmp r3, r2
+ strhi r4, [r2], #4
+ bhi 1b
+
+ /* Set up stack for IRQ mode */
+ msr cpsr_c, #0xd2
+ ldr sp, =irq_stack
+ /* Set up stack for FIQ mode */
+ msr cpsr_c, #0xd1
+ ldr sp, =fiq_stack
+
+ /* Let abort and undefined modes use IRQ stack */
+ msr cpsr_c, #0xd7
+ ldr sp, =irq_stack
+ msr cpsr_c, #0xdb
+ ldr sp, =irq_stack
+ /* Switch to supervisor mode */
+ msr cpsr_c, #0xd3
+ ldr sp, =stackend
+ bl main
+ /* main() should never return */
+
+/* Exception handlers. Will be copied to address 0 after memory remapping */
+ .section .vectors,"aw"
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+ ldr pc, [pc, #24]
+
+ /* Exception vectors */
+ .global vectors
+vectors:
+ .word start
+ .word undef_instr_handler
+ .word software_int_handler
+ .word prefetch_abort_handler
+ .word data_abort_handler
+ .word reserved_handler
+ .word irq_handler
+ .word fiq_handler
+
+ .text
+
+#ifndef STUB
+ .global irq
+ .global fiq
+ .global UIE
+#endif
+
+/* 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:
+ mov r0, lr
+ 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
+
+fiq_handler:
+ @ Branch straight to FIQ handler in pcm_playback.c. This also handles the
+ @ the correct return sequence.
+ stmfd sp!, {r0-r7, r12, lr}
+ bl fiq
+ ldmfd sp!, {r0-r7, r12, lr}
+ subs pc, lr, #4
+
+data_abort_handler:
+ sub r0, lr, #8
+ mov r1, #2
+ b UIE
+
+irq_handler:
+#ifndef STUB
+ stmfd sp!, {r0-r11, r12, lr}
+ bl irq
+ ldmfd sp!, {r0-r11, r12, lr}
+#endif
+ subs pc, lr, #4
+
+#ifdef STUB
+UIE:
+ b UIE
+#endif
+
+/* 256 words of IRQ stack */
+ .space 256*4
+irq_stack:
+
+/* 256 words of FIQ stack */
+ .space 256*4
+fiq_stack:
diff --git a/firmware/target/arm/crt0.S b/firmware/target/arm/crt0.S
index c552e44320..581a997477 100644
--- a/firmware/target/arm/crt0.S
+++ b/firmware/target/arm/crt0.S
@@ -34,30 +34,6 @@ start:
msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */
#ifndef BOOTLOADER
-#if CONFIG_CPU == PNX0101
-
-#ifndef DEBUG
- ldr r0, =0x80105000
- mov r1, #1
- str r1, [r0, #4]
- mov r1, #0
- str r1, [r0, #4]
-1: ldr r1, [r0]
- cmp r1, #0
- bne 1b
- mov r1, #0x74
- str r1, [r0, #8]
- mov r1, #2
- str r1, [r0, #0x18]
- mov r1, #0x120
- str r1, [r0, #0x30]
- mov r1, #6
- str r1, [r0, #4]
- ldr r0, =1f
- mov r15, r0
-1:
-#endif /* !DEBUG */
-#endif /* chipset specific */
#ifndef DEBUG
/* Copy exception handler code to address 0 */
diff --git a/firmware/target/arm/system-pnx0101.c b/firmware/target/arm/system-pnx0101.c
new file mode 100644
index 0000000000..9d8bb405a8
--- /dev/null
+++ b/firmware/target/arm/system-pnx0101.c
@@ -0,0 +1,351 @@
+/***************************************************************************
+ * __________ __ ___.
+ * Open \______ \ ____ ____ | | _\_ |__ _______ ___
+ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
+ * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
+ * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
+ * \/ \/ \/ \/ \/
+ * $Id: $
+ *
+ * Copyright (C) 2007 by Tomasz Malesinski
+ *
+ * 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 <stdlib.h>
+#include "pnx0101.h"
+#include "system.h"
+
+static struct
+{
+ unsigned char freq;
+ unsigned char sys_mult;
+ unsigned char sys_div;
+ unsigned char mem_conf[9];
+}
+perf_modes[3] ICONST_ATTR =
+{
+ {12, 4, 4, {2, 1, 1, 1, 1, 1, 1, 1, 1, 0}},
+ {48, 4, 1, {5, 4, 1, 4, 4, 1, 3, 3, 1, 0}},
+ {60, 5, 1, {6, 5, 1, 5, 5, 1, 4, 3, 1, 1}}
+};
+
+static int performance_mode, bus_divider;
+
+static void cgu_set_sel_stage_input(int clock, int input)
+{
+ int s = CGU.base_ssr[clock];
+ if (s & 1)
+ CGU.base_fs2[clock] = input;
+ else
+ CGU.base_fs1[clock] = input;
+ CGU.base_scr[clock] = (s & 3) ^ 3;
+}
+
+static void cgu_reset_sel_stage_clocks(int first_esr, int n_esr,
+ int first_div, int n_div)
+{
+ int i;
+ for (i = 0; i < n_esr; i++)
+ CGU.clk_esr[first_esr + i] = 0;
+ for (i = 0; i < n_div; i++)
+ CGU.base_fdc[first_div + i] = 0;
+}
+
+static void cgu_configure_div(int div, int n, int m)
+{
+ int msub, madd, div_size, max_n;
+ unsigned long cfg;
+
+ if (n == m)
+ {
+ CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
+ return;
+ }
+
+ msub = -n;
+ madd = m - n;
+ div_size = (div == PNX0101_HIPREC_FDC) ? 10 : 8;
+ max_n = 1 << div_size;
+ while ((madd << 1) < max_n && (msub << 1) >= -max_n)
+ {
+ madd <<= 1;
+ msub <<= 1;
+ }
+ cfg = (((msub << div_size) | madd) << 3) | 4;
+ CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
+ CGU.base_fdc[div] = cfg | 2;
+ CGU.base_fdc[div] = cfg;
+ CGU.base_fdc[div] = cfg | 1;
+}
+
+static void cgu_connect_div_to_clock(int rel_div, int esr)
+{
+ CGU.clk_esr[esr] = (rel_div << 1) | 1;
+}
+
+static void cgu_disconnect_div_from_clock(int esr)
+{
+ CGU.clk_esr[esr] = 0;
+}
+
+static void cgu_enable_clock(int clock)
+{
+ CGU.clk_pcr[clock] |= 1;
+}
+
+static void cgu_start_sel_stage_dividers(int bcr)
+{
+ CGU.base_bcr[bcr] = 1;
+}
+
+/* Convert a pointer that points to IRAM (0x4xxxx) to a pointer that
+ points to the uncached page (0x0xxxx) that is also mapped to IRAM. */
+static inline void *noncached(void *p) {
+ return (void *)(((unsigned long)p) & 0xffff);
+}
+
+/* TODO: if it works, then comment it */
+static void do_set_mem_timings(int mode) ICODE_ATTR;
+static void do_set_mem_timings(int mode)
+{
+ unsigned char *mem_conf = noncached(perf_modes[mode].mem_conf);
+ int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
+ while ((EMC.status & 3) != 0);
+ EMC.control = 5;
+ EMCSTATIC0.waitrd = mem_conf[0];
+ EMCSTATIC0.waitwr = mem_conf[1];
+ EMCSTATIC1.waitrd = mem_conf[3];
+ EMCSTATIC1.waitwr = mem_conf[4];
+ EMCSTATIC2.waitrd = mem_conf[6];
+ EMCSTATIC2.waitwr = mem_conf[7];
+ EMCSTATIC0.waitoen = mem_conf[2];
+ EMCSTATIC1.waitoen = mem_conf[5];
+ EMCSTATIC2.waitoen = mem_conf[8];
+#ifndef DEBUG
+ EMCSTATIC1.config = mem_conf[9] ? 0x80081 : 0x81;
+#endif
+ EMC.control = 1;
+ set_irq_level(old_irq);
+}
+
+static void emc_set_mem_timings(int mode) {
+ void (*f)(int) = noncached(do_set_mem_timings);
+ (*f)(mode);
+}
+
+/*
+static void do_enable_write_buffers(int on) ICODE_ATTR;
+static void do_enable_write_buffers(int on) {
+ int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
+ while ((EMC.status & 3) != 0);
+ EMC.control = 5;
+ EMCSTATIC1.config = on ? 0x80081 : 0x81;
+ EMC.control = 1;
+ set_irq_level(old_irq);
+}
+
+void emc_enable_write_buffers(int on) {
+ void (*f)(int) = noncached(do_enable_write_buffers);
+ (*f)(on);
+}
+*/
+
+/* can it be replaced? */
+static void cgu_busy_wait(int n)
+{
+ while (n > 0)
+ {
+ n--;
+ }
+}
+
+static void cgu_set_sys_mult(int i)
+{
+ cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS, PNX0101_MAIN_CLOCK_FAST);
+ cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3, PNX0101_MAIN_CLOCK_FAST);
+
+ PLL.lppdn = 1;
+ PLL.lpfin = 1;
+ PLL.lpmbyp = 0;
+ PLL.lpdbyp = 0;
+ PLL.lppsel = 1;
+ PLL.lpmsel = i - 1;
+ PLL.lppdn = 0;
+ while (!PLL.lplock);
+
+ cgu_configure_div(PNX0101_FIRST_DIV_SYS + 1, 1, (i == 5) ? 15 : 12);
+ cgu_connect_div_to_clock(1, 0x11);
+ cgu_enable_clock(0x11);
+ cgu_start_sel_stage_dividers(PNX0101_BCR_SYS);
+
+ cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS,
+ PNX0101_MAIN_CLOCK_MAIN_PLL);
+ cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3,
+ PNX0101_MAIN_CLOCK_MAIN_PLL);
+}
+
+static void pnx0101_set_performance_mode(int mode)
+{
+ int old = performance_mode;
+ if (perf_modes[old].freq < perf_modes[mode].freq)
+ {
+ emc_set_mem_timings(mode);
+ if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult)
+ cgu_set_sys_mult(perf_modes[mode].sys_mult);
+ if (perf_modes[old].sys_div != perf_modes[mode].sys_div)
+ cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div);
+ }
+ else if (perf_modes[old].freq > perf_modes[mode].freq)
+ {
+ if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult)
+ cgu_set_sys_mult(perf_modes[mode].sys_mult);
+ if (perf_modes[old].sys_div != perf_modes[mode].sys_div)
+ cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div);
+ emc_set_mem_timings(mode);
+ }
+ performance_mode = mode;
+}
+
+static void pnx0101_init_clocks(void)
+{
+ bus_divider = PNX0101_FIRST_DIV_SYS + (CGU.clk_esr[0] >> 1);
+ performance_mode = 0;
+ pnx0101_set_performance_mode(2);
+/*
+#ifndef DEBUG
+ emc_enable_write_buffers(1);
+#endif
+*/
+ cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB1,
+ PNX0101_MAIN_CLOCK_FAST);
+ cgu_reset_sel_stage_clocks(PNX0101_FIRST_ESR_APB1, PNX0101_N_ESR_APB1,
+ PNX0101_FIRST_DIV_APB1, PNX0101_N_DIV_APB1);
+ cgu_configure_div(PNX0101_FIRST_DIV_APB1, 1, 4);
+ cgu_connect_div_to_clock(0, PNX0101_ESR_APB1);
+ cgu_connect_div_to_clock(0, PNX0101_ESR_T0);
+ cgu_connect_div_to_clock(0, PNX0101_ESR_T1);
+ cgu_connect_div_to_clock(0, PNX0101_ESR_I2C);
+ cgu_enable_clock(PNX0101_CLOCK_APB1);
+ cgu_enable_clock(PNX0101_CLOCK_T0);
+ cgu_enable_clock(PNX0101_CLOCK_T1);
+ cgu_enable_clock(PNX0101_CLOCK_I2C);
+}
+
+#ifdef HAVE_ADJUSTABLE_CPU_FREQ
+void set_cpu_frequency(long frequency)
+{
+ switch (frequency)
+ {
+ case CPUFREQ_MAX:
+ pnx0101_set_performance_mode(2);
+ cpu_frequency = CPUFREQ_MAX;
+ break;
+ case CPUFREQ_NORMAL:
+ pnx0101_set_performance_mode(1);
+ cpu_frequency = CPUFREQ_NORMAL;
+ break;
+ case CPUFREQ_DEFAULT:
+ default:
+ pnx0101_set_performance_mode(0);
+ cpu_frequency = CPUFREQ_DEFAULT;
+ break;
+ }
+
+}
+#endif
+
+interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
+
+#define IRQ_READ(reg, dest) \
+ do { unsigned long v2; \
+ do { \
+ dest = (reg); \
+ v2 = (reg); \
+ } while ((dest != v2)); \
+ } while (0);
+
+#define IRQ_WRITE_WAIT(reg, val, cond) \
+ do { unsigned long v, v2; \
+ do { \
+ (reg) = (val); \
+ v = (reg); \
+ v2 = (reg); \
+ } while ((v != v2) || !(cond)); \
+ } while (0);
+
+static void undefined_int(void)
+{
+}
+
+void irq(void)
+{
+ int n;
+ IRQ_READ(INTVECTOR[0], n)
+ (*(interrupt_vector[n >> 3]))();
+}
+
+void fiq(void)
+{
+}
+
+void irq_enable_int(int n)
+{
+ IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE | INTREQ_ENABLE, v & 0x10000);
+}
+
+void irq_disable_int(int n)
+{
+ IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE, (v & 0x10000) == 0);
+}
+
+void irq_set_int_handler(int n, interrupt_handler_t handler)
+{
+ interrupt_vector[n] = handler;
+}
+
+void system_init(void)
+{
+ int i;
+
+ /* turn off watchdog */
+ (*(volatile unsigned long *)0x80002804) = 0;
+
+ /*
+ IRQ_WRITE_WAIT(INTVECTOR[0], 0, v == 0);
+ IRQ_WRITE_WAIT(INTVECTOR[1], 0, v == 0);
+ IRQ_WRITE_WAIT(INTPRIOMASK[0], 0, v == 0);
+ IRQ_WRITE_WAIT(INTPRIOMASK[1], 0, v == 0);
+ */
+
+ for (i = 0; i < 0x1c; i++)
+ {
+ IRQ_WRITE_WAIT(INTREQ[i],
+ INTREQ_WEPRIO | INTREQ_WETARGET |
+ INTREQ_WEENABLE | INTREQ_WEACTVLO | 1,
+ (v & 0x3010f) == 1);
+ IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEENABLE, (v & 0x10000) == 0);
+ IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEPRIO | 1, (v & 0xf) == 1);
+ interrupt_vector[i + 1] = undefined_int;
+ }
+ interrupt_vector[0] = undefined_int;
+ pnx0101_init_clocks();
+}
+
+
+void system_reboot(void)
+{
+ (*(volatile unsigned long *)0x80002804) = 1;
+ while (1);
+}
+
+int system_memory_guard(int newmode)
+{
+ (void)newmode;
+ return 0;
+}
diff --git a/firmware/timer.c b/firmware/timer.c
index 849e4ba598..ca23cb890c 100644
--- a/firmware/timer.c
+++ b/firmware/timer.c
@@ -28,7 +28,7 @@ static void (*pfn_timer)(void) = NULL; /* timer callback */
static void (*pfn_unregister)(void) = NULL; /* unregister callback */
#ifdef CPU_COLDFIRE
static int base_prescale;
-#elif defined CPU_PP
+#elif defined CPU_PP || CONFIG_CPU == PNX0101
static long cycles_new = 0;
#endif
@@ -67,6 +67,24 @@ void TIMER2(void)
cycles_new = 0;
}
}
+#elif CONFIG_CPU == PNX0101
+void TIMER1_ISR(void)
+{
+ if (cycles_new > 0)
+ {
+ TIMER1.load = cycles_new - 1;
+ cycles_new = 0;
+ }
+ if (pfn_timer != NULL)
+ {
+ cycles_new = -1;
+ /* "lock" the variable, in case timer_set_period()
+ * is called within pfn_timer() */
+ pfn_timer();
+ cycles_new = 0;
+ }
+ TIMER1.clr = 1; /* clear the interrupt */
+}
#endif /* CONFIG_CPU */
static bool timer_set(long cycles, bool start)
@@ -85,8 +103,26 @@ static bool timer_set(long cycles, bool start)
}
#endif
-#if CONFIG_CPU == PNX0101 /* TODO: Implement for iFP */
- (void)start;
+#if CONFIG_CPU == PNX0101
+ if (start)
+ {
+ if (pfn_unregister != NULL)
+ {
+ pfn_unregister();
+ pfn_unregister = NULL;
+ }
+ TIMER1.ctrl &= ~0x80; /* disable the counter */
+ TIMER1.ctrl |= 0x40; /* reload after counting down to zero */
+ TIMER1.ctrl &= ~0xc; /* no prescaler */
+ TIMER1.clr = 1; /* clear an interrupt event */
+ }
+ if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
+ { /* enable timer */
+ TIMER1.load = cycles - 1;
+ TIMER1.ctrl |= 0x80; /* enable the counter */
+ }
+ else
+ cycles_new = cycles;
#endif
#if CONFIG_CPU == SH7034
@@ -229,6 +265,9 @@ bool timer_register(int reg_prio, void (*unregister_callback)(void),
#elif defined(CPU_PP)
/* unmask interrupt source */
CPU_INT_EN = TIMER2_MASK;
+#elif CONFIG_CPU == PNX0101
+ irq_set_int_handler(IRQ_TIMER1, TIMER1_ISR);
+ irq_enable_int(IRQ_TIMER1);
#endif
return true;
}
@@ -249,6 +288,9 @@ void timer_unregister(void)
#elif defined(CPU_PP)
TIMER2_CFG = 0; /* stop timer 2 */
CPU_INT_CLR = TIMER2_MASK;
+#elif CONFIG_CPU == PNX0101
+ TIMER1.ctrl &= ~0x80; /* disable timer 1 */
+ irq_disable_int(5);
#endif
pfn_timer = NULL;
pfn_unregister = NULL;