Commit | Line | Data |
---|---|---|
bde440ee BA |
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> | |
1e140df0 | 21 | #include <linux/notifier.h> |
bde440ee | 22 | #include <linux/remoteproc.h> |
eea07023 | 23 | #include <linux/rpmsg/qcom_glink.h> |
b90fcfcb | 24 | #include <linux/rpmsg/qcom_smd.h> |
bde440ee BA |
25 | |
26 | #include "remoteproc_internal.h" | |
27 | #include "qcom_common.h" | |
28 | ||
eea07023 | 29 | #define to_glink_subdev(d) container_of(d, struct qcom_rproc_glink, subdev) |
b90fcfcb | 30 | #define to_smd_subdev(d) container_of(d, struct qcom_rproc_subdev, subdev) |
1e140df0 BA |
31 | #define to_ssr_subdev(d) container_of(d, struct qcom_rproc_ssr, subdev) |
32 | ||
4fec0a5a | 33 | static BLOCKING_NOTIFIER_HEAD(ssr_notifiers); |
b90fcfcb | 34 | |
bde440ee BA |
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 | */ | |
43 | struct 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 | } | |
52 | EXPORT_SYMBOL_GPL(qcom_mdt_find_rsc_table); | |
53 | ||
eea07023 BA |
54 | static 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 | ||
63 | static 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 | */ | |
76 | void 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 | } | |
87 | EXPORT_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 | */ | |
94 | void 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 | } | |
99 | EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev); | |
100 | ||
b90fcfcb BA |
101 | static 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 | ||
c76929b3 | 107 | return PTR_ERR_OR_ZERO(smd->edge); |
b90fcfcb BA |
108 | } |
109 | ||
110 | static 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 | */ | |
123 | void 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 | } | |
134 | EXPORT_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 | */ | |
141 | void 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 | } | |
146 | EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev); | |
147 | ||
1e140df0 BA |
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 | */ | |
158 | int qcom_register_ssr_notifier(struct notifier_block *nb) | |
159 | { | |
160 | return blocking_notifier_chain_register(&ssr_notifiers, nb); | |
161 | } | |
162 | EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier); | |
163 | ||
164 | /** | |
165 | * qcom_unregister_ssr_notifier() - unregister SSR notification handler | |
166 | * @nb: notifier_block to unregister | |
167 | */ | |
168 | void qcom_unregister_ssr_notifier(struct notifier_block *nb) | |
169 | { | |
170 | blocking_notifier_chain_unregister(&ssr_notifiers, nb); | |
171 | } | |
172 | EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier); | |
173 | ||
174 | static int ssr_notify_start(struct rproc_subdev *subdev) | |
175 | { | |
176 | return 0; | |
177 | } | |
178 | ||
179 | static 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 | */ | |
195 | void 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 | } | |
202 | EXPORT_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 | */ | |
209 | void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr) | |
210 | { | |
211 | rproc_remove_subdev(rproc, &ssr->subdev); | |
212 | } | |
213 | EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev); | |
214 | ||
bde440ee BA |
215 | MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver"); |
216 | MODULE_LICENSE("GPL v2"); |