RK3368 DDR: add support 3368 ddr change freq function
[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)
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         } tx_buf;
411         struct __packed2 {
412                 u32 status;
413         } rx_buf;
414
415         tx_buf.dram_speed_bin = (u32)dram_speed_bin;
416         tx_buf.freq = (u32)freq;
417
418         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
419                         SCPI_DDR_INIT, tx_buf, rx_buf);
420         return scpi_execute_cmd(&sdata);
421 }
422 EXPORT_SYMBOL_GPL(scpi_ddr_init);
423
424 int scpi_ddr_set_clk_rate(u32 rate)
425 {
426         struct scpi_data_buf sdata;
427         struct rockchip_mbox_msg mdata;
428         struct __packed1 {
429                 u32 clk_rate;
430         } tx_buf;
431         struct __packed2 {
432                 u32 status;
433         } rx_buf;
434
435         tx_buf.clk_rate = (u32)rate;
436
437         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
438                         SCPI_DDR_SET_FREQ, tx_buf, rx_buf);
439         return scpi_execute_cmd(&sdata);
440 }
441 EXPORT_SYMBOL_GPL(scpi_ddr_set_clk_rate);
442
443 int scpi_ddr_round_rate(u32 m_hz)
444 {
445         struct scpi_data_buf sdata;
446         struct rockchip_mbox_msg mdata;
447         struct __packed1 {
448                 u32 clk_rate;
449         } tx_buf;
450         struct __packed2 {
451                 u32 status;
452                 u32 round_rate;
453         } rx_buf;
454
455         tx_buf.clk_rate = (u32)m_hz;
456
457         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
458                         SCPI_DDR_ROUND_RATE, tx_buf, rx_buf);
459         if (scpi_execute_cmd(&sdata))
460                 return 0;
461
462         return rx_buf.round_rate;
463 }
464 EXPORT_SYMBOL_GPL(scpi_ddr_round_rate);
465
466 int scpi_ddr_set_auto_self_refresh(u32 en)
467 {
468         struct scpi_data_buf sdata;
469         struct rockchip_mbox_msg mdata;
470         struct __packed1 {
471                 u32 enable;
472         } tx_buf;
473         struct __packed2 {
474                 u32 status;
475         } rx_buf;
476
477         tx_buf.enable = (u32)en;
478
479         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
480                         SCPI_DDR_AUTO_SELF_REFRESH, tx_buf, rx_buf);
481         return scpi_execute_cmd(&sdata);
482 }
483 EXPORT_SYMBOL_GPL(scpi_ddr_set_auto_self_refresh);
484
485 int scpi_ddr_bandwidth_get(struct ddr_bw_info *ddr_bw_ch0,
486                            struct ddr_bw_info *ddr_bw_ch1)
487 {
488         struct scpi_data_buf sdata;
489         struct rockchip_mbox_msg mdata;
490         struct __packed1 {
491                 u32 status;
492         } tx_buf;
493         struct __packed2 {
494                 u32 status;
495                 struct ddr_bw_info ddr_bw_ch0;
496                 struct ddr_bw_info ddr_bw_ch1;
497         } rx_buf;
498
499         tx_buf.status = 0;
500
501         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
502                         SCPI_DDR_BANDWIDTH_GET, tx_buf, rx_buf);
503         if (scpi_execute_cmd(&sdata))
504                 return 0;
505
506         memcpy(ddr_bw_ch0, &(rx_buf.ddr_bw_ch0), sizeof(rx_buf.ddr_bw_ch0));
507         memcpy(ddr_bw_ch1, &(rx_buf.ddr_bw_ch1), sizeof(rx_buf.ddr_bw_ch1));
508
509         return 0;
510 }
511 EXPORT_SYMBOL_GPL(scpi_ddr_bandwidth_get);
512
513 int scpi_ddr_get_clk_rate(void)
514 {
515         struct scpi_data_buf sdata;
516         struct rockchip_mbox_msg mdata;
517         struct __packed1 {
518                 u32 status;
519         } tx_buf;
520         struct __packed2 {
521                 u32 status;
522                 u32 clk_rate;
523         } rx_buf;
524
525         tx_buf.status = 0;
526         SCPI_SETUP_DBUF(sdata, mdata, SCPI_CL_DDR,
527                         SCPI_DDR_GET_FREQ, tx_buf, rx_buf);
528         if (scpi_execute_cmd(&sdata))
529                 return 0;
530
531         return rx_buf.clk_rate;
532 }
533 EXPORT_SYMBOL_GPL(scpi_ddr_get_clk_rate);
534
535 static struct of_device_id mobx_scpi_of_match[] = {
536         { .compatible = "rockchip,mbox-scpi"},
537         { },
538 };
539 MODULE_DEVICE_TABLE(of, mobx_scpi_of_match);
540
541 static int mobx_scpi_probe(struct platform_device *pdev)
542 {
543         int ret = 0;
544         int retry = 3;
545         u32 ver = 0;
546         int check_version = 0; /*0: not check version, 1: check version*/
547
548         the_scpi_device = &pdev->dev;
549
550         while ((retry--) && (check_version != 0)) {
551                 ret = scpi_get_version(SCPI_VERSION, &ver);
552                 if ((ret == 0) && (ver == SCPI_VERSION))
553                         break;
554         }
555
556         if ((retry <= 0) && (check_version != 0)) {
557                 dev_err(&pdev->dev, "Failed to get scpi version\n");
558                 ret = -EIO;
559                 goto exit;
560         }
561
562         dev_info(&pdev->dev,
563                  "Scpi initialize, version: 0x%x\n", ver);
564         return 0;
565 exit:
566         the_scpi_device = NULL;
567         return ret;
568 }
569
570 static struct platform_driver mbox_scpi_driver = {
571         .probe  = mobx_scpi_probe,
572         .driver = {
573                 .name = "mbox-scpi",
574                 .of_match_table = of_match_ptr(mobx_scpi_of_match),
575         },
576 };
577
578 static int __init rockchip_mbox_scpi_init(void)
579 {
580         return platform_driver_register(&mbox_scpi_driver);
581 }
582 subsys_initcall(rockchip_mbox_scpi_init);