diff options
Diffstat (limited to 'firmware')
-rw-r--r-- | firmware/export/pnx0101.h | 38 | ||||
-rw-r--r-- | firmware/target/arm/pnx0101/system-pnx0101.c | 111 |
2 files changed, 73 insertions, 76 deletions
diff --git a/firmware/export/pnx0101.h b/firmware/export/pnx0101.h index 766f3dd2ff..e344f0466e 100644 --- a/firmware/export/pnx0101.h +++ b/firmware/export/pnx0101.h | |||
@@ -220,6 +220,44 @@ struct pnx0101_timer { | |||
220 | #define INTREQ_WEACTVLO 0x02000000 | 220 | #define INTREQ_WEACTVLO 0x02000000 |
221 | #define INTREQ_ENABLE 0x00010000 | 221 | #define INTREQ_ENABLE 0x00010000 |
222 | 222 | ||
223 | /* General purpose DMA */ | ||
224 | |||
225 | struct pnx0101_dma_channel { | ||
226 | unsigned long source; | ||
227 | unsigned long dest; | ||
228 | unsigned long length; | ||
229 | unsigned long config; | ||
230 | unsigned long enable; | ||
231 | unsigned long pad1; | ||
232 | unsigned long pad2; | ||
233 | unsigned long count; | ||
234 | }; | ||
235 | |||
236 | #define DMACHANNEL ((volatile struct pnx0101_dma_channel *)0x80104800) | ||
237 | |||
238 | struct pnx0101_dma { | ||
239 | unsigned long enable; | ||
240 | unsigned long stat; | ||
241 | unsigned long irqmask; | ||
242 | unsigned long softint; | ||
243 | }; | ||
244 | |||
245 | #define DMA (*(volatile struct pnx0101_dma *)0x80104c00) | ||
246 | |||
247 | struct pnx0101_audio { | ||
248 | unsigned long pad1; | ||
249 | unsigned long siocr; | ||
250 | unsigned long pad2; | ||
251 | unsigned long pad3; | ||
252 | unsigned long pad4; | ||
253 | unsigned long pad5; | ||
254 | unsigned long ddacctrl; | ||
255 | unsigned long ddacstat; | ||
256 | unsigned long ddacset; | ||
257 | }; | ||
258 | |||
259 | #define AUDIO (*(volatile struct pnx0101_audio *)0x80200380) | ||
260 | |||
223 | #endif /* ASM */ | 261 | #endif /* ASM */ |
224 | 262 | ||
225 | #endif | 263 | #endif |
diff --git a/firmware/target/arm/pnx0101/system-pnx0101.c b/firmware/target/arm/pnx0101/system-pnx0101.c index 5708168b51..da94f397ca 100644 --- a/firmware/target/arm/pnx0101/system-pnx0101.c +++ b/firmware/target/arm/pnx0101/system-pnx0101.c | |||
@@ -26,13 +26,12 @@ static struct | |||
26 | unsigned char freq; | 26 | unsigned char freq; |
27 | unsigned char sys_mult; | 27 | unsigned char sys_mult; |
28 | unsigned char sys_div; | 28 | unsigned char sys_div; |
29 | unsigned char mem_conf[10]; | ||
30 | } | 29 | } |
31 | perf_modes[3] ICONST_ATTR = | 30 | perf_modes[3] ICONST_ATTR = |
32 | { | 31 | { |
33 | {12, 4, 4, {2, 1, 1, 1, 1, 1, 1, 1, 1, 0}}, | 32 | {12, 4, 4}, |
34 | {48, 4, 1, {5, 4, 1, 4, 4, 1, 3, 3, 1, 0}}, | 33 | {48, 4, 1}, |
35 | {60, 5, 1, {6, 5, 1, 5, 5, 1, 4, 3, 1, 1}} | 34 | {60, 5, 1} |
36 | }; | 35 | }; |
37 | 36 | ||
38 | static int performance_mode, bus_divider; | 37 | static int performance_mode, bus_divider; |
@@ -89,11 +88,6 @@ static void cgu_connect_div_to_clock(int rel_div, int esr) | |||
89 | CGU.clk_esr[esr] = (rel_div << 1) | 1; | 88 | CGU.clk_esr[esr] = (rel_div << 1) | 1; |
90 | } | 89 | } |
91 | 90 | ||
92 | static void cgu_disconnect_div_from_clock(int esr) | ||
93 | { | ||
94 | CGU.clk_esr[esr] = 0; | ||
95 | } | ||
96 | |||
97 | static void cgu_enable_clock(int clock) | 91 | static void cgu_enable_clock(int clock) |
98 | { | 92 | { |
99 | CGU.clk_pcr[clock] |= 1; | 93 | CGU.clk_pcr[clock] |= 1; |
@@ -106,63 +100,43 @@ static void cgu_start_sel_stage_dividers(int bcr) | |||
106 | 100 | ||
107 | /* Convert a pointer that points to IRAM (0x4xxxx) to a pointer that | 101 | /* 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. */ | 102 | points to the uncached page (0x0xxxx) that is also mapped to IRAM. */ |
109 | static inline void *noncached(void *p) { | 103 | static inline void *noncached(void *p) |
104 | { | ||
110 | return (void *)(((unsigned long)p) & 0xffff); | 105 | return (void *)(((unsigned long)p) & 0xffff); |
111 | } | 106 | } |
112 | 107 | ||
113 | /* TODO: if it works, then comment it */ | 108 | /* To avoid SRAM accesses while changing memory controller settings we |
114 | static void do_set_mem_timings(int mode) ICODE_ATTR; | 109 | run this routine from uncached copy of IRAM. All times are in CPU |
115 | static void do_set_mem_timings(int mode) | 110 | cycles. At CPU frequencies lower than 60 MHz we could use faster |
111 | settings, but since DMA may access SRAM at any time, changing | ||
112 | memory timings together with CPU frequency would be tricky. */ | ||
113 | static void do_set_mem_timings(void) ICODE_ATTR; | ||
114 | static void do_set_mem_timings(void) | ||
116 | { | 115 | { |
117 | unsigned char *mem_conf = noncached(perf_modes[mode].mem_conf); | ||
118 | int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL); | 116 | int old_irq = set_irq_level(HIGHEST_IRQ_LEVEL); |
119 | while ((EMC.status & 3) != 0); | 117 | while ((EMC.status & 3) != 0); |
120 | EMC.control = 5; | 118 | EMC.control = 5; |
121 | EMCSTATIC0.waitrd = mem_conf[0]; | 119 | EMCSTATIC0.waitrd = 6; |
122 | EMCSTATIC0.waitwr = mem_conf[1]; | 120 | EMCSTATIC0.waitwr = 5; |
123 | EMCSTATIC1.waitrd = mem_conf[3]; | 121 | EMCSTATIC1.waitrd = 5; |
124 | EMCSTATIC1.waitwr = mem_conf[4]; | 122 | EMCSTATIC1.waitwr = 4; /* OF uses 5 here */ |
125 | EMCSTATIC2.waitrd = mem_conf[6]; | 123 | EMCSTATIC2.waitrd = 4; |
126 | EMCSTATIC2.waitwr = mem_conf[7]; | 124 | EMCSTATIC2.waitwr = 3; |
127 | EMCSTATIC0.waitoen = mem_conf[2]; | 125 | EMCSTATIC0.waitoen = 1; |
128 | EMCSTATIC1.waitoen = mem_conf[5]; | 126 | EMCSTATIC1.waitoen = 1; |
129 | EMCSTATIC2.waitoen = mem_conf[8]; | 127 | EMCSTATIC2.waitoen = 1; |
128 | /* Enable write buffers for SRAM. */ | ||
130 | #ifndef DEBUG | 129 | #ifndef DEBUG |
131 | EMCSTATIC1.config = mem_conf[9] ? 0x80081 : 0x81; | 130 | EMCSTATIC1.config = 0x80081; |
132 | #endif | 131 | #endif |
133 | EMC.control = 1; | 132 | EMC.control = 1; |
134 | set_irq_level(old_irq); | 133 | set_irq_level(old_irq); |
135 | } | 134 | } |
136 | 135 | ||
137 | static void emc_set_mem_timings(int mode) { | 136 | static void emc_set_mem_timings(void) |
138 | void (*f)(int) = noncached(do_set_mem_timings); | ||
139 | (*f)(mode); | ||
140 | } | ||
141 | |||
142 | /* | ||
143 | static void do_enable_write_buffers(int on) ICODE_ATTR; | ||
144 | static 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 | |||
153 | void 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? */ | ||
160 | static void cgu_busy_wait(int n) | ||
161 | { | 137 | { |
162 | while (n > 0) | 138 | void (*f)(void) = noncached(do_set_mem_timings); |
163 | { | 139 | (*f)(); |
164 | n--; | ||
165 | } | ||
166 | } | 140 | } |
167 | 141 | ||
168 | static void cgu_set_sys_mult(int i) | 142 | static void cgu_set_sys_mult(int i) |
@@ -193,22 +167,10 @@ static void cgu_set_sys_mult(int i) | |||
193 | static void pnx0101_set_performance_mode(int mode) | 167 | static void pnx0101_set_performance_mode(int mode) |
194 | { | 168 | { |
195 | int old = performance_mode; | 169 | int old = performance_mode; |
196 | if (perf_modes[old].freq < perf_modes[mode].freq) | 170 | if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult) |
197 | { | 171 | cgu_set_sys_mult(perf_modes[mode].sys_mult); |
198 | emc_set_mem_timings(mode); | 172 | if (perf_modes[old].sys_div != perf_modes[mode].sys_div) |
199 | if (perf_modes[old].sys_mult != perf_modes[mode].sys_mult) | 173 | cgu_configure_div(bus_divider, 1, perf_modes[mode].sys_div); |
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; | 174 | performance_mode = mode; |
213 | } | 175 | } |
214 | 176 | ||
@@ -216,12 +178,9 @@ static void pnx0101_init_clocks(void) | |||
216 | { | 178 | { |
217 | bus_divider = PNX0101_FIRST_DIV_SYS + (CGU.clk_esr[0] >> 1); | 179 | bus_divider = PNX0101_FIRST_DIV_SYS + (CGU.clk_esr[0] >> 1); |
218 | performance_mode = 0; | 180 | performance_mode = 0; |
181 | emc_set_mem_timings(); | ||
219 | pnx0101_set_performance_mode(2); | 182 | pnx0101_set_performance_mode(2); |
220 | /* | 183 | |
221 | #ifndef DEBUG | ||
222 | emc_enable_write_buffers(1); | ||
223 | #endif | ||
224 | */ | ||
225 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB1, | 184 | cgu_set_sel_stage_input(PNX0101_SEL_STAGE_APB1, |
226 | PNX0101_MAIN_CLOCK_FAST); | 185 | PNX0101_MAIN_CLOCK_FAST); |
227 | cgu_reset_sel_stage_clocks(PNX0101_FIRST_ESR_APB1, PNX0101_N_ESR_APB1, | 186 | cgu_reset_sel_stage_clocks(PNX0101_FIRST_ESR_APB1, PNX0101_N_ESR_APB1, |
@@ -285,7 +244,7 @@ static void undefined_int(void) | |||
285 | 244 | ||
286 | void irq(void) | 245 | void irq(void) |
287 | { | 246 | { |
288 | int n; | 247 | unsigned long n; |
289 | IRQ_READ(INTVECTOR[0], n) | 248 | IRQ_READ(INTVECTOR[0], n) |
290 | (*(interrupt_vector[n >> 3]))(); | 249 | (*(interrupt_vector[n >> 3]))(); |
291 | } | 250 | } |
@@ -323,7 +282,7 @@ void system_init(void) | |||
323 | IRQ_WRITE_WAIT(INTPRIOMASK[1], 0, v == 0); | 282 | IRQ_WRITE_WAIT(INTPRIOMASK[1], 0, v == 0); |
324 | */ | 283 | */ |
325 | 284 | ||
326 | for (i = 0; i < 0x1c; i++) | 285 | for (i = 1; i <= 0x1c; i++) |
327 | { | 286 | { |
328 | IRQ_WRITE_WAIT(INTREQ[i], | 287 | IRQ_WRITE_WAIT(INTREQ[i], |
329 | INTREQ_WEPRIO | INTREQ_WETARGET | | 288 | INTREQ_WEPRIO | INTREQ_WETARGET | |
@@ -331,7 +290,7 @@ void system_init(void) | |||
331 | (v & 0x3010f) == 1); | 290 | (v & 0x3010f) == 1); |
332 | IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEENABLE, (v & 0x10000) == 0); | 291 | IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEENABLE, (v & 0x10000) == 0); |
333 | IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEPRIO | 1, (v & 0xf) == 1); | 292 | IRQ_WRITE_WAIT(INTREQ[i], INTREQ_WEPRIO | 1, (v & 0xf) == 1); |
334 | interrupt_vector[i + 1] = undefined_int; | 293 | interrupt_vector[i] = undefined_int; |
335 | } | 294 | } |
336 | interrupt_vector[0] = undefined_int; | 295 | interrupt_vector[0] = undefined_int; |
337 | pnx0101_init_clocks(); | 296 | pnx0101_init_clocks(); |