Commit 73560bc8e347e8c71bd646e977282efab204ff44
1 parent
79b02417
Clean-up/rewrite audio over I^2S support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3704 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
227 additions
and
110 deletions
hw/omap.c
| ... | ... | @@ -997,7 +997,8 @@ static void omap_dma_clk_update(void *opaque, int line, int on) |
| 997 | 997 | struct omap_dma_s *s = (struct omap_dma_s *) opaque; |
| 998 | 998 | |
| 999 | 999 | if (on) { |
| 1000 | - s->delay = ticks_per_sec >> 7; | |
| 1000 | + /* TODO: make a clever calculation */ | |
| 1001 | + s->delay = ticks_per_sec >> 8; | |
| 1001 | 1002 | if (s->run_count) |
| 1002 | 1003 | qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); |
| 1003 | 1004 | } else { |
| ... | ... | @@ -4097,8 +4098,11 @@ struct omap_mcbsp_s { |
| 4097 | 4098 | int tx_rate; |
| 4098 | 4099 | int rx_rate; |
| 4099 | 4100 | int tx_req; |
| 4101 | + int rx_req; | |
| 4100 | 4102 | |
| 4101 | 4103 | struct i2s_codec_s *codec; |
| 4104 | + QEMUTimer *source_timer; | |
| 4105 | + QEMUTimer *sink_timer; | |
| 4102 | 4106 | }; |
| 4103 | 4107 | |
| 4104 | 4108 | static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) |
| ... | ... | @@ -4134,88 +4138,149 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) |
| 4134 | 4138 | qemu_set_irq(s->txirq, irq); |
| 4135 | 4139 | } |
| 4136 | 4140 | |
| 4137 | -static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) | |
| 4141 | +static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s) | |
| 4138 | 4142 | { |
| 4139 | - int prev = s->tx_req; | |
| 4140 | - | |
| 4141 | - s->tx_req = (s->tx_rate || | |
| 4142 | - (s->spcr[0] & (1 << 12))) && /* CLKSTP */ | |
| 4143 | - (s->spcr[1] & (1 << 6)) && /* GRST */ | |
| 4144 | - (s->spcr[1] & (1 << 0)); /* XRST */ | |
| 4145 | - | |
| 4146 | - if (!s->tx_req && prev) { | |
| 4147 | - s->spcr[1] &= ~(1 << 1); /* XRDY */ | |
| 4148 | - qemu_irq_lower(s->txdrq); | |
| 4149 | - omap_mcbsp_intr_update(s); | |
| 4150 | - | |
| 4151 | - if (s->codec) | |
| 4152 | - s->codec->tx_swallow(s->codec->opaque); | |
| 4153 | - } else if (s->codec && s->tx_req && !prev) { | |
| 4154 | - s->spcr[1] |= 1 << 1; /* XRDY */ | |
| 4155 | - qemu_irq_raise(s->txdrq); | |
| 4156 | - omap_mcbsp_intr_update(s); | |
| 4157 | - } | |
| 4143 | + if ((s->spcr[0] >> 1) & 1) /* RRDY */ | |
| 4144 | + s->spcr[0] |= 1 << 2; /* RFULL */ | |
| 4145 | + s->spcr[0] |= 1 << 1; /* RRDY */ | |
| 4146 | + qemu_irq_raise(s->rxdrq); | |
| 4147 | + omap_mcbsp_intr_update(s); | |
| 4158 | 4148 | } |
| 4159 | 4149 | |
| 4160 | -static void omap_mcbsp_rate_update(struct omap_mcbsp_s *s) | |
| 4150 | +static void omap_mcbsp_source_tick(void *opaque) | |
| 4161 | 4151 | { |
| 4162 | - int rx_clk = 0, tx_clk = 0; | |
| 4163 | - int cpu_rate = 1500000; /* XXX */ | |
| 4164 | - if (!s->codec) | |
| 4152 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
| 4153 | + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; | |
| 4154 | + | |
| 4155 | + if (!s->rx_rate) | |
| 4165 | 4156 | return; |
| 4157 | + if (s->rx_req) | |
| 4158 | + printf("%s: Rx FIFO overrun\n", __FUNCTION__); | |
| 4166 | 4159 | |
| 4167 | - if (s->spcr[1] & (1 << 6)) { /* GRST */ | |
| 4168 | - if (s->spcr[0] & (1 << 0)) /* RRST */ | |
| 4169 | - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
| 4170 | - (s->pcr & (1 << 8))) /* CLKRM */ | |
| 4171 | - if (~s->pcr & (1 << 7)) /* SCLKME */ | |
| 4172 | - rx_clk = cpu_rate / | |
| 4173 | - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
| 4174 | - if (s->spcr[1] & (1 << 0)) /* XRST */ | |
| 4175 | - if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
| 4176 | - (s->pcr & (1 << 9))) /* CLKXM */ | |
| 4177 | - if (~s->pcr & (1 << 7)) /* SCLKME */ | |
| 4178 | - tx_clk = cpu_rate / | |
| 4179 | - ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
| 4180 | - } | |
| 4160 | + s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7]; | |
| 4181 | 4161 | |
| 4182 | - s->codec->set_rate(s->codec->opaque, rx_clk, tx_clk); | |
| 4162 | + omap_mcbsp_rx_newdata(s); | |
| 4163 | + qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) + ticks_per_sec); | |
| 4183 | 4164 | } |
| 4184 | 4165 | |
| 4185 | 4166 | static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) |
| 4186 | 4167 | { |
| 4187 | - if (!(s->spcr[0] & 1)) { /* RRST */ | |
| 4188 | - if (s->codec) | |
| 4189 | - s->codec->in.len = 0; | |
| 4190 | - return; | |
| 4168 | + if (!s->codec || !s->codec->rts) | |
| 4169 | + omap_mcbsp_source_tick(s); | |
| 4170 | + else if (s->codec->in.len) { | |
| 4171 | + s->rx_req = s->codec->in.len; | |
| 4172 | + omap_mcbsp_rx_newdata(s); | |
| 4191 | 4173 | } |
| 4192 | - | |
| 4193 | - if ((s->spcr[0] >> 1) & 1) /* RRDY */ | |
| 4194 | - s->spcr[0] |= 1 << 2; /* RFULL */ | |
| 4195 | - s->spcr[0] |= 1 << 1; /* RRDY */ | |
| 4196 | - qemu_irq_raise(s->rxdrq); | |
| 4197 | - omap_mcbsp_intr_update(s); | |
| 4198 | 4174 | } |
| 4199 | 4175 | |
| 4200 | 4176 | static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) |
| 4201 | 4177 | { |
| 4178 | + qemu_del_timer(s->source_timer); | |
| 4179 | +} | |
| 4180 | + | |
| 4181 | +static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s) | |
| 4182 | +{ | |
| 4202 | 4183 | s->spcr[0] &= ~(1 << 1); /* RRDY */ |
| 4203 | 4184 | qemu_irq_lower(s->rxdrq); |
| 4204 | 4185 | omap_mcbsp_intr_update(s); |
| 4205 | 4186 | } |
| 4206 | 4187 | |
| 4207 | -static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) | |
| 4188 | +static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s) | |
| 4189 | +{ | |
| 4190 | + s->spcr[1] |= 1 << 1; /* XRDY */ | |
| 4191 | + qemu_irq_raise(s->txdrq); | |
| 4192 | + omap_mcbsp_intr_update(s); | |
| 4193 | +} | |
| 4194 | + | |
| 4195 | +static void omap_mcbsp_sink_tick(void *opaque) | |
| 4208 | 4196 | { |
| 4209 | - if (s->tx_rate) | |
| 4197 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
| 4198 | + static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 }; | |
| 4199 | + | |
| 4200 | + if (!s->tx_rate) | |
| 4210 | 4201 | return; |
| 4211 | - s->tx_rate = 1; | |
| 4212 | - omap_mcbsp_req_update(s); | |
| 4202 | + if (s->tx_req) | |
| 4203 | + printf("%s: Tx FIFO underrun\n", __FUNCTION__); | |
| 4204 | + | |
| 4205 | + s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7]; | |
| 4206 | + | |
| 4207 | + omap_mcbsp_tx_newdata(s); | |
| 4208 | + qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) + ticks_per_sec); | |
| 4209 | +} | |
| 4210 | + | |
| 4211 | +static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s) | |
| 4212 | +{ | |
| 4213 | + if (!s->codec || !s->codec->cts) | |
| 4214 | + omap_mcbsp_sink_tick(s); | |
| 4215 | + else if (s->codec->out.size) { | |
| 4216 | + s->tx_req = s->codec->out.size; | |
| 4217 | + omap_mcbsp_tx_newdata(s); | |
| 4218 | + } | |
| 4219 | +} | |
| 4220 | + | |
| 4221 | +static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s) | |
| 4222 | +{ | |
| 4223 | + s->spcr[1] &= ~(1 << 1); /* XRDY */ | |
| 4224 | + qemu_irq_lower(s->txdrq); | |
| 4225 | + omap_mcbsp_intr_update(s); | |
| 4226 | + if (s->codec && s->codec->cts) | |
| 4227 | + s->codec->tx_swallow(s->codec->opaque); | |
| 4213 | 4228 | } |
| 4214 | 4229 | |
| 4215 | 4230 | static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) |
| 4216 | 4231 | { |
| 4217 | - s->tx_rate = 0; | |
| 4218 | - omap_mcbsp_req_update(s); | |
| 4232 | + s->tx_req = 0; | |
| 4233 | + omap_mcbsp_tx_done(s); | |
| 4234 | + qemu_del_timer(s->sink_timer); | |
| 4235 | +} | |
| 4236 | + | |
| 4237 | +static void omap_mcbsp_req_update(struct omap_mcbsp_s *s) | |
| 4238 | +{ | |
| 4239 | + int prev_rx_rate, prev_tx_rate; | |
| 4240 | + int rx_rate = 0, tx_rate = 0; | |
| 4241 | + int cpu_rate = 1500000; /* XXX */ | |
| 4242 | + | |
| 4243 | + /* TODO: check CLKSTP bit */ | |
| 4244 | + if (s->spcr[1] & (1 << 6)) { /* GRST */ | |
| 4245 | + if (s->spcr[0] & (1 << 0)) { /* RRST */ | |
| 4246 | + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
| 4247 | + (s->pcr & (1 << 8))) { /* CLKRM */ | |
| 4248 | + if (~s->pcr & (1 << 7)) /* SCLKME */ | |
| 4249 | + rx_rate = cpu_rate / | |
| 4250 | + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
| 4251 | + } else | |
| 4252 | + if (s->codec) | |
| 4253 | + rx_rate = s->codec->rx_rate; | |
| 4254 | + } | |
| 4255 | + | |
| 4256 | + if (s->spcr[1] & (1 << 0)) { /* XRST */ | |
| 4257 | + if ((s->srgr[1] & (1 << 13)) && /* CLKSM */ | |
| 4258 | + (s->pcr & (1 << 9))) { /* CLKXM */ | |
| 4259 | + if (~s->pcr & (1 << 7)) /* SCLKME */ | |
| 4260 | + tx_rate = cpu_rate / | |
| 4261 | + ((s->srgr[0] & 0xff) + 1); /* CLKGDV */ | |
| 4262 | + } else | |
| 4263 | + if (s->codec) | |
| 4264 | + tx_rate = s->codec->tx_rate; | |
| 4265 | + } | |
| 4266 | + } | |
| 4267 | + prev_tx_rate = s->tx_rate; | |
| 4268 | + prev_rx_rate = s->rx_rate; | |
| 4269 | + s->tx_rate = tx_rate; | |
| 4270 | + s->rx_rate = rx_rate; | |
| 4271 | + | |
| 4272 | + if (s->codec) | |
| 4273 | + s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate); | |
| 4274 | + | |
| 4275 | + if (!prev_tx_rate && tx_rate) | |
| 4276 | + omap_mcbsp_tx_start(s); | |
| 4277 | + else if (s->tx_rate && !tx_rate) | |
| 4278 | + omap_mcbsp_tx_stop(s); | |
| 4279 | + | |
| 4280 | + if (!prev_rx_rate && rx_rate) | |
| 4281 | + omap_mcbsp_rx_start(s); | |
| 4282 | + else if (prev_tx_rate && !tx_rate) | |
| 4283 | + omap_mcbsp_rx_stop(s); | |
| 4219 | 4284 | } |
| 4220 | 4285 | |
| 4221 | 4286 | static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) |
| ... | ... | @@ -4230,17 +4295,19 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) |
| 4230 | 4295 | return 0x0000; |
| 4231 | 4296 | /* Fall through. */ |
| 4232 | 4297 | case 0x02: /* DRR1 */ |
| 4233 | - if (!s->codec) | |
| 4234 | - return 0x0000; | |
| 4235 | - if (s->codec->in.len < 2) { | |
| 4298 | + if (s->rx_req < 2) { | |
| 4236 | 4299 | printf("%s: Rx FIFO underrun\n", __FUNCTION__); |
| 4237 | - omap_mcbsp_rx_stop(s); | |
| 4300 | + omap_mcbsp_rx_done(s); | |
| 4238 | 4301 | } else { |
| 4239 | - s->codec->in.len -= 2; | |
| 4240 | - ret = s->codec->in.fifo[s->codec->in.start ++] << 8; | |
| 4241 | - ret |= s->codec->in.fifo[s->codec->in.start ++]; | |
| 4242 | - if (!s->codec->in.len) | |
| 4243 | - omap_mcbsp_rx_stop(s); | |
| 4302 | + s->tx_req -= 2; | |
| 4303 | + if (s->codec && s->codec->in.len >= 2) { | |
| 4304 | + ret = s->codec->in.fifo[s->codec->in.start ++] << 8; | |
| 4305 | + ret |= s->codec->in.fifo[s->codec->in.start ++]; | |
| 4306 | + s->codec->in.len -= 2; | |
| 4307 | + } else | |
| 4308 | + ret = 0x0000; | |
| 4309 | + if (!s->tx_req) | |
| 4310 | + omap_mcbsp_rx_done(s); | |
| 4244 | 4311 | return ret; |
| 4245 | 4312 | } |
| 4246 | 4313 | return 0x0000; |
| ... | ... | @@ -4309,7 +4376,7 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) |
| 4309 | 4376 | return 0; |
| 4310 | 4377 | } |
| 4311 | 4378 | |
| 4312 | -static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, | |
| 4379 | +static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr, | |
| 4313 | 4380 | uint32_t value) |
| 4314 | 4381 | { |
| 4315 | 4382 | struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; |
| ... | ... | @@ -4326,18 +4393,14 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
| 4326 | 4393 | return; |
| 4327 | 4394 | /* Fall through. */ |
| 4328 | 4395 | case 0x06: /* DXR1 */ |
| 4329 | - if (!s->codec) | |
| 4330 | - return; | |
| 4331 | - if (s->tx_req) { | |
| 4332 | - if (s->codec->out.len > s->codec->out.size - 2) { | |
| 4333 | - printf("%s: Tx FIFO overrun\n", __FUNCTION__); | |
| 4334 | - omap_mcbsp_tx_stop(s); | |
| 4335 | - } else { | |
| 4396 | + if (s->tx_req > 1) { | |
| 4397 | + s->tx_req -= 2; | |
| 4398 | + if (s->codec && s->codec->cts) { | |
| 4336 | 4399 | s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; |
| 4337 | 4400 | s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; |
| 4338 | - if (s->codec->out.len >= s->codec->out.size) | |
| 4339 | - omap_mcbsp_tx_stop(s); | |
| 4340 | 4401 | } |
| 4402 | + if (s->tx_req < 2) | |
| 4403 | + omap_mcbsp_tx_done(s); | |
| 4341 | 4404 | } else |
| 4342 | 4405 | printf("%s: Tx FIFO overrun\n", __FUNCTION__); |
| 4343 | 4406 | return; |
| ... | ... | @@ -4346,14 +4409,8 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
| 4346 | 4409 | s->spcr[1] &= 0x0002; |
| 4347 | 4410 | s->spcr[1] |= 0x03f9 & value; |
| 4348 | 4411 | s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ |
| 4349 | - if (~value & 1) { /* XRST */ | |
| 4412 | + if (~value & 1) /* XRST */ | |
| 4350 | 4413 | s->spcr[1] &= ~6; |
| 4351 | - qemu_irq_lower(s->rxdrq); | |
| 4352 | - if (s->codec) | |
| 4353 | - s->codec->out.len = 0; | |
| 4354 | - } | |
| 4355 | - if (s->codec) | |
| 4356 | - omap_mcbsp_rate_update(s); | |
| 4357 | 4414 | omap_mcbsp_req_update(s); |
| 4358 | 4415 | return; |
| 4359 | 4416 | case 0x0a: /* SPCR1 */ |
| ... | ... | @@ -4363,12 +4420,9 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
| 4363 | 4420 | printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); |
| 4364 | 4421 | if (~value & 1) { /* RRST */ |
| 4365 | 4422 | s->spcr[0] &= ~6; |
| 4366 | - qemu_irq_lower(s->txdrq); | |
| 4367 | - if (s->codec) | |
| 4368 | - s->codec->in.len = 0; | |
| 4423 | + s->rx_req = 0; | |
| 4424 | + omap_mcbsp_rx_done(s); | |
| 4369 | 4425 | } |
| 4370 | - if (s->codec) | |
| 4371 | - omap_mcbsp_rate_update(s); | |
| 4372 | 4426 | omap_mcbsp_req_update(s); |
| 4373 | 4427 | return; |
| 4374 | 4428 | |
| ... | ... | @@ -4386,11 +4440,11 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
| 4386 | 4440 | return; |
| 4387 | 4441 | case 0x14: /* SRGR2 */ |
| 4388 | 4442 | s->srgr[1] = value & 0xffff; |
| 4389 | - omap_mcbsp_rate_update(s); | |
| 4443 | + omap_mcbsp_req_update(s); | |
| 4390 | 4444 | return; |
| 4391 | 4445 | case 0x16: /* SRGR1 */ |
| 4392 | 4446 | s->srgr[0] = value & 0xffff; |
| 4393 | - omap_mcbsp_rate_update(s); | |
| 4447 | + omap_mcbsp_req_update(s); | |
| 4394 | 4448 | return; |
| 4395 | 4449 | case 0x18: /* MCR2 */ |
| 4396 | 4450 | s->mcr[1] = value & 0x03e3; |
| ... | ... | @@ -4460,6 +4514,37 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, |
| 4460 | 4514 | OMAP_BAD_REG(addr); |
| 4461 | 4515 | } |
| 4462 | 4516 | |
| 4517 | +static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr, | |
| 4518 | + uint32_t value) | |
| 4519 | +{ | |
| 4520 | + struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; | |
| 4521 | + int offset = addr & OMAP_MPUI_REG_MASK; | |
| 4522 | + | |
| 4523 | + if (offset == 0x04) { /* DXR */ | |
| 4524 | + if (((s->xcr[0] >> 5) & 7) < 3) /* XWDLEN1 */ | |
| 4525 | + return; | |
| 4526 | + if (s->tx_req > 3) { | |
| 4527 | + s->tx_req -= 4; | |
| 4528 | + if (s->codec && s->codec->cts) { | |
| 4529 | + s->codec->out.fifo[s->codec->out.len ++] = | |
| 4530 | + (value >> 24) & 0xff; | |
| 4531 | + s->codec->out.fifo[s->codec->out.len ++] = | |
| 4532 | + (value >> 16) & 0xff; | |
| 4533 | + s->codec->out.fifo[s->codec->out.len ++] = | |
| 4534 | + (value >> 8) & 0xff; | |
| 4535 | + s->codec->out.fifo[s->codec->out.len ++] = | |
| 4536 | + (value >> 0) & 0xff; | |
| 4537 | + } | |
| 4538 | + if (s->tx_req < 4) | |
| 4539 | + omap_mcbsp_tx_done(s); | |
| 4540 | + } else | |
| 4541 | + printf("%s: Tx FIFO overrun\n", __FUNCTION__); | |
| 4542 | + return; | |
| 4543 | + } | |
| 4544 | + | |
| 4545 | + omap_badwidth_write16(opaque, addr, value); | |
| 4546 | +} | |
| 4547 | + | |
| 4463 | 4548 | static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { |
| 4464 | 4549 | omap_badwidth_read16, |
| 4465 | 4550 | omap_mcbsp_read, |
| ... | ... | @@ -4468,8 +4553,8 @@ static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { |
| 4468 | 4553 | |
| 4469 | 4554 | static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { |
| 4470 | 4555 | omap_badwidth_write16, |
| 4471 | - omap_mcbsp_write, | |
| 4472 | - omap_badwidth_write16, | |
| 4556 | + omap_mcbsp_writeh, | |
| 4557 | + omap_mcbsp_writew, | |
| 4473 | 4558 | }; |
| 4474 | 4559 | |
| 4475 | 4560 | static void omap_mcbsp_reset(struct omap_mcbsp_s *s) |
| ... | ... | @@ -4484,8 +4569,11 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s) |
| 4484 | 4569 | memset(&s->rcer, 0, sizeof(s->rcer)); |
| 4485 | 4570 | memset(&s->xcer, 0, sizeof(s->xcer)); |
| 4486 | 4571 | s->tx_req = 0; |
| 4572 | + s->rx_req = 0; | |
| 4487 | 4573 | s->tx_rate = 0; |
| 4488 | 4574 | s->rx_rate = 0; |
| 4575 | + qemu_del_timer(s->source_timer); | |
| 4576 | + qemu_del_timer(s->sink_timer); | |
| 4489 | 4577 | } |
| 4490 | 4578 | |
| 4491 | 4579 | struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, |
| ... | ... | @@ -4500,6 +4588,8 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, |
| 4500 | 4588 | s->rxirq = irq[1]; |
| 4501 | 4589 | s->txdrq = dma[0]; |
| 4502 | 4590 | s->rxdrq = dma[1]; |
| 4591 | + s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s); | |
| 4592 | + s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s); | |
| 4503 | 4593 | omap_mcbsp_reset(s); |
| 4504 | 4594 | |
| 4505 | 4595 | iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, |
| ... | ... | @@ -4513,14 +4603,20 @@ static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level) |
| 4513 | 4603 | { |
| 4514 | 4604 | struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; |
| 4515 | 4605 | |
| 4516 | - omap_mcbsp_rx_start(s); | |
| 4606 | + if (s->rx_rate) { | |
| 4607 | + s->rx_req = s->codec->in.len; | |
| 4608 | + omap_mcbsp_rx_newdata(s); | |
| 4609 | + } | |
| 4517 | 4610 | } |
| 4518 | 4611 | |
| 4519 | 4612 | static void omap_mcbsp_i2s_start(void *opaque, int line, int level) |
| 4520 | 4613 | { |
| 4521 | 4614 | struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; |
| 4522 | 4615 | |
| 4523 | - omap_mcbsp_tx_start(s); | |
| 4616 | + if (s->tx_rate) { | |
| 4617 | + s->tx_req = s->codec->out.size; | |
| 4618 | + omap_mcbsp_tx_newdata(s); | |
| 4619 | + } | |
| 4524 | 4620 | } |
| 4525 | 4621 | |
| 4526 | 4622 | void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) | ... | ... |
hw/omap.h
hw/tsc210x.c
| ... | ... | @@ -283,10 +283,30 @@ static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) |
| 283 | 283 | qemu_irq_raise(s->codec.tx_start); |
| 284 | 284 | } |
| 285 | 285 | |
| 286 | -static void tsc2102_audio_set_format(struct tsc210x_state_s *s) | |
| 286 | +static void tsc2102_audio_rate_update(struct tsc210x_state_s *s) | |
| 287 | 287 | { |
| 288 | - int enable; | |
| 289 | 288 | const struct tsc210x_rate_info_s *rate; |
| 289 | + | |
| 290 | + s->codec.tx_rate = 0; | |
| 291 | + s->codec.rx_rate = 0; | |
| 292 | + if (s->dac_power & (1 << 15)) /* PWDNC */ | |
| 293 | + return; | |
| 294 | + | |
| 295 | + for (rate = tsc2102_rates; rate->rate; rate ++) | |
| 296 | + if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ | |
| 297 | + rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ | |
| 298 | + break; | |
| 299 | + if (!rate->rate) { | |
| 300 | + printf("%s: unknown sampling rate configured\n", __FUNCTION__); | |
| 301 | + return; | |
| 302 | + } | |
| 303 | + | |
| 304 | + s->codec.tx_rate = rate->rate; | |
| 305 | +} | |
| 306 | + | |
| 307 | +static void tsc2102_audio_output_update(struct tsc210x_state_s *s) | |
| 308 | +{ | |
| 309 | + int enable; | |
| 290 | 310 | audsettings_t fmt; |
| 291 | 311 | |
| 292 | 312 | if (s->dac_voice[0]) { |
| ... | ... | @@ -296,32 +316,26 @@ static void tsc2102_audio_set_format(struct tsc210x_state_s *s) |
| 296 | 316 | AUD_close_out(&s->card, s->dac_voice[0]); |
| 297 | 317 | s->dac_voice[0] = 0; |
| 298 | 318 | } |
| 319 | + s->codec.cts = 0; | |
| 299 | 320 | |
| 300 | 321 | enable = |
| 301 | 322 | (~s->dac_power & (1 << 15)) && /* PWDNC */ |
| 302 | 323 | (~s->dac_power & (1 << 10)); /* DAPWDN */ |
| 303 | - if (!enable) | |
| 304 | - return; | |
| 305 | - | |
| 306 | - for (rate = tsc2102_rates; rate->rate; rate ++) | |
| 307 | - if (rate->dsor == (s->audio_ctrl1 & 0x3f) && /* DACFS */ | |
| 308 | - rate->fsref == ((s->audio_ctrl3 >> 13) & 1))/* REFFS */ | |
| 309 | - break; | |
| 310 | - if (!rate->rate) { | |
| 311 | - printf("%s: unknown sampling rate configured\n", __FUNCTION__); | |
| 324 | + if (!enable || !s->codec.tx_rate) | |
| 312 | 325 | return; |
| 313 | - } | |
| 314 | 326 | |
| 315 | 327 | /* Force our own sampling rate even in slave DAC mode */ |
| 316 | 328 | fmt.endianness = 0; |
| 317 | 329 | fmt.nchannels = 2; |
| 318 | - fmt.freq = rate->rate; | |
| 330 | + fmt.freq = s->codec.tx_rate; | |
| 319 | 331 | fmt.fmt = AUD_FMT_S16; |
| 320 | 332 | |
| 321 | 333 | s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], |
| 322 | 334 | "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); |
| 323 | - if (s->dac_voice[0]) | |
| 335 | + if (s->dac_voice[0]) { | |
| 336 | + s->codec.cts = 1; | |
| 324 | 337 | AUD_set_active_out(s->dac_voice[0], 1); |
| 338 | + } | |
| 325 | 339 | } |
| 326 | 340 | |
| 327 | 341 | static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) |
| ... | ... | @@ -587,8 +601,9 @@ static void tsc2102_audio_register_write( |
| 587 | 601 | fprintf(stderr, "tsc2102_audio_register_write: " |
| 588 | 602 | "wrong value written into Audio 1\n"); |
| 589 | 603 | #endif |
| 604 | + tsc2102_audio_rate_update(s); | |
| 590 | 605 | if (s->audio) |
| 591 | - tsc2102_audio_set_format(s); | |
| 606 | + tsc2102_audio_output_update(s); | |
| 592 | 607 | return; |
| 593 | 608 | |
| 594 | 609 | case 0x01: |
| ... | ... | @@ -631,8 +646,9 @@ static void tsc2102_audio_register_write( |
| 631 | 646 | fprintf(stderr, "tsc2102_audio_register_write: " |
| 632 | 647 | "wrong value written into Power\n"); |
| 633 | 648 | #endif |
| 649 | + tsc2102_audio_rate_update(s); | |
| 634 | 650 | if (s->audio) |
| 635 | - tsc2102_audio_set_format(s); | |
| 651 | + tsc2102_audio_output_update(s); | |
| 636 | 652 | return; |
| 637 | 653 | |
| 638 | 654 | case 0x06: /* Audio Control 3 */ |
| ... | ... | @@ -644,7 +660,7 @@ static void tsc2102_audio_register_write( |
| 644 | 660 | "wrong value written into Audio 3\n"); |
| 645 | 661 | #endif |
| 646 | 662 | if (s->audio) |
| 647 | - tsc2102_audio_set_format(s); | |
| 663 | + tsc2102_audio_output_update(s); | |
| 648 | 664 | return; |
| 649 | 665 | |
| 650 | 666 | case 0x07: /* LCH_BASS_BOOST_N0 */ | ... | ... |