diff --git a/drivers/crypto/qce/core.c b/drivers/crypto/qce/core.c index e486d366c0d63..ae5beed600d32 100644 --- a/drivers/crypto/qce/core.c +++ b/drivers/crypto/qce/core.c @@ -12,6 +12,9 @@ #include #include #include +#include +#include +#include #include #include @@ -90,13 +93,17 @@ static int qce_handle_queue(struct qce_device *qce, struct crypto_async_request *async_req, *backlog; int ret = 0, err; + ret = pm_runtime_resume_and_get(qce->dev); + if (ret < 0) + return ret; + scoped_guard(mutex, &qce->lock) { if (req) ret = crypto_enqueue_request(&qce->queue, req); /* busy, do not dequeue request */ if (qce->req) - return ret; + goto qce_suspend; backlog = crypto_get_backlog(&qce->queue); async_req = crypto_dequeue_request(&qce->queue); @@ -105,7 +112,7 @@ static int qce_handle_queue(struct qce_device *qce, } if (!async_req) - return ret; + goto qce_suspend; if (backlog) { scoped_guard(mutex, &qce->lock) @@ -118,6 +125,8 @@ static int qce_handle_queue(struct qce_device *qce, schedule_work(&qce->done_work); } +qce_suspend: + pm_runtime_put_autosuspend(qce->dev); return ret; } @@ -216,37 +225,47 @@ static int qce_crypto_probe(struct platform_device *pdev) if (ret < 0) return ret; - qce->core = devm_clk_get_optional_enabled(qce->dev, "core"); - if (IS_ERR(qce->core)) - return PTR_ERR(qce->core); + /* PM clock helpers: register device clocks */ + ret = devm_pm_clk_create(dev); + if (ret) + return ret; - qce->iface = devm_clk_get_optional_enabled(qce->dev, "iface"); - if (IS_ERR(qce->iface)) - return PTR_ERR(qce->iface); + ret = pm_clk_add(dev, "core"); + if (ret) + return ret; - qce->bus = devm_clk_get_optional_enabled(qce->dev, "bus"); - if (IS_ERR(qce->bus)) - return PTR_ERR(qce->bus); + ret = pm_clk_add(dev, "iface"); + if (ret) + return ret; - qce->mem_path = devm_of_icc_get(qce->dev, "memory"); + ret = pm_clk_add(dev, "bus"); + if (ret) + return ret; + + qce->mem_path = devm_of_icc_get(dev, "memory"); if (IS_ERR(qce->mem_path)) return PTR_ERR(qce->mem_path); - ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH); + /* Enable runtime PM after clocks and ICC are acquired */ + ret = devm_pm_runtime_enable(dev); if (ret) return ret; - ret = devm_qce_dma_request(qce); + ret = pm_runtime_resume_and_get(dev); if (ret) return ret; + ret = devm_qce_dma_request(qce); + if (ret) + goto err_pm; + ret = qce_check_version(qce); if (ret) - return ret; + goto err_pm; ret = devm_mutex_init(qce->dev, &qce->lock); if (ret) - return ret; + goto err_pm; INIT_WORK(&qce->done_work, qce_req_done_work); crypto_init_queue(&qce->queue, QCE_QUEUE_LENGTH); @@ -256,19 +275,68 @@ static int qce_crypto_probe(struct platform_device *pdev) ret = devm_qce_register_algs(qce); if (ret) - return ret; + goto err_pm; qce->dma_size = resource_size(res); qce->base_dma = dma_map_resource(dev, res->start, qce->dma_size, DMA_BIDIRECTIONAL, 0); qce->base_phys = res->start; ret = dma_mapping_error(dev, qce->base_dma); + if (ret) + goto err_pm; + + ret = devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce); + if (ret) + goto err_pm; + + /* Configure autosuspend after successful init */ + pm_runtime_set_autosuspend_delay(dev, 100); + pm_runtime_use_autosuspend(dev); + pm_runtime_mark_last_busy(dev); + pm_runtime_put_autosuspend(dev); + + return 0; + +err_pm: + pm_runtime_put(dev); + + return ret; +} + +static int __maybe_unused qce_runtime_suspend(struct device *dev) +{ + struct qce_device *qce = dev_get_drvdata(dev); + + icc_disable(qce->mem_path); + + return 0; +} + +static int __maybe_unused qce_runtime_resume(struct device *dev) +{ + struct qce_device *qce = dev_get_drvdata(dev); + int ret = 0; + + ret = icc_enable(qce->mem_path); if (ret) return ret; - return devm_add_action_or_reset(qce->dev, qce_crypto_unmap_dma, qce); + ret = icc_set_bw(qce->mem_path, QCE_DEFAULT_MEM_BANDWIDTH, QCE_DEFAULT_MEM_BANDWIDTH); + if (ret) + goto err_icc; + + return 0; + +err_icc: + icc_disable(qce->mem_path); + return ret; } +static const struct dev_pm_ops qce_crypto_pm_ops = { + SET_RUNTIME_PM_OPS(qce_runtime_suspend, qce_runtime_resume, NULL) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) +}; + static const struct of_device_id qce_crypto_of_match[] = { { .compatible = "qcom,crypto-v5.1", }, { .compatible = "qcom,crypto-v5.4", }, @@ -282,6 +350,7 @@ static struct platform_driver qce_crypto_driver = { .driver = { .name = KBUILD_MODNAME, .of_match_table = qce_crypto_of_match, + .pm = &qce_crypto_pm_ops, }, }; module_platform_driver(qce_crypto_driver);