Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware: arm_scmi: Add SCMI v3.1 clock notifications

Add SCMI v3.1 clock pre and post notifications.

Link: https://lore.kernel.org/r/20220330150551.2573938-20-cristian.marussi@arm.com
Signed-off-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

authored by

Cristian Marussi and committed by
Sudeep Holla
7aa75496 71bea057

+142 -5
+131 -5
drivers/firmware/arm_scmi/clock.c
··· 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, ··· 19 18 CLOCK_RATE_GET = 0x6, 20 19 CLOCK_CONFIG_SET = 0x7, 21 20 CLOCK_NAME_GET = 0x8, 21 + CLOCK_RATE_NOTIFY = 0x9, 22 + CLOCK_RATE_CHANGE_REQUESTED_NOTIFY = 0xA, 22 23 }; 23 24 24 25 struct scmi_msg_resp_clock_protocol_attributes { ··· 32 29 struct scmi_msg_resp_clock_attributes { 33 30 __le32 attributes; 34 31 #define CLOCK_ENABLE BIT(0) 35 - #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) 32 + #define SUPPORTS_RATE_CHANGED_NOTIF(x) ((x) & BIT(31)) 33 + #define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30)) 34 + #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) 36 35 u8 name[SCMI_SHORT_NAME_MAX_SIZE]; 37 36 __le32 clock_enable_latency; 38 37 }; ··· 82 77 __le32 rate_high; 83 78 }; 84 79 80 + struct scmi_msg_clock_rate_notify { 81 + __le32 clk_id; 82 + __le32 notify_enable; 83 + }; 84 + 85 + struct scmi_clock_rate_notify_payld { 86 + __le32 agent_id; 87 + __le32 clock_id; 88 + __le32 rate_low; 89 + __le32 rate_high; 90 + }; 91 + 85 92 struct clock_info { 86 93 u32 version; 87 94 int num_clocks; 88 95 int max_async_req; 89 96 atomic_t cur_async_req; 90 97 struct scmi_clock_info *clk; 98 + }; 99 + 100 + static enum scmi_clock_protocol_cmd evt_2_cmd[] = { 101 + CLOCK_RATE_NOTIFY, 102 + CLOCK_RATE_CHANGE_REQUESTED_NOTIFY, 91 103 }; 92 104 93 105 static int ··· 166 144 * If supported overwrite short name with the extended one; 167 145 * on error just carry on and use already provided short name. 168 146 */ 169 - if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2 && 170 - SUPPORTS_EXTENDED_NAMES(attributes)) 171 - ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, 172 - clk->name, SCMI_MAX_STR_SIZE); 147 + if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) { 148 + if (SUPPORTS_EXTENDED_NAMES(attributes)) 149 + ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id, 150 + clk->name, 151 + SCMI_MAX_STR_SIZE); 152 + 153 + if (SUPPORTS_RATE_CHANGED_NOTIF(attributes)) 154 + clk->rate_changed_notifications = true; 155 + if (SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes)) 156 + clk->rate_change_requested_notifications = true; 157 + } 173 158 174 159 return ret; 175 160 } ··· 447 418 .disable_atomic = scmi_clock_disable_atomic, 448 419 }; 449 420 421 + static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph, 422 + u32 clk_id, int message_id, bool enable) 423 + { 424 + int ret; 425 + struct scmi_xfer *t; 426 + struct scmi_msg_clock_rate_notify *notify; 427 + 428 + ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t); 429 + if (ret) 430 + return ret; 431 + 432 + notify = t->tx.buf; 433 + notify->clk_id = cpu_to_le32(clk_id); 434 + notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0; 435 + 436 + ret = ph->xops->do_xfer(ph, t); 437 + 438 + ph->xops->xfer_put(ph, t); 439 + return ret; 440 + } 441 + 442 + static int scmi_clk_set_notify_enabled(const struct scmi_protocol_handle *ph, 443 + u8 evt_id, u32 src_id, bool enable) 444 + { 445 + int ret, cmd_id; 446 + 447 + if (evt_id >= ARRAY_SIZE(evt_2_cmd)) 448 + return -EINVAL; 449 + 450 + cmd_id = evt_2_cmd[evt_id]; 451 + ret = scmi_clk_rate_notify(ph, src_id, cmd_id, enable); 452 + if (ret) 453 + pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n", 454 + evt_id, src_id, ret); 455 + 456 + return ret; 457 + } 458 + 459 + static void *scmi_clk_fill_custom_report(const struct scmi_protocol_handle *ph, 460 + u8 evt_id, ktime_t timestamp, 461 + const void *payld, size_t payld_sz, 462 + void *report, u32 *src_id) 463 + { 464 + const struct scmi_clock_rate_notify_payld *p = payld; 465 + struct scmi_clock_rate_notif_report *r = report; 466 + 467 + if (sizeof(*p) != payld_sz || 468 + (evt_id != SCMI_EVENT_CLOCK_RATE_CHANGED && 469 + evt_id != SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED)) 470 + return NULL; 471 + 472 + r->timestamp = timestamp; 473 + r->agent_id = le32_to_cpu(p->agent_id); 474 + r->clock_id = le32_to_cpu(p->clock_id); 475 + r->rate = get_unaligned_le64(&p->rate_low); 476 + *src_id = r->clock_id; 477 + 478 + return r; 479 + } 480 + 481 + static int scmi_clk_get_num_sources(const struct scmi_protocol_handle *ph) 482 + { 483 + struct clock_info *ci = ph->get_priv(ph); 484 + 485 + if (!ci) 486 + return -EINVAL; 487 + 488 + return ci->num_clocks; 489 + } 490 + 491 + static const struct scmi_event clk_events[] = { 492 + { 493 + .id = SCMI_EVENT_CLOCK_RATE_CHANGED, 494 + .max_payld_sz = sizeof(struct scmi_clock_rate_notify_payld), 495 + .max_report_sz = sizeof(struct scmi_clock_rate_notif_report), 496 + }, 497 + { 498 + .id = SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED, 499 + .max_payld_sz = sizeof(struct scmi_clock_rate_notify_payld), 500 + .max_report_sz = sizeof(struct scmi_clock_rate_notif_report), 501 + }, 502 + }; 503 + 504 + static const struct scmi_event_ops clk_event_ops = { 505 + .get_num_sources = scmi_clk_get_num_sources, 506 + .set_notify_enabled = scmi_clk_set_notify_enabled, 507 + .fill_custom_report = scmi_clk_fill_custom_report, 508 + }; 509 + 510 + static const struct scmi_protocol_events clk_protocol_events = { 511 + .queue_sz = SCMI_PROTO_QUEUE_SZ, 512 + .ops = &clk_event_ops, 513 + .evts = clk_events, 514 + .num_events = ARRAY_SIZE(clk_events), 515 + }; 516 + 450 517 static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph) 451 518 { 452 519 u32 version; ··· 586 461 .owner = THIS_MODULE, 587 462 .instance_init = &scmi_clock_protocol_init, 588 463 .ops = &clk_proto_ops, 464 + .events = &clk_protocol_events, 589 465 }; 590 466 591 467 DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock)
+11
include/linux/scmi_protocol.h
··· 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; ··· 746 744 /* SCMI Notification API - Custom Event Reports */ 747 745 enum scmi_notification_events { 748 746 SCMI_EVENT_POWER_STATE_CHANGED = 0x0, 747 + SCMI_EVENT_CLOCK_RATE_CHANGED = 0x0, 748 + SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED = 0x1, 749 749 SCMI_EVENT_PERFORMANCE_LIMITS_CHANGED = 0x0, 750 750 SCMI_EVENT_PERFORMANCE_LEVEL_CHANGED = 0x1, 751 751 SCMI_EVENT_SENSOR_TRIP_POINT_EVENT = 0x0, ··· 762 758 unsigned int agent_id; 763 759 unsigned int domain_id; 764 760 unsigned int power_state; 761 + }; 762 + 763 + struct scmi_clock_rate_notif_report { 764 + ktime_t timestamp; 765 + unsigned int agent_id; 766 + unsigned int clock_id; 767 + unsigned long long rate; 765 768 }; 766 769 767 770 struct scmi_system_power_state_notifier_report {