From cd3484f7f1386071b1af159023917ed12c182d39 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Jan 2021 17:15:27 +0000 Subject: ASoC: qcom: Fix broken support to MI2S TERTIARY and QUATERNARY lpass hdmi support patch totally removed support for MI2S TERTIARY and QUATERNARY. One of the major issue was spotted with the design of having separate SoC specific header files for the common lpass driver. This design is prone to break as an when new SoC header is added as the common DAI ids of other SoCs will be overwritten by the new ones. Having a common header qcom,lpass.h should fix the issue and any new DAI ids should be added to the common header. With this change lpass also needs a new of_xlate function to resolve dai name. Fixes: 7cb37b7bd0d3 ("ASoC: qcom: Add support for lpass hdmi driver") Reported-by: Jun Nie Reported-by: Stephan Gerhold Tested-by: Srinivasa Rao Signed-off-by: Srinivas Kandagatla Tested-by: Stephan Gerhold Link: https://lore.kernel.org/r/20210119171527.32145-3-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-cpu.c | 22 ++++++++++++++++++++++ sound/soc/qcom/lpass-platform.c | 12 ++++++++++++ sound/soc/qcom/lpass-sc7180.c | 9 +++------ sound/soc/qcom/lpass.h | 2 +- 4 files changed, 38 insertions(+), 7 deletions(-) (limited to 'sound/soc/qcom') diff --git a/sound/soc/qcom/lpass-cpu.c b/sound/soc/qcom/lpass-cpu.c index c5e99c2d89c7..66b834312f33 100644 --- a/sound/soc/qcom/lpass-cpu.c +++ b/sound/soc/qcom/lpass-cpu.c @@ -344,8 +344,30 @@ int asoc_qcom_lpass_cpu_dai_probe(struct snd_soc_dai *dai) } EXPORT_SYMBOL_GPL(asoc_qcom_lpass_cpu_dai_probe); +static int asoc_qcom_of_xlate_dai_name(struct snd_soc_component *component, + struct of_phandle_args *args, + const char **dai_name) +{ + struct lpass_data *drvdata = snd_soc_component_get_drvdata(component); + struct lpass_variant *variant = drvdata->variant; + int id = args->args[0]; + int ret = -EINVAL; + int i; + + for (i = 0; i < variant->num_dai; i++) { + if (variant->dai_driver[i].id == id) { + *dai_name = variant->dai_driver[i].name; + ret = 0; + break; + } + } + + return ret; +} + static const struct snd_soc_component_driver lpass_cpu_comp_driver = { .name = "lpass-cpu", + .of_xlate_dai_name = asoc_qcom_of_xlate_dai_name, }; static bool lpass_cpu_regmap_writeable(struct device *dev, unsigned int reg) diff --git a/sound/soc/qcom/lpass-platform.c b/sound/soc/qcom/lpass-platform.c index d1c248590f3a..0074b7f2dbc1 100644 --- a/sound/soc/qcom/lpass-platform.c +++ b/sound/soc/qcom/lpass-platform.c @@ -257,6 +257,9 @@ static int lpass_platform_pcmops_hw_params(struct snd_soc_component *component, break; case MI2S_PRIMARY: case MI2S_SECONDARY: + case MI2S_TERTIARY: + case MI2S_QUATERNARY: + case MI2S_QUINARY: ret = regmap_fields_write(dmactl->intf, id, LPAIF_DMACTL_AUDINTF(dma_port)); if (ret) { @@ -507,6 +510,9 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, break; case MI2S_PRIMARY: case MI2S_SECONDARY: + case MI2S_TERTIARY: + case MI2S_QUATERNARY: + case MI2S_QUINARY: reg_irqclr = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST); val_irqclr = LPAIF_IRQ_ALL(ch); @@ -559,6 +565,9 @@ static int lpass_platform_pcmops_trigger(struct snd_soc_component *component, break; case MI2S_PRIMARY: case MI2S_SECONDARY: + case MI2S_TERTIARY: + case MI2S_QUATERNARY: + case MI2S_QUINARY: reg_irqen = LPAIF_IRQEN_REG(v, LPAIF_IRQ_PORT_HOST); val_mask = LPAIF_IRQ_ALL(ch); val_irqen = 0; @@ -655,6 +664,9 @@ static irqreturn_t lpass_dma_interrupt_handler( break; case MI2S_PRIMARY: case MI2S_SECONDARY: + case MI2S_TERTIARY: + case MI2S_QUATERNARY: + case MI2S_QUINARY: map = drvdata->lpaif_map; reg = LPAIF_IRQCLEAR_REG(v, LPAIF_IRQ_PORT_HOST); val = 0; diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 85db650c2169..8c168d3c589e 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -20,7 +20,7 @@ #include "lpass.h" static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { - [MI2S_PRIMARY] = { + { .id = MI2S_PRIMARY, .name = "Primary MI2S", .playback = { @@ -44,9 +44,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { }, .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, - }, - - [MI2S_SECONDARY] = { + }, { .id = MI2S_SECONDARY, .name = "Secondary MI2S", .playback = { @@ -60,8 +58,7 @@ static struct snd_soc_dai_driver sc7180_lpass_cpu_dai_driver[] = { }, .probe = &asoc_qcom_lpass_cpu_dai_probe, .ops = &asoc_qcom_lpass_cpu_dai_ops, - }, - [LPASS_DP_RX] = { + }, { .id = LPASS_DP_RX, .name = "Hdmi", .playback = { diff --git a/sound/soc/qcom/lpass.h b/sound/soc/qcom/lpass.h index 0195372905ed..2d68af0da34d 100644 --- a/sound/soc/qcom/lpass.h +++ b/sound/soc/qcom/lpass.h @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include "lpass-hdmi.h" #define LPASS_AHBIX_CLOCK_FREQUENCY 131072000 -- cgit v1.2.3 From 1e066a23e76f90c9c39c189fe0dbf7c6e3dd5044 Mon Sep 17 00:00:00 2001 From: Srinivas Kandagatla Date: Tue, 19 Jan 2021 17:47:00 +0000 Subject: ASoC: qcom: lpass-ipq806x: fix bitwidth regmap field BIT_WIDTH field in I2S_CTL register is two bits wide, however recent regmap field conversion patch trimmed it down to one bit. Fix this by correcting the bit range! Fixes: b5022a36d28f ("ASoC: qcom: lpass: Use regmap_field for i2sctl and dmactl registers") Signed-off-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210119174700.32639-1-srinivas.kandagatla@linaro.org Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-ipq806x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/qcom') diff --git a/sound/soc/qcom/lpass-ipq806x.c b/sound/soc/qcom/lpass-ipq806x.c index 92f98b4df47f..ef8a7984f232 100644 --- a/sound/soc/qcom/lpass-ipq806x.c +++ b/sound/soc/qcom/lpass-ipq806x.c @@ -131,7 +131,7 @@ static struct lpass_variant ipq806x_data = { .micmode = REG_FIELD_ID(0x0010, 4, 7, 5, 0x4), .micmono = REG_FIELD_ID(0x0010, 3, 3, 5, 0x4), .wssrc = REG_FIELD_ID(0x0010, 2, 2, 5, 0x4), - .bitwidth = REG_FIELD_ID(0x0010, 0, 0, 5, 0x4), + .bitwidth = REG_FIELD_ID(0x0010, 0, 1, 5, 0x4), .rdma_dyncclk = REG_FIELD_ID(0x6000, 12, 12, 4, 0x1000), .rdma_bursten = REG_FIELD_ID(0x6000, 11, 11, 4, 0x1000), -- cgit v1.2.3 From 7dfe20ee92f681ab1342015254ddb77a18f40cdb Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 15 Jan 2021 12:33:29 -0800 Subject: ASoC: qcom: Fix number of HDMI RDMA channels on sc7180 Suspending/resuming with an HDMI dongle attached leads to crashes from an audio regmap. Unable to handle kernel paging request at virtual address ffffffc018068000 Mem abort info: ESR = 0x96000047 EC = 0x25: DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 Data abort info: ISV = 0, ISS = 0x00000047 CM = 0, WnR = 1 swapper pgtable: 4k pages, 39-bit VAs, pgdp=0000000081b12000 [ffffffc018068000] pgd=0000000275d14003, pud=0000000275d14003, pmd=000000026365d003, pte=0000000000000000 Internal error: Oops: 96000047 [#1] PREEMPT SMP Call trace: regmap_mmio_write32le+0x2c/0x40 regmap_mmio_write+0x48/0x6c _regmap_bus_reg_write+0x34/0x44 _regmap_write+0x100/0x150 regcache_default_sync+0xc0/0x138 regcache_sync+0x188/0x26c lpass_platform_pcmops_resume+0x48/0x54 [snd_soc_lpass_platform] snd_soc_component_resume+0x28/0x40 soc_resume_deferred+0x6c/0x178 process_one_work+0x208/0x3c8 worker_thread+0x23c/0x3e8 kthread+0x144/0x178 ret_from_fork+0x10/0x18 Code: d503201f d50332bf f94002a8 8b344108 (b9000113) I can reliably reproduce this problem by running 'tail' on the registers file in debugfs for the hdmi regmap. # tail /sys/kernel/debug/regmap/62d87000.lpass-lpass_hdmi/registers [ 84.658733] Unable to handle kernel paging request at virtual address ffffffd0128e800c This crash happens because we're trying to read registers from the regmap beyond the length of the mapping created by ioremap(). The number of hdmi_rdma_channels determines the size of the regmap via this code in sound/soc/qcom/lpass-cpu.c: lpass_hdmi_regmap_config.max_register = LPAIF_HDMI_RDMAPER_REG(variant, variant->hdmi_rdma_channels); According to debugfs the size of the regmap is 0x68010 but according to the DTS file posted in [1] the size is only 0x68000 (see the first reg property of the lpass_cpu node). Let's change the number of channels to be 3 instead of 4 so the math works out to have a max register of 0x67010, nicely fitting inside of the region size of 0x68000. Note: I tried to bump up the size of the register region to the next page to include the 0x68010 register but then the tail command caused SErrors with an async abort, implying that the register region doesn't exist or it isn't clocked because the bus is telling us that the register read failed. I reduce the number of channels and played audio through the HDMI channel and it kept working so I think this is correct. Fixes: 2ad63dc8df6b ("ASoC: qcom: sc7180: Add support for audio over DP") Link: https://lore.kernel.org/r/1601448168-18396-2-git-send-email-srivasam@codeaurora.org [1] Cc: V Sujith Kumar Reddy Cc: Srinivasa Rao Cc: Srinivas Kandagatla Cc: Cheng-Yi Chiang Signed-off-by: Stephen Boyd Link: https://lore.kernel.org/r/20210115203329.846824-1-swboyd@chromium.org Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-sc7180.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/qcom') diff --git a/sound/soc/qcom/lpass-sc7180.c b/sound/soc/qcom/lpass-sc7180.c index 8c168d3c589e..735c9dac28f2 100644 --- a/sound/soc/qcom/lpass-sc7180.c +++ b/sound/soc/qcom/lpass-sc7180.c @@ -171,7 +171,7 @@ static struct lpass_variant sc7180_data = { .rdma_channels = 5, .hdmi_rdma_reg_base = 0x64000, .hdmi_rdma_reg_stride = 0x1000, - .hdmi_rdma_channels = 4, + .hdmi_rdma_channels = 3, .dmactl_audif_start = 1, .wrdma_reg_base = 0x18000, .wrdma_reg_stride = 0x1000, -- cgit v1.2.3 From 70041000450d0a071bf9931d634c8e2820340236 Mon Sep 17 00:00:00 2001 From: Stephan Gerhold Date: Mon, 25 Jan 2021 11:44:42 +0100 Subject: ASoC: qcom: lpass: Fix out-of-bounds DAI ID lookup The "dai_id" given into LPAIF_INTFDMA_REG(...) is already the real DAI ID, not an index into v->dai_driver. Looking it up again seems entirely redundant. For IPQ806x (and SC7180 since commit 09a4f6f5d21c ("ASoC: dt-bindings: lpass: Fix and common up lpass dai ids") this is now often an out-of-bounds read because the indexes in the "dai_driver" array no longer match the actual DAI ID. Cc: Srinivasa Rao Mandadapu Cc: Srinivas Kandagatla Fixes: 7cb37b7bd0d3 ("ASoC: qcom: Add support for lpass hdmi driver") Signed-off-by: Stephan Gerhold Reviewed-by: Srinivas Kandagatla Link: https://lore.kernel.org/r/20210125104442.135899-1-stephan@gerhold.net Signed-off-by: Mark Brown --- sound/soc/qcom/lpass-lpaif-reg.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sound/soc/qcom') diff --git a/sound/soc/qcom/lpass-lpaif-reg.h b/sound/soc/qcom/lpass-lpaif-reg.h index 405542832e99..baf72f124ea9 100644 --- a/sound/soc/qcom/lpass-lpaif-reg.h +++ b/sound/soc/qcom/lpass-lpaif-reg.h @@ -133,7 +133,7 @@ #define LPAIF_WRDMAPERCNT_REG(v, chan) LPAIF_WRDMA_REG_ADDR(v, 0x14, (chan)) #define LPAIF_INTFDMA_REG(v, chan, reg, dai_id) \ - ((v->dai_driver[dai_id].id == LPASS_DP_RX) ? \ + ((dai_id == LPASS_DP_RX) ? \ LPAIF_HDMI_RDMA##reg##_REG(v, chan) : \ LPAIF_RDMA##reg##_REG(v, chan)) -- cgit v1.2.3