summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Malesinski <tomal@rockbox.org>2007-03-24 19:26:13 +0000
committerTomasz Malesinski <tomal@rockbox.org>2007-03-24 19:26:13 +0000
commitcd630c9e0a2e0aa259a6e53a5af1369f36984b1c (patch)
tree84bff67d18b47884f1a777eabfb7ba3de7d35c14
parent7d9ff93b79ef66333669e01d67c7b1736370a346 (diff)
downloadrockbox-cd630c9e0a2e0aa259a6e53a5af1369f36984b1c.tar.gz
rockbox-cd630c9e0a2e0aa259a6e53a5af1369f36984b1c.zip
PNX0101 changes:
Make PNX0101-specific system.c and crt0.S. Add new register names from LPC2880 user manual. Add support for timer. Enable CPU frequency changing. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@12904 a1c6a512-1295-4272-9138-f99709370657
-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
278#elif CONFIG_I2C == I2C_S3C2440 278#elif CONFIG_I2C == I2C_S3C2440
279/* no i2c driver yet */ 279/* no i2c driver yet */
280#endif 280#endif
281#if CONFIG_CPU == PNX0101
282target/arm/system-pnx0101.c
283#endif
281#if defined(CPU_PP) 284#if defined(CPU_PP)
282#ifdef BOOTLOADER 285#ifdef BOOTLOADER
283target/arm/crt0-pp-bl.S 286target/arm/crt0-pp-bl.S
@@ -286,6 +289,8 @@ target/arm/pcm-pp.c
286target/arm/audio-pp.c 289target/arm/audio-pp.c
287target/arm/crt0-pp.S 290target/arm/crt0-pp.S
288#endif 291#endif
292#elif CONFIG_CPU == PNX0101
293target/arm/crt0-pnx0101.S
289#elif defined(CPU_ARM) 294#elif defined(CPU_ARM)
290target/arm/crt0.S 295target/arm/crt0.S
291#endif /* defined(CPU_*) */ 296#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)
9OUTPUT_ARCH(arm) 9OUTPUT_ARCH(arm)
10#ifdef CPU_PP 10#ifdef CPU_PP
11INPUT(target/arm/crt0-pp.o) 11INPUT(target/arm/crt0-pp.o)
12#elif CONFIG_CPU == PNX0101
13INPUT(target/arm/crt0-pnx0101.o)
12#elif defined(CPU_ARM) 14#elif defined(CPU_ARM)
13INPUT(target/arm/crt0.o) 15INPUT(target/arm/crt0.o)
14#endif 16#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 @@
80#define CONFIG_BACKLIGHT BL_IRIVER_IFP7XX /* port controlled */ 80#define CONFIG_BACKLIGHT BL_IRIVER_IFP7XX /* port controlled */
81 81
82/* Define this to the CPU frequency */ 82/* Define this to the CPU frequency */
83#define CPU_FREQ 30000000 83#define CPU_FREQ 48000000
84 84
85#define CONFIG_LCD LCD_IFP7XX 85#define CONFIG_LCD LCD_IFP7XX
86 86
@@ -98,7 +98,7 @@
98#define HAVE_GDB_API 98#define HAVE_GDB_API
99 99
100/* Define this if you have adjustable CPU frequency */ 100/* Define this if you have adjustable CPU frequency */
101//#define HAVE_ADJUSTABLE_CPU_FREQ 101#define HAVE_ADJUSTABLE_CPU_FREQ
102 102
103#define BOOTFILE_EXT "iriver" 103#define BOOTFILE_EXT "iriver"
104#define BOOTFILE "rockbox." BOOTFILE_EXT 104#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 @@
78 78
79#define CODECVOL (*(volatile unsigned long *)0x80200398) 79#define CODECVOL (*(volatile unsigned long *)0x80200398)
80 80
81#ifndef ASM
82
83/* Clock generation unit */
84
85struct pnx0101_cgu {
86 unsigned long base_scr[12];
87 unsigned long base_fs1[12];
88 unsigned long base_fs2[12];
89 unsigned long base_ssr[12];
90 unsigned long clk_pcr[73];
91 unsigned long clk_psr[73];
92 unsigned long clk_esr[67];
93 unsigned long base_bcr[3];
94 unsigned long base_fdc[18];
95};
96
97#define CGU (*(volatile struct pnx0101_cgu *)0x80004000)
98
99#define PNX0101_SEL_STAGE_SYS 0
100#define PNX0101_SEL_STAGE_APB0 1
101#define PNX0101_SEL_STAGE_APB1 2
102#define PNX0101_SEL_STAGE_APB3 3
103#define PNX0101_SEL_STAGE_DAIO 9
104
105#define PNX0101_HIPREC_FDC 16
106
107#define PNX0101_FIRST_DIV_SYS 0
108#define PNX0101_N_DIV_SYS 7
109#define PNX0101_FIRST_DIV_APB0 7
110#define PNX0101_N_DIV_APB0 2
111#define PNX0101_FIRST_DIV_APB1 9
112#define PNX0101_N_DIV_APB1 1
113#define PNX0101_FIRST_DIV_APB3 10
114#define PNX0101_N_DIV_APB3 1
115#define PNX0101_FIRST_DIV_DAIO 12
116#define PNX0101_N_DIV_DAIO 6
117
118#define PNX0101_BCR_SYS 0
119#define PNX0101_BCR_APB0 1
120#define PNX0101_BCR_DAIO 2
121
122#define PNX0101_FIRST_ESR_SYS 0
123#define PNX0101_N_ESR_SYS 28
124#define PNX0101_FIRST_ESR_APB0 28
125#define PNX0101_N_ESR_APB0 9
126#define PNX0101_FIRST_ESR_APB1 37
127#define PNX0101_N_ESR_APB1 4
128#define PNX0101_FIRST_ESR_APB3 41
129#define PNX0101_N_ESR_APB3 16
130#define PNX0101_FIRST_ESR_DAIO 58
131#define PNX0101_N_ESR_DAIO 9
132
133#define PNX0101_ESR_APB1 0x25
134#define PNX0101_ESR_T0 0x26
135#define PNX0101_ESR_T1 0x27
136#define PNX0101_ESR_I2C 0x28
137
138#define PNX0101_CLOCK_APB1 0x25
139#define PNX0101_CLOCK_T0 0x26
140#define PNX0101_CLOCK_T1 0x27
141#define PNX0101_CLOCK_I2C 0x28
142
143#define PNX0101_MAIN_CLOCK_FAST 1
144#define PNX0101_MAIN_CLOCK_MAIN_PLL 9
145
146struct pnx0101_pll {
147 unsigned long hpfin;
148 unsigned long hpmdec;
149 unsigned long hpndec;
150 unsigned long hppdec;
151 unsigned long hpmode;
152 unsigned long hpstat;
153 unsigned long hpack;
154 unsigned long hpreq;
155 unsigned long hppad1;
156 unsigned long hppad2;
157 unsigned long hppad3;
158 unsigned long hpselr;
159 unsigned long hpseli;
160 unsigned long hpselp;
161 unsigned long lpfin;
162 unsigned long lppdn;
163 unsigned long lpmbyp;
164 unsigned long lplock;
165 unsigned long lpdbyp;
166 unsigned long lpmsel;
167 unsigned long lppsel;
168};
169
170#define PLL (*(volatile struct pnx0101_pll *)0x80004cac)
171
172struct pnx0101_emc {
173 unsigned long control;
174 unsigned long status;
175};
176
177#define EMC (*(volatile struct pnx0101_emc *)0x80008000)
178
179struct pnx0101_emcstatic {
180 unsigned long config;
181 unsigned long waitwen;
182 unsigned long waitoen;
183 unsigned long waitrd;
184 unsigned long waitpage;
185 unsigned long waitwr;
186 unsigned long waitturn;
187};
188
189#define EMCSTATIC0 (*(volatile struct pnx0101_emcstatic *)0x80008200)
190#define EMCSTATIC1 (*(volatile struct pnx0101_emcstatic *)0x80008220)
191#define EMCSTATIC2 (*(volatile struct pnx0101_emcstatic *)0x80008240)
192
193/* Timers */
194
195struct pnx0101_timer {
196 unsigned long load;
197 unsigned long value;
198 unsigned long ctrl;
199 unsigned long clr;
200};
201
202#define TIMER0 (*(volatile struct pnx0101_timer *)0x80020000)
203#define TIMER1 (*(volatile struct pnx0101_timer *)0x80020400)
204
205/* Interrupt controller */
206
207#define IRQ_TIMER0 5
208#define IRQ_TIMER1 6
209#define IRQ_DMA 28
210
211#define INTPRIOMASK ((volatile unsigned long *)0x80300000)
212#define INTVECTOR ((volatile unsigned long *)0x80300100)
213#define INTPENDING (*(volatile unsigned long *)0x80300200)
214#define INTFEATURES (*(volatile unsigned long *)0x80300300)
215#define INTREQ ((volatile unsigned long *)0x80300400)
216
217#define INTREQ_WEPRIO 0x10000000
218#define INTREQ_WETARGET 0x08000000
219#define INTREQ_WEENABLE 0x04000000
220#define INTREQ_WEACTVLO 0x02000000
221
222#endif /* ASM */
223
81#endif 224#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)
296#define CPUFREQ_NORMAL 98784000 296#define CPUFREQ_NORMAL 98784000
297#define CPUFREQ_MAX 296352000 297#define CPUFREQ_MAX 296352000
298 298
299#elif CONFIG_CPU == PNX0101
300
301#define CPUFREQ_DEFAULT 12000000
302#define CPUFREQ_NORMAL 48000000
303#define CPUFREQ_MAX 60000000
304
299#else 305#else
300 306
301#define CPUFREQ_DEFAULT_MULT 8 307#define CPUFREQ_DEFAULT_MULT 8
@@ -385,6 +391,7 @@ typedef void (*interrupt_handler_t)(void);
385 391
386void irq_set_int_handler(int n, interrupt_handler_t handler); 392void irq_set_int_handler(int n, interrupt_handler_t handler);
387void irq_enable_int(int n); 393void irq_enable_int(int n);
394void irq_disable_int(int n);
388#endif 395#endif
389 396
390#endif 397#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 @@
32#elif defined(CPU_COLDFIRE) 32#elif defined(CPU_COLDFIRE)
33 /* timer is based on busclk == cpuclk/2 */ 33 /* timer is based on busclk == cpuclk/2 */
34 #define TIMER_FREQ (CPU_FREQ/2) 34 #define TIMER_FREQ (CPU_FREQ/2)
35#elif CONFIG_CPU == PNX0101
36 #define TIMER_FREQ 3000000
35#else 37#else
36 #define TIMER_FREQ CPU_FREQ 38 #define TIMER_FREQ CPU_FREQ
37#endif 39#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)
594 594
595 current_tick++; 595 current_tick++;
596 596
597 TIMERR0C = 1; 597 TIMER0.clr = 0;
598} 598}
599 599
600void tick_start(unsigned int interval_in_ms) 600void tick_start(unsigned int interval_in_ms)
601{ 601{
602 TIMERR08 &= ~0x80; 602 TIMER0.ctrl &= ~0x80; /* Disable the counter */
603 TIMERR0C = 1; 603 TIMER0.ctrl |= 0x40; /* Reload after counting down to zero */
604 TIMERR08 &= ~0x80; 604 TIMER0.load = 3000000 * interval_in_ms / 1000;
605 TIMERR08 |= 0x40; 605 TIMER0.ctrl &= ~0xc; /* No prescaler */
606 TIMERR00 = 3000000 * interval_in_ms / 1000; 606 TIMER0.clr = 1; /* Clear the interrupt request */
607 TIMERR08 &= ~0xc;
608 TIMERR0C = 1;
609 607
610 irq_set_int_handler(4, timer_handler); 608 irq_set_int_handler(IRQ_TIMER0, timer_handler);
611 irq_enable_int(4); 609 irq_enable_int(IRQ_TIMER0);
612 610
613 TIMERR08 |= 0x80; 611 TIMER0.ctrl |= 0x80; /* Enable the counter */
614} 612}
615#elif CONFIG_CPU == S3C2440 613#elif CONFIG_CPU == S3C2440
616void tick_start(unsigned int interval_in_ms) 614void 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)
982 return 0; 982 return 0;
983} 983}
984 984
985#elif CONFIG_CPU==PNX0101
986
987interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
988
989#define IRQ_REG(reg) (*(volatile unsigned long *)(0x80300000 + (reg)))
990
991static inline unsigned long irq_read(int reg)
992{
993 unsigned long v, v2;
994 do
995 {
996 v = IRQ_REG(reg);
997 v2 = IRQ_REG(reg);
998 } while (v != v2);
999 return v;
1000}
1001
1002#define IRQ_WRITE_WAIT(reg, val, cond) \
1003 do { unsigned long v, v2; \
1004 do { \
1005 IRQ_REG(reg) = (val); \
1006 v = IRQ_REG(reg); \
1007 v2 = IRQ_REG(reg); \
1008 } while ((v != v2) || !(cond)); \
1009 } while (0);
1010
1011static void undefined_int(void)
1012{
1013}
1014
1015void irq(void)
1016{
1017 int n = irq_read(0x100) >> 3;
1018 (*(interrupt_vector[n]))();
1019}
1020
1021void fiq(void)
1022{
1023}
1024
1025void irq_enable_int(int n)
1026{
1027 IRQ_WRITE_WAIT(0x404 + n * 4, 0x4010000, v & 0x10000);
1028}
1029
1030void irq_set_int_handler(int n, interrupt_handler_t handler)
1031{
1032 interrupt_vector[n + 1] = handler;
1033}
1034
1035void system_init(void)
1036{
1037 int i;
1038
1039 /* turn off watchdog */
1040 (*(volatile unsigned long *)0x80002804) = 0;
1041
1042 /*
1043 IRQ_WRITE_WAIT(0x100, 0, v == 0);
1044 IRQ_WRITE_WAIT(0x104, 0, v == 0);
1045 IRQ_WRITE_WAIT(0, 0, v == 0);
1046 IRQ_WRITE_WAIT(4, 0, v == 0);
1047 */
1048
1049 for (i = 0; i < 0x1c; i++)
1050 {
1051 IRQ_WRITE_WAIT(0x404 + i * 4, 0x1e000001, (v & 0x3010f) == 1);
1052 IRQ_WRITE_WAIT(0x404 + i * 4, 0x4000000, (v & 0x10000) == 0);
1053 IRQ_WRITE_WAIT(0x404 + i * 4, 0x10000001, (v & 0xf) == 1);
1054 interrupt_vector[i + 1] = undefined_int;
1055 }
1056 interrupt_vector[0] = undefined_int;
1057}
1058
1059
1060void system_reboot(void)
1061{
1062 (*(volatile unsigned long *)0x80002804) = 1;
1063 while (1);
1064}
1065
1066int system_memory_guard(int newmode)
1067{
1068 (void)newmode;
1069 return 0;
1070}
1071
1072#endif /* CPU_ARM */ 985#endif /* CPU_ARM */
1073#endif /* CONFIG_CPU */ 986#endif /* CONFIG_CPU */
1074 987
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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: crt0.S 11850 2006-12-29 02:49:12Z markun $
9 *
10 * Copyright (C) 2002 by Linus Nielsen Feltzing
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19#define ASM /* do not include structure definitions from pnx0101.h */
20
21#include "config.h"
22#include "cpu.h"
23
24 .section .init.text,"ax",%progbits
25
26 .global start
27start:
28
29/* Arm bootloader and startup code based on startup.s from the iPodLinux loader
30 *
31 * Copyright (c) 2003, Daniel Palffy (dpalffy (at) rainstorm.org)
32 * Copyright (c) 2005, Bernard Leach <leachbj@bouncycastle.org>
33 *
34 */
35
36 msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */
37
38#ifndef BOOTLOADER
39#ifndef DEBUG
40 ldr r0, =0x80105000
41 mov r1, #1
42 str r1, [r0, #4]
43 mov r1, #0
44 str r1, [r0, #4]
451: ldr r1, [r0]
46 cmp r1, #0
47 bne 1b
48 mov r1, #0x74
49 str r1, [r0, #8]
50 mov r1, #2
51 str r1, [r0, #0x18]
52 mov r1, #2
53 str r1, [r0, #0x20]
54 mov r1, #82
55 str r1, [r0, #0x28]
56 mov r1, #100
57 str r1, [r0, #0x2c]
58 mov r1, #0x120
59 str r1, [r0, #0x30]
60 mov r1, #6
61 str r1, [r0, #4]
62 ldr r0, =1f
63 mov r15, r0
641:
65#endif /* !DEBUG */
66
67#ifndef DEBUG
68 /* Copy exception handler code to address 0 */
69 ldr r2, =_vectorsstart
70 ldr r3, =_vectorsend
71 ldr r4, =_vectorscopy
721:
73 cmp r3, r2
74 ldrhi r5, [r4], #4
75 strhi r5, [r2], #4
76 bhi 1b
77#else
78 ldr r1, =vectors
79 ldr r0, =irq_handler
80 str r0, [r1, #24]
81 ldr r0, =fiq_handler
82 str r0, [r1, #28]
83#endif
84
85#ifndef STUB
86 /* Zero out IBSS */
87 ldr r2, =_iedata
88 ldr r3, =_iend
89 mov r4, #0
901:
91 cmp r3, r2
92 strhi r4, [r2], #4
93 bhi 1b
94
95 /* Copy the IRAM */
96 ldr r2, =_iramcopy
97 ldr r3, =_iramstart
98 ldr r4, =_iramend
991:
100 cmp r4, r3
101 ldrhi r5, [r2], #4
102 strhi r5, [r3], #4
103 bhi 1b
104#endif /* !STUB */
105#endif /* !BOOTLOADER */
106
107 /* Initialise bss section to zero */
108 ldr r2, =_edata
109 ldr r3, =_end
110 mov r4, #0
1111:
112 cmp r3, r2
113 strhi r4, [r2], #4
114 bhi 1b
115
116 /* Set up some stack and munge it with 0xdeadbeef */
117 ldr sp, =stackend
118 mov r3, sp
119 ldr r2, =stackbegin
120 ldr r4, =0xdeadbeef
1211:
122 cmp r3, r2
123 strhi r4, [r2], #4
124 bhi 1b
125
126 /* Set up stack for IRQ mode */
127 msr cpsr_c, #0xd2
128 ldr sp, =irq_stack
129 /* Set up stack for FIQ mode */
130 msr cpsr_c, #0xd1
131 ldr sp, =fiq_stack
132
133 /* Let abort and undefined modes use IRQ stack */
134 msr cpsr_c, #0xd7
135 ldr sp, =irq_stack
136 msr cpsr_c, #0xdb
137 ldr sp, =irq_stack
138 /* Switch to supervisor mode */
139 msr cpsr_c, #0xd3
140 ldr sp, =stackend
141 bl main
142 /* main() should never return */
143
144/* Exception handlers. Will be copied to address 0 after memory remapping */
145 .section .vectors,"aw"
146 ldr pc, [pc, #24]
147 ldr pc, [pc, #24]
148 ldr pc, [pc, #24]
149 ldr pc, [pc, #24]
150 ldr pc, [pc, #24]
151 ldr pc, [pc, #24]
152 ldr pc, [pc, #24]
153 ldr pc, [pc, #24]
154
155 /* Exception vectors */
156 .global vectors
157vectors:
158 .word start
159 .word undef_instr_handler
160 .word software_int_handler
161 .word prefetch_abort_handler
162 .word data_abort_handler
163 .word reserved_handler
164 .word irq_handler
165 .word fiq_handler
166
167 .text
168
169#ifndef STUB
170 .global irq
171 .global fiq
172 .global UIE
173#endif
174
175/* All illegal exceptions call into UIE with exception address as first
176 parameter. This is calculated differently depending on which exception
177 we're in. Second parameter is exception number, used for a string lookup
178 in UIE.
179 */
180undef_instr_handler:
181 mov r0, lr
182 mov r1, #0
183 b UIE
184
185/* We run supervisor mode most of the time, and should never see a software
186 exception being thrown. Perhaps make it illegal and call UIE?
187 */
188software_int_handler:
189reserved_handler:
190 movs pc, lr
191
192prefetch_abort_handler:
193 sub r0, lr, #4
194 mov r1, #1
195 b UIE
196
197fiq_handler:
198 @ Branch straight to FIQ handler in pcm_playback.c. This also handles the
199 @ the correct return sequence.
200 stmfd sp!, {r0-r7, r12, lr}
201 bl fiq
202 ldmfd sp!, {r0-r7, r12, lr}
203 subs pc, lr, #4
204
205data_abort_handler:
206 sub r0, lr, #8
207 mov r1, #2
208 b UIE
209
210irq_handler:
211#ifndef STUB
212 stmfd sp!, {r0-r11, r12, lr}
213 bl irq
214 ldmfd sp!, {r0-r11, r12, lr}
215#endif
216 subs pc, lr, #4
217
218#ifdef STUB
219UIE:
220 b UIE
221#endif
222
223/* 256 words of IRQ stack */
224 .space 256*4
225irq_stack:
226
227/* 256 words of FIQ stack */
228 .space 256*4
229fiq_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:
34 msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */ 34 msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ */
35 35
36#ifndef BOOTLOADER 36#ifndef BOOTLOADER
37#if CONFIG_CPU == PNX0101
38
39#ifndef DEBUG
40 ldr r0, =0x80105000
41 mov r1, #1
42 str r1, [r0, #4]
43 mov r1, #0
44 str r1, [r0, #4]
451: ldr r1, [r0]
46 cmp r1, #0
47 bne 1b
48 mov r1, #0x74
49 str r1, [r0, #8]
50 mov r1, #2
51 str r1, [r0, #0x18]
52 mov r1, #0x120
53 str r1, [r0, #0x30]
54 mov r1, #6
55 str r1, [r0, #4]
56 ldr r0, =1f
57 mov r15, r0
581:
59#endif /* !DEBUG */
60#endif /* chipset specific */
61 37
62#ifndef DEBUG 38#ifndef DEBUG
63 /* Copy exception handler code to address 0 */ 39 /* 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 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
9 *
10 * Copyright (C) 2007 by Tomasz Malesinski
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <stdlib.h>
21#include "pnx0101.h"
22#include "system.h"
23
24static struct
25{
26 unsigned char freq;
27 unsigned char sys_mult;
28 unsigned char sys_div;
29 unsigned char mem_conf[9];
30}
31perf_modes[3] ICONST_ATTR =
32{
33 {12, 4, 4, {2, 1, 1, 1, 1, 1, 1, 1, 1, 0}},
34 {48, 4, 1, {5, 4, 1, 4, 4, 1, 3, 3, 1, 0}},
35 {60, 5, 1, {6, 5, 1, 5, 5, 1, 4, 3, 1, 1}}
36};
37
38static int performance_mode, bus_divider;
39
40static void cgu_set_sel_stage_input(int clock, int input)
41{
42 int s = CGU.base_ssr[clock];
43 if (s & 1)
44 CGU.base_fs2[clock] = input;
45 else
46 CGU.base_fs1[clock] = input;
47 CGU.base_scr[clock] = (s & 3) ^ 3;
48}
49
50static void cgu_reset_sel_stage_clocks(int first_esr, int n_esr,
51 int first_div, int n_div)
52{
53 int i;
54 for (i = 0; i < n_esr; i++)
55 CGU.clk_esr[first_esr + i] = 0;
56 for (i = 0; i < n_div; i++)
57 CGU.base_fdc[first_div + i] = 0;
58}
59
60static void cgu_configure_div(int div, int n, int m)
61{
62 int msub, madd, div_size, max_n;
63 unsigned long cfg;
64
65 if (n == m)
66 {
67 CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
68 return;
69 }
70
71 msub = -n;
72 madd = m - n;
73 div_size = (div == PNX0101_HIPREC_FDC) ? 10 : 8;
74 max_n = 1 << div_size;
75 while ((madd << 1) < max_n && (msub << 1) >= -max_n)
76 {
77 madd <<= 1;
78 msub <<= 1;
79 }
80 cfg = (((msub << div_size) | madd) << 3) | 4;
81 CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
82 CGU.base_fdc[div] = cfg | 2;
83 CGU.base_fdc[div] = cfg;
84 CGU.base_fdc[div] = cfg | 1;
85}
86
87static void cgu_connect_div_to_clock(int rel_div, int esr)
88{
89 CGU.clk_esr[esr] = (rel_div << 1) | 1;
90}
91
92static void cgu_disconnect_div_from_clock(int esr)
93{
94 CGU.clk_esr[esr] = 0;
95}
96
97static void cgu_enable_clock(int clock)
98{
99 CGU.clk_pcr[clock] |= 1;
100}
101
102static void cgu_start_sel_stage_dividers(int bcr)
103{
104 CGU.base_bcr[bcr] = 1;
105}
106
107/* Convert a pointer that points to IRAM (0x4xxxx) to a pointer that
108 points to the uncached page (0x0xxxx) that is also mapped to IRAM. */
109static inline void *noncached(void *p) {
110 return (void *)(((unsigned long)p) & 0xffff);
111}
112
113/* TODO: if it works, then comment it */
114static void do_set_mem_timings(int mode) ICODE_ATTR;
115static void do_set_mem_timings(int mode)
116{
117 unsigned char *mem_conf = noncached(perf_modes[mode].mem_conf);
118 int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
119 while ((EMC.status & 3) != 0);
120 EMC.control = 5;
121 EMCSTATIC0.waitrd = mem_conf[0];
122 EMCSTATIC0.waitwr = mem_conf[1];
123 EMCSTATIC1.waitrd = mem_conf[3];
124 EMCSTATIC1.waitwr = mem_conf[4];
125 EMCSTATIC2.waitrd = mem_conf[6];
126 EMCSTATIC2.waitwr = mem_conf[7];
127 EMCSTATIC0.waitoen = mem_conf[2];
128 EMCSTATIC1.waitoen = mem_conf[5];
129 EMCSTATIC2.waitoen = mem_conf[8];
130#ifndef DEBUG
131 EMCSTATIC1.config = mem_conf[9] ? 0x80081 : 0x81;
132#endif
133 EMC.control = 1;
134 set_irq_level(old_irq);
135}
136
137static void emc_set_mem_timings(int mode) {
138 void (*f)(int) = noncached(do_set_mem_timings);
139 (*f)(mode);
140}
141
142/*
143static void do_enable_write_buffers(int on) ICODE_ATTR;
144static void do_enable_write_buffers(int on) {
145 int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL);
146 while ((EMC.status & 3) != 0);
147 EMC.control = 5;
148 EMCSTATIC1.config = on ? 0x80081 : 0x81;
149 EMC.control = 1;
150 set_irq_level(old_irq);
151}
152
153void emc_enable_write_buffers(int on) {
154 void (*f)(int) = noncached(do_enable_write_buffers);
155 (*f)(on);
156}
157*/
158
159/* can it be replaced? */
160static void cgu_busy_wait(int n)
161{
162 while (n > 0)
163 {
164 n--;
165 }
166}
167
168static void cgu_set_sys_mult(int i)
169{
170 cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS, PNX0101_MAIN_CLOCK_FAST);
171 cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3, PNX0101_MAIN_CLOCK_FAST);
172
173 PLL.lppdn = 1;
174 PLL.lpfin = 1;
175 PLL.lpmbyp = 0;
176 PLL.lpdbyp = 0;
177 PLL.lppsel = 1;
178 PLL.lpmsel = i - 1;
179 PLL.lppdn = 0;
180 while (!PLL.lplock);
181
182 cgu_configure_div(PNX0101_FIRST_DIV_SYS + 1, 1, (i == 5) ? 15 : 12);
183 cgu_connect_div_to_clock(1, 0x11);
184 cgu_enable_clock(0x11);
185 cgu_start_sel_stage_dividers(PNX0101_BCR_SYS);
186
187 cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS,
188 PNX0101_MAIN_CLOCK_MAIN_PLL);
189 cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3,
190 PNX0101_MAIN_CLOCK_MAIN_PLL);
191}
192
193static void pnx0101_set_performance_mode(int mode)
194{
195 int old = performance_mode;
196 if (perf_modes[old].freq < perf_modes[mode].freq)
197 {
198 emc_set_mem_timings(mode);
199 if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult)
200 cgu_set_sys_mult(perf_modes[mode].sys_mult);
201 if (perf_modes[old].sys_div != perf_modes[mode].sys_div)
202 cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div);
203 }
204 else if (perf_modes[old].freq > perf_modes[mode].freq)
205 {
206 if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult)
207 cgu_set_sys_mult(perf_modes[mode].sys_mult);
208 if (perf_modes[old].sys_div != perf_modes[mode].sys_div)
209 cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div);
210 emc_set_mem_timings(mode);
211 }
212 performance_mode = mode;
213}
214
215static void pnx0101_init_clocks(void)
216{
217 bus_divider = PNX0101_FIRST_DIV_SYS + (CGU.clk_esr[0] >> 1);
218 performance_mode = 0;
219 pnx0101_set_performance_mode(2);
220/*
221#ifndef DEBUG
222 emc_enable_write_buffers(1);
223#endif
224*/
225 cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB1,
226 PNX0101_MAIN_CLOCK_FAST);
227 cgu_reset_sel_stage_clocks(PNX0101_FIRST_ESR_APB1, PNX0101_N_ESR_APB1,
228 PNX0101_FIRST_DIV_APB1, PNX0101_N_DIV_APB1);
229 cgu_configure_div(PNX0101_FIRST_DIV_APB1, 1, 4);
230 cgu_connect_div_to_clock(0, PNX0101_ESR_APB1);
231 cgu_connect_div_to_clock(0, PNX0101_ESR_T0);
232 cgu_connect_div_to_clock(0, PNX0101_ESR_T1);
233 cgu_connect_div_to_clock(0, PNX0101_ESR_I2C);
234 cgu_enable_clock(PNX0101_CLOCK_APB1);
235 cgu_enable_clock(PNX0101_CLOCK_T0);
236 cgu_enable_clock(PNX0101_CLOCK_T1);
237 cgu_enable_clock(PNX0101_CLOCK_I2C);
238}
239
240#ifdef HAVE_ADJUSTABLE_CPU_FREQ
241void set_cpu_frequency(long frequency)
242{
243 switch (frequency)
244 {
245 case CPUFREQ_MAX:
246 pnx0101_set_performance_mode(2);
247 cpu_frequency = CPUFREQ_MAX;
248 break;
249 case CPUFREQ_NORMAL:
250 pnx0101_set_performance_mode(1);
251 cpu_frequency = CPUFREQ_NORMAL;
252 break;
253 case CPUFREQ_DEFAULT:
254 default:
255 pnx0101_set_performance_mode(0);
256 cpu_frequency = CPUFREQ_DEFAULT;
257 break;
258 }
259
260}
261#endif
262
263interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
264
265#define IRQ_READ(reg, dest) \
266 do { unsigned long v2; \
267 do { \
268 dest = (reg); \
269 v2 = (reg); \
270 } while ((dest != v2)); \
271 } while (0);
272
273#define IRQ_WRITE_WAIT(reg, val, cond) \
274 do { unsigned long v, v2; \
275 do { \
276 (reg) = (val); \
277 v = (reg); \
278 v2 = (reg); \
279 } while ((v != v2) || !(cond)); \
280 } while (0);
281
282static void undefined_int(void)
283{
284}
285
286void irq(void)
287{
288 int n;
289 IRQ_READ(INTVECTOR[0], n)
290 (*(interrupt_vector[n >> 3]))();
291}
292
293void fiq(void)
294{
295}
296
297void irq_enable_int(int n)
298{
299 IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE | INTREQ_ENABLE, v & 0x10000);
300}
301
302void irq_disable_int(int n)
303{
304 IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE, (v & 0x10000) == 0);
305}
306
307void irq_set_int_handler(int n, interrupt_handler_t handler)
308{
309 interrupt_vector[n] = handler;
310}
311
312void system_init(void)
313{
314 int i;
315
316 /* turn off watchdog */
317 (*(volatile unsigned long *)0x80002804) = 0;
318
319 /*
320 IRQ_WRITE_WAIT(INTVECTOR[0], 0, v == 0);
321 IRQ_WRITE_WAIT(INTVECTOR[1], 0, v == 0);
322 IRQ_WRITE_WAIT(INTPRIOMASK[0], 0, v == 0);
323 IRQ_WRITE_WAIT(INTPRIOMASK[1], 0, v == 0);
324 */
325
326 for (i = 0; i < 0x1c; i++)
327 {
328 IRQ_WRITE_WAIT(INTREQ[i],
329 INTREQ_WEPRIO | INTREQ_WETARGET |
330 INTREQ_WEENABLE | INTREQ_WEACTVLO | 1,
331 (v & 0x3010f) == 1);
332 IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEENABLE, (v & 0x10000) == 0);
333 IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEPRIO | 1, (v & 0xf) == 1);
334 interrupt_vector[i + 1] = undefined_int;
335 }
336 interrupt_vector[0] = undefined_int;
337 pnx0101_init_clocks();
338}
339
340
341void system_reboot(void)
342{
343 (*(volatile unsigned long *)0x80002804) = 1;
344 while (1);
345}
346
347int system_memory_guard(int newmode)
348{
349 (void)newmode;
350 return 0;
351}
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 */
28static void (*pfn_unregister)(void) = NULL; /* unregister callback */ 28static void (*pfn_unregister)(void) = NULL; /* unregister callback */
29#ifdef CPU_COLDFIRE 29#ifdef CPU_COLDFIRE
30static int base_prescale; 30static int base_prescale;
31#elif defined CPU_PP 31#elif defined CPU_PP || CONFIG_CPU == PNX0101
32static long cycles_new = 0; 32static long cycles_new = 0;
33#endif 33#endif
34 34
@@ -67,6 +67,24 @@ void TIMER2(void)
67 cycles_new = 0; 67 cycles_new = 0;
68 } 68 }
69} 69}
70#elif CONFIG_CPU == PNX0101
71void TIMER1_ISR(void)
72{
73 if (cycles_new > 0)
74 {
75 TIMER1.load = cycles_new - 1;
76 cycles_new = 0;
77 }
78 if (pfn_timer != NULL)
79 {
80 cycles_new = -1;
81 /* "lock" the variable, in case timer_set_period()
82 * is called within pfn_timer() */
83 pfn_timer();
84 cycles_new = 0;
85 }
86 TIMER1.clr = 1; /* clear the interrupt */
87}
70#endif /* CONFIG_CPU */ 88#endif /* CONFIG_CPU */
71 89
72static bool timer_set(long cycles, bool start) 90static bool timer_set(long cycles, bool start)
@@ -85,8 +103,26 @@ static bool timer_set(long cycles, bool start)
85 } 103 }
86#endif 104#endif
87 105
88#if CONFIG_CPU == PNX0101 /* TODO: Implement for iFP */ 106#if CONFIG_CPU == PNX0101
89 (void)start; 107 if (start)
108 {
109 if (pfn_unregister != NULL)
110 {
111 pfn_unregister();
112 pfn_unregister = NULL;
113 }
114 TIMER1.ctrl &= ~0x80; /* disable the counter */
115 TIMER1.ctrl |= 0x40; /* reload after counting down to zero */
116 TIMER1.ctrl &= ~0xc; /* no prescaler */
117 TIMER1.clr = 1; /* clear an interrupt event */
118 }
119 if (start || (cycles_new == -1)) /* within isr, cycles_new is "locked" */
120 { /* enable timer */
121 TIMER1.load = cycles - 1;
122 TIMER1.ctrl |= 0x80; /* enable the counter */
123 }
124 else
125 cycles_new = cycles;
90#endif 126#endif
91 127
92#if CONFIG_CPU == SH7034 128#if CONFIG_CPU == SH7034
@@ -229,6 +265,9 @@ bool timer_register(int reg_prio, void (*unregister_callback)(void),
229#elif defined(CPU_PP) 265#elif defined(CPU_PP)
230 /* unmask interrupt source */ 266 /* unmask interrupt source */
231 CPU_INT_EN = TIMER2_MASK; 267 CPU_INT_EN = TIMER2_MASK;
268#elif CONFIG_CPU == PNX0101
269 irq_set_int_handler(IRQ_TIMER1, TIMER1_ISR);
270 irq_enable_int(IRQ_TIMER1);
232#endif 271#endif
233 return true; 272 return true;
234} 273}
@@ -249,6 +288,9 @@ void timer_unregister(void)
249#elif defined(CPU_PP) 288#elif defined(CPU_PP)
250 TIMER2_CFG = 0; /* stop timer 2 */ 289 TIMER2_CFG = 0; /* stop timer 2 */
251 CPU_INT_CLR = TIMER2_MASK; 290 CPU_INT_CLR = TIMER2_MASK;
291#elif CONFIG_CPU == PNX0101
292 TIMER1.ctrl &= ~0x80; /* disable timer 1 */
293 irq_disable_int(5);
252#endif 294#endif
253 pfn_timer = NULL; 295 pfn_timer = NULL;
254 pfn_unregister = NULL; 296 pfn_unregister = NULL;