From 87e0e2c8753c863415d3fa9220273dad7e178f05 Mon Sep 17 00:00:00 2001 From: Tharun Kumar Merugu Date: Thu, 5 Sep 2019 03:33:24 +0530 Subject: [PATCH] msm: CDSP: add CDSP loader driver Add the CDSP loader driver that loads the compute DSP firmware images and brings the subsystem out of reset during boot-up. Add compilation rules for the CDSP loader. Change-Id: I8cf67edd6e7996da7d223c9e69cd6aa39e2af07e Acked-by: Thyagarajan Venkatanarayanan Signed-off-by: Tharun Kumar Merugu --- drivers/soc/qcom/Kconfig | 8 + drivers/soc/qcom/Makefile | 1 + drivers/soc/qcom/qdsp6v2/Makefile | 2 + drivers/soc/qcom/qdsp6v2/cdsp-loader.c | 268 +++++++++++++++++++++++++ 4 files changed, 279 insertions(+) create mode 100644 drivers/soc/qcom/qdsp6v2/Makefile create mode 100644 drivers/soc/qcom/qdsp6v2/cdsp-loader.c diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 8a84e16481a4..c792b16b5626 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -378,4 +378,12 @@ config SENSORS_SSC exercising sensor use-cases. This driver loads firmware files for SSC and also does time synchronization with DSP clock. +config MSM_CDSP_LOADER + tristate "CDSP loader support" + help + This enables the CDSP loader driver that loads the CDSP + firmware images and brings the compute DSP out of reset + for platforms that have one. + Say M if you want to enable this module. + endmenu diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 809461b1cc4c..99c9991032ec 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -9,6 +9,7 @@ obj-$(CONFIG_QCOM_MDT_LOADER) += mdt_loader.o obj-$(CONFIG_QCOM_PM) += spm.o obj-$(CONFIG_MSM_PIL) += peripheral-loader.o obj-$(CONFIG_MSM_SUBSYSTEM_RESTART) += ssr.o +obj-$(CONFIG_MSM_CDSP_LOADER) += qdsp6v2/ ssr-y := subsystem_restart.o subsystem_notif.o ramdump.o sysmon-qmi.o obj-$(CONFIG_MSM_PIL_SSR_GENERIC) += subsys-pil-tz.o obj-$(CONFIG_MSM_SERVICE_NOTIFIER) += service-notifier.o diff --git a/drivers/soc/qcom/qdsp6v2/Makefile b/drivers/soc/qcom/qdsp6v2/Makefile new file mode 100644 index 000000000000..b7455dbcefcf --- /dev/null +++ b/drivers/soc/qcom/qdsp6v2/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_MSM_CDSP_LOADER) += cdsp-loader.o diff --git a/drivers/soc/qcom/qdsp6v2/cdsp-loader.c b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c new file mode 100644 index 000000000000..218374492255 --- /dev/null +++ b/drivers/soc/qcom/qdsp6v2/cdsp-loader.c @@ -0,0 +1,268 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Copyright (c) 2012-2014, 2017-2019, The Linux Foundation. All rights reserved. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define BOOT_CMD 1 +#define IMAGE_UNLOAD_CMD 0 + +#define CDSP_SUBSYS_DOWN 0 +#define CDSP_SUBSYS_LOADED 1 + +static ssize_t cdsp_boot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t count); + +struct cdsp_loader_private { + void *pil_h; + struct kobject *boot_cdsp_obj; + struct attribute_group *attr_group; +}; + +static struct kobj_attribute cdsp_boot_attribute = + __ATTR(boot, 0220, NULL, cdsp_boot_store); + +static struct attribute *attrs[] = { + &cdsp_boot_attribute.attr, + NULL, +}; + +static u32 cdsp_state = CDSP_SUBSYS_DOWN; +static struct platform_device *cdsp_private; +static void cdsp_loader_unload(struct platform_device *pdev); + +static int cdsp_loader_do(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + int rc = 0; + const char *img_name; + + if (!pdev) { + pr_err("%s: Platform device null\n", __func__); + goto fail; + } + + if (!pdev->dev.of_node) { + dev_err(&pdev->dev, + "%s: Device tree information missing\n", __func__); + + goto fail; + } + + rc = of_property_read_string(pdev->dev.of_node, + "qcom,proc-img-to-load", + &img_name); + if (rc) + goto fail; + + if (!strcmp(img_name, "cdsp")) { + /* cdsp_state always returns "0".*/ + if (cdsp_state == CDSP_SUBSYS_DOWN) { + priv = platform_get_drvdata(pdev); + if (!priv) { + dev_err(&pdev->dev, + "%s: Private data get failed\n", __func__); + goto fail; + } + + dev_dbg(&pdev->dev, "%s: calling subsystem_get on %s\n", + __func__, img_name); + priv->pil_h = subsystem_get("cdsp"); + if (IS_ERR(priv->pil_h)) { + dev_err(&pdev->dev, "%s: subsystem_get failed with error %d\n", + __func__, (int)(PTR_ERR(priv->pil_h))); + goto fail; + } + + /* Set the state of the CDSP.*/ + cdsp_state = CDSP_SUBSYS_LOADED; + } else if (cdsp_state == CDSP_SUBSYS_LOADED) { + dev_dbg(&pdev->dev, + "%s: CDSP state = 0x%x\n", __func__, cdsp_state); + } + + dev_dbg(&pdev->dev, "%s: CDSP image is loaded\n", __func__); + return rc; + } + +fail: + if (pdev) + dev_err(&pdev->dev, + "%s: CDSP image loading failed\n", __func__); + return rc; +} + + +static ssize_t cdsp_boot_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, + size_t count) +{ + int ret = 0; + uint32_t boot = 0; + + ret = kstrtou32(buf, 0, &boot); + if (ret) { + pr_debug("%s: invalid arguments for cdsp_loader.\n", __func__); + return ret; + } + + if (boot == BOOT_CMD) { + pr_debug("%s: going to call cdsp_loader_do\n", __func__); + cdsp_loader_do(cdsp_private); + } else if (boot == IMAGE_UNLOAD_CMD) { + pr_debug("%s: going to call cdsp_unloader\n", __func__); + cdsp_loader_unload(cdsp_private); + } + return count; +} + +static void cdsp_loader_unload(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + + if (!priv) + return; + + if (priv->pil_h) { + dev_dbg(&pdev->dev, "%s: calling subsystem_put\n", __func__); + subsystem_put(priv->pil_h); + priv->pil_h = NULL; + } +} + +static int cdsp_loader_init_sysfs(struct platform_device *pdev) +{ + int ret = -EINVAL; + struct cdsp_loader_private *priv = NULL; + + cdsp_private = NULL; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + ret = -ENOMEM; + return ret; + } + + platform_set_drvdata(pdev, priv); + + priv->pil_h = NULL; + priv->boot_cdsp_obj = NULL; + priv->attr_group = devm_kzalloc(&pdev->dev, + sizeof(*(priv->attr_group)), + GFP_KERNEL); + if (!priv->attr_group) { + ret = -ENOMEM; + goto error_return; + } + + priv->attr_group->attrs = attrs; + + priv->boot_cdsp_obj = kobject_create_and_add("boot_cdsp", kernel_kobj); + if (!priv->boot_cdsp_obj) { + dev_err(&pdev->dev, "%s: sysfs create and add failed\n", + __func__); + ret = -ENOMEM; + goto error_return; + } + + ret = sysfs_create_group(priv->boot_cdsp_obj, priv->attr_group); + if (ret) { + dev_err(&pdev->dev, "%s: sysfs create group failed %d\n", + __func__, ret); + goto error_return; + } + + cdsp_private = pdev; + + return 0; + +error_return: + + if (priv->boot_cdsp_obj) { + kobject_del(priv->boot_cdsp_obj); + priv->boot_cdsp_obj = NULL; + } + if (ret) + dev_err(&pdev->dev, "%s failed with ret %d\n", + __func__, ret); + return ret; +} + +static int cdsp_loader_remove(struct platform_device *pdev) +{ + struct cdsp_loader_private *priv = NULL; + + priv = platform_get_drvdata(pdev); + + if (!priv) + return 0; + + if (priv->pil_h) { + subsystem_put(priv->pil_h); + priv->pil_h = NULL; + } + + if (priv->boot_cdsp_obj) { + sysfs_remove_group(priv->boot_cdsp_obj, priv->attr_group); + kobject_del(priv->boot_cdsp_obj); + priv->boot_cdsp_obj = NULL; + } + + return 0; +} + +static int cdsp_loader_probe(struct platform_device *pdev) +{ + int ret = cdsp_loader_init_sysfs(pdev); + + if (ret != 0) { + dev_err(&pdev->dev, "%s: Error in initing sysfs\n", __func__); + return ret; + } + + return 0; +} + +static const struct of_device_id cdsp_loader_dt_match[] = { + { .compatible = "qcom,cdsp-loader" }, + { } +}; +MODULE_DEVICE_TABLE(of, cdsp_loader_dt_match); + +static struct platform_driver cdsp_loader_driver = { + .driver = { + .name = "cdsp-loader", + .of_match_table = cdsp_loader_dt_match, + }, + .probe = cdsp_loader_probe, + .remove = cdsp_loader_remove, +}; + +static int __init cdsp_loader_init(void) +{ + return platform_driver_register(&cdsp_loader_driver); +} +module_init(cdsp_loader_init); + +static void __exit cdsp_loader_exit(void) +{ + platform_driver_unregister(&cdsp_loader_driver); +} +module_exit(cdsp_loader_exit); + +MODULE_DESCRIPTION("CDSP Loader module"); +MODULE_LICENSE("GPL v2");