Commit 73560bc8e347e8c71bd646e977282efab204ff44

Authored by balrog
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
hw/omap.c
@@ -997,7 +997,8 @@ static void omap_dma_clk_update(void *opaque, int line, int on) @@ -997,7 +997,8 @@ static void omap_dma_clk_update(void *opaque, int line, int on)
997 struct omap_dma_s *s = (struct omap_dma_s *) opaque; 997 struct omap_dma_s *s = (struct omap_dma_s *) opaque;
998 998
999 if (on) { 999 if (on) {
1000 - s->delay = ticks_per_sec >> 7; 1000 + /* TODO: make a clever calculation */
  1001 + s->delay = ticks_per_sec >> 8;
1001 if (s->run_count) 1002 if (s->run_count)
1002 qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay); 1003 qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
1003 } else { 1004 } else {
@@ -4097,8 +4098,11 @@ struct omap_mcbsp_s { @@ -4097,8 +4098,11 @@ struct omap_mcbsp_s {
4097 int tx_rate; 4098 int tx_rate;
4098 int rx_rate; 4099 int rx_rate;
4099 int tx_req; 4100 int tx_req;
  4101 + int rx_req;
4100 4102
4101 struct i2s_codec_s *codec; 4103 struct i2s_codec_s *codec;
  4104 + QEMUTimer *source_timer;
  4105 + QEMUTimer *sink_timer;
4102 }; 4106 };
4103 4107
4104 static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s) 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,88 +4138,149 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
4134 qemu_set_irq(s->txirq, irq); 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 return; 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 static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s) 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 static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s) 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 s->spcr[0] &= ~(1 << 1); /* RRDY */ 4183 s->spcr[0] &= ~(1 << 1); /* RRDY */
4203 qemu_irq_lower(s->rxdrq); 4184 qemu_irq_lower(s->rxdrq);
4204 omap_mcbsp_intr_update(s); 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 return; 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 static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s) 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 static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) 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,17 +4295,19 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
4230 return 0x0000; 4295 return 0x0000;
4231 /* Fall through. */ 4296 /* Fall through. */
4232 case 0x02: /* DRR1 */ 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 printf("%s: Rx FIFO underrun\n", __FUNCTION__); 4299 printf("%s: Rx FIFO underrun\n", __FUNCTION__);
4237 - omap_mcbsp_rx_stop(s); 4300 + omap_mcbsp_rx_done(s);
4238 } else { 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 return ret; 4311 return ret;
4245 } 4312 }
4246 return 0x0000; 4313 return 0x0000;
@@ -4309,7 +4376,7 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr) @@ -4309,7 +4376,7 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
4309 return 0; 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 uint32_t value) 4380 uint32_t value)
4314 { 4381 {
4315 struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; 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,18 +4393,14 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
4326 return; 4393 return;
4327 /* Fall through. */ 4394 /* Fall through. */
4328 case 0x06: /* DXR1 */ 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 s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff; 4399 s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff;
4337 s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff; 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 } else 4404 } else
4342 printf("%s: Tx FIFO overrun\n", __FUNCTION__); 4405 printf("%s: Tx FIFO overrun\n", __FUNCTION__);
4343 return; 4406 return;
@@ -4346,14 +4409,8 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, @@ -4346,14 +4409,8 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
4346 s->spcr[1] &= 0x0002; 4409 s->spcr[1] &= 0x0002;
4347 s->spcr[1] |= 0x03f9 & value; 4410 s->spcr[1] |= 0x03f9 & value;
4348 s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */ 4411 s->spcr[1] |= 0x0004 & (value << 2); /* XEMPTY := XRST */
4349 - if (~value & 1) { /* XRST */ 4412 + if (~value & 1) /* XRST */
4350 s->spcr[1] &= ~6; 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 omap_mcbsp_req_update(s); 4414 omap_mcbsp_req_update(s);
4358 return; 4415 return;
4359 case 0x0a: /* SPCR1 */ 4416 case 0x0a: /* SPCR1 */
@@ -4363,12 +4420,9 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, @@ -4363,12 +4420,9 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
4363 printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__); 4420 printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__);
4364 if (~value & 1) { /* RRST */ 4421 if (~value & 1) { /* RRST */
4365 s->spcr[0] &= ~6; 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 omap_mcbsp_req_update(s); 4426 omap_mcbsp_req_update(s);
4373 return; 4427 return;
4374 4428
@@ -4386,11 +4440,11 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, @@ -4386,11 +4440,11 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
4386 return; 4440 return;
4387 case 0x14: /* SRGR2 */ 4441 case 0x14: /* SRGR2 */
4388 s->srgr[1] = value & 0xffff; 4442 s->srgr[1] = value & 0xffff;
4389 - omap_mcbsp_rate_update(s); 4443 + omap_mcbsp_req_update(s);
4390 return; 4444 return;
4391 case 0x16: /* SRGR1 */ 4445 case 0x16: /* SRGR1 */
4392 s->srgr[0] = value & 0xffff; 4446 s->srgr[0] = value & 0xffff;
4393 - omap_mcbsp_rate_update(s); 4447 + omap_mcbsp_req_update(s);
4394 return; 4448 return;
4395 case 0x18: /* MCR2 */ 4449 case 0x18: /* MCR2 */
4396 s->mcr[1] = value & 0x03e3; 4450 s->mcr[1] = value & 0x03e3;
@@ -4460,6 +4514,37 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr, @@ -4460,6 +4514,37 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
4460 OMAP_BAD_REG(addr); 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 static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { 4548 static CPUReadMemoryFunc *omap_mcbsp_readfn[] = {
4464 omap_badwidth_read16, 4549 omap_badwidth_read16,
4465 omap_mcbsp_read, 4550 omap_mcbsp_read,
@@ -4468,8 +4553,8 @@ static CPUReadMemoryFunc *omap_mcbsp_readfn[] = { @@ -4468,8 +4553,8 @@ static CPUReadMemoryFunc *omap_mcbsp_readfn[] = {
4468 4553
4469 static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = { 4554 static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = {
4470 omap_badwidth_write16, 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 static void omap_mcbsp_reset(struct omap_mcbsp_s *s) 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,8 +4569,11 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
4484 memset(&s->rcer, 0, sizeof(s->rcer)); 4569 memset(&s->rcer, 0, sizeof(s->rcer));
4485 memset(&s->xcer, 0, sizeof(s->xcer)); 4570 memset(&s->xcer, 0, sizeof(s->xcer));
4486 s->tx_req = 0; 4571 s->tx_req = 0;
  4572 + s->rx_req = 0;
4487 s->tx_rate = 0; 4573 s->tx_rate = 0;
4488 s->rx_rate = 0; 4574 s->rx_rate = 0;
  4575 + qemu_del_timer(s->source_timer);
  4576 + qemu_del_timer(s->sink_timer);
4489 } 4577 }
4490 4578
4491 struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base, 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,6 +4588,8 @@ struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
4500 s->rxirq = irq[1]; 4588 s->rxirq = irq[1];
4501 s->txdrq = dma[0]; 4589 s->txdrq = dma[0];
4502 s->rxdrq = dma[1]; 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 omap_mcbsp_reset(s); 4593 omap_mcbsp_reset(s);
4504 4594
4505 iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn, 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,14 +4603,20 @@ static void omap_mcbsp_i2s_swallow(void *opaque, int line, int level)
4513 { 4603 {
4514 struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; 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 static void omap_mcbsp_i2s_start(void *opaque, int line, int level) 4612 static void omap_mcbsp_i2s_start(void *opaque, int line, int level)
4520 { 4613 {
4521 struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque; 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 void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave) 4622 void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave)
hw/omap.h
@@ -491,6 +491,11 @@ struct i2s_codec_s { @@ -491,6 +491,11 @@ struct i2s_codec_s {
491 qemu_irq rx_swallow; 491 qemu_irq rx_swallow;
492 qemu_irq tx_start; 492 qemu_irq tx_start;
493 493
  494 + int tx_rate;
  495 + int cts;
  496 + int rx_rate;
  497 + int rts;
  498 +
494 struct i2s_fifo_s { 499 struct i2s_fifo_s {
495 uint8_t *fifo; 500 uint8_t *fifo;
496 int len; 501 int len;
hw/tsc210x.c
@@ -283,10 +283,30 @@ static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b) @@ -283,10 +283,30 @@ static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b)
283 qemu_irq_raise(s->codec.tx_start); 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 const struct tsc210x_rate_info_s *rate; 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 audsettings_t fmt; 310 audsettings_t fmt;
291 311
292 if (s->dac_voice[0]) { 312 if (s->dac_voice[0]) {
@@ -296,32 +316,26 @@ static void tsc2102_audio_set_format(struct tsc210x_state_s *s) @@ -296,32 +316,26 @@ static void tsc2102_audio_set_format(struct tsc210x_state_s *s)
296 AUD_close_out(&s->card, s->dac_voice[0]); 316 AUD_close_out(&s->card, s->dac_voice[0]);
297 s->dac_voice[0] = 0; 317 s->dac_voice[0] = 0;
298 } 318 }
  319 + s->codec.cts = 0;
299 320
300 enable = 321 enable =
301 (~s->dac_power & (1 << 15)) && /* PWDNC */ 322 (~s->dac_power & (1 << 15)) && /* PWDNC */
302 (~s->dac_power & (1 << 10)); /* DAPWDN */ 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 return; 325 return;
313 - }  
314 326
315 /* Force our own sampling rate even in slave DAC mode */ 327 /* Force our own sampling rate even in slave DAC mode */
316 fmt.endianness = 0; 328 fmt.endianness = 0;
317 fmt.nchannels = 2; 329 fmt.nchannels = 2;
318 - fmt.freq = rate->rate; 330 + fmt.freq = s->codec.tx_rate;
319 fmt.fmt = AUD_FMT_S16; 331 fmt.fmt = AUD_FMT_S16;
320 332
321 s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0], 333 s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
322 "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt); 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 AUD_set_active_out(s->dac_voice[0], 1); 337 AUD_set_active_out(s->dac_voice[0], 1);
  338 + }
325 } 339 }
326 340
327 static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg) 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,8 +601,9 @@ static void tsc2102_audio_register_write(
587 fprintf(stderr, "tsc2102_audio_register_write: " 601 fprintf(stderr, "tsc2102_audio_register_write: "
588 "wrong value written into Audio 1\n"); 602 "wrong value written into Audio 1\n");
589 #endif 603 #endif
  604 + tsc2102_audio_rate_update(s);
590 if (s->audio) 605 if (s->audio)
591 - tsc2102_audio_set_format(s); 606 + tsc2102_audio_output_update(s);
592 return; 607 return;
593 608
594 case 0x01: 609 case 0x01:
@@ -631,8 +646,9 @@ static void tsc2102_audio_register_write( @@ -631,8 +646,9 @@ static void tsc2102_audio_register_write(
631 fprintf(stderr, "tsc2102_audio_register_write: " 646 fprintf(stderr, "tsc2102_audio_register_write: "
632 "wrong value written into Power\n"); 647 "wrong value written into Power\n");
633 #endif 648 #endif
  649 + tsc2102_audio_rate_update(s);
634 if (s->audio) 650 if (s->audio)
635 - tsc2102_audio_set_format(s); 651 + tsc2102_audio_output_update(s);
636 return; 652 return;
637 653
638 case 0x06: /* Audio Control 3 */ 654 case 0x06: /* Audio Control 3 */
@@ -644,7 +660,7 @@ static void tsc2102_audio_register_write( @@ -644,7 +660,7 @@ static void tsc2102_audio_register_write(
644 "wrong value written into Audio 3\n"); 660 "wrong value written into Audio 3\n");
645 #endif 661 #endif
646 if (s->audio) 662 if (s->audio)
647 - tsc2102_audio_set_format(s); 663 + tsc2102_audio_output_update(s);
648 return; 664 return;
649 665
650 case 0x07: /* LCH_BASS_BOOST_N0 */ 666 case 0x07: /* LCH_BASS_BOOST_N0 */