summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Malesinski <tomal@rockbox.org>2007-09-20 22:13:48 +0000
committerTomasz Malesinski <tomal@rockbox.org>2007-09-20 22:13:48 +0000
commit026032f06d162a3ca82cd8ce5ec4f8562707daca (patch)
treee73f65643c40bfbb386c813d771f8fe4b6142201
parentd14d6246c09861cd7cdb9b54ff202a8e89aa3f16 (diff)
downloadrockbox-026032f06d162a3ca82cd8ce5ec4f8562707daca.tar.gz
rockbox-026032f06d162a3ca82cd8ce5ec4f8562707daca.zip
PNX0101: new register names and polishing support for Clock Generation Unit
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@14792 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/export/pnx0101.h38
-rw-r--r--firmware/target/arm/pnx0101/system-pnx0101.c111
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
225struct 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
238struct 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
247struct 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}
31perf_modes[3] ICONST_ATTR = 30perf_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
38static int performance_mode, bus_divider; 37static 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
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) 91static 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. */
109static inline void *noncached(void *p) { 103static 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
114static void do_set_mem_timings(int mode) ICODE_ATTR; 109 run this routine from uncached copy of IRAM. All times are in CPU
115static 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. */
113static void do_set_mem_timings(void) ICODE_ATTR;
114static 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
137static void emc_set_mem_timings(int mode) { 136static void emc_set_mem_timings(void)
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{ 137{
162 while (n > 0) 138 void (*f)(void) = noncached(do_set_mem_timings);
163 { 139 (*f)();
164 n--;
165 }
166} 140}
167 141
168static void cgu_set_sys_mult(int i) 142static void cgu_set_sys_mult(int i)
@@ -193,22 +167,10 @@ static void cgu_set_sys_mult(int i)
193static void pnx0101_set_performance_mode(int mode) 167static 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
286void irq(void) 245void 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();