Merge pull request #452 from mmaka1/clk-gating

plat: apl: clock gating adjusted for dai, dma, and cores
This commit is contained in:
Liam Girdwood 2018-10-08 16:06:26 +01:00 committed by GitHub
commit b180af8ba7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 341 additions and 241 deletions

View File

@ -43,11 +43,6 @@ export ARCH_INCDIR
PLATFORM_INCDIR = -I $(SRC_DIR)/platform/$(PLATFORM)/include
if BUILD_CAVS
PLATFORM_INCDIR += \
-I $(SRC_DIR)/platform/intel/include
endif
if XCC
PLATFORM_INCDIR += \
-I $(ROOT_DIR)/arch/include

View File

@ -566,9 +566,6 @@ AC_CONFIG_FILES([
src/platform/icelake/include/platform/Makefile
src/platform/intel/Makefile
src/platform/intel/cavs/Makefile
src/platform/intel/include/Makefile
src/platform/intel/include/platform/Makefile
src/platform/intel/include/platform/cavs/Makefile
test/Makefile
test/cmocka/Makefile
])

View File

@ -57,12 +57,11 @@ static int hweight_32(uint32_t mask)
/* empty SSP receive FIFO */
static void ssp_empty_rx_fifo(struct dai *dai)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
uint32_t sssr;
uint32_t entries;
uint32_t i;
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
sssr = ssp_read(dai, SSSR);
@ -77,7 +76,7 @@ static void ssp_empty_rx_fifo(struct dai *dai)
ssp_read(dai, SSDR);
}
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
/* save SSP context prior to entering D3 */
@ -132,7 +131,7 @@ static inline int ssp_set_config(struct dai *dai,
bool cbs = false;
int ret = 0;
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* is playback/capture already running */
if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE ||
@ -473,7 +472,7 @@ static inline int ssp_set_config(struct dai *dai,
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
out:
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
return ret;
}
@ -481,14 +480,12 @@ out:
/* Digital Audio interface formatting */
static inline int ssp_set_loopback_mode(struct dai *dai, uint32_t lbm)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
trace_ssp("loo");
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0);
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
return 0;
}
@ -498,7 +495,7 @@ static void ssp_start(struct dai *dai, int direction)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* enable port */
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
@ -512,7 +509,7 @@ static void ssp_start(struct dai *dai, int direction)
else
ssp_update_bits(dai, SSCR1, SSCR1_RSRE, SSCR1_RSRE);
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
/* stop the SSP for either playback or capture */
@ -520,7 +517,7 @@ static void ssp_stop(struct dai *dai, int direction)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* stop Rx if neeed */
if (direction == DAI_DIR_CAPTURE &&
@ -548,7 +545,7 @@ static void ssp_stop(struct dai *dai, int direction)
trace_ssp("Ss2");
}
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
static int ssp_trigger(struct dai *dai, int cmd, int direction)
@ -607,7 +604,7 @@ static int ssp_probe(struct dai *dai)
sizeof(*ssp));
dai_set_drvdata(dai, ssp);
spinlock_init(&ssp->lock);
spinlock_init(&dai->lock);
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;

View File

@ -139,7 +139,7 @@ uint32_t clock_set_freq(int clock, uint32_t hz)
notify_data.old_freq = clk_pdata->clk[clock].freq;
notify_data.old_ticks_per_msec = clk_pdata->clk[clock].ticks_per_msec;
/* atomic context for chaning clocks */
/* atomic context for changing clocks */
spin_lock_irq(&clk_pdata->clk[clock].lock, flags);
switch (clock) {
@ -157,6 +157,8 @@ uint32_t clock_set_freq(int clock, uint32_t hz)
io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL,
SHIM_CLKCTL_HDCS, 0);
#endif
/* TODO: should handle all cores or pass the index as arg */
io_reg_update_bits(SHIM_BASE + SHIM_CLKCTL,
SHIM_CLKCTL_DPCS_MASK(0), cpu_freq[idx].enc);

View File

@ -31,6 +31,7 @@
#include <sof/stream.h>
#include <sof/dmic.h>
#include <sof/interrupt.h>
#include <sof/pm_runtime.h>
#include <sof/math/numbers.h>
#include <sof/audio/format.h>
@ -207,7 +208,7 @@ static uint64_t dmic_work(void *data, uint64_t delay)
int i;
tracev_dmic("wrk");
spin_lock(&dmic->lock);
spin_lock(&dai->lock);
/* Increment gain with logaritmic step.
* Gain is Q2.30 and gain modifier is Q2.14.
@ -257,7 +258,7 @@ static uint64_t dmic_work(void *data, uint64_t delay)
dmic_write(dai, base[i] + OUT_GAIN_RIGHT_B, val);
}
}
spin_unlock(&dmic->lock);
spin_unlock(&dai->lock);
if (gval)
return DMIC_UNMUTE_RAMP_US;
@ -1236,7 +1237,7 @@ static void dmic_start(struct dai *dai)
int fir_b;
/* enable port */
spin_lock(&dmic->lock);
spin_lock(&dai->lock);
trace_dmic("sta");
dmic->state = COMP_STATE_ACTIVE;
dmic->startcount = 0;
@ -1305,7 +1306,7 @@ static void dmic_start(struct dai *dai)
CIC_CONTROL_SOFT_RESET_BIT, 0);
}
spin_unlock(&dmic->lock);
spin_unlock(&dai->lock);
/* Currently there's no DMIC HW internal mutings and wait times
* applied into this start sequence. It can be implemented here if
@ -1324,7 +1325,7 @@ static void dmic_stop(struct dai *dai)
int i;
trace_dmic("sto")
spin_lock(&dmic->lock);
spin_lock(&dai->lock);
dmic->state = COMP_STATE_PREPARE;
/* Stop FIFO packers and set FIFO initialize bits */
@ -1352,7 +1353,7 @@ static void dmic_stop(struct dai *dai)
FIR_CONTROL_B_MUTE_BIT);
}
spin_unlock(&dmic->lock);
spin_unlock(&dai->lock);
}
/* save DMIC context prior to entering D3 */
@ -1446,6 +1447,12 @@ static int dmic_probe(struct dai *dai)
trace_dmic("pro");
if (dai_get_drvdata(dai))
return -EEXIST; /* already created */
/* Disable dynamic clock gating for dmic before touching any reg */
pm_runtime_get_sync(DMIC_CLK, dai->index);
/* allocate private data */
dmic = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM,
sizeof(*dmic));
@ -1455,8 +1462,6 @@ static int dmic_probe(struct dai *dai)
}
dai_set_drvdata(dai, dmic);
spinlock_init(&dmic->lock);
/* Set state, note there is no playback direction support */
dmic->state = COMP_STATE_READY;

View File

@ -612,13 +612,17 @@ static int hda_dma_probe(struct dma *dma)
int i;
struct hda_chan_data *chan;
trace_event(TRACE_CLASS_DMA, "hda-dma-probe %p id %d",
(uintptr_t)dma, dma->plat_data.id);
if (dma_get_drvdata(dma))
return -EEXIST; /* already created */
/* allocate private data */
hda_pdata = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM,
sizeof(*hda_pdata));
dma_set_drvdata(dma, hda_pdata);
spinlock_init(&dma->lock);
/* init channel status */
chan = hda_pdata->chan;

View File

@ -36,6 +36,7 @@
#include <sof/ssp.h>
#include <sof/alloc.h>
#include <sof/interrupt.h>
#include <sof/pm_runtime.h>
#include <sof/math/numbers.h>
#include <config.h>
@ -65,10 +66,9 @@ static int hweight_32(uint32_t mask)
/* empty SSP transmit FIFO */
static void ssp_empty_tx_fifo(struct dai *dai)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
uint32_t sssr;
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
sssr = ssp_read(dai, SSSR);
@ -76,18 +76,17 @@ static void ssp_empty_tx_fifo(struct dai *dai)
if (sssr & SSSR_TUR)
ssp_write(dai, SSSR, sssr);
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
/* empty SSP receive FIFO */
static void ssp_empty_rx_fifo(struct dai *dai)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
uint32_t sssr;
uint32_t entries;
uint32_t i;
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
sssr = ssp_read(dai, SSSR);
@ -102,7 +101,7 @@ static void ssp_empty_rx_fifo(struct dai *dai)
ssp_read(dai, SSDR);
}
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
/* save SSP context prior to entering D3 */
@ -171,7 +170,7 @@ static inline int ssp_set_config(struct dai *dai,
bool start_delay = false;
int ret = 0;
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* is playback/capture already running */
if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE ||
@ -733,7 +732,7 @@ static inline int ssp_set_config(struct dai *dai,
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_PREPARE;
out:
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
return ret;
}
@ -741,14 +740,12 @@ out:
/* Digital Audio interface formatting */
static inline int ssp_set_loopback_mode(struct dai *dai, uint32_t lbm)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
trace_ssp("loo");
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0);
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
return 0;
}
@ -758,7 +755,7 @@ static void ssp_start(struct dai *dai, int direction)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* enable port */
ssp_update_bits(dai, SSCR0, SSCR0_SSE, SSCR0_SSE);
@ -775,7 +772,7 @@ static void ssp_start(struct dai *dai, int direction)
ssp_update_bits(dai, SSRSA, 0x1 << 8, 0x1 << 8);
}
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
/* stop the SSP for either playback or capture */
@ -783,7 +780,7 @@ static void ssp_stop(struct dai *dai, int direction)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* wait to get valid fifo status */
wait_delay(PLATFORM_SSP_STOP_DELAY);
@ -817,7 +814,7 @@ static void ssp_stop(struct dai *dai, int direction)
trace_ssp("Ss2");
}
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
static int ssp_trigger(struct dai *dai, int cmd, int direction)
@ -871,13 +868,17 @@ static int ssp_probe(struct dai *dai)
{
struct ssp_pdata *ssp;
if (dai_get_drvdata(dai))
return -EEXIST; /* already created */
/* Disable dynamic clock gating before touching any register */
pm_runtime_get_sync(SSP_CLK, dai->index);
/* allocate private data */
ssp = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM,
sizeof(*ssp));
dai_set_drvdata(dai, ssp);
spinlock_init(&ssp->lock);
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;

View File

@ -57,6 +57,7 @@
#include <sof/lock.h>
#include <sof/trace.h>
#include <sof/wait.h>
#include <sof/pm_runtime.h>
#include <sof/audio/component.h>
#include <sof/cpu.h>
#include <platform/dma.h>
@ -1276,6 +1277,12 @@ static int dw_dma_probe(struct dma *dma)
struct dma_pdata *dw_pdata;
int i;
if (dma_get_drvdata(dma))
return -EEXIST; /* already created */
/* disable dynamic clock gating */
pm_runtime_get_sync(DW_DMAC_CLK, dma->plat_data.id);
/* allocate private data */
dw_pdata = rzalloc(RZONE_SYS | RZONE_FLAG_UNCACHED, SOF_MEM_CAPS_RAM,
sizeof(*dw_pdata));

View File

@ -90,7 +90,7 @@ static inline int ssp_set_config(struct dai *dai,
bool inverted_frame = false;
int ret = 0;
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* is playback/capture already running */
if (ssp->state[DAI_DIR_PLAYBACK] == COMP_STATE_ACTIVE ||
@ -360,7 +360,7 @@ static inline int ssp_set_config(struct dai *dai,
ssp_update_bits(dai, SSCR0, SSCR0_SSE, 0);
out:
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
return ret;
}
@ -368,14 +368,12 @@ out:
/* Digital Audio interface formatting */
static inline int ssp_set_loopback_mode(struct dai *dai, uint32_t lbm)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
trace_ssp("loo");
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
ssp_update_bits(dai, SSCR1, SSCR1_LBM, lbm ? SSCR1_LBM : 0);
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
return 0;
}
@ -385,7 +383,7 @@ static void ssp_start(struct dai *dai, int direction)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
trace_ssp("sta");
@ -408,7 +406,7 @@ static void ssp_start(struct dai *dai, int direction)
ssp->state[direction] = COMP_STATE_ACTIVE;
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
/* stop the SSP for either playback or capture */
@ -416,7 +414,7 @@ static void ssp_stop(struct dai *dai, int direction)
{
struct ssp_pdata *ssp = dai_get_drvdata(dai);
spin_lock(&ssp->lock);
spin_lock(&dai->lock);
/* stop Rx if neeed */
if (direction == DAI_DIR_CAPTURE &&
@ -445,7 +443,7 @@ static void ssp_stop(struct dai *dai, int direction)
trace_ssp("Ss2");
}
spin_unlock(&ssp->lock);
spin_unlock(&dai->lock);
}
static int ssp_trigger(struct dai *dai, int cmd, int direction)
@ -504,7 +502,7 @@ static int ssp_probe(struct dai *dai)
sizeof(*ssp));
dai_set_drvdata(dai, ssp);
spinlock_init(&ssp->lock);
spinlock_init(&dai->lock);
ssp->state[DAI_DIR_PLAYBACK] = COMP_STATE_READY;
ssp->state[DAI_DIR_CAPTURE] = COMP_STATE_READY;

View File

@ -88,16 +88,6 @@ struct dai_slot_map {
uint32_t slot; /**< physical slot index */
};
/**
* \brief DAI Type.
*/
enum dai_type {
DAI_TYPE_INTEL_SSP = 0, /**< Intel SSP */
DAI_TYPE_INTEL_HDA, /**< Intel HD/A */
DAI_TYPE_INTEL_DMIC, /**< Intel DMIC */
};
struct dai_plat_fifo_data {
uint32_t offset;
uint32_t width;
@ -117,8 +107,10 @@ struct dai_plat_data {
};
struct dai {
uint32_t type;
uint32_t index;
uint32_t type; /**< type, one of SOF_DAI_... */
uint32_t index; /**< index */
spinlock_t lock;
int sref; /**< simple ref counter, guarded by lock */
struct dai_plat_data plat_data;
const struct dai_ops *ops;
void *private;
@ -154,7 +146,7 @@ struct dai *dai_get(uint32_t type, uint32_t index);
#define dai_set_drvdata(dai, data) \
dai->private = data;
#define dai_get_drvdata(dai) \
dai->private;
dai->private
#define dai_base(dai) \
dai->plat_data.base
#define dai_irq(dai) \

View File

@ -162,6 +162,7 @@ struct dma_plat_data {
struct dma {
struct dma_plat_data plat_data;
spinlock_t lock;
int sref; /**< simple ref counter, guarded by lock */
const struct dma_ops *ops;
atomic_t num_channels_busy; /* number of busy channels */
void *private;
@ -190,7 +191,7 @@ struct dma *dma_get(uint32_t dir, uint32_t caps, uint32_t dev, uint32_t flags);
#define dma_set_drvdata(dma, data) \
dma->private = data;
#define dma_get_drvdata(dma) \
dma->private;
dma->private
#define dma_base(dma) \
dma->plat_data.base
#define dma_irq(dma, cpu) \

View File

@ -317,7 +317,6 @@
/* DMIC private data */
struct dmic_pdata {
spinlock_t lock; /* Spinlock that's used in registers IO */
uint16_t fifo_a;
uint16_t fifo_b;
uint16_t enable[DMIC_HW_CONTROLLERS];

View File

@ -249,7 +249,6 @@ struct ssp_pdata {
uint32_t sscr0;
uint32_t sscr1;
uint32_t psp;
spinlock_t lock;
uint32_t state[2]; /* SSP_STATE_ for each direction */
completion_t drain_complete;
struct sof_ipc_dai_config config;

View File

@ -935,6 +935,7 @@ static int ipc_glb_tplg_free(uint32_t header,
int (*free_func)(struct ipc *ipc, uint32_t id))
{
struct sof_ipc_free *ipc_free = _ipc->comp_data;
int ret;
trace_ipc("Tcf");
@ -945,9 +946,14 @@ static int ipc_glb_tplg_free(uint32_t header,
}
/* free the object */
free_func(_ipc, ipc_free->id);
ret = free_func(_ipc, ipc_free->id);
return 0;
if (ret < 0) {
trace_error(TRACE_CLASS_IPC,
"ipc-glb-tplg-free free_func failed %d", ret);
}
return ret;
}
static int ipc_glb_tplg_message(uint32_t header)
@ -1134,7 +1140,8 @@ int ipc_queue_host_message(struct ipc *ipc, uint32_t header, void *tx_data,
msg = msg_get_empty(ipc);
if (msg == NULL) {
trace_ipc_error("eQb");
trace_error(TRACE_CLASS_IPC, "eQb header 0x08x replace %d",
header, replace);
ret = -EBUSY;
goto out;
}

View File

@ -46,19 +46,52 @@ void dai_install(struct dai_type_info *dai_type_array, size_t num_dai_types)
lib_dai.num_dai_types = num_dai_types;
}
struct dai *dai_get(uint32_t type, uint32_t index)
static inline struct dai_type_info *dai_find_type(uint32_t type)
{
int i;
struct dai_type_info *dti;
for (dti = lib_dai.dai_type_array;
dti < lib_dai.dai_type_array + lib_dai.num_dai_types; dti++) {
if (dti->type == type) {
for (i = 0; i < dti->num_dais; i++) {
if (dti->dai_array[i].index == index)
return dti->dai_array + i;
}
}
if (dti->type == type)
return dti;
}
return NULL;
}
struct dai *dai_get(uint32_t type, uint32_t index)
{
int ret = 0;
struct dai_type_info *dti;
struct dai *d;
dti = dai_find_type(type);
if (!dti)
return NULL; /* type not found */
for (d = dti->dai_array; d < dti->dai_array + dti->num_dais; d++) {
if (d->index != index)
continue;
/* device created? */
spin_lock(&d->lock);
if (d->sref == 0) {
trace_event(TRACE_CLASS_DAI,
"dai-probe type %d index %d",
type, index);
ret = dai_probe(d);
if (ret < 0) {
trace_error(TRACE_CLASS_DAI,
"probe failed %d",
ret);
}
}
if (!ret)
d->sref++;
trace_event(TRACE_CLASS_DAI, "dai-get %p sref %d",
(uintptr_t)d, d->sref);
spin_unlock(&d->lock);
return !ret ? d : NULL;
}
trace_error(TRACE_CLASS_DAI, "dai-get type %d index %d not found",
type, index);
return NULL;
}

View File

@ -50,7 +50,7 @@ void dma_install(struct dma *dma_array, size_t num_dmas)
struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
{
int ch_count;
int ch_count, ret;
int min_ch_count = INT32_MAX;
struct dma *d = NULL, *dmin = NULL;
@ -93,9 +93,32 @@ struct dma *dma_get(uint32_t dir, uint32_t cap, uint32_t dev, uint32_t flags)
/* return DMAC */
if (dmin) {
tracev_value(dmin->plat_data.id);
return dmin;
tracev_event(TRACE_CLASS_DMA, "dma-probe id %d",
dmin->plat_data.id);
/* Shared DMA controllers with multiple channels
* may be requested many times, let the probe()
* do on-first-use initialization.
*/
spin_lock(&dmin->lock);
ret = 0;
if (dmin->sref == 0) {
ret = dma_probe(dmin);
if (ret < 0) {
trace_error(TRACE_CLASS_DMA,
"dma-probe failed id %d ret %d",
dmin->plat_data.id, ret);
}
}
if (!ret)
dmin->sref++;
trace_event(TRACE_CLASS_DMA, "dma-get %p sref %d",
(uintptr_t)dmin, dmin->sref);
spin_unlock(&dmin->lock);
return !ret ? dmin : NULL;
}
trace_error(TRACE_CLASS_DMA,
"dma-get dir 0x%x cap 0x%x dev 0x%x flags 0x%x not found",
dir, cap, dev, flags);
return NULL;
}

View File

@ -40,6 +40,7 @@
#warning "ASSEMBLY macro not defined."
#endif
#include <sof/bit.h>
#include <platform/shim.h>
#include <platform/platcfg.h>

View File

@ -145,37 +145,72 @@
#define SHIM_DSPWCTCS_T1A (0x1 << 1) /* Timer 1 armed */
#define SHIM_DSPWCTCS_T0A (0x1 << 0) /* Timer 0 armed */
#define SHIM_CLKCTL 0x78
#define SHIM_CLKSTS 0x7C
#define SHIM_CLKCTL_RAPLLC (0x1 << 31)
#define SHIM_CLKCTL_RXOSCC (0x1 << 30)
#define SHIM_CLKCTL_RFROSCC (0x1 << 29)
/** \brief LDO Control */
#define SHIM_LDOCTL 0xA4
/* LP GPDMA Force Dynamic Clock Gating bits, 0--enable */
#define SHIM_CLKCTL_LPGPDMAFDCGB(x) (0x1 << (26 + x))
#define SHIM_CLKCTL_DMICFDCGB (0x1 << 24)
#define SHIM_CLKCTL_I2SFDCGB(x) (0x1 << (20 + x))
#define SHIM_CLKCTL_I2SEFDCGB(x) (0x1 << (18 + x))
#define SHIM_CLKCTL_TCPLCG(x) (0x1 << (16 + x))
/** \brief Clock control */
#define SHIM_CLKCTL 0x78
/* Core clock PLL divisor */
/** \brief Clock status */
#define SHIM_CLKSTS 0x7C
/** \brief Request Audio PLL Clock */
#define SHIM_CLKCTL_RAPLLC BIT(31)
/** \brief Request XTAL Oscillator Clock */
#define SHIM_CLKCTL_RXOSCC BIT(30)
/** \brief Request Fast RING Oscillator Clock */
#define SHIM_CLKCTL_RFROSCC BIT(29)
/** \brief LP GPDMA Force Dynamic Clock Gating bits, 0: enable */
#define SHIM_CLKCTL_LPGPDMAFDCGB(x) BIT(26 + x)
/** \brief DMIC Force Dynamic Clock Gating */
#define SHIM_CLKCTL_DMICFDCGB BIT(24)
/** \brief I2S Force Dynamic Clock Gating */
#define SHIM_CLKCTL_I2SFDCGB(x) BIT(20 + x)
/** \brief I2S Extension Force Dynamic Clock Gating */
#define SHIM_CLKCTL_I2SEFDCGB(x) BIT(18 + x)
/** \brief Tensilica Core Prevent Local Clock Gating */
#define SHIM_CLKCTL_TCPLCG_EN(x) BIT(16 + x)
#define SHIM_CLKCTL_TCPLCG_DIS(x) 0
/** \brief Core clock PLL divisor */
#define SHIM_CLKCTL_DPCS_MASK(x) (0x3 << (8 + x * 2))
/* Prevent Audio PLL Shutdown */
#define SHIM_CLKCTL_TCPAPLLS (0x1 << 7)
#define SHIM_CLKCTL_DPCS_DIV1(x) (0x0 << (8 + x * 2))
#define SHIM_CLKCTL_DPCS_DIV2(x) (0x1 << (8 + x * 2))
#define SHIM_CLKCTL_DPCS_DIV4(x) (0x3 << (8 + x * 2))
/* 0--from PLL, 1--from oscillator */
#define SHIM_CLKCTL_LDCS (0x1 << 5)
#define SHIM_CLKCTL_HDCS (0x1 << 4)
/** \brief Tensilica Core Prevent Audio PLL Shutdown */
#define SHIM_CLKCTL_TCPAPLLS_EN BIT(7)
#define SHIM_CLKCTL_TCPAPLLS_DIS 0
/* Oscillator clock select select 0--XTAL, 1--Fast RING*/
#define SHIM_CLKCTL_LDOCS (0x1 << 3)
#define SHIM_CLKCTL_HDOCS (0x1 << 2)
/** \brief LP domain clock select, 0: PLL, 1: oscillator */
#define SHIM_CLKCTL_LDCS_XTAL BIT(5)
#define SHIM_CLKCTL_LDCS_PLL 0
/* HP memory clock PLL divisor */
#define SHIM_CLKCTL_HPMPCS (0x1 << 0)
/** \brief HP domain clock select */
#define SHIM_CLKCTL_HDCS BIT(4)
#define SHIM_CLKCTL_HDCS_XTAL BIT(4)
#define SHIM_CLKCTL_HDCS_PLL 0
/** \brief LP domain oscillator clock select select, 0: XTAL, 1: Fast RING */
#define SHIM_CLKCTL_LDOCS BIT(3)
/** \brief HP domain oscillator clock select select, 0: XTAL, 1: Fast RING */
#define SHIM_CLKCTL_HDOCS BIT(2)
/** \brief LP memory clock PLL divisor, 0: div by 2, 1: div by 4 */
#define SHIM_CLKCTL_LPMPCS_DIV4 BIT(1)
#define SHIM_CLKCTL_LPMPCS_DIV2 0
/** \brief HP memory clock PLL divisor, 0: div by 2, 1: div by 4 */
#define SHIM_CLKCTL_HPMPCS_DIV4 BIT(0)
#define SHIM_CLKCTL_HPMPCS_DIV2 0
#define SHIM_PWRCTL 0x90
#define SHIM_PWRSTS 0x92

View File

@ -115,7 +115,7 @@ _PD_SWITCH_TO_XTAL_CLOCK:
// TODO: move to CLOCK hal macros
movi temp_reg0, (SHIM_BASE + SHIM_CLKCTL)
movi temp_reg1, ~(SHIM_CLKCTL_HDOCS | SHIM_CLKCTL_LDOCS)
movi temp_reg2, (SHIM_CLKCTL_LDCS | SHIM_CLKCTL_HDCS)
movi temp_reg2, (SHIM_CLKCTL_LDCS_XTAL | SHIM_CLKCTL_HDCS_XTAL)
l32i temp_reg3, temp_reg0, 0
// Reset LDOCS & HDOCS bits to select XTAL
and temp_reg3, temp_reg3, temp_reg1

View File

@ -1,5 +1,4 @@
SUBDIRS = include
SUBDIRS =
if BUILD_CAVS
SUBDIRS += cavs
endif
endif

View File

@ -231,25 +231,26 @@ int dai_init(void)
{
int i;
/* init ssp */
/* TODO: move all the properties initialization here */
for (i = 0; i < ARRAY_SIZE(ssp); i++) {
/* initialize spin locks early to enable ref counting */
spinlock_init(&ssp[i].lock);
}
/* init hd/a, note that size depends on the platform caps */
for (i = 0; i < ARRAY_SIZE(hda); i++) {
hda[i].type = SOF_DAI_INTEL_HDA;
hda[i].index = i;
hda[i].ops = &hda_ops;
spinlock_init(&hda[i].lock);
}
/* init SSP ports */
trace_point(TRACE_BOOT_PLATFORM_SSP);
for (i = 0; i < DAI_NUM_SSP_BASE + DAI_NUM_SSP_EXT; i++)
dai_probe(ssp + i);
/* Init DMIC. Note that the two PDM controllers and four microphones
* supported max. those are available in platform are handled by dmic0.
*/
trace_point(TRACE_BOOT_PLATFORM_DMIC);
dai_probe(dmic + 0);
#if defined(CONFIG_DMIC)
/* init dmic */
for (i = 0; i < ARRAY_SIZE(dmic); i++)
spinlock_init(&dmic[i].lock);
#endif
dai_install(dti, ARRAY_SIZE(dti));
return 0;
}

View File

@ -263,18 +263,14 @@ struct dma dma[CAVS_PLATFORM_NUM_DMACS] = {
/* Initialize all platform DMAC's */
int dmac_init(void)
{
int i, ret;
int i;
/* no probing before first use */
for (i = 0; i < ARRAY_SIZE(dma); i++) {
ret = dma_probe(&dma[i]);
if (ret < 0) {
/* TODO: dynamic init based on platform settings */
/* trace failed DMAC ID */
trace_error(TRACE_CLASS_DMA, "edi");
trace_error_value(dma[i].plat_data.id);
return ret;
}
}
/* early lock initialization for ref counting */
for (i = 0; i < ARRAY_SIZE(dma); i++)
spinlock_init(&dma[i].lock);
/* tell the lib DMAs are ready to use */
dma_install(dma, ARRAY_SIZE(dma));

View File

@ -321,40 +321,37 @@ int platform_init(struct sof *sof)
/* init the system agent */
sa_init(sof);
/* Set CPU to default frequency for booting */
/* Set CPU to max frequency for booting (single shim_write below) */
trace_point(TRACE_BOOT_SYS_CPU_FREQ);
clock_set_freq(CLK_CPU, CLK_MAX_CPU_HZ);
/* set SSP clock */
trace_point(TRACE_BOOT_PLATFORM_SSP_FREQ);
clock_set_freq(CLK_SSP, SSP_CLOCK_FREQUENCY);
/* initialise the host IPC mechanisms */
trace_point(TRACE_BOOT_PLATFORM_IPC);
ipc_init(sof);
#if defined(CONFIG_APOLLOLAKE)
/* disable PM for boot */
shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) |
SHIM_CLKCTL_LPGPDMAFDCGB(0) |
SHIM_CLKCTL_LPGPDMAFDCGB(1) |
SHIM_CLKCTL_I2SFDCGB(3) |
SHIM_CLKCTL_I2SFDCGB(2) |
SHIM_CLKCTL_I2SFDCGB(1) |
SHIM_CLKCTL_I2SFDCGB(0) |
SHIM_CLKCTL_DMICFDCGB |
SHIM_CLKCTL_I2SEFDCGB(1) |
SHIM_CLKCTL_I2SEFDCGB(0) |
SHIM_CLKCTL_TCPAPLLS |
SHIM_CLKCTL_RAPLLC |
SHIM_CLKCTL_RXOSCC |
SHIM_CLKCTL_RFROSCC |
SHIM_CLKCTL_TCPLCG(0) | SHIM_CLKCTL_TCPLCG(1));
/* initialize PM for boot */
/* TODO: there are two clk freqs CRO & CRO/4
* Running on CRO all the time atm
*/
/* TODO: do not do local clock gating until making sure that
* tensilica core timer is unused.
* Could not find any arch_timer_set/timer_set() direct calls
* on cavs platforms atm.
*/
shim_write(SHIM_CLKCTL,
SHIM_CLKCTL_HDCS_PLL | /* HP domain clocked by PLL */
SHIM_CLKCTL_LDCS_PLL | /* LP domain clocked by PLL */
SHIM_CLKCTL_DPCS_DIV1(0) | /* Core 0 clk not divided */
SHIM_CLKCTL_DPCS_DIV1(1) | /* Core 1 clk not divided */
SHIM_CLKCTL_HPMPCS_DIV2 | /* HP mem clock div by 2 */
SHIM_CLKCTL_LPMPCS_DIV4 | /* LP mem clock div by 4 */
SHIM_CLKCTL_TCPAPLLS_DIS |
SHIM_CLKCTL_TCPLCG_DIS(0) | SHIM_CLKCTL_TCPLCG_DIS(1));
shim_write(SHIM_LPSCTL, shim_read(SHIM_LPSCTL));
#elif defined(CONFIG_CANNONLAKE) || defined(CONFIG_ICELAKE) \
|| defined(CONFIG_SUECREEK)
/* TODO: need to merge as for APL */
clock_set_freq(CLK_CPU, CLK_MAX_CPU_HZ);
/* prevent Core0 clock gating. */
shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) |
@ -368,12 +365,17 @@ int platform_init(struct sof *sof)
shim_write16(SHIM_PWRCTL, SHIM_PWRCTL_TCPDSP0PG);
#endif
/* initialize the host IPC mechanisms */
trace_point(TRACE_BOOT_PLATFORM_IPC);
ipc_init(sof);
/* init DMACs */
trace_point(TRACE_BOOT_PLATFORM_DMA);
ret = dmac_init();
if (ret < 0)
return -ENODEV;
/* init DAIs */
ret = dai_init();
if (ret < 0)
return -ENODEV;

View File

@ -38,7 +38,7 @@
#include <sof/alloc.h>
#include <platform/platform.h>
#include <platform/pm_runtime.h>
#include <platform/cavs/pm_runtime.h>
#include <platform/dai.h>
#if defined(CONFIG_APOLLOLAKE)
//TODO: add support or at least stub api for Cannonlake & Icelake
@ -48,6 +48,68 @@
/** \brief Runtime power management data pointer. */
struct pm_runtime_data *_prd;
/**
* \brief Forces Host DMAs to exit L1.
*/
static inline void cavs_pm_runtime_force_host_dma_l1_exit(void)
{
uint32_t flags;
spin_lock_irq(&_prd->lock, flags);
if (!(shim_read(SHIM_SVCFG) & SHIM_SVCFG_FORCE_L1_EXIT)) {
shim_write(SHIM_SVCFG,
shim_read(SHIM_SVCFG) | SHIM_SVCFG_FORCE_L1_EXIT);
wait_delay(PLATFORM_FORCE_L1_EXIT_TIME);
shim_write(SHIM_SVCFG,
shim_read(SHIM_SVCFG) & ~(SHIM_SVCFG_FORCE_L1_EXIT));
}
spin_unlock_irq(&_prd->lock, flags);
}
static inline void cavs_pm_runtime_dis_ssp_clk_gating(uint32_t index)
{
#if defined(CONFIG_APOLLOLAKE)
shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) |
(index < DAI_NUM_SSP_BASE ?
SHIM_CLKCTL_I2SFDCGB(index) :
SHIM_CLKCTL_I2SEFDCGB(index)));
trace_event(TRACE_CLASS_POWER,
"dis-ssp-clk-gating index %d CLKCTL %08x",
index, shim_read(SHIM_CLKCTL));
#endif
}
#if defined(CONFIG_DMIC)
static inline void cavs_pm_runtime_dis_dmic_clk_gating(uint32_t index)
{
#if defined(CONFIG_APOLLOLAKE)
(void)index;
shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) | SHIM_CLKCTL_DMICFDCGB);
trace_event(TRACE_CLASS_POWER,
"dis-dmic-clk-gating index %d CLKCTL %08x",
index, shim_read(SHIM_CLKCTL));
#endif
}
#endif
static inline void cavs_pm_runtime_dis_dwdma_clk_gating(uint32_t index)
{
#if defined(CONFIG_APOLLOLAKE)
shim_write(SHIM_CLKCTL, shim_read(SHIM_CLKCTL) |
SHIM_CLKCTL_LPGPDMAFDCGB(index));
trace_event(TRACE_CLASS_POWER,
"dis-dwdma-clk-gating index %d CLKCTL %08x",
index, shim_read(SHIM_CLKCTL));
#endif
}
void platform_pm_runtime_init(struct pm_runtime_data *prd)
{
struct platform_pm_runtime_data *pprd;
@ -62,6 +124,21 @@ void platform_pm_runtime_get(enum pm_runtime_context context, uint32_t index,
uint32_t flags)
{
/* Action based on context */
switch (context) {
case SSP_CLK:
cavs_pm_runtime_dis_ssp_clk_gating(index);
break;
#if defined(CONFIG_DMIC)
case DMIC_CLK:
cavs_pm_runtime_dis_dmic_clk_gating(index);
break;
#endif
case DW_DMAC_CLK:
cavs_pm_runtime_dis_dwdma_clk_gating(index);
break;
default:
break;
}
}
void platform_pm_runtime_put(enum pm_runtime_context context, uint32_t index,

View File

@ -1 +0,0 @@
SUBDIRS = platform

View File

@ -1,3 +0,0 @@
if BUILD_CAVS
SUBDIRS = cavs
endif

View File

@ -1,2 +0,0 @@
noinst_HEADERS = \
pm_runtime.h

View File

@ -1,65 +0,0 @@
/*
* Copyright (c) 2018, Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the Intel Corporation nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* Author: Tomasz Lauda <tomasz.lauda@linux.intel.com>
*/
/**
* \file platform/intel/platform/cavs/include/pm_runtime.h
* \brief Runtime power management header file for cAVS
* \author Tomasz Lauda <tomasz.lauda@linux.intel.com>
*/
#ifndef __INCLUDE_CAVS_PM_RUNTIME__
#define __INCLUDE_CAVS_PM_RUNTIME__
#include <platform/pm_runtime.h>
extern struct pm_runtime_data *_prd;
/**
* \brief Forces Host DMAs to exit L1.
*/
static inline void cavs_pm_runtime_force_host_dma_l1_exit(void)
{
uint32_t flags;
spin_lock_irq(&_prd->lock, flags);
if (!(shim_read(SHIM_SVCFG) & SHIM_SVCFG_FORCE_L1_EXIT)) {
shim_write(SHIM_SVCFG,
shim_read(SHIM_SVCFG) | SHIM_SVCFG_FORCE_L1_EXIT);
wait_delay(PLATFORM_FORCE_L1_EXIT_TIME);
shim_write(SHIM_SVCFG,
shim_read(SHIM_SVCFG) & ~(SHIM_SVCFG_FORCE_L1_EXIT));
}
spin_unlock_irq(&_prd->lock, flags);
}
#endif /* __INCLUDE_CAVS_PM_RUNTIME__ */