9ddb1221545a049341b106f4a37b22352992c7bc
[firefly-linux-kernel-4.4.55.git] / drivers / mailbox / scpi_protocol.c
1 /*
2  * System Control and Power Interface (SCPI) Message Protocol driver
3  *
4  * Copyright (C) 2014 ARM Ltd.
5  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14  * more details.
15  *
16  * You should have received a copy of the GNU General Public License along with
17  * this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 #include <linux/of_device.h>
20 #include <linux/platform_device.h>
21 #include <linux/err.h>
22 #include <linux/export.h>
23 #include <linux/kernel.h>
24 #include <linux/module.h>
25 #include <linux/printk.h>
26 #include <linux/mailbox_client.h>
27 #include <linux/scpi_protocol.h>
28 #include <linux/slab.h>
29 #include <linux/rockchip-mailbox.h>
30 #include <linux/rockchip/common.h>
31
32 #include "scpi_cmd.h"
33
34 #define CMD_ID_SHIFT            0
35 #define CMD_ID_MASK             0xff
36 #define CMD_SENDER_ID_SHIFT     8
37 #define CMD_SENDER_ID_MASK      0xff
38 #define CMD_DATA_SIZE_SHIFT     20
39 #define CMD_DATA_SIZE_MASK      0x1ff
40 #define PACK_SCPI_CMD(cmd, sender, txsz)                                \
41         ((((cmd) & CMD_ID_MASK) << CMD_ID_SHIFT) |                      \
42         (((sender) & CMD_SENDER_ID_MASK) << CMD_SENDER_ID_SHIFT) |      \
43         (((txsz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT))
44
45 #define MAX_DVFS_DOMAINS        3
46 #define MAX_DVFS_OPPS           8
47 #define DVFS_LATENCY(hdr)       ((hdr) >> 16)
48 #define DVFS_OPP_COUNT(hdr)     (((hdr) >> 8) & 0xff)
49
50 struct scpi_data_buf {
51         int client_id;
52         struct rockchip_mbox_msg *data;
53         struct completion complete;
54 };
55
56 static int high_priority_cmds[] = {
57         SCPI_CMD_GET_CSS_PWR_STATE,
58         SCPI_CMD_CFG_PWR_STATE_STAT,
59         SCPI_CMD_GET_PWR_STATE_STAT,
60         SCPI_CMD_SET_DVFS,
61         SCPI_CMD_GET_DVFS,
62         SCPI_CMD_SET_RTC,
63         SCPI_CMD_GET_RTC,
64         SCPI_CMD_SET_CLOCK_INDEX,
65         SCPI_CMD_SET_CLOCK_VALUE,
66         SCPI_CMD_GET_CLOCK_VALUE,
67         SCPI_CMD_SET_PSU,
68         SCPI_CMD_GET_PSU,
69         SCPI_CMD_SENSOR_CFG_PERIODIC,
70         SCPI_CMD_SENSOR_CFG_BOUNDS,
71 };
72
73 static struct scpi_opp *scpi_opps[MAX_DVFS_DOMAINS];
74
75 static struct device *the_scpi_device;
76
77 static int scpi_linux_errmap[SCPI_ERR_MAX] = {
78         0, -EINVAL, -ENOEXEC, -EMSGSIZE,
79         -EINVAL, -EACCES, -ERANGE, -ETIMEDOUT,
80         -ENOMEM, -EINVAL, -EOPNOTSUPP, -EIO,
81 };
82
83 static inline int scpi_to_linux_errno(int errno)
84 {
85         if (errno >= SCPI_SUCCESS && errno < SCPI_ERR_MAX)
86                 return scpi_linux_errmap[errno];
87         return -EIO;
88 }
89
90 static bool high_priority_chan_supported(int cmd)
91 {
92         int idx;
93
94         for (idx = 0; idx < ARRAY_SIZE(high_priority_cmds); idx++)
95                 if (cmd == high_priority_cmds[idx])
96                         return true;
97         return false;
98 }
99
100 static void scpi_rx_callback(struct mbox_client *cl, void *msg)
101 {
102         struct rockchip_mbox_msg *data = (struct rockchip_mbox_msg *)msg;
103         struct scpi_data_buf *scpi_buf = data->cl_data;
104
105         complete(&scpi_buf->complete);
106 }
107
108 static int send_scpi_cmd(struct scpi_data_buf *scpi_buf, bool high_priority)
109 {
110         struct mbox_chan *chan;
111         struct mbox_client cl;
112         struct rockchip_mbox_msg *data = scpi_buf->data;
113         u32 status;
114         int ret;
115
116         if (!the_scpi_device) {
117                 pr_err("Scpi initializes unsuccessfully\n");
118                 return -EIO;
119         }
120
121         cl.dev = the_scpi_device;
122         cl.rx_callback = scpi_rx_callback;
123         cl.tx_done = NULL;
124         cl.tx_block = false;
125         cl.knows_txdone = false;
126
127         chan = mbox_request_channel(&cl, high_priority);
128         if (IS_ERR(chan))
129                 return PTR_ERR(chan);
130
131         init_completion(&scpi_buf->complete);
132         if (mbox_send_message(chan, (void *)data) < 0) {
133                 status = SCPI_ERR_TIMEOUT;
134                 goto free_channel;
135         }
136
137         ret = wait_for_completion_timeout(&scpi_buf->complete,
138                                           msecs_to_jiffies(1000));
139         if (ret == 0) {
140                 status = SCPI_ERR_TIMEOUT;
141                 goto free_channel;
142         }
143         status = *(u32 *)(data->rx_buf); /* read first word */
144
145 free_channel:
146         mbox_free_channel(chan);
147
148         return scpi_to_linux_errno(status);
149 }
150
151 #define SCPI_SETUP_DBUF(scpi_buf, mbox_buf, _client_id,\
152                         _cmd, _tx_buf, _rx_buf) \
153 do {                                            \
154         struct rockchip_mbox_msg *pdata = &mbox_buf;    \
155         pdata->cmd = _cmd;                      \
156         pdata->tx_buf = &_tx_buf;               \
157         pdata->tx_size = sizeof(_tx_buf);       \
158         pdata->rx_buf = &_rx_buf;               \
159         pdata->rx_size = sizeof(_rx_buf);       \
160         scpi_buf.client_id = _client_id;        \
161         scpi_buf.data = pdata;                  \
162 } while (0)
163
164 static int scpi_execute_cmd(struct scpi_data_buf *scpi_buf)
165 {
166         struct rockchip_mbox_msg *data;
167         bool high_priority;
168
169         if (!scpi_buf || !scpi_buf->data)
170                 return -EINVAL;
171
172         data = scpi_buf->data;
173         high_priority = high_priority_chan_supported(data->cmd);
174         data->cmd = PACK_SCPI_CMD(data->cmd, scpi_buf->client_id,
175                                   data->tx_size);
176         data->cl_data = scpi_buf;
177
178         return send_scpi_cmd(scpi_buf, high_priority);
179 }
180
181 unsigned long scpi_clk_get_val(u16 clk_id)
182 {
183         struct scpi_data_buf sdata;
184         struct rockchip_mbox_msg mdata;
185         struct __packed {
186                 u32 status;
187                 u32 clk_rate;
188         } buf;
189
190         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_CLOCKS,
191                         SCPI_CMD_GET_CLOCK_VALUE, clk_id, buf);
192         if (scpi_execute_cmd(&sdata))
193                 return 0;
194
195         return buf.clk_rate;
196 }
197 EXPORT_SYMBOL_GPL(scpi_clk_get_val);
198
199 int scpi_clk_set_val(u16 clk_id, unsigned long rate)
200 {
201         struct scpi_data_buf sdata;
202         struct rockchip_mbox_msg mdata;
203         int stat;
204         struct __packed {
205                 u32 clk_rate;
206                 u16 clk_id;
207         } buf;
208
209         buf.clk_rate = (u32)rate;
210         buf.clk_id = clk_id;
211
212         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_CLOCKS,
213                         SCPI_CMD_SET_CLOCK_VALUE, buf, stat);
214         return scpi_execute_cmd(&sdata);
215 }
216 EXPORT_SYMBOL_GPL(scpi_clk_set_val);
217
218 struct scpi_opp *scpi_dvfs_get_opps(u8 domain)
219 {
220         struct scpi_data_buf sdata;
221         struct rockchip_mbox_msg mdata;
222         struct __packed {
223                 u32 status;
224                 u32 header;
225                 struct scpi_opp_entry opp[MAX_DVFS_OPPS];
226         } buf;
227         struct scpi_opp *opps;
228         size_t opps_sz;
229         int count, ret;
230
231         if (domain >= MAX_DVFS_DOMAINS)
232                 return ERR_PTR(-EINVAL);
233
234         if (scpi_opps[domain])  /* data already populated */
235                 return scpi_opps[domain];
236
237         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS,
238                         SCPI_CMD_GET_DVFS_INFO, domain, buf);
239         ret = scpi_execute_cmd(&sdata);
240         if (ret)
241                 return ERR_PTR(ret);
242
243         opps = kmalloc(sizeof(*opps), GFP_KERNEL);
244         if (!opps)
245                 return ERR_PTR(-ENOMEM);
246
247         count = DVFS_OPP_COUNT(buf.header);
248         opps_sz = count * sizeof(*(opps->opp));
249
250         opps->count = count;
251         opps->latency = DVFS_LATENCY(buf.header);
252         opps->opp = kmalloc(opps_sz, GFP_KERNEL);
253         if (!opps->opp) {
254                 kfree(opps);
255                 return ERR_PTR(-ENOMEM);
256         }
257
258         memcpy(opps->opp, &buf.opp[0], opps_sz);
259         scpi_opps[domain] = opps;
260
261         return opps;
262 }
263 EXPORT_SYMBOL_GPL(scpi_dvfs_get_opps);
264
265 int scpi_dvfs_get_idx(u8 domain)
266 {
267         struct scpi_data_buf sdata;
268         struct rockchip_mbox_msg mdata;
269         struct __packed {
270                 u32 status;
271                 u8 dvfs_idx;
272         } buf;
273         int ret;
274
275         if (domain >= MAX_DVFS_DOMAINS)
276                 return -EINVAL;
277
278         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS,
279                         SCPI_CMD_GET_DVFS, domain, buf);
280         ret = scpi_execute_cmd(&sdata);
281
282         if (!ret)
283                 ret = buf.dvfs_idx;
284         return ret;
285 }
286 EXPORT_SYMBOL_GPL(scpi_dvfs_get_idx);
287
288 int scpi_dvfs_set_idx(u8 domain, u8 idx)
289 {
290         struct scpi_data_buf sdata;
291         struct rockchip_mbox_msg mdata;
292         struct __packed {
293                 u8 dvfs_domain;
294                 u8 dvfs_idx;
295         } buf;
296         int stat;
297
298         buf.dvfs_idx = idx;
299         buf.dvfs_domain = domain;
300
301         if (domain >= MAX_DVFS_DOMAINS)
302                 return -EINVAL;
303
304         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DVFS,
305                         SCPI_CMD_SET_DVFS, buf, stat);
306         return scpi_execute_cmd(&sdata);
307 }
308 EXPORT_SYMBOL_GPL(scpi_dvfs_set_idx);
309
310 int scpi_get_sensor(char *name)
311 {
312         struct scpi_data_buf sdata;
313         struct rockchip_mbox_msg mdata;
314         struct __packed {
315                 u32 status;
316                 u16 sensors;
317         } cap_buf;
318         struct __packed {
319                 u32 status;
320                 u16 sensor;
321                 u8 class;
322                 u8 trigger;
323                 char name[20];
324         } info_buf;
325         int ret;
326         u16 sensor_id;
327
328         /* This should be handled by a generic macro */
329         do {
330                 struct rockchip_mbox_msg *pdata = &mdata;
331
332                 pdata->cmd = SCPI_CMD_SENSOR_CAPABILITIES;
333                 pdata->tx_size = 0;
334                 pdata->rx_buf = &cap_buf;
335                 pdata->rx_size = sizeof(cap_buf);
336                 sdata.client_id = SCPI_CL_THERMAL;
337                 sdata.data = pdata;
338         } while (0);
339
340         ret = scpi_execute_cmd(&sdata);
341         if (ret)
342                 goto out;
343
344         ret = -ENODEV;
345         for (sensor_id = 0; sensor_id < cap_buf.sensors; sensor_id++) {
346                 SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL,
347                                 SCPI_CMD_SENSOR_INFO, sensor_id, info_buf);
348                 ret = scpi_execute_cmd(&sdata);
349                 if (ret)
350                         break;
351
352                 if (!strcmp(name, info_buf.name)) {
353                         ret = sensor_id;
354                         break;
355                 }
356         }
357 out:
358         return ret;
359 }
360 EXPORT_SYMBOL_GPL(scpi_get_sensor);
361
362 int scpi_get_sensor_value(u16 sensor, u32 *val)
363 {
364         struct scpi_data_buf sdata;
365         struct rockchip_mbox_msg mdata;
366         struct __packed {
367                 u32 status;
368                 u32 val;
369         } buf;
370         int ret;
371
372         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_THERMAL, SCPI_CMD_SENSOR_VALUE,
373                         sensor, buf);
374
375         ret = scpi_execute_cmd(&sdata);
376         if (ret)
377                 *val = buf.val;
378
379         return ret;
380 }
381 EXPORT_SYMBOL_GPL(scpi_get_sensor_value);
382
383 static int scpi_get_version(u32 old, u32 *ver)
384 {
385         struct scpi_data_buf sdata;
386         struct rockchip_mbox_msg mdata;
387         struct __packed {
388                 u32 status;
389                 u32 ver;
390         } buf;
391         int ret;
392
393         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_SYS, SCPI_SYS_GET_VERSION,
394                         old, buf);
395
396         ret = scpi_execute_cmd(&sdata);
397         if (ret)
398                 *ver = buf.ver;
399
400         return ret;
401 }
402
403 int scpi_ddr_init(u32 dram_speed_bin, u32 freq, u32 lcdc_type)
404 {
405         struct scpi_data_buf sdata;
406         struct rockchip_mbox_msg mdata;
407         struct __packed1 {
408                 u32 dram_speed_bin;
409                 u32 freq;
410                 u32 lcdc_type;
411         } tx_buf;
412         struct __packed2 {
413                 u32 status;
414         } rx_buf;
415
416         tx_buf.dram_speed_bin = (u32)dram_speed_bin;
417         tx_buf.freq = (u32)freq;
418         tx_buf.lcdc_type = (u32)lcdc_type;
419
420         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
421                         SCPI_DDR_INIT, tx_buf, rx_buf);
422         return scpi_execute_cmd(&sdata);
423 }
424 EXPORT_SYMBOL_GPL(scpi_ddr_init);
425
426 int scpi_ddr_set_clk_rate(u32 rate)
427 {
428         struct scpi_data_buf sdata;
429         struct rockchip_mbox_msg mdata;
430         struct __packed1 {
431                 u32 clk_rate;
432         } tx_buf;
433         struct __packed2 {
434                 u32 status;
435         } rx_buf;
436
437         tx_buf.clk_rate = (u32)rate;
438
439         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
440                         SCPI_DDR_SET_FREQ, tx_buf, rx_buf);
441         return scpi_execute_cmd(&sdata);
442 }
443 EXPORT_SYMBOL_GPL(scpi_ddr_set_clk_rate);
444
445 int scpi_ddr_round_rate(u32 m_hz)
446 {
447         struct scpi_data_buf sdata;
448         struct rockchip_mbox_msg mdata;
449         struct __packed1 {
450                 u32 clk_rate;
451         } tx_buf;
452         struct __packed2 {
453                 u32 status;
454                 u32 round_rate;
455         } rx_buf;
456
457         tx_buf.clk_rate = (u32)m_hz;
458
459         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
460                         SCPI_DDR_ROUND_RATE, tx_buf, rx_buf);
461         if (scpi_execute_cmd(&sdata))
462                 return 0;
463
464         return rx_buf.round_rate;
465 }
466 EXPORT_SYMBOL_GPL(scpi_ddr_round_rate);
467
468 int scpi_ddr_set_auto_self_refresh(u32 en)
469 {
470         struct scpi_data_buf sdata;
471         struct rockchip_mbox_msg mdata;
472         struct __packed1 {
473                 u32 enable;
474         } tx_buf;
475         struct __packed2 {
476                 u32 status;
477         } rx_buf;
478
479         tx_buf.enable = (u32)en;
480
481         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
482                         SCPI_DDR_AUTO_SELF_REFRESH, tx_buf, rx_buf);
483         return scpi_execute_cmd(&sdata);
484 }
485 EXPORT_SYMBOL_GPL(scpi_ddr_set_auto_self_refresh);
486
487 int scpi_ddr_bandwidth_get(struct ddr_bw_info *ddr_bw_ch0,
488                            struct ddr_bw_info *ddr_bw_ch1)
489 {
490         struct scpi_data_buf sdata;
491         struct rockchip_mbox_msg mdata;
492         struct __packed1 {
493                 u32 status;
494         } tx_buf;
495         struct __packed2 {
496                 u32 status;
497                 struct ddr_bw_info ddr_bw_ch0;
498                 struct ddr_bw_info ddr_bw_ch1;
499         } rx_buf;
500
501         tx_buf.status = 0;
502
503         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
504                         SCPI_DDR_BANDWIDTH_GET, tx_buf, rx_buf);
505         if (scpi_execute_cmd(&sdata))
506                 return 0;
507
508         memcpy(ddr_bw_ch0, &(rx_buf.ddr_bw_ch0), sizeof(rx_buf.ddr_bw_ch0));
509         memcpy(ddr_bw_ch1, &(rx_buf.ddr_bw_ch1), sizeof(rx_buf.ddr_bw_ch1));
510
511         return 0;
512 }
513 EXPORT_SYMBOL_GPL(scpi_ddr_bandwidth_get);
514
515 int scpi_ddr_get_clk_rate(void)
516 {
517         struct scpi_data_buf sdata;
518         struct rockchip_mbox_msg mdata;
519         struct __packed1 {
520                 u32 status;
521         } tx_buf;
522         struct __packed2 {
523                 u32 status;
524                 u32 clk_rate;
525         } rx_buf;
526
527         tx_buf.status = 0;
528         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
529                         SCPI_DDR_GET_FREQ, tx_buf, rx_buf);
530         if (scpi_execute_cmd(&sdata))
531                 return 0;
532
533         return rx_buf.clk_rate;
534 }
535 EXPORT_SYMBOL_GPL(scpi_ddr_get_clk_rate);
536
537 static struct of_device_id mobx_scpi_of_match[] = {
538         { .compatible = "rockchip,mbox-scpi"},
539         { },
540 };
541 MODULE_DEVICE_TABLE(of, mobx_scpi_of_match);
542
543 static int mobx_scpi_probe(struct platform_device *pdev)
544 {
545         int ret = 0;
546         int retry = 3;
547         u32 ver = 0;
548         int check_version = 0; /*0: not check version, 1: check version*/
549
550         the_scpi_device = &pdev->dev;
551
552         while ((retry--) && (check_version != 0)) {
553                 ret = scpi_get_version(SCPI_VERSION, &ver);
554                 if ((ret == 0) && (ver == SCPI_VERSION))
555                         break;
556         }
557
558         if ((retry <= 0) && (check_version != 0)) {
559                 dev_err(&pdev->dev, "Failed to get scpi version\n");
560                 ret = -EIO;
561                 goto exit;
562         }
563
564         dev_info(&pdev->dev,
565                  "Scpi initialize, version: 0x%x\n", ver);
566         return 0;
567 exit:
568         the_scpi_device = NULL;
569         return ret;
570 }
571
572 static struct platform_driver mbox_scpi_driver = {
573         .probe  = mobx_scpi_probe,
574         .driver = {
575                 .name = "mbox-scpi",
576                 .of_match_table = of_match_ptr(mobx_scpi_of_match),
577         },
578 };
579
580 static int __init rockchip_mbox_scpi_init(void)
581 {
582         return platform_driver_register(&mbox_scpi_driver);
583 }
584 subsys_initcall(rockchip_mbox_scpi_init);