Move c/h files implementing/defining standard library stuff into a new libc directory...
[kugel-rb.git] / firmware / target / arm / pnx0101 / system-pnx0101.c
blob63720d11bee22de92d364f2f13efb93f2e93c931
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: $
10 * Copyright (C) 2007 by Tomasz Malesinski
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.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdlib.h>
23 #include "pnx0101.h"
24 #include "system.h"
26 static struct
28 unsigned char freq;
29 unsigned char sys_mult;
30 unsigned char sys_div;
32 perf_modes[3] ICONST_ATTR =
34 {12, 4, 4},
35 {48, 4, 1},
36 {60, 5, 1}
39 static int performance_mode, bus_divider;
41 static void cgu_set_sel_stage_input(int clock, int input)
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;
51 static void cgu_reset_sel_stage_clocks(int first_esr, int n_esr,
52 int first_div, int n_div)
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;
61 static void cgu_configure_div(int div, int n, int m)
63 int msub, madd, div_size, max_n;
64 unsigned long cfg;
66 if (n == m)
68 CGU.base_fdc[div] = CGU.base_fdc[div] & ~1;
69 return;
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)
78 madd <<= 1;
79 msub <<= 1;
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;
88 static void cgu_connect_div_to_clock(int rel_div, int esr)
90 CGU.clk_esr[esr] = (rel_div << 1) | 1;
93 static void cgu_enable_clock(int clock)
95 CGU.clk_pcr[clock] |= 1;
98 static void cgu_start_sel_stage_dividers(int bcr)
100 CGU.base_bcr[bcr] = 1;
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)
107 return (void *)(((unsigned long)p) & 0xffff);
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)
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);
138 static void emc_set_mem_timings(void)
140 void (*f)(void) = noncached(do_set_mem_timings);
141 (*f)();
144 static void cgu_set_sys_mult(int i)
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);
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);
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);
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);
169 static void pnx0101_set_performance_mode(int mode)
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;
179 static void pnx0101_init_clocks(void)
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);
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);
201 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
202 void set_cpu_frequency(long frequency)
204 switch (frequency)
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;
222 #endif
224 interrupt_handler_t interrupt_vector[0x1d] __attribute__ ((section(".idata")));
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);
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);
243 static void undefined_int(void)
247 void irq(void)
249 unsigned long n;
250 IRQ_READ(INTVECTOR[0], n)
251 (*(interrupt_vector[n >> 3]))();
254 void fiq(void)
258 void irq_enable_int(int n)
260 IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE | INTREQ_ENABLE, v & 0x10000);
263 void irq_disable_int(int n)
265 IRQ_WRITE_WAIT(INTREQ[n], INTREQ_WEENABLE, (v & 0x10000) == 0);
268 void irq_set_int_handler(int n, interrupt_handler_t handler)
270 interrupt_vector[n] = handler;
273 void system_init(void)
275 int i;
277 /* turn off watchdog */
278 (*(volatile unsigned long *)0x80002804) = 0;
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);
287 for (i = 1; i <= 0x1c; i++)
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;
297 interrupt_vector[0] = undefined_int;
298 pnx0101_init_clocks();
302 void system_reboot(void)
304 (*(volatile unsigned long *)0x80002804) = 1;
305 while (1);
308 void system_exception_wait(void)
310 while (1);
313 int system_memory_guard(int newmode)
315 (void)newmode;
316 return 0;