Skip to content

Commit

Permalink
ASoC: qcom: Add support for lpass hdmi driver
Browse files Browse the repository at this point in the history
Upadate lpass cpu and platform driver to support audio over dp.
Also add lpass-hdmi.c and lpass-hdmi.h.

Signed-off-by: V Sujith Kumar Reddy <vsujithk@codeaurora.org>
Signed-off-by: Srinivasa Rao <srivasam@codeaurora.org>
Reviewed-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Tested-by: Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
Link: https://lore.kernel.org/r/1602134223-2562-6-git-send-email-srivasam@codeaurora.org
Signed-off-by: Mark Brown <broonie@kernel.org>
  • Loading branch information
V Sujith Kumar Reddy authored and Mark Brown committed Oct 8, 2020
1 parent d9e8e61 commit 7cb37b7
Show file tree
Hide file tree
Showing 10 changed files with 1,075 additions and 97 deletions.
5 changes: 5 additions & 0 deletions sound/soc/qcom/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ config SND_SOC_LPASS_CPU
tristate
select REGMAP_MMIO

config SND_SOC_LPASS_HDMI
tristate
select REGMAP_MMIO

config SND_SOC_LPASS_PLATFORM
tristate
select REGMAP_MMIO
Expand All @@ -30,6 +34,7 @@ config SND_SOC_LPASS_SC7180
tristate
select SND_SOC_LPASS_CPU
select SND_SOC_LPASS_PLATFORM
select SND_SOC_LPASS_HDMI

config SND_SOC_STORM
tristate "ASoC I2S support for Storm boards"
Expand Down
2 changes: 2 additions & 0 deletions sound/soc/qcom/Makefile
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# SPDX-License-Identifier: GPL-2.0
# Platform
snd-soc-lpass-cpu-objs := lpass-cpu.o
snd-soc-lpass-hdmi-objs := lpass-hdmi.o
snd-soc-lpass-platform-objs := lpass-platform.o
snd-soc-lpass-ipq806x-objs := lpass-ipq806x.o
snd-soc-lpass-apq8016-objs := lpass-apq8016.o
snd-soc-lpass-sc7180-objs := lpass-sc7180.o

obj-$(CONFIG_SND_SOC_LPASS_CPU) += snd-soc-lpass-cpu.o
obj-$(CONFIG_SND_SOC_LPASS_HDMI) += snd-soc-lpass-hdmi.o
obj-$(CONFIG_SND_SOC_LPASS_PLATFORM) += snd-soc-lpass-platform.o
obj-$(CONFIG_SND_SOC_LPASS_IPQ806X) += snd-soc-lpass-ipq806x.o
obj-$(CONFIG_SND_SOC_LPASS_APQ8016) += snd-soc-lpass-apq8016.o
Expand Down
4 changes: 2 additions & 2 deletions sound/soc/qcom/lpass-apq8016.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ static struct snd_soc_dai_driver apq8016_lpass_cpu_dai_driver[] = {
};

static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
int direction)
int direction, unsigned int dai_id)
{
struct lpass_variant *v = drvdata->variant;
int chan = 0;
Expand All @@ -151,7 +151,7 @@ static int apq8016_lpass_alloc_dma_channel(struct lpass_data *drvdata,
return chan;
}

static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan)
static int apq8016_lpass_free_dma_channel(struct lpass_data *drvdata, int chan, unsigned int dai_id)
{
clear_bit(chan, &drvdata->dma_ch_bit_map);

Expand Down
247 changes: 241 additions & 6 deletions sound/soc/qcom/lpass-cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,206 @@ static struct regmap_config lpass_cpu_regmap_config = {
.cache_type = REGCACHE_FLAT,
};

static int lpass_hdmi_init_bitfields(struct device *dev, struct regmap *map)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
struct lpass_variant *v = drvdata->variant;
unsigned int i;
struct lpass_hdmi_tx_ctl *tx_ctl;
struct regmap_field *legacy_en;
struct lpass_vbit_ctrl *vbit_ctl;
struct regmap_field *tx_parity;
struct lpass_dp_metadata_ctl *meta_ctl;
struct lpass_sstream_ctl *sstream_ctl;
struct regmap_field *ch_msb;
struct regmap_field *ch_lsb;
struct lpass_hdmitx_dmactl *tx_dmactl;
int rval;

tx_ctl = devm_kzalloc(dev, sizeof(*tx_ctl), GFP_KERNEL);
if (!tx_ctl)
return -ENOMEM;

QCOM_REGMAP_FIELD_ALLOC(dev, map, v->soft_reset, tx_ctl->soft_reset);
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->force_reset, tx_ctl->force_reset);
drvdata->tx_ctl = tx_ctl;

QCOM_REGMAP_FIELD_ALLOC(dev, map, v->legacy_en, legacy_en);
drvdata->hdmitx_legacy_en = legacy_en;

vbit_ctl = devm_kzalloc(dev, sizeof(*vbit_ctl), GFP_KERNEL);
if (!vbit_ctl)
return -ENOMEM;

QCOM_REGMAP_FIELD_ALLOC(dev, map, v->replace_vbit, vbit_ctl->replace_vbit);
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->vbit_stream, vbit_ctl->vbit_stream);
drvdata->vbit_ctl = vbit_ctl;


QCOM_REGMAP_FIELD_ALLOC(dev, map, v->calc_en, tx_parity);
drvdata->hdmitx_parity_calc_en = tx_parity;

meta_ctl = devm_kzalloc(dev, sizeof(*meta_ctl), GFP_KERNEL);
if (!meta_ctl)
return -ENOMEM;

rval = devm_regmap_field_bulk_alloc(dev, map, &meta_ctl->mute, &v->mute, 7);
if (rval)
return rval;
drvdata->meta_ctl = meta_ctl;

sstream_ctl = devm_kzalloc(dev, sizeof(*sstream_ctl), GFP_KERNEL);
if (!sstream_ctl)
return -ENOMEM;

rval = devm_regmap_field_bulk_alloc(dev, map, &sstream_ctl->sstream_en, &v->sstream_en, 9);
if (rval)
return rval;

drvdata->sstream_ctl = sstream_ctl;

for (i = 0; i < LPASS_MAX_HDMI_DMA_CHANNELS; i++) {
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->msb_bits, ch_msb);
drvdata->hdmitx_ch_msb[i] = ch_msb;

QCOM_REGMAP_FIELD_ALLOC(dev, map, v->lsb_bits, ch_lsb);
drvdata->hdmitx_ch_lsb[i] = ch_lsb;

tx_dmactl = devm_kzalloc(dev, sizeof(*tx_dmactl), GFP_KERNEL);
if (!tx_dmactl)
return -ENOMEM;

QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_chs, tx_dmactl->use_hw_chs);
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->use_hw_usr, tx_dmactl->use_hw_usr);
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_chs_sel, tx_dmactl->hw_chs_sel);
QCOM_REGMAP_FIELD_ALLOC(dev, map, v->hw_usr_sel, tx_dmactl->hw_usr_sel);
drvdata->hdmi_tx_dmactl[i] = tx_dmactl;
}
return 0;
}

static bool lpass_hdmi_regmap_writeable(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
struct lpass_variant *v = drvdata->variant;
int i;

if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_DP_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
return true;
if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
return true;
if (reg == LPASS_HDMITX_APP_IRQCLEAR_REG(v))
return true;

for (i = 0; i < v->hdmi_rdma_channels; i++) {
if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
return true;
if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
return true;
if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
return true;
}

for (i = 0; i < v->rdma_channels; ++i) {
if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
return true;
}
return false;
}

static bool lpass_hdmi_regmap_readable(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
struct lpass_variant *v = drvdata->variant;
int i;

if (reg == LPASS_HDMI_TX_CTL_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_VBIT_CTL_ADDR(v))
return true;

for (i = 0; i < v->hdmi_rdma_channels; i++) {
if (reg == LPASS_HDMI_TX_CH_LSB_ADDR(v, i))
return true;
if (reg == LPASS_HDMI_TX_CH_MSB_ADDR(v, i))
return true;
if (reg == LPASS_HDMI_TX_DMA_ADDR(v, i))
return true;
}

if (reg == LPASS_HDMI_TX_PARITY_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_DP_ADDR(v))
return true;
if (reg == LPASS_HDMI_TX_SSTREAM_ADDR(v))
return true;
if (reg == LPASS_HDMITX_APP_IRQEN_REG(v))
return true;
if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
return true;

for (i = 0; i < v->rdma_channels; ++i) {
if (reg == LPAIF_HDMI_RDMACTL_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMABASE_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMABUFF_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMAPER_REG(v, i))
return true;
if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
return true;
}

return false;
}

static bool lpass_hdmi_regmap_volatile(struct device *dev, unsigned int reg)
{
struct lpass_data *drvdata = dev_get_drvdata(dev);
struct lpass_variant *v = drvdata->variant;
int i;

if (reg == LPASS_HDMITX_APP_IRQSTAT_REG(v))
return true;
if (reg == LPASS_HDMI_TX_LEGACY_ADDR(v))
return true;

for (i = 0; i < v->rdma_channels; ++i) {
if (reg == LPAIF_HDMI_RDMACURR_REG(v, i))
return true;
}
return false;
}

struct regmap_config lpass_hdmi_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
.writeable_reg = lpass_hdmi_regmap_writeable,
.readable_reg = lpass_hdmi_regmap_readable,
.volatile_reg = lpass_hdmi_regmap_volatile,
.cache_type = REGCACHE_FLAT,
};

static unsigned int of_lpass_cpu_parse_sd_lines(struct device *dev,
struct device_node *node,
const char *name)
Expand Down Expand Up @@ -535,13 +735,17 @@ static void of_lpass_cpu_parse_dai_data(struct device *dev,
dev_err(dev, "valid dai id not found: %d\n", ret);
continue;
}

data->mi2s_playback_sd_mode[id] =
of_lpass_cpu_parse_sd_lines(dev, node,
"qcom,playback-sd-lines");
data->mi2s_capture_sd_mode[id] =
of_lpass_cpu_parse_sd_lines(dev, node,
if (id == LPASS_DP_RX) {
data->hdmi_port_enable = 1;
dev_err(dev, "HDMI Port is enabled: %d\n", id);
} else {
data->mi2s_playback_sd_mode[id] =
of_lpass_cpu_parse_sd_lines(dev, node,
"qcom,playback-sd-lines");
data->mi2s_capture_sd_mode[id] =
of_lpass_cpu_parse_sd_lines(dev, node,
"qcom,capture-sd-lines");
}
}
}

Expand Down Expand Up @@ -596,6 +800,27 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return PTR_ERR(drvdata->lpaif_map);
}

if (drvdata->hdmi_port_enable) {
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "lpass-hdmiif");

drvdata->hdmiif = devm_ioremap_resource(dev, res);
if (IS_ERR((void const __force *)drvdata->hdmiif)) {
dev_err(dev, "error mapping reg resource: %ld\n",
PTR_ERR((void const __force *)drvdata->hdmiif));
return PTR_ERR((void const __force *)drvdata->hdmiif);
}

lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant,
variant->hdmi_rdma_channels);
drvdata->hdmiif_map = devm_regmap_init_mmio(dev, drvdata->hdmiif,
&lpass_hdmi_regmap_config);
if (IS_ERR(drvdata->hdmiif_map)) {
dev_err(dev, "error initializing regmap: %ld\n",
PTR_ERR(drvdata->hdmiif_map));
return PTR_ERR(drvdata->hdmiif_map);
}
}

if (variant->init) {
ret = variant->init(pdev);
if (ret) {
Expand All @@ -606,6 +831,9 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)

for (i = 0; i < variant->num_dai; i++) {
dai_id = variant->dai_driver[i].id;
if (dai_id == LPASS_DP_RX)
continue;

drvdata->mi2s_osr_clk[dai_id] = devm_clk_get(dev,
variant->dai_osr_clk_names[i]);
if (IS_ERR(drvdata->mi2s_osr_clk[dai_id])) {
Expand Down Expand Up @@ -641,6 +869,13 @@ int asoc_qcom_lpass_cpu_platform_probe(struct platform_device *pdev)
return ret;
}

if (drvdata->hdmi_port_enable) {
ret = lpass_hdmi_init_bitfields(dev, drvdata->hdmiif_map);
if (ret) {
dev_err(dev, "%s error hdmi init failed\n", __func__);
return ret;
}
}
ret = devm_snd_soc_register_component(dev,
&lpass_cpu_comp_driver,
variant->dai_driver,
Expand Down
Loading

0 comments on commit 7cb37b7

Please sign in to comment.