20.12.2021 20:30, Sameer Pujar пишет: > HDA regression is recently reported on Tegra194 based platforms. > This happens because "hda2codec_2x" reset does not really exist > in Tegra194 and it causes probe failure. All the HDA based audio > tests fail at the moment. This underlying issue is exposed by > commit c045ceb5a145 ("reset: tegra-bpmp: Handle errors in BPMP > response") which now checks return code of BPMP command response. > Fix this issue by skipping unavailable reset on Tegra194. > > Signed-off-by: Sameer Pujar <spujar@xxxxxxxxxx> > Cc: stable@xxxxxxxxxxxxxxx > Depends-on: 87f0e46e7559 ("ALSA: hda/tegra: Reset hardware") > --- > sound/pci/hda/hda_tegra.c | 96 ++++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 86 insertions(+), 10 deletions(-) > > diff --git a/sound/pci/hda/hda_tegra.c b/sound/pci/hda/hda_tegra.c > index ea700395..be010cd 100644 > --- a/sound/pci/hda/hda_tegra.c > +++ b/sound/pci/hda/hda_tegra.c > @@ -68,14 +68,21 @@ > */ > #define TEGRA194_NUM_SDO_LINES 4 > > +struct hda_tegra_soc { > + bool has_hda2codec_2x_reset; > +}; > + > struct hda_tegra { > struct azx chip; > struct device *dev; > - struct reset_control *reset; > + struct reset_control *reset_hda; > + struct reset_control *reset_hda2hdmi; > + struct reset_control *reset_hda2codec_2x; > struct clk_bulk_data clocks[3]; > unsigned int nclocks; > void __iomem *regs; > struct work_struct probe_work; > + const struct hda_tegra_soc *data; > }; > > #ifdef CONFIG_PM > @@ -170,9 +177,26 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) > int rc; > > if (!chip->running) { > - rc = reset_control_assert(hda->reset); > - if (rc) > + rc = reset_control_assert(hda->reset_hda); > + if (rc) { > + dev_err(dev, "hda reset assert failed, err: %d\n", rc); > + return rc; > + } > + > + rc = reset_control_assert(hda->reset_hda2hdmi); > + if (rc) { > + dev_err(dev, "hda2hdmi reset assert failed, err: %d\n", > + rc); > + return rc; > + } > + > + rc = reset_control_assert(hda->reset_hda2codec_2x); > + if (rc) { > + dev_err(dev, > + "hda2codec_2x reset assert failed, err: %d\n", > + rc); > return rc; > + } > } > > rc = clk_bulk_prepare_enable(hda->nclocks, hda->clocks); > @@ -187,9 +211,27 @@ static int __maybe_unused hda_tegra_runtime_resume(struct device *dev) > } else { > usleep_range(10, 100); > > - rc = reset_control_deassert(hda->reset); > - if (rc) > + rc = reset_control_deassert(hda->reset_hda); > + if (rc) { > + dev_err(dev, "hda reset deassert failed, err: %d\n", > + rc); > return rc; > + } > + > + rc = reset_control_deassert(hda->reset_hda2hdmi); > + if (rc) { > + dev_err(dev, "hda2hdmi reset deassert failed, err: %d\n", > + rc); > + return rc; > + } > + > + rc = reset_control_deassert(hda->reset_hda2codec_2x); > + if (rc) { > + dev_err(dev, > + "hda2codec_2x reset deassert failed, err: %d\n", > + rc); > + return rc; > + } > } > > return 0; > @@ -427,9 +469,17 @@ static int hda_tegra_create(struct snd_card *card, > return 0; > } > > +static const struct hda_tegra_soc tegra30_data = { > + .has_hda2codec_2x_reset = true, > +}; > + > +static const struct hda_tegra_soc tegra194_data = { > + .has_hda2codec_2x_reset = false, > +}; > + > static const struct of_device_id hda_tegra_match[] = { > - { .compatible = "nvidia,tegra30-hda" }, > - { .compatible = "nvidia,tegra194-hda" }, > + { .compatible = "nvidia,tegra30-hda", .data = &tegra30_data }, > + { .compatible = "nvidia,tegra194-hda", .data = &tegra194_data }, > {}, > }; > MODULE_DEVICE_TABLE(of, hda_tegra_match); > @@ -449,6 +499,10 @@ static int hda_tegra_probe(struct platform_device *pdev) > hda->dev = &pdev->dev; > chip = &hda->chip; > > + hda->data = of_device_get_match_data(&pdev->dev); > + if (!hda->data) > + return -EINVAL; > + > err = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, > THIS_MODULE, 0, &card); > if (err < 0) { > @@ -456,12 +510,34 @@ static int hda_tegra_probe(struct platform_device *pdev) > return err; > } > > - hda->reset = devm_reset_control_array_get_exclusive(&pdev->dev); > - if (IS_ERR(hda->reset)) { > - err = PTR_ERR(hda->reset); > + hda->reset_hda = devm_reset_control_get_exclusive(&pdev->dev, "hda"); > + if (IS_ERR(hda->reset_hda)) { > + err = PTR_ERR(hda->reset_hda); > goto out_free; > } > > + hda->reset_hda2hdmi = devm_reset_control_get_exclusive(&pdev->dev, > + "hda2hdmi"); > + if (IS_ERR(hda->reset_hda2hdmi)) { > + err = PTR_ERR(hda->reset_hda2hdmi); > + goto out_free; > + } > + > + /* > + * "hda2codec_2x" reset is not present on Tegra194. Though DT would > + * be updated to reflect this, but to have backward compatibility > + * below is necessary. > + */ > + if (hda->data->has_hda2codec_2x_reset) { > + hda->reset_hda2codec_2x = > + devm_reset_control_get_exclusive(&pdev->dev, > + "hda2codec_2x"); > + if (IS_ERR(hda->reset_hda2codec_2x)) { > + err = PTR_ERR(hda->reset_hda2codec_2x); > + goto out_free; > + } > + } > + > hda->clocks[hda->nclocks++].id = "hda"; > hda->clocks[hda->nclocks++].id = "hda2hdmi"; > hda->clocks[hda->nclocks++].id = "hda2codec_2x"; > All stable kernels affected by this problem that don't support the bulk reset API are EOL now. Please use bulk reset API like I suggested in the comment to v1, it will allow us to have a cleaner and nicer code. The bulk reset code will look similar to the bulk clk API already used by the HDA driver, you'll only need to skip adding the hda2codec_2x to resets[3] and switch to use reset_control_bulk_reset_*() variants of the functions.