1
2
3
4
5#include <dt-bindings/power/qcom-aoss-qmp.h>
6#include <linux/clk-provider.h>
7#include <linux/interrupt.h>
8#include <linux/io.h>
9#include <linux/mailbox_client.h>
10#include <linux/module.h>
11#include <linux/platform_device.h>
12#include <linux/pm_domain.h>
13
14#define QMP_DESC_MAGIC 0x0
15#define QMP_DESC_VERSION 0x4
16#define QMP_DESC_FEATURES 0x8
17
18
19#define QMP_DESC_UCORE_LINK_STATE 0xc
20#define QMP_DESC_UCORE_LINK_STATE_ACK 0x10
21#define QMP_DESC_UCORE_CH_STATE 0x14
22#define QMP_DESC_UCORE_CH_STATE_ACK 0x18
23#define QMP_DESC_UCORE_MBOX_SIZE 0x1c
24#define QMP_DESC_UCORE_MBOX_OFFSET 0x20
25
26
27#define QMP_DESC_MCORE_LINK_STATE 0x24
28#define QMP_DESC_MCORE_LINK_STATE_ACK 0x28
29#define QMP_DESC_MCORE_CH_STATE 0x2c
30#define QMP_DESC_MCORE_CH_STATE_ACK 0x30
31#define QMP_DESC_MCORE_MBOX_SIZE 0x34
32#define QMP_DESC_MCORE_MBOX_OFFSET 0x38
33
34#define QMP_STATE_UP GENMASK(15, 0)
35#define QMP_STATE_DOWN GENMASK(31, 16)
36
37#define QMP_MAGIC 0x4d41494c
38#define QMP_VERSION 1
39
40
41#define QMP_MSG_LEN 64
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56struct qmp {
57 void __iomem *msgram;
58 struct device *dev;
59
60 struct mbox_client mbox_client;
61 struct mbox_chan *mbox_chan;
62
63 size_t offset;
64 size_t size;
65
66 wait_queue_head_t event;
67
68 struct mutex tx_lock;
69
70 struct clk_hw qdss_clk;
71 struct genpd_onecell_data pd_data;
72};
73
74struct qmp_pd {
75 struct qmp *qmp;
76 struct generic_pm_domain pd;
77};
78
79#define to_qmp_pd_resource(res) container_of(res, struct qmp_pd, pd)
80
81static void qmp_kick(struct qmp *qmp)
82{
83 mbox_send_message(qmp->mbox_chan, NULL);
84 mbox_client_txdone(qmp->mbox_chan, 0);
85}
86
87static bool qmp_magic_valid(struct qmp *qmp)
88{
89 return readl(qmp->msgram + QMP_DESC_MAGIC) == QMP_MAGIC;
90}
91
92static bool qmp_link_acked(struct qmp *qmp)
93{
94 return readl(qmp->msgram + QMP_DESC_MCORE_LINK_STATE_ACK) == QMP_STATE_UP;
95}
96
97static bool qmp_mcore_channel_acked(struct qmp *qmp)
98{
99 return readl(qmp->msgram + QMP_DESC_MCORE_CH_STATE_ACK) == QMP_STATE_UP;
100}
101
102static bool qmp_ucore_channel_up(struct qmp *qmp)
103{
104 return readl(qmp->msgram + QMP_DESC_UCORE_CH_STATE) == QMP_STATE_UP;
105}
106
107static int qmp_open(struct qmp *qmp)
108{
109 int ret;
110 u32 val;
111
112 if (!qmp_magic_valid(qmp)) {
113 dev_err(qmp->dev, "QMP magic doesn't match\n");
114 return -EINVAL;
115 }
116
117 val = readl(qmp->msgram + QMP_DESC_VERSION);
118 if (val != QMP_VERSION) {
119 dev_err(qmp->dev, "unsupported QMP version %d\n", val);
120 return -EINVAL;
121 }
122
123 qmp->offset = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_OFFSET);
124 qmp->size = readl(qmp->msgram + QMP_DESC_MCORE_MBOX_SIZE);
125 if (!qmp->size) {
126 dev_err(qmp->dev, "invalid mailbox size\n");
127 return -EINVAL;
128 }
129
130
131 val = readl(qmp->msgram + QMP_DESC_UCORE_LINK_STATE);
132 writel(val, qmp->msgram + QMP_DESC_UCORE_LINK_STATE_ACK);
133
134
135 writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
136
137 qmp_kick(qmp);
138
139 ret = wait_event_timeout(qmp->event, qmp_link_acked(qmp), HZ);
140 if (!ret) {
141 dev_err(qmp->dev, "ucore didn't ack link\n");
142 goto timeout_close_link;
143 }
144
145 writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
146
147 qmp_kick(qmp);
148
149 ret = wait_event_timeout(qmp->event, qmp_ucore_channel_up(qmp), HZ);
150 if (!ret) {
151 dev_err(qmp->dev, "ucore didn't open channel\n");
152 goto timeout_close_channel;
153 }
154
155
156 writel(QMP_STATE_UP, qmp->msgram + QMP_DESC_UCORE_CH_STATE_ACK);
157
158 qmp_kick(qmp);
159
160 ret = wait_event_timeout(qmp->event, qmp_mcore_channel_acked(qmp), HZ);
161 if (!ret) {
162 dev_err(qmp->dev, "ucore didn't ack channel\n");
163 goto timeout_close_channel;
164 }
165
166 return 0;
167
168timeout_close_channel:
169 writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
170
171timeout_close_link:
172 writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
173 qmp_kick(qmp);
174
175 return -ETIMEDOUT;
176}
177
178static void qmp_close(struct qmp *qmp)
179{
180 writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_CH_STATE);
181 writel(QMP_STATE_DOWN, qmp->msgram + QMP_DESC_MCORE_LINK_STATE);
182 qmp_kick(qmp);
183}
184
185static irqreturn_t qmp_intr(int irq, void *data)
186{
187 struct qmp *qmp = data;
188
189 wake_up_interruptible_all(&qmp->event);
190
191 return IRQ_HANDLED;
192}
193
194static bool qmp_message_empty(struct qmp *qmp)
195{
196 return readl(qmp->msgram + qmp->offset) == 0;
197}
198
199
200
201
202
203
204
205
206
207
208
209
210
211static int qmp_send(struct qmp *qmp, const void *data, size_t len)
212{
213 long time_left;
214 int ret;
215
216 if (WARN_ON(len + sizeof(u32) > qmp->size))
217 return -EINVAL;
218
219 if (WARN_ON(len % sizeof(u32)))
220 return -EINVAL;
221
222 mutex_lock(&qmp->tx_lock);
223
224
225 __iowrite32_copy(qmp->msgram + qmp->offset + sizeof(u32),
226 data, len / sizeof(u32));
227 writel(len, qmp->msgram + qmp->offset);
228 qmp_kick(qmp);
229
230 time_left = wait_event_interruptible_timeout(qmp->event,
231 qmp_message_empty(qmp), HZ);
232 if (!time_left) {
233 dev_err(qmp->dev, "ucore did not ack channel\n");
234 ret = -ETIMEDOUT;
235
236
237 writel(0, qmp->msgram + qmp->offset);
238 } else {
239 ret = 0;
240 }
241
242 mutex_unlock(&qmp->tx_lock);
243
244 return ret;
245}
246
247static int qmp_qdss_clk_prepare(struct clk_hw *hw)
248{
249 static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 1}";
250 struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
251
252 return qmp_send(qmp, buf, sizeof(buf));
253}
254
255static void qmp_qdss_clk_unprepare(struct clk_hw *hw)
256{
257 static const char buf[QMP_MSG_LEN] = "{class: clock, res: qdss, val: 0}";
258 struct qmp *qmp = container_of(hw, struct qmp, qdss_clk);
259
260 qmp_send(qmp, buf, sizeof(buf));
261}
262
263static const struct clk_ops qmp_qdss_clk_ops = {
264 .prepare = qmp_qdss_clk_prepare,
265 .unprepare = qmp_qdss_clk_unprepare,
266};
267
268static int qmp_qdss_clk_add(struct qmp *qmp)
269{
270 static const struct clk_init_data qdss_init = {
271 .ops = &qmp_qdss_clk_ops,
272 .name = "qdss",
273 };
274 int ret;
275
276 qmp->qdss_clk.init = &qdss_init;
277 ret = clk_hw_register(qmp->dev, &qmp->qdss_clk);
278 if (ret < 0) {
279 dev_err(qmp->dev, "failed to register qdss clock\n");
280 return ret;
281 }
282
283 ret = of_clk_add_hw_provider(qmp->dev->of_node, of_clk_hw_simple_get,
284 &qmp->qdss_clk);
285 if (ret < 0) {
286 dev_err(qmp->dev, "unable to register of clk hw provider\n");
287 clk_hw_unregister(&qmp->qdss_clk);
288 }
289
290 return ret;
291}
292
293static void qmp_qdss_clk_remove(struct qmp *qmp)
294{
295 of_clk_del_provider(qmp->dev->of_node);
296 clk_hw_unregister(&qmp->qdss_clk);
297}
298
299static int qmp_pd_power_toggle(struct qmp_pd *res, bool enable)
300{
301 char buf[QMP_MSG_LEN] = {};
302
303 snprintf(buf, sizeof(buf),
304 "{class: image, res: load_state, name: %s, val: %s}",
305 res->pd.name, enable ? "on" : "off");
306 return qmp_send(res->qmp, buf, sizeof(buf));
307}
308
309static int qmp_pd_power_on(struct generic_pm_domain *domain)
310{
311 return qmp_pd_power_toggle(to_qmp_pd_resource(domain), true);
312}
313
314static int qmp_pd_power_off(struct generic_pm_domain *domain)
315{
316 return qmp_pd_power_toggle(to_qmp_pd_resource(domain), false);
317}
318
319static const char * const sdm845_resources[] = {
320 [AOSS_QMP_LS_CDSP] = "cdsp",
321 [AOSS_QMP_LS_LPASS] = "adsp",
322 [AOSS_QMP_LS_MODEM] = "modem",
323 [AOSS_QMP_LS_SLPI] = "slpi",
324 [AOSS_QMP_LS_SPSS] = "spss",
325 [AOSS_QMP_LS_VENUS] = "venus",
326};
327
328static int qmp_pd_add(struct qmp *qmp)
329{
330 struct genpd_onecell_data *data = &qmp->pd_data;
331 struct device *dev = qmp->dev;
332 struct qmp_pd *res;
333 size_t num = ARRAY_SIZE(sdm845_resources);
334 int ret;
335 int i;
336
337 res = devm_kcalloc(dev, num, sizeof(*res), GFP_KERNEL);
338 if (!res)
339 return -ENOMEM;
340
341 data->domains = devm_kcalloc(dev, num, sizeof(*data->domains),
342 GFP_KERNEL);
343 if (!data->domains)
344 return -ENOMEM;
345
346 for (i = 0; i < num; i++) {
347 res[i].qmp = qmp;
348 res[i].pd.name = sdm845_resources[i];
349 res[i].pd.power_on = qmp_pd_power_on;
350 res[i].pd.power_off = qmp_pd_power_off;
351
352 ret = pm_genpd_init(&res[i].pd, NULL, true);
353 if (ret < 0) {
354 dev_err(dev, "failed to init genpd\n");
355 goto unroll_genpds;
356 }
357
358 data->domains[i] = &res[i].pd;
359 }
360
361 data->num_domains = i;
362
363 ret = of_genpd_add_provider_onecell(dev->of_node, data);
364 if (ret < 0)
365 goto unroll_genpds;
366
367 return 0;
368
369unroll_genpds:
370 for (i--; i >= 0; i--)
371 pm_genpd_remove(data->domains[i]);
372
373 return ret;
374}
375
376static void qmp_pd_remove(struct qmp *qmp)
377{
378 struct genpd_onecell_data *data = &qmp->pd_data;
379 struct device *dev = qmp->dev;
380 int i;
381
382 of_genpd_del_provider(dev->of_node);
383
384 for (i = 0; i < data->num_domains; i++)
385 pm_genpd_remove(data->domains[i]);
386}
387
388static int qmp_probe(struct platform_device *pdev)
389{
390 struct resource *res;
391 struct qmp *qmp;
392 int irq;
393 int ret;
394
395 qmp = devm_kzalloc(&pdev->dev, sizeof(*qmp), GFP_KERNEL);
396 if (!qmp)
397 return -ENOMEM;
398
399 qmp->dev = &pdev->dev;
400 init_waitqueue_head(&qmp->event);
401 mutex_init(&qmp->tx_lock);
402
403 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
404 qmp->msgram = devm_ioremap_resource(&pdev->dev, res);
405 if (IS_ERR(qmp->msgram))
406 return PTR_ERR(qmp->msgram);
407
408 qmp->mbox_client.dev = &pdev->dev;
409 qmp->mbox_client.knows_txdone = true;
410 qmp->mbox_chan = mbox_request_channel(&qmp->mbox_client, 0);
411 if (IS_ERR(qmp->mbox_chan)) {
412 dev_err(&pdev->dev, "failed to acquire ipc mailbox\n");
413 return PTR_ERR(qmp->mbox_chan);
414 }
415
416 irq = platform_get_irq(pdev, 0);
417 ret = devm_request_irq(&pdev->dev, irq, qmp_intr, IRQF_ONESHOT,
418 "aoss-qmp", qmp);
419 if (ret < 0) {
420 dev_err(&pdev->dev, "failed to request interrupt\n");
421 goto err_free_mbox;
422 }
423
424 ret = qmp_open(qmp);
425 if (ret < 0)
426 goto err_free_mbox;
427
428 ret = qmp_qdss_clk_add(qmp);
429 if (ret)
430 goto err_close_qmp;
431
432 ret = qmp_pd_add(qmp);
433 if (ret)
434 goto err_remove_qdss_clk;
435
436 platform_set_drvdata(pdev, qmp);
437
438 return 0;
439
440err_remove_qdss_clk:
441 qmp_qdss_clk_remove(qmp);
442err_close_qmp:
443 qmp_close(qmp);
444err_free_mbox:
445 mbox_free_channel(qmp->mbox_chan);
446
447 return ret;
448}
449
450static int qmp_remove(struct platform_device *pdev)
451{
452 struct qmp *qmp = platform_get_drvdata(pdev);
453
454 qmp_qdss_clk_remove(qmp);
455 qmp_pd_remove(qmp);
456
457 qmp_close(qmp);
458 mbox_free_channel(qmp->mbox_chan);
459
460 return 0;
461}
462
463static const struct of_device_id qmp_dt_match[] = {
464 { .compatible = "qcom,sdm845-aoss-qmp", },
465 {}
466};
467MODULE_DEVICE_TABLE(of, qmp_dt_match);
468
469static struct platform_driver qmp_driver = {
470 .driver = {
471 .name = "qcom_aoss_qmp",
472 .of_match_table = qmp_dt_match,
473 },
474 .probe = qmp_probe,
475 .remove = qmp_remove,
476};
477module_platform_driver(qmp_driver);
478
479MODULE_DESCRIPTION("Qualcomm AOSS QMP driver");
480MODULE_LICENSE("GPL v2");
481