2021-01-12 13:10:21

by Dmitry Osipenko

[permalink] [raw]
Subject: [PATCH v1 0/5] Clock and reset improvements for Tegra ALSA drivers

This series improves the handling of clock and reset controls of
NVIDA Tegra ALSA drivers. Tegra HDA and AHUB drivers aren't handling
resets properly, which needs to be fixed in order to unblock other patches
related to fixes on the reset controller driver since HDA/AHUB are bound
to fail once reset controller driver will be corrected. In particular ALSA
drivers are relying on implicit de-assertion of resets which is done by the
tegra-clk driver. It's not the business of the clk driver to touch resets
and we need to fix this because it breaks reset/clk programming sequences
of other Tegra drivers.

Dmitry Osipenko (5):
ALSA: hda/tegra: Use clk_bulk helpers
ALSA: hda/tegra: Reset hardware
ASoC: tegra: ahub: Use of_reset_control_array_get_exclusive()
ASoC: tegra: ahub: Use clk_bulk helpers
ASoC: tegra: ahub: Reset hardware properly

sound/pci/hda/hda_tegra.c | 86 +++++++++------------------
sound/soc/tegra/tegra30_ahub.c | 103 ++++++---------------------------
sound/soc/tegra/tegra30_ahub.h | 6 +-
3 files changed, 49 insertions(+), 146 deletions(-)

--
2.29.2


2021-01-12 13:10:34

by Dmitry Osipenko

[permalink] [raw]
Subject: [PATCH v1 1/5] ALSA: hda/tegra: Use clk_bulk helpers

Use clk_bulk helpers to make code cleaner.

Tested-by: Peter Geis <[email protected]>
Tested-by: Nicolas Chauvet <[email protected]>
Signed-off-by: Dmitry Osipenko <[email protected]>
---
sound/pci/hda/hda_tegra.c | 68 ++++++---------------------------------
1 file changed, 9 insertions(+), 59 deletions(-)

diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
index 70164d1428d4..4c799661c2f6 100644
--- a/sound/pci/hda/hda_tegra.c
+++ b/sound/pci/hda/hda_tegra.c
@@ -70,9 +70,8 @@
struct hda_tegra {
struct azx chip;
struct device *dev;
- struct clk *hda_clk;
- struct clk *hda2codec_2x_clk;
- struct clk *hda2hdmi_clk;
+ struct clk_bulk_data clocks[3];
+ unsigned int nclocks;
void __iomem *regs;
struct work_struct probe_work;
};
@@ -113,36 +112,6 @@ static void hda_tegra_init(struct hda_tegra *hda)
writel(v, hda->regs + HDA_IPFS_INTR_MASK);
}

-static int hda_tegra_enable_clocks(struct hda_tegra *data)
-{
- int rc;
-
- rc = clk_prepare_enable(data->hda_clk);
- if (rc)
- return rc;
- rc = clk_prepare_enable(data->hda2codec_2x_clk);
- if (rc)
- goto disable_hda;
- rc = clk_prepare_enable(data->hda2hdmi_clk);
- if (rc)
- goto disable_codec_2x;
-
- return 0;
-
-disable_codec_2x:
- clk_disable_unprepare(data->hda2codec_2x_clk);
-disable_hda:
- clk_disable_unprepare(data->hda_clk);
- return rc;
-}
-
-static void hda_tegra_disable_clocks(struct hda_tegra *data)
-{
- clk_disable_unprepare(data->hda2hdmi_clk);
- clk_disable_unprepare(data->hda2codec_2x_clk);
- clk_disable_unprepare(data->hda_clk);
-}
-
/*
* power management
*/
@@ -186,7 +155,7 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
azx_stop_chip(chip);
azx_enter_link_reset(chip);
}
- hda_tegra_disable_clocks(hda);
+ clk_bulk_disable_unprepare(hda->nclocks, hda->clocks);

return 0;
}
@@ -198,7 +167,7 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
int rc;

- rc = hda_tegra_enable_clocks(hda);
+ rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks);
if (rc != 0)
return rc;
if (chip && chip->running) {
@@ -268,29 +237,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
return 0;
}

-static int hda_tegra_init_clk(struct hda_tegra *hda)
-{
- struct device *dev = hda->dev;
-
- hda->hda_clk = devm_clk_get(dev, "hda");
- if (IS_ERR(hda->hda_clk)) {
- dev_err(dev, "failed to get hda clock\n");
- return PTR_ERR(hda->hda_clk);
- }
- hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x");
- if (IS_ERR(hda->hda2codec_2x_clk)) {
- dev_err(dev, "failed to get hda2codec_2x clock\n");
- return PTR_ERR(hda->hda2codec_2x_clk);
- }
- hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi");
- if (IS_ERR(hda->hda2hdmi_clk)) {
- dev_err(dev, "failed to get hda2hdmi clock\n");
- return PTR_ERR(hda->hda2hdmi_clk);
- }
-
- return 0;
-}
-
static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
{
struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
@@ -495,7 +441,11 @@ static int hda_tegra_probe(struct platform_device *pdev)
return err;
}

- err = hda_tegra_init_clk(hda);
+ hda->clocks[hda->nclocks++].id = "hda";
+ hda->clocks[hda->nclocks++].id = "hda2hdmi";
+ hda->clocks[hda->nclocks++].id = "hda2codec_2x";
+
+ err = devm_clk_bulk_get(&pdev->dev, hda->nclocks, hda->clocks);
if (err < 0)
goto out_free;

--
2.29.2

2021-01-12 13:12:33

by Dmitry Osipenko

[permalink] [raw]
Subject: [PATCH v1 5/5] ASoC: tegra: ahub: Reset hardware properly

Assert hardware reset before clocks are enabled and then de-assert it
after clocks are enabled. This brings hardware into a predictable state
and removes relying on implicit de-assertion of resets which is done by
the clk driver.

Tested-by: Peter Geis <[email protected]>
Tested-by: Nicolas Chauvet <[email protected]>
Signed-off-by: Dmitry Osipenko <[email protected]>
---
sound/soc/tegra/tegra30_ahub.c | 33 ++++++++++++++++-----------------
sound/soc/tegra/tegra30_ahub.h | 1 +
2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 4dbb58f7ea36..246cf6a373a1 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -65,10 +65,20 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
{
int ret;

+ ret = reset_control_assert(ahub->reset);
+ if (ret)
+ return ret;
+
ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
if (ret)
return ret;

+ ret = reset_control_reset(ahub->reset);
+ if (ret) {
+ clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
+ return ret;
+ }
+
regcache_cache_only(ahub->regmap_apbif, false);
regcache_cache_only(ahub->regmap_ahub, false);

@@ -462,7 +472,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
const struct tegra30_ahub_soc_data *soc_data;
- struct reset_control *rst;
struct resource *res0;
void __iomem *regs_apbif, *regs_ahub;
int ret = 0;
@@ -475,22 +484,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
return -EINVAL;
soc_data = match->data;

- /*
- * The AHUB hosts a register bus: the "configlink". For this to
- * operate correctly, all devices on this bus must be out of reset.
- * Ensure that here.
- */
- rst = of_reset_control_array_get_exclusive(pdev->dev.of_node);
- if (IS_ERR(rst)) {
- dev_err(&pdev->dev, "Can't get reset: %p\n", rst);
- return PTR_ERR(rst);
- }
-
- ret = reset_control_deassert(rst);
- reset_control_put(rst);
- if (ret)
- return ret;
-
ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
GFP_KERNEL);
if (!ahub)
@@ -507,6 +500,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
if (ret)
return ret;

+ ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
+ if (IS_ERR(ahub->reset)) {
+ dev_err(&pdev->dev, "Can't get reset: %p\n", ahub->reset);
+ return PTR_ERR(ahub->reset);
+ }
+
res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs_apbif = devm_ioremap_resource(&pdev->dev, res0);
if (IS_ERR(regs_apbif))
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 063aed5037d7..ceb056575e98 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -510,6 +510,7 @@ struct tegra30_ahub_soc_data {
struct tegra30_ahub {
const struct tegra30_ahub_soc_data *soc_data;
struct device *dev;
+ struct reset_control *reset;
struct clk_bulk_data clocks[2];
unsigned int nclocks;
resource_size_t apbif_addr;
--
2.29.2

2021-01-13 01:40:18

by Dmitry Osipenko

[permalink] [raw]
Subject: [PATCH v1 4/5] ASoC: tegra: ahub: Use clk_bulk helpers

Use clk_bulk helpers to make code cleaner.

Tested-by: Peter Geis <[email protected]>
Tested-by: Nicolas Chauvet <[email protected]>
Signed-off-by: Dmitry Osipenko <[email protected]>
---
sound/soc/tegra/tegra30_ahub.c | 30 +++++++-----------------------
sound/soc/tegra/tegra30_ahub.h | 4 ++--
2 files changed, 9 insertions(+), 25 deletions(-)

diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
index 1e9767c75b11..4dbb58f7ea36 100644
--- a/sound/soc/tegra/tegra30_ahub.c
+++ b/sound/soc/tegra/tegra30_ahub.c
@@ -45,8 +45,7 @@ static int tegra30_ahub_runtime_suspend(struct device *dev)
regcache_cache_only(ahub->regmap_apbif, true);
regcache_cache_only(ahub->regmap_ahub, true);

- clk_disable_unprepare(ahub->clk_apbif);
- clk_disable_unprepare(ahub->clk_d_audio);
+ clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);

return 0;
}
@@ -66,17 +65,9 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
{
int ret;

- ret = clk_prepare_enable(ahub->clk_d_audio);
- if (ret) {
- dev_err(dev, "clk_enable d_audio failed: %d\n", ret);
- return ret;
- }
- ret = clk_prepare_enable(ahub->clk_apbif);
- if (ret) {
- dev_err(dev, "clk_enable apbif failed: %d\n", ret);
- clk_disable(ahub->clk_d_audio);
+ ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
+ if (ret)
return ret;
- }

regcache_cache_only(ahub->regmap_apbif, false);
regcache_cache_only(ahub->regmap_ahub, false);
@@ -509,19 +500,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
ahub->soc_data = soc_data;
ahub->dev = &pdev->dev;

- ahub->clk_d_audio = devm_clk_get(&pdev->dev, "d_audio");
- if (IS_ERR(ahub->clk_d_audio)) {
- dev_err(&pdev->dev, "Can't retrieve ahub d_audio clock\n");
- ret = PTR_ERR(ahub->clk_d_audio);
- return ret;
- }
+ ahub->clocks[ahub->nclocks++].id = "apbif";
+ ahub->clocks[ahub->nclocks++].id = "d_audio";

- ahub->clk_apbif = devm_clk_get(&pdev->dev, "apbif");
- if (IS_ERR(ahub->clk_apbif)) {
- dev_err(&pdev->dev, "Can't retrieve ahub apbif clock\n");
- ret = PTR_ERR(ahub->clk_apbif);
+ ret = devm_clk_bulk_get(&pdev->dev, ahub->nclocks, ahub->clocks);
+ if (ret)
return ret;
- }

res0 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
regs_apbif = devm_ioremap_resource(&pdev->dev, res0);
diff --git a/sound/soc/tegra/tegra30_ahub.h b/sound/soc/tegra/tegra30_ahub.h
index 5a2500b4ea06..063aed5037d7 100644
--- a/sound/soc/tegra/tegra30_ahub.h
+++ b/sound/soc/tegra/tegra30_ahub.h
@@ -510,8 +510,8 @@ struct tegra30_ahub_soc_data {
struct tegra30_ahub {
const struct tegra30_ahub_soc_data *soc_data;
struct device *dev;
- struct clk *clk_d_audio;
- struct clk *clk_apbif;
+ struct clk_bulk_data clocks[2];
+ unsigned int nclocks;
resource_size_t apbif_addr;
struct regmap *regmap_apbif;
struct regmap *regmap_ahub;
--
2.29.2

2021-01-15 10:20:36

by Takashi Iwai

[permalink] [raw]
Subject: Re: [PATCH v1 0/5] Clock and reset improvements for Tegra ALSA drivers

On Tue, 12 Jan 2021 13:58:29 +0100,
Dmitry Osipenko wrote:
>
> This series improves the handling of clock and reset controls of
> NVIDA Tegra ALSA drivers. Tegra HDA and AHUB drivers aren't handling
> resets properly, which needs to be fixed in order to unblock other patches
> related to fixes on the reset controller driver since HDA/AHUB are bound
> to fail once reset controller driver will be corrected. In particular ALSA
> drivers are relying on implicit de-assertion of resets which is done by the
> tegra-clk driver. It's not the business of the clk driver to touch resets
> and we need to fix this because it breaks reset/clk programming sequences
> of other Tegra drivers.
>
> Dmitry Osipenko (5):
> ALSA: hda/tegra: Use clk_bulk helpers
> ALSA: hda/tegra: Reset hardware
> ASoC: tegra: ahub: Use of_reset_control_array_get_exclusive()
> ASoC: tegra: ahub: Use clk_bulk helpers
> ASoC: tegra: ahub: Reset hardware properly

Thierry, Jonathan, Sameer, could you guys check those please?


thanks,

Takashi

>
> sound/pci/hda/hda_tegra.c | 86 +++++++++------------------
> sound/soc/tegra/tegra30_ahub.c | 103 ++++++---------------------------
> sound/soc/tegra/tegra30_ahub.h | 6 +-
> 3 files changed, 49 insertions(+), 146 deletions(-)
>
> --
> 2.29.2
>

2021-01-15 11:25:27

by Ben Dooks

[permalink] [raw]
Subject: Re: [PATCH v1 0/5] Clock and reset improvements for Tegra ALSA drivers

On 12/01/2021 12:58, Dmitry Osipenko wrote:
> This series improves the handling of clock and reset controls of
> NVIDA Tegra ALSA drivers. Tegra HDA and AHUB drivers aren't handling
> resets properly, which needs to be fixed in order to unblock other patches
> related to fixes on the reset controller driver since HDA/AHUB are bound
> to fail once reset controller driver will be corrected. In particular ALSA
> drivers are relying on implicit de-assertion of resets which is done by the
> tegra-clk driver. It's not the business of the clk driver to touch resets
> and we need to fix this because it breaks reset/clk programming sequences
> of other Tegra drivers.
>
> Dmitry Osipenko (5):
> ALSA: hda/tegra: Use clk_bulk helpers
> ALSA: hda/tegra: Reset hardware
> ASoC: tegra: ahub: Use of_reset_control_array_get_exclusive()
> ASoC: tegra: ahub: Use clk_bulk helpers
> ASoC: tegra: ahub: Reset hardware properly
>
> sound/pci/hda/hda_tegra.c | 86 +++++++++------------------
> sound/soc/tegra/tegra30_ahub.c | 103 ++++++---------------------------
> sound/soc/tegra/tegra30_ahub.h | 6 +-
> 3 files changed, 49 insertions(+), 146 deletions(-)

I wonder if this will help with the issues we saw when the tegra is
the i2s clock slave.


--
Ben Dooks http://www.codethink.co.uk/
Senior Engineer Codethink - Providing Genius

https://www.codethink.co.uk/privacy.html

2021-01-15 13:00:43

by Dmitry Osipenko

[permalink] [raw]
Subject: Re: [PATCH v1 0/5] Clock and reset improvements for Tegra ALSA drivers

15.01.2021 13:52, Ben Dooks пишет:
> On 12/01/2021 12:58, Dmitry Osipenko wrote:
>> This series improves the handling of clock and reset controls of
>> NVIDA Tegra ALSA drivers. Tegra HDA and AHUB drivers aren't handling
>> resets properly, which needs to be fixed in order to unblock other
>> patches
>> related to fixes on the reset controller driver since HDA/AHUB are bound
>> to fail once reset controller driver will be corrected. In particular
>> ALSA
>> drivers are relying on implicit de-assertion of resets which is done
>> by the
>> tegra-clk driver. It's not the business of the clk driver to touch resets
>> and we need to fix this because it breaks reset/clk programming sequences
>> of other Tegra drivers.
>>
>> Dmitry Osipenko (5):
>>    ALSA: hda/tegra: Use clk_bulk helpers
>>    ALSA: hda/tegra: Reset hardware
>>    ASoC: tegra: ahub: Use of_reset_control_array_get_exclusive()
>>    ASoC: tegra: ahub: Use clk_bulk helpers
>>    ASoC: tegra: ahub: Reset hardware properly
>>
>>   sound/pci/hda/hda_tegra.c      |  86 +++++++++------------------
>>   sound/soc/tegra/tegra30_ahub.c | 103 ++++++---------------------------
>>   sound/soc/tegra/tegra30_ahub.h |   6 +-
>>   3 files changed, 49 insertions(+), 146 deletions(-)
>
> I wonder if this will help with the issues we saw when the tegra is
> the i2s clock slave.

Probably no, this series shouldn't fix any of the current problems. I
will be surprised if it does.

2021-01-15 13:04:59

by Dmitry Osipenko

[permalink] [raw]
Subject: Re: [PATCH v1 5/5] ASoC: tegra: ahub: Reset hardware properly

12.01.2021 15:58, Dmitry Osipenko пишет:
> Assert hardware reset before clocks are enabled and then de-assert it
> after clocks are enabled. This brings hardware into a predictable state
> and removes relying on implicit de-assertion of resets which is done by
> the clk driver.
>
> Tested-by: Peter Geis <[email protected]>
> Tested-by: Nicolas Chauvet <[email protected]>
> Signed-off-by: Dmitry Osipenko <[email protected]>
> ---
> sound/soc/tegra/tegra30_ahub.c | 33 ++++++++++++++++-----------------
> sound/soc/tegra/tegra30_ahub.h | 1 +
> 2 files changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
> index 4dbb58f7ea36..246cf6a373a1 100644
> --- a/sound/soc/tegra/tegra30_ahub.c
> +++ b/sound/soc/tegra/tegra30_ahub.c
> @@ -65,10 +65,20 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
> {
> int ret;
>
> + ret = reset_control_assert(ahub->reset);
> + if (ret)
> + return ret;
> +
> ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
> if (ret)
> return ret;
>
> + ret = reset_control_reset(ahub->reset);
> + if (ret) {
> + clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
> + return ret;
> + }
> +
> regcache_cache_only(ahub->regmap_apbif, false);
> regcache_cache_only(ahub->regmap_ahub, false);

I just realized that this is incorrect version of the patch which misses
the regcache syncing after the h/w reset. I'll make a v2.

2021-01-15 15:24:38

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v1 1/5] ALSA: hda/tegra: Use clk_bulk helpers

On Tue, Jan 12, 2021 at 03:58:30PM +0300, Dmitry Osipenko wrote:
> Use clk_bulk helpers to make code cleaner.
>
> Tested-by: Peter Geis <[email protected]>
> Tested-by: Nicolas Chauvet <[email protected]>
> Signed-off-by: Dmitry Osipenko <[email protected]>
> ---
> sound/pci/hda/hda_tegra.c | 68 ++++++---------------------------------
> 1 file changed, 9 insertions(+), 59 deletions(-)

Heh... I have a branch samewhere with this same patch. Glad I can cross
that off my list. One thing jumped out at me, see below.

> diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c
> index 70164d1428d4..4c799661c2f6 100644
> --- a/sound/pci/hda/hda_tegra.c
> +++ b/sound/pci/hda/hda_tegra.c
> @@ -70,9 +70,8 @@
> struct hda_tegra {
> struct azx chip;
> struct device *dev;
> - struct clk *hda_clk;
> - struct clk *hda2codec_2x_clk;
> - struct clk *hda2hdmi_clk;
> + struct clk_bulk_data clocks[3];
> + unsigned int nclocks;
> void __iomem *regs;
> struct work_struct probe_work;
> };
> @@ -113,36 +112,6 @@ static void hda_tegra_init(struct hda_tegra *hda)
> writel(v, hda->regs + HDA_IPFS_INTR_MASK);
> }
>
> -static int hda_tegra_enable_clocks(struct hda_tegra *data)
> -{
> - int rc;
> -
> - rc = clk_prepare_enable(data->hda_clk);
> - if (rc)
> - return rc;
> - rc = clk_prepare_enable(data->hda2codec_2x_clk);
> - if (rc)
> - goto disable_hda;
> - rc = clk_prepare_enable(data->hda2hdmi_clk);
> - if (rc)
> - goto disable_codec_2x;
> -
> - return 0;
> -
> -disable_codec_2x:
> - clk_disable_unprepare(data->hda2codec_2x_clk);
> -disable_hda:
> - clk_disable_unprepare(data->hda_clk);
> - return rc;
> -}
> -
> -static void hda_tegra_disable_clocks(struct hda_tegra *data)
> -{
> - clk_disable_unprepare(data->hda2hdmi_clk);
> - clk_disable_unprepare(data->hda2codec_2x_clk);
> - clk_disable_unprepare(data->hda_clk);
> -}
> -
> /*
> * power management
> */
> @@ -186,7 +155,7 @@ static int __maybe_unused hda_tegra_runtime_suspend(struct device *dev)
> azx_stop_chip(chip);
> azx_enter_link_reset(chip);
> }
> - hda_tegra_disable_clocks(hda);
> + clk_bulk_disable_unprepare(hda->nclocks, hda->clocks);
>
> return 0;
> }
> @@ -198,7 +167,7 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev)
> struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
> int rc;
>
> - rc = hda_tegra_enable_clocks(hda);
> + rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks);
> if (rc != 0)
> return rc;
> if (chip && chip->running) {
> @@ -268,29 +237,6 @@ static int hda_tegra_init_chip(struct azx *chip, struct platform_device *pdev)
> return 0;
> }
>
> -static int hda_tegra_init_clk(struct hda_tegra *hda)
> -{
> - struct device *dev = hda->dev;
> -
> - hda->hda_clk = devm_clk_get(dev, "hda");
> - if (IS_ERR(hda->hda_clk)) {
> - dev_err(dev, "failed to get hda clock\n");
> - return PTR_ERR(hda->hda_clk);
> - }
> - hda->hda2codec_2x_clk = devm_clk_get(dev, "hda2codec_2x");
> - if (IS_ERR(hda->hda2codec_2x_clk)) {
> - dev_err(dev, "failed to get hda2codec_2x clock\n");
> - return PTR_ERR(hda->hda2codec_2x_clk);
> - }
> - hda->hda2hdmi_clk = devm_clk_get(dev, "hda2hdmi");
> - if (IS_ERR(hda->hda2hdmi_clk)) {
> - dev_err(dev, "failed to get hda2hdmi clock\n");
> - return PTR_ERR(hda->hda2hdmi_clk);
> - }
> -
> - return 0;
> -}
> -
> static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
> {
> struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
> @@ -495,7 +441,11 @@ static int hda_tegra_probe(struct platform_device *pdev)
> return err;
> }
>
> - err = hda_tegra_init_clk(hda);
> + hda->clocks[hda->nclocks++].id = "hda";
> + hda->clocks[hda->nclocks++].id = "hda2hdmi";
> + hda->clocks[hda->nclocks++].id = "hda2codec_2x";

Originally the code did this in this order: "hda", "hda2codec_2x" and
"hda2hdmi". I don't expect the exact order to be very relevant, but was
there any particular reason to change it?

In either case, this should be fine:

Acked-by: Thierry Reding <[email protected]>


Attachments:
(No filename) (4.09 kB)
signature.asc (849.00 B)
Download all attachments

2021-01-15 15:40:48

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v1 4/5] ASoC: tegra: ahub: Use clk_bulk helpers

On Tue, Jan 12, 2021 at 03:58:33PM +0300, Dmitry Osipenko wrote:
> Use clk_bulk helpers to make code cleaner.
>
> Tested-by: Peter Geis <[email protected]>
> Tested-by: Nicolas Chauvet <[email protected]>
> Signed-off-by: Dmitry Osipenko <[email protected]>
> ---
> sound/soc/tegra/tegra30_ahub.c | 30 +++++++-----------------------
> sound/soc/tegra/tegra30_ahub.h | 4 ++--
> 2 files changed, 9 insertions(+), 25 deletions(-)

Acked-by: Thierry Reding <[email protected]>


Attachments:
(No filename) (492.00 B)
signature.asc (849.00 B)
Download all attachments

2021-01-15 15:46:57

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v1 5/5] ASoC: tegra: ahub: Reset hardware properly

On Tue, Jan 12, 2021 at 03:58:34PM +0300, Dmitry Osipenko wrote:
> Assert hardware reset before clocks are enabled and then de-assert it
> after clocks are enabled. This brings hardware into a predictable state
> and removes relying on implicit de-assertion of resets which is done by
> the clk driver.
>
> Tested-by: Peter Geis <[email protected]>
> Tested-by: Nicolas Chauvet <[email protected]>
> Signed-off-by: Dmitry Osipenko <[email protected]>
> ---
> sound/soc/tegra/tegra30_ahub.c | 33 ++++++++++++++++-----------------
> sound/soc/tegra/tegra30_ahub.h | 1 +
> 2 files changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
> index 4dbb58f7ea36..246cf6a373a1 100644
> --- a/sound/soc/tegra/tegra30_ahub.c
> +++ b/sound/soc/tegra/tegra30_ahub.c
> @@ -65,10 +65,20 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
> {
> int ret;
>
> + ret = reset_control_assert(ahub->reset);
> + if (ret)
> + return ret;
> +
> ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
> if (ret)
> return ret;
>
> + ret = reset_control_reset(ahub->reset);
> + if (ret) {
> + clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
> + return ret;
> + }
> +
> regcache_cache_only(ahub->regmap_apbif, false);
> regcache_cache_only(ahub->regmap_ahub, false);
>
> @@ -462,7 +472,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
> {
> const struct of_device_id *match;
> const struct tegra30_ahub_soc_data *soc_data;
> - struct reset_control *rst;
> struct resource *res0;
> void __iomem *regs_apbif, *regs_ahub;
> int ret = 0;
> @@ -475,22 +484,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
> return -EINVAL;
> soc_data = match->data;
>
> - /*
> - * The AHUB hosts a register bus: the "configlink". For this to
> - * operate correctly, all devices on this bus must be out of reset.
> - * Ensure that here.
> - */
> - rst = of_reset_control_array_get_exclusive(pdev->dev.of_node);
> - if (IS_ERR(rst)) {
> - dev_err(&pdev->dev, "Can't get reset: %p\n", rst);
> - return PTR_ERR(rst);
> - }
> -
> - ret = reset_control_deassert(rst);
> - reset_control_put(rst);
> - if (ret)
> - return ret;
> -
> ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
> GFP_KERNEL);
> if (!ahub)
> @@ -507,6 +500,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
> if (ret)
> return ret;
>
> + ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
> + if (IS_ERR(ahub->reset)) {
> + dev_err(&pdev->dev, "Can't get reset: %p\n", ahub->reset);

I didn't notice that the prior patch already introduced this, but I'd
prefer for this to either be %pe so that the symbolic error name is
printed, or %ld with PTR_ERR(ahub->reset) to format this in a more
standard way that can be more easily grepped for and parsed.

It also seems like the prior patch that converts this to use
of_reset_control_array_get_exclusive() is a bit pointless now. Why not
just move to this directly instead?

Thierry


Attachments:
(No filename) (3.10 kB)
signature.asc (849.00 B)
Download all attachments

2021-01-17 23:50:33

by Dmitry Osipenko

[permalink] [raw]
Subject: Re: [PATCH v1 1/5] ALSA: hda/tegra: Use clk_bulk helpers

15.01.2021 18:22, Thierry Reding пишет:
...
>> static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
>> {
>> struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
>> @@ -495,7 +441,11 @@ static int hda_tegra_probe(struct platform_device *pdev)
>> return err;
>> }
>>
>> - err = hda_tegra_init_clk(hda);
>> + hda->clocks[hda->nclocks++].id = "hda";
>> + hda->clocks[hda->nclocks++].id = "hda2hdmi";
>> + hda->clocks[hda->nclocks++].id = "hda2codec_2x";
>
> Originally the code did this in this order: "hda", "hda2codec_2x" and
> "hda2hdmi". I don't expect the exact order to be very relevant, but was
> there any particular reason to change it?

The reason was "to make code look nicer". This was a conscious decision
since indeed the clocks order shouldn't matter for this driver.

2021-01-18 00:08:36

by Dmitry Osipenko

[permalink] [raw]
Subject: Re: [PATCH v1 5/5] ASoC: tegra: ahub: Reset hardware properly

15.01.2021 18:44, Thierry Reding пишет:
> On Tue, Jan 12, 2021 at 03:58:34PM +0300, Dmitry Osipenko wrote:
>> Assert hardware reset before clocks are enabled and then de-assert it
>> after clocks are enabled. This brings hardware into a predictable state
>> and removes relying on implicit de-assertion of resets which is done by
>> the clk driver.
>>
>> Tested-by: Peter Geis <[email protected]>
>> Tested-by: Nicolas Chauvet <[email protected]>
>> Signed-off-by: Dmitry Osipenko <[email protected]>
>> ---
>> sound/soc/tegra/tegra30_ahub.c | 33 ++++++++++++++++-----------------
>> sound/soc/tegra/tegra30_ahub.h | 1 +
>> 2 files changed, 17 insertions(+), 17 deletions(-)
>>
>> diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
>> index 4dbb58f7ea36..246cf6a373a1 100644
>> --- a/sound/soc/tegra/tegra30_ahub.c
>> +++ b/sound/soc/tegra/tegra30_ahub.c
>> @@ -65,10 +65,20 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
>> {
>> int ret;
>>
>> + ret = reset_control_assert(ahub->reset);
>> + if (ret)
>> + return ret;
>> +
>> ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
>> if (ret)
>> return ret;
>>
>> + ret = reset_control_reset(ahub->reset);
>> + if (ret) {
>> + clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
>> + return ret;
>> + }
>> +
>> regcache_cache_only(ahub->regmap_apbif, false);
>> regcache_cache_only(ahub->regmap_ahub, false);
>>
>> @@ -462,7 +472,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
>> {
>> const struct of_device_id *match;
>> const struct tegra30_ahub_soc_data *soc_data;
>> - struct reset_control *rst;
>> struct resource *res0;
>> void __iomem *regs_apbif, *regs_ahub;
>> int ret = 0;
>> @@ -475,22 +484,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
>> return -EINVAL;
>> soc_data = match->data;
>>
>> - /*
>> - * The AHUB hosts a register bus: the "configlink". For this to
>> - * operate correctly, all devices on this bus must be out of reset.
>> - * Ensure that here.
>> - */
>> - rst = of_reset_control_array_get_exclusive(pdev->dev.of_node);
>> - if (IS_ERR(rst)) {
>> - dev_err(&pdev->dev, "Can't get reset: %p\n", rst);
>> - return PTR_ERR(rst);
>> - }
>> -
>> - ret = reset_control_deassert(rst);
>> - reset_control_put(rst);
>> - if (ret)
>> - return ret;
>> -
>> ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
>> GFP_KERNEL);
>> if (!ahub)
>> @@ -507,6 +500,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
>> if (ret)
>> return ret;
>>
>> + ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
>> + if (IS_ERR(ahub->reset)) {
>> + dev_err(&pdev->dev, "Can't get reset: %p\n", ahub->reset);
>
> I didn't notice that the prior patch already introduced this, but I'd
> prefer for this to either be %pe so that the symbolic error name is
> printed, or %ld with PTR_ERR(ahub->reset) to format this in a more
> standard way that can be more easily grepped for and parsed.

This is already fixed in v2. Good catch anyways, thanks.

> It also seems like the prior patch that converts this to use
> of_reset_control_array_get_exclusive() is a bit pointless now. Why not
> just move to this directly instead?

These are two independent changes. The previous patch fixed the missing
resets, this patch changes the hardware initialization logic.

2021-01-19 17:35:53

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v1 1/5] ALSA: hda/tegra: Use clk_bulk helpers

On Mon, Jan 18, 2021 at 02:31:35AM +0300, Dmitry Osipenko wrote:
> 15.01.2021 18:22, Thierry Reding пишет:
> ...
> >> static int hda_tegra_first_init(struct azx *chip, struct platform_device *pdev)
> >> {
> >> struct hda_tegra *hda = container_of(chip, struct hda_tegra, chip);
> >> @@ -495,7 +441,11 @@ static int hda_tegra_probe(struct platform_device *pdev)
> >> return err;
> >> }
> >>
> >> - err = hda_tegra_init_clk(hda);
> >> + hda->clocks[hda->nclocks++].id = "hda";
> >> + hda->clocks[hda->nclocks++].id = "hda2hdmi";
> >> + hda->clocks[hda->nclocks++].id = "hda2codec_2x";
> >
> > Originally the code did this in this order: "hda", "hda2codec_2x" and
> > "hda2hdmi". I don't expect the exact order to be very relevant, but was
> > there any particular reason to change it?
>
> The reason was "to make code look nicer". This was a conscious decision
> since indeed the clocks order shouldn't matter for this driver.

Yeah, it's probably fine. In case this ends up causing trouble after all
we can always change the order back.

Thierry


Attachments:
(No filename) (1.06 kB)
signature.asc (849.00 B)
Download all attachments

2021-01-19 17:37:30

by Thierry Reding

[permalink] [raw]
Subject: Re: [PATCH v1 5/5] ASoC: tegra: ahub: Reset hardware properly

On Mon, Jan 18, 2021 at 03:02:38AM +0300, Dmitry Osipenko wrote:
> 15.01.2021 18:44, Thierry Reding пишет:
> > On Tue, Jan 12, 2021 at 03:58:34PM +0300, Dmitry Osipenko wrote:
> >> Assert hardware reset before clocks are enabled and then de-assert it
> >> after clocks are enabled. This brings hardware into a predictable state
> >> and removes relying on implicit de-assertion of resets which is done by
> >> the clk driver.
> >>
> >> Tested-by: Peter Geis <[email protected]>
> >> Tested-by: Nicolas Chauvet <[email protected]>
> >> Signed-off-by: Dmitry Osipenko <[email protected]>
> >> ---
> >> sound/soc/tegra/tegra30_ahub.c | 33 ++++++++++++++++-----------------
> >> sound/soc/tegra/tegra30_ahub.h | 1 +
> >> 2 files changed, 17 insertions(+), 17 deletions(-)
> >>
> >> diff --git a/sound/soc/tegra/tegra30_ahub.c b/sound/soc/tegra/tegra30_ahub.c
> >> index 4dbb58f7ea36..246cf6a373a1 100644
> >> --- a/sound/soc/tegra/tegra30_ahub.c
> >> +++ b/sound/soc/tegra/tegra30_ahub.c
> >> @@ -65,10 +65,20 @@ static int tegra30_ahub_runtime_resume(struct device *dev)
> >> {
> >> int ret;
> >>
> >> + ret = reset_control_assert(ahub->reset);
> >> + if (ret)
> >> + return ret;
> >> +
> >> ret = clk_bulk_prepare_enable(ahub->nclocks, ahub->clocks);
> >> if (ret)
> >> return ret;
> >>
> >> + ret = reset_control_reset(ahub->reset);
> >> + if (ret) {
> >> + clk_bulk_disable_unprepare(ahub->nclocks, ahub->clocks);
> >> + return ret;
> >> + }
> >> +
> >> regcache_cache_only(ahub->regmap_apbif, false);
> >> regcache_cache_only(ahub->regmap_ahub, false);
> >>
> >> @@ -462,7 +472,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
> >> {
> >> const struct of_device_id *match;
> >> const struct tegra30_ahub_soc_data *soc_data;
> >> - struct reset_control *rst;
> >> struct resource *res0;
> >> void __iomem *regs_apbif, *regs_ahub;
> >> int ret = 0;
> >> @@ -475,22 +484,6 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
> >> return -EINVAL;
> >> soc_data = match->data;
> >>
> >> - /*
> >> - * The AHUB hosts a register bus: the "configlink". For this to
> >> - * operate correctly, all devices on this bus must be out of reset.
> >> - * Ensure that here.
> >> - */
> >> - rst = of_reset_control_array_get_exclusive(pdev->dev.of_node);
> >> - if (IS_ERR(rst)) {
> >> - dev_err(&pdev->dev, "Can't get reset: %p\n", rst);
> >> - return PTR_ERR(rst);
> >> - }
> >> -
> >> - ret = reset_control_deassert(rst);
> >> - reset_control_put(rst);
> >> - if (ret)
> >> - return ret;
> >> -
> >> ahub = devm_kzalloc(&pdev->dev, sizeof(struct tegra30_ahub),
> >> GFP_KERNEL);
> >> if (!ahub)
> >> @@ -507,6 +500,12 @@ static int tegra30_ahub_probe(struct platform_device *pdev)
> >> if (ret)
> >> return ret;
> >>
> >> + ahub->reset = devm_reset_control_array_get_exclusive(&pdev->dev);
> >> + if (IS_ERR(ahub->reset)) {
> >> + dev_err(&pdev->dev, "Can't get reset: %p\n", ahub->reset);
> >
> > I didn't notice that the prior patch already introduced this, but I'd
> > prefer for this to either be %pe so that the symbolic error name is
> > printed, or %ld with PTR_ERR(ahub->reset) to format this in a more
> > standard way that can be more easily grepped for and parsed.
>
> This is already fixed in v2. Good catch anyways, thanks.
>
> > It also seems like the prior patch that converts this to use
> > of_reset_control_array_get_exclusive() is a bit pointless now. Why not
> > just move to this directly instead?
>
> These are two independent changes. The previous patch fixed the missing
> resets, this patch changes the hardware initialization logic.

But moving to devm_reset_control_array_get_exclusive() isn't really part
of the hardware initialization logic change, right? So it's not strictly
related to the rest of this patch.

Anyway, I don't feel strongly about it being part of this patch, so feel
free to keep it here.

Thierry


Attachments:
(No filename) (3.95 kB)
signature.asc (849.00 B)
Download all attachments