Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/sound/hdaudio.h
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@ struct hdac_bus {
bool needs_damn_long_delay:1;
bool not_use_interrupts:1; /* prohibiting the RIRB IRQ */
bool access_sdnctl_in_dword:1; /* accessing the sdnctl register by dword */
bool use_pio_for_commands:1; /* Use PIO instead of CORB for commands */

int poll_count;

Expand Down
127 changes: 120 additions & 7 deletions sound/hda/hdac_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus)
azx_clear_corbrp(bus);

/* enable corb dma */
snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);
if (!bus->use_pio_for_commands)
snd_hdac_chip_writeb(bus, CORBCTL, AZX_CORBCTL_RUN);

/* RIRB set up */
bus->rirb.addr = bus->rb.addr + 2048;
Expand Down Expand Up @@ -135,14 +136,94 @@ static unsigned int azx_command_addr(u32 cmd)
return addr;
}

/* receive an Immediate Response with PIO */
static int snd_hdac_bus_wait_for_pio_response(struct hdac_bus *bus,
Comment thread
plbossart marked this conversation as resolved.
Resolved
unsigned int addr)
{
int timeout = 50;

while (timeout--) {
/* check IRV bit */
if (snd_hdac_chip_readw(bus, IRS) & AZX_IRS_VALID) {
/* reuse rirb.res as the response return value */
bus->rirb.res[addr] = snd_hdac_chip_readl(bus, IR);
return 0;
}
udelay(1);
}

dev_dbg_ratelimited(bus->dev, "get_response_pio timeout: IRS=%#x\n",
snd_hdac_chip_readw(bus, IRS));

bus->rirb.res[addr] = -1;

return -EIO;
}

/**
* snd_hdac_bus_send_cmd - send a command verb via CORB
* 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.
*/
int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)
static int snd_hdac_bus_send_cmd_pio(struct hdac_bus *bus, unsigned int val)
{
unsigned int 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);
}

dev_dbg_ratelimited(bus->dev, "send_cmd_pio timeout: IRS=%#x, val=%#x\n",
snd_hdac_chip_readw(bus, IRS), val);

out:
spin_unlock_irq(&bus->reg_lock);

return ret;
}

/**
* 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.
*/
static int snd_hdac_bus_get_response_pio(struct hdac_bus *bus,
unsigned int addr, unsigned int *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.
*/
static int snd_hdac_bus_send_cmd_corb(struct hdac_bus *bus, unsigned int val)
{
unsigned int addr = azx_command_addr(val);
unsigned int wp, rp;
Expand Down Expand Up @@ -176,7 +257,6 @@ int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val)

return 0;
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd);

#define AZX_RIRB_EX_UNSOL_EV (1<<4)

Expand Down Expand Up @@ -234,15 +314,15 @@ void snd_hdac_bus_update_rirb(struct hdac_bus *bus)
EXPORT_SYMBOL_GPL(snd_hdac_bus_update_rirb);

/**
* snd_hdac_bus_get_response - receive a response via RIRB
* 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.
*/
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
unsigned int *res)
static int snd_hdac_bus_get_response_rirb(struct hdac_bus *bus,
unsigned int addr, unsigned int *res)
{
unsigned long timeout;
unsigned long loopcounter;
Expand Down Expand Up @@ -293,6 +373,39 @@ int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,

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, unsigned int val)
{
if (bus->use_pio_for_commands)
return snd_hdac_bus_send_cmd_pio(bus, val);

return snd_hdac_bus_send_cmd_corb(bus, val);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_send_cmd);

/**
* 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, unsigned int addr,
unsigned int *res)
{
if (bus->use_pio_for_commands)
return snd_hdac_bus_get_response_pio(bus, addr, res);

return snd_hdac_bus_get_response_rirb(bus, addr, res);
}
EXPORT_SYMBOL_GPL(snd_hdac_bus_get_response);

#define HDAC_MAX_CAPS 10
Expand Down
7 changes: 5 additions & 2 deletions sound/pci/hda/hda_controller.c
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ static int azx_send_cmd(struct hdac_bus *bus, unsigned int val)

if (chip->disabled)
return 0;
if (chip->single_cmd)
if (chip->single_cmd || bus->use_pio_for_commands)
return azx_single_send_cmd(bus, val);
else
return snd_hdac_bus_send_cmd(bus, val);
Expand All @@ -920,7 +920,7 @@ static int azx_get_response(struct hdac_bus *bus, unsigned int addr,

if (chip->disabled)
return 0;
if (chip->single_cmd)
if (chip->single_cmd || bus->use_pio_for_commands)
return azx_single_get_response(bus, addr, res);
else
return azx_rirb_get_response(bus, addr, res);
Expand Down Expand Up @@ -1180,6 +1180,9 @@ int azx_bus_init(struct azx *chip, const char *model)
if (chip->driver_caps & AZX_DCAPS_4K_BDLE_BOUNDARY)
bus->core.align_bdle_4k = true;

if (chip->driver_caps & AZX_DCAPS_PIO_COMMANDS)
bus->core.use_pio_for_commands = true;

Comment thread
plbossart marked this conversation as resolved.
Resolved
/* enable sync_write flag for stable communication as default */
bus->core.sync_write = 1;

Expand Down
1 change: 1 addition & 0 deletions sound/pci/hda/hda_controller.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
#define AZX_DCAPS_SEPARATE_STREAM_TAG (1 << 30) /* capture and playback use separate stream tag */
#define AZX_DCAPS_PIO_COMMANDS (1 << 31) /* Use PIO instead of CORB for commands */

enum {
AZX_SNOOP_TYPE_NONE,
Expand Down
5 changes: 4 additions & 1 deletion sound/pci/hda/hda_intel.c
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ enum {

#define AZX_DCAPS_INTEL_BROXTON AZX_DCAPS_INTEL_SKYLAKE

#define AZX_DCAPS_INTEL_LNL \
(AZX_DCAPS_INTEL_SKYLAKE | AZX_DCAPS_PIO_COMMANDS)

/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_POSFIX_LPIB |\
Expand Down Expand Up @@ -2503,7 +2506,7 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE_DATA(INTEL, HDA_RPL_PX, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
{ PCI_DEVICE_DATA(INTEL, HDA_MTL, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Lunarlake-P */
{ PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
{ PCI_DEVICE_DATA(INTEL, HDA_LNL_P, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_LNL) },
/* Arrow Lake-S */
{ PCI_DEVICE_DATA(INTEL, HDA_ARL_S, AZX_DRIVER_SKL | AZX_DCAPS_INTEL_SKYLAKE) },
/* Arrow Lake */
Expand Down
5 changes: 5 additions & 0 deletions sound/soc/sof/intel/hda-bus.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,12 @@ void sof_hda_bus_init(struct snd_sof_dev *sdev, struct device *dev)

#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_LINK)
#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
const struct sof_intel_dsp_desc *chip = get_chip_info(sdev->pdata);

snd_hdac_ext_bus_init(bus, dev, &bus_core_ops, sof_hda_ext_ops);

if (chip && chip->hw_ip_version == SOF_INTEL_ACE_2_0)
Comment thread
plbossart marked this conversation as resolved.
Resolved
bus->use_pio_for_commands = true;
#else
snd_hdac_ext_bus_init(bus, dev, NULL, NULL);
#endif
Expand Down