Commit 5439779e84e352f20ee2d3e26daec81292f1b59a
1 parent
2ea815ca
ETRAX: Allow boot from flash. Support the watchdog timer and resets through it.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@4592 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
2 changed files
with
163 additions
and
82 deletions
hw/etraxfs.c
| @@ -32,25 +32,29 @@ | @@ -32,25 +32,29 @@ | ||
| 32 | 32 | ||
| 33 | #include "etraxfs_dma.h" | 33 | #include "etraxfs_dma.h" |
| 34 | 34 | ||
| 35 | -static void main_cpu_reset(void *opaque) | ||
| 36 | -{ | ||
| 37 | - CPUState *env = opaque; | ||
| 38 | - cpu_reset(env); | ||
| 39 | -} | ||
| 40 | - | ||
| 41 | /* Init functions for different blocks. */ | 35 | /* Init functions for different blocks. */ |
| 42 | extern qemu_irq *etraxfs_pic_init(CPUState *env, target_phys_addr_t base); | 36 | extern qemu_irq *etraxfs_pic_init(CPUState *env, target_phys_addr_t base); |
| 43 | void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, | 37 | void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, |
| 44 | - target_phys_addr_t base); | ||
| 45 | -void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | ||
| 46 | - qemu_irq *irq, target_phys_addr_t base); | 38 | + target_phys_addr_t base); |
| 39 | +void *etraxfs_eth_init(NICInfo *nd, CPUState *env, | ||
| 40 | + qemu_irq *irq, target_phys_addr_t base); | ||
| 47 | void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, | 41 | void etraxfs_ser_init(CPUState *env, qemu_irq *irq, CharDriverState *chr, |
| 48 | - target_phys_addr_t base); | 42 | + target_phys_addr_t base); |
| 49 | 43 | ||
| 50 | #define FLASH_SIZE 0x2000000 | 44 | #define FLASH_SIZE 0x2000000 |
| 51 | #define INTMEM_SIZE (128 * 1024) | 45 | #define INTMEM_SIZE (128 * 1024) |
| 52 | 46 | ||
| 53 | static void *etraxfs_dmac; | 47 | static void *etraxfs_dmac; |
| 48 | +static uint32_t bootstrap_pc; | ||
| 49 | + | ||
| 50 | +static void main_cpu_reset(void *opaque) | ||
| 51 | +{ | ||
| 52 | + CPUState *env = opaque; | ||
| 53 | + cpu_reset(env); | ||
| 54 | + | ||
| 55 | + env->pregs[PR_CCS] &= ~I_FLAG; | ||
| 56 | + env->pc = bootstrap_pc; | ||
| 57 | +} | ||
| 54 | 58 | ||
| 55 | static | 59 | static |
| 56 | void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | 60 | void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, |
| @@ -64,6 +68,7 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | @@ -64,6 +68,7 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | ||
| 64 | int kernel_size; | 68 | int kernel_size; |
| 65 | int i; | 69 | int i; |
| 66 | ram_addr_t phys_ram; | 70 | ram_addr_t phys_ram; |
| 71 | + ram_addr_t phys_flash; | ||
| 67 | ram_addr_t phys_intmem; | 72 | ram_addr_t phys_intmem; |
| 68 | 73 | ||
| 69 | /* init CPUs */ | 74 | /* init CPUs */ |
| @@ -83,40 +88,42 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | @@ -83,40 +88,42 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | ||
| 83 | /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the | 88 | /* The ETRAX-FS has 128Kb on chip ram, the docs refer to it as the |
| 84 | internal memory. Cached and uncached mappings. */ | 89 | internal memory. Cached and uncached mappings. */ |
| 85 | phys_intmem = qemu_ram_alloc(INTMEM_SIZE); | 90 | phys_intmem = qemu_ram_alloc(INTMEM_SIZE); |
| 86 | - cpu_register_physical_memory(0xb8000000, INTMEM_SIZE, | ||
| 87 | - phys_intmem | IO_MEM_RAM); | ||
| 88 | - cpu_register_physical_memory(0x38000000, INTMEM_SIZE, | ||
| 89 | - phys_intmem | IO_MEM_RAM); | ||
| 90 | - | ||
| 91 | - cpu_register_physical_memory(0, FLASH_SIZE, IO_MEM_ROM); | ||
| 92 | - cpu_register_physical_memory(0x80000000, FLASH_SIZE, IO_MEM_ROM); | ||
| 93 | - cpu_register_physical_memory(0x04000000, FLASH_SIZE, IO_MEM_ROM); | ||
| 94 | - cpu_register_physical_memory(0x84000000, FLASH_SIZE, | ||
| 95 | - 0x04000000 | IO_MEM_ROM); | ||
| 96 | - i = drive_get_index(IF_PFLASH, 0, 0); | ||
| 97 | - pflash_cfi02_register(0x80000000, qemu_ram_alloc(FLASH_SIZE), | ||
| 98 | - drives_table[i].bdrv, (64 * 1024), | ||
| 99 | - FLASH_SIZE >> 16, | ||
| 100 | - 1, 2, 0x0000, 0x0000, 0x0000, 0x0000, 0x555, 0x2aa); | 91 | + cpu_register_physical_memory(0xb8000000, INTMEM_SIZE, |
| 92 | + phys_intmem | IO_MEM_RAM); | ||
| 93 | + cpu_register_physical_memory(0x38000000, INTMEM_SIZE, | ||
| 94 | + phys_intmem | IO_MEM_RAM); | ||
| 95 | + | ||
| 101 | 96 | ||
| 97 | + phys_flash = qemu_ram_alloc(FLASH_SIZE); | ||
| 98 | + i = drive_get_index(IF_PFLASH, 0, 0); | ||
| 99 | + pflash_cfi02_register(0x80000000, phys_flash, | ||
| 100 | + drives_table[i].bdrv, (64 * 1024), | ||
| 101 | + FLASH_SIZE >> 16, | ||
| 102 | + 1, 2, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 103 | + 0x555, 0x2aa); | ||
| 104 | + pflash_cfi02_register(0x0, phys_flash, | ||
| 105 | + drives_table[i].bdrv, (64 * 1024), | ||
| 106 | + FLASH_SIZE >> 16, | ||
| 107 | + 1, 2, 0x0000, 0x0000, 0x0000, 0x0000, | ||
| 108 | + 0x555, 0x2aa); | ||
| 102 | pic = etraxfs_pic_init(env, 0xb001c000); | 109 | pic = etraxfs_pic_init(env, 0xb001c000); |
| 103 | etraxfs_dmac = etraxfs_dmac_init(env, 0xb0000000, 10); | 110 | etraxfs_dmac = etraxfs_dmac_init(env, 0xb0000000, 10); |
| 104 | for (i = 0; i < 10; i++) { | 111 | for (i = 0; i < 10; i++) { |
| 105 | - /* On ETRAX, odd numbered channels are inputs. */ | ||
| 106 | - etraxfs_dmac_connect(etraxfs_dmac, i, pic + 7 + i, i & 1); | 112 | + /* On ETRAX, odd numbered channels are inputs. */ |
| 113 | + etraxfs_dmac_connect(etraxfs_dmac, i, pic + 7 + i, i & 1); | ||
| 107 | } | 114 | } |
| 108 | 115 | ||
| 109 | /* Add the two ethernet blocks. */ | 116 | /* Add the two ethernet blocks. */ |
| 110 | eth[0] = etraxfs_eth_init(&nd_table[0], env, pic + 25, 0xb0034000); | 117 | eth[0] = etraxfs_eth_init(&nd_table[0], env, pic + 25, 0xb0034000); |
| 111 | if (nb_nics > 1) | 118 | if (nb_nics > 1) |
| 112 | - eth[1] = etraxfs_eth_init(&nd_table[1], env, pic + 26, 0xb0036000); | ||
| 113 | - | 119 | + eth[1] = etraxfs_eth_init(&nd_table[1], env, pic + 26, 0xb0036000); |
| 120 | + | ||
| 114 | /* The DMA Connector block is missing, hardwire things for now. */ | 121 | /* The DMA Connector block is missing, hardwire things for now. */ |
| 115 | etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); | 122 | etraxfs_dmac_connect_client(etraxfs_dmac, 0, eth[0]); |
| 116 | etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1); | 123 | etraxfs_dmac_connect_client(etraxfs_dmac, 1, eth[0] + 1); |
| 117 | if (eth[1]) { | 124 | if (eth[1]) { |
| 118 | - etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]); | ||
| 119 | - etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1); | 125 | + etraxfs_dmac_connect_client(etraxfs_dmac, 6, eth[1]); |
| 126 | + etraxfs_dmac_connect_client(etraxfs_dmac, 7, eth[1] + 1); | ||
| 120 | } | 127 | } |
| 121 | 128 | ||
| 122 | /* 2 timers. */ | 129 | /* 2 timers. */ |
| @@ -124,40 +131,31 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | @@ -124,40 +131,31 @@ void bareetraxfs_init (ram_addr_t ram_size, int vga_ram_size, | ||
| 124 | etraxfs_timer_init(env, pic + 0x1b, 0xb005e000); | 131 | etraxfs_timer_init(env, pic + 0x1b, 0xb005e000); |
| 125 | 132 | ||
| 126 | for (i = 0; i < 4; i++) { | 133 | for (i = 0; i < 4; i++) { |
| 127 | - if (serial_hds[i]) { | ||
| 128 | - etraxfs_ser_init(env, pic + 0x14 + i, | ||
| 129 | - serial_hds[i], 0xb0026000 + i * 0x2000); | ||
| 130 | - } | 134 | + if (serial_hds[i]) { |
| 135 | + etraxfs_ser_init(env, pic + 0x14 + i, | ||
| 136 | + serial_hds[i], 0xb0026000 + i * 0x2000); | ||
| 137 | + } | ||
| 131 | } | 138 | } |
| 132 | 139 | ||
| 140 | + if (kernel_filename) { | ||
| 133 | #if 1 | 141 | #if 1 |
| 134 | - /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis devboard | ||
| 135 | - SDK. */ | ||
| 136 | - kernel_size = load_elf(kernel_filename, 0, &env->pc, NULL, NULL); | 142 | + /* Boots a kernel elf binary, os/linux-2.6/vmlinux from the axis |
| 143 | + devboard SDK. */ | ||
| 144 | + kernel_size = load_elf(kernel_filename, 0, | ||
| 145 | + &bootstrap_pc, NULL, NULL); | ||
| 137 | #else | 146 | #else |
| 138 | - /* Takes a kimage from the axis devboard SDK. */ | ||
| 139 | - kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); | ||
| 140 | - env->pc = 0x40004000; | 147 | + /* Takes a kimage from the axis devboard SDK. */ |
| 148 | + kernel_size = load_image(kernel_filename, phys_ram_base + 0x4000); | ||
| 149 | + bootstrap_pc = 0x40004000; | ||
| 150 | + /* magic for boot. */ | ||
| 151 | + env->regs[8] = 0x56902387; | ||
| 152 | + env->regs[9] = 0x40004000 + kernel_size; | ||
| 141 | #endif | 153 | #endif |
| 142 | - /* magic for boot. */ | ||
| 143 | - env->regs[8] = 0x56902387; | ||
| 144 | - env->regs[9] = 0x40004000 + kernel_size; | ||
| 145 | - | ||
| 146 | - { | ||
| 147 | - unsigned char *ptr = phys_ram_base + 0x4000; | ||
| 148 | - int i; | ||
| 149 | - for (i = 0; i < 8; i++) | ||
| 150 | - { | ||
| 151 | - printf ("%2.2x ", ptr[i]); | ||
| 152 | - } | ||
| 153 | - printf("\n"); | ||
| 154 | } | 154 | } |
| 155 | + env->pc = bootstrap_pc; | ||
| 155 | 156 | ||
| 156 | printf ("pc =%x\n", env->pc); | 157 | printf ("pc =%x\n", env->pc); |
| 157 | printf ("ram size =%ld\n", ram_size); | 158 | printf ("ram size =%ld\n", ram_size); |
| 158 | - printf ("kernel name =%s\n", kernel_filename); | ||
| 159 | - printf ("kernel size =%d\n", kernel_size); | ||
| 160 | - printf ("cpu haltd =%d\n", env->halted); | ||
| 161 | } | 159 | } |
| 162 | 160 | ||
| 163 | void DMA_run(void) | 161 | void DMA_run(void) |
| @@ -169,5 +167,5 @@ QEMUMachine bareetraxfs_machine = { | @@ -169,5 +167,5 @@ QEMUMachine bareetraxfs_machine = { | ||
| 169 | "bareetraxfs", | 167 | "bareetraxfs", |
| 170 | "Bare ETRAX FS board", | 168 | "Bare ETRAX FS board", |
| 171 | bareetraxfs_init, | 169 | bareetraxfs_init, |
| 172 | - 0x4000000, | 170 | + 0x8000000, |
| 173 | }; | 171 | }; |
hw/etraxfs_timer.c
| @@ -24,6 +24,7 @@ | @@ -24,6 +24,7 @@ | ||
| 24 | #include <stdio.h> | 24 | #include <stdio.h> |
| 25 | #include <sys/time.h> | 25 | #include <sys/time.h> |
| 26 | #include "hw.h" | 26 | #include "hw.h" |
| 27 | +#include "sysemu.h" | ||
| 27 | #include "qemu-timer.h" | 28 | #include "qemu-timer.h" |
| 28 | 29 | ||
| 29 | #define D(x) | 30 | #define D(x) |
| @@ -36,6 +37,7 @@ | @@ -36,6 +37,7 @@ | ||
| 36 | #define RW_TMR1_CTRL 0x18 | 37 | #define RW_TMR1_CTRL 0x18 |
| 37 | #define R_TIME 0x38 | 38 | #define R_TIME 0x38 |
| 38 | #define RW_WD_CTRL 0x40 | 39 | #define RW_WD_CTRL 0x40 |
| 40 | +#define R_WD_STAT 0x44 | ||
| 39 | #define RW_INTR_MASK 0x48 | 41 | #define RW_INTR_MASK 0x48 |
| 40 | #define RW_ACK_INTR 0x4c | 42 | #define RW_ACK_INTR 0x4c |
| 41 | #define R_INTR 0x50 | 43 | #define R_INTR 0x50 |
| @@ -46,8 +48,12 @@ struct fs_timer_t { | @@ -46,8 +48,12 @@ struct fs_timer_t { | ||
| 46 | qemu_irq *irq; | 48 | qemu_irq *irq; |
| 47 | target_phys_addr_t base; | 49 | target_phys_addr_t base; |
| 48 | 50 | ||
| 49 | - QEMUBH *bh; | ||
| 50 | - ptimer_state *ptimer; | 51 | + QEMUBH *bh_t0; |
| 52 | + QEMUBH *bh_t1; | ||
| 53 | + QEMUBH *bh_wd; | ||
| 54 | + ptimer_state *ptimer_t0; | ||
| 55 | + ptimer_state *ptimer_t1; | ||
| 56 | + ptimer_state *ptimer_wd; | ||
| 51 | struct timeval last; | 57 | struct timeval last; |
| 52 | 58 | ||
| 53 | /* Control registers. */ | 59 | /* Control registers. */ |
| @@ -59,6 +65,8 @@ struct fs_timer_t { | @@ -59,6 +65,8 @@ struct fs_timer_t { | ||
| 59 | uint32_t r_tmr1_data; | 65 | uint32_t r_tmr1_data; |
| 60 | uint32_t rw_tmr1_ctrl; | 66 | uint32_t rw_tmr1_ctrl; |
| 61 | 67 | ||
| 68 | + uint32_t rw_wd_ctrl; | ||
| 69 | + | ||
| 62 | uint32_t rw_intr_mask; | 70 | uint32_t rw_intr_mask; |
| 63 | uint32_t rw_ack_intr; | 71 | uint32_t rw_ack_intr; |
| 64 | uint32_t r_intr; | 72 | uint32_t r_intr; |
| @@ -114,15 +122,28 @@ timer_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -114,15 +122,28 @@ timer_winvalid (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
| 114 | } | 122 | } |
| 115 | 123 | ||
| 116 | #define TIMER_SLOWDOWN 1 | 124 | #define TIMER_SLOWDOWN 1 |
| 117 | -static void update_ctrl(struct fs_timer_t *t) | 125 | +static void update_ctrl(struct fs_timer_t *t, int tnum) |
| 118 | { | 126 | { |
| 119 | unsigned int op; | 127 | unsigned int op; |
| 120 | unsigned int freq; | 128 | unsigned int freq; |
| 121 | unsigned int freq_hz; | 129 | unsigned int freq_hz; |
| 122 | unsigned int div; | 130 | unsigned int div; |
| 131 | + uint32_t ctrl; | ||
| 132 | + ptimer_state *timer; | ||
| 133 | + | ||
| 134 | + if (tnum == 0) { | ||
| 135 | + ctrl = t->rw_tmr0_ctrl; | ||
| 136 | + div = t->rw_tmr0_div; | ||
| 137 | + timer = t->ptimer_t0; | ||
| 138 | + } else { | ||
| 139 | + ctrl = t->rw_tmr1_ctrl; | ||
| 140 | + div = t->rw_tmr1_div; | ||
| 141 | + timer = t->ptimer_t1; | ||
| 142 | + } | ||
| 143 | + | ||
| 123 | 144 | ||
| 124 | - op = t->rw_tmr0_ctrl & 3; | ||
| 125 | - freq = t->rw_tmr0_ctrl >> 2; | 145 | + op = ctrl & 3; |
| 146 | + freq = ctrl >> 2; | ||
| 126 | freq_hz = 32000000; | 147 | freq_hz = 32000000; |
| 127 | 148 | ||
| 128 | switch (freq) | 149 | switch (freq) |
| @@ -134,33 +155,32 @@ static void update_ctrl(struct fs_timer_t *t) | @@ -134,33 +155,32 @@ static void update_ctrl(struct fs_timer_t *t) | ||
| 134 | case 4: freq_hz = 29493000; break; | 155 | case 4: freq_hz = 29493000; break; |
| 135 | case 5: freq_hz = 32000000; break; | 156 | case 5: freq_hz = 32000000; break; |
| 136 | case 6: freq_hz = 32768000; break; | 157 | case 6: freq_hz = 32768000; break; |
| 137 | - case 7: freq_hz = 100000000; break; | 158 | + case 7: freq_hz = 100001000; break; |
| 138 | default: | 159 | default: |
| 139 | abort(); | 160 | abort(); |
| 140 | break; | 161 | break; |
| 141 | } | 162 | } |
| 142 | 163 | ||
| 143 | - D(printf ("freq_hz=%d div=%d\n", freq_hz, t->rw_tmr0_div)); | ||
| 144 | - div = t->rw_tmr0_div * TIMER_SLOWDOWN; | 164 | + D(printf ("freq_hz=%d div=%d\n", freq_hz, div)); |
| 165 | + div = div * TIMER_SLOWDOWN; | ||
| 145 | div >>= 15; | 166 | div >>= 15; |
| 146 | freq_hz >>= 15; | 167 | freq_hz >>= 15; |
| 147 | - ptimer_set_freq(t->ptimer, freq_hz); | ||
| 148 | - ptimer_set_limit(t->ptimer, div, 0); | 168 | + ptimer_set_freq(timer, freq_hz); |
| 169 | + ptimer_set_limit(timer, div, 0); | ||
| 149 | 170 | ||
| 150 | switch (op) | 171 | switch (op) |
| 151 | { | 172 | { |
| 152 | case 0: | 173 | case 0: |
| 153 | /* Load. */ | 174 | /* Load. */ |
| 154 | - ptimer_set_limit(t->ptimer, div, 1); | ||
| 155 | - ptimer_run(t->ptimer, 1); | 175 | + ptimer_set_limit(timer, div, 1); |
| 156 | break; | 176 | break; |
| 157 | case 1: | 177 | case 1: |
| 158 | /* Hold. */ | 178 | /* Hold. */ |
| 159 | - ptimer_stop(t->ptimer); | 179 | + ptimer_stop(timer); |
| 160 | break; | 180 | break; |
| 161 | case 2: | 181 | case 2: |
| 162 | /* Run. */ | 182 | /* Run. */ |
| 163 | - ptimer_run(t->ptimer, 0); | 183 | + ptimer_run(timer, 0); |
| 164 | break; | 184 | break; |
| 165 | default: | 185 | default: |
| 166 | abort(); | 186 | abort(); |
| @@ -180,13 +200,55 @@ static void timer_update_irq(struct fs_timer_t *t) | @@ -180,13 +200,55 @@ static void timer_update_irq(struct fs_timer_t *t) | ||
| 180 | qemu_irq_lower(t->irq[0]); | 200 | qemu_irq_lower(t->irq[0]); |
| 181 | } | 201 | } |
| 182 | 202 | ||
| 183 | -static void timer_hit(void *opaque) | 203 | +static void timer0_hit(void *opaque) |
| 184 | { | 204 | { |
| 185 | struct fs_timer_t *t = opaque; | 205 | struct fs_timer_t *t = opaque; |
| 186 | t->r_intr |= 1; | 206 | t->r_intr |= 1; |
| 187 | timer_update_irq(t); | 207 | timer_update_irq(t); |
| 188 | } | 208 | } |
| 189 | 209 | ||
| 210 | +static void timer1_hit(void *opaque) | ||
| 211 | +{ | ||
| 212 | + struct fs_timer_t *t = opaque; | ||
| 213 | + t->r_intr |= 2; | ||
| 214 | + timer_update_irq(t); | ||
| 215 | +} | ||
| 216 | + | ||
| 217 | +static void watchdog_hit(void *opaque) | ||
| 218 | +{ | ||
| 219 | + qemu_system_reset_request(); | ||
| 220 | +} | ||
| 221 | + | ||
| 222 | +static inline void timer_watchdog_update(struct fs_timer_t *t, uint32_t value) | ||
| 223 | +{ | ||
| 224 | + unsigned int wd_en = t->rw_wd_ctrl & (1 << 8); | ||
| 225 | + unsigned int wd_key = t->rw_wd_ctrl >> 9; | ||
| 226 | + unsigned int wd_cnt = t->rw_wd_ctrl & 511; | ||
| 227 | + unsigned int new_key = value >> 9 & ((1 << 7) - 1); | ||
| 228 | + unsigned int new_cmd = (value >> 8) & 1; | ||
| 229 | + | ||
| 230 | + /* If the watchdog is enabled, they written key must match the | ||
| 231 | + complement of the previous. */ | ||
| 232 | + wd_key = ~wd_key & ((1 << 7) - 1); | ||
| 233 | + | ||
| 234 | + if (wd_en && wd_key != new_key) | ||
| 235 | + return; | ||
| 236 | + | ||
| 237 | + D(printf("en=%d new_key=%x oldkey=%x cmd=%d cnt=%d\n", | ||
| 238 | + wd_en, new_key, wd_key, wd_cmd, wd_cnt)); | ||
| 239 | + | ||
| 240 | + ptimer_set_freq(t->ptimer_wd, 760); | ||
| 241 | + if (wd_cnt == 0) | ||
| 242 | + wd_cnt = 256; | ||
| 243 | + ptimer_set_count(t->ptimer_wd, wd_cnt); | ||
| 244 | + if (new_cmd) | ||
| 245 | + ptimer_run(t->ptimer_wd, 1); | ||
| 246 | + else | ||
| 247 | + ptimer_stop(t->ptimer_wd); | ||
| 248 | + | ||
| 249 | + t->rw_wd_ctrl = value; | ||
| 250 | +} | ||
| 251 | + | ||
| 190 | static void | 252 | static void |
| 191 | timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | 253 | timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) |
| 192 | { | 254 | { |
| @@ -203,13 +265,15 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -203,13 +265,15 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
| 203 | case RW_TMR0_CTRL: | 265 | case RW_TMR0_CTRL: |
| 204 | D(printf ("RW_TMR0_CTRL=%x\n", value)); | 266 | D(printf ("RW_TMR0_CTRL=%x\n", value)); |
| 205 | t->rw_tmr0_ctrl = value; | 267 | t->rw_tmr0_ctrl = value; |
| 206 | - update_ctrl(t); | 268 | + update_ctrl(t, 0); |
| 207 | break; | 269 | break; |
| 208 | case RW_TMR1_DIV: | 270 | case RW_TMR1_DIV: |
| 209 | t->rw_tmr1_div = value; | 271 | t->rw_tmr1_div = value; |
| 210 | break; | 272 | break; |
| 211 | case RW_TMR1_CTRL: | 273 | case RW_TMR1_CTRL: |
| 212 | D(printf ("RW_TMR1_CTRL=%x\n", value)); | 274 | D(printf ("RW_TMR1_CTRL=%x\n", value)); |
| 275 | + t->rw_tmr1_ctrl = value; | ||
| 276 | + update_ctrl(t, 1); | ||
| 213 | break; | 277 | break; |
| 214 | case RW_INTR_MASK: | 278 | case RW_INTR_MASK: |
| 215 | D(printf ("RW_INTR_MASK=%x\n", value)); | 279 | D(printf ("RW_INTR_MASK=%x\n", value)); |
| @@ -217,7 +281,7 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -217,7 +281,7 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
| 217 | timer_update_irq(t); | 281 | timer_update_irq(t); |
| 218 | break; | 282 | break; |
| 219 | case RW_WD_CTRL: | 283 | case RW_WD_CTRL: |
| 220 | - D(printf ("RW_WD_CTRL=%x\n", value)); | 284 | + timer_watchdog_update(t, value); |
| 221 | break; | 285 | break; |
| 222 | case RW_ACK_INTR: | 286 | case RW_ACK_INTR: |
| 223 | t->rw_ack_intr = value; | 287 | t->rw_ack_intr = value; |
| @@ -232,17 +296,30 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | @@ -232,17 +296,30 @@ timer_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
| 232 | } | 296 | } |
| 233 | 297 | ||
| 234 | static CPUReadMemoryFunc *timer_read[] = { | 298 | static CPUReadMemoryFunc *timer_read[] = { |
| 235 | - &timer_rinvalid, | ||
| 236 | - &timer_rinvalid, | ||
| 237 | - &timer_readl, | 299 | + &timer_rinvalid, |
| 300 | + &timer_rinvalid, | ||
| 301 | + &timer_readl, | ||
| 238 | }; | 302 | }; |
| 239 | 303 | ||
| 240 | static CPUWriteMemoryFunc *timer_write[] = { | 304 | static CPUWriteMemoryFunc *timer_write[] = { |
| 241 | - &timer_winvalid, | ||
| 242 | - &timer_winvalid, | ||
| 243 | - &timer_writel, | 305 | + &timer_winvalid, |
| 306 | + &timer_winvalid, | ||
| 307 | + &timer_writel, | ||
| 244 | }; | 308 | }; |
| 245 | 309 | ||
| 310 | +static void etraxfs_timer_reset(void *opaque) | ||
| 311 | +{ | ||
| 312 | + struct fs_timer_t *t = opaque; | ||
| 313 | + | ||
| 314 | + ptimer_stop(t->ptimer_t0); | ||
| 315 | + ptimer_stop(t->ptimer_t1); | ||
| 316 | + ptimer_stop(t->ptimer_wd); | ||
| 317 | + t->rw_wd_ctrl = 0; | ||
| 318 | + t->r_intr = 0; | ||
| 319 | + t->rw_intr_mask = 0; | ||
| 320 | + qemu_irq_lower(t->irq[0]); | ||
| 321 | +} | ||
| 322 | + | ||
| 246 | void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, | 323 | void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, |
| 247 | target_phys_addr_t base) | 324 | target_phys_addr_t base) |
| 248 | { | 325 | { |
| @@ -253,12 +330,18 @@ void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, | @@ -253,12 +330,18 @@ void etraxfs_timer_init(CPUState *env, qemu_irq *irqs, | ||
| 253 | if (!t) | 330 | if (!t) |
| 254 | return; | 331 | return; |
| 255 | 332 | ||
| 256 | - t->bh = qemu_bh_new(timer_hit, t); | ||
| 257 | - t->ptimer = ptimer_init(t->bh); | 333 | + t->bh_t0 = qemu_bh_new(timer0_hit, t); |
| 334 | + t->bh_t1 = qemu_bh_new(timer1_hit, t); | ||
| 335 | + t->bh_wd = qemu_bh_new(watchdog_hit, t); | ||
| 336 | + t->ptimer_t0 = ptimer_init(t->bh_t0); | ||
| 337 | + t->ptimer_t1 = ptimer_init(t->bh_t1); | ||
| 338 | + t->ptimer_wd = ptimer_init(t->bh_wd); | ||
| 258 | t->irq = irqs; | 339 | t->irq = irqs; |
| 259 | t->env = env; | 340 | t->env = env; |
| 260 | t->base = base; | 341 | t->base = base; |
| 261 | 342 | ||
| 262 | timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t); | 343 | timer_regs = cpu_register_io_memory(0, timer_read, timer_write, t); |
| 263 | cpu_register_physical_memory (base, 0x5c, timer_regs); | 344 | cpu_register_physical_memory (base, 0x5c, timer_regs); |
| 345 | + | ||
| 346 | + qemu_register_reset(etraxfs_timer_reset, t); | ||
| 264 | } | 347 | } |