1// SPDX-License-Identifier: GPL-2.0
2/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. */
3
4#include <linux/err.h>
5#include <linux/init.h>
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <linux/mutex.h>
9#include <linux/pm_domain.h>
10#include <linux/of.h>
11#include <linux/platform_device.h>
12#include <linux/pm_opp.h>
13#include <linux/soc/qcom/smd-rpm.h>
14
15#include <dt-bindings/power/qcom-rpmpd.h>
16
17#define domain_to_rpmpd(domain) container_of(domain, struct rpmpd, pd)
18
19static struct qcom_smd_rpm *rpmpd_smd_rpm;
20
21/* Resource types:
22 * RPMPD_X is X encoded as a little-endian, lower-case, ASCII string */
23#define RPMPD_SMPA 0x61706d73
24#define RPMPD_LDOA 0x616f646c
25#define RPMPD_SMPB 0x62706d73
26#define RPMPD_LDOB 0x626f646c
27#define RPMPD_RWCX 0x78637772
28#define RPMPD_RWMX 0x786d7772
29#define RPMPD_RWLC 0x636c7772
30#define RPMPD_RWLM 0x6d6c7772
31#define RPMPD_RWSC 0x63737772
32#define RPMPD_RWSM 0x6d737772
33#define RPMPD_RWGX 0x78677772
34
35/* Operation Keys */
36#define KEY_CORNER		0x6e726f63 /* corn */
37#define KEY_ENABLE		0x6e657773 /* swen */
38#define KEY_FLOOR_CORNER	0x636676   /* vfc */
39#define KEY_FLOOR_LEVEL		0x6c6676   /* vfl */
40#define KEY_LEVEL		0x6c766c76 /* vlvl */
41
42#define MAX_CORNER_RPMPD_STATE	6
43
44struct rpmpd_req {
45	__le32 key;
46	__le32 nbytes;
47	__le32 value;
48};
49
50struct rpmpd {
51	struct generic_pm_domain pd;
52	struct generic_pm_domain *parent;
53	struct rpmpd *peer;
54	const bool active_only;
55	unsigned int corner;
56	bool enabled;
57	const int res_type;
58	const int res_id;
59	unsigned int max_state;
60	__le32 key;
61	bool state_synced;
62};
63
64struct rpmpd_desc {
65	struct rpmpd **rpmpds;
66	size_t num_pds;
67	unsigned int max_state;
68};
69
70static DEFINE_MUTEX(rpmpd_lock);
71
72/* CX */
73static struct rpmpd cx_rwcx0_lvl_ao;
74static struct rpmpd cx_rwcx0_lvl = {
75	.pd = { .name = "cx", },
76	.peer = &cx_rwcx0_lvl_ao,
77	.res_type = RPMPD_RWCX,
78	.res_id = 0,
79	.key = KEY_LEVEL,
80};
81
82static struct rpmpd cx_rwcx0_lvl_ao = {
83	.pd = { .name = "cx_ao", },
84	.peer = &cx_rwcx0_lvl,
85	.active_only = true,
86	.res_type = RPMPD_RWCX,
87	.res_id = 0,
88	.key = KEY_LEVEL,
89};
90
91static struct rpmpd cx_s1a_corner_ao;
92static struct rpmpd cx_s1a_corner = {
93	.pd = { .name = "cx", },
94	.peer = &cx_s1a_corner_ao,
95	.res_type = RPMPD_SMPA,
96	.res_id = 1,
97	.key = KEY_CORNER,
98};
99
100static struct rpmpd cx_s1a_corner_ao = {
101	.pd = { .name = "cx_ao", },
102	.peer = &cx_s1a_corner,
103	.active_only = true,
104	.res_type = RPMPD_SMPA,
105	.res_id = 1,
106	.key = KEY_CORNER,
107};
108
109static struct rpmpd cx_s1a_lvl_ao;
110static struct rpmpd cx_s1a_lvl = {
111	.pd = { .name = "cx", },
112	.peer = &cx_s1a_lvl_ao,
113	.res_type = RPMPD_SMPA,
114	.res_id = 1,
115	.key = KEY_LEVEL,
116};
117
118static struct rpmpd cx_s1a_lvl_ao = {
119	.pd = { .name = "cx_ao", },
120	.peer = &cx_s1a_lvl,
121	.active_only = true,
122	.res_type = RPMPD_SMPA,
123	.res_id = 1,
124	.key = KEY_LEVEL,
125};
126
127static struct rpmpd cx_s2a_corner_ao;
128static struct rpmpd cx_s2a_corner = {
129	.pd = { .name = "cx", },
130	.peer = &cx_s2a_corner_ao,
131	.res_type = RPMPD_SMPA,
132	.res_id = 2,
133	.key = KEY_CORNER,
134};
135
136static struct rpmpd cx_s2a_corner_ao = {
137	.pd = { .name = "cx_ao", },
138	.peer = &cx_s2a_corner,
139	.active_only = true,
140	.res_type = RPMPD_SMPA,
141	.res_id = 2,
142	.key = KEY_CORNER,
143};
144
145static struct rpmpd cx_s2a_lvl_ao;
146static struct rpmpd cx_s2a_lvl = {
147	.pd = { .name = "cx", },
148	.peer = &cx_s2a_lvl_ao,
149	.res_type = RPMPD_SMPA,
150	.res_id = 2,
151	.key = KEY_LEVEL,
152};
153
154static struct rpmpd cx_s2a_lvl_ao = {
155	.pd = { .name = "cx_ao", },
156	.peer = &cx_s2a_lvl,
157	.active_only = true,
158	.res_type = RPMPD_SMPA,
159	.res_id = 2,
160	.key = KEY_LEVEL,
161};
162
163static struct rpmpd cx_s3a_lvl_ao;
164static struct rpmpd cx_s3a_lvl = {
165	.pd = { .name = "cx", },
166	.peer = &cx_s3a_lvl_ao,
167	.res_type = RPMPD_SMPA,
168	.res_id = 3,
169	.key = KEY_LEVEL,
170};
171
172static struct rpmpd cx_s3a_lvl_ao = {
173	.pd = { .name = "cx_ao", },
174	.peer = &cx_s3a_lvl,
175	.active_only = true,
176	.res_type = RPMPD_SMPA,
177	.res_id = 3,
178	.key = KEY_LEVEL,
179};
180
181static struct rpmpd cx_rwcx0_vfl = {
182	.pd = { .name = "cx_vfl", },
183	.res_type = RPMPD_RWCX,
184	.res_id = 0,
185	.key = KEY_FLOOR_LEVEL,
186};
187
188static struct rpmpd cx_rwsc2_vfl = {
189	.pd = { .name = "cx_vfl", },
190	.res_type = RPMPD_RWSC,
191	.res_id = 2,
192	.key = KEY_FLOOR_LEVEL,
193};
194
195static struct rpmpd cx_s1a_vfc = {
196	.pd = { .name = "cx_vfc", },
197	.res_type = RPMPD_SMPA,
198	.res_id = 1,
199	.key = KEY_FLOOR_CORNER,
200};
201
202static struct rpmpd cx_s1a_vfl = {
203	.pd = { .name = "cx_vfl", },
204	.res_type = RPMPD_SMPA,
205	.res_id = 1,
206	.key = KEY_FLOOR_LEVEL,
207};
208
209static struct rpmpd cx_s2a_vfc = {
210	.pd = { .name = "cx_vfc", },
211	.res_type = RPMPD_SMPA,
212	.res_id = 2,
213	.key = KEY_FLOOR_CORNER,
214};
215
216static struct rpmpd cx_s2a_vfl = {
217	.pd = { .name = "cx_vfl", },
218	.res_type = RPMPD_SMPA,
219	.res_id = 2,
220	.key = KEY_FLOOR_LEVEL,
221};
222
223static struct rpmpd cx_s3a_vfl = {
224	.pd = { .name = "cx_vfl", },
225	.res_type = RPMPD_SMPA,
226	.res_id = 3,
227	.key = KEY_FLOOR_LEVEL,
228};
229
230static struct rpmpd cx_s2b_corner_ao;
231static struct rpmpd cx_s2b_corner = {
232	.pd = { .name = "cx", },
233	.peer = &cx_s2b_corner_ao,
234	.res_type = RPMPD_SMPB,
235	.res_id = 2,
236	.key = KEY_CORNER,
237};
238
239static struct rpmpd cx_s2b_corner_ao = {
240	.pd = { .name = "cx_ao", },
241	.peer = &cx_s2b_corner,
242	.active_only = true,
243	.res_type = RPMPD_SMPB,
244	.res_id = 2,
245	.key = KEY_CORNER,
246};
247
248static struct rpmpd cx_s2b_vfc = {
249	.pd = { .name = "cx_vfc", },
250	.res_type = RPMPD_SMPB,
251	.res_id = 2,
252	.key = KEY_FLOOR_CORNER,
253};
254
255/* G(F)X */
256static struct rpmpd gfx_s7a_corner = {
257	.pd = { .name = "gfx", },
258	.res_type = RPMPD_SMPA,
259	.res_id = 7,
260	.key = KEY_CORNER,
261};
262
263static struct rpmpd gfx_s7a_vfc = {
264	.pd = { .name = "gfx_vfc", },
265	.res_type = RPMPD_SMPA,
266	.res_id = 7,
267	.key = KEY_FLOOR_CORNER,
268};
269
270static struct rpmpd gfx_s2b_corner = {
271	.pd = { .name = "gfx", },
272	.res_type = RPMPD_SMPB,
273	.res_id = 2,
274	.key = KEY_CORNER,
275};
276
277static struct rpmpd gfx_s2b_vfc = {
278	.pd = { .name = "gfx_vfc", },
279	.res_type = RPMPD_SMPB,
280	.res_id = 2,
281	.key = KEY_FLOOR_CORNER,
282};
283
284static struct rpmpd gfx_s4b_corner = {
285	.pd = { .name = "gfx", },
286	.res_type = RPMPD_SMPB,
287	.res_id = 4,
288	.key = KEY_CORNER,
289};
290
291static struct rpmpd gfx_s4b_vfc = {
292	.pd = { .name = "gfx_vfc", },
293	.res_type = RPMPD_SMPB,
294	.res_id = 4,
295	.key = KEY_FLOOR_CORNER,
296};
297
298static struct rpmpd mx_rwmx0_lvl;
299static struct rpmpd gx_rwgx0_lvl_ao;
300static struct rpmpd gx_rwgx0_lvl = {
301	.pd = { .name = "gx", },
302	.peer = &gx_rwgx0_lvl_ao,
303	.res_type = RPMPD_RWGX,
304	.parent = &mx_rwmx0_lvl.pd,
305	.res_id = 0,
306	.key = KEY_LEVEL,
307};
308
309static struct rpmpd mx_rwmx0_lvl_ao;
310static struct rpmpd gx_rwgx0_lvl_ao = {
311	.pd = { .name = "gx_ao", },
312	.peer = &gx_rwgx0_lvl,
313	.parent = &mx_rwmx0_lvl_ao.pd,
314	.active_only = true,
315	.res_type = RPMPD_RWGX,
316	.res_id = 0,
317	.key = KEY_LEVEL,
318};
319
320/* MX */
321static struct rpmpd mx_l2a_lvl_ao;
322static struct rpmpd mx_l2a_lvl = {
323	.pd = { .name = "mx", },
324	.peer = &mx_l2a_lvl_ao,
325	.res_type = RPMPD_LDOA,
326	.res_id = 2,
327	.key = KEY_LEVEL,
328};
329
330static struct rpmpd mx_l2a_lvl_ao = {
331	.pd = { .name = "mx_ao", },
332	.peer = &mx_l2a_lvl,
333	.active_only = true,
334	.res_type = RPMPD_LDOA,
335	.res_id = 2,
336	.key = KEY_LEVEL,
337};
338
339static struct rpmpd mx_l3a_corner_ao;
340static struct rpmpd mx_l3a_corner = {
341	.pd = { .name = "mx", },
342	.peer = &mx_l3a_corner_ao,
343	.res_type = RPMPD_LDOA,
344	.res_id = 3,
345	.key = KEY_CORNER,
346};
347
348static struct rpmpd mx_l3a_corner_ao = {
349	.pd = { .name = "mx_ao", },
350	.peer = &mx_l3a_corner,
351	.active_only = true,
352	.res_type = RPMPD_LDOA,
353	.res_id = 3,
354	.key = KEY_CORNER,
355};
356
357static struct rpmpd mx_l3a_lvl_ao;
358static struct rpmpd mx_l3a_lvl = {
359	.pd = { .name = "mx", },
360	.peer = &mx_l3a_lvl_ao,
361	.res_type = RPMPD_LDOA,
362	.res_id = 3,
363	.key = KEY_LEVEL,
364};
365
366static struct rpmpd mx_l3a_lvl_ao = {
367	.pd = { .name = "mx_ao", },
368	.peer = &mx_l3a_lvl,
369	.active_only = true,
370	.res_type = RPMPD_LDOA,
371	.res_id = 3,
372	.key = KEY_LEVEL,
373};
374
375static struct rpmpd mx_l12a_lvl_ao;
376static struct rpmpd mx_l12a_lvl = {
377	.pd = { .name = "mx", },
378	.peer = &mx_l12a_lvl_ao,
379	.res_type = RPMPD_LDOA,
380	.res_id = 12,
381	.key = KEY_LEVEL,
382};
383
384static struct rpmpd mx_l12a_lvl_ao = {
385	.pd = { .name = "mx_ao", },
386	.peer = &mx_l12a_lvl,
387	.active_only = true,
388	.res_type = RPMPD_LDOA,
389	.res_id = 12,
390	.key = KEY_LEVEL,
391};
392
393static struct rpmpd mx_s2a_corner_ao;
394static struct rpmpd mx_s2a_corner = {
395	.pd = { .name = "mx", },
396	.peer = &mx_s2a_corner_ao,
397	.res_type = RPMPD_SMPA,
398	.res_id = 2,
399	.key = KEY_CORNER,
400};
401
402static struct rpmpd mx_s2a_corner_ao = {
403	.pd = { .name = "mx_ao", },
404	.peer = &mx_s2a_corner,
405	.active_only = true,
406	.res_type = RPMPD_SMPA,
407	.res_id = 2,
408	.key = KEY_CORNER,
409};
410
411static struct rpmpd mx_rwmx0_lvl_ao;
412static struct rpmpd mx_rwmx0_lvl = {
413	.pd = { .name = "mx", },
414	.peer = &mx_rwmx0_lvl_ao,
415	.res_type = RPMPD_RWMX,
416	.res_id = 0,
417	.key = KEY_LEVEL,
418};
419
420static struct rpmpd mx_rwmx0_lvl_ao = {
421	.pd = { .name = "mx_ao", },
422	.peer = &mx_rwmx0_lvl,
423	.active_only = true,
424	.res_type = RPMPD_RWMX,
425	.res_id = 0,
426	.key = KEY_LEVEL,
427};
428
429static struct rpmpd mx_s6a_lvl_ao;
430static struct rpmpd mx_s6a_lvl = {
431	.pd = { .name = "mx", },
432	.peer = &mx_s6a_lvl_ao,
433	.res_type = RPMPD_SMPA,
434	.res_id = 6,
435	.key = KEY_LEVEL,
436};
437
438static struct rpmpd mx_s6a_lvl_ao = {
439	.pd = { .name = "mx_ao", },
440	.peer = &mx_s6a_lvl,
441	.active_only = true,
442	.res_type = RPMPD_SMPA,
443	.res_id = 6,
444	.key = KEY_LEVEL,
445};
446
447static struct rpmpd mx_s7a_lvl_ao;
448static struct rpmpd mx_s7a_lvl = {
449	.pd = { .name = "mx", },
450	.peer = &mx_s7a_lvl_ao,
451	.res_type = RPMPD_SMPA,
452	.res_id = 7,
453	.key = KEY_LEVEL,
454};
455
456static struct rpmpd mx_s7a_lvl_ao = {
457	.pd = { .name = "mx_ao", },
458	.peer = &mx_s7a_lvl,
459	.active_only = true,
460	.res_type = RPMPD_SMPA,
461	.res_id = 7,
462	.key = KEY_LEVEL,
463};
464
465static struct rpmpd mx_l12a_vfl = {
466	.pd = { .name = "mx_vfl", },
467	.res_type = RPMPD_LDOA,
468	.res_id = 12,
469	.key = KEY_FLOOR_LEVEL,
470};
471
472static struct rpmpd mx_rwmx0_vfl = {
473	.pd = { .name = "mx_vfl", },
474	.res_type = RPMPD_RWMX,
475	.res_id = 0,
476	.key = KEY_FLOOR_LEVEL,
477};
478
479static struct rpmpd mx_rwsm6_vfl = {
480	.pd = { .name = "mx_vfl", },
481	.res_type = RPMPD_RWSM,
482	.res_id = 6,
483	.key = KEY_FLOOR_LEVEL,
484};
485
486/* MD */
487static struct rpmpd md_s1a_corner_ao;
488static struct rpmpd md_s1a_corner = {
489	.pd = { .name = "md", },
490	.peer = &md_s1a_corner_ao,
491	.res_type = RPMPD_SMPA,
492	.res_id = 1,
493	.key = KEY_CORNER,
494};
495
496static struct rpmpd md_s1a_corner_ao = {
497	.pd = { .name = "md_ao", },
498	.peer = &md_s1a_corner,
499	.active_only = true,
500	.res_type = RPMPD_SMPA,
501	.res_id = 1,
502	.key = KEY_CORNER,
503};
504
505static struct rpmpd md_s1a_lvl_ao;
506static struct rpmpd md_s1a_lvl = {
507	.pd = { .name = "md", },
508	.peer = &md_s1a_lvl_ao,
509	.res_type = RPMPD_SMPA,
510	.res_id = 1,
511	.key = KEY_LEVEL,
512};
513
514static struct rpmpd md_s1a_lvl_ao = {
515	.pd = { .name = "md_ao", },
516	.peer = &md_s1a_lvl,
517	.active_only = true,
518	.res_type = RPMPD_SMPA,
519	.res_id = 1,
520	.key = KEY_LEVEL,
521};
522
523static struct rpmpd md_s1a_vfc = {
524	.pd = { .name = "md_vfc", },
525	.res_type = RPMPD_SMPA,
526	.res_id = 1,
527	.key = KEY_FLOOR_CORNER,
528};
529
530/* LPI_CX */
531static struct rpmpd lpi_cx_rwlc0_lvl = {
532	.pd = { .name = "lpi_cx", },
533	.res_type = RPMPD_RWLC,
534	.res_id = 0,
535	.key = KEY_LEVEL,
536};
537
538static struct rpmpd lpi_cx_rwlc0_vfl = {
539	.pd = { .name = "lpi_cx_vfl", },
540	.res_type = RPMPD_RWLC,
541	.res_id = 0,
542	.key = KEY_FLOOR_LEVEL,
543};
544
545/* LPI_MX */
546static struct rpmpd lpi_mx_rwlm0_lvl = {
547	.pd = { .name = "lpi_mx", },
548	.res_type = RPMPD_RWLM,
549	.res_id = 0,
550	.key = KEY_LEVEL,
551};
552
553static struct rpmpd lpi_mx_rwlm0_vfl = {
554	.pd = { .name = "lpi_mx_vfl", },
555	.res_type = RPMPD_RWLM,
556	.res_id = 0,
557	.key = KEY_FLOOR_LEVEL,
558};
559
560/* SSC_CX */
561static struct rpmpd ssc_cx_l26a_corner = {
562	.pd = { .name = "ssc_cx", },
563	.res_type = RPMPD_LDOA,
564	.res_id = 26,
565	.key = KEY_CORNER,
566};
567
568static struct rpmpd ssc_cx_rwlc0_lvl = {
569	.pd = { .name = "ssc_cx", },
570	.res_type = RPMPD_RWLC,
571	.res_id = 0,
572	.key = KEY_LEVEL,
573};
574
575static struct rpmpd ssc_cx_rwsc0_lvl = {
576	.pd = { .name = "ssc_cx", },
577	.res_type = RPMPD_RWSC,
578	.res_id = 0,
579	.key = KEY_LEVEL,
580};
581
582static struct rpmpd ssc_cx_l26a_vfc = {
583	.pd = { .name = "ssc_cx_vfc", },
584	.res_type = RPMPD_LDOA,
585	.res_id = 26,
586	.key = KEY_FLOOR_CORNER,
587};
588
589static struct rpmpd ssc_cx_rwlc0_vfl = {
590	.pd = { .name = "ssc_cx_vfl", },
591	.res_type = RPMPD_RWLC,
592	.res_id = 0,
593	.key = KEY_FLOOR_LEVEL,
594};
595
596static struct rpmpd ssc_cx_rwsc0_vfl = {
597	.pd = { .name = "ssc_cx_vfl", },
598	.res_type = RPMPD_RWSC,
599	.res_id = 0,
600	.key = KEY_FLOOR_LEVEL,
601};
602
603/* SSC_MX */
604static struct rpmpd ssc_mx_rwlm0_lvl = {
605	.pd = { .name = "ssc_mx", },
606	.res_type = RPMPD_RWLM,
607	.res_id = 0,
608	.key = KEY_LEVEL,
609};
610
611static struct rpmpd ssc_mx_rwsm0_lvl = {
612	.pd = { .name = "ssc_mx", },
613	.res_type = RPMPD_RWSM,
614	.res_id = 0,
615	.key = KEY_LEVEL,
616};
617
618static struct rpmpd ssc_mx_rwlm0_vfl = {
619	.pd = { .name = "ssc_mx_vfl", },
620	.res_type = RPMPD_RWLM,
621	.res_id = 0,
622	.key = KEY_FLOOR_LEVEL,
623};
624
625static struct rpmpd ssc_mx_rwsm0_vfl = {
626	.pd = { .name = "ssc_mx_vfl", },
627	.res_type = RPMPD_RWSM,
628	.res_id = 0,
629	.key = KEY_FLOOR_LEVEL,
630};
631
632static struct rpmpd *mdm9607_rpmpds[] = {
633	[MDM9607_VDDCX] =	&cx_s3a_lvl,
634	[MDM9607_VDDCX_AO] =	&cx_s3a_lvl_ao,
635	[MDM9607_VDDCX_VFL] =	&cx_s3a_vfl,
636	[MDM9607_VDDMX] =	&mx_l12a_lvl,
637	[MDM9607_VDDMX_AO] =	&mx_l12a_lvl_ao,
638	[MDM9607_VDDMX_VFL] =	&mx_l12a_vfl,
639};
640
641static const struct rpmpd_desc mdm9607_desc = {
642	.rpmpds = mdm9607_rpmpds,
643	.num_pds = ARRAY_SIZE(mdm9607_rpmpds),
644	.max_state = RPM_SMD_LEVEL_TURBO,
645};
646
647static struct rpmpd *msm8226_rpmpds[] = {
648	[MSM8226_VDDCX] =	&cx_s1a_corner,
649	[MSM8226_VDDCX_AO] =	&cx_s1a_corner_ao,
650	[MSM8226_VDDCX_VFC] =	&cx_s1a_vfc,
651};
652
653static const struct rpmpd_desc msm8226_desc = {
654	.rpmpds = msm8226_rpmpds,
655	.num_pds = ARRAY_SIZE(msm8226_rpmpds),
656	.max_state = MAX_CORNER_RPMPD_STATE,
657};
658
659static struct rpmpd *msm8939_rpmpds[] = {
660	[MSM8939_VDDMDCX] =	&md_s1a_corner,
661	[MSM8939_VDDMDCX_AO] =	&md_s1a_corner_ao,
662	[MSM8939_VDDMDCX_VFC] =	&md_s1a_vfc,
663	[MSM8939_VDDCX] =	&cx_s2a_corner,
664	[MSM8939_VDDCX_AO] =	&cx_s2a_corner_ao,
665	[MSM8939_VDDCX_VFC] =	&cx_s2a_vfc,
666	[MSM8939_VDDMX] =	&mx_l3a_corner,
667	[MSM8939_VDDMX_AO] =	&mx_l3a_corner_ao,
668};
669
670static const struct rpmpd_desc msm8939_desc = {
671	.rpmpds = msm8939_rpmpds,
672	.num_pds = ARRAY_SIZE(msm8939_rpmpds),
673	.max_state = MAX_CORNER_RPMPD_STATE,
674};
675
676static struct rpmpd *msm8916_rpmpds[] = {
677	[MSM8916_VDDCX] =	&cx_s1a_corner,
678	[MSM8916_VDDCX_AO] =	&cx_s1a_corner_ao,
679	[MSM8916_VDDCX_VFC] =	&cx_s1a_vfc,
680	[MSM8916_VDDMX] =	&mx_l3a_corner,
681	[MSM8916_VDDMX_AO] =	&mx_l3a_corner_ao,
682};
683
684static const struct rpmpd_desc msm8916_desc = {
685	.rpmpds = msm8916_rpmpds,
686	.num_pds = ARRAY_SIZE(msm8916_rpmpds),
687	.max_state = MAX_CORNER_RPMPD_STATE,
688};
689
690static struct rpmpd *msm8917_rpmpds[] = {
691	[MSM8917_VDDCX] =	&cx_s2a_lvl,
692	[MSM8917_VDDCX_AO] =	&cx_s2a_lvl_ao,
693	[MSM8917_VDDCX_VFL] =	&cx_s2a_vfl,
694	[MSM8917_VDDMX] =	&mx_l3a_lvl,
695	[MSM8917_VDDMX_AO] =	&mx_l3a_lvl_ao,
696};
697
698static const struct rpmpd_desc msm8917_desc = {
699	.rpmpds = msm8917_rpmpds,
700	.num_pds = ARRAY_SIZE(msm8917_rpmpds),
701	.max_state = RPM_SMD_LEVEL_TURBO,
702};
703
704static struct rpmpd *msm8953_rpmpds[] = {
705	[MSM8953_VDDMD] =	&md_s1a_lvl,
706	[MSM8953_VDDMD_AO] =	&md_s1a_lvl_ao,
707	[MSM8953_VDDCX] =	&cx_s2a_lvl,
708	[MSM8953_VDDCX_AO] =	&cx_s2a_lvl_ao,
709	[MSM8953_VDDCX_VFL] =	&cx_s2a_vfl,
710	[MSM8953_VDDMX] =	&mx_s7a_lvl,
711	[MSM8953_VDDMX_AO] =	&mx_s7a_lvl_ao,
712};
713
714static const struct rpmpd_desc msm8953_desc = {
715	.rpmpds = msm8953_rpmpds,
716	.num_pds = ARRAY_SIZE(msm8953_rpmpds),
717	.max_state = RPM_SMD_LEVEL_TURBO,
718};
719
720static struct rpmpd *msm8974_rpmpds[] = {
721	[MSM8974_VDDCX] =	&cx_s2b_corner,
722	[MSM8974_VDDCX_AO] =	&cx_s2b_corner_ao,
723	[MSM8974_VDDCX_VFC] =	&cx_s2b_vfc,
724	[MSM8974_VDDGFX] =	&gfx_s4b_corner,
725	[MSM8974_VDDGFX_VFC] =	&gfx_s4b_vfc,
726};
727
728static const struct rpmpd_desc msm8974_desc = {
729	.rpmpds = msm8974_rpmpds,
730	.num_pds = ARRAY_SIZE(msm8974_rpmpds),
731	.max_state = MAX_CORNER_RPMPD_STATE,
732};
733
734static struct rpmpd *msm8974pro_pma8084_rpmpds[] = {
735	[MSM8974_VDDCX] =	&cx_s2a_corner,
736	[MSM8974_VDDCX_AO] =	&cx_s2a_corner_ao,
737	[MSM8974_VDDCX_VFC] =	&cx_s2a_vfc,
738	[MSM8974_VDDGFX] =	&gfx_s7a_corner,
739	[MSM8974_VDDGFX_VFC] =	&gfx_s7a_vfc,
740};
741
742static const struct rpmpd_desc msm8974pro_pma8084_desc = {
743	.rpmpds = msm8974pro_pma8084_rpmpds,
744	.num_pds = ARRAY_SIZE(msm8974pro_pma8084_rpmpds),
745	.max_state = MAX_CORNER_RPMPD_STATE,
746};
747
748static struct rpmpd *msm8976_rpmpds[] = {
749	[MSM8976_VDDCX] =	&cx_s2a_lvl,
750	[MSM8976_VDDCX_AO] =	&cx_s2a_lvl_ao,
751	[MSM8976_VDDCX_VFL] =	&cx_rwsc2_vfl,
752	[MSM8976_VDDMX] =	&mx_s6a_lvl,
753	[MSM8976_VDDMX_AO] =	&mx_s6a_lvl_ao,
754	[MSM8976_VDDMX_VFL] =	&mx_rwsm6_vfl,
755};
756
757static const struct rpmpd_desc msm8976_desc = {
758	.rpmpds = msm8976_rpmpds,
759	.num_pds = ARRAY_SIZE(msm8976_rpmpds),
760	.max_state = RPM_SMD_LEVEL_TURBO_HIGH,
761};
762
763static struct rpmpd *msm8994_rpmpds[] = {
764	[MSM8994_VDDCX] =	&cx_s1a_corner,
765	[MSM8994_VDDCX_AO] =	&cx_s1a_corner_ao,
766	[MSM8994_VDDCX_VFC] =	&cx_s1a_vfc,
767	[MSM8994_VDDMX] =	&mx_s2a_corner,
768	[MSM8994_VDDMX_AO] =	&mx_s2a_corner_ao,
769
770	/* Attention! *Some* 8994 boards with pm8004 may use SMPC here! */
771	[MSM8994_VDDGFX] =	&gfx_s2b_corner,
772	[MSM8994_VDDGFX_VFC] =	&gfx_s2b_vfc,
773};
774
775static const struct rpmpd_desc msm8994_desc = {
776	.rpmpds = msm8994_rpmpds,
777	.num_pds = ARRAY_SIZE(msm8994_rpmpds),
778	.max_state = MAX_CORNER_RPMPD_STATE,
779};
780
781static struct rpmpd *msm8996_rpmpds[] = {
782	[MSM8996_VDDCX] =	&cx_s1a_corner,
783	[MSM8996_VDDCX_AO] =	&cx_s1a_corner_ao,
784	[MSM8996_VDDCX_VFC] =	&cx_s1a_vfc,
785	[MSM8996_VDDMX] =	&mx_s2a_corner,
786	[MSM8996_VDDMX_AO] =	&mx_s2a_corner_ao,
787	[MSM8996_VDDSSCX] =	&ssc_cx_l26a_corner,
788	[MSM8996_VDDSSCX_VFC] =	&ssc_cx_l26a_vfc,
789};
790
791static const struct rpmpd_desc msm8996_desc = {
792	.rpmpds = msm8996_rpmpds,
793	.num_pds = ARRAY_SIZE(msm8996_rpmpds),
794	.max_state = MAX_CORNER_RPMPD_STATE,
795};
796
797static struct rpmpd *msm8998_rpmpds[] = {
798	[MSM8998_VDDCX] =	&cx_rwcx0_lvl,
799	[MSM8998_VDDCX_AO] =	&cx_rwcx0_lvl_ao,
800	[MSM8998_VDDCX_VFL] =	&cx_rwcx0_vfl,
801	[MSM8998_VDDMX] =	&mx_rwmx0_lvl,
802	[MSM8998_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
803	[MSM8998_VDDMX_VFL] =	&mx_rwmx0_vfl,
804	[MSM8998_SSCCX] =	&ssc_cx_rwsc0_lvl,
805	[MSM8998_SSCCX_VFL] =	&ssc_cx_rwsc0_vfl,
806	[MSM8998_SSCMX] =	&ssc_mx_rwsm0_lvl,
807	[MSM8998_SSCMX_VFL] =	&ssc_mx_rwsm0_vfl,
808};
809
810static const struct rpmpd_desc msm8998_desc = {
811	.rpmpds = msm8998_rpmpds,
812	.num_pds = ARRAY_SIZE(msm8998_rpmpds),
813	.max_state = RPM_SMD_LEVEL_BINNING,
814};
815
816static struct rpmpd *qcs404_rpmpds[] = {
817	[QCS404_VDDMX] =	&mx_rwmx0_lvl,
818	[QCS404_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
819	[QCS404_VDDMX_VFL] =	&mx_rwmx0_vfl,
820	[QCS404_LPICX] =	&lpi_cx_rwlc0_lvl,
821	[QCS404_LPICX_VFL] =	&lpi_cx_rwlc0_vfl,
822	[QCS404_LPIMX] =	&lpi_mx_rwlm0_lvl,
823	[QCS404_LPIMX_VFL] =	&lpi_mx_rwlm0_vfl,
824};
825
826static const struct rpmpd_desc qcs404_desc = {
827	.rpmpds = qcs404_rpmpds,
828	.num_pds = ARRAY_SIZE(qcs404_rpmpds),
829	.max_state = RPM_SMD_LEVEL_BINNING,
830};
831
832static struct rpmpd *qm215_rpmpds[] = {
833	[QM215_VDDCX] =		&cx_s1a_lvl,
834	[QM215_VDDCX_AO] =	&cx_s1a_lvl_ao,
835	[QM215_VDDCX_VFL] =	&cx_s1a_vfl,
836	[QM215_VDDMX] =		&mx_l2a_lvl,
837	[QM215_VDDMX_AO] =	&mx_l2a_lvl_ao,
838};
839
840static const struct rpmpd_desc qm215_desc = {
841	.rpmpds = qm215_rpmpds,
842	.num_pds = ARRAY_SIZE(qm215_rpmpds),
843	.max_state = RPM_SMD_LEVEL_TURBO,
844};
845
846static struct rpmpd *sdm660_rpmpds[] = {
847	[SDM660_VDDCX] =	&cx_rwcx0_lvl,
848	[SDM660_VDDCX_AO] =	&cx_rwcx0_lvl_ao,
849	[SDM660_VDDCX_VFL] =	&cx_rwcx0_vfl,
850	[SDM660_VDDMX] =	&mx_rwmx0_lvl,
851	[SDM660_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
852	[SDM660_VDDMX_VFL] =	&mx_rwmx0_vfl,
853	[SDM660_SSCCX] =	&ssc_cx_rwlc0_lvl,
854	[SDM660_SSCCX_VFL] =	&ssc_cx_rwlc0_vfl,
855	[SDM660_SSCMX] =	&ssc_mx_rwlm0_lvl,
856	[SDM660_SSCMX_VFL] =	&ssc_mx_rwlm0_vfl,
857};
858
859static const struct rpmpd_desc sdm660_desc = {
860	.rpmpds = sdm660_rpmpds,
861	.num_pds = ARRAY_SIZE(sdm660_rpmpds),
862	.max_state = RPM_SMD_LEVEL_TURBO,
863};
864
865static struct rpmpd *sm6115_rpmpds[] = {
866	[SM6115_VDDCX] =	&cx_rwcx0_lvl,
867	[SM6115_VDDCX_AO] =	&cx_rwcx0_lvl_ao,
868	[SM6115_VDDCX_VFL] =	&cx_rwcx0_vfl,
869	[SM6115_VDDMX] =	&mx_rwmx0_lvl,
870	[SM6115_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
871	[SM6115_VDDMX_VFL] =	&mx_rwmx0_vfl,
872	[SM6115_VDD_LPI_CX] =	&lpi_cx_rwlc0_lvl,
873	[SM6115_VDD_LPI_MX] =	&lpi_mx_rwlm0_lvl,
874};
875
876static const struct rpmpd_desc sm6115_desc = {
877	.rpmpds = sm6115_rpmpds,
878	.num_pds = ARRAY_SIZE(sm6115_rpmpds),
879	.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
880};
881
882static struct rpmpd *sm6125_rpmpds[] = {
883	[SM6125_VDDCX] =	&cx_rwcx0_lvl,
884	[SM6125_VDDCX_AO] =	&cx_rwcx0_lvl_ao,
885	[SM6125_VDDCX_VFL] =	&cx_rwcx0_vfl,
886	[SM6125_VDDMX] =	&mx_rwmx0_lvl,
887	[SM6125_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
888	[SM6125_VDDMX_VFL] =	&mx_rwmx0_vfl,
889};
890
891static const struct rpmpd_desc sm6125_desc = {
892	.rpmpds = sm6125_rpmpds,
893	.num_pds = ARRAY_SIZE(sm6125_rpmpds),
894	.max_state = RPM_SMD_LEVEL_BINNING,
895};
896
897static struct rpmpd *sm6375_rpmpds[] = {
898	[SM6375_VDDCX] =	&cx_rwcx0_lvl,
899	[SM6375_VDDCX_AO] =	&cx_rwcx0_lvl_ao,
900	[SM6375_VDDCX_VFL] =	&cx_rwcx0_vfl,
901	[SM6375_VDDMX] =	&mx_rwmx0_lvl,
902	[SM6375_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
903	[SM6375_VDDMX_VFL] =	&mx_rwmx0_vfl,
904	[SM6375_VDDGX] =	&gx_rwgx0_lvl,
905	[SM6375_VDDGX_AO] =	&gx_rwgx0_lvl_ao,
906	[SM6375_VDD_LPI_CX] =	&lpi_cx_rwlc0_lvl,
907	[SM6375_VDD_LPI_MX] =	&lpi_mx_rwlm0_lvl,
908};
909
910static const struct rpmpd_desc sm6375_desc = {
911	.rpmpds = sm6375_rpmpds,
912	.num_pds = ARRAY_SIZE(sm6375_rpmpds),
913	.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
914};
915
916static struct rpmpd *qcm2290_rpmpds[] = {
917	[QCM2290_VDDCX] =	&cx_rwcx0_lvl,
918	[QCM2290_VDDCX_AO] =	&cx_rwcx0_lvl_ao,
919	[QCM2290_VDDCX_VFL] =	&cx_rwcx0_vfl,
920	[QCM2290_VDDMX] =	&mx_rwmx0_lvl,
921	[QCM2290_VDDMX_AO] =	&mx_rwmx0_lvl_ao,
922	[QCM2290_VDDMX_VFL] =	&mx_rwmx0_vfl,
923	[QCM2290_VDD_LPI_CX] =	&lpi_cx_rwlc0_lvl,
924	[QCM2290_VDD_LPI_MX] =	&lpi_mx_rwlm0_lvl,
925};
926
927static const struct rpmpd_desc qcm2290_desc = {
928	.rpmpds = qcm2290_rpmpds,
929	.num_pds = ARRAY_SIZE(qcm2290_rpmpds),
930	.max_state = RPM_SMD_LEVEL_TURBO_NO_CPR,
931};
932
933static const struct of_device_id rpmpd_match_table[] = {
934	{ .compatible = "qcom,mdm9607-rpmpd", .data = &mdm9607_desc },
935	{ .compatible = "qcom,msm8226-rpmpd", .data = &msm8226_desc },
936	{ .compatible = "qcom,msm8909-rpmpd", .data = &msm8916_desc },
937	{ .compatible = "qcom,msm8916-rpmpd", .data = &msm8916_desc },
938	{ .compatible = "qcom,msm8917-rpmpd", .data = &msm8917_desc },
939	{ .compatible = "qcom,msm8939-rpmpd", .data = &msm8939_desc },
940	{ .compatible = "qcom,msm8953-rpmpd", .data = &msm8953_desc },
941	{ .compatible = "qcom,msm8974-rpmpd", .data = &msm8974_desc },
942	{ .compatible = "qcom,msm8974pro-pma8084-rpmpd", .data = &msm8974pro_pma8084_desc },
943	{ .compatible = "qcom,msm8976-rpmpd", .data = &msm8976_desc },
944	{ .compatible = "qcom,msm8994-rpmpd", .data = &msm8994_desc },
945	{ .compatible = "qcom,msm8996-rpmpd", .data = &msm8996_desc },
946	{ .compatible = "qcom,msm8998-rpmpd", .data = &msm8998_desc },
947	{ .compatible = "qcom,qcm2290-rpmpd", .data = &qcm2290_desc },
948	{ .compatible = "qcom,qcs404-rpmpd", .data = &qcs404_desc },
949	{ .compatible = "qcom,qm215-rpmpd", .data = &qm215_desc },
950	{ .compatible = "qcom,sdm660-rpmpd", .data = &sdm660_desc },
951	{ .compatible = "qcom,sm6115-rpmpd", .data = &sm6115_desc },
952	{ .compatible = "qcom,sm6125-rpmpd", .data = &sm6125_desc },
953	{ .compatible = "qcom,sm6375-rpmpd", .data = &sm6375_desc },
954	{ }
955};
956MODULE_DEVICE_TABLE(of, rpmpd_match_table);
957
958static int rpmpd_send_enable(struct rpmpd *pd, bool enable)
959{
960	struct rpmpd_req req = {
961		.key = KEY_ENABLE,
962		.nbytes = cpu_to_le32(sizeof(u32)),
963		.value = cpu_to_le32(enable),
964	};
965
966	return qcom_rpm_smd_write(rpmpd_smd_rpm, QCOM_SMD_RPM_ACTIVE_STATE,
967				  pd->res_type, pd->res_id, &req, sizeof(req));
968}
969
970static int rpmpd_send_corner(struct rpmpd *pd, int state, unsigned int corner)
971{
972	struct rpmpd_req req = {
973		.key = pd->key,
974		.nbytes = cpu_to_le32(sizeof(u32)),
975		.value = cpu_to_le32(corner),
976	};
977
978	return qcom_rpm_smd_write(rpmpd_smd_rpm, state, pd->res_type, pd->res_id,
979				  &req, sizeof(req));
980};
981
982static void to_active_sleep(struct rpmpd *pd, unsigned int corner,
983			    unsigned int *active, unsigned int *sleep)
984{
985	*active = corner;
986
987	if (pd->active_only)
988		*sleep = 0;
989	else
990		*sleep = *active;
991}
992
993static int rpmpd_aggregate_corner(struct rpmpd *pd)
994{
995	int ret;
996	struct rpmpd *peer = pd->peer;
997	unsigned int active_corner, sleep_corner;
998	unsigned int this_active_corner = 0, this_sleep_corner = 0;
999	unsigned int peer_active_corner = 0, peer_sleep_corner = 0;
1000
1001	/* Clamp to the highest corner/level if sync_state isn't done yet */
1002	if (!pd->state_synced)
1003		this_active_corner = this_sleep_corner = pd->max_state - 1;
1004	else
1005		to_active_sleep(pd, pd->corner, &this_active_corner, &this_sleep_corner);
1006
1007	if (peer && peer->enabled)
1008		to_active_sleep(peer, peer->corner, &peer_active_corner,
1009				&peer_sleep_corner);
1010
1011	active_corner = max(this_active_corner, peer_active_corner);
1012
1013	ret = rpmpd_send_corner(pd, QCOM_SMD_RPM_ACTIVE_STATE, active_corner);
1014	if (ret)
1015		return ret;
1016
1017	sleep_corner = max(this_sleep_corner, peer_sleep_corner);
1018
1019	return rpmpd_send_corner(pd, QCOM_SMD_RPM_SLEEP_STATE, sleep_corner);
1020}
1021
1022static int rpmpd_power_on(struct generic_pm_domain *domain)
1023{
1024	int ret;
1025	struct rpmpd *pd = domain_to_rpmpd(domain);
1026
1027	mutex_lock(&rpmpd_lock);
1028
1029	ret = rpmpd_send_enable(pd, true);
1030	if (ret)
1031		goto out;
1032
1033	pd->enabled = true;
1034
1035	if (pd->corner)
1036		ret = rpmpd_aggregate_corner(pd);
1037
1038out:
1039	mutex_unlock(&rpmpd_lock);
1040
1041	return ret;
1042}
1043
1044static int rpmpd_power_off(struct generic_pm_domain *domain)
1045{
1046	int ret;
1047	struct rpmpd *pd = domain_to_rpmpd(domain);
1048
1049	mutex_lock(&rpmpd_lock);
1050
1051	ret = rpmpd_send_enable(pd, false);
1052	if (!ret)
1053		pd->enabled = false;
1054
1055	mutex_unlock(&rpmpd_lock);
1056
1057	return ret;
1058}
1059
1060static int rpmpd_set_performance(struct generic_pm_domain *domain,
1061				 unsigned int state)
1062{
1063	int ret = 0;
1064	struct rpmpd *pd = domain_to_rpmpd(domain);
1065
1066	if (state > pd->max_state)
1067		state = pd->max_state;
1068
1069	mutex_lock(&rpmpd_lock);
1070
1071	pd->corner = state;
1072
1073	/* Always send updates for vfc and vfl */
1074	if (!pd->enabled && pd->key != cpu_to_le32(KEY_FLOOR_CORNER) &&
1075	    pd->key != cpu_to_le32(KEY_FLOOR_LEVEL))
1076		goto out;
1077
1078	ret = rpmpd_aggregate_corner(pd);
1079
1080out:
1081	mutex_unlock(&rpmpd_lock);
1082
1083	return ret;
1084}
1085
1086static int rpmpd_probe(struct platform_device *pdev)
1087{
1088	int i;
1089	size_t num;
1090	struct genpd_onecell_data *data;
1091	struct rpmpd **rpmpds;
1092	const struct rpmpd_desc *desc;
1093
1094	rpmpd_smd_rpm = dev_get_drvdata(pdev->dev.parent);
1095	if (!rpmpd_smd_rpm) {
1096		dev_err(&pdev->dev, "Unable to retrieve handle to RPM\n");
1097		return -ENODEV;
1098	}
1099
1100	desc = of_device_get_match_data(&pdev->dev);
1101	if (!desc)
1102		return -EINVAL;
1103
1104	rpmpds = desc->rpmpds;
1105	num = desc->num_pds;
1106
1107	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
1108	if (!data)
1109		return -ENOMEM;
1110
1111	data->domains = devm_kcalloc(&pdev->dev, num, sizeof(*data->domains),
1112				     GFP_KERNEL);
1113	if (!data->domains)
1114		return -ENOMEM;
1115
1116	data->num_domains = num;
1117
1118	for (i = 0; i < num; i++) {
1119		if (!rpmpds[i]) {
1120			dev_warn(&pdev->dev, "rpmpds[] with empty entry at index=%d\n",
1121				 i);
1122			continue;
1123		}
1124
1125		rpmpds[i]->max_state = desc->max_state;
1126		rpmpds[i]->pd.power_off = rpmpd_power_off;
1127		rpmpds[i]->pd.power_on = rpmpd_power_on;
1128		rpmpds[i]->pd.set_performance_state = rpmpd_set_performance;
1129		rpmpds[i]->pd.flags = GENPD_FLAG_ACTIVE_WAKEUP;
1130		pm_genpd_init(&rpmpds[i]->pd, NULL, true);
1131
1132		data->domains[i] = &rpmpds[i]->pd;
1133	}
1134
1135	/* Add subdomains */
1136	for (i = 0; i < num; i++) {
1137		if (!rpmpds[i])
1138			continue;
1139
1140		if (rpmpds[i]->parent)
1141			pm_genpd_add_subdomain(rpmpds[i]->parent, &rpmpds[i]->pd);
1142	}
1143
1144	return of_genpd_add_provider_onecell(pdev->dev.of_node, data);
1145}
1146
1147static void rpmpd_sync_state(struct device *dev)
1148{
1149	const struct rpmpd_desc *desc = of_device_get_match_data(dev);
1150	struct rpmpd **rpmpds = desc->rpmpds;
1151	struct rpmpd *pd;
1152	unsigned int i;
1153	int ret;
1154
1155	mutex_lock(&rpmpd_lock);
1156	for (i = 0; i < desc->num_pds; i++) {
1157		pd = rpmpds[i];
1158		if (!pd)
1159			continue;
1160
1161		pd->state_synced = true;
1162
1163		if (!pd->enabled)
1164			pd->corner = 0;
1165
1166		ret = rpmpd_aggregate_corner(pd);
1167		if (ret)
1168			dev_err(dev, "failed to sync %s: %d\n", pd->pd.name, ret);
1169	}
1170	mutex_unlock(&rpmpd_lock);
1171}
1172
1173static struct platform_driver rpmpd_driver = {
1174	.driver = {
1175		.name = "qcom-rpmpd",
1176		.of_match_table = rpmpd_match_table,
1177		.suppress_bind_attrs = true,
1178		.sync_state = rpmpd_sync_state,
1179	},
1180	.probe = rpmpd_probe,
1181};
1182
1183static int __init rpmpd_init(void)
1184{
1185	return platform_driver_register(&rpmpd_driver);
1186}
1187core_initcall(rpmpd_init);
1188
1189MODULE_DESCRIPTION("Qualcomm Technologies, Inc. RPM Power Domain Driver");
1190MODULE_LICENSE("GPL v2");
1191