Revision e2f8a44d
b/hw/pxa2xx.c | ||
---|---|---|
224 | 224 |
} |
225 | 225 |
}; |
226 | 226 |
|
227 |
static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm) |
|
227 |
static int pxa2xx_clkcfg_read(CPUARMState *env, const ARMCPRegInfo *ri, |
|
228 |
uint64_t *value) |
|
228 | 229 |
{ |
229 |
PXA2xxState *s = (PXA2xxState *) opaque; |
|
230 |
|
|
231 |
switch (reg) { |
|
232 |
case 6: /* Clock Configuration register */ |
|
233 |
return s->clkcfg; |
|
234 |
|
|
235 |
case 7: /* Power Mode register */ |
|
236 |
return 0; |
|
230 |
PXA2xxState *s = (PXA2xxState *)ri->opaque; |
|
231 |
*value = s->clkcfg; |
|
232 |
return 0; |
|
233 |
} |
|
237 | 234 |
|
238 |
default: |
|
239 |
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); |
|
240 |
break; |
|
235 |
static int pxa2xx_clkcfg_write(CPUARMState *env, const ARMCPRegInfo *ri, |
|
236 |
uint64_t value) |
|
237 |
{ |
|
238 |
PXA2xxState *s = (PXA2xxState *)ri->opaque; |
|
239 |
s->clkcfg = value & 0xf; |
|
240 |
if (value & 2) { |
|
241 |
printf("%s: CPU frequency change attempt\n", __func__); |
|
241 | 242 |
} |
242 | 243 |
return 0; |
243 | 244 |
} |
244 | 245 |
|
245 |
static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
|
|
246 |
uint32_t value)
|
|
246 |
static int pxa2xx_pwrmode_write(CPUARMState *env, const ARMCPRegInfo *ri,
|
|
247 |
uint64_t value)
|
|
247 | 248 |
{ |
248 |
PXA2xxState *s = (PXA2xxState *) opaque;
|
|
249 |
PXA2xxState *s = (PXA2xxState *)ri->opaque;
|
|
249 | 250 |
static const char *pwrmode[8] = { |
250 | 251 |
"Normal", "Idle", "Deep-idle", "Standby", |
251 | 252 |
"Sleep", "reserved (!)", "reserved (!)", "Deep-sleep", |
252 | 253 |
}; |
253 | 254 |
|
254 |
switch (reg) { |
|
255 |
case 6: /* Clock Configuration register */ |
|
256 |
s->clkcfg = value & 0xf; |
|
257 |
if (value & 2) |
|
258 |
printf("%s: CPU frequency change attempt\n", __FUNCTION__); |
|
255 |
if (value & 8) { |
|
256 |
printf("%s: CPU voltage change attempt\n", __func__); |
|
257 |
} |
|
258 |
switch (value & 7) { |
|
259 |
case 0: |
|
260 |
/* Do nothing */ |
|
259 | 261 |
break; |
260 | 262 |
|
261 |
case 7: /* Power Mode register */ |
|
262 |
if (value & 8) |
|
263 |
printf("%s: CPU voltage change attempt\n", __FUNCTION__); |
|
264 |
switch (value & 7) { |
|
265 |
case 0: |
|
266 |
/* Do nothing */ |
|
267 |
break; |
|
268 |
|
|
269 |
case 1: |
|
270 |
/* Idle */ |
|
271 |
if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ |
|
272 |
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); |
|
273 |
break; |
|
274 |
} |
|
275 |
/* Fall through. */ |
|
276 |
|
|
277 |
case 2: |
|
278 |
/* Deep-Idle */ |
|
263 |
case 1: |
|
264 |
/* Idle */ |
|
265 |
if (!(s->cm_regs[CCCR >> 2] & (1 << 31))) { /* CPDIS */ |
|
279 | 266 |
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); |
280 |
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ |
|
281 |
goto message; |
|
282 |
|
|
283 |
case 3: |
|
284 |
s->cpu->env.uncached_cpsr = |
|
285 |
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; |
|
286 |
s->cpu->env.cp15.c1_sys = 0; |
|
287 |
s->cpu->env.cp15.c1_coproc = 0; |
|
288 |
s->cpu->env.cp15.c2_base0 = 0; |
|
289 |
s->cpu->env.cp15.c3 = 0; |
|
290 |
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ |
|
291 |
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ |
|
292 |
|
|
293 |
/* |
|
294 |
* The scratch-pad register is almost universally used |
|
295 |
* for storing the return address on suspend. For the |
|
296 |
* lack of a resuming bootloader, perform a jump |
|
297 |
* directly to that address. |
|
298 |
*/ |
|
299 |
memset(s->cpu->env.regs, 0, 4 * 15); |
|
300 |
s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; |
|
267 |
break; |
|
268 |
} |
|
269 |
/* Fall through. */ |
|
270 |
|
|
271 |
case 2: |
|
272 |
/* Deep-Idle */ |
|
273 |
cpu_interrupt(&s->cpu->env, CPU_INTERRUPT_HALT); |
|
274 |
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ |
|
275 |
goto message; |
|
276 |
|
|
277 |
case 3: |
|
278 |
s->cpu->env.uncached_cpsr = |
|
279 |
ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I; |
|
280 |
s->cpu->env.cp15.c1_sys = 0; |
|
281 |
s->cpu->env.cp15.c1_coproc = 0; |
|
282 |
s->cpu->env.cp15.c2_base0 = 0; |
|
283 |
s->cpu->env.cp15.c3 = 0; |
|
284 |
s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */ |
|
285 |
s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */ |
|
286 |
|
|
287 |
/* |
|
288 |
* The scratch-pad register is almost universally used |
|
289 |
* for storing the return address on suspend. For the |
|
290 |
* lack of a resuming bootloader, perform a jump |
|
291 |
* directly to that address. |
|
292 |
*/ |
|
293 |
memset(s->cpu->env.regs, 0, 4 * 15); |
|
294 |
s->cpu->env.regs[15] = s->pm_regs[PSPR >> 2]; |
|
301 | 295 |
|
302 | 296 |
#if 0 |
303 |
buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
|
|
304 |
cpu_physical_memory_write(0, &buffer, 4);
|
|
305 |
buffer = s->pm_regs[PSPR >> 2];
|
|
306 |
cpu_physical_memory_write(8, &buffer, 4);
|
|
297 |
buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
|
|
298 |
cpu_physical_memory_write(0, &buffer, 4); |
|
299 |
buffer = s->pm_regs[PSPR >> 2]; |
|
300 |
cpu_physical_memory_write(8, &buffer, 4); |
|
307 | 301 |
#endif |
308 | 302 |
|
309 |
/* Suspend */ |
|
310 |
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); |
|
311 |
|
|
312 |
goto message; |
|
303 |
/* Suspend */ |
|
304 |
cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT); |
|
313 | 305 |
|
314 |
default: |
|
315 |
message: |
|
316 |
printf("%s: machine entered %s mode\n", __FUNCTION__, |
|
317 |
pwrmode[value & 7]); |
|
318 |
} |
|
319 |
break; |
|
306 |
goto message; |
|
320 | 307 |
|
321 | 308 |
default: |
322 |
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); |
|
323 |
break; |
|
309 |
message: |
|
310 |
printf("%s: machine entered %s mode\n", __func__, |
|
311 |
pwrmode[value & 7]); |
|
324 | 312 |
} |
325 |
} |
|
326 | 313 |
|
327 |
static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm) |
|
328 |
{ |
|
329 |
switch (crm) { |
|
330 |
case 0: |
|
331 |
return pxa2xx_clkpwr_read(opaque, op2, reg, crm); |
|
332 |
default: |
|
333 |
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); |
|
334 |
break; |
|
335 |
} |
|
336 | 314 |
return 0; |
337 | 315 |
} |
338 | 316 |
|
339 |
static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm, |
|
340 |
uint32_t value) |
|
341 |
{ |
|
342 |
switch (crm) { |
|
343 |
case 0: |
|
344 |
pxa2xx_clkpwr_write(opaque, op2, reg, crm, value); |
|
345 |
break; |
|
346 |
default: |
|
347 |
printf("%s: Bad register 0x%x\n", __FUNCTION__, reg); |
|
348 |
break; |
|
349 |
} |
|
350 |
} |
|
351 |
|
|
352 | 317 |
static int pxa2xx_cppmnc_read(CPUARMState *env, const ARMCPRegInfo *ri, |
353 | 318 |
uint64_t *value) |
354 | 319 |
{ |
... | ... | |
400 | 365 |
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, |
401 | 366 |
{ .name = "CPPMN3", .cp = 14, .crn = 2, .crm = 3, .opc1 = 0, .opc2 = 0, |
402 | 367 |
.access = PL1_RW, .type = ARM_CP_CONST, .resetvalue = 0 }, |
368 |
/* cp14 crn==6: CLKCFG */ |
|
369 |
{ .name = "CLKCFG", .cp = 14, .crn = 6, .crm = 0, .opc1 = 0, .opc2 = 0, |
|
370 |
.access = PL1_RW, |
|
371 |
.readfn = pxa2xx_clkcfg_read, .writefn = pxa2xx_clkcfg_write }, |
|
372 |
/* cp14 crn==7: PWRMODE */ |
|
373 |
{ .name = "PWRMODE", .cp = 14, .crn = 7, .crm = 0, .opc1 = 0, .opc2 = 0, |
|
374 |
.access = PL1_RW, |
|
375 |
.readfn = arm_cp_read_zero, .writefn = pxa2xx_pwrmode_write }, |
|
403 | 376 |
REGINFO_SENTINEL |
404 | 377 |
}; |
405 | 378 |
|
... | ... | |
2111 | 2084 |
memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); |
2112 | 2085 |
vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); |
2113 | 2086 |
|
2114 |
cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); |
|
2115 | 2087 |
pxa2xx_setup_cp14(s); |
2116 | 2088 |
|
2117 | 2089 |
s->mm_base = 0x48000000; |
... | ... | |
2243 | 2215 |
memory_region_add_subregion(address_space, s->cm_base, &s->cm_iomem); |
2244 | 2216 |
vmstate_register(NULL, 0, &vmstate_pxa2xx_cm, s); |
2245 | 2217 |
|
2246 |
cpu_arm_set_cp_io(&s->cpu->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s); |
|
2247 | 2218 |
pxa2xx_setup_cp14(s); |
2248 | 2219 |
|
2249 | 2220 |
s->mm_base = 0x48000000; |
Also available in: Unified diff