diff --git a/Makefile.am b/Makefile.am index 6be7c8eae34d..892cc2c08d98 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 diff --git a/configure.ac b/configure.ac index 02c2579a5bad..9071e7239d59 100644 --- a/configure.ac +++ b/configure.ac @@ -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 ]) diff --git a/src/drivers/intel/baytrail/ssp.c b/src/drivers/intel/baytrail/ssp.c index cd67a47e3840..0acbd97eb32c 100644 --- a/src/drivers/intel/baytrail/ssp.c +++ b/src/drivers/intel/baytrail/ssp.c @@ -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 @@ static inline int ssp_set_config(struct dai *dai, /* 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; diff --git a/src/drivers/intel/cavs/clk.c b/src/drivers/intel/cavs/clk.c index 785ec7e98e51..28b34e6f29d6 100644 --- a/src/drivers/intel/cavs/clk.c +++ b/src/drivers/intel/cavs/clk.c @@ -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); diff --git a/src/drivers/intel/cavs/dmic.c b/src/drivers/intel/cavs/dmic.c index 5cf88bca7fb8..a95337210a8c 100644 --- a/src/drivers/intel/cavs/dmic.c +++ b/src/drivers/intel/cavs/dmic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -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; diff --git a/src/drivers/intel/cavs/hda-dma.c b/src/drivers/intel/cavs/hda-dma.c index 311c70c17322..6b7a048d7ce7 100644 --- a/src/drivers/intel/cavs/hda-dma.c +++ b/src/drivers/intel/cavs/hda-dma.c @@ -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; diff --git a/src/drivers/intel/cavs/ssp.c b/src/drivers/intel/cavs/ssp.c index 081829a9e425..4d39f4697302 100644 --- a/src/drivers/intel/cavs/ssp.c +++ b/src/drivers/intel/cavs/ssp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -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 @@ static inline int ssp_set_config(struct dai *dai, /* 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; diff --git a/src/drivers/intel/dw-dma.c b/src/drivers/intel/dw-dma.c index 29008f59cbd8..1e4f25d3bcf9 100644 --- a/src/drivers/intel/dw-dma.c +++ b/src/drivers/intel/dw-dma.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -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)); diff --git a/src/drivers/intel/haswell/ssp.c b/src/drivers/intel/haswell/ssp.c index 2ca95effe43f..3365ce970307 100644 --- a/src/drivers/intel/haswell/ssp.c +++ b/src/drivers/intel/haswell/ssp.c @@ -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 @@ static inline int ssp_set_config(struct dai *dai, /* 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; diff --git a/src/include/sof/dai.h b/src/include/sof/dai.h index 90434188c5eb..c9644947e199 100644 --- a/src/include/sof/dai.h +++ b/src/include/sof/dai.h @@ -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) \ diff --git a/src/include/sof/dma.h b/src/include/sof/dma.h index 491938f0f761..7f8af2174c89 100644 --- a/src/include/sof/dma.h +++ b/src/include/sof/dma.h @@ -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) \ diff --git a/src/include/sof/dmic.h b/src/include/sof/dmic.h index 9bbf491ad84d..1027ef8da58c 100644 --- a/src/include/sof/dmic.h +++ b/src/include/sof/dmic.h @@ -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]; diff --git a/src/include/sof/ssp.h b/src/include/sof/ssp.h index a9defcf2697e..92ac4f44a07d 100644 --- a/src/include/sof/ssp.h +++ b/src/include/sof/ssp.h @@ -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; diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 0e15821a88e9..58c660685685 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -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; } diff --git a/src/lib/dai.c b/src/lib/dai.c index 270e8ab381c3..5e43221ebfc5 100644 --- a/src/lib/dai.c +++ b/src/lib/dai.c @@ -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; } diff --git a/src/lib/dma.c b/src/lib/dma.c index 53fae9690e69..014c6b1c5718 100644 --- a/src/lib/dma.c +++ b/src/lib/dma.c @@ -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; } diff --git a/src/platform/apollolake/include/platform/asm_memory_management.h b/src/platform/apollolake/include/platform/asm_memory_management.h index 7ef9cb24a825..69246fb8ca22 100644 --- a/src/platform/apollolake/include/platform/asm_memory_management.h +++ b/src/platform/apollolake/include/platform/asm_memory_management.h @@ -40,6 +40,7 @@ #warning "ASSEMBLY macro not defined." #endif +#include #include #include diff --git a/src/platform/apollolake/include/platform/shim.h b/src/platform/apollolake/include/platform/shim.h index a121410f42a8..cfa10b533d72 100644 --- a/src/platform/apollolake/include/platform/shim.h +++ b/src/platform/apollolake/include/platform/shim.h @@ -145,37 +145,72 @@ #define SHIM_DSPWCTCS_T1A (0x1 << 1) /* Timer 1 armed */ #define SHIM_DSPWCTCS_T0A (0x1 << 0) /* Timer 0 armed */ +/** \brief LDO Control */ +#define SHIM_LDOCTL 0xA4 + +/** \brief Clock control */ #define SHIM_CLKCTL 0x78 + +/** \brief Clock status */ #define SHIM_CLKSTS 0x7C -#define SHIM_CLKCTL_RAPLLC (0x1 << 31) -#define SHIM_CLKCTL_RXOSCC (0x1 << 30) -#define SHIM_CLKCTL_RFROSCC (0x1 << 29) +/** \brief Request Audio PLL Clock */ +#define SHIM_CLKCTL_RAPLLC BIT(31) -#define SHIM_LDOCTL 0xA4 +/** \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) -/* 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 I2S Force Dynamic Clock Gating */ +#define SHIM_CLKCTL_I2SFDCGB(x) BIT(20 + x) -/* Core clock PLL divisor */ +/** \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)) + +/** \brief Tensilica Core Prevent Audio PLL Shutdown */ +#define SHIM_CLKCTL_TCPAPLLS_EN BIT(7) +#define SHIM_CLKCTL_TCPAPLLS_DIS 0 + +/** \brief LP domain clock select, 0: PLL, 1: oscillator */ +#define SHIM_CLKCTL_LDCS_XTAL BIT(5) +#define SHIM_CLKCTL_LDCS_PLL 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) -/* 0--from PLL, 1--from oscillator */ -#define SHIM_CLKCTL_LDCS (0x1 << 5) -#define SHIM_CLKCTL_HDCS (0x1 << 4) +/** \brief HP domain oscillator clock select select, 0: XTAL, 1: Fast RING */ +#define SHIM_CLKCTL_HDOCS BIT(2) -/* Oscillator clock select select 0--XTAL, 1--Fast RING*/ -#define SHIM_CLKCTL_LDOCS (0x1 << 3) -#define SHIM_CLKCTL_HDOCS (0x1 << 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 -/* HP memory clock PLL divisor */ -#define SHIM_CLKCTL_HPMPCS (0x1 << 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 diff --git a/src/platform/apollolake/power_down.S b/src/platform/apollolake/power_down.S index b0c04b588126..b75c7b4cfbe0 100644 --- a/src/platform/apollolake/power_down.S +++ b/src/platform/apollolake/power_down.S @@ -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 diff --git a/src/platform/intel/Makefile.am b/src/platform/intel/Makefile.am index 6a966baf3682..c2c6328c8a98 100644 --- a/src/platform/intel/Makefile.am +++ b/src/platform/intel/Makefile.am @@ -1,5 +1,4 @@ -SUBDIRS = include - +SUBDIRS = if BUILD_CAVS SUBDIRS += cavs -endif \ No newline at end of file +endif diff --git a/src/platform/intel/cavs/dai.c b/src/platform/intel/cavs/dai.c index 3ff261393ef0..4bd2f3ef651a 100644 --- a/src/platform/intel/cavs/dai.c +++ b/src/platform/intel/cavs/dai.c @@ -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; } diff --git a/src/platform/intel/cavs/dma.c b/src/platform/intel/cavs/dma.c index 4a79ee1c59ed..36ee217da22b 100644 --- a/src/platform/intel/cavs/dma.c +++ b/src/platform/intel/cavs/dma.c @@ -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)); diff --git a/src/platform/intel/cavs/platform.c b/src/platform/intel/cavs/platform.c index 15b16db6b3bd..905065e5c9bb 100644 --- a/src/platform/intel/cavs/platform.c +++ b/src/platform/intel/cavs/platform.c @@ -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); +#if defined(CONFIG_APOLLOLAKE) + /* initialize PM for boot */ - /* initialise the host IPC mechanisms */ - trace_point(TRACE_BOOT_PLATFORM_IPC); - ipc_init(sof); + /* TODO: there are two clk freqs CRO & CRO/4 + * Running on CRO all the time atm + */ -#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)); + /* 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; diff --git a/src/platform/intel/cavs/pm_runtime.c b/src/platform/intel/cavs/pm_runtime.c index 17ad2f14c3ac..4e77d165cc6e 100644 --- a/src/platform/intel/cavs/pm_runtime.c +++ b/src/platform/intel/cavs/pm_runtime.c @@ -38,7 +38,7 @@ #include #include #include -#include +#include #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, diff --git a/src/platform/intel/include/Makefile.am b/src/platform/intel/include/Makefile.am deleted file mode 100644 index 912728c3a5d0..000000000000 --- a/src/platform/intel/include/Makefile.am +++ /dev/null @@ -1 +0,0 @@ -SUBDIRS = platform diff --git a/src/platform/intel/include/platform/Makefile.am b/src/platform/intel/include/platform/Makefile.am deleted file mode 100644 index 13161e04979b..000000000000 --- a/src/platform/intel/include/platform/Makefile.am +++ /dev/null @@ -1,3 +0,0 @@ -if BUILD_CAVS -SUBDIRS = cavs -endif diff --git a/src/platform/intel/include/platform/cavs/Makefile.am b/src/platform/intel/include/platform/cavs/Makefile.am deleted file mode 100644 index 712c19764b14..000000000000 --- a/src/platform/intel/include/platform/cavs/Makefile.am +++ /dev/null @@ -1,2 +0,0 @@ -noinst_HEADERS = \ - pm_runtime.h diff --git a/src/platform/intel/include/platform/cavs/pm_runtime.h b/src/platform/intel/include/platform/cavs/pm_runtime.h deleted file mode 100644 index e6b483debd2f..000000000000 --- a/src/platform/intel/include/platform/cavs/pm_runtime.h +++ /dev/null @@ -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 - */ - -/** - * \file platform/intel/platform/cavs/include/pm_runtime.h - * \brief Runtime power management header file for cAVS - * \author Tomasz Lauda - */ - -#ifndef __INCLUDE_CAVS_PM_RUNTIME__ -#define __INCLUDE_CAVS_PM_RUNTIME__ - -#include - -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__ */