/** * snd_hdac_bus_init_cmd_io - set up CORB/RIRB buffers * @bus: HD-audio core bus
*/ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
{
WARN_ON_ONCE(!bus->rb.area);
spin_lock_irq(&bus->reg_lock); /* CORB set up */
bus->corb.addr = bus->rb.addr;
bus->corb.buf = (__le32 *)bus->rb.area;
snd_hdac_chip_writel(bus, CORBLBASE, (u32)bus->corb.addr);
snd_hdac_chip_writel(bus, CORBUBASE, upper_32_bits(bus->corb.addr));
/* set the corb size to 256 entries (ULI requires explicitly) */
snd_hdac_chip_writeb(bus, CORBSIZE, 0x02); /* set the corb write pointer to 0 */
snd_hdac_chip_writew(bus, CORBWP, 0);
/* reset the corb hw read pointer */
snd_hdac_chip_writew(bus, CORBRP, AZX_CORBRP_RST); if (!bus->corbrp_self_clear)
azx_clear_corbrp(bus);
/* enable corb dma */ if (!bus->use_pio_for_commands)
snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);
/** * snd_hdac_bus_send_cmd_pio - send a command verb via Immediate Command * @bus: HD-audio core bus * @val: encoded verb value to send * * Returns zero for success or a negative error code.
*/ staticint snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsignedint val)
{ unsignedint addr = azx_command_addr(val); int timeout = 50; int ret = -EIO;
spin_lock_irq(&bus->reg_lock);
while (timeout--) { /* check ICB bit */ if (!((snd_hdac_chip_readw(bus, IRS) & AZX_IRS_BUSY))) { /* Clear IRV bit */
snd_hdac_chip_updatew(bus, IRS, AZX_IRS_VALID, AZX_IRS_VALID);
snd_hdac_chip_writel(bus, IC, val); /* Set ICB bit */
snd_hdac_chip_updatew(bus, IRS, AZX_IRS_BUSY, AZX_IRS_BUSY);
ret = snd_hdac_bus_wait_for_pio_response(bus, addr); goto out;
}
udelay(1);
}
/** * snd_hdac_bus_get_response_pio - receive a response via Immediate Response * @bus: HD-audio core bus * @addr: codec address * @res: pointer to store the value, NULL when not needed * * Returns zero if a value is read, or a negative error code.
*/ staticint snd_hdac_bus_get_response_pio(struct hdac_bus *bus, unsignedint addr, unsignedint *res)
{ if (res)
*res = bus->rirb.res[addr];
return 0;
}
/** * snd_hdac_bus_send_cmd_corb - send a command verb via CORB * @bus: HD-audio core bus * @val: encoded verb value to send * * Returns zero for success or a negative error code.
*/ staticint snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsignedint val)
{ unsignedint addr = azx_command_addr(val); unsignedint wp, rp;
/** * snd_hdac_bus_get_response_rirb - receive a response via RIRB * @bus: HD-audio core bus * @addr: codec address * @res: pointer to store the value, NULL when not needed * * Returns zero if a value is read, or a negative error code.
*/ staticint snd_hdac_bus_get_response_rirb(struct hdac_bus *bus, unsignedint addr, unsignedint *res)
{ unsignedlong timeout; unsignedlong loopcounter;
wait_queue_entry_t wait; bool warned = false;
for (loopcounter = 0;; loopcounter++) {
spin_lock_irq(&bus->reg_lock); if (!bus->polling_mode)
prepare_to_wait(&bus->rirb_wq, &wait,
TASK_UNINTERRUPTIBLE); if (bus->polling_mode)
snd_hdac_bus_update_rirb(bus); if (!bus->rirb.cmds[addr]) { if (res)
*res = bus->rirb.res[addr]; /* the last value */ if (!bus->polling_mode)
finish_wait(&bus->rirb_wq, &wait);
spin_unlock_irq(&bus->reg_lock); return 0;
}
spin_unlock_irq(&bus->reg_lock); if (time_after(jiffies, timeout)) break; #define LOOP_COUNT_MAX 3000 if (!bus->polling_mode) {
schedule_timeout(msecs_to_jiffies(2));
} elseif (bus->needs_damn_long_delay ||
loopcounter > LOOP_COUNT_MAX) { if (loopcounter > LOOP_COUNT_MAX && !warned) {
dev_dbg_ratelimited(bus->dev, "too slow response, last cmd=%#08x\n",
bus->last_cmd[addr]);
warned = true;
}
msleep(2); /* temporary workaround */
} else {
udelay(10);
cond_resched();
}
}
if (!bus->polling_mode)
finish_wait(&bus->rirb_wq, &wait);
return -EIO;
}
/** * snd_hdac_bus_send_cmd - send a command verb via CORB or PIO * @bus: HD-audio core bus * @val: encoded verb value to send * * Returns zero for success or a negative error code.
*/ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsignedint val)
{ if (bus->use_pio_for_commands) return snd_hdac_bus_send_cmd_pio(bus, val);
/** * snd_hdac_bus_get_response - receive a response via RIRB or PIO * @bus: HD-audio core bus * @addr: codec address * @res: pointer to store the value, NULL when not needed * * Returns zero if a value is read, or a negative error code.
*/ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsignedint addr, unsignedint *res)
{ if (bus->use_pio_for_commands) return snd_hdac_bus_get_response_pio(bus, addr, res);
/** * snd_hdac_bus_enter_link_reset - enter link reset * @bus: HD-audio core bus * * Enter to the link reset state.
*/ void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus)
{ unsignedlong timeout;
/* delay for >= 100us for codec PLL to settle per spec * Rev 0.9 section 5.5.1
*/
usleep_range(500, 1000);
/* Bring controller out of reset */
snd_hdac_bus_exit_link_reset(bus);
/* Brent Chartrand said to wait >= 540us for codecs to initialize */
usleep_range(1000, 1200);
skip_reset: /* check to see if controller is ready */ if (!snd_hdac_chip_readb(bus, GCTL)) {
dev_dbg(bus->dev, "controller not ready!\n"); return -EBUSY;
}
/* initialize the codec command I/O */
snd_hdac_bus_init_cmd_io(bus);
/* enable interrupts after CORB/RIRB buffers are initialized above */
azx_int_enable(bus);
/* program the position buffer */ if (bus->use_posbuf && bus->posbuf.addr) {
snd_hdac_chip_writel(bus, DPLBASE, (u32)bus->posbuf.addr);
snd_hdac_chip_writel(bus, DPUBASE, upper_32_bits(bus->posbuf.addr));
}
/** * snd_hdac_bus_handle_stream_irq - interrupt handler for streams * @bus: HD-audio core bus * @status: INTSTS register value * @ack: callback to be called for woken streams * * Returns the bits of handled streams, or zero if no stream is handled.
*/ int snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsignedint status, void (*ack)(struct hdac_bus *, struct hdac_stream *))
{ struct hdac_stream *azx_dev;
u8 sd_status; int handled = 0;
/** * snd_hdac_bus_alloc_stream_pages - allocate BDL and other buffers * @bus: HD-audio core bus * * Call this after assigning the all streams. * Returns zero for success, or a negative error code.
*/ int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus)
{ struct hdac_stream *s; int num_streams = 0; int dma_type = bus->dma_type ? bus->dma_type : SNDRV_DMA_TYPE_DEV; int err;
list_for_each_entry(s, &bus->stream_list, list) { /* allocate memory for the BDL for each stream */
err = snd_dma_alloc_pages(dma_type, bus->dev,
BDL_SIZE, &s->bdl);
num_streams++; if (err < 0) return -ENOMEM;
}
if (WARN_ON(!num_streams)) return -EINVAL; /* allocate memory for the position buffer */
err = snd_dma_alloc_pages(dma_type, bus->dev,
num_streams * 8, &bus->posbuf); if (err < 0) return -ENOMEM;
list_for_each_entry(s, &bus->stream_list, list)
s->posbuf = (__le32 *)(bus->posbuf.area + s->index * 8);
/* single page (at least 4096 bytes) must suffice for both ringbuffes */ return snd_dma_alloc_pages(dma_type, bus->dev, PAGE_SIZE, &bus->rb);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_alloc_stream_pages);
/** * snd_hdac_bus_free_stream_pages - release BDL and other buffers * @bus: HD-audio core bus
*/ void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus)
{ struct hdac_stream *s;
list_for_each_entry(s, &bus->stream_list, list) { if (s->bdl.area)
snd_dma_free_pages(&s->bdl);
}
if (bus->rb.area)
snd_dma_free_pages(&bus->rb); if (bus->posbuf.area)
snd_dma_free_pages(&bus->posbuf);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_free_stream_pages);
/** * snd_hdac_bus_link_power - power up/down codec link * @codec: HD-audio device * @enable: whether to power-up the link
*/ void snd_hdac_bus_link_power(struct hdac_device *codec, bool enable)
{ if (enable)
set_bit(codec->addr, &codec->bus->codec_powered); else
clear_bit(codec->addr, &codec->bus->codec_powered);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_link_power);
Messung V0.5
¤ Dauer der Verarbeitung: 0.2 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.