From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Hardik T Shah Date: Thu, 10 Mar 2016 10:33:33 +0530 Subject: [PATCH] ASoC: CNL: Register soundwire controller to bus driver. This patch registers the SoundWire controller to the SoundWire bus driver. Change-Id: Iefc4a7cd30d2f5ad043fe63e82f519ebc488bf65 Signed-off-by: Hardik T Shah --- sound/soc/intel/skylake/cnl-sst-dsp.c | 6 ++ sound/soc/intel/skylake/cnl-sst-dsp.h | 13 +++ sound/soc/intel/skylake/cnl-sst.c | 121 ++++++++++++++++++++++++++ sound/soc/intel/skylake/skl-sst-ipc.h | 5 ++ 4 files changed, 145 insertions(+) diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.c b/sound/soc/intel/skylake/cnl-sst-dsp.c index 2f8326707c21..2d9c86ddcdf0 100644 --- a/sound/soc/intel/skylake/cnl-sst-dsp.c +++ b/sound/soc/intel/skylake/cnl-sst-dsp.c @@ -237,6 +237,12 @@ void cnl_ipc_int_disable(struct sst_dsp *ctx) CNL_ADSPIC_IPC, 0); } +void cnl_sdw_int_enable(struct sst_dsp *ctx, bool enable) +{ + sst_dsp_shim_update_bits(ctx, CNL_ADSP_REG_ADSPIC2, + CNL_ADSPIC2_SNDW, CNL_ADSPIC2_SNDW); +} + void cnl_ipc_op_int_enable(struct sst_dsp *ctx) { /* enable IPC DONE interrupt */ diff --git a/sound/soc/intel/skylake/cnl-sst-dsp.h b/sound/soc/intel/skylake/cnl-sst-dsp.h index 09bd218df5c4..323cebc4e389 100644 --- a/sound/soc/intel/skylake/cnl-sst-dsp.h +++ b/sound/soc/intel/skylake/cnl-sst-dsp.h @@ -26,6 +26,8 @@ struct sst_generic_ipc; #define CNL_ADSP_REG_ADSPCS (CNL_ADSP_GEN_BASE + 0x04) #define CNL_ADSP_REG_ADSPIC (CNL_ADSP_GEN_BASE + 0x08) #define CNL_ADSP_REG_ADSPIS (CNL_ADSP_GEN_BASE + 0x0c) +#define CNL_ADSP_REG_ADSPIC2 (CNL_ADSP_GEN_BASE + 0x10) +#define CNL_ADSP_REG_ADSPIS2 (CNL_ADSP_GEN_BASE + 0x14) /* Intel HD Audio Inter-Processor Communication Registers */ #define CNL_ADSP_IPC_BASE 0xc0 @@ -72,6 +74,16 @@ struct sst_generic_ipc; #define CNL_ADSPIC_IPC 0x1 #define CNL_ADSPIS_IPC 0x1 +#define CNL_ADSPIC2_SNDW 0x20 + +#define CNL_SDW_SHIM_BASE 0x2C000 +#define CNL_SDW_LINK_0_BASE 0x30000 +#define CNL_SDW_LINK_1_BASE 0x40000 +#define CNL_SDW_LINK_2_BASE 0x50000 +#define CNL_SDW_LINK_3_BASE 0x60000 +#define CNL_ALH_BASE 0x2C800 + +/* ADSPCS - Audio DSP Control & Status */ #define CNL_DSP_CORES 4 #define CNL_DSP_CORES_MASK ((1 << CNL_DSP_CORES) - 1) @@ -98,6 +110,7 @@ void cnl_dsp_free(struct sst_dsp *dsp); void cnl_ipc_int_enable(struct sst_dsp *ctx); void cnl_ipc_int_disable(struct sst_dsp *ctx); +void cnl_sdw_int_enable(struct sst_dsp *ctx, bool enable); void cnl_ipc_op_int_enable(struct sst_dsp *ctx); void cnl_ipc_op_int_disable(struct sst_dsp *ctx); bool cnl_ipc_int_status(struct sst_dsp *ctx); diff --git a/sound/soc/intel/skylake/cnl-sst.c b/sound/soc/intel/skylake/cnl-sst.c index b508426113a7..797a3053399d 100644 --- a/sound/soc/intel/skylake/cnl-sst.c +++ b/sound/soc/intel/skylake/cnl-sst.c @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include "../common/sst-dsp.h" @@ -498,6 +500,118 @@ static int cnl_ipc_init(struct device *dev, struct skl_sst *cnl) return 0; } +static int skl_register_sdw_masters(struct device *dev, struct skl_sst *dsp, + void __iomem *mmio_base, int irq) +{ + struct sdw_master_capabilities *m_cap; + struct sdw_mstr_dp0_capabilities *dp0_cap; + struct sdw_mstr_dpn_capabilities *dpn_cap; + struct sdw_master *master; + struct cnl_sdw_data *p_data; + int ret = 0, i, j; + /* TODO: This number 4 should come from ACPI */ + dsp->num_sdw_controllers = 1; + master = devm_kzalloc(dev, + (sizeof(*master) * dsp->num_sdw_controllers), + GFP_KERNEL); + if (!master) { + return -ENOMEM; + dsp->num_sdw_controllers = 0; + } + dsp->mstr = master; + /* TODO This should come from ACPI */ + for (i = 0; i < dsp->num_sdw_controllers; i++) { + p_data = devm_kzalloc(dev, sizeof(*p_data), GFP_KERNEL); + if (!p_data) + return -ENOMEM; + /* PCI Device is parent of the SoundWire master device */ + /* TODO: All these hardcoding should come from ACPI */ + master[i].dev.parent = dev; + master[i].dev.platform_data = p_data; + m_cap = &master[i].mstr_capabilities; + dp0_cap = &m_cap->sdw_dp0_cap; + master[i].nr = i; + master[i].timeout = -1; + master[i].retries = CNL_SDW_MAX_CMD_RETRIES; + m_cap->base_clk_freq = 9.6 * 1000 * 1000; + strcpy(master[i].name, "cnl_sdw_mstr"); + m_cap->highphy_capable = 0; + m_cap->sdw_dp0_supported = 1; + m_cap->num_data_ports = CNL_SDW_MAX_PORTS; + dp0_cap->max_word_length = 32; + dp0_cap->min_word_length = 1; + dp0_cap->num_word_length = 0; + dp0_cap->word_length_buffer = NULL; + dp0_cap->bra_max_data_per_frame = 0; + m_cap->sdw_dpn_cap = kzalloc(((sizeof(*dpn_cap)) * + CNL_SDW_MAX_PORTS), GFP_KERNEL); + if (!m_cap->sdw_dpn_cap) + return -ENOMEM; + for (j = 0; j < m_cap->num_data_ports; j++) { + dpn_cap = &m_cap->sdw_dpn_cap[i]; + /* Both Tx and Rx */ + dpn_cap->port_direction = 0x3; + dpn_cap->port_number = i; + dpn_cap->max_word_length = 32; + dpn_cap->min_word_length = 1; + dpn_cap->num_word_length = 0; + dpn_cap->word_length_buffer = NULL; + dpn_cap->dpn_type = SDW_FULL_DP; + dpn_cap->min_ch_num = 1; + dpn_cap->max_ch_num = 8; + dpn_cap->num_ch_supported = 0; + dpn_cap->ch_supported = NULL; + /* IP supports all, but we are going to support only + * isochronous + */ + dpn_cap->port_mode_mask = + SDW_PORT_FLOW_MODE_ISOCHRONOUS; + dpn_cap->block_packing_mode_mask = + SDW_PORT_BLK_PKG_MODE_BLK_PER_PORT | + SDW_PORT_BLK_PKG_MODE_BLK_PER_CH; + } + switch (i) { + case 0: + p_data->sdw_regs = mmio_base + CNL_SDW_LINK_0_BASE; + break; + case 1: + p_data->sdw_regs = mmio_base + CNL_SDW_LINK_1_BASE; + break; + case 2: + p_data->sdw_regs = mmio_base + CNL_SDW_LINK_2_BASE; + break; + case 3: + p_data->sdw_regs = mmio_base + CNL_SDW_LINK_3_BASE; + break; + default: + return -EINVAL; + } + p_data->sdw_shim = mmio_base + CNL_SDW_SHIM_BASE; + p_data->alh_base = mmio_base + CNL_ALH_BASE; + p_data->inst_id = i; + p_data->irq = irq; + ret = sdw_add_master_controller(&master[i]); + if (ret) { + dev_err(dev, "Failed to register soundwire master\n"); + return ret; + } + } + /* Enable the global soundwire interrupts */ + cnl_sdw_int_enable(dsp->dsp, 1); + return 0; +} + +static void skl_unregister_sdw_masters(struct skl_sst *ctx) +{ + int i; + + /* Disable global soundwire interrupts */ + cnl_sdw_int_enable(ctx->dsp, 0); + for (i = 0; i < ctx->num_sdw_controllers; i++) + sdw_del_master_controller(&ctx->mstr[i]); + +} + int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, const char *fw_name, struct skl_dsp_loader_ops dsp_ops, struct skl_sst **dsp) @@ -545,6 +659,12 @@ int cnl_sst_dsp_init(struct device *dev, void __iomem *mmio_base, int irq, return ret; } + ret = skl_register_sdw_masters(dev, cnl, mmio_base, irq); + if (ret) { + dev_err(cnl->dev, "%s SoundWire masters registration failed\n", __func__); + return ret; + } + return 0; } EXPORT_SYMBOL_GPL(cnl_sst_dsp_init); @@ -576,6 +696,7 @@ void cnl_sst_dsp_cleanup(struct device *dev, struct skl_sst *ctx) release_firmware(ctx->dsp->fw); skl_freeup_uuid_list(ctx); + skl_unregister_sdw_masters(ctx); cnl_ipc_free(&ctx->ipc); ctx->dsp->ops->free(ctx->dsp); diff --git a/sound/soc/intel/skylake/skl-sst-ipc.h b/sound/soc/intel/skylake/skl-sst-ipc.h index f74f040dfd83..10a486939515 100644 --- a/sound/soc/intel/skylake/skl-sst-ipc.h +++ b/sound/soc/intel/skylake/skl-sst-ipc.h @@ -121,6 +121,11 @@ struct skl_sst { /* Callback to update dynamic clock and power gating registers */ void (*clock_power_gating)(struct device *dev, bool enable); + + /* SDW Devices in DSP Space */ + int num_sdw_controllers; + /* Array of sdw masters */ + struct sdw_master *mstr; }; struct skl_ipc_init_instance_msg { -- https://clearlinux.org