diff options
Diffstat (limited to 'firmware/target/arm/pnx0101/system-pnx0101.c')
-rw-r--r-- | firmware/target/arm/pnx0101/system-pnx0101.c | 317 |
1 files changed, 0 insertions, 317 deletions
diff --git a/firmware/target/arm/pnx0101/system-pnx0101.c b/firmware/target/arm/pnx0101/system-pnx0101.c deleted file mode 100644 index 63720d11be..0000000000 --- a/firmware/target/arm/pnx0101/system-pnx0101.c +++ /dev/null | |||
@@ -1,317 +0,0 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id: $ | ||
9 | * | ||
10 | * Copyright (C) 2007 by Tomasz Malesinski | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or | ||
13 | * modify it under the terms of the GNU General Public License | ||
14 | * as published by the Free Software Foundation; either version 2 | ||
15 | * of the License, or (at your option) any later version. | ||
16 | * | ||
17 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
18 | * KIND, either express or implied. | ||
19 | * | ||
20 | ****************************************************************************/ | ||
21 | |||
22 | #include <stdlib.h> | ||
23 | #include "pnx0101.h" | ||
24 | #include "system.h" | ||
25 | |||
26 | static struct | ||
27 | { | ||
28 | unsigned char freq; | ||
29 | unsigned char sys_mult; | ||
30 | unsigned char sys_div; | ||
31 | } | ||
32 | perf_modes[3] ICONST_ATTR = | ||
33 | { | ||
34 | {12, 4, 4}, | ||
35 | {48, 4, 1}, | ||
36 | {60, 5, 1} | ||
37 | }; | ||
38 | |||
39 | static int performance_mode, bus_divider; | ||
40 | |||
41 | static void cgu_set_sel_stage_input(int clock, int input) | ||
42 | { | ||
43 | int s = CGU.base_ssr[clock]; | ||
44 | if (s & 1) | ||
45 | CGU.base_fs2[clock] = input; | ||
46 | else | ||
47 | CGU.base_fs1[clock] = input; | ||
48 | CGU.base_scr[clock] = (s & 3) ^ 3; | ||
49 | } | ||
50 | |||
51 | static void cgu_reset_sel_stage_clocks(int first_esr, int n_esr, | ||
52 | int first_div, int n_div) | ||
53 | { | ||
54 | int i; | ||
55 | for (i = 0; i < n_esr; i++) | ||
56 | CGU.clk_esr[first_esr + i] = 0; | ||
57 | for (i = 0; i < n_div; i++) | ||
58 | CGU.base_fdc[first_div + i] = 0; | ||
59 | } | ||
60 | |||
61 | static void cgu_configure_div(int div, int n, int m) | ||
62 | { | ||
63 | int msub, madd, div_size, max_n; | ||
64 | unsigned long cfg; | ||
65 | |||
66 | if (n == m) | ||
67 | { | ||
68 | CGU.base_fdc[div] = CGU.base_fdc[div] & ~1; | ||
69 | return; | ||
70 | } | ||
71 | |||
72 | msub = -n; | ||
73 | madd = m - n; | ||
74 | div_size = (div == PNX0101_HIPREC_FDC) ? 10 : 8; | ||
75 | max_n = 1 << div_size; | ||
76 | while ((madd << 1) < max_n && (msub << 1) >= -max_n) | ||
77 | { | ||
78 | madd <<= 1; | ||
79 | msub <<= 1; | ||
80 | } | ||
81 | cfg = (((msub << div_size) | madd) << 3) | 4; | ||
82 | CGU.base_fdc[div] = CGU.base_fdc[div] & ~1; | ||
83 | CGU.base_fdc[div] = cfg | 2; | ||
84 | CGU.base_fdc[div] = cfg; | ||
85 | CGU.base_fdc[div] = cfg | 1; | ||
86 | } | ||
87 | |||
88 | static void cgu_connect_div_to_clock(int rel_div, int esr) | ||
89 | { | ||
90 | CGU.clk_esr[esr] = (rel_div << 1) | 1; | ||
91 | } | ||
92 | |||
93 | static void cgu_enable_clock(int clock) | ||
94 | { | ||
95 | CGU.clk_pcr[clock] |= 1; | ||
96 | } | ||
97 | |||
98 | static void cgu_start_sel_stage_dividers(int bcr) | ||
99 | { | ||
100 | CGU.base_bcr[bcr] = 1; | ||
101 | } | ||
102 | |||
103 | /* Convert a pointer that points to IRAM (0x4xxxx) to a pointer that | ||
104 | points to the uncached page (0x0xxxx) that is also mapped to IRAM. */ | ||
105 | static inline void *noncached(void *p) | ||
106 | { | ||
107 | return (void *)(((unsigned long)p) & 0xffff); | ||
108 | } | ||
109 | |||
110 | /* To avoid SRAM accesses while changing memory controller settings we | ||
111 | run this routine from uncached copy of IRAM. All times are in CPU | ||
112 | cycles. At CPU frequencies lower than 60 MHz we could use faster | ||
113 | settings, but since DMA may access SRAM at any time, changing | ||
114 | memory timings together with CPU frequency would be tricky. */ | ||
115 | static void do_set_mem_timings(void) ICODE_ATTR; | ||
116 | static void do_set_mem_timings(void) | ||
117 | { | ||
118 | int old_irq = disable_irq_save(); | ||
119 | while ((EMC.status & 3) != 0); | ||
120 | EMC.control = 5; | ||
121 | EMCSTATIC0.waitrd = 6; | ||
122 | EMCSTATIC0.waitwr = 5; | ||
123 | EMCSTATIC1.waitrd = 5; | ||
124 | EMCSTATIC1.waitwr = 4; /* OF uses 5 here */ | ||
125 | EMCSTATIC2.waitrd = 4; | ||
126 | EMCSTATIC2.waitwr = 3; | ||
127 | EMCSTATIC0.waitoen = 1; | ||
128 | EMCSTATIC1.waitoen = 1; | ||
129 | EMCSTATIC2.waitoen = 1; | ||
130 | /* Enable write buffers for SRAM. */ | ||
131 | #ifndef DEBUG | ||
132 | EMCSTATIC1.config = 0x80081; | ||
133 | #endif | ||
134 | EMC.control = 1; | ||
135 | restore_irq(old_irq); | ||
136 | } | ||
137 | |||
138 | static void emc_set_mem_timings(void) | ||
139 | { | ||
140 | void (*f)(void) = noncached(do_set_mem_timings); | ||
141 | (*f)(); | ||
142 | } | ||
143 | |||
144 | static void cgu_set_sys_mult(int i) | ||
145 | { | ||
146 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS, PNX0101_MAIN_CLOCK_FAST); | ||
147 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3, PNX0101_MAIN_CLOCK_FAST); | ||
148 | |||
149 | PLL.lppdn = 1; | ||
150 | PLL.lpfin = 1; | ||
151 | PLL.lpmbyp = 0; | ||
152 | PLL.lpdbyp = 0; | ||
153 | PLL.lppsel = 1; | ||
154 | PLL.lpmsel = i - 1; | ||
155 | PLL.lppdn = 0; | ||
156 | while (!PLL.lplock); | ||
157 | |||
158 | cgu_configure_div(PNX0101_FIRST_DIV_SYS + 1, 1, (i == 5) ? 15 : 12); | ||
159 | cgu_connect_div_to_clock(1, 0x11); | ||
160 | cgu_enable_clock(0x11); | ||
161 | cgu_start_sel_stage_dividers(PNX0101_BCR_SYS); | ||
162 | |||
163 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_SYS, | ||
164 | PNX0101_MAIN_CLOCK_MAIN_PLL); | ||
165 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB3, | ||
166 | PNX0101_MAIN_CLOCK_MAIN_PLL); | ||
167 | } | ||
168 | |||
169 | static void pnx0101_set_performance_mode(int mode) | ||
170 | { | ||
171 | int old = performance_mode; | ||
172 | if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult) | ||
173 | cgu_set_sys_mult(perf_modes[mode].sys_mult); | ||
174 | if (perf_modes[old].sys_div != perf_modes[mode].sys_div) | ||
175 | cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div); | ||
176 | performance_mode = mode; | ||
177 | } | ||
178 | |||
179 | static void pnx0101_init_clocks(void) | ||
180 | { | ||
181 | bus_divider = PNX0101_FIRST_DIV_SYS + (CGU.clk_esr[0] >> 1); | ||
182 | performance_mode = 0; | ||
183 | emc_set_mem_timings(); | ||
184 | pnx0101_set_performance_mode(2); | ||
185 | |||
186 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB1, | ||
187 | PNX0101_MAIN_CLOCK_FAST); | ||
188 | cgu_reset_sel_stage_clocks(PNX0101_FIRST_ESR_APB1, PNX0101_N_ESR_APB1, | ||
189 | PNX0101_FIRST_DIV_APB1, PNX0101_N_DIV_APB1); | ||
190 | cgu_configure_div(PNX0101_FIRST_DIV_APB1, 1, 4); | ||
191 | cgu_connect_div_to_clock(0, PNX0101_ESR_APB1); | ||
192 | cgu_connect_div_to_clock(0, PNX0101_ESR_T0); | ||
193 | cgu_connect_div_to_clock(0, PNX0101_ESR_T1); | ||
194 | cgu_connect_div_to_clock(0, PNX0101_ESR_I2C); | ||
195 | cgu_enable_clock(PNX0101_CLOCK_APB1); | ||
196 | cgu_enable_clock(PNX0101_CLOCK_T0); | ||
197 | cgu_enable_clock(PNX0101_CLOCK_T1); | ||
198 | cgu_enable_clock(PNX0101_CLOCK_I2C); | ||
199 | } | ||
200 | |||
201 | #ifdef HAVE_ADJUSTABLE_CPU_FREQ | ||
202 | void set_cpu_frequency(long frequency) | ||
203 | { | ||
204 | switch (frequency) | ||
205 | { | ||
206 | case CPUFREQ_MAX: | ||
207 | pnx0101_set_performance_mode(2); | ||
208 | cpu_frequency = CPUFREQ_MAX; | ||
209 | break; | ||
210 | case CPUFREQ_NORMAL: | ||
211 | pnx0101_set_performance_mode(1); | ||
212 | cpu_frequency = CPUFREQ_NORMAL; | ||
213 | break; | ||
214 | case CPUFREQ_DEFAULT: | ||
215 | default: | ||
216 | pnx0101_set_performance_mode(0); | ||
217 | cpu_frequency = CPUFREQ_DEFAULT; | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | } | ||
222 | #endif | ||
223 | |||
224 | interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata"))); | ||
225 | |||
226 | #define IRQ_READ(reg, dest) \ | ||
227 | do { unsigned long v2; \ | ||
228 | do { \ | ||
229 | dest = (reg); \ | ||
230 | v2 = (reg); \ | ||
231 | } while ((dest != v2)); \ | ||
232 | } while (0); | ||
233 | |||
234 | #define IRQ_WRITE_WAIT(reg, val, cond) \ | ||
235 | do { unsigned long v, v2; \ | ||
236 | do { \ | ||
237 | (reg) = (val); \ | ||
238 | v = (reg); \ | ||
239 | v2 = (reg); \ | ||
240 | } while ((v != v2) || !(cond)); \ | ||
241 | } while (0); | ||
242 | |||
243 | static void undefined_int(void) | ||
244 | { | ||
245 | } | ||
246 | |||
247 | void irq(void) | ||
248 | { | ||
249 | unsigned long n; | ||
250 | IRQ_READ(INTVECTOR[0], n) | ||
251 | (*(interrupt_vector[n >> 3]))(); | ||
252 | } | ||
253 | |||
254 | void fiq(void) | ||
255 | { | ||
256 | } | ||
257 | |||
258 | void irq_enable_int(int n) | ||
259 | { | ||
260 | IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE | INTREQ_ENABLE, v & 0x10000); | ||
261 | } | ||
262 | |||
263 | void irq_disable_int(int n) | ||
264 | { | ||
265 | IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE, (v & 0x10000) == 0); | ||
266 | } | ||
267 | |||
268 | void irq_set_int_handler(int n, interrupt_handler_t handler) | ||
269 | { | ||
270 | interrupt_vector[n] = handler; | ||
271 | } | ||
272 | |||
273 | void system_init(void) | ||
274 | { | ||
275 | int i; | ||
276 | |||
277 | /* turn off watchdog */ | ||
278 | (*(volatile unsigned long *)0x80002804) = 0; | ||
279 | |||
280 | /* | ||
281 | IRQ_WRITE_WAIT(INTVECTOR[0], 0, v == 0); | ||
282 | IRQ_WRITE_WAIT(INTVECTOR[1], 0, v == 0); | ||
283 | IRQ_WRITE_WAIT(INTPRIOMASK[0], 0, v == 0); | ||
284 | IRQ_WRITE_WAIT(INTPRIOMASK[1], 0, v == 0); | ||
285 | */ | ||
286 | |||
287 | for (i = 1; i <= 0x1c; i++) | ||
288 | { | ||
289 | IRQ_WRITE_WAIT(INTREQ[i], | ||
290 | INTREQ_WEPRIO | INTREQ_WETARGET | | ||
291 | INTREQ_WEENABLE | INTREQ_WEACTVLO | 1, | ||
292 | (v & 0x3010f) == 1); | ||
293 | IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEENABLE, (v & 0x10000) == 0); | ||
294 | IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEPRIO | 1, (v & 0xf) == 1); | ||
295 | interrupt_vector[i] = undefined_int; | ||
296 | } | ||
297 | interrupt_vector[0] = undefined_int; | ||
298 | pnx0101_init_clocks(); | ||
299 | } | ||
300 | |||
301 | |||
302 | void system_reboot(void) | ||
303 | { | ||
304 | (*(volatile unsigned long *)0x80002804) = 1; | ||
305 | while (1); | ||
306 | } | ||
307 | |||
308 | void system_exception_wait(void) | ||
309 | { | ||
310 | while (1); | ||
311 | } | ||
312 | |||
313 | int system_memory_guard(int newmode) | ||
314 | { | ||
315 | (void)newmode; | ||
316 | return 0; | ||
317 | } | ||