spi: qup: Request DMA before enabling clocks
[ Upstream commit0c331fd1dc
] It is usually better to request all necessary resources (clocks, regulators, ...) before starting to make use of them. That way they do not change state in case one of the resources is not available yet and probe deferral (-EPROBE_DEFER) is necessary. This is particularly important for DMA channels and IOMMUs which are not enforced by fw_devlink yet (unless you use fw_devlink.strict=1). spi-qup does this in the wrong order, the clocks are enabled and disabled again when the DMA channels are not available yet. This causes issues in some cases: On most SoCs one of the SPI QUP clocks is shared with the UART controller. When using earlycon UART is actively used during boot but might not have probed yet, usually for the same reason (waiting for the DMA controller). In this case, the brief enable/disable cycle ends up gating the clock and further UART console output will halt the system completely. Avoid this by requesting the DMA channels before changing the clock state. Fixes:612762e82a
("spi: qup: Add DMA capabilities") Signed-off-by: Stephan Gerhold <stephan@gerhold.net> Link: https://lore.kernel.org/r/20230518-spi-qup-clk-defer-v1-1-f49fc9ca4e02@gerhold.net Signed-off-by: Mark Brown <broonie@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
Родитель
f0e84db82e
Коммит
8ef72e7830
|
@ -1030,23 +1030,8 @@ static int spi_qup_probe(struct platform_device *pdev)
|
|||
return -ENXIO;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(cclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot enable core clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(iclk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(cclk);
|
||||
dev_err(dev, "cannot enable iface clock\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
master = spi_alloc_master(dev, sizeof(struct spi_qup));
|
||||
if (!master) {
|
||||
clk_disable_unprepare(cclk);
|
||||
clk_disable_unprepare(iclk);
|
||||
dev_err(dev, "cannot allocate master\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
@ -1092,6 +1077,19 @@ static int spi_qup_probe(struct platform_device *pdev)
|
|||
spin_lock_init(&controller->lock);
|
||||
init_completion(&controller->done);
|
||||
|
||||
ret = clk_prepare_enable(cclk);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot enable core clock\n");
|
||||
goto error_dma;
|
||||
}
|
||||
|
||||
ret = clk_prepare_enable(iclk);
|
||||
if (ret) {
|
||||
clk_disable_unprepare(cclk);
|
||||
dev_err(dev, "cannot enable iface clock\n");
|
||||
goto error_dma;
|
||||
}
|
||||
|
||||
iomode = readl_relaxed(base + QUP_IO_M_MODES);
|
||||
|
||||
size = QUP_IO_M_OUTPUT_BLOCK_SIZE(iomode);
|
||||
|
@ -1121,7 +1119,7 @@ static int spi_qup_probe(struct platform_device *pdev)
|
|||
ret = spi_qup_set_state(controller, QUP_STATE_RESET);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot set RESET state\n");
|
||||
goto error_dma;
|
||||
goto error_clk;
|
||||
}
|
||||
|
||||
writel_relaxed(0, base + QUP_OPERATIONAL);
|
||||
|
@ -1145,7 +1143,7 @@ static int spi_qup_probe(struct platform_device *pdev)
|
|||
ret = devm_request_irq(dev, irq, spi_qup_qup_irq,
|
||||
IRQF_TRIGGER_HIGH, pdev->name, controller);
|
||||
if (ret)
|
||||
goto error_dma;
|
||||
goto error_clk;
|
||||
|
||||
pm_runtime_set_autosuspend_delay(dev, MSEC_PER_SEC);
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
|
@ -1160,11 +1158,12 @@ static int spi_qup_probe(struct platform_device *pdev)
|
|||
|
||||
disable_pm:
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
error_clk:
|
||||
clk_disable_unprepare(cclk);
|
||||
clk_disable_unprepare(iclk);
|
||||
error_dma:
|
||||
spi_qup_release_dma(master);
|
||||
error:
|
||||
clk_disable_unprepare(cclk);
|
||||
clk_disable_unprepare(iclk);
|
||||
spi_master_put(master);
|
||||
return ret;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче