Merge tag 'rproc-v4.16' of git://github.com/andersson/remoteproc
[linux-2.6-microblaze.git] / drivers / remoteproc / qcom_common.c
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
33 static BLOCKING_NOTIFIER_HEAD(ssr_notifiers);
34
35 static int glink_subdev_probe(struct rproc_subdev *subdev)
36 {
37         struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
38
39         glink->edge = qcom_glink_smem_register(glink->dev, glink->node);
40
41         return PTR_ERR_OR_ZERO(glink->edge);
42 }
43
44 static void glink_subdev_remove(struct rproc_subdev *subdev)
45 {
46         struct qcom_rproc_glink *glink = to_glink_subdev(subdev);
47
48         qcom_glink_smem_unregister(glink->edge);
49         glink->edge = NULL;
50 }
51
52 /**
53  * qcom_add_glink_subdev() - try to add a GLINK subdevice to rproc
54  * @rproc:      rproc handle to parent the subdevice
55  * @glink:      reference to a GLINK subdev context
56  */
57 void qcom_add_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
58 {
59         struct device *dev = &rproc->dev;
60
61         glink->node = of_get_child_by_name(dev->parent->of_node, "glink-edge");
62         if (!glink->node)
63                 return;
64
65         glink->dev = dev;
66         rproc_add_subdev(rproc, &glink->subdev, glink_subdev_probe, glink_subdev_remove);
67 }
68 EXPORT_SYMBOL_GPL(qcom_add_glink_subdev);
69
70 /**
71  * qcom_remove_glink_subdev() - remove a GLINK subdevice from rproc
72  * @rproc:      rproc handle
73  * @glink:      reference to a GLINK subdev context
74  */
75 void qcom_remove_glink_subdev(struct rproc *rproc, struct qcom_rproc_glink *glink)
76 {
77         rproc_remove_subdev(rproc, &glink->subdev);
78         of_node_put(glink->node);
79 }
80 EXPORT_SYMBOL_GPL(qcom_remove_glink_subdev);
81
82 static int smd_subdev_probe(struct rproc_subdev *subdev)
83 {
84         struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
85
86         smd->edge = qcom_smd_register_edge(smd->dev, smd->node);
87
88         return PTR_ERR_OR_ZERO(smd->edge);
89 }
90
91 static void smd_subdev_remove(struct rproc_subdev *subdev)
92 {
93         struct qcom_rproc_subdev *smd = to_smd_subdev(subdev);
94
95         qcom_smd_unregister_edge(smd->edge);
96         smd->edge = NULL;
97 }
98
99 /**
100  * qcom_add_smd_subdev() - try to add a SMD subdevice to rproc
101  * @rproc:      rproc handle to parent the subdevice
102  * @smd:        reference to a Qualcomm subdev context
103  */
104 void qcom_add_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
105 {
106         struct device *dev = &rproc->dev;
107
108         smd->node = of_get_child_by_name(dev->parent->of_node, "smd-edge");
109         if (!smd->node)
110                 return;
111
112         smd->dev = dev;
113         rproc_add_subdev(rproc, &smd->subdev, smd_subdev_probe, smd_subdev_remove);
114 }
115 EXPORT_SYMBOL_GPL(qcom_add_smd_subdev);
116
117 /**
118  * qcom_remove_smd_subdev() - remove the smd subdevice from rproc
119  * @rproc:      rproc handle
120  * @smd:        the SMD subdevice to remove
121  */
122 void qcom_remove_smd_subdev(struct rproc *rproc, struct qcom_rproc_subdev *smd)
123 {
124         rproc_remove_subdev(rproc, &smd->subdev);
125         of_node_put(smd->node);
126 }
127 EXPORT_SYMBOL_GPL(qcom_remove_smd_subdev);
128
129 /**
130  * qcom_register_ssr_notifier() - register SSR notification handler
131  * @nb:         notifier_block to notify for restart notifications
132  *
133  * Returns 0 on success, negative errno on failure.
134  *
135  * This register the @notify function as handler for restart notifications. As
136  * remote processors are stopped this function will be called, with the SSR
137  * name passed as a parameter.
138  */
139 int qcom_register_ssr_notifier(struct notifier_block *nb)
140 {
141         return blocking_notifier_chain_register(&ssr_notifiers, nb);
142 }
143 EXPORT_SYMBOL_GPL(qcom_register_ssr_notifier);
144
145 /**
146  * qcom_unregister_ssr_notifier() - unregister SSR notification handler
147  * @nb:         notifier_block to unregister
148  */
149 void qcom_unregister_ssr_notifier(struct notifier_block *nb)
150 {
151         blocking_notifier_chain_unregister(&ssr_notifiers, nb);
152 }
153 EXPORT_SYMBOL_GPL(qcom_unregister_ssr_notifier);
154
155 static int ssr_notify_start(struct rproc_subdev *subdev)
156 {
157         return  0;
158 }
159
160 static void ssr_notify_stop(struct rproc_subdev *subdev)
161 {
162         struct qcom_rproc_ssr *ssr = to_ssr_subdev(subdev);
163
164         blocking_notifier_call_chain(&ssr_notifiers, 0, (void *)ssr->name);
165 }
166
167 /**
168  * qcom_add_ssr_subdev() - register subdevice as restart notification source
169  * @rproc:      rproc handle
170  * @ssr:        SSR subdevice handle
171  * @ssr_name:   identifier to use for notifications originating from @rproc
172  *
173  * As the @ssr is registered with the @rproc SSR events will be sent to all
174  * registered listeners in the system as the remoteproc is shut down.
175  */
176 void qcom_add_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr,
177                          const char *ssr_name)
178 {
179         ssr->name = ssr_name;
180
181         rproc_add_subdev(rproc, &ssr->subdev, ssr_notify_start, ssr_notify_stop);
182 }
183 EXPORT_SYMBOL_GPL(qcom_add_ssr_subdev);
184
185 /**
186  * qcom_remove_ssr_subdev() - remove subdevice as restart notification source
187  * @rproc:      rproc handle
188  * @ssr:        SSR subdevice handle
189  */
190 void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr)
191 {
192         rproc_remove_subdev(rproc, &ssr->subdev);
193 }
194 EXPORT_SYMBOL_GPL(qcom_remove_ssr_subdev);
195
196 MODULE_DESCRIPTION("Qualcomm Remoteproc helper driver");
197 MODULE_LICENSE("GPL v2");