at v4.14 216 lines 6.3 kB view raw
1/* 2 * Qualcomm Peripheral Image Loader helpers 3 * 4 * Copyright (C) 2016 Linaro Ltd 5 * Copyright (C) 2015 Sony Mobile Communications Inc 6 * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU General Public License 10 * version 2 as published by the Free Software Foundation. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 */ 17 18#include <linux/firmware.h> 19#include <linux/kernel.h> 20#include <linux/module.h> 21#include <linux/notifier.h> 22#include <linux/remoteproc.h> 23#include <linux/rpmsg/qcom_glink.h> 24#include <linux/rpmsg/qcom_smd.h> 25 26#include "remoteproc_internal.h" 27#include "qcom_common.h" 28 29#define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev) 30#define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) 31#define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) 32 33static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); 34 35/** 36 * qcom_mdt_find_rsc_table() - provide dummy resource table for remoteproc 37 * @rproc: remoteproc handle 38 * @fw: firmware header 39 * @tablesz: outgoing size of the table 40 * 41 * Returns a dummy table. 42 */ 43struct resource_table *qcom_mdt_find_rsc_table(struct rproc *rproc, 44 const struct firmware *fw, 45 int *tablesz) 46{ 47 static struct resource_table table = { .ver = 1, }; 48 49 *tablesz = sizeof(table); 50 return &table; 51} 52EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table); 53 54static int glink_subdev_probe(struct rproc_subdev *subdev) 55{ 56 struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 57 58 glink->edge = qcom_glink_smem_register(glink->dev, glink->node); 59 60 return IS_ERR(glink->edge) ? PTR_ERR(glink->edge) : 0; 61} 62 63static void glink_subdev_remove(struct rproc_subdev *subdev) 64{ 65 struct qcom_rproc_glink *glink = to_glink_subdev(subdev); 66 67 qcom_glink_smem_unregister(glink->edge); 68 glink->edge = NULL; 69} 70 71/** 72 * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc 73 * @rproc: rproc handle to parent the subdevice 74 * @glink: reference to a GLINK subdev context 75 */ 76void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) 77{ 78 struct device *dev = &rproc->dev; 79 80 glink->node = of_get_child_by_name(dev->parent->of_node, "glink-edge"); 81 if (!glink->node) 82 return; 83 84 glink->dev = dev; 85 rproc_add_subdev(rproc, &glink->subdev, glink_subdev_probe, glink_subdev_remove); 86} 87EXPORT_SYMBOL_GPL(qcom_add_glink_subdev); 88 89/** 90 * qcom_remove_glink_subdev() - remove a GLINK subdevice from rproc 91 * @rproc: rproc handle 92 * @glink: reference to a GLINK subdev context 93 */ 94void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink) 95{ 96 rproc_remove_subdev(rproc, &glink->subdev); 97 of_node_put(glink->node); 98} 99EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev); 100 101static int smd_subdev_probe(struct rproc_subdev *subdev) 102{ 103 struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); 104 105 smd->edge = qcom_smd_register_edge(smd->dev, smd->node); 106 107 return PTR_ERR_OR_ZERO(smd->edge); 108} 109 110static void smd_subdev_remove(struct rproc_subdev *subdev) 111{ 112 struct qcom_rproc_subdev *smd = to_smd_subdev(subdev); 113 114 qcom_smd_unregister_edge(smd->edge); 115 smd->edge = NULL; 116} 117 118/** 119 * qcom_add_smd_subdev() - try to add a SMD subdevice to rproc 120 * @rproc: rproc handle to parent the subdevice 121 * @smd: reference to a Qualcomm subdev context 122 */ 123void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) 124{ 125 struct device *dev = &rproc->dev; 126 127 smd->node = of_get_child_by_name(dev->parent->of_node, "smd-edge"); 128 if (!smd->node) 129 return; 130 131 smd->dev = dev; 132 rproc_add_subdev(rproc, &smd->subdev, smd_subdev_probe, smd_subdev_remove); 133} 134EXPORT_SYMBOL_GPL(qcom_add_smd_subdev); 135 136/** 137 * qcom_remove_smd_subdev() - remove the smd subdevice from rproc 138 * @rproc: rproc handle 139 * @smd: the SMD subdevice to remove 140 */ 141void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd) 142{ 143 rproc_remove_subdev(rproc, &smd->subdev); 144 of_node_put(smd->node); 145} 146EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); 147 148/** 149 * qcom_register_ssr_notifier() - register SSR notification handler 150 * @nb: notifier_block to notify for restart notifications 151 * 152 * Returns 0 on success, negative errno on failure. 153 * 154 * This register the @notify function as handler for restart notifications. As 155 * remote processors are stopped this function will be called, with the SSR 156 * name passed as a parameter. 157 */ 158int qcom_register_ssr_notifier(struct notifier_block *nb) 159{ 160 return blocking_notifier_chain_register(&ssr_notifiers, nb); 161} 162EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); 163 164/** 165 * qcom_unregister_ssr_notifier() - unregister SSR notification handler 166 * @nb: notifier_block to unregister 167 */ 168void qcom_unregister_ssr_notifier(struct notifier_block *nb) 169{ 170 blocking_notifier_chain_unregister(&ssr_notifiers, nb); 171} 172EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); 173 174static int ssr_notify_start(struct rproc_subdev *subdev) 175{ 176 return 0; 177} 178 179static void ssr_notify_stop(struct rproc_subdev *subdev) 180{ 181 struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev); 182 183 blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr->name); 184} 185 186/** 187 * qcom_add_ssr_subdev() - register subdevice as restart notification source 188 * @rproc: rproc handle 189 * @ssr: SSR subdevice handle 190 * @ssr_name: identifier to use for notifications originating from @rproc 191 * 192 * As the @ssr is registered with the @rproc SSR events will be sent to all 193 * registered listeners in the system as the remoteproc is shut down. 194 */ 195void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr, 196 const char *ssr_name) 197{ 198 ssr->name = ssr_name; 199 200 rproc_add_subdev(rproc, &ssr->subdev, ssr_notify_start, ssr_notify_stop); 201} 202EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev); 203 204/** 205 * qcom_remove_ssr_subdev() - remove subdevice as restart notification source 206 * @rproc: rproc handle 207 * @ssr: SSR subdevice handle 208 */ 209void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr) 210{ 211 rproc_remove_subdev(rproc, &ssr->subdev); 212} 213EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev); 214 215MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver"); 216MODULE_LICENSE("GPL v2");