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
6 changes: 6 additions & 0 deletions boards/xtensa/intel_adsp_ace15_mtpm/pre_dt_board.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

# Suppress "unique_unit_address_if_enabled" to handle the following overlaps:
# - dmic0: dmic0@10000 & dmic1: dmic1@10000
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
6 changes: 6 additions & 0 deletions boards/xtensa/intel_adsp_cavs15/pre_dt_board.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

# Suppress "unique_unit_address_if_enabled" to handle the following overlaps:
# - dmic0: dmic0@10000 & dmic1: dmic1@10000
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
6 changes: 6 additions & 0 deletions boards/xtensa/intel_adsp_cavs25/pre_dt_board.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Copyright (c) 2022 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

# Suppress "unique_unit_address_if_enabled" to handle the following overlaps:
# - dmic0: dmic0@10000 & dmic1: dmic1@10000
list(APPEND EXTRA_DTC_FLAGS "-Wno-unique_unit_address_if_enabled")
121 changes: 112 additions & 9 deletions drivers/dai/intel/dmic/dmic.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,82 @@ struct dai_dmic_global_shared dai_dmic_global;

int dai_dmic_set_config_nhlt(struct dai_intel_dmic *dmic, const void *spec_config);

/* Exponent function for small values of x. This function calculates
* fairly accurately exponent for x in range -2.0 .. +2.0. The iteration
* uses first 11 terms of Taylor series approximation for exponent
* function. With the current scaling the numerator just remains under
* 64 bits with the 11 terms.
*
* See https://en.wikipedia.org/wiki/Exponential_function#Computation
*
* The input is Q3.29
* The output is Q9.23
*/
static int32_t exp_small_fixed(int32_t x)
{
int64_t p;
int64_t num = Q_SHIFT_RND(x, 29, 23);
int32_t y = (int32_t)num;
int32_t den = 1;
int32_t inc;
int k;

/* Numerator is x^k, denominator is k! */
for (k = 2; k < 12; k++) {
p = num * x; /* Q9.23 x Q3.29 -> Q12.52 */
num = Q_SHIFT_RND(p, 52, 23);
den = den * k;
inc = (int32_t)(num / den);
y += inc;
}

return y + ONE_Q23;
}

static int32_t exp_fixed(int32_t x)
{
int32_t xs;
int32_t y;
int32_t z;
int i;
int n = 0;

if (x < Q_CONVERT_FLOAT(-11.5, 27))
return 0;

if (x > Q_CONVERT_FLOAT(7.6245, 27))
return INT32_MAX;

/* x is Q5.27 */
xs = x;
while (xs >= TWO_Q27 || xs <= MINUS_TWO_Q27) {
xs >>= 1;
n++;
}

/* exp_small_fixed() input is Q3.29, while x1 is Q5.27
* exp_small_fixed() output is Q9.23, while z is Q12.20
*/
z = Q_SHIFT_RND(exp_small_fixed(Q_SHIFT_LEFT(xs, 27, 29)), 23, 20);
y = ONE_Q20;
for (i = 0; i < (1 << n); i++)
y = (int32_t)Q_MULTSR_32X32((int64_t)y, z, 20, 20, 20);

return y;
}

static int32_t db2lin_fixed(int32_t db)
{
int32_t arg;

if (db < Q_CONVERT_FLOAT(-100.0, 24))
return 0;

/* Q8.24 x Q5.27, result needs to be Q5.27 */
arg = (int32_t)Q_MULTSR_32X32((int64_t)db, LOG10_DIV20_Q27, 24, 27, 27);
return exp_fixed(arg);
}

static void dai_dmic_update_bits(const struct dai_intel_dmic *dmic,
uint32_t reg, uint32_t mask, uint32_t val)
{
Expand Down Expand Up @@ -157,7 +233,7 @@ static void dai_dmic_irq_handler(const void *data)
/* Trace OUTSTAT0 register */
val0 = dai_dmic_read(dmic, OUTSTAT0);
val1 = dai_dmic_read(dmic, OUTSTAT1);
LOG_INF("dmic_irq_handler(), OUTSTAT0 = 0x%x, OUTSTAT1 = 0x%x", val0, val1);
LOG_DBG("dmic_irq_handler(), OUTSTAT0 = 0x%x, OUTSTAT1 = 0x%x", val0, val1);

if (val0 & OUTSTAT0_ROR_BIT) {
LOG_ERR("dmic_irq_handler(): full fifo A or PDM overrun");
Expand All @@ -174,30 +250,53 @@ static void dai_dmic_irq_handler(const void *data)

static inline void dai_dmic_dis_clk_gating(const struct dai_intel_dmic *dmic)
{
#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V15
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be good to have shim registers definitions and basic access functions separated from main DMIC driver code and moved to platform specific headers. This patch now adds #ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V15, but shim registers definition for SOC_SERIES_INTEL_ACE will change from one version to another. In result soon we would have here several #ifdefs for different generations.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@juimonen @jxstelter Is this something to do now, or later in separate PR. Given we only have two cases now, I'd prefer to do this in separate PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK. Separate PR will be good.

uint32_t shim_reg;

shim_reg = sys_read32(SHIM_CLKCTL) | SHIM_CLKCTL_DMICFDCGB;

sys_write32(shim_reg, SHIM_CLKCTL);

LOG_INF("dis-dmic-clk-gating CLKCTL %08x", shim_reg);
#else
/* Disable DMIC clock gating */
sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | DMIC_DCGD),
dmic->shim_base + DMICLCTL_OFFSET);
#endif
}

static inline void dai_dmic_en_clk_gating(const struct dai_intel_dmic *dmic)
{
#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V15
uint32_t shim_reg;

shim_reg = sys_read32(SHIM_CLKCTL) & ~SHIM_CLKCTL_DMICFDCGB;

sys_write32(shim_reg, SHIM_CLKCTL);

LOG_INF("en-dmic-clk-gating CLKCTL %08x", shim_reg);
#else
/* Enable DMIC clock gating */
sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & ~DMIC_DCGD),
dmic->shim_base + DMICLCTL_OFFSET);
#endif
}

static inline void dai_dmic_en_power(const struct dai_intel_dmic *dmic)
{
#ifndef CONFIG_SOC_SERIES_INTEL_CAVS_V15
/* Enable DMIC power */
sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) | DMICLCTL_SPA),
dmic->shim_base + DMICLCTL_OFFSET);

#endif
}
static inline void dai_dmic_dis_power(const struct dai_intel_dmic *dmic)
{
#ifndef CONFIG_SOC_SERIES_INTEL_CAVS_V15
/* Disable DMIC power */
sys_write32((sys_read32(dmic->shim_base + DMICLCTL_OFFSET) & (~DMICLCTL_SPA)),
dmic->shim_base + DMICLCTL_OFFSET);
#endif
}

static int dai_dmic_probe(struct dai_intel_dmic *dmic)
Expand All @@ -220,6 +319,7 @@ static int dai_dmic_probe(struct dai_intel_dmic *dmic)
dai_dmic_claim_ownership(dmic);

irq_enable(dmic->irq);

return 0;
}

Expand Down Expand Up @@ -291,7 +391,7 @@ static int dai_timestamp_dmic_stop(const struct device *dev, struct dai_ts_cfg *
}

static int dai_timestamp_dmic_get(const struct device *dev, struct dai_ts_cfg *cfg,
struct dai_ts_data *tsd)
struct dai_ts_data *tsd)
{
/* Read DMIC timestamp registers */
uint32_t tsctrl = TS_DMIC_LOCAL_TSCTRL;
Expand Down Expand Up @@ -507,6 +607,9 @@ static void dai_dmic_start(struct dai_intel_dmic *dmic)
for (i = 0; i < CONFIG_DAI_DMIC_HW_CONTROLLERS; i++) {
dai_dmic_update_bits(dmic, base[i] + CIC_CONTROL,
CIC_CONTROL_SOFT_RESET_BIT, 0);

LOG_INF("dmic_start(), cic 0x%08x",
dai_dmic_read(dmic, base[i] + CIC_CONTROL));
}

/* Set bit dai->index */
Expand All @@ -519,7 +622,7 @@ static void dai_dmic_start(struct dai_intel_dmic *dmic)
dmic_sync_trigger(dmic);

LOG_INF("dmic_start(), dmic_active_fifos_mask = 0x%x",
dai_dmic_global.active_fifos_mask);
dai_dmic_global.active_fifos_mask);
}

static void dai_dmic_stop(struct dai_intel_dmic *dmic, bool stop_is_pause)
Expand Down Expand Up @@ -587,7 +690,7 @@ const struct dai_properties *dai_dmic_get_properties(const struct device *dev,
}

static int dai_dmic_trigger(const struct device *dev, enum dai_dir dir,
enum dai_trigger_cmd cmd)
enum dai_trigger_cmd cmd)
{
struct dai_intel_dmic *dmic = (struct dai_intel_dmic *)dev->data;

Expand Down Expand Up @@ -757,12 +860,12 @@ static int dai_dmic_initialize_device(const struct device *dev)
.dai_index = n \
}, \
.reg_base = DT_INST_REG_ADDR_BY_IDX(n, 0), \
.shim_base = DT_INST_PROP_BY_IDX(n, shim, 0), \
.shim_base = DT_INST_PROP(n, shim), \
.irq = DT_INST_IRQN(n), \
.fifo = \
{ \
.offset = DT_INST_REG_ADDR_BY_IDX(n, 0) \
+ OUTDATA##n, \
+ DT_INST_PROP(n, fifo), \
.handshake = DMA_HANDSHAKE_DMIC_CH##n \
}, \
}; \
Expand All @@ -773,7 +876,7 @@ static int dai_dmic_initialize_device(const struct device *dev)
&dai_intel_dmic_data_##n, \
&dai_intel_dmic_properties_##n, \
POST_KERNEL, \
CONFIG_DAI_INIT_PRIORITY, \
CONFIG_DAI_INIT_PRIORITY, \
&dai_dmic_ops);

DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_DMIC_DEVICE_INIT);
DT_INST_FOREACH_STATUS_OKAY(DAI_INTEL_DMIC_DEVICE_INIT)
99 changes: 23 additions & 76 deletions drivers/dai/intel/dmic/dmic.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@
#define TS_LOCAL_OFFS_FRM GET_BITS(15, 12)
#define TS_LOCAL_OFFS_CLK GET_BITS(11, 0)

#ifdef CONFIG_SOC_SERIES_INTEL_CAVS_V15
/* Clock control */
#define SHIM_CLKCTL 0x78
/* DMIC Force Dynamic Clock Gating */
#define SHIM_CLKCTL_DMICFDCGB BIT(24)
#endif

/* Digital Mic Shim Registers */
#define DMICLCTL_OFFSET 0x04
#define DMICIPPTR_OFFSET 0x08
Expand Down Expand Up @@ -155,7 +162,11 @@
#define OUTCONTROL0_FCI(x) SET_BIT(24, x)
#define OUTCONTROL0_BFTH(x) SET_BITS(23, 20, x)
#define OUTCONTROL0_OF(x) SET_BITS(19, 18, x)
#ifdef CONFIG_SOC_SERIES_INTEL_ACE
#define OUTCONTROL0_IPM(x) SET_BITS(17, 15, x)
#else
#define OUTCONTROL0_IPM(x) SET_BITS(17, 16, x)
#endif
#define OUTCONTROL0_IPM_SOURCE_1(x) SET_BITS(14, 13, x)
#define OUTCONTROL0_IPM_SOURCE_2(x) SET_BITS(12, 11, x)
#define OUTCONTROL0_IPM_SOURCE_3(x) SET_BITS(10, 9, x)
Expand All @@ -168,7 +179,11 @@
#define OUTCONTROL0_FCI_GET(x) GET_BIT(24, x)
#define OUTCONTROL0_BFTH_GET(x) GET_BITS(23, 20, x)
#define OUTCONTROL0_OF_GET(x) GET_BITS(19, 18, x)
#ifdef CONFIG_SOC_SERIES_INTEL_ACE
#define OUTCONTROL0_IPM_GET(x) GET_BITS(17, 15, x)
#else
#define OUTCONTROL0_IPM_GET(x) GET_BITS(17, 16, x)
#endif
#define OUTCONTROL0_IPM_SOURCE_1_GET(x) GET_BITS(14, 13, x)
#define OUTCONTROL0_IPM_SOURCE_2_GET(x) GET_BITS(12, 11, x)
#define OUTCONTROL0_IPM_SOURCE_3_GET(x) GET_BITS(10, 9, x)
Expand All @@ -187,7 +202,11 @@
#define OUTCONTROL1_FCI(x) SET_BIT(24, x)
#define OUTCONTROL1_BFTH(x) SET_BITS(23, 20, x)
#define OUTCONTROL1_OF(x) SET_BITS(19, 18, x)
#ifdef CONFIG_SOC_SERIES_INTEL_ACE
#define OUTCONTROL1_IPM(x) SET_BITS(17, 15, x)
#else
#define OUTCONTROL1_IPM(x) SET_BITS(17, 16, x)
#endif
#define OUTCONTROL1_IPM_SOURCE_1(x) SET_BITS(14, 13, x)
#define OUTCONTROL1_IPM_SOURCE_2(x) SET_BITS(12, 11, x)
#define OUTCONTROL1_IPM_SOURCE_3(x) SET_BITS(10, 9, x)
Expand All @@ -200,7 +219,11 @@
#define OUTCONTROL1_FCI_GET(x) GET_BIT(24, x)
#define OUTCONTROL1_BFTH_GET(x) GET_BITS(23, 20, x)
#define OUTCONTROL1_OF_GET(x) GET_BITS(19, 18, x)
#ifdef CONFIG_SOC_SERIES_INTEL_ACE
#define OUTCONTROL1_IPM_GET(x) GET_BITS(17, 15, x)
#else
#define OUTCONTROL1_IPM_GET(x) GET_BITS(17, 16, x)
#endif
#define OUTCONTROL1_IPM_SOURCE_1_GET(x) GET_BITS(14, 13, x)
#define OUTCONTROL1_IPM_SOURCE_2_GET(x) GET_BITS(12, 11, x)
#define OUTCONTROL1_IPM_SOURCE_3_GET(x) GET_BITS(10, 9, x)
Expand Down Expand Up @@ -535,82 +558,6 @@ struct dai_intel_dmic {
uint32_t flags;
};

/* Exponent function for small values of x. This function calculates
* fairly accurately exponent for x in range -2.0 .. +2.0. The iteration
* uses first 11 terms of Taylor series approximation for exponent
* function. With the current scaling the numerator just remains under
* 64 bits with the 11 terms.
*
* See https://en.wikipedia.org/wiki/Exponential_function#Computation
*
* The input is Q3.29
* The output is Q9.23
*/
static int32_t exp_small_fixed(int32_t x)
{
int64_t p;
int64_t num = Q_SHIFT_RND(x, 29, 23);
int32_t y = (int32_t)num;
int32_t den = 1;
int32_t inc;
int k;

/* Numerator is x^k, denominator is k! */
for (k = 2; k < 12; k++) {
p = num * x; /* Q9.23 x Q3.29 -> Q12.52 */
num = Q_SHIFT_RND(p, 52, 23);
den = den * k;
inc = (int32_t)(num / den);
y += inc;
}

return y + ONE_Q23;
}

static int32_t exp_fixed(int32_t x)
{
int32_t xs;
int32_t y;
int32_t z;
int i;
int n = 0;

if (x < Q_CONVERT_FLOAT(-11.5, 27))
return 0;

if (x > Q_CONVERT_FLOAT(7.6245, 27))
return INT32_MAX;

/* x is Q5.27 */
xs = x;
while (xs >= TWO_Q27 || xs <= MINUS_TWO_Q27) {
xs >>= 1;
n++;
}

/* exp_small_fixed() input is Q3.29, while x1 is Q5.27
* exp_small_fixed() output is Q9.23, while z is Q12.20
*/
z = Q_SHIFT_RND(exp_small_fixed(Q_SHIFT_LEFT(xs, 27, 29)), 23, 20);
y = ONE_Q20;
for (i = 0; i < (1 << n); i++)
y = (int32_t)Q_MULTSR_32X32((int64_t)y, z, 20, 20, 20);

return y;
}

static int32_t db2lin_fixed(int32_t db)
{
int32_t arg;

if (db < Q_CONVERT_FLOAT(-100.0, 24))
return 0;

/* Q8.24 x Q5.27, result needs to be Q5.27 */
arg = (int32_t)Q_MULTSR_32X32((int64_t)db, LOG10_DIV20_Q27, 24, 27, 27);
return exp_fixed(arg);
}

static inline int32_t sat_int32(int64_t x)
{
if (x > INT32_MAX)
Expand Down
Loading