clear-pkgs-linux-iot-lts2018/0176-ASoC-CNL-Register-soun...

245 lines
7.9 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Hardik T Shah <hardik.t.shah@intel.com>
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 <hardik.t.shah@intel.com>
---
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 <linux/delay.h>
#include <linux/firmware.h>
#include <linux/device.h>
+#include <linux/sdw_bus.h>
+#include <linux/sdw/sdw_cnl.h>
#include <asm/set_memory.h>
#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