Clean-up/rewrite audio over I^2S support.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3704 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
		
							parent
							
								
									79b0241756
								
							
						
					
					
						commit
						73560bc8e3
					
				
							
								
								
									
										294
									
								
								hw/omap.c
									
									
									
									
									
								
							
							
						
						
									
										294
									
								
								hw/omap.c
									
									
									
									
									
								
							@ -997,7 +997,8 @@ static void omap_dma_clk_update(void *opaque, int line, int on)
 | 
				
			|||||||
    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
 | 
					    struct omap_dma_s *s = (struct omap_dma_s *) opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (on) {
 | 
					    if (on) {
 | 
				
			||||||
        s->delay = ticks_per_sec >> 7;
 | 
					        /* TODO: make a clever calculation */
 | 
				
			||||||
 | 
					        s->delay = ticks_per_sec >> 8;
 | 
				
			||||||
        if (s->run_count)
 | 
					        if (s->run_count)
 | 
				
			||||||
            qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
 | 
					            qemu_mod_timer(s->tm, qemu_get_clock(vm_clock) + s->delay);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
@ -4097,8 +4098,11 @@ struct omap_mcbsp_s {
 | 
				
			|||||||
    int tx_rate;
 | 
					    int tx_rate;
 | 
				
			||||||
    int rx_rate;
 | 
					    int rx_rate;
 | 
				
			||||||
    int tx_req;
 | 
					    int tx_req;
 | 
				
			||||||
 | 
					    int rx_req;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct i2s_codec_s *codec;
 | 
					    struct i2s_codec_s *codec;
 | 
				
			||||||
 | 
					    QEMUTimer *source_timer;
 | 
				
			||||||
 | 
					    QEMUTimer *sink_timer;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
 | 
					static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
 | 
				
			||||||
@ -4134,62 +4138,8 @@ static void omap_mcbsp_intr_update(struct omap_mcbsp_s *s)
 | 
				
			|||||||
    qemu_set_irq(s->txirq, irq);
 | 
					    qemu_set_irq(s->txirq, irq);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
 | 
					static void omap_mcbsp_rx_newdata(struct omap_mcbsp_s *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int prev = s->tx_req;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s->tx_req = (s->tx_rate ||
 | 
					 | 
				
			||||||
                    (s->spcr[0] & (1 << 12))) &&	/* CLKSTP */
 | 
					 | 
				
			||||||
            (s->spcr[1] & (1 << 6)) &&			/* GRST */
 | 
					 | 
				
			||||||
            (s->spcr[1] & (1 << 0));			/* XRST */
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (!s->tx_req && prev) {
 | 
					 | 
				
			||||||
        s->spcr[1] &= ~(1 << 1);			/* XRDY */
 | 
					 | 
				
			||||||
        qemu_irq_lower(s->txdrq);
 | 
					 | 
				
			||||||
        omap_mcbsp_intr_update(s);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if (s->codec)
 | 
					 | 
				
			||||||
            s->codec->tx_swallow(s->codec->opaque);
 | 
					 | 
				
			||||||
    } else if (s->codec && s->tx_req && !prev) {
 | 
					 | 
				
			||||||
        s->spcr[1] |= 1 << 1;				/* XRDY */
 | 
					 | 
				
			||||||
        qemu_irq_raise(s->txdrq);
 | 
					 | 
				
			||||||
        omap_mcbsp_intr_update(s);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void omap_mcbsp_rate_update(struct omap_mcbsp_s *s)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    int rx_clk = 0, tx_clk = 0;
 | 
					 | 
				
			||||||
    int cpu_rate = 1500000;	/* XXX */
 | 
					 | 
				
			||||||
    if (!s->codec)
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if (s->spcr[1] & (1 << 6)) {			/* GRST */
 | 
					 | 
				
			||||||
        if (s->spcr[0] & (1 << 0))			/* RRST */
 | 
					 | 
				
			||||||
            if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
 | 
					 | 
				
			||||||
                            (s->pcr & (1 << 8)))	/* CLKRM */
 | 
					 | 
				
			||||||
                if (~s->pcr & (1 << 7))			/* SCLKME */
 | 
					 | 
				
			||||||
                    rx_clk = cpu_rate /
 | 
					 | 
				
			||||||
                            ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
 | 
					 | 
				
			||||||
        if (s->spcr[1] & (1 << 0))			/* XRST */
 | 
					 | 
				
			||||||
            if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
 | 
					 | 
				
			||||||
                            (s->pcr & (1 << 9)))	/* CLKXM */
 | 
					 | 
				
			||||||
                if (~s->pcr & (1 << 7))			/* SCLKME */
 | 
					 | 
				
			||||||
                    tx_clk = cpu_rate /
 | 
					 | 
				
			||||||
                            ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    s->codec->set_rate(s->codec->opaque, rx_clk, tx_clk);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
    if (!(s->spcr[0] & 1)) {				/* RRST */
 | 
					 | 
				
			||||||
        if (s->codec)
 | 
					 | 
				
			||||||
            s->codec->in.len = 0;
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    if ((s->spcr[0] >> 1) & 1)				/* RRDY */
 | 
					    if ((s->spcr[0] >> 1) & 1)				/* RRDY */
 | 
				
			||||||
        s->spcr[0] |= 1 << 2;				/* RFULL */
 | 
					        s->spcr[0] |= 1 << 2;				/* RFULL */
 | 
				
			||||||
    s->spcr[0] |= 1 << 1;				/* RRDY */
 | 
					    s->spcr[0] |= 1 << 1;				/* RRDY */
 | 
				
			||||||
@ -4197,25 +4147,140 @@ static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s)
 | 
				
			|||||||
    omap_mcbsp_intr_update(s);
 | 
					    omap_mcbsp_intr_update(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_source_tick(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
				
			||||||
 | 
					    static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!s->rx_rate)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    if (s->rx_req)
 | 
				
			||||||
 | 
					        printf("%s: Rx FIFO overrun\n", __FUNCTION__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->rx_req = s->rx_rate << bps[(s->rcr[0] >> 5) & 7];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    omap_mcbsp_rx_newdata(s);
 | 
				
			||||||
 | 
					    qemu_mod_timer(s->source_timer, qemu_get_clock(vm_clock) + ticks_per_sec);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_rx_start(struct omap_mcbsp_s *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    if (!s->codec || !s->codec->rts)
 | 
				
			||||||
 | 
					        omap_mcbsp_source_tick(s);
 | 
				
			||||||
 | 
					    else if (s->codec->in.len) {
 | 
				
			||||||
 | 
					        s->rx_req = s->codec->in.len;
 | 
				
			||||||
 | 
					        omap_mcbsp_rx_newdata(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s)
 | 
					static void omap_mcbsp_rx_stop(struct omap_mcbsp_s *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    qemu_del_timer(s->source_timer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_rx_done(struct omap_mcbsp_s *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    s->spcr[0] &= ~(1 << 1);				/* RRDY */
 | 
					    s->spcr[0] &= ~(1 << 1);				/* RRDY */
 | 
				
			||||||
    qemu_irq_lower(s->rxdrq);
 | 
					    qemu_irq_lower(s->rxdrq);
 | 
				
			||||||
    omap_mcbsp_intr_update(s);
 | 
					    omap_mcbsp_intr_update(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_tx_newdata(struct omap_mcbsp_s *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    s->spcr[1] |= 1 << 1;				/* XRDY */
 | 
				
			||||||
 | 
					    qemu_irq_raise(s->txdrq);
 | 
				
			||||||
 | 
					    omap_mcbsp_intr_update(s);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_sink_tick(void *opaque)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
				
			||||||
 | 
					    static const int bps[8] = { 0, 1, 1, 2, 2, 2, -255, -255 };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!s->tx_rate)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    if (s->tx_req)
 | 
				
			||||||
 | 
					        printf("%s: Tx FIFO underrun\n", __FUNCTION__);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->tx_req = s->tx_rate << bps[(s->xcr[0] >> 5) & 7];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    omap_mcbsp_tx_newdata(s);
 | 
				
			||||||
 | 
					    qemu_mod_timer(s->sink_timer, qemu_get_clock(vm_clock) + ticks_per_sec);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s)
 | 
					static void omap_mcbsp_tx_start(struct omap_mcbsp_s *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    if (s->tx_rate)
 | 
					    if (!s->codec || !s->codec->cts)
 | 
				
			||||||
        return;
 | 
					        omap_mcbsp_sink_tick(s);
 | 
				
			||||||
    s->tx_rate = 1;
 | 
					    else if (s->codec->out.size) {
 | 
				
			||||||
    omap_mcbsp_req_update(s);
 | 
					        s->tx_req = s->codec->out.size;
 | 
				
			||||||
 | 
					        omap_mcbsp_tx_newdata(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_tx_done(struct omap_mcbsp_s *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    s->spcr[1] &= ~(1 << 1);				/* XRDY */
 | 
				
			||||||
 | 
					    qemu_irq_lower(s->txdrq);
 | 
				
			||||||
 | 
					    omap_mcbsp_intr_update(s);
 | 
				
			||||||
 | 
					    if (s->codec && s->codec->cts)
 | 
				
			||||||
 | 
					        s->codec->tx_swallow(s->codec->opaque);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s)
 | 
					static void omap_mcbsp_tx_stop(struct omap_mcbsp_s *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    s->tx_rate = 0;
 | 
					    s->tx_req = 0;
 | 
				
			||||||
    omap_mcbsp_req_update(s);
 | 
					    omap_mcbsp_tx_done(s);
 | 
				
			||||||
 | 
					    qemu_del_timer(s->sink_timer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_req_update(struct omap_mcbsp_s *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int prev_rx_rate, prev_tx_rate;
 | 
				
			||||||
 | 
					    int rx_rate = 0, tx_rate = 0;
 | 
				
			||||||
 | 
					    int cpu_rate = 1500000;	/* XXX */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* TODO: check CLKSTP bit */
 | 
				
			||||||
 | 
					    if (s->spcr[1] & (1 << 6)) {			/* GRST */
 | 
				
			||||||
 | 
					        if (s->spcr[0] & (1 << 0)) {			/* RRST */
 | 
				
			||||||
 | 
					            if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
 | 
				
			||||||
 | 
					                            (s->pcr & (1 << 8))) {	/* CLKRM */
 | 
				
			||||||
 | 
					                if (~s->pcr & (1 << 7))			/* SCLKME */
 | 
				
			||||||
 | 
					                    rx_rate = cpu_rate /
 | 
				
			||||||
 | 
					                            ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
 | 
				
			||||||
 | 
					            } else
 | 
				
			||||||
 | 
					                if (s->codec)
 | 
				
			||||||
 | 
					                    rx_rate = s->codec->rx_rate;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (s->spcr[1] & (1 << 0)) {			/* XRST */
 | 
				
			||||||
 | 
					            if ((s->srgr[1] & (1 << 13)) &&		/* CLKSM */
 | 
				
			||||||
 | 
					                            (s->pcr & (1 << 9))) {	/* CLKXM */
 | 
				
			||||||
 | 
					                if (~s->pcr & (1 << 7))			/* SCLKME */
 | 
				
			||||||
 | 
					                    tx_rate = cpu_rate /
 | 
				
			||||||
 | 
					                            ((s->srgr[0] & 0xff) + 1);	/* CLKGDV */
 | 
				
			||||||
 | 
					            } else
 | 
				
			||||||
 | 
					                if (s->codec)
 | 
				
			||||||
 | 
					                    tx_rate = s->codec->tx_rate;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    prev_tx_rate = s->tx_rate;
 | 
				
			||||||
 | 
					    prev_rx_rate = s->rx_rate;
 | 
				
			||||||
 | 
					    s->tx_rate = tx_rate;
 | 
				
			||||||
 | 
					    s->rx_rate = rx_rate;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->codec)
 | 
				
			||||||
 | 
					        s->codec->set_rate(s->codec->opaque, rx_rate, tx_rate);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!prev_tx_rate && tx_rate)
 | 
				
			||||||
 | 
					        omap_mcbsp_tx_start(s);
 | 
				
			||||||
 | 
					    else if (s->tx_rate && !tx_rate)
 | 
				
			||||||
 | 
					        omap_mcbsp_tx_stop(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (!prev_rx_rate && rx_rate)
 | 
				
			||||||
 | 
					        omap_mcbsp_rx_start(s);
 | 
				
			||||||
 | 
					    else if (prev_tx_rate && !tx_rate)
 | 
				
			||||||
 | 
					        omap_mcbsp_rx_stop(s);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
 | 
					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)
 | 
				
			|||||||
            return 0x0000;
 | 
					            return 0x0000;
 | 
				
			||||||
        /* Fall through.  */
 | 
					        /* Fall through.  */
 | 
				
			||||||
    case 0x02:	/* DRR1 */
 | 
					    case 0x02:	/* DRR1 */
 | 
				
			||||||
        if (!s->codec)
 | 
					        if (s->rx_req < 2) {
 | 
				
			||||||
            return 0x0000;
 | 
					 | 
				
			||||||
        if (s->codec->in.len < 2) {
 | 
					 | 
				
			||||||
            printf("%s: Rx FIFO underrun\n", __FUNCTION__);
 | 
					            printf("%s: Rx FIFO underrun\n", __FUNCTION__);
 | 
				
			||||||
            omap_mcbsp_rx_stop(s);
 | 
					            omap_mcbsp_rx_done(s);
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            s->codec->in.len -= 2;
 | 
					            s->tx_req -= 2;
 | 
				
			||||||
            ret = s->codec->in.fifo[s->codec->in.start ++] << 8;
 | 
					            if (s->codec && s->codec->in.len >= 2) {
 | 
				
			||||||
            ret |= s->codec->in.fifo[s->codec->in.start ++];
 | 
					                ret = s->codec->in.fifo[s->codec->in.start ++] << 8;
 | 
				
			||||||
            if (!s->codec->in.len)
 | 
					                ret |= s->codec->in.fifo[s->codec->in.start ++];
 | 
				
			||||||
                omap_mcbsp_rx_stop(s);
 | 
					                s->codec->in.len -= 2;
 | 
				
			||||||
 | 
					            } else
 | 
				
			||||||
 | 
					                ret = 0x0000;
 | 
				
			||||||
 | 
					            if (!s->tx_req)
 | 
				
			||||||
 | 
					                omap_mcbsp_rx_done(s);
 | 
				
			||||||
            return ret;
 | 
					            return ret;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return 0x0000;
 | 
					        return 0x0000;
 | 
				
			||||||
@ -4309,7 +4376,7 @@ static uint32_t omap_mcbsp_read(void *opaque, target_phys_addr_t addr)
 | 
				
			|||||||
    return 0;
 | 
					    return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
 | 
					static void omap_mcbsp_writeh(void *opaque, target_phys_addr_t addr,
 | 
				
			||||||
                uint32_t value)
 | 
					                uint32_t value)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
					    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,
 | 
				
			|||||||
            return;
 | 
					            return;
 | 
				
			||||||
        /* Fall through.  */
 | 
					        /* Fall through.  */
 | 
				
			||||||
    case 0x06:	/* DXR1 */
 | 
					    case 0x06:	/* DXR1 */
 | 
				
			||||||
        if (!s->codec)
 | 
					        if (s->tx_req > 1) {
 | 
				
			||||||
            return;
 | 
					            s->tx_req -= 2;
 | 
				
			||||||
        if (s->tx_req) {
 | 
					            if (s->codec && s->codec->cts) {
 | 
				
			||||||
            if (s->codec->out.len > s->codec->out.size - 2) {
 | 
					 | 
				
			||||||
                printf("%s: Tx FIFO overrun\n", __FUNCTION__);
 | 
					 | 
				
			||||||
                omap_mcbsp_tx_stop(s);
 | 
					 | 
				
			||||||
            } else {
 | 
					 | 
				
			||||||
                s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff;
 | 
					                s->codec->out.fifo[s->codec->out.len ++] = (value >> 8) & 0xff;
 | 
				
			||||||
                s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff;
 | 
					                s->codec->out.fifo[s->codec->out.len ++] = (value >> 0) & 0xff;
 | 
				
			||||||
                if (s->codec->out.len >= s->codec->out.size)
 | 
					 | 
				
			||||||
                    omap_mcbsp_tx_stop(s);
 | 
					 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            if (s->tx_req < 2)
 | 
				
			||||||
 | 
					                omap_mcbsp_tx_done(s);
 | 
				
			||||||
        } else
 | 
					        } else
 | 
				
			||||||
            printf("%s: Tx FIFO overrun\n", __FUNCTION__);
 | 
					            printf("%s: Tx FIFO overrun\n", __FUNCTION__);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
@ -4346,14 +4409,8 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
 | 
				
			|||||||
        s->spcr[1] &= 0x0002;
 | 
					        s->spcr[1] &= 0x0002;
 | 
				
			||||||
        s->spcr[1] |= 0x03f9 & value;
 | 
					        s->spcr[1] |= 0x03f9 & value;
 | 
				
			||||||
        s->spcr[1] |= 0x0004 & (value << 2);		/* XEMPTY := XRST */
 | 
					        s->spcr[1] |= 0x0004 & (value << 2);		/* XEMPTY := XRST */
 | 
				
			||||||
        if (~value & 1) {				/* XRST */
 | 
					        if (~value & 1)					/* XRST */
 | 
				
			||||||
            s->spcr[1] &= ~6;
 | 
					            s->spcr[1] &= ~6;
 | 
				
			||||||
            qemu_irq_lower(s->rxdrq);
 | 
					 | 
				
			||||||
            if (s->codec)
 | 
					 | 
				
			||||||
                s->codec->out.len = 0;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        if (s->codec)
 | 
					 | 
				
			||||||
            omap_mcbsp_rate_update(s);
 | 
					 | 
				
			||||||
        omap_mcbsp_req_update(s);
 | 
					        omap_mcbsp_req_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    case 0x0a:	/* SPCR1 */
 | 
					    case 0x0a:	/* SPCR1 */
 | 
				
			||||||
@ -4363,12 +4420,9 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
 | 
				
			|||||||
            printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__);
 | 
					            printf("%s: Digital Loopback mode enable attempt\n", __FUNCTION__);
 | 
				
			||||||
        if (~value & 1) {				/* RRST */
 | 
					        if (~value & 1) {				/* RRST */
 | 
				
			||||||
            s->spcr[0] &= ~6;
 | 
					            s->spcr[0] &= ~6;
 | 
				
			||||||
            qemu_irq_lower(s->txdrq);
 | 
					            s->rx_req = 0;
 | 
				
			||||||
            if (s->codec)
 | 
					            omap_mcbsp_rx_done(s);
 | 
				
			||||||
                s->codec->in.len = 0;
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (s->codec)
 | 
					 | 
				
			||||||
            omap_mcbsp_rate_update(s);
 | 
					 | 
				
			||||||
        omap_mcbsp_req_update(s);
 | 
					        omap_mcbsp_req_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -4386,11 +4440,11 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    case 0x14:	/* SRGR2 */
 | 
					    case 0x14:	/* SRGR2 */
 | 
				
			||||||
        s->srgr[1] = value & 0xffff;
 | 
					        s->srgr[1] = value & 0xffff;
 | 
				
			||||||
        omap_mcbsp_rate_update(s);
 | 
					        omap_mcbsp_req_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    case 0x16:	/* SRGR1 */
 | 
					    case 0x16:	/* SRGR1 */
 | 
				
			||||||
        s->srgr[0] = value & 0xffff;
 | 
					        s->srgr[0] = value & 0xffff;
 | 
				
			||||||
        omap_mcbsp_rate_update(s);
 | 
					        omap_mcbsp_req_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
    case 0x18:	/* MCR2 */
 | 
					    case 0x18:	/* MCR2 */
 | 
				
			||||||
        s->mcr[1] = value & 0x03e3;
 | 
					        s->mcr[1] = value & 0x03e3;
 | 
				
			||||||
@ -4460,6 +4514,37 @@ static void omap_mcbsp_write(void *opaque, target_phys_addr_t addr,
 | 
				
			|||||||
    OMAP_BAD_REG(addr);
 | 
					    OMAP_BAD_REG(addr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void omap_mcbsp_writew(void *opaque, target_phys_addr_t addr,
 | 
				
			||||||
 | 
					                uint32_t value)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
				
			||||||
 | 
					    int offset = addr & OMAP_MPUI_REG_MASK;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (offset == 0x04) {				/* DXR */
 | 
				
			||||||
 | 
					        if (((s->xcr[0] >> 5) & 7) < 3)			/* XWDLEN1 */
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        if (s->tx_req > 3) {
 | 
				
			||||||
 | 
					            s->tx_req -= 4;
 | 
				
			||||||
 | 
					            if (s->codec && s->codec->cts) {
 | 
				
			||||||
 | 
					                s->codec->out.fifo[s->codec->out.len ++] =
 | 
				
			||||||
 | 
					                        (value >> 24) & 0xff;
 | 
				
			||||||
 | 
					                s->codec->out.fifo[s->codec->out.len ++] =
 | 
				
			||||||
 | 
					                        (value >> 16) & 0xff;
 | 
				
			||||||
 | 
					                s->codec->out.fifo[s->codec->out.len ++] =
 | 
				
			||||||
 | 
					                        (value >> 8) & 0xff;
 | 
				
			||||||
 | 
					                s->codec->out.fifo[s->codec->out.len ++] =
 | 
				
			||||||
 | 
					                        (value >> 0) & 0xff;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (s->tx_req < 4)
 | 
				
			||||||
 | 
					                omap_mcbsp_tx_done(s);
 | 
				
			||||||
 | 
					        } else
 | 
				
			||||||
 | 
					            printf("%s: Tx FIFO overrun\n", __FUNCTION__);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    omap_badwidth_write16(opaque, addr, value);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static CPUReadMemoryFunc *omap_mcbsp_readfn[] = {
 | 
					static CPUReadMemoryFunc *omap_mcbsp_readfn[] = {
 | 
				
			||||||
    omap_badwidth_read16,
 | 
					    omap_badwidth_read16,
 | 
				
			||||||
    omap_mcbsp_read,
 | 
					    omap_mcbsp_read,
 | 
				
			||||||
@ -4468,8 +4553,8 @@ static CPUReadMemoryFunc *omap_mcbsp_readfn[] = {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = {
 | 
					static CPUWriteMemoryFunc *omap_mcbsp_writefn[] = {
 | 
				
			||||||
    omap_badwidth_write16,
 | 
					    omap_badwidth_write16,
 | 
				
			||||||
    omap_mcbsp_write,
 | 
					    omap_mcbsp_writeh,
 | 
				
			||||||
    omap_badwidth_write16,
 | 
					    omap_mcbsp_writew,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
 | 
					static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
 | 
				
			||||||
@ -4484,8 +4569,11 @@ static void omap_mcbsp_reset(struct omap_mcbsp_s *s)
 | 
				
			|||||||
    memset(&s->rcer, 0, sizeof(s->rcer));
 | 
					    memset(&s->rcer, 0, sizeof(s->rcer));
 | 
				
			||||||
    memset(&s->xcer, 0, sizeof(s->xcer));
 | 
					    memset(&s->xcer, 0, sizeof(s->xcer));
 | 
				
			||||||
    s->tx_req = 0;
 | 
					    s->tx_req = 0;
 | 
				
			||||||
 | 
					    s->rx_req = 0;
 | 
				
			||||||
    s->tx_rate = 0;
 | 
					    s->tx_rate = 0;
 | 
				
			||||||
    s->rx_rate = 0;
 | 
					    s->rx_rate = 0;
 | 
				
			||||||
 | 
					    qemu_del_timer(s->source_timer);
 | 
				
			||||||
 | 
					    qemu_del_timer(s->sink_timer);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct omap_mcbsp_s *omap_mcbsp_init(target_phys_addr_t base,
 | 
					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,
 | 
				
			|||||||
    s->rxirq = irq[1];
 | 
					    s->rxirq = irq[1];
 | 
				
			||||||
    s->txdrq = dma[0];
 | 
					    s->txdrq = dma[0];
 | 
				
			||||||
    s->rxdrq = dma[1];
 | 
					    s->rxdrq = dma[1];
 | 
				
			||||||
 | 
					    s->sink_timer = qemu_new_timer(vm_clock, omap_mcbsp_sink_tick, s);
 | 
				
			||||||
 | 
					    s->source_timer = qemu_new_timer(vm_clock, omap_mcbsp_source_tick, s);
 | 
				
			||||||
    omap_mcbsp_reset(s);
 | 
					    omap_mcbsp_reset(s);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    iomemtype = cpu_register_io_memory(0, omap_mcbsp_readfn,
 | 
					    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)
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
					    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    omap_mcbsp_rx_start(s);
 | 
					    if (s->rx_rate) {
 | 
				
			||||||
 | 
					        s->rx_req = s->codec->in.len;
 | 
				
			||||||
 | 
					        omap_mcbsp_rx_newdata(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void omap_mcbsp_i2s_start(void *opaque, int line, int level)
 | 
					static void omap_mcbsp_i2s_start(void *opaque, int line, int level)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
					    struct omap_mcbsp_s *s = (struct omap_mcbsp_s *) opaque;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    omap_mcbsp_tx_start(s);
 | 
					    if (s->tx_rate) {
 | 
				
			||||||
 | 
					        s->tx_req = s->codec->out.size;
 | 
				
			||||||
 | 
					        omap_mcbsp_tx_newdata(s);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave)
 | 
					void omap_mcbsp_i2s_attach(struct omap_mcbsp_s *s, struct i2s_codec_s *slave)
 | 
				
			||||||
 | 
				
			|||||||
@ -491,6 +491,11 @@ struct i2s_codec_s {
 | 
				
			|||||||
    qemu_irq rx_swallow;
 | 
					    qemu_irq rx_swallow;
 | 
				
			||||||
    qemu_irq tx_start;
 | 
					    qemu_irq tx_start;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    int tx_rate;
 | 
				
			||||||
 | 
					    int cts;
 | 
				
			||||||
 | 
					    int rx_rate;
 | 
				
			||||||
 | 
					    int rts;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct i2s_fifo_s {
 | 
					    struct i2s_fifo_s {
 | 
				
			||||||
        uint8_t *fifo;
 | 
					        uint8_t *fifo;
 | 
				
			||||||
        int len;
 | 
					        int len;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										56
									
								
								hw/tsc210x.c
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								hw/tsc210x.c
									
									
									
									
									
								
							@ -283,24 +283,13 @@ static void tsc210x_audio_out_cb(struct tsc210x_state_s *s, int free_b)
 | 
				
			|||||||
    qemu_irq_raise(s->codec.tx_start);
 | 
					    qemu_irq_raise(s->codec.tx_start);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void tsc2102_audio_set_format(struct tsc210x_state_s *s)
 | 
					static void tsc2102_audio_rate_update(struct tsc210x_state_s *s)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
    int enable;
 | 
					 | 
				
			||||||
    const struct tsc210x_rate_info_s *rate;
 | 
					    const struct tsc210x_rate_info_s *rate;
 | 
				
			||||||
    audsettings_t fmt;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (s->dac_voice[0]) {
 | 
					    s->codec.tx_rate = 0;
 | 
				
			||||||
        tsc210x_out_flush(s, s->codec.out.len);
 | 
					    s->codec.rx_rate = 0;
 | 
				
			||||||
        s->codec.out.size = 0;
 | 
					    if (s->dac_power & (1 << 15))				/* PWDNC */
 | 
				
			||||||
        AUD_set_active_out(s->dac_voice[0], 0);
 | 
					 | 
				
			||||||
        AUD_close_out(&s->card, s->dac_voice[0]);
 | 
					 | 
				
			||||||
        s->dac_voice[0] = 0;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    enable =
 | 
					 | 
				
			||||||
            (~s->dac_power & (1 << 15)) &&			/* PWDNC */
 | 
					 | 
				
			||||||
            (~s->dac_power & (1 << 10));			/* DAPWDN */
 | 
					 | 
				
			||||||
    if (!enable)
 | 
					 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    for (rate = tsc2102_rates; rate->rate; rate ++)
 | 
					    for (rate = tsc2102_rates; rate->rate; rate ++)
 | 
				
			||||||
@ -312,16 +301,41 @@ static void tsc2102_audio_set_format(struct tsc210x_state_s *s)
 | 
				
			|||||||
        return;
 | 
					        return;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    s->codec.tx_rate = rate->rate;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void tsc2102_audio_output_update(struct tsc210x_state_s *s)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    int enable;
 | 
				
			||||||
 | 
					    audsettings_t fmt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (s->dac_voice[0]) {
 | 
				
			||||||
 | 
					        tsc210x_out_flush(s, s->codec.out.len);
 | 
				
			||||||
 | 
					        s->codec.out.size = 0;
 | 
				
			||||||
 | 
					        AUD_set_active_out(s->dac_voice[0], 0);
 | 
				
			||||||
 | 
					        AUD_close_out(&s->card, s->dac_voice[0]);
 | 
				
			||||||
 | 
					        s->dac_voice[0] = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    s->codec.cts = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    enable =
 | 
				
			||||||
 | 
					            (~s->dac_power & (1 << 15)) &&			/* PWDNC */
 | 
				
			||||||
 | 
					            (~s->dac_power & (1 << 10));			/* DAPWDN */
 | 
				
			||||||
 | 
					    if (!enable || !s->codec.tx_rate)
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /* Force our own sampling rate even in slave DAC mode */
 | 
					    /* Force our own sampling rate even in slave DAC mode */
 | 
				
			||||||
    fmt.endianness = 0;
 | 
					    fmt.endianness = 0;
 | 
				
			||||||
    fmt.nchannels = 2;
 | 
					    fmt.nchannels = 2;
 | 
				
			||||||
    fmt.freq = rate->rate;
 | 
					    fmt.freq = s->codec.tx_rate;
 | 
				
			||||||
    fmt.fmt = AUD_FMT_S16;
 | 
					    fmt.fmt = AUD_FMT_S16;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
 | 
					    s->dac_voice[0] = AUD_open_out(&s->card, s->dac_voice[0],
 | 
				
			||||||
                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
 | 
					                    "tsc2102.sink", s, (void *) tsc210x_audio_out_cb, &fmt);
 | 
				
			||||||
    if (s->dac_voice[0])
 | 
					    if (s->dac_voice[0]) {
 | 
				
			||||||
 | 
					        s->codec.cts = 1;
 | 
				
			||||||
        AUD_set_active_out(s->dac_voice[0], 1);
 | 
					        AUD_set_active_out(s->dac_voice[0], 1);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg)
 | 
					static uint16_t tsc2102_data_register_read(struct tsc210x_state_s *s, int reg)
 | 
				
			||||||
@ -587,8 +601,9 @@ static void tsc2102_audio_register_write(
 | 
				
			|||||||
            fprintf(stderr, "tsc2102_audio_register_write: "
 | 
					            fprintf(stderr, "tsc2102_audio_register_write: "
 | 
				
			||||||
                            "wrong value written into Audio 1\n");
 | 
					                            "wrong value written into Audio 1\n");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					        tsc2102_audio_rate_update(s);
 | 
				
			||||||
        if (s->audio)
 | 
					        if (s->audio)
 | 
				
			||||||
            tsc2102_audio_set_format(s);
 | 
					            tsc2102_audio_output_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case 0x01:
 | 
					    case 0x01:
 | 
				
			||||||
@ -631,8 +646,9 @@ static void tsc2102_audio_register_write(
 | 
				
			|||||||
            fprintf(stderr, "tsc2102_audio_register_write: "
 | 
					            fprintf(stderr, "tsc2102_audio_register_write: "
 | 
				
			||||||
                            "wrong value written into Power\n");
 | 
					                            "wrong value written into Power\n");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					        tsc2102_audio_rate_update(s);
 | 
				
			||||||
        if (s->audio)
 | 
					        if (s->audio)
 | 
				
			||||||
            tsc2102_audio_set_format(s);
 | 
					            tsc2102_audio_output_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case 0x06:	/* Audio Control 3 */
 | 
					    case 0x06:	/* Audio Control 3 */
 | 
				
			||||||
@ -644,7 +660,7 @@ static void tsc2102_audio_register_write(
 | 
				
			|||||||
                            "wrong value written into Audio 3\n");
 | 
					                            "wrong value written into Audio 3\n");
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
        if (s->audio)
 | 
					        if (s->audio)
 | 
				
			||||||
            tsc2102_audio_set_format(s);
 | 
					            tsc2102_audio_output_update(s);
 | 
				
			||||||
        return;
 | 
					        return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    case 0x07:	/* LCH_BASS_BOOST_N0 */
 | 
					    case 0x07:	/* LCH_BASS_BOOST_N0 */
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user