diff options
author | j_mayer | 2007-04-16 22:09:45 +0200 |
---|---|---|
committer | j_mayer | 2007-04-16 22:09:45 +0200 |
commit | 8ecc7913525ecb6a1a41ceceac93d485a544054f (patch) | |
tree | c23ccf196aa6cf9436dcda3c80decad4c1540a92 /hw/ppc.c | |
parent | Sparc host update (Ben Taylor, Martin Bochnig) (diff) | |
download | qemu-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.c | 97 |
1 files changed, 68 insertions, 29 deletions
@@ -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; } /*****************************************************************************/ |