From 62f8f76604623980d41cf73691ca45288871efd9 Mon Sep 17 00:00:00 2001 From: Keyon Jie Date: Fri, 25 Oct 2019 17:41:00 -0500 Subject: [PATCH] ASoC: SOF: Intel: hda-dsp: Add helper for setting DSP D0ix substate Adding helper to implement setting dsp to d0i3 or d0i0 status, this will be needed for driver D0ix support. Signed-off-by: Keyon Jie Signed-off-by: Pierre-Louis Bossart Link: https://lore.kernel.org/r/20191025224122.7718-5-pierre-louis.bossart@linux.intel.com Signed-off-by: Mark Brown --- sound/soc/sof/intel/hda-dsp.c | 46 +++++++++++++++++++++++++++++++++++++++++++ sound/soc/sof/intel/hda.h | 10 ++++++++++ 2 files changed, 56 insertions(+) diff --git a/sound/soc/sof/intel/hda-dsp.c b/sound/soc/sof/intel/hda-dsp.c index 3ea4016..fa2f1f6 100644 --- a/sound/soc/sof/intel/hda-dsp.c +++ b/sound/soc/sof/intel/hda-dsp.c @@ -306,6 +306,52 @@ void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev) HDA_DSP_REG_HIPCCTL_BUSY | HDA_DSP_REG_HIPCCTL_DONE, 0); } +static int hda_dsp_wait_d0i3c_done(struct snd_sof_dev *sdev, int retry) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + + while (snd_hdac_chip_readb(bus, VS_D0I3C) & SOF_HDA_VS_D0I3C_CIP) { + if (!retry--) + return -ETIMEDOUT; + usleep_range(10, 15); + } + + return 0; +} + +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate) +{ + struct hdac_bus *bus = sof_to_bus(sdev); + int retry = 50; + int ret; + u8 value; + + /* Write to D0I3C after Command-In-Progress bit is cleared */ + ret = hda_dsp_wait_d0i3c_done(sdev, retry); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout before update D0I3C!\n"); + return ret; + } + + /* Update D0I3C register */ + value = d0_substate == SOF_DSP_D0I3 ? SOF_HDA_VS_D0I3C_I3 : 0; + snd_hdac_chip_updateb(bus, VS_D0I3C, SOF_HDA_VS_D0I3C_I3, value); + + /* Wait for cmd in progress to be cleared before exiting the function */ + retry = 50; + ret = hda_dsp_wait_d0i3c_done(sdev, retry); + if (ret < 0) { + dev_err(bus->dev, "CIP timeout after D0I3C updated!\n"); + return ret; + } + + dev_vdbg(bus->dev, "D0I3C updated, register = 0x%x\n", + snd_hdac_chip_readb(bus, VS_D0I3C)); + + return 0; +} + static int hda_suspend(struct snd_sof_dev *sdev, bool runtime_suspend) { struct sof_intel_hda_dev *hda = sdev->pdata->hw_pdata; diff --git a/sound/soc/sof/intel/hda.h b/sound/soc/sof/intel/hda.h index ea02bf4..0e7c366 100644 --- a/sound/soc/sof/intel/hda.h +++ b/sound/soc/sof/intel/hda.h @@ -64,6 +64,13 @@ #define SOF_HDA_PPCTL_PIE BIT(31) #define SOF_HDA_PPCTL_GPROCEN BIT(30) +/*Vendor Specific Registers*/ +#define SOF_HDA_VS_D0I3C 0x104A + +/* D0I3C Register fields */ +#define SOF_HDA_VS_D0I3C_CIP BIT(0) /* Command-In-Progress */ +#define SOF_HDA_VS_D0I3C_I3 BIT(2) /* D0i3 enable bit */ + /* DPIB entry size: 8 Bytes = 2 DWords */ #define SOF_HDA_DPIB_ENTRY_SIZE 0x8 @@ -455,6 +462,9 @@ int hda_dsp_core_reset_power_down(struct snd_sof_dev *sdev, void hda_dsp_ipc_int_enable(struct snd_sof_dev *sdev); void hda_dsp_ipc_int_disable(struct snd_sof_dev *sdev); +int hda_dsp_set_power_state(struct snd_sof_dev *sdev, + enum sof_d0_substate d0_substate); + int hda_dsp_suspend(struct snd_sof_dev *sdev); int hda_dsp_resume(struct snd_sof_dev *sdev); int hda_dsp_runtime_suspend(struct snd_sof_dev *sdev); -- 2.7.4