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

Configure Feed

Select the types of activity you want to include in your feed.

clk: Add clock driver for the RISC-V RPMI clock service group

The RPMI specification defines a clock service group which can be
accessed via SBI MPXY extension or dedicated S-mode RPMI transport.

Add mailbox client based clock driver for the RISC-V RPMI clock
service group.

Reviewed-by: Stephen Boyd <sboyd@kernel.org>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Co-developed-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Anup Patel <apatel@ventanamicro.com>
Signed-off-by: Rahul Pathak <rpathak@ventanamicro.com>
Link: https://lore.kernel.org/r/20250818040920.272664-11-apatel@ventanamicro.com
[pjw@kernel.org: converted rpmi_clkrate_u64 macro to a function; replaced bare constant with a macro]
Signed-off-by: Paul Walmsley <pjw@kernel.org>

authored by

Rahul Pathak and committed by
Paul Walmsley
5ba9f520 b3858302

+645
+8
drivers/clk/Kconfig
··· 501 501 Not all features of the PLL are currently supported 502 502 by the driver. 503 503 504 + config COMMON_CLK_RPMI 505 + tristate "Clock driver based on RISC-V RPMI" 506 + depends on MAILBOX 507 + default RISCV 508 + help 509 + Support for clocks based on the clock service group defined by 510 + the RISC-V platform management interface (RPMI) specification. 511 + 504 512 source "drivers/clk/actions/Kconfig" 505 513 source "drivers/clk/analogbits/Kconfig" 506 514 source "drivers/clk/baikal-t1/Kconfig"
+1
drivers/clk/Makefile
··· 86 86 obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o 87 87 obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o 88 88 obj-$(CONFIG_COMMON_CLK_RP1) += clk-rp1.o 89 + obj-$(CONFIG_COMMON_CLK_RPMI) += clk-rpmi.o 89 90 obj-$(CONFIG_COMMON_CLK_HI655X) += clk-hi655x.o 90 91 obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o 91 92 obj-$(CONFIG_COMMON_CLK_SCMI) += clk-scmi.o
+620
drivers/clk/clk-rpmi.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * RISC-V MPXY Based Clock Driver 4 + * 5 + * Copyright (C) 2025 Ventana Micro Systems Ltd. 6 + */ 7 + 8 + #include <linux/clk-provider.h> 9 + #include <linux/err.h> 10 + #include <linux/mailbox_client.h> 11 + #include <linux/mailbox/riscv-rpmi-message.h> 12 + #include <linux/module.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/types.h> 15 + #include <linux/slab.h> 16 + #include <linux/wordpart.h> 17 + 18 + #define RPMI_CLK_DISCRETE_MAX_NUM_RATES 16 19 + #define RPMI_CLK_NAME_LEN 16 20 + 21 + #define to_rpmi_clk(clk) container_of(clk, struct rpmi_clk, hw) 22 + 23 + enum rpmi_clk_config { 24 + RPMI_CLK_DISABLE = 0, 25 + RPMI_CLK_ENABLE = 1, 26 + RPMI_CLK_CONFIG_MAX_IDX 27 + }; 28 + 29 + #define RPMI_CLK_TYPE_MASK GENMASK(1, 0) 30 + enum rpmi_clk_type { 31 + RPMI_CLK_DISCRETE = 0, 32 + RPMI_CLK_LINEAR = 1, 33 + RPMI_CLK_TYPE_MAX_IDX 34 + }; 35 + 36 + struct rpmi_clk_context { 37 + struct device *dev; 38 + struct mbox_chan *chan; 39 + struct mbox_client client; 40 + u32 max_msg_data_size; 41 + }; 42 + 43 + /* 44 + * rpmi_clk_rates represents the rates format 45 + * as specified by the RPMI specification. 46 + * No other data format (e.g., struct linear_range) 47 + * is required to avoid to and from conversion. 48 + */ 49 + union rpmi_clk_rates { 50 + u64 discrete[RPMI_CLK_DISCRETE_MAX_NUM_RATES]; 51 + struct { 52 + u64 min; 53 + u64 max; 54 + u64 step; 55 + } linear; 56 + }; 57 + 58 + struct rpmi_clk { 59 + struct rpmi_clk_context *context; 60 + u32 id; 61 + u32 num_rates; 62 + u32 transition_latency; 63 + enum rpmi_clk_type type; 64 + union rpmi_clk_rates *rates; 65 + char name[RPMI_CLK_NAME_LEN]; 66 + struct clk_hw hw; 67 + }; 68 + 69 + struct rpmi_clk_rate_discrete { 70 + __le32 lo; 71 + __le32 hi; 72 + }; 73 + 74 + struct rpmi_clk_rate_linear { 75 + __le32 min_lo; 76 + __le32 min_hi; 77 + __le32 max_lo; 78 + __le32 max_hi; 79 + __le32 step_lo; 80 + __le32 step_hi; 81 + }; 82 + 83 + struct rpmi_get_num_clocks_rx { 84 + __le32 status; 85 + __le32 num_clocks; 86 + }; 87 + 88 + struct rpmi_get_attrs_tx { 89 + __le32 clkid; 90 + }; 91 + 92 + struct rpmi_get_attrs_rx { 93 + __le32 status; 94 + __le32 flags; 95 + __le32 num_rates; 96 + __le32 transition_latency; 97 + char name[RPMI_CLK_NAME_LEN]; 98 + }; 99 + 100 + struct rpmi_get_supp_rates_tx { 101 + __le32 clkid; 102 + __le32 clk_rate_idx; 103 + }; 104 + 105 + struct rpmi_get_supp_rates_rx { 106 + __le32 status; 107 + __le32 flags; 108 + __le32 remaining; 109 + __le32 returned; 110 + __le32 rates[]; 111 + }; 112 + 113 + struct rpmi_get_rate_tx { 114 + __le32 clkid; 115 + }; 116 + 117 + struct rpmi_get_rate_rx { 118 + __le32 status; 119 + __le32 lo; 120 + __le32 hi; 121 + }; 122 + 123 + struct rpmi_set_rate_tx { 124 + __le32 clkid; 125 + __le32 flags; 126 + __le32 lo; 127 + __le32 hi; 128 + }; 129 + 130 + struct rpmi_set_rate_rx { 131 + __le32 status; 132 + }; 133 + 134 + struct rpmi_set_config_tx { 135 + __le32 clkid; 136 + __le32 config; 137 + }; 138 + 139 + struct rpmi_set_config_rx { 140 + __le32 status; 141 + }; 142 + 143 + static inline u64 rpmi_clkrate_u64(u32 __hi, u32 __lo) 144 + { 145 + return (((u64)(__hi) << 32) | (u32)(__lo)); 146 + } 147 + 148 + static u32 rpmi_clk_get_num_clocks(struct rpmi_clk_context *context) 149 + { 150 + struct rpmi_get_num_clocks_rx rx, *resp; 151 + struct rpmi_mbox_message msg; 152 + int ret; 153 + 154 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_NUM_CLOCKS, 155 + NULL, 0, &rx, sizeof(rx)); 156 + 157 + ret = rpmi_mbox_send_message(context->chan, &msg); 158 + if (ret) 159 + return 0; 160 + 161 + resp = rpmi_mbox_get_msg_response(&msg); 162 + if (!resp || resp->status) 163 + return 0; 164 + 165 + return le32_to_cpu(resp->num_clocks); 166 + } 167 + 168 + static int rpmi_clk_get_attrs(u32 clkid, struct rpmi_clk *rpmi_clk) 169 + { 170 + struct rpmi_clk_context *context = rpmi_clk->context; 171 + struct rpmi_mbox_message msg; 172 + struct rpmi_get_attrs_tx tx; 173 + struct rpmi_get_attrs_rx rx, *resp; 174 + u8 format; 175 + int ret; 176 + 177 + tx.clkid = cpu_to_le32(clkid); 178 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_ATTRIBUTES, 179 + &tx, sizeof(tx), &rx, sizeof(rx)); 180 + 181 + ret = rpmi_mbox_send_message(context->chan, &msg); 182 + if (ret) 183 + return ret; 184 + 185 + resp = rpmi_mbox_get_msg_response(&msg); 186 + if (!resp) 187 + return -EINVAL; 188 + if (resp->status) 189 + return rpmi_to_linux_error(le32_to_cpu(resp->status)); 190 + 191 + rpmi_clk->id = clkid; 192 + rpmi_clk->num_rates = le32_to_cpu(resp->num_rates); 193 + rpmi_clk->transition_latency = le32_to_cpu(resp->transition_latency); 194 + strscpy(rpmi_clk->name, resp->name, RPMI_CLK_NAME_LEN); 195 + 196 + format = le32_to_cpu(resp->flags) & RPMI_CLK_TYPE_MASK; 197 + if (format >= RPMI_CLK_TYPE_MAX_IDX) 198 + return -EINVAL; 199 + 200 + rpmi_clk->type = format; 201 + 202 + return 0; 203 + } 204 + 205 + static int rpmi_clk_get_supported_rates(u32 clkid, struct rpmi_clk *rpmi_clk) 206 + { 207 + struct rpmi_clk_context *context = rpmi_clk->context; 208 + struct rpmi_clk_rate_discrete *rate_discrete; 209 + struct rpmi_clk_rate_linear *rate_linear; 210 + struct rpmi_get_supp_rates_tx tx; 211 + struct rpmi_get_supp_rates_rx *resp; 212 + struct rpmi_mbox_message msg; 213 + size_t clk_rate_idx; 214 + int ret, rateidx, j; 215 + 216 + tx.clkid = cpu_to_le32(clkid); 217 + tx.clk_rate_idx = 0; 218 + 219 + /* 220 + * Make sure we allocate rx buffer sufficient to be accommodate all 221 + * the rates sent in one RPMI message. 222 + */ 223 + struct rpmi_get_supp_rates_rx *rx __free(kfree) = 224 + kzalloc(context->max_msg_data_size, GFP_KERNEL); 225 + if (!rx) 226 + return -ENOMEM; 227 + 228 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_SUPPORTED_RATES, 229 + &tx, sizeof(tx), rx, context->max_msg_data_size); 230 + 231 + ret = rpmi_mbox_send_message(context->chan, &msg); 232 + if (ret) 233 + return ret; 234 + 235 + resp = rpmi_mbox_get_msg_response(&msg); 236 + if (!resp) 237 + return -EINVAL; 238 + if (resp->status) 239 + return rpmi_to_linux_error(le32_to_cpu(resp->status)); 240 + if (!le32_to_cpu(resp->returned)) 241 + return -EINVAL; 242 + 243 + if (rpmi_clk->type == RPMI_CLK_DISCRETE) { 244 + rate_discrete = (struct rpmi_clk_rate_discrete *)resp->rates; 245 + 246 + for (rateidx = 0; rateidx < le32_to_cpu(resp->returned); rateidx++) { 247 + rpmi_clk->rates->discrete[rateidx] = 248 + rpmi_clkrate_u64(le32_to_cpu(rate_discrete[rateidx].hi), 249 + le32_to_cpu(rate_discrete[rateidx].lo)); 250 + } 251 + 252 + /* 253 + * Keep sending the request message until all 254 + * the rates are received. 255 + */ 256 + clk_rate_idx = 0; 257 + while (le32_to_cpu(resp->remaining)) { 258 + clk_rate_idx += le32_to_cpu(resp->returned); 259 + tx.clk_rate_idx = cpu_to_le32(clk_rate_idx); 260 + 261 + rpmi_mbox_init_send_with_response(&msg, 262 + RPMI_CLK_SRV_GET_SUPPORTED_RATES, 263 + &tx, sizeof(tx), 264 + rx, context->max_msg_data_size); 265 + 266 + ret = rpmi_mbox_send_message(context->chan, &msg); 267 + if (ret) 268 + return ret; 269 + 270 + resp = rpmi_mbox_get_msg_response(&msg); 271 + if (!resp) 272 + return -EINVAL; 273 + if (resp->status) 274 + return rpmi_to_linux_error(le32_to_cpu(resp->status)); 275 + if (!le32_to_cpu(resp->returned)) 276 + return -EINVAL; 277 + 278 + for (j = 0; j < le32_to_cpu(resp->returned); j++) { 279 + if (rateidx >= clk_rate_idx + le32_to_cpu(resp->returned)) 280 + break; 281 + rpmi_clk->rates->discrete[rateidx++] = 282 + rpmi_clkrate_u64(le32_to_cpu(rate_discrete[j].hi), 283 + le32_to_cpu(rate_discrete[j].lo)); 284 + } 285 + } 286 + } else if (rpmi_clk->type == RPMI_CLK_LINEAR) { 287 + rate_linear = (struct rpmi_clk_rate_linear *)resp->rates; 288 + 289 + rpmi_clk->rates->linear.min = rpmi_clkrate_u64(le32_to_cpu(rate_linear->min_hi), 290 + le32_to_cpu(rate_linear->min_lo)); 291 + rpmi_clk->rates->linear.max = rpmi_clkrate_u64(le32_to_cpu(rate_linear->max_hi), 292 + le32_to_cpu(rate_linear->max_lo)); 293 + rpmi_clk->rates->linear.step = rpmi_clkrate_u64(le32_to_cpu(rate_linear->step_hi), 294 + le32_to_cpu(rate_linear->step_lo)); 295 + } 296 + 297 + return 0; 298 + } 299 + 300 + static unsigned long rpmi_clk_recalc_rate(struct clk_hw *hw, 301 + unsigned long parent_rate) 302 + { 303 + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); 304 + struct rpmi_clk_context *context = rpmi_clk->context; 305 + struct rpmi_mbox_message msg; 306 + struct rpmi_get_rate_tx tx; 307 + struct rpmi_get_rate_rx rx, *resp; 308 + int ret; 309 + 310 + tx.clkid = cpu_to_le32(rpmi_clk->id); 311 + 312 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_GET_RATE, 313 + &tx, sizeof(tx), &rx, sizeof(rx)); 314 + 315 + ret = rpmi_mbox_send_message(context->chan, &msg); 316 + if (ret) 317 + return ret; 318 + 319 + resp = rpmi_mbox_get_msg_response(&msg); 320 + if (!resp) 321 + return -EINVAL; 322 + if (resp->status) 323 + return rpmi_to_linux_error(le32_to_cpu(resp->status)); 324 + 325 + return rpmi_clkrate_u64(le32_to_cpu(resp->hi), le32_to_cpu(resp->lo)); 326 + } 327 + 328 + static int rpmi_clk_determine_rate(struct clk_hw *hw, 329 + struct clk_rate_request *req) 330 + { 331 + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); 332 + u64 fmin, fmax, ftmp; 333 + 334 + /* 335 + * Keep the requested rate if the clock format 336 + * is of discrete type. Let the platform which 337 + * is actually controlling the clock handle that. 338 + */ 339 + if (rpmi_clk->type == RPMI_CLK_DISCRETE) 340 + return 0; 341 + 342 + fmin = rpmi_clk->rates->linear.min; 343 + fmax = rpmi_clk->rates->linear.max; 344 + 345 + if (req->rate <= fmin) { 346 + req->rate = fmin; 347 + return 0; 348 + } else if (req->rate >= fmax) { 349 + req->rate = fmax; 350 + return 0; 351 + } 352 + 353 + ftmp = req->rate - fmin; 354 + ftmp += rpmi_clk->rates->linear.step - 1; 355 + do_div(ftmp, rpmi_clk->rates->linear.step); 356 + 357 + req->rate = ftmp * rpmi_clk->rates->linear.step + fmin; 358 + 359 + return 0; 360 + } 361 + 362 + static int rpmi_clk_set_rate(struct clk_hw *hw, unsigned long rate, 363 + unsigned long parent_rate) 364 + { 365 + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); 366 + struct rpmi_clk_context *context = rpmi_clk->context; 367 + struct rpmi_mbox_message msg; 368 + struct rpmi_set_rate_tx tx; 369 + struct rpmi_set_rate_rx rx, *resp; 370 + int ret; 371 + 372 + tx.clkid = cpu_to_le32(rpmi_clk->id); 373 + tx.lo = cpu_to_le32(lower_32_bits(rate)); 374 + tx.hi = cpu_to_le32(upper_32_bits(rate)); 375 + 376 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_SET_RATE, 377 + &tx, sizeof(tx), &rx, sizeof(rx)); 378 + 379 + ret = rpmi_mbox_send_message(context->chan, &msg); 380 + if (ret) 381 + return ret; 382 + 383 + resp = rpmi_mbox_get_msg_response(&msg); 384 + if (!resp) 385 + return -EINVAL; 386 + if (resp->status) 387 + return rpmi_to_linux_error(le32_to_cpu(resp->status)); 388 + 389 + return 0; 390 + } 391 + 392 + static int rpmi_clk_enable(struct clk_hw *hw) 393 + { 394 + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); 395 + struct rpmi_clk_context *context = rpmi_clk->context; 396 + struct rpmi_mbox_message msg; 397 + struct rpmi_set_config_tx tx; 398 + struct rpmi_set_config_rx rx, *resp; 399 + int ret; 400 + 401 + tx.config = cpu_to_le32(RPMI_CLK_ENABLE); 402 + tx.clkid = cpu_to_le32(rpmi_clk->id); 403 + 404 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_SET_CONFIG, 405 + &tx, sizeof(tx), &rx, sizeof(rx)); 406 + 407 + ret = rpmi_mbox_send_message(context->chan, &msg); 408 + if (ret) 409 + return ret; 410 + 411 + resp = rpmi_mbox_get_msg_response(&msg); 412 + if (!resp) 413 + return -EINVAL; 414 + if (resp->status) 415 + return rpmi_to_linux_error(le32_to_cpu(resp->status)); 416 + 417 + return 0; 418 + } 419 + 420 + static void rpmi_clk_disable(struct clk_hw *hw) 421 + { 422 + struct rpmi_clk *rpmi_clk = to_rpmi_clk(hw); 423 + struct rpmi_clk_context *context = rpmi_clk->context; 424 + struct rpmi_mbox_message msg; 425 + struct rpmi_set_config_tx tx; 426 + struct rpmi_set_config_rx rx; 427 + 428 + tx.config = cpu_to_le32(RPMI_CLK_DISABLE); 429 + tx.clkid = cpu_to_le32(rpmi_clk->id); 430 + 431 + rpmi_mbox_init_send_with_response(&msg, RPMI_CLK_SRV_SET_CONFIG, 432 + &tx, sizeof(tx), &rx, sizeof(rx)); 433 + 434 + rpmi_mbox_send_message(context->chan, &msg); 435 + } 436 + 437 + static const struct clk_ops rpmi_clk_ops = { 438 + .recalc_rate = rpmi_clk_recalc_rate, 439 + .determine_rate = rpmi_clk_determine_rate, 440 + .set_rate = rpmi_clk_set_rate, 441 + .prepare = rpmi_clk_enable, 442 + .unprepare = rpmi_clk_disable, 443 + }; 444 + 445 + static struct clk_hw *rpmi_clk_enumerate(struct rpmi_clk_context *context, u32 clkid) 446 + { 447 + struct device *dev = context->dev; 448 + unsigned long min_rate, max_rate; 449 + union rpmi_clk_rates *rates; 450 + struct rpmi_clk *rpmi_clk; 451 + struct clk_init_data init = {}; 452 + struct clk_hw *clk_hw; 453 + int ret; 454 + 455 + rates = devm_kzalloc(dev, sizeof(*rates), GFP_KERNEL); 456 + if (!rates) 457 + return ERR_PTR(-ENOMEM); 458 + 459 + rpmi_clk = devm_kzalloc(dev, sizeof(*rpmi_clk), GFP_KERNEL); 460 + if (!rpmi_clk) 461 + return ERR_PTR(-ENOMEM); 462 + 463 + rpmi_clk->context = context; 464 + rpmi_clk->rates = rates; 465 + 466 + ret = rpmi_clk_get_attrs(clkid, rpmi_clk); 467 + if (ret) 468 + return dev_err_ptr_probe(dev, ret, 469 + "Failed to get clk-%u attributes\n", 470 + clkid); 471 + 472 + ret = rpmi_clk_get_supported_rates(clkid, rpmi_clk); 473 + if (ret) 474 + return dev_err_ptr_probe(dev, ret, 475 + "Get supported rates failed for clk-%u\n", 476 + clkid); 477 + 478 + init.flags = CLK_GET_RATE_NOCACHE; 479 + init.num_parents = 0; 480 + init.ops = &rpmi_clk_ops; 481 + init.name = rpmi_clk->name; 482 + clk_hw = &rpmi_clk->hw; 483 + clk_hw->init = &init; 484 + 485 + ret = devm_clk_hw_register(dev, clk_hw); 486 + if (ret) 487 + return dev_err_ptr_probe(dev, ret, 488 + "Unable to register clk-%u\n", 489 + clkid); 490 + 491 + if (rpmi_clk->type == RPMI_CLK_DISCRETE) { 492 + min_rate = rpmi_clk->rates->discrete[0]; 493 + max_rate = rpmi_clk->rates->discrete[rpmi_clk->num_rates - 1]; 494 + } else { 495 + min_rate = rpmi_clk->rates->linear.min; 496 + max_rate = rpmi_clk->rates->linear.max; 497 + } 498 + 499 + clk_hw_set_rate_range(clk_hw, min_rate, max_rate); 500 + 501 + return clk_hw; 502 + } 503 + 504 + static void rpmi_clk_mbox_chan_release(void *data) 505 + { 506 + struct mbox_chan *chan = data; 507 + 508 + mbox_free_channel(chan); 509 + } 510 + 511 + static int rpmi_clk_probe(struct platform_device *pdev) 512 + { 513 + int ret; 514 + unsigned int num_clocks, i; 515 + struct clk_hw_onecell_data *clk_data; 516 + struct rpmi_clk_context *context; 517 + struct rpmi_mbox_message msg; 518 + struct clk_hw *hw_ptr; 519 + struct device *dev = &pdev->dev; 520 + 521 + context = devm_kzalloc(dev, sizeof(*context), GFP_KERNEL); 522 + if (!context) 523 + return -ENOMEM; 524 + context->dev = dev; 525 + platform_set_drvdata(pdev, context); 526 + 527 + context->client.dev = context->dev; 528 + context->client.rx_callback = NULL; 529 + context->client.tx_block = false; 530 + context->client.knows_txdone = true; 531 + context->client.tx_tout = 0; 532 + 533 + context->chan = mbox_request_channel(&context->client, 0); 534 + if (IS_ERR(context->chan)) 535 + return PTR_ERR(context->chan); 536 + 537 + ret = devm_add_action_or_reset(dev, rpmi_clk_mbox_chan_release, context->chan); 538 + if (ret) 539 + return dev_err_probe(dev, ret, "Failed to add rpmi mbox channel cleanup\n"); 540 + 541 + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SPEC_VERSION); 542 + ret = rpmi_mbox_send_message(context->chan, &msg); 543 + if (ret) 544 + return dev_err_probe(dev, ret, "Failed to get spec version\n"); 545 + if (msg.attr.value < RPMI_MKVER(1, 0)) { 546 + return dev_err_probe(dev, -EINVAL, 547 + "msg protocol version mismatch, expected 0x%x, found 0x%x\n", 548 + RPMI_MKVER(1, 0), msg.attr.value); 549 + } 550 + 551 + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_ID); 552 + ret = rpmi_mbox_send_message(context->chan, &msg); 553 + if (ret) 554 + return dev_err_probe(dev, ret, "Failed to get service group ID\n"); 555 + if (msg.attr.value != RPMI_SRVGRP_CLOCK) { 556 + return dev_err_probe(dev, -EINVAL, 557 + "service group match failed, expected 0x%x, found 0x%x\n", 558 + RPMI_SRVGRP_CLOCK, msg.attr.value); 559 + } 560 + 561 + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_SERVICEGROUP_VERSION); 562 + ret = rpmi_mbox_send_message(context->chan, &msg); 563 + if (ret) 564 + return dev_err_probe(dev, ret, "Failed to get service group version\n"); 565 + if (msg.attr.value < RPMI_MKVER(1, 0)) { 566 + return dev_err_probe(dev, -EINVAL, 567 + "service group version failed, expected 0x%x, found 0x%x\n", 568 + RPMI_MKVER(1, 0), msg.attr.value); 569 + } 570 + 571 + rpmi_mbox_init_get_attribute(&msg, RPMI_MBOX_ATTR_MAX_MSG_DATA_SIZE); 572 + ret = rpmi_mbox_send_message(context->chan, &msg); 573 + if (ret) 574 + return dev_err_probe(dev, ret, "Failed to get max message data size\n"); 575 + 576 + context->max_msg_data_size = msg.attr.value; 577 + num_clocks = rpmi_clk_get_num_clocks(context); 578 + if (!num_clocks) 579 + return dev_err_probe(dev, -ENODEV, "No clocks found\n"); 580 + 581 + clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, num_clocks), 582 + GFP_KERNEL); 583 + if (!clk_data) 584 + return dev_err_probe(dev, -ENOMEM, "No memory for clock data\n"); 585 + clk_data->num = num_clocks; 586 + 587 + for (i = 0; i < clk_data->num; i++) { 588 + hw_ptr = rpmi_clk_enumerate(context, i); 589 + if (IS_ERR(hw_ptr)) { 590 + return dev_err_probe(dev, PTR_ERR(hw_ptr), 591 + "Failed to register clk-%d\n", i); 592 + } 593 + clk_data->hws[i] = hw_ptr; 594 + } 595 + 596 + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get, clk_data); 597 + if (ret) 598 + return dev_err_probe(dev, ret, "Failed to register clock HW provider\n"); 599 + 600 + return 0; 601 + } 602 + 603 + static const struct of_device_id rpmi_clk_of_match[] = { 604 + { .compatible = "riscv,rpmi-clock" }, 605 + { } 606 + }; 607 + MODULE_DEVICE_TABLE(of, rpmi_clk_of_match); 608 + 609 + static struct platform_driver rpmi_clk_driver = { 610 + .driver = { 611 + .name = "riscv-rpmi-clock", 612 + .of_match_table = rpmi_clk_of_match, 613 + }, 614 + .probe = rpmi_clk_probe, 615 + }; 616 + module_platform_driver(rpmi_clk_driver); 617 + 618 + MODULE_AUTHOR("Rahul Pathak <rpathak@ventanamicro.com>"); 619 + MODULE_DESCRIPTION("Clock Driver based on RPMI message protocol"); 620 + MODULE_LICENSE("GPL");
+16
include/linux/mailbox/riscv-rpmi-message.h
··· 90 90 } 91 91 } 92 92 93 + /* RPMI service group IDs */ 94 + #define RPMI_SRVGRP_CLOCK 0x00008 95 + 96 + /* RPMI clock service IDs */ 97 + enum rpmi_clock_service_id { 98 + RPMI_CLK_SRV_ENABLE_NOTIFICATION = 0x01, 99 + RPMI_CLK_SRV_GET_NUM_CLOCKS = 0x02, 100 + RPMI_CLK_SRV_GET_ATTRIBUTES = 0x03, 101 + RPMI_CLK_SRV_GET_SUPPORTED_RATES = 0x04, 102 + RPMI_CLK_SRV_SET_CONFIG = 0x05, 103 + RPMI_CLK_SRV_GET_CONFIG = 0x06, 104 + RPMI_CLK_SRV_SET_RATE = 0x07, 105 + RPMI_CLK_SRV_GET_RATE = 0x08, 106 + RPMI_CLK_SRV_ID_MAX_COUNT 107 + }; 108 + 93 109 /* RPMI Linux mailbox attribute IDs */ 94 110 enum rpmi_mbox_attribute_id { 95 111 RPMI_MBOX_ATTR_SPEC_VERSION,