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 device_t dev; 92 zynqmp_callfn_t callfn; 93 }; 94 95 /* SMC calling methods */ 96 #define PM_SIP_SVC 0xC2000000 97 98 static int 99 zynqmp_call_smc(uint32_t id, uint32_t a0, uint32_t a1, uint32_t a2, uint32_t a3, uint32_t *payload, bool ignore_error) 100 { 101 struct arm_smccc_res res; 102 uint64_t args[3]; 103 104 args[0] = id | PM_SIP_SVC; 105 args[1] = ((uint64_t)a1 << 32) | a0; 106 args[2] = ((uint64_t)a3 << 32) | a2; 107 arm_smccc_invoke_smc(args[0], args[1], args[2], &res); 108 if (payload != NULL) { 109 payload[0] = res.a0 & 0xFFFFFFFF; 110 payload[1] = res.a0 >> 32; 111 payload[2] = res.a1 & 0xFFFFFFFF; 112 payload[3] = res.a1 >> 32; 113 if (!ignore_error && payload[0] != PM_RET_SUCCESS) { 114 printf("%s: fail %x\n", __func__, payload[0]); 115 return (EINVAL); 116 } 117 } 118 return (0); 119 } 120 121 /* Firmware methods */ 122 static int 123 zynqmp_get_api_version(struct zynqmp_firmware_softc *sc) 124 { 125 uint32_t payload[4]; 126 int rv; 127 128 rv = zynqmp_call_smc(PM_GET_API_VERSION, 0, 0, 0, 0, payload, false); 129 if (rv != 0) { 130 device_printf(sc->dev, "SMC Call fail %d\n", rv); 131 goto out; 132 } 133 device_printf(sc->dev, "API version = %d.%d\n", 134 payload[1] >> 16, payload[1] & 0xFFFF); 135 out: 136 return (rv); 137 } 138 139 static int 140 zynqmp_get_chipid(struct zynqmp_firmware_softc *sc) 141 { 142 uint32_t payload[4]; 143 int rv; 144 145 rv = zynqmp_call_smc(PM_GET_CHIPID, 0, 0, 0, 0, payload, false); 146 if (rv != 0) { 147 device_printf(sc->dev, "SMC Call fail %d\n", rv); 148 goto out; 149 } 150 device_printf(sc->dev, "ID Code = %x Version = %x\n", 151 payload[1], payload[2]); 152 out: 153 return (rv); 154 } 155 156 static int 157 zynqmp_get_trustzone_version(struct zynqmp_firmware_softc *sc) 158 { 159 uint32_t payload[4]; 160 int rv; 161 162 rv = zynqmp_call_smc(PM_GET_TRUSTZONE_VERSION, 0, 0, 0, 0, payload, false); 163 if (rv != 0) { 164 device_printf(sc->dev, "SMC Call fail %d\n", rv); 165 goto out; 166 } 167 device_printf(sc->dev, "Trustzone Version = %x\n", 168 payload[1]); 169 out: 170 return (rv); 171 } 172 173 /* zynqmp_firmware methods */ 174 static int 175 zynqmp_firmware_clock_enable(device_t dev, uint32_t clkid) 176 { 177 struct zynqmp_firmware_softc *sc; 178 uint32_t payload[4]; 179 int rv; 180 181 sc = device_get_softc(dev); 182 rv = zynqmp_call_smc(PM_CLOCK_ENABLE, clkid, 0, 0, 0, payload, false); 183 if (rv != 0) 184 device_printf(sc->dev, "SMC Call fail %d\n", rv); 185 return (rv); 186 } 187 188 static int 189 zynqmp_firmware_clock_disable(device_t dev, uint32_t clkid) 190 { 191 struct zynqmp_firmware_softc *sc; 192 uint32_t payload[4]; 193 int rv; 194 195 sc = device_get_softc(dev); 196 rv = zynqmp_call_smc(PM_CLOCK_DISABLE, clkid, 0, 0, 0, payload, false); 197 if (rv != 0) 198 device_printf(sc->dev, "SMC Call fail %d\n", rv); 199 return (rv); 200 } 201 202 static int 203 zynqmp_firmware_clock_getstate(device_t dev, uint32_t clkid, bool *enabled) 204 { 205 struct zynqmp_firmware_softc *sc; 206 uint32_t payload[4]; 207 int rv; 208 209 sc = device_get_softc(dev); 210 rv = zynqmp_call_smc(PM_CLOCK_GETSTATE, clkid, 0, 0, 0, payload, false); 211 if (rv != 0) { 212 device_printf(sc->dev, "SMC Call fail %d\n", rv); 213 goto out; 214 } 215 *enabled = payload[1] == 1 ? true : false; 216 217 out: 218 return (rv); 219 } 220 221 static int 222 zynqmp_firmware_clock_setdivider(device_t dev, uint32_t clkid, uint32_t div) 223 { 224 struct zynqmp_firmware_softc *sc; 225 uint32_t payload[4]; 226 int rv; 227 228 sc = device_get_softc(dev); 229 rv = zynqmp_call_smc(PM_CLOCK_SETDIVIDER, clkid, div, 0, 0, payload, false); 230 if (rv != 0) 231 device_printf(sc->dev, "SMC Call fail %d\n", rv); 232 return (rv); 233 } 234 235 static int 236 zynqmp_firmware_clock_getdivider(device_t dev, uint32_t clkid, uint32_t *div) 237 { 238 struct zynqmp_firmware_softc *sc; 239 uint32_t payload[4]; 240 int rv; 241 242 sc = device_get_softc(dev); 243 rv = zynqmp_call_smc(PM_CLOCK_GETDIVIDER, clkid, 0, 0, 0, payload, false); 244 if (rv != 0) { 245 device_printf(sc->dev, "SMC Call fail %d\n", rv); 246 goto out; 247 } 248 *div = payload[1]; 249 250 out: 251 return (rv); 252 } 253 254 static int 255 zynqmp_firmware_clock_setparent(device_t dev, uint32_t clkid, uint32_t parentid) 256 { 257 struct zynqmp_firmware_softc *sc; 258 uint32_t payload[4]; 259 int rv; 260 261 sc = device_get_softc(dev); 262 rv = zynqmp_call_smc(PM_CLOCK_SETPARENT, clkid, parentid, 0, 0, payload, false); 263 if (rv != 0) 264 device_printf(sc->dev, "SMC Call fail %d\n", rv); 265 return (rv); 266 } 267 268 static int 269 zynqmp_firmware_clock_getparent(device_t dev, uint32_t clkid, uint32_t *parentid) 270 { 271 struct zynqmp_firmware_softc *sc; 272 uint32_t payload[4]; 273 int rv; 274 275 sc = device_get_softc(dev); 276 rv = zynqmp_call_smc(PM_CLOCK_GETPARENT, clkid, 0, 0, 0, payload, false); 277 if (rv != 0) { 278 device_printf(sc->dev, "SMC Call fail %d\n", rv); 279 goto out; 280 } 281 *parentid = payload[1]; 282 out: 283 return (rv); 284 } 285 286 static int 287 zynqmp_firmware_pll_get_mode(device_t dev, uint32_t pllid, uint32_t *mode) 288 { 289 struct zynqmp_firmware_softc *sc; 290 uint32_t payload[4]; 291 int rv; 292 293 sc = device_get_softc(dev); 294 rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_MODE, pllid, 0, payload, false); 295 if (rv != 0) { 296 device_printf(sc->dev, "SMC Call fail %d\n", rv); 297 goto out; 298 } 299 *mode = payload[1]; 300 out: 301 return (rv); 302 } 303 304 static int 305 zynqmp_firmware_pll_get_frac_data(device_t dev, uint32_t pllid, uint32_t *data) 306 { 307 struct zynqmp_firmware_softc *sc; 308 uint32_t payload[4]; 309 int rv; 310 311 sc = device_get_softc(dev); 312 rv = zynqmp_call_smc(PM_IOCTL, 0, IOCTL_GET_PLL_FRAC_DATA, pllid, 0, payload, false); 313 if (rv != 0) { 314 device_printf(sc->dev, "SMC Call fail %d\n", rv); 315 goto out; 316 } 317 *data = payload[1]; 318 out: 319 return (rv); 320 } 321 322 static int 323 zynqmp_firmware_clock_get_fixedfactor(device_t dev, uint32_t clkid, uint32_t *mult, uint32_t *div) 324 { 325 struct zynqmp_firmware_softc *sc; 326 uint32_t payload[4]; 327 int rv; 328 329 sc = device_get_softc(dev); 330 rv = zynqmp_call_smc(PM_QUERY_DATA, PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, clkid, 0, 0, payload, true); 331 if (rv != 0) { 332 device_printf(sc->dev, "SMC Call fail %d\n", rv); 333 goto out; 334 } 335 *mult = payload[1]; 336 *div = payload[2]; 337 out: 338 return (rv); 339 } 340 341 static int 342 zynqmp_firmware_query_data(device_t dev, uint32_t qid, uint32_t arg1, uint32_t arg2, uint32_t arg3, uint32_t *data) 343 { 344 struct zynqmp_firmware_softc *sc; 345 int rv; 346 347 sc = device_get_softc(dev); 348 rv = zynqmp_call_smc(PM_QUERY_DATA, qid, arg1, arg2, arg3, data, true); 349 /* 350 * PM_QID_CLOCK_GET_NAME always success and if the clock name couldn't 351 * be found the clock name will be all null byte 352 */ 353 if (qid == 1) 354 rv = 0; 355 if (rv != 0) 356 device_printf(sc->dev, "SMC Call fail %d\n", rv); 357 return (rv); 358 } 359 360 static int 361 zynqmp_firmware_reset_assert(device_t dev, uint32_t resetid, bool enable) 362 { 363 struct zynqmp_firmware_softc *sc; 364 int rv; 365 366 sc = device_get_softc(dev); 367 rv = zynqmp_call_smc(PM_RESET_ASSERT, resetid, enable, 0, 0, NULL, true); 368 if (rv != 0) 369 device_printf(sc->dev, "SMC Call fail %d\n", rv); 370 371 return (rv); 372 } 373 374 static int 375 zynqmp_firmware_reset_get_status(device_t dev, uint32_t resetid, bool *status) 376 { 377 struct zynqmp_firmware_softc *sc; 378 uint32_t payload[4]; 379 int rv; 380 381 sc = device_get_softc(dev); 382 rv = zynqmp_call_smc(PM_RESET_GET_STATUS, resetid, 0, 0, 0, payload, true); 383 if (rv != 0) { 384 device_printf(sc->dev, "SMC Call fail %d\n", rv); 385 return (rv); 386 } 387 *status = payload[1]; 388 389 return (rv); 390 } 391 392 /* Simplebus methods */ 393 static struct simplebus_devinfo * 394 zynqmp_firmware_setup_dinfo(device_t dev, phandle_t node, 395 struct simplebus_devinfo *di) 396 { 397 struct simplebus_softc *sc; 398 struct simplebus_devinfo *ndi; 399 400 sc = device_get_softc(dev); 401 if (di == NULL) 402 ndi = malloc(sizeof(*ndi), M_DEVBUF, M_WAITOK | M_ZERO); 403 else 404 ndi = di; 405 if (ofw_bus_gen_setup_devinfo(&ndi->obdinfo, node) != 0) { 406 if (di == NULL) 407 free(ndi, M_DEVBUF); 408 return (NULL); 409 } 410 411 /* reg resources is from the parent but interrupts is on the node itself */ 412 resource_list_init(&ndi->rl); 413 ofw_bus_reg_to_rl(dev, OF_parent(node), sc->acells, sc->scells, &ndi->rl); 414 ofw_bus_intr_to_rl(dev, node, &ndi->rl, NULL); 415 416 return (ndi); 417 } 418 419 static device_t 420 zynqmp_firmware_add_device(device_t dev, phandle_t node, u_int order, 421 const char *name, int unit, struct simplebus_devinfo *di) 422 { 423 struct simplebus_devinfo *ndi; 424 device_t cdev; 425 426 if ((ndi = zynqmp_firmware_setup_dinfo(dev, node, di)) == NULL) 427 return (NULL); 428 cdev = device_add_child_ordered(dev, order, name, unit); 429 if (cdev == NULL) { 430 device_printf(dev, "<%s>: device_add_child failed\n", 431 ndi->obdinfo.obd_name); 432 resource_list_free(&ndi->rl); 433 ofw_bus_gen_destroy_devinfo(&ndi->obdinfo); 434 if (di == NULL) 435 free(ndi, M_DEVBUF); 436 return (NULL); 437 } 438 device_set_ivars(cdev, ndi); 439 440 return(cdev); 441 } 442 443 static int 444 zynqmp_firmware_probe(device_t dev) 445 { 446 447 if (!ofw_bus_status_okay(dev)) 448 return (ENXIO); 449 if (!ofw_bus_is_compatible(dev, "xlnx,zynqmp-firmware")) 450 return (ENXIO); 451 device_set_desc(dev, "ZynqMP Firmware"); 452 return (0); 453 } 454 455 static int 456 zynqmp_firmware_attach(device_t dev) 457 { 458 struct zynqmp_firmware_softc *sc; 459 phandle_t node, child; 460 device_t cdev; 461 462 sc = device_get_softc(dev); 463 sc->dev = dev; 464 465 if (bootverbose) { 466 zynqmp_get_api_version(sc); 467 zynqmp_get_chipid(sc); 468 zynqmp_get_trustzone_version(sc); 469 } 470 471 /* Attach children */ 472 node = ofw_bus_get_node(dev); 473 for (child = OF_child(node); child != 0; child = OF_peer(child)) { 474 cdev = zynqmp_firmware_add_device(dev, child, 0, NULL, -1, NULL); 475 if (cdev != NULL) 476 device_probe_and_attach(cdev); 477 } 478 479 bus_attach_children(dev); 480 return (0); 481 } 482 483 static device_method_t zynqmp_firmware_methods[] = { 484 /* device_if */ 485 DEVMETHOD(device_probe, zynqmp_firmware_probe), 486 DEVMETHOD(device_attach, zynqmp_firmware_attach), 487 488 /* zynqmp_firmware_if */ 489 DEVMETHOD(zynqmp_firmware_clock_enable, zynqmp_firmware_clock_enable), 490 DEVMETHOD(zynqmp_firmware_clock_disable, zynqmp_firmware_clock_disable), 491 DEVMETHOD(zynqmp_firmware_clock_getstate, zynqmp_firmware_clock_getstate), 492 DEVMETHOD(zynqmp_firmware_clock_setdivider, zynqmp_firmware_clock_setdivider), 493 DEVMETHOD(zynqmp_firmware_clock_getdivider, zynqmp_firmware_clock_getdivider), 494 DEVMETHOD(zynqmp_firmware_clock_setparent, zynqmp_firmware_clock_setparent), 495 DEVMETHOD(zynqmp_firmware_clock_getparent, zynqmp_firmware_clock_getparent), 496 DEVMETHOD(zynqmp_firmware_pll_get_mode, zynqmp_firmware_pll_get_mode), 497 DEVMETHOD(zynqmp_firmware_pll_get_frac_data, zynqmp_firmware_pll_get_frac_data), 498 DEVMETHOD(zynqmp_firmware_clock_get_fixedfactor, zynqmp_firmware_clock_get_fixedfactor), 499 DEVMETHOD(zynqmp_firmware_query_data, zynqmp_firmware_query_data), 500 DEVMETHOD(zynqmp_firmware_reset_assert, zynqmp_firmware_reset_assert), 501 DEVMETHOD(zynqmp_firmware_reset_get_status, zynqmp_firmware_reset_get_status), 502 503 DEVMETHOD_END 504 }; 505 506 DEFINE_CLASS_1(zynqmp_firmware, zynqmp_firmware_driver, zynqmp_firmware_methods, 507 sizeof(struct zynqmp_firmware_softc), simplebus_driver); 508 509 EARLY_DRIVER_MODULE(zynqmp_firmware, simplebus, zynqmp_firmware_driver, 0, 0, 510 BUS_PASS_BUS + BUS_PASS_ORDER_LATE); 511 MODULE_VERSION(zynqmp_firmware, 1); 512