18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Qualcomm Peripheral Image Loader helpers 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (C) 2016 Linaro Ltd 68c2ecf20Sopenharmony_ci * Copyright (C) 2015 Sony Mobile Communications Inc 78c2ecf20Sopenharmony_ci * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/firmware.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/notifier.h> 148c2ecf20Sopenharmony_ci#include <linux/remoteproc.h> 158c2ecf20Sopenharmony_ci#include <linux/remoteproc/qcom_rproc.h> 168c2ecf20Sopenharmony_ci#include <linux/rpmsg/qcom_glink.h> 178c2ecf20Sopenharmony_ci#include <linux/rpmsg/qcom_smd.h> 188c2ecf20Sopenharmony_ci#include <linux/slab.h> 198c2ecf20Sopenharmony_ci#include <linux/soc/qcom/mdt_loader.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include "remoteproc_internal.h" 228c2ecf20Sopenharmony_ci#include "qcom_common.h" 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev) 258c2ecf20Sopenharmony_ci#define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) 268c2ecf20Sopenharmony_ci#define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_cistruct qcom_ssr_subsystem { 298c2ecf20Sopenharmony_ci const char *name; 308c2ecf20Sopenharmony_ci struct srcu_notifier_head notifier_list; 318c2ecf20Sopenharmony_ci struct list_head list; 328c2ecf20Sopenharmony_ci}; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic LIST_HEAD(qcom_ssr_subsystem_list); 358c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(qcom_ssr_subsys_lock); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic int glink_subdev_start(struct rproc_subdev *subdev) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci glink->edge = qcom_glink_smem_register(glink->dev, glink->node); 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(glink->edge); 448c2ecf20Sopenharmony_ci} 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_cistatic void glink_subdev_stop(struct rproc_subdev *subdev, bool crashed) 478c2ecf20Sopenharmony_ci{ 488c2ecf20Sopenharmony_ci struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci qcom_glink_smem_unregister(glink->edge); 518c2ecf20Sopenharmony_ci glink->edge = NULL; 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_cistatic void glink_subdev_unprepare(struct rproc_subdev *subdev) 558c2ecf20Sopenharmony_ci{ 568c2ecf20Sopenharmony_ci struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci qcom_glink_ssr_notify(glink->ssr_name); 598c2ecf20Sopenharmony_ci} 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci/** 628c2ecf20Sopenharmony_ci * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc 638c2ecf20Sopenharmony_ci * @rproc: rproc handle to parent the subdevice 648c2ecf20Sopenharmony_ci * @glink: reference to a GLINK subdev context 658c2ecf20Sopenharmony_ci * @ssr_name: identifier of the associated remoteproc for ssr notifications 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_civoid qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink, 688c2ecf20Sopenharmony_ci const char *ssr_name) 698c2ecf20Sopenharmony_ci{ 708c2ecf20Sopenharmony_ci struct device *dev = &rproc->dev; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci glink->node = of_get_child_by_name(dev->parent->of_node, "glink-edge"); 738c2ecf20Sopenharmony_ci if (!glink->node) 748c2ecf20Sopenharmony_ci return; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci glink->ssr_name = kstrdup_const(ssr_name, GFP_KERNEL); 778c2ecf20Sopenharmony_ci if (!glink->ssr_name) 788c2ecf20Sopenharmony_ci return; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci glink->dev = dev; 818c2ecf20Sopenharmony_ci glink->subdev.start = glink_subdev_start; 828c2ecf20Sopenharmony_ci glink->subdev.stop = glink_subdev_stop; 838c2ecf20Sopenharmony_ci glink->subdev.unprepare = glink_subdev_unprepare; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci rproc_add_subdev(rproc, &glink->subdev); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_add_glink_subdev); 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci/** 908c2ecf20Sopenharmony_ci * qcom_remove_glink_subdev() - remove a GLINK subdevice from rproc 918c2ecf20Sopenharmony_ci * @rproc: rproc handle 928c2ecf20Sopenharmony_ci * @glink: reference to a GLINK subdev context 938c2ecf20Sopenharmony_ci */ 948c2ecf20Sopenharmony_civoid qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if (!glink->node) 978c2ecf20Sopenharmony_ci return; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci rproc_remove_subdev(rproc, &glink->subdev); 1008c2ecf20Sopenharmony_ci kfree_const(glink->ssr_name); 1018c2ecf20Sopenharmony_ci of_node_put(glink->node); 1028c2ecf20Sopenharmony_ci} 1038c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_remove_glink_subdev); 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci/** 1068c2ecf20Sopenharmony_ci * qcom_register_dump_segments() - register segments for coredump 1078c2ecf20Sopenharmony_ci * @rproc: remoteproc handle 1088c2ecf20Sopenharmony_ci * @fw: firmware header 1098c2ecf20Sopenharmony_ci * 1108c2ecf20Sopenharmony_ci * Register all segments of the ELF in the remoteproc coredump segment list 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * Return: 0 on success, negative errno on failure. 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ciint qcom_register_dump_segments(struct rproc *rproc, 1158c2ecf20Sopenharmony_ci const struct firmware *fw) 1168c2ecf20Sopenharmony_ci{ 1178c2ecf20Sopenharmony_ci const struct elf32_phdr *phdrs; 1188c2ecf20Sopenharmony_ci const struct elf32_phdr *phdr; 1198c2ecf20Sopenharmony_ci const struct elf32_hdr *ehdr; 1208c2ecf20Sopenharmony_ci int ret; 1218c2ecf20Sopenharmony_ci int i; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci ehdr = (struct elf32_hdr *)fw->data; 1248c2ecf20Sopenharmony_ci phdrs = (struct elf32_phdr *)(ehdr + 1); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci for (i = 0; i < ehdr->e_phnum; i++) { 1278c2ecf20Sopenharmony_ci phdr = &phdrs[i]; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (phdr->p_type != PT_LOAD) 1308c2ecf20Sopenharmony_ci continue; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci if ((phdr->p_flags & QCOM_MDT_TYPE_MASK) == QCOM_MDT_TYPE_HASH) 1338c2ecf20Sopenharmony_ci continue; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci if (!phdr->p_memsz) 1368c2ecf20Sopenharmony_ci continue; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci ret = rproc_coredump_add_segment(rproc, phdr->p_paddr, 1398c2ecf20Sopenharmony_ci phdr->p_memsz); 1408c2ecf20Sopenharmony_ci if (ret) 1418c2ecf20Sopenharmony_ci return ret; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci return 0; 1458c2ecf20Sopenharmony_ci} 1468c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_register_dump_segments); 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_cistatic int smd_subdev_start(struct rproc_subdev *subdev) 1498c2ecf20Sopenharmony_ci{ 1508c2ecf20Sopenharmony_ci struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci smd->edge = qcom_smd_register_edge(smd->dev, smd->node); 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci return PTR_ERR_OR_ZERO(smd->edge); 1558c2ecf20Sopenharmony_ci} 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_cistatic void smd_subdev_stop(struct rproc_subdev *subdev, bool crashed) 1588c2ecf20Sopenharmony_ci{ 1598c2ecf20Sopenharmony_ci struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci qcom_smd_unregister_edge(smd->edge); 1628c2ecf20Sopenharmony_ci smd->edge = NULL; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci/** 1668c2ecf20Sopenharmony_ci * qcom_add_smd_subdev() - try to add a SMD subdevice to rproc 1678c2ecf20Sopenharmony_ci * @rproc: rproc handle to parent the subdevice 1688c2ecf20Sopenharmony_ci * @smd: reference to a Qualcomm subdev context 1698c2ecf20Sopenharmony_ci */ 1708c2ecf20Sopenharmony_civoid qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct device *dev = &rproc->dev; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci smd->node = of_get_child_by_name(dev->parent->of_node, "smd-edge"); 1758c2ecf20Sopenharmony_ci if (!smd->node) 1768c2ecf20Sopenharmony_ci return; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci smd->dev = dev; 1798c2ecf20Sopenharmony_ci smd->subdev.start = smd_subdev_start; 1808c2ecf20Sopenharmony_ci smd->subdev.stop = smd_subdev_stop; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci rproc_add_subdev(rproc, &smd->subdev); 1838c2ecf20Sopenharmony_ci} 1848c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_add_smd_subdev); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci/** 1878c2ecf20Sopenharmony_ci * qcom_remove_smd_subdev() - remove the smd subdevice from rproc 1888c2ecf20Sopenharmony_ci * @rproc: rproc handle 1898c2ecf20Sopenharmony_ci * @smd: the SMD subdevice to remove 1908c2ecf20Sopenharmony_ci */ 1918c2ecf20Sopenharmony_civoid qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci if (!smd->node) 1948c2ecf20Sopenharmony_ci return; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci rproc_remove_subdev(rproc, &smd->subdev); 1978c2ecf20Sopenharmony_ci of_node_put(smd->node); 1988c2ecf20Sopenharmony_ci} 1998c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_cistatic struct qcom_ssr_subsystem *qcom_ssr_get_subsys(const char *name) 2028c2ecf20Sopenharmony_ci{ 2038c2ecf20Sopenharmony_ci struct qcom_ssr_subsystem *info; 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci mutex_lock(&qcom_ssr_subsys_lock); 2068c2ecf20Sopenharmony_ci /* Match in the global qcom_ssr_subsystem_list with name */ 2078c2ecf20Sopenharmony_ci list_for_each_entry(info, &qcom_ssr_subsystem_list, list) 2088c2ecf20Sopenharmony_ci if (!strcmp(info->name, name)) 2098c2ecf20Sopenharmony_ci goto out; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci info = kzalloc(sizeof(*info), GFP_KERNEL); 2128c2ecf20Sopenharmony_ci if (!info) { 2138c2ecf20Sopenharmony_ci info = ERR_PTR(-ENOMEM); 2148c2ecf20Sopenharmony_ci goto out; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci info->name = kstrdup_const(name, GFP_KERNEL); 2178c2ecf20Sopenharmony_ci srcu_init_notifier_head(&info->notifier_list); 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_ci /* Add to global notification list */ 2208c2ecf20Sopenharmony_ci list_add_tail(&info->list, &qcom_ssr_subsystem_list); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ciout: 2238c2ecf20Sopenharmony_ci mutex_unlock(&qcom_ssr_subsys_lock); 2248c2ecf20Sopenharmony_ci return info; 2258c2ecf20Sopenharmony_ci} 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci/** 2288c2ecf20Sopenharmony_ci * qcom_register_ssr_notifier() - register SSR notification handler 2298c2ecf20Sopenharmony_ci * @name: Subsystem's SSR name 2308c2ecf20Sopenharmony_ci * @nb: notifier_block to be invoked upon subsystem's state change 2318c2ecf20Sopenharmony_ci * 2328c2ecf20Sopenharmony_ci * This registers the @nb notifier block as part the notifier chain for a 2338c2ecf20Sopenharmony_ci * remoteproc associated with @name. The notifier block's callback 2348c2ecf20Sopenharmony_ci * will be invoked when the remote processor's SSR events occur 2358c2ecf20Sopenharmony_ci * (pre/post startup and pre/post shutdown). 2368c2ecf20Sopenharmony_ci * 2378c2ecf20Sopenharmony_ci * Return: a subsystem cookie on success, ERR_PTR on failure. 2388c2ecf20Sopenharmony_ci */ 2398c2ecf20Sopenharmony_civoid *qcom_register_ssr_notifier(const char *name, struct notifier_block *nb) 2408c2ecf20Sopenharmony_ci{ 2418c2ecf20Sopenharmony_ci struct qcom_ssr_subsystem *info; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci info = qcom_ssr_get_subsys(name); 2448c2ecf20Sopenharmony_ci if (IS_ERR(info)) 2458c2ecf20Sopenharmony_ci return info; 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci srcu_notifier_chain_register(&info->notifier_list, nb); 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci return &info->notifier_list; 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/** 2548c2ecf20Sopenharmony_ci * qcom_unregister_ssr_notifier() - unregister SSR notification handler 2558c2ecf20Sopenharmony_ci * @notify: subsystem cookie returned from qcom_register_ssr_notifier 2568c2ecf20Sopenharmony_ci * @nb: notifier_block to unregister 2578c2ecf20Sopenharmony_ci * 2588c2ecf20Sopenharmony_ci * This function will unregister the notifier from the particular notifier 2598c2ecf20Sopenharmony_ci * chain. 2608c2ecf20Sopenharmony_ci * 2618c2ecf20Sopenharmony_ci * Return: 0 on success, %ENOENT otherwise. 2628c2ecf20Sopenharmony_ci */ 2638c2ecf20Sopenharmony_ciint qcom_unregister_ssr_notifier(void *notify, struct notifier_block *nb) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci return srcu_notifier_chain_unregister(notify, nb); 2668c2ecf20Sopenharmony_ci} 2678c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic int ssr_notify_prepare(struct rproc_subdev *subdev) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 2728c2ecf20Sopenharmony_ci struct qcom_ssr_notify_data data = { 2738c2ecf20Sopenharmony_ci .name = ssr->info->name, 2748c2ecf20Sopenharmony_ci .crashed = false, 2758c2ecf20Sopenharmony_ci }; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci srcu_notifier_call_chain(&ssr->info->notifier_list, 2788c2ecf20Sopenharmony_ci QCOM_SSR_BEFORE_POWERUP, &data); 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic int ssr_notify_start(struct rproc_subdev *subdev) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 2858c2ecf20Sopenharmony_ci struct qcom_ssr_notify_data data = { 2868c2ecf20Sopenharmony_ci .name = ssr->info->name, 2878c2ecf20Sopenharmony_ci .crashed = false, 2888c2ecf20Sopenharmony_ci }; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci srcu_notifier_call_chain(&ssr->info->notifier_list, 2918c2ecf20Sopenharmony_ci QCOM_SSR_AFTER_POWERUP, &data); 2928c2ecf20Sopenharmony_ci return 0; 2938c2ecf20Sopenharmony_ci} 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_cistatic void ssr_notify_stop(struct rproc_subdev *subdev, bool crashed) 2968c2ecf20Sopenharmony_ci{ 2978c2ecf20Sopenharmony_ci struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 2988c2ecf20Sopenharmony_ci struct qcom_ssr_notify_data data = { 2998c2ecf20Sopenharmony_ci .name = ssr->info->name, 3008c2ecf20Sopenharmony_ci .crashed = crashed, 3018c2ecf20Sopenharmony_ci }; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci srcu_notifier_call_chain(&ssr->info->notifier_list, 3048c2ecf20Sopenharmony_ci QCOM_SSR_BEFORE_SHUTDOWN, &data); 3058c2ecf20Sopenharmony_ci} 3068c2ecf20Sopenharmony_ci 3078c2ecf20Sopenharmony_cistatic void ssr_notify_unprepare(struct rproc_subdev *subdev) 3088c2ecf20Sopenharmony_ci{ 3098c2ecf20Sopenharmony_ci struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 3108c2ecf20Sopenharmony_ci struct qcom_ssr_notify_data data = { 3118c2ecf20Sopenharmony_ci .name = ssr->info->name, 3128c2ecf20Sopenharmony_ci .crashed = false, 3138c2ecf20Sopenharmony_ci }; 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci srcu_notifier_call_chain(&ssr->info->notifier_list, 3168c2ecf20Sopenharmony_ci QCOM_SSR_AFTER_SHUTDOWN, &data); 3178c2ecf20Sopenharmony_ci} 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci/** 3208c2ecf20Sopenharmony_ci * qcom_add_ssr_subdev() - register subdevice as restart notification source 3218c2ecf20Sopenharmony_ci * @rproc: rproc handle 3228c2ecf20Sopenharmony_ci * @ssr: SSR subdevice handle 3238c2ecf20Sopenharmony_ci * @ssr_name: identifier to use for notifications originating from @rproc 3248c2ecf20Sopenharmony_ci * 3258c2ecf20Sopenharmony_ci * As the @ssr is registered with the @rproc SSR events will be sent to all 3268c2ecf20Sopenharmony_ci * registered listeners for the remoteproc when it's SSR events occur 3278c2ecf20Sopenharmony_ci * (pre/post startup and pre/post shutdown). 3288c2ecf20Sopenharmony_ci */ 3298c2ecf20Sopenharmony_civoid qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, 3308c2ecf20Sopenharmony_ci const char *ssr_name) 3318c2ecf20Sopenharmony_ci{ 3328c2ecf20Sopenharmony_ci struct qcom_ssr_subsystem *info; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci info = qcom_ssr_get_subsys(ssr_name); 3358c2ecf20Sopenharmony_ci if (IS_ERR(info)) { 3368c2ecf20Sopenharmony_ci dev_err(&rproc->dev, "Failed to add ssr subdevice\n"); 3378c2ecf20Sopenharmony_ci return; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci ssr->info = info; 3418c2ecf20Sopenharmony_ci ssr->subdev.prepare = ssr_notify_prepare; 3428c2ecf20Sopenharmony_ci ssr->subdev.start = ssr_notify_start; 3438c2ecf20Sopenharmony_ci ssr->subdev.stop = ssr_notify_stop; 3448c2ecf20Sopenharmony_ci ssr->subdev.unprepare = ssr_notify_unprepare; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci rproc_add_subdev(rproc, &ssr->subdev); 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_add_ssr_subdev); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci/** 3518c2ecf20Sopenharmony_ci * qcom_remove_ssr_subdev() - remove subdevice as restart notification source 3528c2ecf20Sopenharmony_ci * @rproc: rproc handle 3538c2ecf20Sopenharmony_ci * @ssr: SSR subdevice handle 3548c2ecf20Sopenharmony_ci */ 3558c2ecf20Sopenharmony_civoid qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr) 3568c2ecf20Sopenharmony_ci{ 3578c2ecf20Sopenharmony_ci rproc_remove_subdev(rproc, &ssr->subdev); 3588c2ecf20Sopenharmony_ci ssr->info = NULL; 3598c2ecf20Sopenharmony_ci} 3608c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev); 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Qualcomm Remoteproc helper driver"); 3638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 364