diff options
author | Arnd Bergmann <arnd@arndb.de> | 2016-11-30 11:01:23 -0500 |
---|---|---|
committer | Arnd Bergmann <arnd@arndb.de> | 2016-11-30 11:01:23 -0500 |
commit | e7541f90d42a5f838a3b0556f6ef90f77f5e8bcd (patch) | |
tree | 9d31b70af8f059706034168b5e8b9c82c1352239 /drivers/firmware | |
parent | bc28ba81db8e4c20b92c08ebec2405fcb87ae120 (diff) | |
parent | 8358c6b5fc8c160d0af8654f313b8a7745f8e304 (diff) |
Merge tag 'scpi-updates-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux into next/drivers
Pull "SCPI updates for v4.10" from Sudeep Holla:
1. Adds support for pre-v1.0 SCPI protocol versions
2. Adds support for SCPI used on Amlogic GXBB SoC platforms using the
newly added pre-v1.0 SCPI protocol
3. Decouples some platform specific details from generic SCPI binding
* tag 'scpi-updates-4.10' of git://git.kernel.org/pub/scm/linux/kernel/git/sudeep.holla/linux:
firmware: arm_scpi: add support for pre-v1.0 SCPI compatible
Documentation: bindings: Add support for Amlogic GXBB SCPI protocol
Documentation: bindings: add compatible specific to pre v1.0 SCPI protocols
Documentation: bindings: decouple juno specific details from generic binding
firmware: arm_scpi: allow firmware with get_capabilities not implemented
firmware: arm_scpi: add alternative legacy structures, functions and macros
firmware: arm_scpi: increase MAX_DVFS_OPPS to 16 entries
firmware: arm_scpi: add command indirection to support legacy commands
Diffstat (limited to 'drivers/firmware')
-rw-r--r-- | drivers/firmware/arm_scpi.c | 276 |
1 files changed, 244 insertions, 32 deletions
diff --git a/drivers/firmware/arm_scpi.c b/drivers/firmware/arm_scpi.c index ce2bc2a38101..70e13230d8db 100644 --- a/drivers/firmware/arm_scpi.c +++ b/drivers/firmware/arm_scpi.c | |||
@@ -50,20 +50,27 @@ | |||
50 | #define CMD_TOKEN_ID_MASK 0xff | 50 | #define CMD_TOKEN_ID_MASK 0xff |
51 | #define CMD_DATA_SIZE_SHIFT 16 | 51 | #define CMD_DATA_SIZE_SHIFT 16 |
52 | #define CMD_DATA_SIZE_MASK 0x1ff | 52 | #define CMD_DATA_SIZE_MASK 0x1ff |
53 | #define CMD_LEGACY_DATA_SIZE_SHIFT 20 | ||
54 | #define CMD_LEGACY_DATA_SIZE_MASK 0x1ff | ||
53 | #define PACK_SCPI_CMD(cmd_id, tx_sz) \ | 55 | #define PACK_SCPI_CMD(cmd_id, tx_sz) \ |
54 | ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \ | 56 | ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \ |
55 | (((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT)) | 57 | (((tx_sz) & CMD_DATA_SIZE_MASK) << CMD_DATA_SIZE_SHIFT)) |
56 | #define ADD_SCPI_TOKEN(cmd, token) \ | 58 | #define ADD_SCPI_TOKEN(cmd, token) \ |
57 | ((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT)) | 59 | ((cmd) |= (((token) & CMD_TOKEN_ID_MASK) << CMD_TOKEN_ID_SHIFT)) |
60 | #define PACK_LEGACY_SCPI_CMD(cmd_id, tx_sz) \ | ||
61 | ((((cmd_id) & CMD_ID_MASK) << CMD_ID_SHIFT) | \ | ||
62 | (((tx_sz) & CMD_LEGACY_DATA_SIZE_MASK) << CMD_LEGACY_DATA_SIZE_SHIFT)) | ||
58 | 63 | ||
59 | #define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK) | 64 | #define CMD_SIZE(cmd) (((cmd) >> CMD_DATA_SIZE_SHIFT) & CMD_DATA_SIZE_MASK) |
65 | #define CMD_LEGACY_SIZE(cmd) (((cmd) >> CMD_LEGACY_DATA_SIZE_SHIFT) & \ | ||
66 | CMD_LEGACY_DATA_SIZE_MASK) | ||
60 | #define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | CMD_ID_MASK) | 67 | #define CMD_UNIQ_MASK (CMD_TOKEN_ID_MASK << CMD_TOKEN_ID_SHIFT | CMD_ID_MASK) |
61 | #define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK) | 68 | #define CMD_XTRACT_UNIQ(cmd) ((cmd) & CMD_UNIQ_MASK) |
62 | 69 | ||
63 | #define SCPI_SLOT 0 | 70 | #define SCPI_SLOT 0 |
64 | 71 | ||
65 | #define MAX_DVFS_DOMAINS 8 | 72 | #define MAX_DVFS_DOMAINS 8 |
66 | #define MAX_DVFS_OPPS 8 | 73 | #define MAX_DVFS_OPPS 16 |
67 | #define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16) | 74 | #define DVFS_LATENCY(hdr) (le32_to_cpu(hdr) >> 16) |
68 | #define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff) | 75 | #define DVFS_OPP_COUNT(hdr) ((le32_to_cpu(hdr) >> 8) & 0xff) |
69 | 76 | ||
@@ -99,6 +106,7 @@ enum scpi_error_codes { | |||
99 | SCPI_ERR_MAX | 106 | SCPI_ERR_MAX |
100 | }; | 107 | }; |
101 | 108 | ||
109 | /* SCPI Standard commands */ | ||
102 | enum scpi_std_cmd { | 110 | enum scpi_std_cmd { |
103 | SCPI_CMD_INVALID = 0x00, | 111 | SCPI_CMD_INVALID = 0x00, |
104 | SCPI_CMD_SCPI_READY = 0x01, | 112 | SCPI_CMD_SCPI_READY = 0x01, |
@@ -132,6 +140,108 @@ enum scpi_std_cmd { | |||
132 | SCPI_CMD_COUNT | 140 | SCPI_CMD_COUNT |
133 | }; | 141 | }; |
134 | 142 | ||
143 | /* SCPI Legacy Commands */ | ||
144 | enum legacy_scpi_std_cmd { | ||
145 | LEGACY_SCPI_CMD_INVALID = 0x00, | ||
146 | LEGACY_SCPI_CMD_SCPI_READY = 0x01, | ||
147 | LEGACY_SCPI_CMD_SCPI_CAPABILITIES = 0x02, | ||
148 | LEGACY_SCPI_CMD_EVENT = 0x03, | ||
149 | LEGACY_SCPI_CMD_SET_CSS_PWR_STATE = 0x04, | ||
150 | LEGACY_SCPI_CMD_GET_CSS_PWR_STATE = 0x05, | ||
151 | LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT = 0x06, | ||
152 | LEGACY_SCPI_CMD_GET_PWR_STATE_STAT = 0x07, | ||
153 | LEGACY_SCPI_CMD_SYS_PWR_STATE = 0x08, | ||
154 | LEGACY_SCPI_CMD_L2_READY = 0x09, | ||
155 | LEGACY_SCPI_CMD_SET_AP_TIMER = 0x0a, | ||
156 | LEGACY_SCPI_CMD_CANCEL_AP_TIME = 0x0b, | ||
157 | LEGACY_SCPI_CMD_DVFS_CAPABILITIES = 0x0c, | ||
158 | LEGACY_SCPI_CMD_GET_DVFS_INFO = 0x0d, | ||
159 | LEGACY_SCPI_CMD_SET_DVFS = 0x0e, | ||
160 | LEGACY_SCPI_CMD_GET_DVFS = 0x0f, | ||
161 | LEGACY_SCPI_CMD_GET_DVFS_STAT = 0x10, | ||
162 | LEGACY_SCPI_CMD_SET_RTC = 0x11, | ||
163 | LEGACY_SCPI_CMD_GET_RTC = 0x12, | ||
164 | LEGACY_SCPI_CMD_CLOCK_CAPABILITIES = 0x13, | ||
165 | LEGACY_SCPI_CMD_SET_CLOCK_INDEX = 0x14, | ||
166 | LEGACY_SCPI_CMD_SET_CLOCK_VALUE = 0x15, | ||
167 | LEGACY_SCPI_CMD_GET_CLOCK_VALUE = 0x16, | ||
168 | LEGACY_SCPI_CMD_PSU_CAPABILITIES = 0x17, | ||
169 | LEGACY_SCPI_CMD_SET_PSU = 0x18, | ||
170 | LEGACY_SCPI_CMD_GET_PSU = 0x19, | ||
171 | LEGACY_SCPI_CMD_SENSOR_CAPABILITIES = 0x1a, | ||
172 | LEGACY_SCPI_CMD_SENSOR_INFO = 0x1b, | ||
173 | LEGACY_SCPI_CMD_SENSOR_VALUE = 0x1c, | ||
174 | LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC = 0x1d, | ||
175 | LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS = 0x1e, | ||
176 | LEGACY_SCPI_CMD_SENSOR_ASYNC_VALUE = 0x1f, | ||
177 | LEGACY_SCPI_CMD_COUNT | ||
178 | }; | ||
179 | |||
180 | /* List all commands that are required to go through the high priority link */ | ||
181 | static int legacy_hpriority_cmds[] = { | ||
182 | LEGACY_SCPI_CMD_GET_CSS_PWR_STATE, | ||
183 | LEGACY_SCPI_CMD_CFG_PWR_STATE_STAT, | ||
184 | LEGACY_SCPI_CMD_GET_PWR_STATE_STAT, | ||
185 | LEGACY_SCPI_CMD_SET_DVFS, | ||
186 | LEGACY_SCPI_CMD_GET_DVFS, | ||
187 | LEGACY_SCPI_CMD_SET_RTC, | ||
188 | LEGACY_SCPI_CMD_GET_RTC, | ||
189 | LEGACY_SCPI_CMD_SET_CLOCK_INDEX, | ||
190 | LEGACY_SCPI_CMD_SET_CLOCK_VALUE, | ||
191 | LEGACY_SCPI_CMD_GET_CLOCK_VALUE, | ||
192 | LEGACY_SCPI_CMD_SET_PSU, | ||
193 | LEGACY_SCPI_CMD_GET_PSU, | ||
194 | LEGACY_SCPI_CMD_SENSOR_CFG_PERIODIC, | ||
195 | LEGACY_SCPI_CMD_SENSOR_CFG_BOUNDS, | ||
196 | }; | ||
197 | |||
198 | /* List all commands used by this driver, used as indexes */ | ||
199 | enum scpi_drv_cmds { | ||
200 | CMD_SCPI_CAPABILITIES = 0, | ||
201 | CMD_GET_CLOCK_INFO, | ||
202 | CMD_GET_CLOCK_VALUE, | ||
203 | CMD_SET_CLOCK_VALUE, | ||
204 | CMD_GET_DVFS, | ||
205 | CMD_SET_DVFS, | ||
206 | CMD_GET_DVFS_INFO, | ||
207 | CMD_SENSOR_CAPABILITIES, | ||
208 | CMD_SENSOR_INFO, | ||
209 | CMD_SENSOR_VALUE, | ||
210 | CMD_SET_DEVICE_PWR_STATE, | ||
211 | CMD_GET_DEVICE_PWR_STATE, | ||
212 | CMD_MAX_COUNT, | ||
213 | }; | ||
214 | |||
215 | static int scpi_std_commands[CMD_MAX_COUNT] = { | ||
216 | SCPI_CMD_SCPI_CAPABILITIES, | ||
217 | SCPI_CMD_GET_CLOCK_INFO, | ||
218 | SCPI_CMD_GET_CLOCK_VALUE, | ||
219 | SCPI_CMD_SET_CLOCK_VALUE, | ||
220 | SCPI_CMD_GET_DVFS, | ||
221 | SCPI_CMD_SET_DVFS, | ||
222 | SCPI_CMD_GET_DVFS_INFO, | ||
223 | SCPI_CMD_SENSOR_CAPABILITIES, | ||
224 | SCPI_CMD_SENSOR_INFO, | ||
225 | SCPI_CMD_SENSOR_VALUE, | ||
226 | SCPI_CMD_SET_DEVICE_PWR_STATE, | ||
227 | SCPI_CMD_GET_DEVICE_PWR_STATE, | ||
228 | }; | ||
229 | |||
230 | static int scpi_legacy_commands[CMD_MAX_COUNT] = { | ||
231 | LEGACY_SCPI_CMD_SCPI_CAPABILITIES, | ||
232 | -1, /* GET_CLOCK_INFO */ | ||
233 | LEGACY_SCPI_CMD_GET_CLOCK_VALUE, | ||
234 | LEGACY_SCPI_CMD_SET_CLOCK_VALUE, | ||
235 | LEGACY_SCPI_CMD_GET_DVFS, | ||
236 | LEGACY_SCPI_CMD_SET_DVFS, | ||
237 | LEGACY_SCPI_CMD_GET_DVFS_INFO, | ||
238 | LEGACY_SCPI_CMD_SENSOR_CAPABILITIES, | ||
239 | LEGACY_SCPI_CMD_SENSOR_INFO, | ||
240 | LEGACY_SCPI_CMD_SENSOR_VALUE, | ||
241 | -1, /* SET_DEVICE_PWR_STATE */ | ||
242 | -1, /* GET_DEVICE_PWR_STATE */ | ||
243 | }; | ||
244 | |||
135 | struct scpi_xfer { | 245 | struct scpi_xfer { |
136 | u32 slot; /* has to be first element */ | 246 | u32 slot; /* has to be first element */ |
137 | u32 cmd; | 247 | u32 cmd; |
@@ -160,7 +270,10 @@ struct scpi_chan { | |||
160 | struct scpi_drvinfo { | 270 | struct scpi_drvinfo { |
161 | u32 protocol_version; | 271 | u32 protocol_version; |
162 | u32 firmware_version; | 272 | u32 firmware_version; |
273 | bool is_legacy; | ||
163 | int num_chans; | 274 | int num_chans; |
275 | int *commands; | ||
276 | DECLARE_BITMAP(cmd_priority, LEGACY_SCPI_CMD_COUNT); | ||
164 | atomic_t next_chan; | 277 | atomic_t next_chan; |
165 | struct scpi_ops *scpi_ops; | 278 | struct scpi_ops *scpi_ops; |
166 | struct scpi_chan *channels; | 279 | struct scpi_chan *channels; |
@@ -177,6 +290,11 @@ struct scpi_shared_mem { | |||
177 | u8 payload[0]; | 290 | u8 payload[0]; |
178 | } __packed; | 291 | } __packed; |
179 | 292 | ||
293 | struct legacy_scpi_shared_mem { | ||
294 | __le32 status; | ||
295 | u8 payload[0]; | ||
296 | } __packed; | ||
297 | |||
180 | struct scp_capabilities { | 298 | struct scp_capabilities { |
181 | __le32 protocol_version; | 299 | __le32 protocol_version; |
182 | __le32 event_version; | 300 | __le32 event_version; |
@@ -202,6 +320,12 @@ struct clk_set_value { | |||
202 | __le32 rate; | 320 | __le32 rate; |
203 | } __packed; | 321 | } __packed; |
204 | 322 | ||
323 | struct legacy_clk_set_value { | ||
324 | __le32 rate; | ||
325 | __le16 id; | ||
326 | __le16 reserved; | ||
327 | } __packed; | ||
328 | |||
205 | struct dvfs_info { | 329 | struct dvfs_info { |
206 | __le32 header; | 330 | __le32 header; |
207 | struct { | 331 | struct { |
@@ -273,19 +397,43 @@ static void scpi_process_cmd(struct scpi_chan *ch, u32 cmd) | |||
273 | return; | 397 | return; |
274 | } | 398 | } |
275 | 399 | ||
276 | list_for_each_entry(t, &ch->rx_pending, node) | 400 | /* Command type is not replied by the SCP Firmware in legacy Mode |
277 | if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) { | 401 | * We should consider that command is the head of pending RX commands |
278 | list_del(&t->node); | 402 | * if the list is not empty. In TX only mode, the list would be empty. |
279 | match = t; | 403 | */ |
280 | break; | 404 | if (scpi_info->is_legacy) { |
281 | } | 405 | match = list_first_entry(&ch->rx_pending, struct scpi_xfer, |
406 | node); | ||
407 | list_del(&match->node); | ||
408 | } else { | ||
409 | list_for_each_entry(t, &ch->rx_pending, node) | ||
410 | if (CMD_XTRACT_UNIQ(t->cmd) == CMD_XTRACT_UNIQ(cmd)) { | ||
411 | list_del(&t->node); | ||
412 | match = t; | ||
413 | break; | ||
414 | } | ||
415 | } | ||
282 | /* check if wait_for_completion is in progress or timed-out */ | 416 | /* check if wait_for_completion is in progress or timed-out */ |
283 | if (match && !completion_done(&match->done)) { | 417 | if (match && !completion_done(&match->done)) { |
284 | struct scpi_shared_mem *mem = ch->rx_payload; | 418 | unsigned int len; |
285 | unsigned int len = min(match->rx_len, CMD_SIZE(cmd)); | 419 | |
420 | if (scpi_info->is_legacy) { | ||
421 | struct legacy_scpi_shared_mem *mem = ch->rx_payload; | ||
422 | |||
423 | /* RX Length is not replied by the legacy Firmware */ | ||
424 | len = match->rx_len; | ||
425 | |||
426 | match->status = le32_to_cpu(mem->status); | ||
427 | memcpy_fromio(match->rx_buf, mem->payload, len); | ||
428 | } else { | ||
429 | struct scpi_shared_mem *mem = ch->rx_payload; | ||
430 | |||
431 | len = min(match->rx_len, CMD_SIZE(cmd)); | ||
432 | |||
433 | match->status = le32_to_cpu(mem->status); | ||
434 | memcpy_fromio(match->rx_buf, mem->payload, len); | ||
435 | } | ||
286 | 436 | ||
287 | match->status = le32_to_cpu(mem->status); | ||
288 | memcpy_fromio(match->rx_buf, mem->payload, len); | ||
289 | if (match->rx_len > len) | 437 | if (match->rx_len > len) |
290 | memset(match->rx_buf + len, 0, match->rx_len - len); | 438 | memset(match->rx_buf + len, 0, match->rx_len - len); |
291 | complete(&match->done); | 439 | complete(&match->done); |
@@ -297,7 +445,10 @@ static void scpi_handle_remote_msg(struct mbox_client *c, void *msg) | |||
297 | { | 445 | { |
298 | struct scpi_chan *ch = container_of(c, struct scpi_chan, cl); | 446 | struct scpi_chan *ch = container_of(c, struct scpi_chan, cl); |
299 | struct scpi_shared_mem *mem = ch->rx_payload; | 447 | struct scpi_shared_mem *mem = ch->rx_payload; |
300 | u32 cmd = le32_to_cpu(mem->command); | 448 | u32 cmd = 0; |
449 | |||
450 | if (!scpi_info->is_legacy) | ||
451 | cmd = le32_to_cpu(mem->command); | ||
301 | 452 | ||
302 | scpi_process_cmd(ch, cmd); | 453 | scpi_process_cmd(ch, cmd); |
303 | } | 454 | } |
@@ -309,8 +460,13 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg) | |||
309 | struct scpi_chan *ch = container_of(c, struct scpi_chan, cl); | 460 | struct scpi_chan *ch = container_of(c, struct scpi_chan, cl); |
310 | struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload; | 461 | struct scpi_shared_mem *mem = (struct scpi_shared_mem *)ch->tx_payload; |
311 | 462 | ||
312 | if (t->tx_buf) | 463 | if (t->tx_buf) { |
313 | memcpy_toio(mem->payload, t->tx_buf, t->tx_len); | 464 | if (scpi_info->is_legacy) |
465 | memcpy_toio(ch->tx_payload, t->tx_buf, t->tx_len); | ||
466 | else | ||
467 | memcpy_toio(mem->payload, t->tx_buf, t->tx_len); | ||
468 | } | ||
469 | |||
314 | if (t->rx_buf) { | 470 | if (t->rx_buf) { |
315 | if (!(++ch->token)) | 471 | if (!(++ch->token)) |
316 | ++ch->token; | 472 | ++ch->token; |
@@ -319,7 +475,9 @@ static void scpi_tx_prepare(struct mbox_client *c, void *msg) | |||
319 | list_add_tail(&t->node, &ch->rx_pending); | 475 | list_add_tail(&t->node, &ch->rx_pending); |
320 | spin_unlock_irqrestore(&ch->rx_lock, flags); | 476 | spin_unlock_irqrestore(&ch->rx_lock, flags); |
321 | } | 477 | } |
322 | mem->command = cpu_to_le32(t->cmd); | 478 | |
479 | if (!scpi_info->is_legacy) | ||
480 | mem->command = cpu_to_le32(t->cmd); | ||
323 | } | 481 | } |
324 | 482 | ||
325 | static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch) | 483 | static struct scpi_xfer *get_scpi_xfer(struct scpi_chan *ch) |
@@ -344,23 +502,38 @@ static void put_scpi_xfer(struct scpi_xfer *t, struct scpi_chan *ch) | |||
344 | mutex_unlock(&ch->xfers_lock); | 502 | mutex_unlock(&ch->xfers_lock); |
345 | } | 503 | } |
346 | 504 | ||
347 | static int scpi_send_message(u8 cmd, void *tx_buf, unsigned int tx_len, | 505 | static int scpi_send_message(u8 idx, void *tx_buf, unsigned int tx_len, |
348 | void *rx_buf, unsigned int rx_len) | 506 | void *rx_buf, unsigned int rx_len) |
349 | { | 507 | { |
350 | int ret; | 508 | int ret; |
351 | u8 chan; | 509 | u8 chan; |
510 | u8 cmd; | ||
352 | struct scpi_xfer *msg; | 511 | struct scpi_xfer *msg; |
353 | struct scpi_chan *scpi_chan; | 512 | struct scpi_chan *scpi_chan; |
354 | 513 | ||
355 | chan = atomic_inc_return(&scpi_info->next_chan) % scpi_info->num_chans; | 514 | if (scpi_info->commands[idx] < 0) |
515 | return -EOPNOTSUPP; | ||
516 | |||
517 | cmd = scpi_info->commands[idx]; | ||
518 | |||
519 | if (scpi_info->is_legacy) | ||
520 | chan = test_bit(cmd, scpi_info->cmd_priority) ? 1 : 0; | ||
521 | else | ||
522 | chan = atomic_inc_return(&scpi_info->next_chan) % | ||
523 | scpi_info->num_chans; | ||
356 | scpi_chan = scpi_info->channels + chan; | 524 | scpi_chan = scpi_info->channels + chan; |
357 | 525 | ||
358 | msg = get_scpi_xfer(scpi_chan); | 526 | msg = get_scpi_xfer(scpi_chan); |
359 | if (!msg) | 527 | if (!msg) |
360 | return -ENOMEM; | 528 | return -ENOMEM; |
361 | 529 | ||
362 | msg->slot = BIT(SCPI_SLOT); | 530 | if (scpi_info->is_legacy) { |
363 | msg->cmd = PACK_SCPI_CMD(cmd, tx_len); | 531 | msg->cmd = PACK_LEGACY_SCPI_CMD(cmd, tx_len); |
532 | msg->slot = msg->cmd; | ||
533 | } else { | ||
534 | msg->slot = BIT(SCPI_SLOT); | ||
535 | msg->cmd = PACK_SCPI_CMD(cmd, tx_len); | ||
536 | } | ||
364 | msg->tx_buf = tx_buf; | 537 | msg->tx_buf = tx_buf; |
365 | msg->tx_len = tx_len; | 538 | msg->tx_len = tx_len; |
366 | msg->rx_buf = rx_buf; | 539 | msg->rx_buf = rx_buf; |
@@ -397,7 +570,7 @@ scpi_clk_get_range(u16 clk_id, unsigned long *min, unsigned long *max) | |||
397 | struct clk_get_info clk; | 570 | struct clk_get_info clk; |
398 | __le16 le_clk_id = cpu_to_le16(clk_id); | 571 | __le16 le_clk_id = cpu_to_le16(clk_id); |
399 | 572 | ||
400 | ret = scpi_send_message(SCPI_CMD_GET_CLOCK_INFO, &le_clk_id, | 573 | ret = scpi_send_message(CMD_GET_CLOCK_INFO, &le_clk_id, |
401 | sizeof(le_clk_id), &clk, sizeof(clk)); | 574 | sizeof(le_clk_id), &clk, sizeof(clk)); |
402 | if (!ret) { | 575 | if (!ret) { |
403 | *min = le32_to_cpu(clk.min_rate); | 576 | *min = le32_to_cpu(clk.min_rate); |
@@ -412,8 +585,9 @@ static unsigned long scpi_clk_get_val(u16 clk_id) | |||
412 | struct clk_get_value clk; | 585 | struct clk_get_value clk; |
413 | __le16 le_clk_id = cpu_to_le16(clk_id); | 586 | __le16 le_clk_id = cpu_to_le16(clk_id); |
414 | 587 | ||
415 | ret = scpi_send_message(SCPI_CMD_GET_CLOCK_VALUE, &le_clk_id, | 588 | ret = scpi_send_message(CMD_GET_CLOCK_VALUE, &le_clk_id, |
416 | sizeof(le_clk_id), &clk, sizeof(clk)); | 589 | sizeof(le_clk_id), &clk, sizeof(clk)); |
590 | |||
417 | return ret ? ret : le32_to_cpu(clk.rate); | 591 | return ret ? ret : le32_to_cpu(clk.rate); |
418 | } | 592 | } |
419 | 593 | ||
@@ -425,7 +599,19 @@ static int scpi_clk_set_val(u16 clk_id, unsigned long rate) | |||
425 | .rate = cpu_to_le32(rate) | 599 | .rate = cpu_to_le32(rate) |
426 | }; | 600 | }; |
427 | 601 | ||
428 | return scpi_send_message(SCPI_CMD_SET_CLOCK_VALUE, &clk, sizeof(clk), | 602 | return scpi_send_message(CMD_SET_CLOCK_VALUE, &clk, sizeof(clk), |
603 | &stat, sizeof(stat)); | ||
604 | } | ||
605 | |||
606 | static int legacy_scpi_clk_set_val(u16 clk_id, unsigned long rate) | ||
607 | { | ||
608 | int stat; | ||
609 | struct legacy_clk_set_value clk = { | ||
610 | .id = cpu_to_le16(clk_id), | ||
611 | .rate = cpu_to_le32(rate) | ||
612 | }; | ||
613 | |||
614 | return scpi_send_message(CMD_SET_CLOCK_VALUE, &clk, sizeof(clk), | ||
429 | &stat, sizeof(stat)); | 615 | &stat, sizeof(stat)); |
430 | } | 616 | } |
431 | 617 | ||
@@ -434,8 +620,9 @@ static int scpi_dvfs_get_idx(u8 domain) | |||
434 | int ret; | 620 | int ret; |
435 | u8 dvfs_idx; | 621 | u8 dvfs_idx; |
436 | 622 | ||
437 | ret = scpi_send_message(SCPI_CMD_GET_DVFS, &domain, sizeof(domain), | 623 | ret = scpi_send_message(CMD_GET_DVFS, &domain, sizeof(domain), |
438 | &dvfs_idx, sizeof(dvfs_idx)); | 624 | &dvfs_idx, sizeof(dvfs_idx)); |
625 | |||
439 | return ret ? ret : dvfs_idx; | 626 | return ret ? ret : dvfs_idx; |
440 | } | 627 | } |
441 | 628 | ||
@@ -444,7 +631,7 @@ static int scpi_dvfs_set_idx(u8 domain, u8 index) | |||
444 | int stat; | 631 | int stat; |
445 | struct dvfs_set dvfs = {domain, index}; | 632 | struct dvfs_set dvfs = {domain, index}; |
446 | 633 | ||
447 | return scpi_send_message(SCPI_CMD_SET_DVFS, &dvfs, sizeof(dvfs), | 634 | return scpi_send_message(CMD_SET_DVFS, &dvfs, sizeof(dvfs), |
448 | &stat, sizeof(stat)); | 635 | &stat, sizeof(stat)); |
449 | } | 636 | } |
450 | 637 | ||
@@ -468,9 +655,8 @@ static struct scpi_dvfs_info *scpi_dvfs_get_info(u8 domain) | |||
468 | if (scpi_info->dvfs[domain]) /* data already populated */ | 655 | if (scpi_info->dvfs[domain]) /* data already populated */ |
469 | return scpi_info->dvfs[domain]; | 656 | return scpi_info->dvfs[domain]; |
470 | 657 | ||
471 | ret = scpi_send_message(SCPI_CMD_GET_DVFS_INFO, &domain, sizeof(domain), | 658 | ret = scpi_send_message(CMD_GET_DVFS_INFO, &domain, sizeof(domain), |
472 | &buf, sizeof(buf)); | 659 | &buf, sizeof(buf)); |
473 | |||
474 | if (ret) | 660 | if (ret) |
475 | return ERR_PTR(ret); | 661 | return ERR_PTR(ret); |
476 | 662 | ||
@@ -503,7 +689,7 @@ static int scpi_sensor_get_capability(u16 *sensors) | |||
503 | struct sensor_capabilities cap_buf; | 689 | struct sensor_capabilities cap_buf; |
504 | int ret; | 690 | int ret; |
505 | 691 | ||
506 | ret = scpi_send_message(SCPI_CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf, | 692 | ret = scpi_send_message(CMD_SENSOR_CAPABILITIES, NULL, 0, &cap_buf, |
507 | sizeof(cap_buf)); | 693 | sizeof(cap_buf)); |
508 | if (!ret) | 694 | if (!ret) |
509 | *sensors = le16_to_cpu(cap_buf.sensors); | 695 | *sensors = le16_to_cpu(cap_buf.sensors); |
@@ -517,7 +703,7 @@ static int scpi_sensor_get_info(u16 sensor_id, struct scpi_sensor_info *info) | |||
517 | struct _scpi_sensor_info _info; | 703 | struct _scpi_sensor_info _info; |
518 | int ret; | 704 | int ret; |
519 | 705 | ||
520 | ret = scpi_send_message(SCPI_CMD_SENSOR_INFO, &id, sizeof(id), | 706 | ret = scpi_send_message(CMD_SENSOR_INFO, &id, sizeof(id), |
521 | &_info, sizeof(_info)); | 707 | &_info, sizeof(_info)); |
522 | if (!ret) { | 708 | if (!ret) { |
523 | memcpy(info, &_info, sizeof(*info)); | 709 | memcpy(info, &_info, sizeof(*info)); |
@@ -533,7 +719,7 @@ static int scpi_sensor_get_value(u16 sensor, u64 *val) | |||
533 | struct sensor_value buf; | 719 | struct sensor_value buf; |
534 | int ret; | 720 | int ret; |
535 | 721 | ||
536 | ret = scpi_send_message(SCPI_CMD_SENSOR_VALUE, &id, sizeof(id), | 722 | ret = scpi_send_message(CMD_SENSOR_VALUE, &id, sizeof(id), |
537 | &buf, sizeof(buf)); | 723 | &buf, sizeof(buf)); |
538 | if (!ret) | 724 | if (!ret) |
539 | *val = (u64)le32_to_cpu(buf.hi_val) << 32 | | 725 | *val = (u64)le32_to_cpu(buf.hi_val) << 32 | |
@@ -548,7 +734,7 @@ static int scpi_device_get_power_state(u16 dev_id) | |||
548 | u8 pstate; | 734 | u8 pstate; |
549 | __le16 id = cpu_to_le16(dev_id); | 735 | __le16 id = cpu_to_le16(dev_id); |
550 | 736 | ||
551 | ret = scpi_send_message(SCPI_CMD_GET_DEVICE_PWR_STATE, &id, | 737 | ret = scpi_send_message(CMD_GET_DEVICE_PWR_STATE, &id, |
552 | sizeof(id), &pstate, sizeof(pstate)); | 738 | sizeof(id), &pstate, sizeof(pstate)); |
553 | return ret ? ret : pstate; | 739 | return ret ? ret : pstate; |
554 | } | 740 | } |
@@ -561,7 +747,7 @@ static int scpi_device_set_power_state(u16 dev_id, u8 pstate) | |||
561 | .pstate = pstate, | 747 | .pstate = pstate, |
562 | }; | 748 | }; |
563 | 749 | ||
564 | return scpi_send_message(SCPI_CMD_SET_DEVICE_PWR_STATE, &dev_set, | 750 | return scpi_send_message(CMD_SET_DEVICE_PWR_STATE, &dev_set, |
565 | sizeof(dev_set), &stat, sizeof(stat)); | 751 | sizeof(dev_set), &stat, sizeof(stat)); |
566 | } | 752 | } |
567 | 753 | ||
@@ -591,12 +777,16 @@ static int scpi_init_versions(struct scpi_drvinfo *info) | |||
591 | int ret; | 777 | int ret; |
592 | struct scp_capabilities caps; | 778 | struct scp_capabilities caps; |
593 | 779 | ||
594 | ret = scpi_send_message(SCPI_CMD_SCPI_CAPABILITIES, NULL, 0, | 780 | ret = scpi_send_message(CMD_SCPI_CAPABILITIES, NULL, 0, |
595 | &caps, sizeof(caps)); | 781 | &caps, sizeof(caps)); |
596 | if (!ret) { | 782 | if (!ret) { |
597 | info->protocol_version = le32_to_cpu(caps.protocol_version); | 783 | info->protocol_version = le32_to_cpu(caps.protocol_version); |
598 | info->firmware_version = le32_to_cpu(caps.platform_version); | 784 | info->firmware_version = le32_to_cpu(caps.platform_version); |
599 | } | 785 | } |
786 | /* Ignore error if not implemented */ | ||
787 | if (scpi_info->is_legacy && ret == -EOPNOTSUPP) | ||
788 | return 0; | ||
789 | |||
600 | return ret; | 790 | return ret; |
601 | } | 791 | } |
602 | 792 | ||
@@ -681,6 +871,11 @@ static int scpi_alloc_xfer_list(struct device *dev, struct scpi_chan *ch) | |||
681 | return 0; | 871 | return 0; |
682 | } | 872 | } |
683 | 873 | ||
874 | static const struct of_device_id legacy_scpi_of_match[] = { | ||
875 | {.compatible = "arm,scpi-pre-1.0"}, | ||
876 | {}, | ||
877 | }; | ||
878 | |||
684 | static int scpi_probe(struct platform_device *pdev) | 879 | static int scpi_probe(struct platform_device *pdev) |
685 | { | 880 | { |
686 | int count, idx, ret; | 881 | int count, idx, ret; |
@@ -693,6 +888,9 @@ static int scpi_probe(struct platform_device *pdev) | |||
693 | if (!scpi_info) | 888 | if (!scpi_info) |
694 | return -ENOMEM; | 889 | return -ENOMEM; |
695 | 890 | ||
891 | if (of_match_device(legacy_scpi_of_match, &pdev->dev)) | ||
892 | scpi_info->is_legacy = true; | ||
893 | |||
696 | count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); | 894 | count = of_count_phandle_with_args(np, "mboxes", "#mbox-cells"); |
697 | if (count < 0) { | 895 | if (count < 0) { |
698 | dev_err(dev, "no mboxes property in '%s'\n", np->full_name); | 896 | dev_err(dev, "no mboxes property in '%s'\n", np->full_name); |
@@ -755,8 +953,21 @@ err: | |||
755 | 953 | ||
756 | scpi_info->channels = scpi_chan; | 954 | scpi_info->channels = scpi_chan; |
757 | scpi_info->num_chans = count; | 955 | scpi_info->num_chans = count; |
956 | scpi_info->commands = scpi_std_commands; | ||
957 | |||
758 | platform_set_drvdata(pdev, scpi_info); | 958 | platform_set_drvdata(pdev, scpi_info); |
759 | 959 | ||
960 | if (scpi_info->is_legacy) { | ||
961 | /* Replace with legacy variants */ | ||
962 | scpi_ops.clk_set_val = legacy_scpi_clk_set_val; | ||
963 | scpi_info->commands = scpi_legacy_commands; | ||
964 | |||
965 | /* Fill priority bitmap */ | ||
966 | for (idx = 0; idx < ARRAY_SIZE(legacy_hpriority_cmds); idx++) | ||
967 | set_bit(legacy_hpriority_cmds[idx], | ||
968 | scpi_info->cmd_priority); | ||
969 | } | ||
970 | |||
760 | ret = scpi_init_versions(scpi_info); | 971 | ret = scpi_init_versions(scpi_info); |
761 | if (ret) { | 972 | if (ret) { |
762 | dev_err(dev, "incorrect or no SCP firmware found\n"); | 973 | dev_err(dev, "incorrect or no SCP firmware found\n"); |
@@ -781,6 +992,7 @@ err: | |||
781 | 992 | ||
782 | static const struct of_device_id scpi_of_match[] = { | 993 | static const struct of_device_id scpi_of_match[] = { |
783 | {.compatible = "arm,scpi"}, | 994 | {.compatible = "arm,scpi"}, |
995 | {.compatible = "arm,scpi-pre-1.0"}, | ||
784 | {}, | 996 | {}, |
785 | }; | 997 | }; |
786 | 998 | ||