ASoC: Intel: avs: Abstract IPC handling

Servicing IPCs on CNL platforms and onward differs from the existing
one. To make room for these, enrich platform descriptor with fields
representing crucial IPC registers and utilize them throughout the code.

While cleaning up device descriptors, reduce the number of code lines by
assigning 'min_fw_version' within a single line.

Reviewed-by: Amadeusz Sławiński <amadeuszx.slawinski@linux.intel.com>
Signed-off-by: Cezary Rojewski <cezary.rojewski@intel.com>
Link: https://msgid.link/r/20240220115035.770402-5-cezary.rojewski@intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
This commit is contained in:
Cezary Rojewski 2024-02-20 12:50:29 +01:00 committed by Mark Brown
parent a8f858d98f
commit 7576e2f4d9
No known key found for this signature in database
GPG Key ID: 24D68B725D5487D0
5 changed files with 72 additions and 41 deletions

View File

@ -73,6 +73,23 @@ extern const struct avs_dsp_ops avs_apl_dsp_ops;
#define avs_platattr_test(adev, attr) \
((adev)->spec->attributes & AVS_PLATATTR_##attr)
struct avs_sram_spec {
const u32 base_offset;
const u32 window_size;
const u32 rom_status_offset;
};
struct avs_hipc_spec {
const u32 req_offset;
const u32 req_ext_offset;
const u32 req_busy_mask;
const u32 ack_offset;
const u32 ack_done_mask;
const u32 rsp_offset;
const u32 rsp_busy_mask;
const u32 ctl_offset;
};
/* Platform specific descriptor */
struct avs_spec {
const char *name;
@ -82,9 +99,8 @@ struct avs_spec {
const u32 core_init_mask; /* used during DSP boot */
const u64 attributes; /* bitmask of AVS_PLATATTR_* */
const u32 sram_base_offset;
const u32 sram_window_size;
const u32 rom_status;
const struct avs_sram_spec *sram;
const struct avs_hipc_spec *hipc;
};
struct avs_fw_entry {

View File

@ -730,36 +730,47 @@ static const struct dev_pm_ops avs_dev_pm = {
SET_RUNTIME_PM_OPS(avs_runtime_suspend, avs_runtime_resume, NULL)
};
static const struct avs_sram_spec skl_sram_spec = {
.base_offset = SKL_ADSP_SRAM_BASE_OFFSET,
.window_size = SKL_ADSP_SRAM_WINDOW_SIZE,
.rom_status_offset = SKL_ADSP_SRAM_BASE_OFFSET,
};
static const struct avs_sram_spec apl_sram_spec = {
.base_offset = APL_ADSP_SRAM_BASE_OFFSET,
.window_size = APL_ADSP_SRAM_WINDOW_SIZE,
.rom_status_offset = APL_ADSP_SRAM_BASE_OFFSET,
};
static const struct avs_hipc_spec skl_hipc_spec = {
.req_offset = SKL_ADSP_REG_HIPCI,
.req_ext_offset = SKL_ADSP_REG_HIPCIE,
.req_busy_mask = SKL_ADSP_HIPCI_BUSY,
.ack_offset = SKL_ADSP_REG_HIPCIE,
.ack_done_mask = SKL_ADSP_HIPCIE_DONE,
.rsp_offset = SKL_ADSP_REG_HIPCT,
.rsp_busy_mask = SKL_ADSP_HIPCT_BUSY,
.ctl_offset = SKL_ADSP_REG_HIPCCTL,
};
static const struct avs_spec skl_desc = {
.name = "skl",
.min_fw_version = {
.major = 9,
.minor = 21,
.hotfix = 0,
.build = 4732,
},
.min_fw_version = { 9, 21, 0, 4732 },
.dsp_ops = &avs_skl_dsp_ops,
.core_init_mask = 1,
.attributes = AVS_PLATATTR_CLDMA,
.sram_base_offset = SKL_ADSP_SRAM_BASE_OFFSET,
.sram_window_size = SKL_ADSP_SRAM_WINDOW_SIZE,
.rom_status = SKL_ADSP_SRAM_BASE_OFFSET,
.sram = &skl_sram_spec,
.hipc = &skl_hipc_spec,
};
static const struct avs_spec apl_desc = {
.name = "apl",
.min_fw_version = {
.major = 9,
.minor = 22,
.hotfix = 1,
.build = 4323,
},
.min_fw_version = { 9, 22, 1, 4323 },
.dsp_ops = &avs_apl_dsp_ops,
.core_init_mask = 3,
.attributes = AVS_PLATATTR_IMR,
.sram_base_offset = APL_ADSP_SRAM_BASE_OFFSET,
.sram_window_size = APL_ADSP_SRAM_WINDOW_SIZE,
.rom_status = APL_ADSP_SRAM_BASE_OFFSET,
.sram = &apl_sram_spec,
.hipc = &skl_hipc_spec,
};
static const struct pci_device_id avs_ids[] = {

View File

@ -305,6 +305,7 @@ irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id)
{
struct avs_dev *adev = dev_id;
struct avs_ipc *ipc = adev->ipc;
const struct avs_spec *const spec = adev->spec;
u32 adspis, hipc_rsp, hipc_ack;
irqreturn_t ret = IRQ_NONE;
@ -312,35 +313,35 @@ irqreturn_t avs_dsp_irq_handler(int irq, void *dev_id)
if (adspis == UINT_MAX || !(adspis & AVS_ADSP_ADSPIS_IPC))
return ret;
hipc_ack = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCIE);
hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
hipc_ack = snd_hdac_adsp_readl(adev, spec->hipc->ack_offset);
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
/* DSP acked host's request */
if (hipc_ack & SKL_ADSP_HIPCIE_DONE) {
if (hipc_ack & spec->hipc->ack_done_mask) {
/*
* As an extra precaution, mask done interrupt. Code executed
* due to complete() found below does not assume any masking.
*/
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
AVS_ADSP_HIPCCTL_DONE, 0);
complete(&ipc->done_completion);
/* tell DSP it has our attention */
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCIE,
SKL_ADSP_HIPCIE_DONE,
SKL_ADSP_HIPCIE_DONE);
snd_hdac_adsp_updatel(adev, spec->hipc->ack_offset,
spec->hipc->ack_done_mask,
spec->hipc->ack_done_mask);
/* unmask done interrupt */
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
AVS_ADSP_HIPCCTL_DONE,
AVS_ADSP_HIPCCTL_DONE);
ret = IRQ_HANDLED;
}
/* DSP sent new response to process */
if (hipc_rsp & SKL_ADSP_HIPCT_BUSY) {
if (hipc_rsp & spec->hipc->rsp_busy_mask) {
/* mask busy interrupt */
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL,
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset,
AVS_ADSP_HIPCCTL_BUSY, 0);
ret = IRQ_WAKE_THREAD;
@ -379,10 +380,11 @@ irqreturn_t avs_dsp_irq_thread(int irq, void *dev_id)
static bool avs_ipc_is_busy(struct avs_ipc *ipc)
{
struct avs_dev *adev = to_avs_dev(ipc->dev);
const struct avs_spec *const spec = adev->spec;
u32 hipc_rsp;
hipc_rsp = snd_hdac_adsp_readl(adev, SKL_ADSP_REG_HIPCT);
return hipc_rsp & SKL_ADSP_HIPCT_BUSY;
hipc_rsp = snd_hdac_adsp_readl(adev, spec->hipc->rsp_offset);
return hipc_rsp & spec->hipc->rsp_busy_mask;
}
static int avs_ipc_wait_busy_completion(struct avs_ipc *ipc, int timeout)
@ -440,9 +442,10 @@ static void avs_ipc_msg_init(struct avs_ipc *ipc, struct avs_ipc_msg *reply)
static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx, bool read_fwregs)
{
const struct avs_spec *const spec = adev->spec;
u64 reg = ULONG_MAX;
tx->header |= SKL_ADSP_HIPCI_BUSY;
tx->header |= spec->hipc->req_busy_mask;
if (read_fwregs)
reg = readq(avs_sram_addr(adev, AVS_FW_REGS_WINDOW));
@ -450,8 +453,8 @@ static void avs_dsp_send_tx(struct avs_dev *adev, struct avs_ipc_msg *tx, bool r
if (tx->size)
memcpy_toio(avs_downlink_addr(adev), tx->data, tx->size);
snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCIE, tx->header >> 32);
snd_hdac_adsp_writel(adev, SKL_ADSP_REG_HIPCI, tx->header & UINT_MAX);
snd_hdac_adsp_writel(adev, spec->hipc->req_ext_offset, tx->header >> 32);
snd_hdac_adsp_writel(adev, spec->hipc->req_offset, tx->header & UINT_MAX);
}
static int avs_dsp_do_send_msg(struct avs_dev *adev, struct avs_ipc_msg *request,
@ -606,6 +609,7 @@ int avs_dsp_send_rom_msg(struct avs_dev *adev, struct avs_ipc_msg *request, cons
void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable)
{
const struct avs_spec *const spec = adev->spec;
u32 value, mask;
/*
@ -617,7 +621,7 @@ void avs_dsp_interrupt_control(struct avs_dev *adev, bool enable)
mask = AVS_ADSP_HIPCCTL_DONE | AVS_ADSP_HIPCCTL_BUSY;
value = enable ? mask : 0;
snd_hdac_adsp_updatel(adev, SKL_ADSP_REG_HIPCCTL, mask, value);
snd_hdac_adsp_updatel(adev, spec->hipc->ctl_offset, mask, value);
}
int avs_ipc_init(struct avs_ipc *ipc, struct device *dev)

View File

@ -306,7 +306,7 @@ avs_hda_init_rom(struct avs_dev *adev, unsigned int dma_id, bool purge)
}
/* await ROM init */
ret = snd_hdac_adsp_readq_poll(adev, spec->rom_status, reg,
ret = snd_hdac_adsp_readq_poll(adev, spec->sram->rom_status_offset, reg,
(reg & 0xF) == AVS_ROM_INIT_DONE ||
(reg & 0xF) == APL_ROM_FW_ENTERED,
AVS_ROM_INIT_POLLING_US, APL_ROM_INIT_TIMEOUT_US);

View File

@ -57,7 +57,7 @@
#define APL_ADSP_SRAM_WINDOW_SIZE 0x20000
/* Constants used when accessing SRAM, space shared with firmware */
#define AVS_FW_REG_BASE(adev) ((adev)->spec->sram_base_offset)
#define AVS_FW_REG_BASE(adev) ((adev)->spec->sram->base_offset)
#define AVS_FW_REG_STATUS(adev) (AVS_FW_REG_BASE(adev) + 0x0)
#define AVS_FW_REG_ERROR_CODE(adev) (AVS_FW_REG_BASE(adev) + 0x4)
@ -72,8 +72,8 @@
/* registry I/O helpers */
#define avs_sram_offset(adev, window_idx) \
((adev)->spec->sram_base_offset + \
(adev)->spec->sram_window_size * (window_idx))
((adev)->spec->sram->base_offset + \
(adev)->spec->sram->window_size * (window_idx))
#define avs_sram_addr(adev, window_idx) \
((adev)->dsp_ba + avs_sram_offset(adev, window_idx))