Add SCMI v3.1 clock pre and post notifications.
Unified · Split
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/sort.h> | 10 | #include <linux/sort.h> |
| 11 | 11 | ||
| 12 | #include "protocols.h" | 12 | #include "protocols.h" |
| 13 | #include "notify.h" | ||
| 13 | 14 | ||
| 14 | enum scmi_clock_protocol_cmd { | 15 | enum scmi_clock_protocol_cmd { |
| 15 | CLOCK_ATTRIBUTES = 0x3, | 16 | CLOCK_ATTRIBUTES = 0x3, |
| @@ -18,6 +19,8 @@ enum scmi_clock_protocol_cmd { · 2 unmodified lines | |||
| 18 | CLOCK_RATE_GET = 0x6, | 19 | CLOCK_RATE_GET = 0x6, |
| 19 | CLOCK_CONFIG_SET = 0x7, | 20 | CLOCK_CONFIG_SET = 0x7, |
| 20 | CLOCK_NAME_GET = 0x8, | 21 | CLOCK_NAME_GET = 0x8, |
| 22 | CLOCK_RATE_NOTIFY = 0x9, | ||
| 23 | CLOCK_RATE_CHANGE_REQUESTED_NOTIFY = 0xA, | ||
| 21 | }; | 24 | }; |
| 22 | 25 | ||
| 23 | struct scmi_msg_resp_clock_protocol_attributes { | 26 | struct scmi_msg_resp_clock_protocol_attributes { |
| @@ -29,7 +32,9 @@ struct scmi_msg_resp_clock_protocol_attributes { · 5 unmodified lines | |||
| 29 | struct scmi_msg_resp_clock_attributes { | 32 | struct scmi_msg_resp_clock_attributes { |
| 30 | __le32 attributes; | 33 | __le32 attributes; |
| 31 | #define CLOCK_ENABLE BIT(0) | 34 | #define CLOCK_ENABLE BIT(0) |
| 32 | #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) | 35 | #define SUPPORTS_RATE_CHANGED_NOTIF(x) ((x) & BIT(31)) |
| 36 | #define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30)) | ||
| 37 | #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) | ||
| 33 | u8 name[SCMI_SHORT_NAME_MAX_SIZE]; | 38 | u8 name[SCMI_SHORT_NAME_MAX_SIZE]; |
| 34 | __le32 clock_enable_latency; | 39 | __le32 clock_enable_latency; |
| 35 | }; | 40 | }; |
| @@ -77,6 +82,18 @@ struct scmi_msg_resp_set_rate_complete { · 41 unmodified lines | |||
| 77 | __le32 rate_high; | 82 | __le32 rate_high; |
| 78 | }; | 83 | }; |
| 79 | 84 | ||
| 85 | struct scmi_msg_clock_rate_notify { | ||
| 86 | __le32 clk_id; | ||
| 87 | __le32 notify_enable; | ||
| 88 | }; | ||
| 89 | |||
| 90 | struct scmi_clock_rate_notify_payld { | ||
| 91 | __le32 agent_id; | ||
| 92 | __le32 clock_id; | ||
| 93 | __le32 rate_low; | ||
| 94 | __le32 rate_high; | ||
| 95 | }; | ||
| 96 | |||
| 80 | struct clock_info { | 97 | struct clock_info { |
| 81 | u32 version; | 98 | u32 version; |
| 82 | int num_clocks; | 99 | int num_clocks; |
| @@ -85,6 +102,11 @@ struct clock_info { · 2 unmodified lines | |||
| 85 | struct scmi_clock_info *clk; | 102 | struct scmi_clock_info *clk; |
| 86 | }; | 103 | }; |
| 87 | 104 | ||
| 105 | static enum scmi_clock_protocol_cmd evt_2_cmd[] = { | ||
| 106 | CLOCK_RATE_NOTIFY, | ||
| 107 | CLOCK_RATE_CHANGE_REQUESTED_NOTIFY, | ||
| 108 | }; | ||
| 109 | |||
| 88 | static int | 110 | static int |
| 89 | scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, | 111 | scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, |
| 90 | struct clock_info *ci) | 112 | struct clock_info *ci) |
| @@ -144,10 +166,17 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, · 53 unmodified lines | |||
| 144 | * If supported overwrite short name with the extended one; | 166 | * If supported overwrite short name with the extended one; |
| 145 | * on error just carry on and use already provided short name. | 167 | * on error just carry on and use already provided short name. |
| 146 | */ | 168 | */ |
| 147 | if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2 && | 169 | if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) { |
| 148 | SUPPORTS_EXTENDED_NAMES(attributes)) | 170 | if (SUPPORTS_EXTENDED_NAMES(attributes)) |
| 149 | ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, | 171 | ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, |
| 150 | clk->name, SCMI_MAX_STR_SIZE); | 172 | clk->name, |
| 173 | SCMI_MAX_STR_SIZE); | ||
| 174 | |||
| 175 | if (SUPPORTS_RATE_CHANGED_NOTIF(attributes)) | ||
| 176 | clk->rate_changed_notifications = true; | ||
| 177 | if (SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes)) | ||
| 178 | clk->rate_change_requested_notifications = true; | ||
| 179 | } | ||
| 151 | 180 | ||
| 152 | return ret; | 181 | return ret; |
| 153 | } | 182 | } |
| @@ -418,6 +447,102 @@ static const struct scmi_clk_proto_ops clk_proto_ops = { · 264 unmodified lines | |||
| 418 | .disable_atomic = scmi_clock_disable_atomic, | 447 | .disable_atomic = scmi_clock_disable_atomic, |
| 419 | }; | 448 | }; |
| 420 | 449 | ||
| 450 | static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph, | ||
| 451 | u32 clk_id, int message_id, bool enable) | ||
| 452 | { | ||
| 453 | int ret; | ||
| 454 | struct scmi_xfer *t; | ||
| 455 | struct scmi_msg_clock_rate_notify *notify; | ||
| 456 | |||
| 457 | ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t); | ||
| 458 | if (ret) | ||
| 459 | return ret; | ||
| 460 | |||
| 461 | notify = t->tx.buf; | ||
| 462 | notify->clk_id = cpu_to_le32(clk_id); | ||
| 463 | notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; | ||
| 464 | |||
| 465 | ret = ph->xops->do_xfer(ph, t); | ||
| 466 | |||
| 467 | ph->xops->xfer_put(ph, t); | ||
| 468 | return ret; | ||
| 469 | } | ||
| 470 | |||
| 471 | static int scmi_clk_set_notify_enabled(const struct scmi_protocol_handle *ph, | ||
| 472 | u8 evt_id, u32 src_id, bool enable) | ||
| 473 | { | ||
| 474 | int ret, cmd_id; | ||
| 475 | |||
| 476 | if (evt_id >= ARRAY_SIZE(evt_2_cmd)) | ||
| 477 | return -EINVAL; | ||
| 478 | |||
| 479 | cmd_id = evt_2_cmd[evt_id]; | ||
| 480 | ret = scmi_clk_rate_notify(ph, src_id, cmd_id, enable); | ||
| 481 | if (ret) | ||
| 482 | pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", | ||
| 483 | evt_id, src_id, ret); | ||
| 484 | |||
| 485 | return ret; | ||
| 486 | } | ||
| 487 | |||
| 488 | static void *scmi_clk_fill_custom_report(const struct scmi_protocol_handle *ph, | ||
| 489 | u8 evt_id, ktime_t timestamp, | ||
| 490 | const void *payld, size_t payld_sz, | ||
| 491 | void *report, u32 *src_id) | ||
| 492 | { | ||
| 493 | const struct scmi_clock_rate_notify_payld *p = payld; | ||
| 494 | struct scmi_clock_rate_notif_report *r = report; | ||
| 495 | |||
| 496 | if (sizeof(*p) != payld_sz || | ||
| 497 | (evt_id != SCMI_EVENT_CLOCK_RATE_CHANGED && | ||
| 498 | evt_id != SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED)) | ||
| 499 | return NULL; | ||
| 500 | |||
| 501 | r->timestamp = timestamp; | ||
| 502 | r->agent_id = le32_to_cpu(p->agent_id); | ||
| 503 | r->clock_id = le32_to_cpu(p->clock_id); | ||
| 504 | r->rate = get_unaligned_le64(&p->rate_low); | ||
| 505 | *src_id = r->clock_id; | ||
| 506 | |||
| 507 | return r; | ||
| 508 | } | ||
| 509 | |||
| 510 | static int scmi_clk_get_num_sources(const struct scmi_protocol_handle *ph) | ||
| 511 | { | ||
| 512 | struct clock_info *ci = ph->get_priv(ph); | ||
| 513 | |||
| 514 | if (!ci) | ||
| 515 | return -EINVAL; | ||
| 516 | |||
| 517 | return ci->num_clocks; | ||
| 518 | } | ||
| 519 | |||
| 520 | static const struct scmi_event clk_events[] = { | ||
| 521 | { | ||
| 522 | .id = SCMI_EVENT_CLOCK_RATE_CHANGED, | ||
| 523 | .max_payld_sz = sizeof(struct scmi_clock_rate_notify_payld), | ||
| 524 | .max_report_sz = sizeof(struct scmi_clock_rate_notif_report), | ||
| 525 | }, | ||
| 526 | { | ||
| 527 | .id = SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED, | ||
| 528 | .max_payld_sz = sizeof(struct scmi_clock_rate_notify_payld), | ||
| 529 | .max_report_sz = sizeof(struct scmi_clock_rate_notif_report), | ||
| 530 | }, | ||
| 531 | }; | ||
| 532 | |||
| 533 | static const struct scmi_event_ops clk_event_ops = { | ||
| 534 | .get_num_sources = scmi_clk_get_num_sources, | ||
| 535 | .set_notify_enabled = scmi_clk_set_notify_enabled, | ||
| 536 | .fill_custom_report = scmi_clk_fill_custom_report, | ||
| 537 | }; | ||
| 538 | |||
| 539 | static const struct scmi_protocol_events clk_protocol_events = { | ||
| 540 | .queue_sz = SCMI_PROTO_QUEUE_SZ, | ||
| 541 | .ops = &clk_event_ops, | ||
| 542 | .evts = clk_events, | ||
| 543 | .num_events = ARRAY_SIZE(clk_events), | ||
| 544 | }; | ||
| 545 | |||
| 421 | static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) | 546 | static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) |
| 422 | { | 547 | { |
| 423 | u32 version; | 548 | u32 version; |
| @@ -461,6 +586,7 @@ static const struct scmi_protocol scmi_clock = { · 37 unmodified lines | |||
| 461 | .owner = THIS_MODULE, | 586 | .owner = THIS_MODULE, |
| 462 | .instance_init = &scmi_clock_protocol_init, | 587 | .instance_init = &scmi_clock_protocol_init, |
| 463 | .ops = &clk_proto_ops, | 588 | .ops = &clk_proto_ops, |
| 589 | .events = &clk_protocol_events, | ||
| 464 | }; | 590 | }; |
| 465 | 591 | ||
| 466 | DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock) | 592 | DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock) |
| @@ -44,6 +44,8 @@ struct scmi_clock_info { · 43 unmodified lines | |||
| 44 | char name[SCMI_MAX_STR_SIZE]; | 44 | char name[SCMI_MAX_STR_SIZE]; |
| 45 | unsigned int enable_latency; | 45 | unsigned int enable_latency; |
| 46 | bool rate_discrete; | 46 | bool rate_discrete; |
| 47 | bool rate_changed_notifications; | ||
| 48 | bool rate_change_requested_notifications; | ||
| 47 | union { | 49 | union { |
| 48 | struct { | 50 | struct { |
| 49 | int num_rates; | 51 | int num_rates; |
| @@ -744,6 +746,8 @@ void scmi_protocol_unregister(const struct scmi_protocol *proto); · 694 unmodified lines | |||
| 744 | /* SCMI Notification API - Custom Event Reports */ | 746 | /* SCMI Notification API - Custom Event Reports */ |
| 745 | enum scmi_notification_events { | 747 | enum scmi_notification_events { |
| 746 | SCMI_EVENT_POWER_STATE_CHANGED = 0x0, | 748 | SCMI_EVENT_POWER_STATE_CHANGED = 0x0, |
| 749 | SCMI_EVENT_CLOCK_RATE_CHANGED = 0x0, | ||
| 750 | SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED = 0x1, | ||
| 747 | SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED = 0x0, | 751 | SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED = 0x0, |
| 748 | SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED = 0x1, | 752 | SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED = 0x1, |
| 749 | SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0, | 753 | SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0, |
| @@ -760,6 +764,13 @@ struct scmi_power_state_changed_report { · 10 unmodified lines | |||
| 760 | unsigned int power_state; | 764 | unsigned int power_state; |
| 761 | }; | 765 | }; |
| 762 | 766 | ||
| 767 | struct scmi_clock_rate_notif_report { | ||
| 768 | ktime_t timestamp; | ||
| 769 | unsigned int agent_id; | ||
| 770 | unsigned int clock_id; | ||
| 771 | unsigned long long rate; | ||
| 772 | }; | ||
| 773 | |||
| 763 | struct scmi_system_power_state_notifier_report { | 774 | struct scmi_system_power_state_notifier_report { |
| 764 | ktime_t timestamp; | 775 | ktime_t timestamp; |
| 765 | unsigned int agent_id; | 776 | unsigned int agent_id; |