From 8ca75efad82ff82b0c352f04f39db9b9c6e0ff8b Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 19 Feb 2019 16:19:41 +0100 Subject: [PATCH 01/16] ASoC: samsung: i2s: Fix multiple "IIS multi" devices initialization On some SoCs (e.g. Exynos5433) there are multiple "IIS multi audio interfaces" and the driver will try to register there multiple times same platform device for the secondary FIFO, which of course fails miserably. To fix this we derive the secondary platform device name from the primary device name. The secondary device name will now be -sec instead of fixed "samsung-i2s-sec". The fixed platform_device_id table entry is removed as the secondary device name is now dynamic and device/driver matching is done through driver_override. Change-Id: I49ed3e20279af198cdce11c08cc11bd6536dddad Reported-by: Marek Szyprowski Suggested-by: Marek Szyprowski Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- sound/soc/samsung/i2s.c | 50 ++++++++++++++++++++++++++++++---------------- sound/soc/samsung/odroid.c | 2 +- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index cd92bb6..4231001 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1339,20 +1339,35 @@ static int i2s_register_clock_provider(struct samsung_i2s_priv *priv) /* Create platform device for the secondary PCM */ static int i2s_create_secondary_device(struct samsung_i2s_priv *priv) { - struct platform_device *pdev; + struct platform_device *pdev_sec; + const char *devname; int ret; - pdev = platform_device_register_simple("samsung-i2s-sec", -1, NULL, 0); - if (!pdev) + devname = devm_kasprintf(&priv->pdev->dev, GFP_KERNEL, "%s-sec", + dev_name(&priv->pdev->dev)); + if (!devname) return -ENOMEM; - ret = device_attach(&pdev->dev); + pdev_sec = platform_device_alloc(devname, -1); + if (!pdev_sec) + return -ENOMEM; + + pdev_sec->driver_override = kstrdup("samsung-i2s", GFP_KERNEL); + + ret = platform_device_add(pdev_sec); if (ret < 0) { - dev_info(&pdev->dev, "device_attach() failed\n"); + platform_device_put(pdev_sec); return ret; } - priv->pdev_sec = pdev; + ret = device_attach(&pdev_sec->dev); + if (ret <= 0) { + platform_device_unregister(priv->pdev_sec); + dev_info(&pdev_sec->dev, "device_attach() failed\n"); + return ret; + } + + priv->pdev_sec = pdev_sec; return 0; } @@ -1367,22 +1382,25 @@ static int samsung_i2s_probe(struct platform_device *pdev) { struct i2s_dai *pri_dai, *sec_dai = NULL; struct s3c_audio_pdata *i2s_pdata = pdev->dev.platform_data; - struct resource *res; u32 regs_base, idma_addr = 0; struct device_node *np = pdev->dev.of_node; const struct samsung_i2s_dai_data *i2s_dai_data; - int num_dais, ret; + const struct platform_device_id *id; struct samsung_i2s_priv *priv; + struct resource *res; + int num_dais, ret; - if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) + if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) { i2s_dai_data = of_device_get_match_data(&pdev->dev); - else - i2s_dai_data = (struct samsung_i2s_dai_data *) - platform_get_device_id(pdev)->driver_data; + } else { + id = platform_get_device_id(pdev); - /* Nothing to do if it is the secondary device probe */ - if (!i2s_dai_data) - return 0; + /* Nothing to do if it is the secondary device probe */ + if (!id) + return 0; + + i2s_dai_data = (struct samsung_i2s_dai_data *)id->driver_data; + } priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) @@ -1637,8 +1655,6 @@ static const struct platform_device_id samsung_i2s_driver_ids[] = { { .name = "samsung-i2s", .driver_data = (kernel_ulong_t)&i2sv3_dai_type, - }, { - .name = "samsung-i2s-sec", }, {}, }; diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 5b2bcd1..bd2c516 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -185,7 +185,7 @@ static struct snd_soc_dai_link odroid_card_dais[] = { .ops = &odroid_card_fe_ops, .name = "Secondary", .stream_name = "Secondary", - .platform_name = "samsung-i2s-sec", + .platform_name = "3830000.i2s-sec", .dynamic = 1, .dpcm_playback = 1, } -- 2.7.4 From d78ff27418486a7462ea27f1ad5c86ca72556431 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 20 Feb 2019 12:06:07 +0100 Subject: [PATCH 02/16] ASoC: samsung: odroid: Fix of_node refcount unbalance In odroid_audio_probe() some OF nodes are left without reference count decrease after use. Fix it by ensuring required of_node_calls() are done before exiting probe. Change-Id: Ifbcb6294331acc59028e675d8ab1143394508d66 Reported-by: Takashi Iwai Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index bd2c516..c3b0f6c 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -257,27 +257,31 @@ static int odroid_audio_probe(struct platform_device *pdev) ret = of_parse_phandle_with_args(cpu, "sound-dai", "#sound-dai-cells", i, &args); if (ret < 0) - return ret; + break; if (!args.np) { dev_err(dev, "sound-dai property parse error: %d\n", ret); - return -EINVAL; + ret = -EINVAL; + break; } ret = snd_soc_get_dai_name(&args, &link->cpu_dai_name); of_node_put(args.np); if (ret < 0) - return ret; + break; } + if (ret == 0) + cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); - cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); of_node_put(cpu); of_node_put(codec); + if (ret < 0) + return ret; ret = snd_soc_of_get_dai_link_codecs(dev, codec, codec_link); if (ret < 0) - goto err_put_codec_n; + goto err_put_cpu_dai; /* Set capture capability only for boards with the MAX98090 CODEC */ if (codec_link->num_codecs > 1) { @@ -288,7 +292,7 @@ static int odroid_audio_probe(struct platform_device *pdev) priv->sclk_i2s = of_clk_get_by_name(cpu_dai, "i2s_opclk1"); if (IS_ERR(priv->sclk_i2s)) { ret = PTR_ERR(priv->sclk_i2s); - goto err_put_codec_n; + goto err_put_cpu_dai; } priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); @@ -310,7 +314,8 @@ err_put_clk_i2s: clk_put(priv->clk_i2s_bus); err_put_sclk: clk_put(priv->sclk_i2s); -err_put_codec_n: +err_put_cpu_dai: + of_node_put(cpu_dai); snd_soc_of_put_dai_link_codecs(codec_link); return ret; } -- 2.7.4 From 48e666b5772d8c5e9bc4423474cccc75270fec61 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 21 Feb 2019 10:42:28 +0100 Subject: [PATCH 03/16] ASoC: samsung: odroid: Prevent uninitialized variable use MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit This addresses an issue pointed out by compiler warning: sound/soc/samsung/odroid.c: In function ‘odroid_audio_probe’: sound/soc/samsung/odroid.c:298:22: warning: ‘cpu_dai’ may be used uninitialized in this function [-Wmaybe-uninitialized] priv->clk_i2s_bus = of_clk_get_by_name(cpu_dai, "iis"); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Change-Id: I39c6dd0a1aa5ec68bfc17c895988c21a1a34733e Signed-off-by: Sylwester Nawrocki Signed-off-by: Mark Brown --- sound/soc/samsung/odroid.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index c3b0f6c..694512f 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -194,7 +194,8 @@ static struct snd_soc_dai_link odroid_card_dais[] = { static int odroid_audio_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct device_node *cpu, *cpu_dai, *codec; + struct device_node *cpu_dai = NULL; + struct device_node *cpu, *codec; struct odroid_priv *priv; struct snd_soc_card *card; struct snd_soc_dai_link *link, *codec_link; @@ -271,8 +272,11 @@ static int odroid_audio_probe(struct platform_device *pdev) if (ret < 0) break; } - if (ret == 0) + if (ret == 0) { cpu_dai = of_parse_phandle(cpu, "sound-dai", 0); + if (!cpu_dai) + ret = -EINVAL; + } of_node_put(cpu); of_node_put(codec); -- 2.7.4 From 509991a0d84159f4ff7cbe0d00188156243fa9f2 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Thu, 14 Feb 2019 16:45:55 +0100 Subject: [PATCH 04/16] ASoC: dmaengine: Remove unused SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME flag There is now no users of this flag so remove it together with related code. The chan_name field of snd_dmaengine_dai_dma_data data structure is not removed as it is still in use by the PXA platform. Change-Id: Ia8bb6022ce7c5e85abb7c5410459130666785f45 Signed-off-by: Sylwester Nawrocki Acked-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- include/sound/dmaengine_pcm.h | 4 ---- sound/soc/soc-generic-dmaengine-pcm.c | 21 ++++----------------- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/include/sound/dmaengine_pcm.h b/include/sound/dmaengine_pcm.h index 67be244..3e43b89 100644 --- a/include/sound/dmaengine_pcm.h +++ b/include/sound/dmaengine_pcm.h @@ -107,10 +107,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data( * playback. */ #define SND_DMAENGINE_PCM_FLAG_HALF_DUPLEX BIT(3) -/* - * The PCM streams have custom channel names specified. - */ -#define SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME BIT(4) /** * struct snd_dmaengine_pcm_config - Configuration data for dmaengine based PCM diff --git a/sound/soc/soc-generic-dmaengine-pcm.c b/sound/soc/soc-generic-dmaengine-pcm.c index 06d4dfc..8a55d3f 100644 --- a/sound/soc/soc-generic-dmaengine-pcm.c +++ b/sound/soc/soc-generic-dmaengine-pcm.c @@ -263,7 +263,6 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) struct dmaengine_pcm *pcm = soc_platform_to_pcm(rtd->platform); const struct snd_dmaengine_pcm_config *config = pcm->config; struct device *dev = rtd->platform->dev; - struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; size_t prealloc_buffer_size; size_t max_buffer_size; @@ -283,19 +282,9 @@ static int dmaengine_pcm_new(struct snd_soc_pcm_runtime *rtd) if (!substream) continue; - dma_data = snd_soc_dai_get_dma_data(rtd->cpu_dai, substream); - - if (!pcm->chan[i] && - ((pcm->flags & SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME) || - (config && config->chan_names[i]))) { - const char *chan_name = dma_data->chan_name; - - if (config && config->chan_names[i]) - chan_name = config->chan_names[i]; - + if (!pcm->chan[i] && config && config->chan_names[i]) pcm->chan[i] = dma_request_slave_channel(dev, - chan_name); - } + config->chan_names[i]); if (!pcm->chan[i] && (pcm->flags & SND_DMAENGINE_PCM_FLAG_COMPAT)) { pcm->chan[i] = dmaengine_pcm_compat_request_channel(rtd, @@ -365,10 +354,8 @@ static int dmaengine_pcm_request_chan_of(struct dmaengine_pcm *pcm, const char *name; struct dma_chan *chan; - if ((pcm->flags & (SND_DMAENGINE_PCM_FLAG_NO_DT | - SND_DMAENGINE_PCM_FLAG_CUSTOM_CHANNEL_NAME)) || - (!dev->of_node && !(config && config->dma_dev && - config->dma_dev->of_node))) + if ((pcm->flags & SND_DMAENGINE_PCM_FLAG_NO_DT) || (!dev->of_node && + !(config && config->dma_dev && config->dma_dev->of_node))) return 0; if (config && config->dma_dev) { -- 2.7.4 From 132495eca68055477c61edc9a98bdbe526baa004 Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Wed, 27 Feb 2019 11:47:39 +0100 Subject: [PATCH 05/16] LOCAL: ASoC: temporary workaround for i2s/prepare_lock deadlock This reverts commit 00ffa8a3b1a60a89ab0ef5ae1d8e41269c30a3bd. Change-Id: I396b1250a748fdb8219abf6d0bf71c5fab119658 Signed-off-by: Marek Szyprowski --- sound/soc/samsung/i2s.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index 4231001..d3d250e 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -618,11 +618,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai, int clk_id, unsigned int rfs, writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(&priv->lock, flags); done: - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); return 0; err: - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); return ret; } @@ -706,7 +706,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) if (any_active(i2s) && ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) { spin_unlock_irqrestore(&priv->lock, flags); - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; @@ -716,7 +716,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) mod |= tmp; writel(mod, priv->addr + I2SMOD); spin_unlock_irqrestore(&priv->lock, flags); - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); return 0; } @@ -867,7 +867,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream, spin_unlock_irqrestore(&priv->pcm_lock, flags); - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); } static int config_setup(struct i2s_dai *i2s) @@ -973,7 +973,7 @@ static int i2s_trigger(struct snd_pcm_substream *substream, } spin_unlock_irqrestore(&priv->lock, flags); - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); break; } @@ -991,13 +991,13 @@ static int i2s_set_clkdiv(struct snd_soc_dai *dai, pm_runtime_get_sync(dai->dev); if ((any_active(i2s) && div && (get_bfs(i2s) != div)) || (other && other->bfs && (other->bfs != div))) { - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); dev_err(&i2s->pdev->dev, "%s:%d Other DAI busy\n", __func__, __LINE__); return -EAGAIN; } i2s->bfs = div; - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); break; default: dev_err(&i2s->pdev->dev, @@ -1083,7 +1083,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) if (!is_opened(other)) i2s_set_sysclk(dai, SAMSUNG_I2S_CDCLK, 0, SND_SOC_CLOCK_IN); - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); return 0; } @@ -1104,7 +1104,7 @@ static int samsung_i2s_dai_remove(struct snd_soc_dai *dai) } } - pm_runtime_put(dai->dev); + pm_runtime_put_sync(dai->dev); return 0; } -- 2.7.4 From f58933cc561a67de83fbe4e758907c9f6c9ae9d5 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:41 +0100 Subject: [PATCH 06/16] ARM: dts: exynos: Add support for secondary DAI to Odroid XU3 This patch extends DAPM routing and adds secondary CPU DAI entry to support the secondary audio PCM interface on Odroid XU3. Change-Id: I2efb8eca9418554482194a2c54aa6b6ca674d5c2 Signed-off-by: Sylwester Nawrocki Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi index fe4d8ef..15b1e9f 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi @@ -27,7 +27,9 @@ "Headphone Jack", "MICBIAS", "IN1", "Headphone Jack", "Speakers", "SPKL", - "Speakers", "SPKR"; + "Speakers", "SPKR", + "I2S Playback", "Mixer DAI TX", + "HiFi Playback", "Mixer DAI TX"; assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>, <&clock CLK_MOUT_EPLL>, @@ -57,7 +59,7 @@ <196608000>; cpu { - sound-dai = <&i2s0 0>; + sound-dai = <&i2s0 0>, <&i2s0 1>; }; codec { sound-dai = <&hdmi>, <&max98090>; -- 2.7.4 From ad7d7f298cd27d6d60d73604c27265813a027ce7 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Tue, 12 Feb 2019 19:03:42 +0100 Subject: [PATCH 07/16] ARM: dts: exynos: Add support for secondary DAI to Odroid XU4 This patch extends DAPM routing and adds secondary CPU DAI entry to support the secondary audio PCM interface on Odroid XU4. Change-Id: Id20d2a064f5d29c4edf349e9a968864a48a11b46 Signed-off-by: Sylwester Nawrocki Signed-off-by: Krzysztof Kozlowski --- arch/arm/boot/dts/exynos5422-odroidxu4.dts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/exynos5422-odroidxu4.dts b/arch/arm/boot/dts/exynos5422-odroidxu4.dts index f501f29..3f3e81f 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu4.dts +++ b/arch/arm/boot/dts/exynos5422-odroidxu4.dts @@ -36,6 +36,8 @@ compatible = "samsung,odroid-xu3-audio"; model = "Odroid-XU4"; + samsung,audio-routing = "I2S Playback", "Mixer DAI TX"; + assigned-clocks = <&clock CLK_MOUT_EPLL>, <&clock CLK_MOUT_MAU_EPLL>, <&clock CLK_MOUT_USER_MAU_EPLL>, @@ -61,7 +63,7 @@ <196608000>; cpu { - sound-dai = <&i2s0 0>; + sound-dai = <&i2s0 0>, <&i2s0 1>; }; codec { -- 2.7.4 From 974ab062962f5dbe62f8744257540a24cb9a8d74 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 4 Mar 2019 17:17:14 +0100 Subject: [PATCH 08/16] ASoC: samsung: i2s: Fix DAPM routes for capture stream This patch sets missing stream_name of capture part of the DAI driver so we can define DAPM routing properly also for the capture stream. Fixes: 64aba9bca5bd ("ASoC: samsung: i2s: Add widgets and routes for DPCM support") Change-Id: I7ac244afcd74d92cf92da1d9d7d9606285ea0360 Signed-off-by: Sylwester Nawrocki --- sound/soc/samsung/i2s.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c index d3d250e..23ff857 100644 --- a/sound/soc/samsung/i2s.c +++ b/sound/soc/samsung/i2s.c @@ -1134,7 +1134,7 @@ static const struct snd_soc_dapm_route samsung_i2s_dapm_routes[] = { { "Playback Mixer", NULL, "Secondary" }, { "Mixer DAI TX", NULL, "Playback Mixer" }, - { "Playback Mixer", NULL, "Mixer DAI RX" }, + { "Primary Capture", NULL, "Mixer DAI RX" }, }; static const struct snd_soc_component_driver samsung_i2s_component = { @@ -1201,6 +1201,7 @@ static int i2s_alloc_dais(struct samsung_i2s_priv *priv, dai_drv->capture.channels_max = 2; dai_drv->capture.rates = i2s_dai_data->pcm_rates; dai_drv->capture.formats = SAMSUNG_I2S_FMTS; + dai_drv->capture.stream_name = "Primary Capture"; return 0; } -- 2.7.4 From 7316ba0d62bb4f6ee663e8307ed2f352ffe24dec Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Mon, 4 Mar 2019 17:18:32 +0100 Subject: [PATCH 09/16] ARM: dts: exynos: Fix audio routing on exynos5422-odroidxu3 Add missing audio routing entry for the capture stream, this change is required to fix audio recording on Odroid XU3. Change-Id: I8db68ab3e097a0f3cfd07224016e4704e57c6635 Fixes: 885b005d232c ("ARM: dts: exynos: Add support for secondary DAI to Odroid XU3") Signed-off-by: Sylwester Nawrocki --- arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi index 15b1e9f..39a3bf9 100644 --- a/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi +++ b/arch/arm/boot/dts/exynos5422-odroidxu3-audio.dtsi @@ -29,7 +29,8 @@ "Speakers", "SPKL", "Speakers", "SPKR", "I2S Playback", "Mixer DAI TX", - "HiFi Playback", "Mixer DAI TX"; + "HiFi Playback", "Mixer DAI TX", + "Mixer DAI RX", "HiFi Capture"; assigned-clocks = <&i2s0 CLK_I2S_RCLK_SRC>, <&clock CLK_MOUT_EPLL>, -- 2.7.4 From f707903a809938ef09f4bcf6368e6cc83b2fc991 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 8 Mar 2019 16:36:38 +0100 Subject: [PATCH 10/16] ASoS: samsung: odroid: Fix clock configuration for 44100 sample rate After commit fbeec965b8d1c ("ASoC: samsung: odroid: Fix 32000 sample rate handling") due to clock rounding error CODEC master clock frequency is being set to 20070401 Hz instead of 22579000 Hz. This results in too fast actual sample rate for fs=44100, e.g. 2 kHz tone has really 3555 Hz frequency (2000 Hz * 20070401/22579000 * 2). Fix this by increasing correction passed to clk_set_rate() to take into account inaccuracy of EPLL frequency properly. Change-Id: I8d08bec8e70394421c115bde1d511b730885bbe2 Signed-off-by: Sylwester Nawrocki --- sound/soc/samsung/odroid.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 694512f..1dc54c4 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -91,11 +91,11 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, return ret; /* - * We add 1 to the rclk_freq value in order to avoid too low clock + * We add 2 to the rclk_freq value in order to avoid too low clock * frequency values due to the EPLL output frequency not being exact * multiple of the audio sampling rate. */ - rclk_freq = params_rate(params) * rfs + 1; + rclk_freq = params_rate(params) * rfs + 2; ret = clk_set_rate(priv->sclk_i2s, rclk_freq); if (ret < 0) -- 2.7.4 From acdb73fab61be9a387771c6a86d225db5d2d6300 Mon Sep 17 00:00:00 2001 From: Jaechul Lee Date: Fri, 8 Mar 2019 08:42:55 +0900 Subject: [PATCH 11/16] ASoC: samsung: odroid: Change rfs value to 256 rfs is set 256 as a default value in I2S module. Due to clock rate setting rounding errors with rfs=512 playback is almost twice faster than original speed when the device is opened with 44.1k samplerate. pulseaudio that uses 44.1k sinks can't play the sound properly. Change-Id: I21d5553e36dcbf00802230cf1c60f5fb7df1056d Signed-off-by: Jaechul Lee --- sound/soc/samsung/odroid.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sound/soc/samsung/odroid.c b/sound/soc/samsung/odroid.c index 1dc54c4..b61d866 100644 --- a/sound/soc/samsung/odroid.c +++ b/sound/soc/samsung/odroid.c @@ -74,13 +74,16 @@ static int odroid_card_be_hw_params(struct snd_pcm_substream *substream, case 44100: case 88200: pll_freq = 180633609U; - rfs = 512; + rfs = 256; break; case 32000: + pll_freq = 196608001U; + rfs = 512; + break; case 48000: case 96000: pll_freq = 196608001U; - rfs = 512; + rfs = 256; break; default: return -EINVAL; -- 2.7.4 From d0d37833d37e5f749eeffedadfa9662b6ed2d80a Mon Sep 17 00:00:00 2001 From: Marek Szyprowski Date: Tue, 19 Mar 2019 13:58:06 +0100 Subject: [PATCH 12/16] ARM: dts: exynos: Increase minimal ACLK400_DISP1 frequency on Exynos542x ACLK400_DISP1 bus feeds some internal buses of the display subsystem, some of which are also related to TV/Mixer hardware modules. When that bus is set to 120MHz, Exynos Mixer is not able to properly handle two XRGB display planes at FullHD-60MHz. DMA underrun happens, which in turn might result in reading data out of the configured buffer, what causes IOMMU page fault and kernel panic. This change fixes the following IOMMU fault, observed, when 2 Mixer planes were enabled: exynos-sysmmu 14650000.sysmmu: 14450000.mixer: PAGE FAULT occurred at 0x20fe9000 ------------[ cut here ]------------ kernel BUG at ../drivers/iommu/exynos-iommu.c:450! Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM Modules linked in: CPU: 5 PID: 0 Comm: swapper/5 Not tainted 5.0.0-00003-g1b03088168ea #149 Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) PC is at exynos_sysmmu_irq+0x1c0/0x264 LR is at lock_is_held_type+0x44/0x64 ... Reported-by: Marian Mihailescu Fixes: 5d99cc59a3c6 ("ARM: dts: exynos: Move Exynos5250 and Exynos5420 nodes under soc") Fixes: b04a62d3ade3 ("ARM: dts: exynos: Add bus nodes using VDD_INT for Exynos542x SoC") Signed-off-by: Marek Szyprowski Change-Id: I3d2f341f5e89d4631401f653d0ad9e36f26f45ad --- arch/arm/boot/dts/exynos5420.dtsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi index 5451c13..d490d22 100644 --- a/arch/arm/boot/dts/exynos5420.dtsi +++ b/arch/arm/boot/dts/exynos5420.dtsi @@ -1300,7 +1300,7 @@ compatible = "operating-points-v2"; opp00 { - opp-hz = /bits/ 64 <120000000>; + opp-hz = /bits/ 64 <150000000>; }; opp01 { opp-hz = /bits/ 64 <200000000>; -- 2.7.4 From 1d2108db4bdec55725b3217f06ac5138ea558b87 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Fri, 2 Feb 2018 16:11:22 +0100 Subject: [PATCH 13/16] drm/exynos/mixer: fix synchronization check in interlaced mode In case of interlace mode video processor registers and mixer config register must be check to ensure internal state is in sync with shadow registers. This patch fixes page-faults in interlaced mode. Signed-off-by: Andrzej Hajda Signed-off-by: Inki Dae [backport of mainline commit 2eced8e917b060587fc8ed46df41c364957a5050] Signed-off-by: Marek Szyprowski Change-Id: I8b09ed165101a7dcccd1d6e7338e0216a27f4481 --- drivers/gpu/drm/exynos/exynos_mixer.c | 10 ++++++++++ drivers/gpu/drm/exynos/regs-mixer.h | 1 + 2 files changed, 11 insertions(+) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index c31a3d2..94ba8cd 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -494,6 +494,7 @@ static void vp_video_buffer(struct mixer_context *ctx, spin_lock_irqsave(&ctx->reg_slock, flags); + vp_reg_write(ctx, VP_SHADOW_UPDATE, 1); /* interlace or progressive scan mode */ val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0); vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP); @@ -711,6 +712,15 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) /* interlace scan need to check shadow register */ if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) { + if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) && + vp_reg_read(ctx, VP_SHADOW_UPDATE)) + goto out; + + base = mixer_reg_read(ctx, MXR_CFG); + shadow = mixer_reg_read(ctx, MXR_CFG_S); + if (base != shadow) + goto out; + base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0)); shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0)); if (base != shadow) diff --git a/drivers/gpu/drm/exynos/regs-mixer.h b/drivers/gpu/drm/exynos/regs-mixer.h index c311f57..189cfa2 100644 --- a/drivers/gpu/drm/exynos/regs-mixer.h +++ b/drivers/gpu/drm/exynos/regs-mixer.h @@ -47,6 +47,7 @@ #define MXR_MO 0x0304 #define MXR_RESOLUTION 0x0310 +#define MXR_CFG_S 0x2004 #define MXR_GRAPHIC0_BASE_S 0x2024 #define MXR_GRAPHIC1_BASE_S 0x2044 -- 2.7.4 From bf75262d7163301a838c4d4f9e5c761c4aa2da46 Mon Sep 17 00:00:00 2001 From: Andrzej Hajda Date: Tue, 19 Mar 2019 14:05:11 +0100 Subject: [PATCH 14/16] drm/exynos/mixer: fix MIXER shadow registry synchronisation code MIXER on Exynos5 SoCs uses different synchronisation method than Exynos4 to update internal state (shadow registers). Apparently the driver implements it incorrectly. The rule should be as follows: - do not request updating registers until previous request was finished, ie. MXR_CFG_LAYER_UPDATE_COUNT must be 0. - before setting registers synchronisation on VSYNC should be turned off, ie. MXR_STATUS_SYNC_ENABLE should be reset, - after finishing MXR_STATUS_SYNC_ENABLE should be set again. The patch hopefully implements it correctly. Below sample kernel log from page fault caused by the bug: [ 25.670038] exynos-sysmmu 14650000.sysmmu: 14450000.mixer: PAGE FAULT occurred at 0x2247b800 [ 25.677888] ------------[ cut here ]------------ [ 25.682164] kernel BUG at ../drivers/iommu/exynos-iommu.c:450! [ 25.687971] Internal error: Oops - BUG: 0 [#1] PREEMPT SMP ARM [ 25.693778] Modules linked in: [ 25.696816] CPU: 5 PID: 1553 Comm: fb-release_test Not tainted 5.0.0-rc7-01157-g5f86b1566bdd #136 [ 25.705646] Hardware name: SAMSUNG EXYNOS (Flattened Device Tree) [ 25.711710] PC is at exynos_sysmmu_irq+0x1c0/0x264 [ 25.716470] LR is at lock_is_held_type+0x44/0x64 v2: added missing MXR_CFG_LAYER_UPDATE bit setting in mixer_enable_sync Reported-by: Marian Mihailescu Signed-off-by: Andrzej Hajda Change-Id: Idd49412e699350a7ea3a98ef7f925924e0ddf1ff --- drivers/gpu/drm/exynos/exynos_mixer.c | 110 ++++++++++++++++++++-------------- 1 file changed, 66 insertions(+), 44 deletions(-) diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c index 94ba8cd..5ed9f05 100644 --- a/drivers/gpu/drm/exynos/exynos_mixer.c +++ b/drivers/gpu/drm/exynos/exynos_mixer.c @@ -20,6 +20,7 @@ #include "regs-vp.h" #include +#include #include #include #include @@ -349,15 +350,62 @@ static void mixer_cfg_vp_blend(struct mixer_context *ctx) mixer_reg_write(ctx, MXR_VIDEO_CFG, val); } -static void mixer_vsync_set_update(struct mixer_context *ctx, bool enable) +static bool mixer_is_synced(struct mixer_context *ctx) { - /* block update on vsync */ - mixer_reg_writemask(ctx, MXR_STATUS, enable ? - MXR_STATUS_SYNC_ENABLE : 0, MXR_STATUS_SYNC_ENABLE); + u32 base, shadow; + if (ctx->mxr_ver == MXR_VER_16_0_33_0 || + ctx->mxr_ver == MXR_VER_128_0_0_184) + return !(mixer_reg_read(ctx, MXR_CFG) & + MXR_CFG_LAYER_UPDATE_COUNT_MASK); + + if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) && + vp_reg_read(ctx, VP_SHADOW_UPDATE)) + return false; + + base = mixer_reg_read(ctx, MXR_CFG); + shadow = mixer_reg_read(ctx, MXR_CFG_S); + if (base != shadow) + return false; + + base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0)); + shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0)); + if (base != shadow) + return false; + + base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1)); + shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1)); + if (base != shadow) + return false; + + return true; +} + +static int mixer_wait_for_sync(struct mixer_context *ctx) +{ + ktime_t timeout = ktime_add_us(ktime_get(), 100000); + + while (!mixer_is_synced(ctx)) { + usleep_range(1000, 2000); + if (ktime_compare(ktime_get(), timeout) > 0) + return -ETIMEDOUT; + } + return 0; +} + +static void mixer_disable_sync(struct mixer_context *ctx) +{ + mixer_reg_writemask(ctx, MXR_STATUS, 0, MXR_STATUS_SYNC_ENABLE); +} + +static void mixer_enable_sync(struct mixer_context *ctx) +{ + if (ctx->mxr_ver == MXR_VER_16_0_33_0 || + ctx->mxr_ver == MXR_VER_128_0_0_184) + mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); + mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SYNC_ENABLE); if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags)) - vp_reg_write(ctx, VP_SHADOW_UPDATE, enable ? - VP_SHADOW_UPDATE_ENABLE : 0); + vp_reg_write(ctx, VP_SHADOW_UPDATE, VP_SHADOW_UPDATE_ENABLE); } static void mixer_cfg_scan(struct mixer_context *ctx, int width, int height) @@ -494,7 +542,6 @@ static void vp_video_buffer(struct mixer_context *ctx, spin_lock_irqsave(&ctx->reg_slock, flags); - vp_reg_write(ctx, VP_SHADOW_UPDATE, 1); /* interlace or progressive scan mode */ val = (test_bit(MXR_BIT_INTERLACE, &ctx->flags) ? ~0 : 0); vp_reg_writemask(ctx, VP_MODE, val, VP_MODE_LINE_SKIP); @@ -547,11 +594,6 @@ static void vp_video_buffer(struct mixer_context *ctx, vp_regs_dump(ctx); } -static void mixer_layer_update(struct mixer_context *ctx) -{ - mixer_reg_writemask(ctx, MXR_CFG, ~0, MXR_CFG_LAYER_UPDATE); -} - static void mixer_graph_buffer(struct mixer_context *ctx, struct exynos_drm_plane *plane) { @@ -628,11 +670,6 @@ static void mixer_graph_buffer(struct mixer_context *ctx, mixer_cfg_layer(ctx, win, priority, true); mixer_cfg_gfx_blend(ctx, win, is_alpha_format(fb->format->format)); - /* layer update mandatory for mixer 16.0.33.0 */ - if (ctx->mxr_ver == MXR_VER_16_0_33_0 || - ctx->mxr_ver == MXR_VER_128_0_0_184) - mixer_layer_update(ctx); - spin_unlock_irqrestore(&ctx->reg_slock, flags); mixer_regs_dump(ctx); @@ -697,7 +734,7 @@ static void mixer_win_reset(struct mixer_context *ctx) static irqreturn_t mixer_irq_handler(int irq, void *arg) { struct mixer_context *ctx = arg; - u32 val, base, shadow; + u32 val; spin_lock(&ctx->reg_slock); @@ -711,26 +748,9 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg) val &= ~MXR_INT_STATUS_VSYNC; /* interlace scan need to check shadow register */ - if (test_bit(MXR_BIT_INTERLACE, &ctx->flags)) { - if (test_bit(MXR_BIT_VP_ENABLED, &ctx->flags) && - vp_reg_read(ctx, VP_SHADOW_UPDATE)) - goto out; - - base = mixer_reg_read(ctx, MXR_CFG); - shadow = mixer_reg_read(ctx, MXR_CFG_S); - if (base != shadow) - goto out; - - base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(0)); - shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(0)); - if (base != shadow) - goto out; - - base = mixer_reg_read(ctx, MXR_GRAPHIC_BASE(1)); - shadow = mixer_reg_read(ctx, MXR_GRAPHIC_BASE_S(1)); - if (base != shadow) - goto out; - } + if (test_bit(MXR_BIT_INTERLACE, &ctx->flags) + && !mixer_is_synced(ctx)) + goto out; drm_crtc_handle_vblank(&ctx->crtc->base); } @@ -907,12 +927,14 @@ static void mixer_disable_vblank(struct exynos_drm_crtc *crtc) static void mixer_atomic_begin(struct exynos_drm_crtc *crtc) { - struct mixer_context *mixer_ctx = crtc->ctx; + struct mixer_context *ctx = crtc->ctx; - if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) + if (!test_bit(MXR_BIT_POWERED, &ctx->flags)) return; - mixer_vsync_set_update(mixer_ctx, false); + if (mixer_wait_for_sync(ctx)) + dev_err(ctx->dev, "timeout waiting for VSYNC\n"); + mixer_disable_sync(ctx); } static void mixer_update_plane(struct exynos_drm_crtc *crtc, @@ -954,7 +976,7 @@ static void mixer_atomic_flush(struct exynos_drm_crtc *crtc) if (!test_bit(MXR_BIT_POWERED, &mixer_ctx->flags)) return; - mixer_vsync_set_update(mixer_ctx, true); + mixer_enable_sync(mixer_ctx); exynos_crtc_handle_event(crtc); } @@ -969,7 +991,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) exynos_drm_pipe_clk_enable(crtc, true); - mixer_vsync_set_update(ctx, false); + mixer_disable_sync(ctx); mixer_reg_writemask(ctx, MXR_STATUS, ~0, MXR_STATUS_SOFT_RESET); @@ -982,7 +1004,7 @@ static void mixer_enable(struct exynos_drm_crtc *crtc) mixer_commit(ctx); - mixer_vsync_set_update(ctx, true); + mixer_enable_sync(ctx); set_bit(MXR_BIT_POWERED, &ctx->flags); } -- 2.7.4 From 4625551527e673d59d74a2e0f0483ae85dcdb207 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Fri, 1 Mar 2019 16:30:16 +0100 Subject: [PATCH 15/16] soc: samsung: asv: Wait until OPP gets released before adding new one There is currently no check whether an OPP is actually removed before attempting to add an replacement OPP. In situations when and OPP is referenced when we try to remove it and it is not already removed at the time of return from the dev_pm_opp_remove() call subsequent dev_pm_opp_add() invocation will fail. To avoid that add a polling loop with timeout as a barrier before adding new OPP. This patch should also prevent related cpufreq core issues as indicated by logs as follows. exynos_asv_update_cpu_opp cpu4 opp5, freq: 2000 missing exynos5433_asv_opp_get_voltage: arm,cortex-a57: [6] freq: 1900, voltage: 1262500 -> 1187500 cpu cpu4: _opp_add: duplicate OPPs detected. Existing: freq: 1900000000, volt: 1262500, enabled: 1. New: freq: 1900000000, volt: 1187500, enabled: 1 exynos_asv_update_cpu_opp: Failed to add OPP 1900000000 Hz/1187500 uV for cpu4 (-17) cpu cpu4: dev_pm_opp_set_rate: failed to find OPP for freq 1900000000 (-34) exynos5433_asv_opp_get_voltage: arm,cortex-a57: [9] freq: 1600, voltage: 1137500 -> 1062500 cpufreq: __target_index: Failed to change cpu frequency: -34 Change-Id: Ibf6a568cabbd5380952d97f93d27ac59f1db125b Signed-off-by: Sylwester Nawrocki --- drivers/soc/samsung/exynos-asv.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c index f416e0f..611c374 100644 --- a/drivers/soc/samsung/exynos-asv.c +++ b/drivers/soc/samsung/exynos-asv.c @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,7 @@ int exynos_asv_update_cpu_opp(struct device *cpu) for (i = 0; i < subsys->dvfs_nr; i++) { unsigned int new_voltage; unsigned int voltage; + int timeout = 1000; int err; opp_freq = subsys->asv_table[i][0]; @@ -66,6 +68,14 @@ int exynos_asv_update_cpu_opp(struct device *cpu) opp_freq *= MHZ; dev_pm_opp_remove(cpu, opp_freq); + while (--timeout) { + opp = dev_pm_opp_find_freq_exact(cpu, opp_freq, true); + if (IS_ERR(opp)) + break; + dev_pm_opp_put(opp); + msleep(1); + } + err = dev_pm_opp_add(cpu, opp_freq, new_voltage); if (err < 0) pr_err("%s: Failed to add OPP %u Hz/%u uV for cpu%d\n", -- 2.7.4 From d20edbc85ae24e9ec178370a4983e65ef7d83e02 Mon Sep 17 00:00:00 2001 From: Sylwester Nawrocki Date: Wed, 30 Jan 2019 18:17:23 +0100 Subject: [PATCH 16/16] soc: samsung: asv: Print error code when adding an OPP fails Log error code from devm_pm_opp_add() to make any errors easier to debug. Change-Id: If418320565f1efc14d16242d8b166bea07353c54 Signed-off-by: Sylwester Nawrocki --- drivers/soc/samsung/exynos-asv.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/soc/samsung/exynos-asv.c b/drivers/soc/samsung/exynos-asv.c index 611c374..71fa32f 100644 --- a/drivers/soc/samsung/exynos-asv.c +++ b/drivers/soc/samsung/exynos-asv.c @@ -78,8 +78,8 @@ int exynos_asv_update_cpu_opp(struct device *cpu) err = dev_pm_opp_add(cpu, opp_freq, new_voltage); if (err < 0) - pr_err("%s: Failed to add OPP %u Hz/%u uV for cpu%d\n", - __func__, opp_freq, new_voltage, cpu->id); + pr_err("%s: Failed to add OPP %u Hz/%u uV for cpu%d (%d)\n", + __func__, opp_freq, new_voltage, cpu->id, err); } return 0; -- 2.7.4