1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023 Beckhoff Automation GmbH & Co. KG 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 30 #include <sys/param.h> 31 #include <sys/systm.h> 32 #include <sys/kernel.h> 33 #include <sys/module.h> 34 #include <sys/malloc.h> 35 #include <sys/bus.h> 36 #include <sys/cpu.h> 37 #include <machine/bus.h> 38 39 #include <dev/fdt/simplebus.h> 40 41 #include <dev/ofw/openfirm.h> 42 #include <dev/ofw/ofw_bus.h> 43 #include <dev/ofw/ofw_bus_subr.h> 44 45 #include <dev/psci/smccc.h> 46 47 #include <dev/firmware/xilinx/pm_defs.h> 48 49 #include "zynqmp_firmware_if.h" 50 51 enum { 52 IOCTL_GET_RPU_OPER_MODE = 0, 53 IOCTL_SET_RPU_OPER_MODE = 1, 54 IOCTL_RPU_BOOT_ADDR_CONFIG = 2, 55 IOCTL_TCM_COMB_CONFIG = 3, 56 IOCTL_SET_TAPDELAY_BYPASS = 4, 57 IOCTL_SET_SGMII_MODE = 5, 58 IOCTL_SD_DLL_RESET = 6, 59 IOCTL_SET_SD_TAPDELAY = 7, 60 /* Ioctl for clock driver */ 61 IOCTL_SET_PLL_FRAC_MODE = 8, 62 IOCTL_GET_PLL_FRAC_MODE = 9, 63 IOCTL_SET_PLL_FRAC_DATA = 10, 64 IOCTL_GET_PLL_FRAC_DATA = 11, 65 IOCTL_WRITE_GGS = 12, 66 IOCTL_READ_GGS = 13, 67 IOCTL_WRITE_PGGS = 14, 68 IOCTL_READ_PGGS = 15, 69 /* IOCTL for ULPI reset */ 70 IOCTL_ULPI_RESET = 16, 71 /* Set healthy bit value */ 72 IOCTL_SET_BOOT_HEALTH_STATUS = 17, 73 IOCTL_AFI = 18, 74 /* Probe counter read/write */ 75 IOCTL_PROBE_COUNTER_READ = 19, 76 IOCTL_PROBE_COUNTER_WRITE = 20, 77 IOCTL_OSPI_MUX_SELECT = 21, 78 /* IOCTL for USB power request */ 79 IOCTL_USB_SET_STATE = 22, 80 /* IOCTL to get last reset reason */ 81 IOCTL_GET_LAST_RESET_REASON = 23, 82 /* AI engine NPI ISR clear */ 83 IOCTL_AIE_ISR_CLEAR = 24, 84 /* Register SGI to ATF */ 85 IOCTL_REGISTER_SGI = 25, 86 }; 87 88 typedef int (*zynqmp_callfn_t)(register_t, register_t, register_t, uint32_t *payload); 89 90 struct zynqmp_firmware_softc { 91 struct simplebus_softc sc; 92 device_t dev; 93 zynqmp_callfn_t callfn; 94 }; 95 96 /* SMC calling methods */ 97 #define PM_SIP_SVC 0xC2000000 98 99 static int 100 zynqmp_call_smc(uint32_t id, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t *payload, bool ignore_error) 101 { 102 struct arm_smccc_res res; 103 uint64_t args[3]; 104 105 args[0] = id | PM_SIP_SVC; 106 args[1] = ((uint64_t)a1 << 32) | a0; 107 args[2] = ((uint64_t)a3 << 32) | a2; 108 arm_smccc_invoke_smc(args[0], args[1], args[2], &res); 109 if (payload != NULL) { 110 payload[0] = res.a0 & 0xFFFFFFFF; 111 payload[1] = res.a0 >> 32; 112 payload[2] = res.a1 & 0xFFFFFFFF; 113 payload[3] = res.a1 >> 32; 114 if (!ignore_error && payload[0] != PM_RET_SUCCESS) { 115 printf("%s: fail %x\n", __func__, payload[0]); 116 return (EINVAL); 117 } 118 } 119 return (0); 120 } 121 122 /* Firmware methods */ 123 static int 124 zynqmp_get_api_version(struct zynqmp_firmware_softc *sc) 125 { 126 uint32_t payload[4]; 127 int rv; 128 129 rv = zynqmp_call_smc(PM_GET_API_VERSION, 0, 0, 0, 0, payload, false); 130 if (rv != 0) { 131 device_printf(sc->dev, "SMC Call fail %d\n", rv); 132 goto out; 133 } 134 device_printf(sc->dev, "API version = %d.%d\n", 135 payload[1] >> 16, payload[1] & 0xFFFF); 136 out: 137 return (rv); 138 } 139 140 static int 141 zynqmp_get_chipid(struct zynqmp_firmware_softc *sc) 142 { 143 uint32_t payload[4]; 144 int rv; 145 146 rv = zynqmp_call_smc(PM_GET_CHIPID, 0, 0, 0, 0, payload, false); 147 if (rv != 0) { 148 device_printf(sc->dev, "SMC Call fail %d\n", rv); 149 goto out; 150 } 151 device_printf(sc->dev, "ID Code = %x Version = %x\n", 152 payload[1], payload[2]); 153 out: 154 return (rv); 155 } 156 157 static int 158 zynqmp_get_trustzone_version(struct zynqmp_firmware_softc *sc) 159 { 160 uint32_t payload[4]; 161 int rv; 162 163 rv = zynqmp_call_smc(PM_GET_TRUSTZONE_VERSION, 0, 0, 0, 0, payload, false); 164 if (rv != 0) { 165 device_printf(sc->dev, "SMC Call fail %d\n", rv); 166 goto out; 167 } 168 device_printf(sc->dev, "Trustzone Version = %x\n", 169 payload[1]); 170 out: 171 return (rv); 172 } 173 174 /* zynqmp_firmware methods */ 175 static int 176 zynqmp_firmware_clock_enable(device_t dev, uint32_t clkid) 177 { 178 struct zynqmp_firmware_softc *sc; 179 uint32_t payload[4]; 180 int rv; 181 182 sc = device_get_softc(dev); 183 rv = zynqmp_call_smc(PM_CLOCK_ENABLE, clkid, 0, 0, 0, payload, false); 184 if (rv != 0) 185 device_printf(sc->dev, "SMC Call fail %d\n", rv); 186 return (rv); 187 } 188 189 static int 190 zynqmp_firmware_clock_disable(device_t dev, uint32_t clkid) 191 { 192 struct zynqmp_firmware_softc *sc; 193 uint32_t payload[4]; 194 int rv; 195 196 sc = device_get_softc(dev); 197 rv = zynqmp_call_smc(PM_CLOCK_DISABLE, clkid, 0, 0, 0, payload, false); 198 if (rv != 0) 199 device_printf(sc->dev, "SMC Call fail %d\n", rv); 200 return (rv); 201 } 202 203 static int 204 zynqmp_firmware_clock_getstate(device_t dev, uint32_t clkid, bool *enabled) 205 { 206 struct zynqmp_firmware_softc *sc; 207 uint32_t payload[4]; 208 int rv; 209 210 sc = device_get_softc(dev); 211 rv = zynqmp_call_smc(PM_CLOCK_GETSTATE, clkid, 0, 0, 0, payload, false); 212 if (rv != 0) { 213 device_printf(sc->dev, "SMC Call fail %d\n", rv); 214 goto out; 215 } 216 *enabled = payload[1] == 1 ? true : false; 217 218 out: 219 return (rv); 220 } 221 222 static int 223 zynqmp_firmware_clock_setdivider(device_t dev, uint32_t clkid, uint32_t div) 224 { 225 struct zynqmp_firmware_softc *sc; 226 uint32_t payload[4]; 227 int rv; 228 229 sc = device_get_softc(dev); 230 rv = zynqmp_call_smc(PM_CLOCK_SETDIVIDER, clkid, div, 0, 0, payload, false); 231 if (rv != 0) 232 device_printf(sc->dev, "SMC Call fail %d\n", rv); 233 return (rv); 234 } 235 236 static int 237 zynqmp_firmware_clock_getdivider(device_t dev, uint32_t clkid, uint32_t *div) 238 { 239 struct zynqmp_firmware_softc *sc; 240 uint32_t payload[4]; 241 int rv; 242 243 sc = device_get_softc(dev); 244 rv = zynqmp_call_smc(PM_CLOCK_GETDIVIDER, clkid, 0, 0, 0, payload, false); 245 if (rv != 0) { 246 device_printf(sc->dev, "SMC Call fail %d\n", rv); 247 goto out; 248 } 249 *div = payload[1]; 250 251 out: 252 return (rv); 253 } 254 255 static int 256 zynqmp_firmware_clock_setparent(device_t dev, uint32_t clkid, uint32_t parentid) 257 { 258 struct zynqmp_firmware_softc *sc; 259 uint32_t payload[4]; 260 int rv; 261 262 sc = device_get_softc(dev); 263 rv = zynqmp_call_smc(PM_CLOCK_SETPARENT, clkid, parentid, 0, 0, payload, false); 264 if (rv != 0) 265 device_printf(sc->dev, "SMC Call fail %d\n", rv); 266 return (rv); 267 } 268 269 static int 270 zynqmp_firmware_clock_getparent(device_t dev, uint32_t clkid, uint32_t *parentid) 271 { 272 struct zynqmp_firmware_softc *sc; 273 uint32_t payload[4]; 274 int rv; 275 276 sc = device_get_softc(dev); 277 rv = zynqmp_call_smc(PM_CLOCK_GETPARENT, clkid, 0, 0, 0, payload, false); 278 if (rv != 0) { 279 device_printf(sc->dev, "SMC Call fail %d\n", rv); 280 goto out; 281 } 282 *parentid = payload[1]; 283 out: 284 return (rv); 285 } 286 287 static int 288 zynqmp_firmware_pll_get_mode(device_t dev, uint32_t pllid, uint32_t *mode) 289 { 290 struct zynqmp_firmware_softc *sc; 291 uint32_t payload[4]; 292 int rv; 293 294 sc = device_get_softc(dev); 295 rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE, pllid, 0, payload, false); 296 if (rv != 0) { 297 device_printf(sc->dev, "SMC Call fail %d\n", rv); 298 goto out; 299 } 300 *mode = payload[1]; 301 out: 302 return (rv); 303 } 304 305 static int 306 zynqmp_firmware_pll_get_frac_data(device_t dev, uint32_t pllid, uint32_t *data) 307 { 308 struct zynqmp_firmware_softc *sc; 309 uint32_t payload[4]; 310 int rv; 311 312 sc = device_get_softc(dev); 313 rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA, pllid, 0, payload, false); 314 if (rv != 0) { 315 device_printf(sc->dev, "SMC Call fail %d\n", rv); 316 goto out; 317 } 318 *data = payload[1]; 319 out: 320 return (rv); 321 } 322 323 static int 324 zynqmp_firmware_clock_get_fixedfactor(device_t dev, uint32_t clkid, uint32_t *mult, uint32_t *div) 325 { 326 struct zynqmp_firmware_softc *sc; 327 uint32_t payload[4]; 328 int rv; 329 330 sc = device_get_softc(dev); 331 rv = zynqmp_call_smc(PM_QUERY_DATA, PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, clkid, 0, 0, payload, true); 332 if (rv != 0) { 333 device_printf(sc->dev, "SMC Call fail %d\n", rv); 334 goto out; 335 } 336 *mult = payload[1]; 337 *div = payload[2]; 338 out: 339 return (rv); 340 } 341 342 static int 343 zynqmp_firmware_query_data(device_t dev, uint32_t qid, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t *data) 344 { 345 struct zynqmp_firmware_softc *sc; 346 int rv; 347 348 sc = device_get_softc(dev); 349 rv = zynqmp_call_smc(PM_QUERY_DATA, qid, arg1, arg2, arg3, data, true); 350 /* 351 * PM_QID_CLOCK_GET_NAME always success and if the clock name couldn't 352 * be found the clock name will be all null byte 353 */ 354 if (qid == 1) 355 rv = 0; 356 if (rv != 0) 357 device_printf(sc->dev, "SMC Call fail %d\n", rv); 358 return (rv); 359 } 360 361 static int 362 zynqmp_firmware_reset_assert(device_t dev, uint32_t resetid, bool enable) 363 { 364 struct zynqmp_firmware_softc *sc; 365 int rv; 366 367 sc = device_get_softc(dev); 368 rv = zynqmp_call_smc(PM_RESET_ASSERT, resetid, enable, 0, 0, NULL, true); 369 if (rv != 0) 370 device_printf(sc->dev, "SMC Call fail %d\n", rv); 371 372 return (rv); 373 } 374 375 static int 376 zynqmp_firmware_reset_get_status(device_t dev, uint32_t resetid, bool *status) 377 { 378 struct zynqmp_firmware_softc *sc; 379 uint32_t payload[4]; 380 int rv; 381 382 sc = device_get_softc(dev); 383 rv = zynqmp_call_smc(PM_RESET_GET_STATUS, resetid, 0, 0, 0, payload, true); 384 if (rv != 0) { 385 device_printf(sc->dev, "SMC Call fail %d\n", rv); 386 return (rv); 387 } 388 *status = payload[1]; 389 390 return (rv); 391 } 392 393 /* Simplebus methods */ 394 static struct simplebus_devinfo * 395 zynqmp_firmware_setup_dinfo(device_t dev, phandle_t node, 396 struct simplebus_devinfo *di) 397 { 398 struct simplebus_softc *sc; 399 struct simplebus_devinfo *ndi; 400 401 sc = device_get_softc(dev); 402 if (di == NULL) 403 ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 404 else 405 ndi = di; 406 if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { 407 if (di == NULL) 408 free(ndi, M_DEVBUF); 409 return (NULL); 410 } 411 412 /* reg resources is from the parent but interrupts is on the node itself */ 413 resource_list_init(&ndi->rl); 414 ofw_bus_reg_to_rl(dev, OF_parent(node), sc->acells, sc->scells, &ndi->rl); 415 ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL); 416 417 return (ndi); 418 } 419 420 static device_t 421 zynqmp_firmware_add_device(device_t dev, phandle_t node, u_int order, 422 const char *name, int unit, struct simplebus_devinfo *di) 423 { 424 struct simplebus_devinfo *ndi; 425 device_t cdev; 426 427 if ((ndi = zynqmp_firmware_setup_dinfo(dev, node, di)) == NULL) 428 return (NULL); 429 cdev = device_add_child_ordered(dev, order, name, unit); 430 if (cdev == NULL) { 431 device_printf(dev, "<%s>: device_add_child failed\n", 432 ndi->obdinfo.obd_name); 433 resource_list_free(&ndi->rl); 434 ofw_bus_gen_destroy_devinfo(&ndi->obdinfo); 435 if (di == NULL) 436 free(ndi, M_DEVBUF); 437 return (NULL); 438 } 439 device_set_ivars(cdev, ndi); 440 441 return(cdev); 442 } 443 444 static int 445 zynqmp_firmware_probe(device_t dev) 446 { 447 448 if (!ofw_bus_status_okay(dev)) 449 return (ENXIO); 450 if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-firmware")) 451 return (ENXIO); 452 device_set_desc(dev, "ZynqMP Firmware"); 453 return (0); 454 } 455 456 static int 457 zynqmp_firmware_attach(device_t dev) 458 { 459 struct zynqmp_firmware_softc *sc; 460 phandle_t node, child; 461 device_t cdev; 462 463 sc = device_get_softc(dev); 464 sc->dev = dev; 465 466 if (bootverbose) { 467 zynqmp_get_api_version(sc); 468 zynqmp_get_chipid(sc); 469 zynqmp_get_trustzone_version(sc); 470 } 471 472 /* Attach children */ 473 node = ofw_bus_get_node(dev); 474 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 475 cdev = zynqmp_firmware_add_device(dev, child, 0, NULL, -1, NULL); 476 if (cdev != NULL) 477 device_probe_and_attach(cdev); 478 } 479 480 bus_attach_children(dev); 481 return (0); 482 } 483 484 static device_method_t zynqmp_firmware_methods[] = { 485 /* device_if */ 486 DEVMETHOD(device_probe, zynqmp_firmware_probe), 487 DEVMETHOD(device_attach, zynqmp_firmware_attach), 488 489 /* zynqmp_firmware_if */ 490 DEVMETHOD(zynqmp_firmware_clock_enable, zynqmp_firmware_clock_enable), 491 DEVMETHOD(zynqmp_firmware_clock_disable, zynqmp_firmware_clock_disable), 492 DEVMETHOD(zynqmp_firmware_clock_getstate, zynqmp_firmware_clock_getstate), 493 DEVMETHOD(zynqmp_firmware_clock_setdivider, zynqmp_firmware_clock_setdivider), 494 DEVMETHOD(zynqmp_firmware_clock_getdivider, zynqmp_firmware_clock_getdivider), 495 DEVMETHOD(zynqmp_firmware_clock_setparent, zynqmp_firmware_clock_setparent), 496 DEVMETHOD(zynqmp_firmware_clock_getparent, zynqmp_firmware_clock_getparent), 497 DEVMETHOD(zynqmp_firmware_pll_get_mode, zynqmp_firmware_pll_get_mode), 498 DEVMETHOD(zynqmp_firmware_pll_get_frac_data, zynqmp_firmware_pll_get_frac_data), 499 DEVMETHOD(zynqmp_firmware_clock_get_fixedfactor, zynqmp_firmware_clock_get_fixedfactor), 500 DEVMETHOD(zynqmp_firmware_query_data, zynqmp_firmware_query_data), 501 DEVMETHOD(zynqmp_firmware_reset_assert, zynqmp_firmware_reset_assert), 502 DEVMETHOD(zynqmp_firmware_reset_get_status, zynqmp_firmware_reset_get_status), 503 504 DEVMETHOD_END 505 }; 506 507 DEFINE_CLASS_1(zynqmp_firmware, zynqmp_firmware_driver, zynqmp_firmware_methods, 508 sizeof(struct zynqmp_firmware_softc), simplebus_driver); 509 510 EARLY_DRIVER_MODULE(zynqmp_firmware, simplebus, zynqmp_firmware_driver, 0, 0, 511 BUS_PASS_BUS + BUS_PASS_ORDER_LATE); 512 MODULE_VERSION(zynqmp_firmware, 1); 513