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

firmware: arm_scmi: Implement clock get permissions

ARM SCMI v3.2 introduces clock get permission command. To implement the
same let us stash the values of those permissions in the scmi_clock_info.
They indicate if the operation is forbidden or not.

If the CLOCK_GET_PERMISSIONS command is not supported, the default
permissions are set to allow the operations, otherwise they will be set
according to the response of CLOCK_GET_PERMISSIONS from the SCMI
platform firmware.

Reviewed-by: Cristian Marussi <cristian.marussi@arm.com>
Signed-off-by: Peng Fan <peng.fan@nxp.com>
Link: https://lore.kernel.org/r/20240121110901.1414856-1-peng.fan@oss.nxp.com
Signed-off-by: Sudeep Holla <sudeep.holla@arm.com>

authored by

Peng Fan and committed by
Sudeep Holla
dc36561e 2858f6e5

+67
+64
drivers/firmware/arm_scmi/clock.c
··· 28 28 CLOCK_POSSIBLE_PARENTS_GET = 0xC, 29 29 CLOCK_PARENT_SET = 0xD, 30 30 CLOCK_PARENT_GET = 0xE, 31 + CLOCK_GET_PERMISSIONS = 0xF, 31 32 }; 33 + 34 + #define CLOCK_STATE_CONTROL_ALLOWED BIT(31) 35 + #define CLOCK_PARENT_CONTROL_ALLOWED BIT(30) 36 + #define CLOCK_RATE_CONTROL_ALLOWED BIT(29) 32 37 33 38 enum clk_state { 34 39 CLK_STATE_DISABLE, ··· 54 49 #define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x) ((x) & BIT(30)) 55 50 #define SUPPORTS_EXTENDED_NAMES(x) ((x) & BIT(29)) 56 51 #define SUPPORTS_PARENT_CLOCK(x) ((x) & BIT(28)) 52 + #define SUPPORTS_GET_PERMISSIONS(x) ((x) & BIT(1)) 57 53 u8 name[SCMI_SHORT_NAME_MAX_SIZE]; 58 54 __le32 clock_enable_latency; 59 55 }; ··· 299 293 return ret; 300 294 } 301 295 296 + static int 297 + scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id, 298 + struct scmi_clock_info *clk) 299 + { 300 + struct scmi_xfer *t; 301 + u32 perm; 302 + int ret; 303 + 304 + ret = ph->xops->xfer_get_init(ph, CLOCK_GET_PERMISSIONS, 305 + sizeof(clk_id), sizeof(perm), &t); 306 + if (ret) 307 + return ret; 308 + 309 + put_unaligned_le32(clk_id, t->tx.buf); 310 + 311 + ret = ph->xops->do_xfer(ph, t); 312 + if (!ret) { 313 + perm = get_unaligned_le32(t->rx.buf); 314 + 315 + clk->state_ctrl_forbidden = !(perm & CLOCK_STATE_CONTROL_ALLOWED); 316 + clk->rate_ctrl_forbidden = !(perm & CLOCK_RATE_CONTROL_ALLOWED); 317 + clk->parent_ctrl_forbidden = !(perm & CLOCK_PARENT_CONTROL_ALLOWED); 318 + } 319 + 320 + ph->xops->xfer_put(ph, t); 321 + 322 + return ret; 323 + } 324 + 302 325 static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph, 303 326 u32 clk_id, struct scmi_clock_info *clk, 304 327 u32 version) ··· 374 339 clk->rate_change_requested_notifications = true; 375 340 if (SUPPORTS_PARENT_CLOCK(attributes)) 376 341 scmi_clock_possible_parents(ph, clk_id, clk); 342 + if (SUPPORTS_GET_PERMISSIONS(attributes)) 343 + scmi_clock_get_permissions(ph, clk_id, clk); 377 344 } 378 345 379 346 return ret; ··· 548 511 struct scmi_xfer *t; 549 512 struct scmi_clock_set_rate *cfg; 550 513 struct clock_info *ci = ph->get_priv(ph); 514 + struct scmi_clock_info *clk; 515 + 516 + clk = scmi_clock_domain_lookup(ci, clk_id); 517 + if (IS_ERR(clk)) 518 + return PTR_ERR(clk); 519 + 520 + if (clk->rate_ctrl_forbidden) 521 + return -EACCES; 551 522 552 523 ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t); 553 524 if (ret) ··· 641 596 if (parent_id >= clk->num_parents) 642 597 return -EINVAL; 643 598 599 + if (clk->parent_ctrl_forbidden) 600 + return -EACCES; 601 + 644 602 ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET, 645 603 sizeof(*cfg), 0, &t); 646 604 if (ret) ··· 727 679 bool atomic) 728 680 { 729 681 struct clock_info *ci = ph->get_priv(ph); 682 + struct scmi_clock_info *clk; 683 + 684 + clk = scmi_clock_domain_lookup(ci, clk_id); 685 + if (IS_ERR(clk)) 686 + return PTR_ERR(clk); 687 + 688 + if (clk->state_ctrl_forbidden) 689 + return -EACCES; 730 690 731 691 return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE, 732 692 NULL_OEM_TYPE, 0, atomic); ··· 744 688 bool atomic) 745 689 { 746 690 struct clock_info *ci = ph->get_priv(ph); 691 + struct scmi_clock_info *clk; 692 + 693 + clk = scmi_clock_domain_lookup(ci, clk_id); 694 + if (IS_ERR(clk)) 695 + return PTR_ERR(clk); 696 + 697 + if (clk->state_ctrl_forbidden) 698 + return -EACCES; 747 699 748 700 return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE, 749 701 NULL_OEM_TYPE, 0, atomic);
+3
include/linux/scmi_protocol.h
··· 47 47 bool rate_discrete; 48 48 bool rate_changed_notifications; 49 49 bool rate_change_requested_notifications; 50 + bool state_ctrl_forbidden; 51 + bool rate_ctrl_forbidden; 52 + bool parent_ctrl_forbidden; 50 53 union { 51 54 struct { 52 55 int num_rates;