summaryrefslogtreecommitdiffstats
path: root/hw/ppc.c
diff options
context:
space:
mode:
authorj_mayer2007-04-16 22:09:45 +0200
committerj_mayer2007-04-16 22:09:45 +0200
commit8ecc7913525ecb6a1a41ceceac93d485a544054f (patch)
treec23ccf196aa6cf9436dcda3c80decad4c1540a92 /hw/ppc.c
parentSparc host update (Ben Taylor, Martin Bochnig) (diff)
downloadqemu-8ecc7913525ecb6a1a41ceceac93d485a544054f.tar.gz
qemu-8ecc7913525ecb6a1a41ceceac93d485a544054f.tar.xz
qemu-8ecc7913525ecb6a1a41ceceac93d485a544054f.zip
Add callbacks to allow dynamic change of PowerPC clocks (to be improved)
Fix embedded PowerPC watchdog and timers Fix PowerPC 405 SPR Add generic PowerPC 405 core instanciation code + resets support. Implement simple peripherals shared by most PowerPC 405 implementations PowerPC 405 EC & EP microcontrollers preliminary support git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2690 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw/ppc.c')
-rw-r--r--hw/ppc.c97
1 files changed, 68 insertions, 29 deletions
diff --git a/hw/ppc.c b/hw/ppc.c
index 62e9e1b1e7..1f6efee139 100644
--- a/hw/ppc.c
+++ b/hw/ppc.c
@@ -290,33 +290,55 @@ static void ppc405_set_irq (void *opaque, int pin, int level)
int cur_level;
#if defined(PPC_DEBUG_IRQ)
- printf("%s: env %p pin %d level %d\n", __func__, env, pin, level);
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+ env, pin, level);
+ }
#endif
cur_level = (env->irq_input_state >> pin) & 1;
/* Don't generate spurious events */
if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
switch (pin) {
case PPC405_INPUT_RESET_SYS:
- /* XXX: TODO: reset all peripherals */
- /* No break here */
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the PowerPC system\n",
+ __func__);
+ }
+#endif
+ ppc40x_system_reset(env);
+ }
+ break;
case PPC405_INPUT_RESET_CHIP:
- /* XXX: TODO: reset on-chip peripherals */
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
+ }
+#endif
+ ppc40x_chip_reset(env);
+ }
+ break;
/* No break here */
case PPC405_INPUT_RESET_CORE:
/* XXX: TODO: update DBSR[MRR] */
if (level) {
-#if 0 // XXX: TOFIX
#if defined(PPC_DEBUG_IRQ)
- printf("%s: reset the CPU\n", __func__);
-#endif
- cpu_reset(env);
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
+ }
#endif
+ ppc40x_core_reset(env);
}
break;
case PPC405_INPUT_CINT:
/* Level sensitive - active high */
#if defined(PPC_DEBUG_IRQ)
- printf("%s: set the critical IRQ state to %d\n", __func__, level);
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the critical IRQ state to %d\n",
+ __func__, level);
+ }
#endif
/* XXX: TOFIX */
ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
@@ -538,8 +560,21 @@ static void cpu_ppc_decr_cb (void *opaque)
_cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
}
+static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
+{
+ CPUState *env = opaque;
+ ppc_tb_t *tb_env = env->tb_env;
+
+ tb_env->tb_freq = freq;
+ /* There is a bug in Linux 2.4 kernels:
+ * if a decrementer exception is pending when it enables msr_ee at startup,
+ * it's not ready to handle it...
+ */
+ _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+}
+
/* Set up (once) timebase frequency (in Hz) */
-ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
{
ppc_tb_t *tb_env;
@@ -547,23 +582,15 @@ ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
if (tb_env == NULL)
return NULL;
env->tb_env = tb_env;
- if (tb_env->tb_freq == 0 || 1) {
- tb_env->tb_freq = freq;
- /* Create new timer */
- tb_env->decr_timer =
- qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
- /* There is a bug in Linux 2.4 kernels:
- * if a decrementer exception is pending when it enables msr_ee,
- * it's not ready to handle it...
- */
- _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
- }
+ /* Create new timer */
+ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
+ cpu_ppc_set_tb_clk(env, freq);
- return tb_env;
+ return &cpu_ppc_set_tb_clk;
}
/* Specific helpers for POWER & PowerPC 601 RTC */
-ppc_tb_t *cpu_ppc601_rtc_init (CPUState *env)
+clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
{
return cpu_ppc_tb_init(env, 7812500);
}
@@ -733,10 +760,14 @@ static void cpu_4xx_wdt_cb (void *opaque)
/* No reset */
break;
case 0x1: /* Core reset */
+ ppc40x_core_reset(env);
+ break;
case 0x2: /* Chip reset */
+ ppc40x_chip_reset(env);
+ break;
case 0x3: /* System reset */
- qemu_system_reset_request();
- return;
+ ppc40x_system_reset(env);
+ break;
}
}
}
@@ -784,20 +815,25 @@ void store_booke_tsr (CPUState *env, target_ulong val)
void store_booke_tcr (CPUState *env, target_ulong val)
{
- /* We don't update timers now. Maybe we should... */
env->spr[SPR_40x_TCR] = val & 0xFF800000;
+ cpu_4xx_wdt_cb(env);
}
-void ppc_emb_timers_init (CPUState *env)
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
{
ppc_tb_t *tb_env;
ppcemb_timer_t *ppcemb_timer;
- tb_env = env->tb_env;
+ tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+ if (tb_env == NULL)
+ return NULL;
+ env->tb_env = tb_env;
ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
+ tb_env->tb_freq = freq;
tb_env->opaque = ppcemb_timer;
- if (loglevel)
+ if (loglevel) {
fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
+ }
if (ppcemb_timer != NULL) {
/* We use decr timer for PIT */
tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
@@ -806,6 +842,9 @@ void ppc_emb_timers_init (CPUState *env)
ppcemb_timer->wdt_timer =
qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
}
+
+ /* XXX: TODO: add callback for clock frequency change */
+ return NULL;
}
/*****************************************************************************/