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
53 changes: 29 additions & 24 deletions sound/soc/sof/intel/hda-dsp.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,21 +27,21 @@
int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask)
{
u32 adspcs;
u32 reset;
int ret;

/* set reset bits for cores */
reset = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_CRST_MASK(core_mask),
HDA_DSP_ADSPCS_CRST_MASK(core_mask));
reset, reset),

/* poll with timeout to check if operation successful */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_CRST_MASK(core_mask),
HDA_DSP_ADSPCS_CRST_MASK(core_mask),
HDA_DSP_RESET_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS, adspcs,
((adspcs & reset) == reset),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);

/* has core entered reset ? */
adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
Expand All @@ -59,6 +59,7 @@ int hda_dsp_core_reset_enter(struct snd_sof_dev *sdev, unsigned int core_mask)

int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask)
{
unsigned int crst;
u32 adspcs;
int ret;

Expand All @@ -69,11 +70,12 @@ int hda_dsp_core_reset_leave(struct snd_sof_dev *sdev, unsigned int core_mask)
0);

/* poll with timeout to check if operation successful */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_CRST_MASK(core_mask), 0,
HDA_DSP_RESET_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
crst = HDA_DSP_ADSPCS_CRST_MASK(core_mask);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS, adspcs,
!(adspcs & crst),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);

/* has core left reset ? */
adspcs = snd_sof_dsp_read(sdev, HDA_DSP_BAR,
Expand Down Expand Up @@ -133,6 +135,7 @@ int hda_dsp_core_run(struct snd_sof_dev *sdev, unsigned int core_mask)

int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
{
unsigned int cpa;
u32 adspcs;
int ret;

Expand All @@ -142,12 +145,12 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)
HDA_DSP_ADSPCS_SPA_MASK(core_mask));

/* poll with timeout to check if operation successful */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_CPA_MASK(core_mask),
HDA_DSP_ADSPCS_CPA_MASK(core_mask),
HDA_DSP_PU_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
cpa = HDA_DSP_ADSPCS_CPA_MASK(core_mask);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS, adspcs,
(adspcs & cpa) == cpa,
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_RESET_TIMEOUT_US);
if (ret < 0)
dev_err(sdev->dev, "error: timeout on core powerup\n");

Expand All @@ -167,16 +170,18 @@ int hda_dsp_core_power_up(struct snd_sof_dev *sdev, unsigned int core_mask)

int hda_dsp_core_power_down(struct snd_sof_dev *sdev, unsigned int core_mask)
{
u32 adspcs;

/* update bits */
snd_sof_dsp_update_bits_unlocked(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS,
HDA_DSP_ADSPCS_SPA_MASK(core_mask), 0);

/* poll with timeout to check if operation successful */
return snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS, HDA_DSP_ADSPCS_CPA_MASK(core_mask), 0,
HDA_DSP_PD_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
return snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_REG_ADSPCS, adspcs,
!(adspcs & HDA_DSP_ADSPCS_SPA_MASK(core_mask)),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_PD_TIMEOUT * USEC_PER_MSEC);
}

bool hda_dsp_core_is_enabled(struct snd_sof_dev *sdev,
Expand Down
25 changes: 14 additions & 11 deletions sound/soc/sof/intel/hda-loader-skl.c
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ static void cl_cleanup_skl(struct snd_sof_dev *sdev)

static int cl_dsp_init_skl(struct snd_sof_dev *sdev)
{
unsigned int sts;
int ret;

/*
Expand Down Expand Up @@ -353,11 +354,12 @@ static int cl_dsp_init_skl(struct snd_sof_dev *sdev)
hda_dsp_ipc_int_enable(sdev);

/* polling the ROM init status information. */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_ADSP_FW_STATUS_SKL,
HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT,
HDA_DSP_INIT_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_ADSP_FW_STATUS_SKL, sts,
((sts & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_INIT),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_INIT_TIMEOUT_US);
if (ret < 0)
goto err;

Expand Down Expand Up @@ -432,6 +434,7 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev)
struct snd_sof_pdata *plat_data = sdev->pdata;
const struct firmware *fw = plat_data->fw;
unsigned int bufsize = HDA_SKL_CLDMA_MAX_BUFFER_SIZE;
unsigned int status;
int ret = 0;

dev_dbg(sdev->dev, "firmware size: 0x%zx buffer size 0x%x\n", fw->size,
Expand All @@ -443,12 +446,12 @@ static int cl_copy_fw_skl(struct snd_sof_dev *sdev)
return ret;
}

ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_ADSP_FW_STATUS_SKL,
HDA_DSP_ROM_STS_MASK,
HDA_DSP_ROM_FW_FW_LOADED,
HDA_DSP_BASEFW_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_ADSP_FW_STATUS_SKL, status,
((status & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_FW_FW_LOADED),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_BASEFW_TIMEOUT_US);
if (ret < 0)
dev_err(sdev->dev, "error: firmware transfer timeout!");

Expand Down
37 changes: 21 additions & 16 deletions sound/soc/sof/intel/hda-loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata,
{
struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata;
const struct sof_intel_dsp_desc *chip = hda->desc;
unsigned int status;
int ret;

/* step 1: power up corex */
Expand All @@ -105,11 +106,12 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata,
}

/* step 4: wait for IPC DONE bit from ROM */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
chip->ipc_ack,
chip->ipc_ack_mask, chip->ipc_ack_mask,
HDA_DSP_INIT_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
chip->ipc_ack, status,
((status & chip->ipc_ack_mask)
== chip->ipc_ack_mask),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_INIT_TIMEOUT_US);

if (ret < 0) {
dev_err(sdev->dev, "error: waiting for HIPCIE done\n");
Expand All @@ -128,11 +130,13 @@ static int cl_dsp_init(struct snd_sof_dev *sdev, const void *fwdata,
hda_dsp_ipc_int_enable(sdev);

/* step 7: wait for ROM init */
ret = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS,
HDA_DSP_ROM_STS_MASK, HDA_DSP_ROM_INIT,
chip->rom_init_timeout,
HDA_DSP_REG_POLL_INTERVAL_US);
ret = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS, status,
((status & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_INIT),
HDA_DSP_REG_POLL_INTERVAL_US,
chip->rom_init_timeout *
USEC_PER_MSEC);
if (!ret)
return 0;

Expand Down Expand Up @@ -221,6 +225,7 @@ static int cl_cleanup(struct snd_sof_dev *sdev, struct snd_dma_buffer *dmab,

static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream)
{
unsigned int reg;
int ret, status;

ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_START);
Expand All @@ -229,12 +234,12 @@ static int cl_copy_fw(struct snd_sof_dev *sdev, struct hdac_ext_stream *stream)
return ret;
}

status = snd_sof_dsp_register_poll(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS,
HDA_DSP_ROM_STS_MASK,
HDA_DSP_ROM_FW_ENTERED,
HDA_DSP_BASEFW_TIMEOUT,
HDA_DSP_REG_POLL_INTERVAL_US);
status = snd_sof_dsp_read_poll_timeout(sdev, HDA_DSP_BAR,
HDA_DSP_SRAM_REG_ROM_STATUS, reg,
((reg & HDA_DSP_ROM_STS_MASK)
== HDA_DSP_ROM_FW_ENTERED),
HDA_DSP_REG_POLL_INTERVAL_US,
HDA_DSP_BASEFW_TIMEOUT_US);

ret = cl_trigger(sdev, stream, SNDRV_PCM_TRIGGER_STOP);
if (ret < 0) {
Expand Down
6 changes: 3 additions & 3 deletions sound/soc/sof/intel/hda.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,9 @@
/* various timeout values */
#define HDA_DSP_PU_TIMEOUT 50
#define HDA_DSP_PD_TIMEOUT 50
#define HDA_DSP_RESET_TIMEOUT 50
#define HDA_DSP_BASEFW_TIMEOUT 3000
#define HDA_DSP_INIT_TIMEOUT 500
#define HDA_DSP_RESET_TIMEOUT_US 50000
#define HDA_DSP_BASEFW_TIMEOUT_US 3000000
#define HDA_DSP_INIT_TIMEOUT_US 500000
#define HDA_DSP_CTRL_RESET_TIMEOUT 100
#define HDA_DSP_WAIT_TIMEOUT 500 /* 500 msec */
#define HDA_DSP_REG_POLL_INTERVAL_US 500 /* 0.5 msec */
Expand Down
40 changes: 0 additions & 40 deletions sound/soc/sof/ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,46 +142,6 @@ void snd_sof_dsp_update_bits_forced(struct snd_sof_dev *sdev, u32 bar,
}
EXPORT_SYMBOL(snd_sof_dsp_update_bits_forced);

int snd_sof_dsp_register_poll(struct snd_sof_dev *sdev, u32 bar, u32 offset,
u32 mask, u32 target, u32 timeout_ms,
u32 interval_us)
{
u32 reg;
unsigned long tout_jiff;
int k = 0, s = interval_us;

/*
* Split the loop into 2 sleep stages with varying resolution.
* To do it more accurately, the range of wakeups are:
* In case of interval_us = 500,
* Phase 1(first 5ms): min sleep 0.5ms; max sleep 1ms.
* Phase 2(beyond 5ms): min sleep 5ms; max sleep 10ms.
*/

tout_jiff = jiffies + msecs_to_jiffies(timeout_ms);
do {
reg = snd_sof_dsp_read(sdev, bar, offset);
if ((reg & mask) == target)
break;

/* Phase 2 after 5ms(500us * 10) */
if (++k > 10)
s = interval_us * 10;

usleep_range(s, 2 * s);
} while (time_before(jiffies, tout_jiff));

if ((reg & mask) == target) {
dev_dbg(sdev->dev, "FW Poll Status: reg=%#x successful\n", reg);

return 0;
}

dev_dbg(sdev->dev, "FW Poll Status: reg=%#x timedout\n", reg);
return -ETIME;
}
EXPORT_SYMBOL(snd_sof_dsp_register_poll);

void snd_sof_dsp_panic(struct snd_sof_dev *sdev, u32 offset)
{
dev_err(sdev->dev, "error : DSP panic!\n");
Expand Down
44 changes: 44 additions & 0 deletions sound/soc/sof/ops.h
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,50 @@ static inline const struct snd_sof_dsp_ops
return NULL;
}

/**
* snd_sof_dsp_register_poll_timeout - Periodically poll an address
* until a condition is met or a timeout occurs
* @op: accessor function (takes @addr as its only argument)
* @addr: Address to poll
* @val: Variable to read the value into
* @cond: Break condition (usually involving @val)
* @sleep_us: Maximum time to sleep between reads in us (0
* tight-loops). Should be less than ~20ms since usleep_range
* is used (see Documentation/timers/timers-howto.txt).
* @timeout_us: Timeout in us, 0 means never timeout
*
* Returns 0 on success and -ETIMEDOUT upon a timeout. In either
* case, the last read value at @addr is stored in @val. Must not
* be called from atomic context if sleep_us or timeout_us are used.
*
* This is modelled after the readx_poll_timeout macros in linux/iopoll.h.
*/
#define snd_sof_dsp_read_poll_timeout(sdev, bar, offset, val, cond, sleep_us, timeout_us) \
({ \
u64 __timeout_us = (timeout_us); \
unsigned long __sleep_us = (sleep_us); \
ktime_t __timeout = ktime_add_us(ktime_get(), __timeout_us); \
might_sleep_if((__sleep_us) != 0); \
for (;;) { \
(val) = snd_sof_dsp_read(sdev, bar, offset); \
if (cond) { \
dev_dbg(sdev->dev, \
"FW Poll Status: reg=%#x successful\n", (val)); \
break; \
} \
if (__timeout_us && \
ktime_compare(ktime_get(), __timeout) > 0) { \
(val) = snd_sof_dsp_read(sdev, bar, offset); \
dev_dbg(sdev->dev, \
"FW Poll Status: reg=%#x timedout\n", (val)); \
break; \
} \
if (__sleep_us) \
usleep_range((__sleep_us >> 2) + 1, __sleep_us); \
} \
(cond) ? 0 : -ETIMEDOUT; \
})

/* This is for registers bits with attribute RWC */
bool snd_sof_pci_update_bits(struct snd_sof_dev *sdev, u32 offset,
u32 mask, u32 value);
Expand Down