Commit d8f699cb32c8c418b65aa6a2c252e097ae4716ae
1 parent
bfa30a38
Zeroing ITR shouldn't ack irq zero.
Fix PWT & PWL clocks, fix user refcounting for clocks, add 'hsab_ck' and 'usb_w2fc_ck'. Fix TCMI register addresses. Implement OMAP McBSP controller and connection to I2S-compatible CODECs. Add audio support for TSC2102 as an I2S CODEC. Connect TSC2102 I2S interface to CPU's McBSP1 interface in the Palm Tungsten|E. Correct '>' instead of '>>' typos. Implement GPIO PIN_CONTROL register (not in OMAP310 TRM, from OMAP1510). git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3534 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
858 additions
and
61 deletions
hw/omap.c
... | ... | @@ -254,7 +254,7 @@ static void omap_inth_write(void *opaque, target_phys_addr_t addr, |
254 | 254 | |
255 | 255 | switch (offset) { |
256 | 256 | case 0x00: /* ITR */ |
257 | - s->irqs &= value; | |
257 | + s->irqs &= value | 1; | |
258 | 258 | omap_inth_sir_update(s); |
259 | 259 | omap_inth_update(s); |
260 | 260 | return; |
... | ... | @@ -992,7 +992,7 @@ static void omap_dma_clk_update(void *opaque, int line, int on) |
992 | 992 | struct omap_dma_s *s = (struct omap_dma_s *) opaque; |
993 | 993 | |
994 | 994 | if (on) { |
995 | - s->delay = ticks_per_sec >> 5; | |
995 | + s->delay = ticks_per_sec >> 7; | |
996 | 996 | if (s->run_count) |
997 | 997 | qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); |
998 | 998 | } else { |
... | ... | @@ -1325,8 +1325,10 @@ static void omap_wd_timer_write(void *opaque, target_phys_addr_t addr, |
1325 | 1325 | s->mode |= (value >> 15) & 1; |
1326 | 1326 | if (s->last_wr == 0xf5) { |
1327 | 1327 | if ((value & 0xff) == 0xa0) { |
1328 | - s->mode = 0; | |
1329 | - omap_clk_put(s->timer.clk); | |
1328 | + if (s->mode) { | |
1329 | + s->mode = 0; | |
1330 | + omap_clk_put(s->timer.clk); | |
1331 | + } | |
1330 | 1332 | } else { |
1331 | 1333 | /* XXX: on T|E hardware somehow this has no effect, |
1332 | 1334 | * on Zire 71 it works as specified. */ |
... | ... | @@ -2217,23 +2219,23 @@ static uint32_t omap_tcmi_read(void *opaque, target_phys_addr_t addr) |
2217 | 2219 | uint32_t ret; |
2218 | 2220 | |
2219 | 2221 | switch (offset) { |
2220 | - case 0xfffecc00: /* IMIF_PRIO */ | |
2221 | - case 0xfffecc04: /* EMIFS_PRIO */ | |
2222 | - case 0xfffecc08: /* EMIFF_PRIO */ | |
2223 | - case 0xfffecc0c: /* EMIFS_CONFIG */ | |
2224 | - case 0xfffecc10: /* EMIFS_CS0_CONFIG */ | |
2225 | - case 0xfffecc14: /* EMIFS_CS1_CONFIG */ | |
2226 | - case 0xfffecc18: /* EMIFS_CS2_CONFIG */ | |
2227 | - case 0xfffecc1c: /* EMIFS_CS3_CONFIG */ | |
2228 | - case 0xfffecc24: /* EMIFF_MRS */ | |
2229 | - case 0xfffecc28: /* TIMEOUT1 */ | |
2230 | - case 0xfffecc2c: /* TIMEOUT2 */ | |
2231 | - case 0xfffecc30: /* TIMEOUT3 */ | |
2232 | - case 0xfffecc3c: /* EMIFF_SDRAM_CONFIG_2 */ | |
2233 | - case 0xfffecc40: /* EMIFS_CFG_DYN_WAIT */ | |
2222 | + case 0x00: /* IMIF_PRIO */ | |
2223 | + case 0x04: /* EMIFS_PRIO */ | |
2224 | + case 0x08: /* EMIFF_PRIO */ | |
2225 | + case 0x0c: /* EMIFS_CONFIG */ | |
2226 | + case 0x10: /* EMIFS_CS0_CONFIG */ | |
2227 | + case 0x14: /* EMIFS_CS1_CONFIG */ | |
2228 | + case 0x18: /* EMIFS_CS2_CONFIG */ | |
2229 | + case 0x1c: /* EMIFS_CS3_CONFIG */ | |
2230 | + case 0x24: /* EMIFF_MRS */ | |
2231 | + case 0x28: /* TIMEOUT1 */ | |
2232 | + case 0x2c: /* TIMEOUT2 */ | |
2233 | + case 0x30: /* TIMEOUT3 */ | |
2234 | + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ | |
2235 | + case 0x40: /* EMIFS_CFG_DYN_WAIT */ | |
2234 | 2236 | return s->tcmi_regs[offset >> 2]; |
2235 | 2237 | |
2236 | - case 0xfffecc20: /* EMIFF_SDRAM_CONFIG */ | |
2238 | + case 0x20: /* EMIFF_SDRAM_CONFIG */ | |
2237 | 2239 | ret = s->tcmi_regs[offset >> 2]; |
2238 | 2240 | s->tcmi_regs[offset >> 2] &= ~1; /* XXX: Clear SLRF on SDRAM access */ |
2239 | 2241 | /* XXX: We can try using the VGA_DIRTY flag for this */ |
... | ... | @@ -2251,23 +2253,23 @@ static void omap_tcmi_write(void *opaque, target_phys_addr_t addr, |
2251 | 2253 | int offset = addr - s->tcmi_base; |
2252 | 2254 | |
2253 | 2255 | switch (offset) { |
2254 | - case 0xfffecc00: /* IMIF_PRIO */ | |
2255 | - case 0xfffecc04: /* EMIFS_PRIO */ | |
2256 | - case 0xfffecc08: /* EMIFF_PRIO */ | |
2257 | - case 0xfffecc10: /* EMIFS_CS0_CONFIG */ | |
2258 | - case 0xfffecc14: /* EMIFS_CS1_CONFIG */ | |
2259 | - case 0xfffecc18: /* EMIFS_CS2_CONFIG */ | |
2260 | - case 0xfffecc1c: /* EMIFS_CS3_CONFIG */ | |
2261 | - case 0xfffecc20: /* EMIFF_SDRAM_CONFIG */ | |
2262 | - case 0xfffecc24: /* EMIFF_MRS */ | |
2263 | - case 0xfffecc28: /* TIMEOUT1 */ | |
2264 | - case 0xfffecc2c: /* TIMEOUT2 */ | |
2265 | - case 0xfffecc30: /* TIMEOUT3 */ | |
2266 | - case 0xfffecc3c: /* EMIFF_SDRAM_CONFIG_2 */ | |
2267 | - case 0xfffecc40: /* EMIFS_CFG_DYN_WAIT */ | |
2256 | + case 0x00: /* IMIF_PRIO */ | |
2257 | + case 0x04: /* EMIFS_PRIO */ | |
2258 | + case 0x08: /* EMIFF_PRIO */ | |
2259 | + case 0x10: /* EMIFS_CS0_CONFIG */ | |
2260 | + case 0x14: /* EMIFS_CS1_CONFIG */ | |
2261 | + case 0x18: /* EMIFS_CS2_CONFIG */ | |
2262 | + case 0x1c: /* EMIFS_CS3_CONFIG */ | |
2263 | + case 0x20: /* EMIFF_SDRAM_CONFIG */ | |
2264 | + case 0x24: /* EMIFF_MRS */ | |
2265 | + case 0x28: /* TIMEOUT1 */ | |
2266 | + case 0x2c: /* TIMEOUT2 */ | |
2267 | + case 0x30: /* TIMEOUT3 */ | |
2268 | + case 0x3c: /* EMIFF_SDRAM_CONFIG_2 */ | |
2269 | + case 0x40: /* EMIFS_CFG_DYN_WAIT */ | |
2268 | 2270 | s->tcmi_regs[offset >> 2] = value; |
2269 | 2271 | break; |
2270 | - case 0xfffecc0c: /* EMIFS_CONFIG */ | |
2272 | + case 0x0c: /* EMIFS_CONFIG */ | |
2271 | 2273 | s->tcmi_regs[offset >> 2] = (value & 0xf) | (1 << 4); |
2272 | 2274 | break; |
2273 | 2275 | |
... | ... | @@ -2441,7 +2443,7 @@ static uint32_t omap_clkm_read(void *opaque, target_phys_addr_t addr) |
2441 | 2443 | return s->clkm.arm_rstct2; |
2442 | 2444 | |
2443 | 2445 | case 0x18: /* ARM_SYSST */ |
2444 | - return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start; | |
2446 | + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start; | |
2445 | 2447 | |
2446 | 2448 | case 0x1c: /* ARM_CKOUT1 */ |
2447 | 2449 | return s->clkm.arm_ckout1; |
... | ... | @@ -2720,7 +2722,7 @@ static uint32_t omap_clkdsp_read(void *opaque, target_phys_addr_t addr) |
2720 | 2722 | return s->clkm.dsp_rstct2; |
2721 | 2723 | |
2722 | 2724 | case 0x18: /* DSP_SYSST */ |
2723 | - return (s->clkm.clocking_scheme < 11) | s->clkm.cold_start | | |
2725 | + return (s->clkm.clocking_scheme << 11) | s->clkm.cold_start | | |
2724 | 2726 | (s->env->halted << 6); /* Quite useless... */ |
2725 | 2727 | } |
2726 | 2728 | |
... | ... | @@ -2796,9 +2798,9 @@ static void omap_clkm_reset(struct omap_mpu_state_s *s) |
2796 | 2798 | s->clkm.clocking_scheme = 0; |
2797 | 2799 | omap_clkm_ckctl_update(s, ~0, 0x3000); |
2798 | 2800 | s->clkm.arm_ckctl = 0x3000; |
2799 | - omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 & 0x0400, 0x0400); | |
2801 | + omap_clkm_idlect1_update(s, s->clkm.arm_idlect1 ^ 0x0400, 0x0400); | |
2800 | 2802 | s->clkm.arm_idlect1 = 0x0400; |
2801 | - omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 & 0x0100, 0x0100); | |
2803 | + omap_clkm_idlect2_update(s, s->clkm.arm_idlect2 ^ 0x0100, 0x0100); | |
2802 | 2804 | s->clkm.arm_idlect2 = 0x0100; |
2803 | 2805 | s->clkm.arm_ewupct = 0x003f; |
2804 | 2806 | s->clkm.arm_rstct1 = 0x0000; |
... | ... | @@ -2822,8 +2824,11 @@ static void omap_clkm_init(target_phys_addr_t mpu_base, |
2822 | 2824 | |
2823 | 2825 | s->clkm.mpu_base = mpu_base; |
2824 | 2826 | s->clkm.dsp_base = dsp_base; |
2825 | - s->clkm.cold_start = 0x3a; | |
2827 | + s->clkm.arm_idlect1 = 0x03ff; | |
2828 | + s->clkm.arm_idlect2 = 0x0100; | |
2829 | + s->clkm.dsp_idlect1 = 0x0002; | |
2826 | 2830 | omap_clkm_reset(s); |
2831 | + s->clkm.cold_start = 0x3a; | |
2827 | 2832 | |
2828 | 2833 | cpu_register_physical_memory(s->clkm.mpu_base, 0x100, iomemtype[0]); |
2829 | 2834 | cpu_register_physical_memory(s->clkm.dsp_base, 0x1000, iomemtype[1]); |
... | ... | @@ -2956,9 +2961,8 @@ static void omap_mpuio_write(void *opaque, target_phys_addr_t addr, |
2956 | 2961 | |
2957 | 2962 | switch (offset) { |
2958 | 2963 | case 0x04: /* OUTPUT_REG */ |
2959 | - diff = s->outputs ^ (value & ~s->dir); | |
2964 | + diff = (s->outputs ^ value) & ~s->dir; | |
2960 | 2965 | s->outputs = value; |
2961 | - value &= ~s->dir; | |
2962 | 2966 | while ((ln = ffs(diff))) { |
2963 | 2967 | ln --; |
2964 | 2968 | if (s->handler[ln]) |
... | ... | @@ -3120,6 +3124,7 @@ struct omap_gpio_s { |
3120 | 3124 | uint16_t edge; |
3121 | 3125 | uint16_t mask; |
3122 | 3126 | uint16_t ints; |
3127 | + uint16_t pins; | |
3123 | 3128 | }; |
3124 | 3129 | |
3125 | 3130 | static void omap_gpio_set(void *opaque, int line, int level) |
... | ... | @@ -3146,7 +3151,7 @@ static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) |
3146 | 3151 | |
3147 | 3152 | switch (offset) { |
3148 | 3153 | case 0x00: /* DATA_INPUT */ |
3149 | - return s->inputs; | |
3154 | + return s->inputs & s->pins; | |
3150 | 3155 | |
3151 | 3156 | case 0x04: /* DATA_OUTPUT */ |
3152 | 3157 | return s->outputs; |
... | ... | @@ -3162,6 +3167,10 @@ static uint32_t omap_gpio_read(void *opaque, target_phys_addr_t addr) |
3162 | 3167 | |
3163 | 3168 | case 0x14: /* INTERRUPT_STATUS */ |
3164 | 3169 | return s->ints; |
3170 | + | |
3171 | + case 0x18: /* PIN_CONTROL (not in OMAP310) */ | |
3172 | + OMAP_BAD_REG(addr); | |
3173 | + return s->pins; | |
3165 | 3174 | } |
3166 | 3175 | |
3167 | 3176 | OMAP_BAD_REG(addr); |
... | ... | @@ -3219,6 +3228,11 @@ static void omap_gpio_write(void *opaque, target_phys_addr_t addr, |
3219 | 3228 | qemu_irq_lower(s->irq); |
3220 | 3229 | break; |
3221 | 3230 | |
3231 | + case 0x18: /* PIN_CONTROL (not in OMAP310 TRM) */ | |
3232 | + OMAP_BAD_REG(addr); | |
3233 | + s->pins = value; | |
3234 | + break; | |
3235 | + | |
3222 | 3236 | default: |
3223 | 3237 | OMAP_BAD_REG(addr); |
3224 | 3238 | return; |
... | ... | @@ -3246,6 +3260,7 @@ void omap_gpio_reset(struct omap_gpio_s *s) |
3246 | 3260 | s->edge = ~0; |
3247 | 3261 | s->mask = ~0; |
3248 | 3262 | s->ints = 0; |
3263 | + s->pins = ~0; | |
3249 | 3264 | } |
3250 | 3265 | |
3251 | 3266 | struct omap_gpio_s *omap_gpio_init(target_phys_addr_t base, |
... | ... | @@ -4058,6 +4073,458 @@ struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, |
4058 | 4073 | return s; |
4059 | 4074 | } |
4060 | 4075 | |
4076 | +/* Multi-channel Buffered Serial Port interfaces */ | |
4077 | +struct omap_mcbsp_s { | |
4078 | + target_phys_addr_t base; | |
4079 | + qemu_irq txirq; | |
4080 | + qemu_irq rxirq; | |
4081 | + qemu_irq txdrq; | |
4082 | + qemu_irq rxdrq; | |
4083 | + | |
4084 | + uint16_t spcr[2]; | |
4085 | + uint16_t rcr[2]; | |
4086 | + uint16_t xcr[2]; | |
4087 | + uint16_t srgr[2]; | |
4088 | + uint16_t mcr[2]; | |
4089 | + uint16_t pcr; | |
4090 | + uint16_t rcer[8]; | |
4091 | + uint16_t xcer[8]; | |
4092 | + int tx_rate; | |
4093 | + int rx_rate; | |
4094 | + int tx_req; | |
4095 | + | |
4096 | + struct i2s_codec_s *codec; | |
4097 | +}; | |
4098 | + | |
4099 | +static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) | |
4100 | +{ | |
4101 | + int irq; | |
4102 | + | |
4103 | + switch ((s->spcr[0] >> 4) & 3) { /* RINTM */ | |
4104 | + case 0: | |
4105 | + irq = (s->spcr[0] >> 1) & 1; /* RRDY */ | |
4106 | + break; | |
4107 | + case 3: | |
4108 | + irq = (s->spcr[0] >> 3) & 1; /* RSYNCERR */ | |
4109 | + break; | |
4110 | + default: | |
4111 | + irq = 0; | |
4112 | + break; | |
4113 | + } | |
4114 | + | |
4115 | + qemu_set_irq(s->rxirq, irq); | |
4116 | + | |
4117 | + switch ((s->spcr[1] >> 4) & 3) { /* XINTM */ | |
4118 | + case 0: | |
4119 | + irq = (s->spcr[1] >> 1) & 1; /* XRDY */ | |
4120 | + break; | |
4121 | + case 3: | |
4122 | + irq = (s->spcr[1] >> 3) & 1; /* XSYNCERR */ | |
4123 | + break; | |
4124 | + default: | |
4125 | + irq = 0; | |
4126 | + break; | |
4127 | + } | |
4128 | + | |
4129 | + qemu_set_irq(s->txirq, irq); | |
4130 | +} | |
4131 | + | |
4132 | +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) | |
4133 | +{ | |
4134 | + int prev = s->tx_req; | |
4135 | + | |
4136 | + s->tx_req = (s->tx_rate || | |
4137 | + (s->spcr[0] & (1 << 12))) && /* CLKSTP */ | |
4138 | + (s->spcr[1] & (1 << 6)) && /* GRST */ | |
4139 | + (s->spcr[1] & (1 << 0)); /* XRST */ | |
4140 | + | |
4141 | + if (!s->tx_req && prev) { | |
4142 | + s->spcr[1] &= ~(1 << 1); /* XRDY */ | |
4143 | + qemu_irq_lower(s->txdrq); | |
4144 | + omap_mcbsp_intr_update(s); | |
4145 | + | |
4146 | + if (s->codec) | |
4147 | + s->codec->tx_swallow(s->codec->opaque); | |
4148 | + } else if (s->codec && s->tx_req && !prev) { | |
4149 | + s->spcr[1] |= 1 << 1; /* XRDY */ | |
4150 | + qemu_irq_raise(s->txdrq); | |
4151 | + omap_mcbsp_intr_update(s); | |
4152 | + } | |
4153 | +} | |
4154 | + | |
4155 | +static void omap_mcbsp_rate_update(struct omap_mcbsp_s *s) | |
4156 | +{ | |
4157 | + int rx_clk = 0, tx_clk = 0; | |
4158 | + int cpu_rate = 1500000; /* XXX */ | |
4159 | + if (!s->codec) | |
4160 | + return; | |
4161 | + | |
4162 | + if (s->spcr[1] & (1 << 6)) { /* GRST */ | |
4163 | + if (s->spcr[0] & (1 << 0)) /* RRST */ | |
4164 | + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
4165 | + (s->pcr & (1 << 8))) /* CLKRM */ | |
4166 | + if (~s->pcr & (1 << 7)) /* SCLKME */ | |
4167 | + rx_clk = cpu_rate / | |
4168 | + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
4169 | + if (s->spcr[1] & (1 << 0)) /* XRST */ | |
4170 | + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
4171 | + (s->pcr & (1 << 9))) /* CLKXM */ | |
4172 | + if (~s->pcr & (1 << 7)) /* SCLKME */ | |
4173 | + tx_clk = cpu_rate / | |
4174 | + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
4175 | + } | |
4176 | + | |
4177 | + s->codec->set_rate(s->codec->opaque, rx_clk, tx_clk); | |
4178 | +} | |
4179 | + | |
4180 | +static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) | |
4181 | +{ | |
4182 | + if (!(s->spcr[0] & 1)) { /* RRST */ | |
4183 | + if (s->codec) | |
4184 | + s->codec->in.len = 0; | |
4185 | + return; | |
4186 | + } | |
4187 | + | |
4188 | + if ((s->spcr[0] >> 1) & 1) /* RRDY */ | |
4189 | + s->spcr[0] |= 1 << 2; /* RFULL */ | |
4190 | + s->spcr[0] |= 1 << 1; /* RRDY */ | |
4191 | + qemu_irq_raise(s->rxdrq); | |
4192 | + omap_mcbsp_intr_update(s); | |
4193 | +} | |
4194 | + | |
4195 | +static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) | |
4196 | +{ | |
4197 | + s->spcr[0] &= ~(1 << 1); /* RRDY */ | |
4198 | + qemu_irq_lower(s->rxdrq); | |
4199 | + omap_mcbsp_intr_update(s); | |
4200 | +} | |
4201 | + | |
4202 | +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) | |
4203 | +{ | |
4204 | + if (s->tx_rate) | |
4205 | + return; | |
4206 | + s->tx_rate = 1; | |
4207 | + omap_mcbsp_req_update(s); | |
4208 | +} | |
4209 | + | |
4210 | +static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) | |
4211 | +{ | |
4212 | + s->tx_rate = 0; | |
4213 | + omap_mcbsp_req_update(s); | |
4214 | +} | |
4215 | + | |
4216 | +static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) | |
4217 | +{ | |
4218 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4219 | + int offset = addr & OMAP_MPUI_REG_MASK; | |
4220 | + uint16_t ret; | |
4221 | + | |
4222 | + switch (offset) { | |
4223 | + case 0x00: /* DRR2 */ | |
4224 | + if (((s->rcr[0] >> 5) & 7) < 3) /* RWDLEN1 */ | |
4225 | + return 0x0000; | |
4226 | + /* Fall through. */ | |
4227 | + case 0x02: /* DRR1 */ | |
4228 | + if (!s->codec) | |
4229 | + return 0x0000; | |
4230 | + if (s->codec->in.len < 2) { | |
4231 | + printf("%s: Rx FIFO underrun\n", __FUNCTION__); | |
4232 | + omap_mcbsp_rx_stop(s); | |
4233 | + } else { | |
4234 | + s->codec->in.len -= 2; | |
4235 | + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; | |
4236 | + ret |= s->codec->in.fifo[s->codec->in.start ++]; | |
4237 | + if (!s->codec->in.len) | |
4238 | + omap_mcbsp_rx_stop(s); | |
4239 | + return ret; | |
4240 | + } | |
4241 | + return 0x0000; | |
4242 | + | |
4243 | + case 0x04: /* DXR2 */ | |
4244 | + case 0x06: /* DXR1 */ | |
4245 | + return 0x0000; | |
4246 | + | |
4247 | + case 0x08: /* SPCR2 */ | |
4248 | + return s->spcr[1]; | |
4249 | + case 0x0a: /* SPCR1 */ | |
4250 | + return s->spcr[0]; | |
4251 | + case 0x0c: /* RCR2 */ | |
4252 | + return s->rcr[1]; | |
4253 | + case 0x0e: /* RCR1 */ | |
4254 | + return s->rcr[0]; | |
4255 | + case 0x10: /* XCR2 */ | |
4256 | + return s->xcr[1]; | |
4257 | + case 0x12: /* XCR1 */ | |
4258 | + return s->xcr[0]; | |
4259 | + case 0x14: /* SRGR2 */ | |
4260 | + return s->srgr[1]; | |
4261 | + case 0x16: /* SRGR1 */ | |
4262 | + return s->srgr[0]; | |
4263 | + case 0x18: /* MCR2 */ | |
4264 | + return s->mcr[1]; | |
4265 | + case 0x1a: /* MCR1 */ | |
4266 | + return s->mcr[0]; | |
4267 | + case 0x1c: /* RCERA */ | |
4268 | + return s->rcer[0]; | |
4269 | + case 0x1e: /* RCERB */ | |
4270 | + return s->rcer[1]; | |
4271 | + case 0x20: /* XCERA */ | |
4272 | + return s->xcer[0]; | |
4273 | + case 0x22: /* XCERB */ | |
4274 | + return s->xcer[1]; | |
4275 | + case 0x24: /* PCR0 */ | |
4276 | + return s->pcr; | |
4277 | + case 0x26: /* RCERC */ | |
4278 | + return s->rcer[2]; | |
4279 | + case 0x28: /* RCERD */ | |
4280 | + return s->rcer[3]; | |
4281 | + case 0x2a: /* XCERC */ | |
4282 | + return s->xcer[2]; | |
4283 | + case 0x2c: /* XCERD */ | |
4284 | + return s->xcer[3]; | |
4285 | + case 0x2e: /* RCERE */ | |
4286 | + return s->rcer[4]; | |
4287 | + case 0x30: /* RCERF */ | |
4288 | + return s->rcer[5]; | |
4289 | + case 0x32: /* XCERE */ | |
4290 | + return s->xcer[4]; | |
4291 | + case 0x34: /* XCERF */ | |
4292 | + return s->xcer[5]; | |
4293 | + case 0x36: /* RCERG */ | |
4294 | + return s->rcer[6]; | |
4295 | + case 0x38: /* RCERH */ | |
4296 | + return s->rcer[7]; | |
4297 | + case 0x3a: /* XCERG */ | |
4298 | + return s->xcer[6]; | |
4299 | + case 0x3c: /* XCERH */ | |
4300 | + return s->xcer[7]; | |
4301 | + } | |
4302 | + | |
4303 | + OMAP_BAD_REG(addr); | |
4304 | + return 0; | |
4305 | +} | |
4306 | + | |
4307 | +static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, | |
4308 | + uint32_t value) | |
4309 | +{ | |
4310 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4311 | + int offset = addr & OMAP_MPUI_REG_MASK; | |
4312 | + | |
4313 | + switch (offset) { | |
4314 | + case 0x00: /* DRR2 */ | |
4315 | + case 0x02: /* DRR1 */ | |
4316 | + OMAP_RO_REG(addr); | |
4317 | + return; | |
4318 | + | |
4319 | + case 0x04: /* DXR2 */ | |
4320 | + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ | |
4321 | + return; | |
4322 | + /* Fall through. */ | |
4323 | + case 0x06: /* DXR1 */ | |
4324 | + if (!s->codec) | |
4325 | + return; | |
4326 | + if (s->tx_req) { | |
4327 | + if (s->codec->out.len > s->codec->out.size - 2) { | |
4328 | + printf("%s: Tx FIFO overrun\n", __FUNCTION__); | |
4329 | + omap_mcbsp_tx_stop(s); | |
4330 | + } else { | |
4331 | + s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; | |
4332 | + s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; | |
4333 | + if (s->codec->out.len >= s->codec->out.size) | |
4334 | + omap_mcbsp_tx_stop(s); | |
4335 | + } | |
4336 | + } else | |
4337 | + printf("%s: Tx FIFO overrun\n", __FUNCTION__); | |
4338 | + return; | |
4339 | + | |
4340 | + case 0x08: /* SPCR2 */ | |
4341 | + s->spcr[1] &= 0x0002; | |
4342 | + s->spcr[1] |= 0x03f9 & value; | |
4343 | + s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ | |
4344 | + if (~value & 1) { /* XRST */ | |
4345 | + s->spcr[1] &= ~6; | |
4346 | + qemu_irq_lower(s->rxdrq); | |
4347 | + if (s->codec) | |
4348 | + s->codec->out.len = 0; | |
4349 | + } | |
4350 | + if (s->codec) | |
4351 | + omap_mcbsp_rate_update(s); | |
4352 | + omap_mcbsp_req_update(s); | |
4353 | + return; | |
4354 | + case 0x0a: /* SPCR1 */ | |
4355 | + s->spcr[0] &= 0x0006; | |
4356 | + s->spcr[0] |= 0xf8f9 & value; | |
4357 | + if (value & (1 << 15)) /* DLB */ | |
4358 | + printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); | |
4359 | + if (~value & 1) { /* RRST */ | |
4360 | + s->spcr[0] &= ~6; | |
4361 | + qemu_irq_lower(s->txdrq); | |
4362 | + if (s->codec) | |
4363 | + s->codec->in.len = 0; | |
4364 | + } | |
4365 | + if (s->codec) | |
4366 | + omap_mcbsp_rate_update(s); | |
4367 | + omap_mcbsp_req_update(s); | |
4368 | + return; | |
4369 | + | |
4370 | + case 0x0c: /* RCR2 */ | |
4371 | + s->rcr[1] = value & 0xffff; | |
4372 | + return; | |
4373 | + case 0x0e: /* RCR1 */ | |
4374 | + s->rcr[0] = value & 0x7fe0; | |
4375 | + return; | |
4376 | + case 0x10: /* XCR2 */ | |
4377 | + s->xcr[1] = value & 0xffff; | |
4378 | + return; | |
4379 | + case 0x12: /* XCR1 */ | |
4380 | + s->xcr[0] = value & 0x7fe0; | |
4381 | + return; | |
4382 | + case 0x14: /* SRGR2 */ | |
4383 | + s->srgr[1] = value & 0xffff; | |
4384 | + omap_mcbsp_rate_update(s); | |
4385 | + return; | |
4386 | + case 0x16: /* SRGR1 */ | |
4387 | + s->srgr[0] = value & 0xffff; | |
4388 | + omap_mcbsp_rate_update(s); | |
4389 | + return; | |
4390 | + case 0x18: /* MCR2 */ | |
4391 | + s->mcr[1] = value & 0x03e3; | |
4392 | + if (value & 3) /* XMCM */ | |
4393 | + printf("%s: Tx channel selection mode enable attempt\n", | |
4394 | + __FUNCTION__); | |
4395 | + return; | |
4396 | + case 0x1a: /* MCR1 */ | |
4397 | + s->mcr[0] = value & 0x03e1; | |
4398 | + if (value & 1) /* RMCM */ | |
4399 | + printf("%s: Rx channel selection mode enable attempt\n", | |
4400 | + __FUNCTION__); | |
4401 | + return; | |
4402 | + case 0x1c: /* RCERA */ | |
4403 | + s->rcer[0] = value & 0xffff; | |
4404 | + return; | |
4405 | + case 0x1e: /* RCERB */ | |
4406 | + s->rcer[1] = value & 0xffff; | |
4407 | + return; | |
4408 | + case 0x20: /* XCERA */ | |
4409 | + s->xcer[0] = value & 0xffff; | |
4410 | + return; | |
4411 | + case 0x22: /* XCERB */ | |
4412 | + s->xcer[1] = value & 0xffff; | |
4413 | + return; | |
4414 | + case 0x24: /* PCR0 */ | |
4415 | + s->pcr = value & 0x7faf; | |
4416 | + return; | |
4417 | + case 0x26: /* RCERC */ | |
4418 | + s->rcer[2] = value & 0xffff; | |
4419 | + return; | |
4420 | + case 0x28: /* RCERD */ | |
4421 | + s->rcer[3] = value & 0xffff; | |
4422 | + return; | |
4423 | + case 0x2a: /* XCERC */ | |
4424 | + s->xcer[2] = value & 0xffff; | |
4425 | + return; | |
4426 | + case 0x2c: /* XCERD */ | |
4427 | + s->xcer[3] = value & 0xffff; | |
4428 | + return; | |
4429 | + case 0x2e: /* RCERE */ | |
4430 | + s->rcer[4] = value & 0xffff; | |
4431 | + return; | |
4432 | + case 0x30: /* RCERF */ | |
4433 | + s->rcer[5] = value & 0xffff; | |
4434 | + return; | |
4435 | + case 0x32: /* XCERE */ | |
4436 | + s->xcer[4] = value & 0xffff; | |
4437 | + return; | |
4438 | + case 0x34: /* XCERF */ | |
4439 | + s->xcer[5] = value & 0xffff; | |
4440 | + return; | |
4441 | + case 0x36: /* RCERG */ | |
4442 | + s->rcer[6] = value & 0xffff; | |
4443 | + return; | |
4444 | + case 0x38: /* RCERH */ | |
4445 | + s->rcer[7] = value & 0xffff; | |
4446 | + return; | |
4447 | + case 0x3a: /* XCERG */ | |
4448 | + s->xcer[6] = value & 0xffff; | |
4449 | + return; | |
4450 | + case 0x3c: /* XCERH */ | |
4451 | + s->xcer[7] = value & 0xffff; | |
4452 | + return; | |
4453 | + } | |
4454 | + | |
4455 | + OMAP_BAD_REG(addr); | |
4456 | +} | |
4457 | + | |
4458 | +static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { | |
4459 | + omap_badwidth_read16, | |
4460 | + omap_mcbsp_read, | |
4461 | + omap_badwidth_read16, | |
4462 | +}; | |
4463 | + | |
4464 | +static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { | |
4465 | + omap_badwidth_write16, | |
4466 | + omap_mcbsp_write, | |
4467 | + omap_badwidth_write16, | |
4468 | +}; | |
4469 | + | |
4470 | +static void omap_mcbsp_reset(struct omap_mcbsp_s *s) | |
4471 | +{ | |
4472 | + memset(&s->spcr, 0, sizeof(s->spcr)); | |
4473 | + memset(&s->rcr, 0, sizeof(s->rcr)); | |
4474 | + memset(&s->xcr, 0, sizeof(s->xcr)); | |
4475 | + s->srgr[0] = 0x0001; | |
4476 | + s->srgr[1] = 0x2000; | |
4477 | + memset(&s->mcr, 0, sizeof(s->mcr)); | |
4478 | + memset(&s->pcr, 0, sizeof(s->pcr)); | |
4479 | + memset(&s->rcer, 0, sizeof(s->rcer)); | |
4480 | + memset(&s->xcer, 0, sizeof(s->xcer)); | |
4481 | + s->tx_req = 0; | |
4482 | + s->tx_rate = 0; | |
4483 | + s->rx_rate = 0; | |
4484 | +} | |
4485 | + | |
4486 | +struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, | |
4487 | + qemu_irq *irq, qemu_irq *dma, omap_clk clk) | |
4488 | +{ | |
4489 | + int iomemtype; | |
4490 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) | |
4491 | + qemu_mallocz(sizeof(struct omap_mcbsp_s)); | |
4492 | + | |
4493 | + s->base = base; | |
4494 | + s->txirq = irq[0]; | |
4495 | + s->rxirq = irq[1]; | |
4496 | + s->txdrq = dma[0]; | |
4497 | + s->rxdrq = dma[1]; | |
4498 | + omap_mcbsp_reset(s); | |
4499 | + | |
4500 | + iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, | |
4501 | + omap_mcbsp_writefn, s); | |
4502 | + cpu_register_physical_memory(s->base, 0x800, iomemtype); | |
4503 | + | |
4504 | + return s; | |
4505 | +} | |
4506 | + | |
4507 | +void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) | |
4508 | +{ | |
4509 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4510 | + | |
4511 | + omap_mcbsp_rx_start(s); | |
4512 | +} | |
4513 | + | |
4514 | +void omap_mcbsp_i2s_start(void *opaque, int line, int level) | |
4515 | +{ | |
4516 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
4517 | + | |
4518 | + omap_mcbsp_tx_start(s); | |
4519 | +} | |
4520 | + | |
4521 | +void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) | |
4522 | +{ | |
4523 | + s->codec = slave; | |
4524 | + slave->rx_swallow = qemu_allocate_irqs(omap_mcbsp_i2s_swallow, s, 1)[0]; | |
4525 | + slave->tx_start = qemu_allocate_irqs(omap_mcbsp_i2s_start, s, 1)[0]; | |
4526 | +} | |
4527 | + | |
4061 | 4528 | /* General chip reset */ |
4062 | 4529 | static void omap_mpu_reset(void *opaque) |
4063 | 4530 | { |
... | ... | @@ -4092,6 +4559,9 @@ static void omap_mpu_reset(void *opaque) |
4092 | 4559 | omap_pwt_reset(mpu); |
4093 | 4560 | omap_i2c_reset(mpu->i2c); |
4094 | 4561 | omap_rtc_reset(mpu->rtc); |
4562 | + omap_mcbsp_reset(mpu->mcbsp1); | |
4563 | + omap_mcbsp_reset(mpu->mcbsp2); | |
4564 | + omap_mcbsp_reset(mpu->mcbsp3); | |
4095 | 4565 | cpu_reset(mpu->env); |
4096 | 4566 | } |
4097 | 4567 | |
... | ... | @@ -4254,8 +4724,8 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, |
4254 | 4724 | s->microwire = omap_uwire_init(0xfffb3000, &s->irq[1][OMAP_INT_uWireTX], |
4255 | 4725 | s->drq[OMAP_DMA_UWIRE_TX], omap_findclk(s, "mpuper_ck")); |
4256 | 4726 | |
4257 | - omap_pwl_init(0xfffb5800, s, omap_findclk(s, "clk32-kHz")); | |
4258 | - omap_pwt_init(0xfffb6000, s, omap_findclk(s, "xtal_osc_12m")); | |
4727 | + omap_pwl_init(0xfffb5800, s, omap_findclk(s, "armxor_ck")); | |
4728 | + omap_pwt_init(0xfffb6000, s, omap_findclk(s, "armxor_ck")); | |
4259 | 4729 | |
4260 | 4730 | s->i2c = omap_i2c_init(0xfffb3800, s->irq[1][OMAP_INT_I2C], |
4261 | 4731 | &s->drq[OMAP_DMA_I2C_RX], omap_findclk(s, "mpuper_ck")); |
... | ... | @@ -4263,14 +4733,18 @@ struct omap_mpu_state_s *omap310_mpu_init(unsigned long sdram_size, |
4263 | 4733 | s->rtc = omap_rtc_init(0xfffb4800, &s->irq[1][OMAP_INT_RTC_TIMER], |
4264 | 4734 | omap_findclk(s, "clk32-kHz")); |
4265 | 4735 | |
4736 | + s->mcbsp1 = omap_mcbsp_init(0xfffb1800, &s->irq[1][OMAP_INT_McBSP1TX], | |
4737 | + &s->drq[OMAP_DMA_MCBSP1_TX], omap_findclk(s, "dspxor_ck")); | |
4738 | + s->mcbsp2 = omap_mcbsp_init(0xfffb1000, &s->irq[0][OMAP_INT_310_McBSP2_TX], | |
4739 | + &s->drq[OMAP_DMA_MCBSP2_TX], omap_findclk(s, "mpuper_ck")); | |
4740 | + s->mcbsp3 = omap_mcbsp_init(0xfffb7000, &s->irq[1][OMAP_INT_McBSP3TX], | |
4741 | + &s->drq[OMAP_DMA_MCBSP3_TX], omap_findclk(s, "dspxor_ck")); | |
4742 | + | |
4266 | 4743 | /* Register mappings not currenlty implemented: |
4267 | - * McBSP2 Comm fffb1000 - fffb17ff | |
4268 | - * McBSP1 Audio fffb1800 - fffb1fff (not mapped on OMAP310) | |
4269 | 4744 | * MCSI2 Comm fffb2000 - fffb27ff (not mapped on OMAP310) |
4270 | 4745 | * MCSI1 Bluetooth fffb2800 - fffb2fff (not mapped on OMAP310) |
4271 | 4746 | * USB W2FC fffb4000 - fffb47ff |
4272 | 4747 | * Camera Interface fffb6800 - fffb6fff |
4273 | - * McBSP3 fffb7000 - fffb77ff (not mapped on OMAP310) | |
4274 | 4748 | * USB Host fffba000 - fffba7ff |
4275 | 4749 | * FAC fffba800 - fffbafff |
4276 | 4750 | * HDQ/1-Wire fffbc000 - fffbc7ff | ... | ... |
hw/omap.h
... | ... | @@ -479,6 +479,30 @@ struct omap_rtc_s; |
479 | 479 | struct omap_rtc_s *omap_rtc_init(target_phys_addr_t base, |
480 | 480 | qemu_irq *irq, omap_clk clk); |
481 | 481 | |
482 | +struct i2s_codec_s { | |
483 | + void *opaque; | |
484 | + | |
485 | + /* The CPU can call this if it is generating the clock signal on the | |
486 | + * i2s port. The CODEC can ignore it if it is set up as a clock | |
487 | + * master and generates its own clock. */ | |
488 | + void (*set_rate)(void *opaque, int in, int out); | |
489 | + | |
490 | + void (*tx_swallow)(void *opaque); | |
491 | + qemu_irq rx_swallow; | |
492 | + qemu_irq tx_start; | |
493 | + | |
494 | + struct i2s_fifo_s { | |
495 | + uint8_t *fifo; | |
496 | + int len; | |
497 | + int start; | |
498 | + int size; | |
499 | + } in, out; | |
500 | +}; | |
501 | +struct omap_mcbsp_s; | |
502 | +struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, | |
503 | + qemu_irq *irq, qemu_irq *dma, omap_clk clk); | |
504 | +void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave); | |
505 | + | |
482 | 506 | /* omap_lcdc.c */ |
483 | 507 | struct omap_lcd_panel_s; |
484 | 508 | void omap_lcdc_reset(struct omap_lcd_panel_s *s); |
... | ... | @@ -536,6 +560,9 @@ struct omap_mpu_state_s { |
536 | 560 | |
537 | 561 | struct omap_gpio_s *gpio; |
538 | 562 | |
563 | + struct omap_mcbsp_s *mcbsp1; | |
564 | + struct omap_mcbsp_s *mcbsp3; | |
565 | + | |
539 | 566 | /* MPU public TIPB peripherals */ |
540 | 567 | struct omap_32khz_timer_s *os_timer; |
541 | 568 | |
... | ... | @@ -563,6 +590,8 @@ struct omap_mpu_state_s { |
563 | 590 | |
564 | 591 | struct omap_rtc_s *rtc; |
565 | 592 | |
593 | + struct omap_mcbsp_s *mcbsp2; | |
594 | + | |
566 | 595 | /* MPU private TIPB peripherals */ |
567 | 596 | struct omap_intr_handler_s *ih[2]; |
568 | 597 | |
... | ... | @@ -646,6 +675,7 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, |
646 | 675 | __FUNCTION__, paddr) |
647 | 676 | |
648 | 677 | # define TCMI_VERBOSE 1 |
678 | +//# define MEM_VERBOSE 1 | |
649 | 679 | |
650 | 680 | # ifdef TCMI_VERBOSE |
651 | 681 | # define OMAP_8B_REG(paddr) \ |
... | ... | @@ -665,4 +695,97 @@ void omap_badwidth_write32(void *opaque, target_phys_addr_t addr, |
665 | 695 | |
666 | 696 | # define OMAP_MPUI_REG_MASK 0x000007ff |
667 | 697 | |
698 | +# ifdef MEM_VERBOSE | |
699 | +struct io_fn { | |
700 | + CPUReadMemoryFunc **mem_read; | |
701 | + CPUWriteMemoryFunc **mem_write; | |
702 | + void *opaque; | |
703 | + int in; | |
704 | +}; | |
705 | + | |
706 | +static uint32_t io_readb(void *opaque, target_phys_addr_t addr) | |
707 | +{ | |
708 | + struct io_fn *s = opaque; | |
709 | + uint32_t ret; | |
710 | + | |
711 | + s->in ++; | |
712 | + ret = s->mem_read[0](s->opaque, addr); | |
713 | + s->in --; | |
714 | + if (!s->in) | |
715 | + fprintf(stderr, "%08x ---> %02x\n", (uint32_t) addr, ret); | |
716 | + return ret; | |
717 | +} | |
718 | +static uint32_t io_readh(void *opaque, target_phys_addr_t addr) | |
719 | +{ | |
720 | + struct io_fn *s = opaque; | |
721 | + uint32_t ret; | |
722 | + | |
723 | + s->in ++; | |
724 | + ret = s->mem_read[1](s->opaque, addr); | |
725 | + s->in --; | |
726 | + if (!s->in) | |
727 | + fprintf(stderr, "%08x ---> %04x\n", (uint32_t) addr, ret); | |
728 | + return ret; | |
729 | +} | |
730 | +static uint32_t io_readw(void *opaque, target_phys_addr_t addr) | |
731 | +{ | |
732 | + struct io_fn *s = opaque; | |
733 | + uint32_t ret; | |
734 | + | |
735 | + s->in ++; | |
736 | + ret = s->mem_read[2](s->opaque, addr); | |
737 | + s->in --; | |
738 | + if (!s->in) | |
739 | + fprintf(stderr, "%08x ---> %08x\n", (uint32_t) addr, ret); | |
740 | + return ret; | |
741 | +} | |
742 | +static void io_writeb(void *opaque, target_phys_addr_t addr, uint32_t value) | |
743 | +{ | |
744 | + struct io_fn *s = opaque; | |
745 | + | |
746 | + if (!s->in) | |
747 | + fprintf(stderr, "%08x <--- %02x\n", (uint32_t) addr, value); | |
748 | + s->in ++; | |
749 | + s->mem_write[0](s->opaque, addr, value); | |
750 | + s->in --; | |
751 | +} | |
752 | +static void io_writeh(void *opaque, target_phys_addr_t addr, uint32_t value) | |
753 | +{ | |
754 | + struct io_fn *s = opaque; | |
755 | + | |
756 | + if (!s->in) | |
757 | + fprintf(stderr, "%08x <--- %04x\n", (uint32_t) addr, value); | |
758 | + s->in ++; | |
759 | + s->mem_write[1](s->opaque, addr, value); | |
760 | + s->in --; | |
761 | +} | |
762 | +static void io_writew(void *opaque, target_phys_addr_t addr, uint32_t value) | |
763 | +{ | |
764 | + struct io_fn *s = opaque; | |
765 | + | |
766 | + if (!s->in) | |
767 | + fprintf(stderr, "%08x <--- %08x\n", (uint32_t) addr, value); | |
768 | + s->in ++; | |
769 | + s->mem_write[2](s->opaque, addr, value); | |
770 | + s->in --; | |
771 | +} | |
772 | + | |
773 | +static CPUReadMemoryFunc *io_readfn[] = { io_readb, io_readh, io_readw, }; | |
774 | +static CPUWriteMemoryFunc *io_writefn[] = { io_writeb, io_writeh, io_writew, }; | |
775 | + | |
776 | +inline static int debug_register_io_memory(int io_index, | |
777 | + CPUReadMemoryFunc **mem_read, CPUWriteMemoryFunc **mem_write, | |
778 | + void *opaque) | |
779 | +{ | |
780 | + struct io_fn *s = qemu_malloc(sizeof(struct io_fn)); | |
781 | + | |
782 | + s->mem_read = mem_read; | |
783 | + s->mem_write = mem_write; | |
784 | + s->opaque = opaque; | |
785 | + s->in = 0; | |
786 | + return cpu_register_io_memory(io_index, io_readfn, io_writefn, s); | |
787 | +} | |
788 | +# define cpu_register_io_memory debug_register_io_memory | |
789 | +# endif | |
790 | + | |
668 | 791 | #endif /* hw_omap_h */ | ... | ... |
hw/omap1_clk.c
... | ... | @@ -307,6 +307,12 @@ static struct clk lbfree_ck = { |
307 | 307 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, |
308 | 308 | }; |
309 | 309 | |
310 | +static struct clk hsab_ck = { | |
311 | + .name = "hsab_ck", | |
312 | + .parent = &tc_ck, | |
313 | + .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310, | |
314 | +}; | |
315 | + | |
310 | 316 | static struct clk rhea1_ck = { |
311 | 317 | .name = "rhea1_ck", |
312 | 318 | .parent = &tc_ck, |
... | ... | @@ -359,7 +365,7 @@ static struct clk uart2_ck = { |
359 | 365 | static struct clk uart3_1510 = { |
360 | 366 | .name = "uart3_ck", |
361 | 367 | /* Direct from ULPD, no real parent */ |
362 | - .parent = &armper_ck,/* either armper_ck or dpll4 */ | |
368 | + .parent = &armper_ck, /* either armper_ck or dpll4 */ | |
363 | 369 | .rate = 12000000, |
364 | 370 | .flags = CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP310 | ALWAYS_ENABLED, |
365 | 371 | }; |
... | ... | @@ -395,11 +401,12 @@ static struct clk usb_hhc_ck16xx = { |
395 | 401 | .flags = CLOCK_IN_OMAP16XX, |
396 | 402 | }; |
397 | 403 | |
398 | -static struct clk usb_dc_ck = { | |
399 | - .name = "usb_dc_ck", | |
400 | - /* Direct from ULPD, no parent */ | |
404 | +static struct clk usb_w2fc_mclk = { | |
405 | + .name = "usb_w2fc_mclk", | |
406 | + .alias = "usb_w2fc_ck", | |
407 | + .parent = &ck_48m, | |
401 | 408 | .rate = 48000000, |
402 | - .flags = CLOCK_IN_OMAP16XX, | |
409 | + .flags = CLOCK_IN_OMAP310 | CLOCK_IN_OMAP1510 | CLOCK_IN_OMAP16XX, | |
403 | 410 | }; |
404 | 411 | |
405 | 412 | static struct clk mclk_1510 = { |
... | ... | @@ -539,6 +546,7 @@ static struct clk *onchip_clks[] = { |
539 | 546 | &api_ck, |
540 | 547 | &lb_ck, |
541 | 548 | &lbfree_ck, |
549 | + &hsab_ck, | |
542 | 550 | &rhea1_ck, |
543 | 551 | &rhea2_ck, |
544 | 552 | &lcd_ck_16xx, |
... | ... | @@ -551,7 +559,6 @@ static struct clk *onchip_clks[] = { |
551 | 559 | &uart3_16xx, |
552 | 560 | &usb_clk0, |
553 | 561 | &usb_hhc_ck1510, &usb_hhc_ck16xx, |
554 | - &usb_dc_ck, | |
555 | 562 | &mclk_1510, &mclk_16xx, &mclk_310, |
556 | 563 | &bclk_1510, &bclk_16xx, &bclk_310, |
557 | 564 | &mmc1_ck, |
... | ... | @@ -560,6 +567,7 @@ static struct clk *onchip_clks[] = { |
560 | 567 | &cam_exclk, |
561 | 568 | &cam_lclk, |
562 | 569 | &clk32k, |
570 | + &usb_w2fc_mclk, | |
563 | 571 | /* Virtual clocks */ |
564 | 572 | &i2c_fck, |
565 | 573 | &i2c_ick, | ... | ... |
hw/palm.c
... | ... | @@ -78,11 +78,18 @@ static CPUWriteMemoryFunc *static_writefn[] = { |
78 | 78 | |
79 | 79 | static void palmte_microwire_setup(struct omap_mpu_state_s *cpu) |
80 | 80 | { |
81 | - omap_uwire_attach( | |
82 | - cpu->microwire, | |
83 | - tsc2102_init( | |
84 | - omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO]), | |
85 | - 0); | |
81 | + struct uwire_slave_s *tsc; | |
82 | + AudioState *audio = 0; | |
83 | + | |
84 | +#ifdef HAS_AUDIO | |
85 | + audio = AUD_init(); | |
86 | +#endif | |
87 | + | |
88 | + tsc = tsc2102_init(omap_gpio_in_get(cpu->gpio)[PALMTE_PINTDAV_GPIO], | |
89 | + audio); | |
90 | + | |
91 | + omap_uwire_attach(cpu->microwire, tsc, 0); | |
92 | + omap_mcbsp_i2s_attach(cpu->mcbsp1, tsc210x_codec(tsc)); | |
86 | 93 | } |
87 | 94 | |
88 | 95 | static struct { | ... | ... |
hw/tsc210x.c
... | ... | @@ -32,7 +32,11 @@ |
32 | 32 | struct tsc210x_state_s { |
33 | 33 | qemu_irq pint; |
34 | 34 | QEMUTimer *timer; |
35 | + QEMUSoundCard card; | |
35 | 36 | struct uwire_slave_s chip; |
37 | + struct i2s_codec_s codec; | |
38 | + uint8_t in_fifo[16384]; | |
39 | + uint8_t out_fifo[16384]; | |
36 | 40 | |
37 | 41 | int x, y; |
38 | 42 | int pressure; |
... | ... | @@ -63,6 +67,13 @@ struct tsc210x_state_s { |
63 | 67 | uint16_t dac_power; |
64 | 68 | int64_t powerdown; |
65 | 69 | uint16_t filter_data[0x14]; |
70 | + | |
71 | + const char *name; | |
72 | + SWVoiceIn *adc_voice[1]; | |
73 | + SWVoiceOut *dac_voice[1]; | |
74 | + int i2s_rx_rate; | |
75 | + int i2s_tx_rate; | |
76 | + AudioState *audio; | |
66 | 77 | }; |
67 | 78 | |
68 | 79 | static const int resolution[4] = { 12, 8, 10, 12 }; |
... | ... | @@ -171,9 +182,144 @@ static void tsc210x_reset(struct tsc210x_state_s *s) |
171 | 182 | s->filter_data[0x12] = 0x7d83; |
172 | 183 | s->filter_data[0x13] = 0x84ee; |
173 | 184 | |
185 | + s->i2s_tx_rate = 0; | |
186 | + s->i2s_rx_rate = 0; | |
187 | + | |
174 | 188 | qemu_set_irq(s->pint, !s->irq); |
175 | 189 | } |
176 | 190 | |
191 | +struct tsc210x_rate_info_s { | |
192 | + int rate; | |
193 | + int dsor; | |
194 | + int fsref; | |
195 | +}; | |
196 | + | |
197 | +/* { rate, dsor, fsref } */ | |
198 | +static const struct tsc210x_rate_info_s tsc2101_rates[] = { | |
199 | + /* Fsref / 6.0 */ | |
200 | + { 7350, 7, 1 }, | |
201 | + { 8000, 7, 0 }, | |
202 | + /* Fsref / 5.5 */ | |
203 | + { 8018, 6, 1 }, | |
204 | + { 8727, 6, 0 }, | |
205 | + /* Fsref / 5.0 */ | |
206 | + { 8820, 5, 1 }, | |
207 | + { 9600, 5, 0 }, | |
208 | + /* Fsref / 4.0 */ | |
209 | + { 11025, 4, 1 }, | |
210 | + { 12000, 4, 0 }, | |
211 | + /* Fsref / 3.0 */ | |
212 | + { 14700, 3, 1 }, | |
213 | + { 16000, 3, 0 }, | |
214 | + /* Fsref / 2.0 */ | |
215 | + { 22050, 2, 1 }, | |
216 | + { 24000, 2, 0 }, | |
217 | + /* Fsref / 1.5 */ | |
218 | + { 29400, 1, 1 }, | |
219 | + { 32000, 1, 0 }, | |
220 | + /* Fsref */ | |
221 | + { 44100, 0, 1 }, | |
222 | + { 48000, 0, 0 }, | |
223 | + | |
224 | + { 0, 0, 0 }, | |
225 | +}; | |
226 | + | |
227 | +/* { rate, dsor, fsref } */ | |
228 | +static const struct tsc210x_rate_info_s tsc2102_rates[] = { | |
229 | + /* Fsref / 6.0 */ | |
230 | + { 7350, 63, 1 }, | |
231 | + { 8000, 63, 0 }, | |
232 | + /* Fsref / 6.0 */ | |
233 | + { 7350, 54, 1 }, | |
234 | + { 8000, 54, 0 }, | |
235 | + /* Fsref / 5.0 */ | |
236 | + { 8820, 45, 1 }, | |
237 | + { 9600, 45, 0 }, | |
238 | + /* Fsref / 4.0 */ | |
239 | + { 11025, 36, 1 }, | |
240 | + { 12000, 36, 0 }, | |
241 | + /* Fsref / 3.0 */ | |
242 | + { 14700, 27, 1 }, | |
243 | + { 16000, 27, 0 }, | |
244 | + /* Fsref / 2.0 */ | |
245 | + { 22050, 18, 1 }, | |
246 | + { 24000, 18, 0 }, | |
247 | + /* Fsref / 1.5 */ | |
248 | + { 29400, 9, 1 }, | |
249 | + { 32000, 9, 0 }, | |
250 | + /* Fsref */ | |
251 | + { 44100, 0, 1 }, | |
252 | + { 48000, 0, 0 }, | |
253 | + | |
254 | + { 0, 0, 0 }, | |
255 | +}; | |
256 | + | |
257 | +static inline void tsc210x_out_flush(struct tsc210x_state_s *s, int len) | |
258 | +{ | |
259 | + uint8_t *data = s->codec.out.fifo + s->codec.out.start; | |
260 | + uint8_t *end = data + len; | |
261 | + | |
262 | + while (data < end) | |
263 | + data += AUD_write(s->dac_voice[0], data, end - data) ?: (end - data); | |
264 | + | |
265 | + s->codec.out.len -= len; | |
266 | + if (s->codec.out.len) | |
267 | + memmove(s->codec.out.fifo, end, s->codec.out.len); | |
268 | + s->codec.out.start = 0; | |
269 | +} | |
270 | + | |
271 | +static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) | |
272 | +{ | |
273 | + if (s->codec.out.len >= free_b) { | |
274 | + tsc210x_out_flush(s, free_b); | |
275 | + return; | |
276 | + } | |
277 | + | |
278 | + s->codec.out.size = MIN(free_b, 16384); | |
279 | + qemu_irq_raise(s->codec.tx_start); | |
280 | +} | |
281 | + | |
282 | +static void tsc2102_audio_set_format(struct tsc210x_state_s *s) | |
283 | +{ | |
284 | + int enable; | |
285 | + const struct tsc210x_rate_info_s *rate; | |
286 | + audsettings_t fmt; | |
287 | + | |
288 | + if (s->dac_voice[0]) { | |
289 | + tsc210x_out_flush(s, s->codec.out.len); | |
290 | + s->codec.out.size = 0; | |
291 | + AUD_set_active_out(s->dac_voice[0], 0); | |
292 | + AUD_close_out(&s->card, s->dac_voice[0]); | |
293 | + s->dac_voice[0] = 0; | |
294 | + } | |
295 | + | |
296 | + enable = | |
297 | + (~s->dac_power & (1 << 15)) && /* PWDNC */ | |
298 | + (~s->dac_power & (1 << 10)); /* DAPWDN */ | |
299 | + if (!enable) | |
300 | + return; | |
301 | + | |
302 | + for (rate = tsc2102_rates; rate->rate; rate ++) | |
303 | + if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ | |
304 | + rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ | |
305 | + break; | |
306 | + if (!rate->rate) { | |
307 | + printf("%s: unknown sampling rate configured\n", __FUNCTION__); | |
308 | + return; | |
309 | + } | |
310 | + | |
311 | + /* Force our own sampling rate even in slave DAC mode */ | |
312 | + fmt.endianness = 0; | |
313 | + fmt.nchannels = 2; | |
314 | + fmt.freq = rate->rate; | |
315 | + fmt.fmt = AUD_FMT_S16; | |
316 | + | |
317 | + s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], | |
318 | + "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); | |
319 | + if (s->dac_voice[0]) | |
320 | + AUD_set_active_out(s->dac_voice[0], 1); | |
321 | +} | |
322 | + | |
177 | 323 | static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) |
178 | 324 | { |
179 | 325 | switch (reg) { |
... | ... | @@ -437,6 +583,8 @@ static void tsc2102_audio_register_write( |
437 | 583 | fprintf(stderr, "tsc2102_audio_register_write: " |
438 | 584 | "wrong value written into Audio 1\n"); |
439 | 585 | #endif |
586 | + if (s->audio) | |
587 | + tsc2102_audio_set_format(s); | |
440 | 588 | return; |
441 | 589 | |
442 | 590 | case 0x01: |
... | ... | @@ -479,6 +627,8 @@ static void tsc2102_audio_register_write( |
479 | 627 | fprintf(stderr, "tsc2102_audio_register_write: " |
480 | 628 | "wrong value written into Power\n"); |
481 | 629 | #endif |
630 | + if (s->audio) | |
631 | + tsc2102_audio_set_format(s); | |
482 | 632 | return; |
483 | 633 | |
484 | 634 | case 0x06: /* Audio Control 3 */ |
... | ... | @@ -489,6 +639,8 @@ static void tsc2102_audio_register_write( |
489 | 639 | fprintf(stderr, "tsc2102_audio_register_write: " |
490 | 640 | "wrong value written into Audio 3\n"); |
491 | 641 | #endif |
642 | + if (s->audio) | |
643 | + tsc2102_audio_set_format(s); | |
492 | 644 | return; |
493 | 645 | |
494 | 646 | case 0x07: /* LCH_BASS_BOOST_N0 */ |
... | ... | @@ -718,6 +870,20 @@ static void tsc210x_touchscreen_event(void *opaque, |
718 | 870 | tsc210x_pin_update(s); |
719 | 871 | } |
720 | 872 | |
873 | +static void tsc210x_i2s_swallow(struct tsc210x_state_s *s) | |
874 | +{ | |
875 | + if (s->dac_voice[0]) | |
876 | + tsc210x_out_flush(s, s->codec.out.len); | |
877 | + else | |
878 | + s->codec.out.len = 0; | |
879 | +} | |
880 | + | |
881 | +static void tsc210x_i2s_set_rate(struct tsc210x_state_s *s, int in, int out) | |
882 | +{ | |
883 | + s->i2s_tx_rate = out; | |
884 | + s->i2s_rx_rate = in; | |
885 | +} | |
886 | + | |
721 | 887 | static void tsc210x_save(QEMUFile *f, void *opaque) |
722 | 888 | { |
723 | 889 | struct tsc210x_state_s *s = (struct tsc210x_state_s *) opaque; |
... | ... | @@ -817,7 +983,7 @@ static int tsc210x_load(QEMUFile *f, void *opaque, int version_id) |
817 | 983 | |
818 | 984 | static int tsc2102_iid = 0; |
819 | 985 | |
820 | -struct uwire_slave_s *tsc2102_init(qemu_irq pint) | |
986 | +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio) | |
821 | 987 | { |
822 | 988 | struct tsc210x_state_s *s; |
823 | 989 | |
... | ... | @@ -830,19 +996,37 @@ struct uwire_slave_s *tsc2102_init(qemu_irq pint) |
830 | 996 | s->precision = s->nextprecision = 0; |
831 | 997 | s->timer = qemu_new_timer(vm_clock, tsc210x_timer_tick, s); |
832 | 998 | s->pint = pint; |
999 | + s->name = "tsc2102"; | |
1000 | + s->audio = audio; | |
833 | 1001 | |
834 | 1002 | s->chip.opaque = s; |
835 | 1003 | s->chip.send = (void *) tsc210x_write; |
836 | 1004 | s->chip.receive = (void *) tsc210x_read; |
837 | 1005 | |
1006 | + s->codec.opaque = s; | |
1007 | + s->codec.tx_swallow = (void *) tsc210x_i2s_swallow; | |
1008 | + s->codec.set_rate = (void *) tsc210x_i2s_set_rate; | |
1009 | + s->codec.in.fifo = s->in_fifo; | |
1010 | + s->codec.out.fifo = s->out_fifo; | |
1011 | + | |
838 | 1012 | tsc210x_reset(s); |
839 | 1013 | |
840 | 1014 | qemu_add_mouse_event_handler(tsc210x_touchscreen_event, s, 1, |
841 | 1015 | "QEMU TSC2102-driven Touchscreen"); |
842 | 1016 | |
1017 | + if (s->audio) | |
1018 | + AUD_register_card(s->audio, s->name, &s->card); | |
1019 | + | |
843 | 1020 | qemu_register_reset((void *) tsc210x_reset, s); |
844 | - register_savevm("tsc2102", tsc2102_iid ++, 0, | |
1021 | + register_savevm(s->name, tsc2102_iid ++, 0, | |
845 | 1022 | tsc210x_save, tsc210x_load, s); |
846 | 1023 | |
847 | 1024 | return &s->chip; |
848 | 1025 | } |
1026 | + | |
1027 | +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip) | |
1028 | +{ | |
1029 | + struct tsc210x_state_s *s = (struct tsc210x_state_s *) chip->opaque; | |
1030 | + | |
1031 | + return &s->codec; | |
1032 | +} | ... | ... |
vl.h
... | ... | @@ -1667,7 +1667,8 @@ void qemu_get_ptimer(QEMUFile *f, ptimer_state *s); |
1667 | 1667 | #include "hw/omap.h" |
1668 | 1668 | |
1669 | 1669 | /* tsc210x.c */ |
1670 | -struct uwire_slave_s *tsc2102_init(qemu_irq pint); | |
1670 | +struct uwire_slave_s *tsc2102_init(qemu_irq pint, AudioState *audio); | |
1671 | +struct i2s_codec_s *tsc210x_codec(struct uwire_slave_s *chip); | |
1671 | 1672 | |
1672 | 1673 | /* mcf_uart.c */ |
1673 | 1674 | uint32_t mcf_uart_read(void *opaque, target_phys_addr_t addr); | ... | ... |