1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
29 unsigned char sys_mult
;
30 unsigned char sys_div
;
32 perf_modes
[3] ICONST_ATTR
=
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
];
45 CGU
.base_fs2
[clock
] = input
;
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
)
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
;
68 CGU
.base_fdc
[div
] = CGU
.base_fdc
[div
] & ~1;
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
)
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);
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. */
132 EMCSTATIC1
.config
= 0x80081;
135 restore_irq(old_irq
);
138 static void emc_set_mem_timings(void)
140 void (*f
)(void) = noncached(do_set_mem_timings
);
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
);
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
)
207 pnx0101_set_performance_mode(2);
208 cpu_frequency
= CPUFREQ_MAX
;
211 pnx0101_set_performance_mode(1);
212 cpu_frequency
= CPUFREQ_NORMAL
;
214 case CPUFREQ_DEFAULT
:
216 pnx0101_set_performance_mode(0);
217 cpu_frequency
= CPUFREQ_DEFAULT
;
224 interrupt_handler_t interrupt_vector
[0x1d] __attribute__ ((section(".idata")));
226 #define IRQ_READ(reg, dest) \
227 do { unsigned long v2; \
231 } while ((dest != v2)); \
234 #define IRQ_WRITE_WAIT(reg, val, cond) \
235 do { unsigned long v, v2; \
240 } while ((v != v2) || !(cond)); \
243 static void undefined_int(void)
250 IRQ_READ(INTVECTOR
[0], n
)
251 (*(interrupt_vector
[n
>> 3]))();
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)
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,
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;
308 void system_exception_wait(void)
313 int system_memory_guard(int newmode
)