Add SCMI v3.1 clock pre and post notifications.
Unified · Split
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/sort.h> |
| 11 | 11 | |
| 12 | 12 | #include "protocols.h" |
| 13 | +#include "notify.h" | |
| 13 | 14 | |
| 14 | 15 | enum scmi_clock_protocol_cmd { |
| 15 | 16 | CLOCK_ATTRIBUTES = 0x3, |
| @@ -18,6 +19,8 @@ enum scmi_clock_protocol_cmd { · 2 unmodified lines | ||
| 18 | 19 | CLOCK_RATE_GET = 0x6, |
| 19 | 20 | CLOCK_CONFIG_SET = 0x7, |
| 20 | 21 | CLOCK_NAME_GET = 0x8, |
| 22 | + CLOCK_RATE_NOTIFY = 0x9, | |
| 23 | + CLOCK_RATE_CHANGE_REQUESTED_NOTIFY = 0xA, | |
| 21 | 24 | }; |
| 22 | 25 | |
| 23 | 26 | struct scmi_msg_resp_clock_protocol_attributes { |
| @@ -29,7 +32,9 @@ struct scmi_msg_resp_clock_protocol_attributes { · 5 unmodified lines | ||
| 29 | 32 | struct scmi_msg_resp_clock_attributes { |
| 30 | 33 | __le32 attributes; |
| 31 | 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 | 38 | u8 name[SCMI_SHORT_NAME_MAX_SIZE]; |
| 34 | 39 | __le32 clock_enable_latency; |
| 35 | 40 | }; |
| @@ -77,6 +82,18 @@ struct scmi_msg_resp_set_rate_complete { · 41 unmodified lines | ||
| 77 | 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 | 97 | struct clock_info { |
| 81 | 98 | u32 version; |
| 82 | 99 | int num_clocks; |
| @@ -85,6 +102,11 @@ struct clock_info { · 2 unmodified lines | ||
| 85 | 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 | 110 | static int |
| 89 | 111 | scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph, |
| 90 | 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 | 166 | * If supported overwrite short name with the extended one; |
| 145 | 167 | * on error just carry on and use already provided short name. |
| 146 | 168 | */ |
| 147 | − if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2 && | |
| 148 | − SUPPORTS_EXTENDED_NAMES(attributes)) | |
| 149 | − ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, | |
| 150 | − clk->name, SCMI_MAX_STR_SIZE); | |
| 169 | + if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) { | |
| 170 | + if (SUPPORTS_EXTENDED_NAMES(attributes)) | |
| 171 | + ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, | |
| 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 | 181 | return ret; |
| 153 | 182 | } |
| @@ -418,6 +447,102 @@ static const struct scmi_clk_proto_ops clk_proto_ops = { · 264 unmodified lines | ||
| 418 | 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 | 546 | static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) |
| 422 | 547 | { |
| 423 | 548 | u32 version; |
| @@ -461,6 +586,7 @@ static const struct scmi_protocol scmi_clock = { · 37 unmodified lines | ||
| 461 | 586 | .owner = THIS_MODULE, |
| 462 | 587 | .instance_init = &scmi_clock_protocol_init, |
| 463 | 588 | .ops = &clk_proto_ops, |
| 589 | + .events = &clk_protocol_events, | |
| 464 | 590 | }; |
| 465 | 591 | |
| 466 | 592 | DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock) |
| @@ -44,6 +44,8 @@ struct scmi_clock_info { · 43 unmodified lines | ||
| 44 | 44 | char name[SCMI_MAX_STR_SIZE]; |
| 45 | 45 | unsigned int enable_latency; |
| 46 | 46 | bool rate_discrete; |
| 47 | + bool rate_changed_notifications; | |
| 48 | + bool rate_change_requested_notifications; | |
| 47 | 49 | union { |
| 48 | 50 | struct { |
| 49 | 51 | int num_rates; |
| @@ -744,6 +746,8 @@ void scmi_protocol_unregister(const struct scmi_protocol *proto); · 694 unmodified lines | ||
| 744 | 746 | /* SCMI Notification API - Custom Event Reports */ |
| 745 | 747 | enum scmi_notification_events { |
| 746 | 748 | SCMI_EVENT_POWER_STATE_CHANGED = 0x0, |
| 749 | + SCMI_EVENT_CLOCK_RATE_CHANGED = 0x0, | |
| 750 | + SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED = 0x1, | |
| 747 | 751 | SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED = 0x0, |
| 748 | 752 | SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED = 0x1, |
| 749 | 753 | SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0, |
| @@ -760,6 +764,13 @@ struct scmi_power_state_changed_report { · 10 unmodified lines | ||
| 760 | 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 | 774 | struct scmi_system_power_state_notifier_report { |
| 764 | 775 | ktime_t timestamp; |
| 765 | 776 | unsigned int agent_id; |