1 /* $OpenBSD: scmi.c,v 1.2 2024/11/25 22:12:18 tobhe Exp $ */ 2 3 /* 4 * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org> 5 * Copyright (c) 2024 Tobias Heider <tobhe@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/param.h> 21 #include <sys/device.h> 22 #include <sys/systm.h> 23 #include <sys/malloc.h> 24 #include <sys/sensors.h> 25 #include <sys/sysctl.h> 26 27 #include <machine/bus.h> 28 #include <machine/fdt.h> 29 30 #include <dev/ofw/openfirm.h> 31 #include <dev/ofw/ofw_clock.h> 32 #include <dev/ofw/ofw_misc.h> 33 #include <dev/ofw/fdt.h> 34 35 #include <dev/fdt/pscivar.h> 36 37 struct scmi_shmem { 38 uint32_t reserved1; 39 uint32_t channel_status; 40 #define SCMI_CHANNEL_ERROR (1 << 1) 41 #define SCMI_CHANNEL_FREE (1 << 0) 42 uint32_t reserved2; 43 uint32_t reserved3; 44 uint32_t channel_flags; 45 uint32_t length; 46 uint32_t message_header; 47 uint32_t message_payload[]; 48 }; 49 50 #define SCMI_SUCCESS 0 51 #define SCMI_NOT_SUPPORTED -1 52 #define SCMI_BUSY -6 53 #define SCMI_COMMS_ERROR -7 54 55 /* Protocols */ 56 #define SCMI_BASE 0x10 57 #define SCMI_PERF 0x13 58 #define SCMI_CLOCK 0x14 59 60 /* Common messages */ 61 #define SCMI_PROTOCOL_VERSION 0x0 62 #define SCMI_PROTOCOL_ATTRIBUTES 0x1 63 #define SCMI_PROTOCOL_MESSAGE_ATTRIBUTES 0x2 64 65 /* Clock management messages */ 66 #define SCMI_CLOCK_ATTRIBUTES 0x3 67 #define SCMI_CLOCK_DESCRIBE_RATES 0x4 68 #define SCMI_CLOCK_RATE_SET 0x5 69 #define SCMI_CLOCK_RATE_GET 0x6 70 #define SCMI_CLOCK_CONFIG_SET 0x7 71 #define SCMI_CLOCK_CONFIG_SET_ENABLE (1 << 0) 72 73 /* Performance management messages */ 74 #define SCMI_PERF_DOMAIN_ATTRIBUTES 0x3 75 #define SCMI_PERF_DESCRIBE_LEVELS 0x4 76 #define SCMI_PERF_LEVEL_GET 0x8 77 78 struct scmi_resp_perf_describe_levels_40 { 79 uint16_t pl_nret; 80 uint16_t pl_nrem; 81 struct { 82 uint32_t pe_perf; 83 uint32_t pe_cost; 84 uint16_t pe_latency; 85 uint16_t pe_reserved; 86 uint32_t pe_ifreq; 87 uint32_t pe_lindex; 88 } pl_entry[]; 89 }; 90 91 static inline void 92 scmi_message_header(volatile struct scmi_shmem *shmem, 93 uint32_t protocol_id, uint32_t message_id) 94 { 95 shmem->message_header = (protocol_id << 10) | (message_id << 0); 96 } 97 98 struct scmi_perf_level { 99 uint32_t pl_perf; 100 uint32_t pl_cost; 101 uint32_t pl_ifreq; 102 }; 103 104 struct scmi_perf_domain { 105 size_t pd_nlevels; 106 struct scmi_perf_level *pd_levels; 107 int pd_curlevel; 108 }; 109 110 struct scmi_softc { 111 struct device sc_dev; 112 bus_space_tag_t sc_iot; 113 int sc_node; 114 115 bus_space_handle_t sc_ioh_tx; 116 bus_space_handle_t sc_ioh_rx; 117 volatile struct scmi_shmem *sc_shmem_tx; 118 volatile struct scmi_shmem *sc_shmem_rx; 119 120 uint32_t sc_smc_id; 121 struct mbox_channel *sc_mc_tx; 122 struct mbox_channel *sc_mc_rx; 123 124 uint16_t sc_ver_major; 125 uint16_t sc_ver_minor; 126 127 /* SCMI_CLOCK */ 128 struct clock_device sc_cd; 129 130 /* SCMI_PERF */ 131 int sc_perf_power_unit; 132 #define SCMI_POWER_UNIT_UW 0x2 133 #define SCMI_POWER_UNIT_MW 0x1 134 #define SCMI_POWER_UNIT_NONE 0x0 135 size_t sc_perf_ndomains; 136 struct scmi_perf_domain *sc_perf_domains; 137 138 struct ksensordev sc_perf_sensordev; 139 struct ksensordev sc_perf_psensordev; 140 struct ksensor *sc_perf_fsensors; 141 struct ksensor *sc_perf_psensors; 142 143 int32_t (*sc_command)(struct scmi_softc *); 144 }; 145 146 int scmi_match(struct device *, void *, void *); 147 void scmi_attach(struct device *, struct device *, void *); 148 int scmi_attach_smc(struct scmi_softc *, struct fdt_attach_args *); 149 void scmi_attach_mbox_deferred(struct device *); 150 151 const struct cfattach scmi_ca = { 152 sizeof(struct scmi_softc), scmi_match, scmi_attach 153 }; 154 155 struct cfdriver scmi_cd = { 156 NULL, "scmi", DV_DULL 157 }; 158 159 void scmi_attach_proto(struct scmi_softc *, int); 160 void scmi_attach_clock(struct scmi_softc *, int); 161 void scmi_attach_perf(struct scmi_softc *, int); 162 163 int32_t scmi_smc_command(struct scmi_softc *); 164 int32_t scmi_mbox_command(struct scmi_softc *); 165 166 int 167 scmi_match(struct device *parent, void *match, void *aux) 168 { 169 struct fdt_attach_args *faa = aux; 170 171 return OF_is_compatible(faa->fa_node, "arm,scmi-smc") || 172 OF_is_compatible(faa->fa_node, "arm,scmi"); 173 } 174 175 void 176 scmi_attach(struct device *parent, struct device *self, void *aux) 177 { 178 struct scmi_softc *sc = (struct scmi_softc *)self; 179 struct fdt_attach_args *faa = aux; 180 181 sc->sc_iot = faa->fa_iot; 182 sc->sc_node = faa->fa_node; 183 184 if (OF_is_compatible(faa->fa_node, "arm,scmi-smc")) { 185 scmi_attach_smc(sc, faa); 186 } else if (OF_is_compatible(faa->fa_node, "arm,scmi")) { 187 printf("\n"); 188 /* Defer because we need the mailbox driver attached first */ 189 config_defer(self, scmi_attach_mbox_deferred); 190 } 191 } 192 193 int 194 scmi_attach_smc(struct scmi_softc *sc, struct fdt_attach_args *faa) 195 { 196 volatile struct scmi_shmem *shmem; 197 struct fdt_reg reg; 198 int32_t status; 199 uint32_t version; 200 uint32_t phandle; 201 void *node; 202 int proto; 203 204 sc->sc_smc_id = OF_getpropint(faa->fa_node, "arm,smc-id", 0); 205 if (sc->sc_smc_id == 0) { 206 printf(": no SMC id\n"); 207 return -1; 208 } 209 210 phandle = OF_getpropint(faa->fa_node, "shmem", 0); 211 node = fdt_find_phandle(phandle); 212 if (node == NULL || !fdt_is_compatible(node, "arm,scmi-shmem") || 213 fdt_get_reg(node, 0, ®)) { 214 printf(": no shared memory\n"); 215 return -1; 216 } 217 218 if (bus_space_map(sc->sc_iot, reg.addr, 219 reg.size, 0, &sc->sc_ioh_tx)) { 220 printf(": can't map shared memory\n"); 221 return -1; 222 } 223 sc->sc_shmem_tx = bus_space_vaddr(sc->sc_iot, sc->sc_ioh_tx); 224 shmem = sc->sc_shmem_tx; 225 226 sc->sc_command = scmi_smc_command; 227 228 if ((shmem->channel_status & SCMI_CHANNEL_FREE) == 0) { 229 printf(": channel busy\n"); 230 return -1; 231 } 232 233 scmi_message_header(shmem, SCMI_BASE, SCMI_PROTOCOL_VERSION); 234 shmem->length = sizeof(uint32_t); 235 status = sc->sc_command(sc); 236 if (status != SCMI_SUCCESS) { 237 printf(": protocol version command failed\n"); 238 return -1; 239 } 240 241 version = shmem->message_payload[1]; 242 sc->sc_ver_major = version >> 16; 243 sc->sc_ver_minor = version & 0xfffff; 244 printf(": SCMI %d.%d\n", sc->sc_ver_major, sc->sc_ver_minor); 245 246 for (proto = OF_child(faa->fa_node); proto; proto = OF_peer(proto)) 247 scmi_attach_proto(sc, proto); 248 249 return 0; 250 } 251 252 void 253 scmi_attach_mbox_deferred(struct device *self) 254 { 255 struct scmi_softc *sc = (struct scmi_softc *)self; 256 uint32_t *shmems; 257 int32_t status; 258 uint32_t version; 259 struct fdt_reg reg; 260 int len; 261 void *node; 262 int proto; 263 264 /* we only support the 2 mbox / 2 shmem case */ 265 len = OF_getproplen(sc->sc_node, "mboxes"); 266 if (len != 4 * sizeof(uint32_t)) { 267 printf("%s: invalid number of mboxes\n", sc->sc_dev.dv_xname); 268 return; 269 } 270 271 len = OF_getproplen(sc->sc_node, "shmem"); 272 if (len != 2 * sizeof(uint32_t)) { 273 printf("%s: invalid number of shmems\n", sc->sc_dev.dv_xname); 274 return; 275 } 276 277 shmems = malloc(len, M_DEVBUF, M_WAITOK); 278 OF_getpropintarray(sc->sc_node, "shmem", shmems, len); 279 280 sc->sc_mc_tx = mbox_channel(sc->sc_node, "tx", NULL); 281 if (sc->sc_mc_tx == NULL) { 282 printf("%s: no tx mbox\n", sc->sc_dev.dv_xname); 283 return; 284 } 285 sc->sc_mc_rx = mbox_channel(sc->sc_node, "rx", NULL); 286 if (sc->sc_mc_rx == NULL) { 287 printf("%s: no rx mbox\n", sc->sc_dev.dv_xname); 288 return; 289 } 290 291 node = fdt_find_phandle(shmems[0]); 292 if (node == NULL || !fdt_is_compatible(node, "arm,scmi-shmem") || 293 fdt_get_reg(node, 0, ®)) { 294 printf("%s: no shared memory\n", sc->sc_dev.dv_xname); 295 return; 296 } 297 if (bus_space_map(sc->sc_iot, reg.addr, reg.size, 0, &sc->sc_ioh_tx)) { 298 printf("%s: can't map shared memory\n", sc->sc_dev.dv_xname); 299 return; 300 } 301 sc->sc_shmem_tx = bus_space_vaddr(sc->sc_iot, sc->sc_ioh_tx); 302 303 node = fdt_find_phandle(shmems[1]); 304 if (node == NULL || !fdt_is_compatible(node, "arm,scmi-shmem") || 305 fdt_get_reg(node, 0, ®)) { 306 printf("%s: no shared memory\n", sc->sc_dev.dv_xname); 307 return; 308 } 309 if (bus_space_map(sc->sc_iot, reg.addr, reg.size, 0, &sc->sc_ioh_rx)) { 310 printf("%s: can't map shared memory\n", sc->sc_dev.dv_xname); 311 return; 312 } 313 sc->sc_shmem_rx = bus_space_vaddr(sc->sc_iot, sc->sc_ioh_rx); 314 315 sc->sc_command = scmi_mbox_command; 316 317 scmi_message_header(sc->sc_shmem_tx, SCMI_BASE, SCMI_PROTOCOL_VERSION); 318 sc->sc_shmem_tx->length = sizeof(uint32_t); 319 status = sc->sc_command(sc); 320 if (status != SCMI_SUCCESS) { 321 printf("%s: protocol version command failed\n", 322 sc->sc_dev.dv_xname); 323 return; 324 } 325 326 version = sc->sc_shmem_tx->message_payload[1]; 327 sc->sc_ver_major = version >> 16; 328 sc->sc_ver_minor = version & 0xfffff; 329 printf("%s: SCMI %d.%d\n", sc->sc_dev.dv_xname, sc->sc_ver_major, 330 sc->sc_ver_minor); 331 332 for (proto = OF_child(sc->sc_node); proto; proto = OF_peer(proto)) 333 scmi_attach_proto(sc, proto); 334 } 335 336 int32_t 337 scmi_smc_command(struct scmi_softc *sc) 338 { 339 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 340 int32_t status; 341 342 shmem->channel_status = 0; 343 status = smccc(sc->sc_smc_id, 0, 0, 0); 344 if (status != PSCI_SUCCESS) 345 return SCMI_NOT_SUPPORTED; 346 if ((shmem->channel_status & SCMI_CHANNEL_ERROR)) 347 return SCMI_COMMS_ERROR; 348 if ((shmem->channel_status & SCMI_CHANNEL_FREE) == 0) 349 return SCMI_BUSY; 350 return shmem->message_payload[0]; 351 } 352 353 int32_t 354 scmi_mbox_command(struct scmi_softc *sc) 355 { 356 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 357 int ret; 358 int i; 359 360 shmem->channel_status = 0; 361 ret = mbox_send(sc->sc_mc_tx, NULL, 0); 362 if (ret != 0) 363 return SCMI_NOT_SUPPORTED; 364 365 /* XXX: poll for now */ 366 for (i = 0; i < 20; i++) { 367 if (shmem->channel_status & SCMI_CHANNEL_FREE) 368 break; 369 delay(10); 370 } 371 if ((shmem->channel_status & SCMI_CHANNEL_ERROR)) 372 return SCMI_COMMS_ERROR; 373 if ((shmem->channel_status & SCMI_CHANNEL_FREE) == 0) 374 return SCMI_BUSY; 375 376 return shmem->message_payload[0]; 377 } 378 379 void 380 scmi_attach_proto(struct scmi_softc *sc, int node) 381 { 382 switch (OF_getpropint(node, "reg", -1)) { 383 case SCMI_CLOCK: 384 scmi_attach_clock(sc, node); 385 break; 386 case SCMI_PERF: 387 scmi_attach_perf(sc, node); 388 break; 389 default: 390 break; 391 } 392 } 393 394 /* Clock management. */ 395 396 void scmi_clock_enable(void *, uint32_t *, int); 397 uint32_t scmi_clock_get_frequency(void *, uint32_t *); 398 int scmi_clock_set_frequency(void *, uint32_t *, uint32_t); 399 400 void 401 scmi_attach_clock(struct scmi_softc *sc, int node) 402 { 403 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 404 int32_t status; 405 int nclocks; 406 407 scmi_message_header(shmem, SCMI_CLOCK, SCMI_PROTOCOL_ATTRIBUTES); 408 shmem->length = sizeof(uint32_t); 409 status = sc->sc_command(sc); 410 if (status != SCMI_SUCCESS) 411 return; 412 413 nclocks = shmem->message_payload[1] & 0xffff; 414 if (nclocks == 0) 415 return; 416 417 sc->sc_cd.cd_node = node; 418 sc->sc_cd.cd_cookie = sc; 419 sc->sc_cd.cd_enable = scmi_clock_enable; 420 sc->sc_cd.cd_get_frequency = scmi_clock_get_frequency; 421 sc->sc_cd.cd_set_frequency = scmi_clock_set_frequency; 422 clock_register(&sc->sc_cd); 423 } 424 425 void 426 scmi_clock_enable(void *cookie, uint32_t *cells, int on) 427 { 428 struct scmi_softc *sc = cookie; 429 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 430 uint32_t idx = cells[0]; 431 432 scmi_message_header(shmem, SCMI_CLOCK, SCMI_CLOCK_CONFIG_SET); 433 shmem->length = 3 * sizeof(uint32_t); 434 shmem->message_payload[0] = idx; 435 shmem->message_payload[1] = on ? SCMI_CLOCK_CONFIG_SET_ENABLE : 0; 436 sc->sc_command(sc); 437 } 438 439 uint32_t 440 scmi_clock_get_frequency(void *cookie, uint32_t *cells) 441 { 442 struct scmi_softc *sc = cookie; 443 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 444 uint32_t idx = cells[0]; 445 int32_t status; 446 447 scmi_message_header(shmem, SCMI_CLOCK, SCMI_CLOCK_RATE_GET); 448 shmem->length = 2 * sizeof(uint32_t); 449 shmem->message_payload[0] = idx; 450 status = sc->sc_command(sc); 451 if (status != SCMI_SUCCESS) 452 return 0; 453 if (shmem->message_payload[2] != 0) 454 return 0; 455 456 return shmem->message_payload[1]; 457 } 458 459 int 460 scmi_clock_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 461 { 462 struct scmi_softc *sc = cookie; 463 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 464 uint32_t idx = cells[0]; 465 int32_t status; 466 467 scmi_message_header(shmem, SCMI_CLOCK, SCMI_CLOCK_RATE_SET); 468 shmem->length = 5 * sizeof(uint32_t); 469 shmem->message_payload[0] = 0; 470 shmem->message_payload[1] = idx; 471 shmem->message_payload[2] = freq; 472 shmem->message_payload[3] = 0; 473 status = sc->sc_command(sc); 474 if (status != SCMI_SUCCESS) 475 return -1; 476 477 return 0; 478 } 479 480 /* Performance management */ 481 void scmi_perf_descr_levels(struct scmi_softc *, int); 482 void scmi_perf_refresh_sensor(void *); 483 484 void 485 scmi_attach_perf(struct scmi_softc *sc, int node) 486 { 487 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 488 int32_t status; 489 uint32_t version; 490 int i; 491 492 scmi_message_header(sc->sc_shmem_tx, SCMI_PERF, SCMI_PROTOCOL_VERSION); 493 sc->sc_shmem_tx->length = sizeof(uint32_t); 494 status = sc->sc_command(sc); 495 if (status != SCMI_SUCCESS) { 496 printf("%s: SCMI_PROTOCOL_VERSION failed\n", 497 sc->sc_dev.dv_xname); 498 return; 499 } 500 501 version = shmem->message_payload[1]; 502 if (version != 0x40000) { 503 printf("%s: invalid perf protocol version (0x%x != 0x4000)", 504 sc->sc_dev.dv_xname, version); 505 return; 506 } 507 508 scmi_message_header(shmem, SCMI_PERF, SCMI_PROTOCOL_ATTRIBUTES); 509 shmem->length = sizeof(uint32_t); 510 status = sc->sc_command(sc); 511 if (status != SCMI_SUCCESS) { 512 printf("%s: SCMI_PROTOCOL_ATTRIBUTES failed\n", 513 sc->sc_dev.dv_xname); 514 return; 515 } 516 517 sc->sc_perf_ndomains = shmem->message_payload[1] & 0xffff; 518 sc->sc_perf_domains = malloc(sc->sc_perf_ndomains * 519 sizeof(struct scmi_perf_domain), M_DEVBUF, M_ZERO | M_WAITOK); 520 sc->sc_perf_power_unit = (shmem->message_payload[1] >> 16) & 0x3; 521 522 strlcpy(sc->sc_perf_sensordev.xname, sc->sc_dev.dv_xname, 523 sizeof(sc->sc_perf_sensordev.xname)); 524 525 sc->sc_perf_fsensors = 526 malloc(sc->sc_perf_ndomains * sizeof(struct ksensor), 527 M_DEVBUF, M_ZERO | M_WAITOK); 528 sc->sc_perf_psensors = 529 malloc(sc->sc_perf_ndomains * sizeof(struct ksensor), 530 M_DEVBUF, M_ZERO | M_WAITOK); 531 532 /* Add one frequency sensor per perf domain */ 533 for (i = 0; i < sc->sc_perf_ndomains; i++) { 534 scmi_message_header(shmem, SCMI_PERF, 535 SCMI_PERF_DOMAIN_ATTRIBUTES); 536 shmem->length = 2 * sizeof(uint32_t); 537 shmem->message_payload[0] = i; 538 status = sc->sc_command(sc); 539 if (status != SCMI_SUCCESS) { 540 printf("%s: SCMI_PERF_DOMAIN_ATTRIBUTES failed\n", 541 sc->sc_dev.dv_xname); 542 goto err; 543 } 544 545 scmi_perf_descr_levels(sc, i); 546 547 sc->sc_perf_fsensors[i].type = SENSOR_FREQ; 548 sensor_attach(&sc->sc_perf_sensordev, &sc->sc_perf_fsensors[i]); 549 sc->sc_perf_psensors[i].type = SENSOR_WATTS; 550 sensor_attach(&sc->sc_perf_sensordev, &sc->sc_perf_psensors[i]); 551 } 552 sensordev_install(&sc->sc_perf_sensordev); 553 sensor_task_register(sc, scmi_perf_refresh_sensor, 1); 554 return; 555 err: 556 free(sc->sc_perf_fsensors, M_DEVBUF, 557 sc->sc_perf_ndomains * sizeof(struct ksensor)); 558 free(sc->sc_perf_psensors, M_DEVBUF, 559 sc->sc_perf_ndomains * sizeof(struct ksensor)); 560 } 561 562 void 563 scmi_perf_descr_levels(struct scmi_softc *sc, int domain) 564 { 565 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 566 volatile struct scmi_resp_perf_describe_levels_40 *pl; 567 struct scmi_perf_domain *pd = &sc->sc_perf_domains[domain]; 568 int status, i, idx; 569 570 idx = 0; 571 do { 572 scmi_message_header(shmem, SCMI_PERF, 573 SCMI_PERF_DESCRIBE_LEVELS); 574 shmem->length = sizeof(uint32_t) * 3; 575 shmem->message_payload[0] = domain; 576 shmem->message_payload[1] = idx; 577 status = sc->sc_command(sc); 578 if (status != SCMI_SUCCESS) { 579 printf("%s: SCMI_PERF_DESCRIBE_LEVELS failed\n", 580 sc->sc_dev.dv_xname); 581 return; 582 } 583 584 pl = (struct scmi_resp_perf_describe_levels_40 *) 585 &shmem->message_payload[1]; 586 587 if (pd->pd_levels == NULL) { 588 pd->pd_nlevels = pl->pl_nret + pl->pl_nrem; 589 pd->pd_levels = malloc(pd->pd_nlevels * 590 sizeof(struct scmi_perf_level), 591 M_DEVBUF, M_ZERO | M_WAITOK); 592 } 593 594 for (i = 0; i < pl->pl_nret; i++) { 595 pd->pd_levels[idx + i].pl_cost = 596 pl->pl_entry[i].pe_cost; 597 pd->pd_levels[idx + i].pl_perf = 598 pl->pl_entry[i].pe_perf; 599 pd->pd_levels[idx + i].pl_ifreq = 600 pl->pl_entry[i].pe_ifreq; 601 } 602 idx += pl->pl_nret; 603 } while (pl->pl_nrem); 604 } 605 606 void 607 scmi_perf_refresh_sensor(void *arg) 608 { 609 struct scmi_softc *sc = arg; 610 volatile struct scmi_shmem *shmem = sc->sc_shmem_tx; 611 uint64_t power_cost; 612 int32_t status; 613 int level, i; 614 615 if (sc->sc_perf_domains == NULL) 616 return; 617 618 for (i = 0; i < sc->sc_perf_ndomains; i++) { 619 if (sc->sc_perf_domains[i].pd_levels == NULL) 620 return; 621 622 scmi_message_header(shmem, SCMI_PERF, 623 SCMI_PERF_LEVEL_GET); 624 shmem->length = sizeof(uint32_t) * 2; 625 shmem->message_payload[0] = i; 626 status = sc->sc_command(sc); 627 if (status != SCMI_SUCCESS) { 628 printf("%s: SCMI_PERF_LEVEL_GET failed\n", 629 sc->sc_dev.dv_xname); 630 return; 631 } 632 633 level = shmem->message_payload[1]; 634 if (sc->sc_perf_fsensors == NULL || 635 sc->sc_perf_psensors == NULL) 636 return; 637 638 sc->sc_perf_domains[i].pd_curlevel = level; 639 sc->sc_perf_fsensors[i].value = 640 (uint64_t)sc->sc_perf_domains[i]. 641 pd_levels[level].pl_ifreq * 1000000000; 642 643 switch (sc->sc_perf_power_unit) { 644 case SCMI_POWER_UNIT_UW: 645 power_cost = (uint64_t)sc->sc_perf_domains[i]. 646 pd_levels[level].pl_cost; 647 break; 648 case SCMI_POWER_UNIT_MW: 649 power_cost = (uint64_t)sc->sc_perf_domains[i]. 650 pd_levels[level].pl_cost * 1000; 651 break; 652 default: 653 continue; 654 } 655 sc->sc_perf_psensors[i].value = power_cost; 656 } 657 } 658