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
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
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
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
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
>
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
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.
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.
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]>
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]>
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
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.
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.
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
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