1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause 3 */ 4 /* 5 * // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 6 * 7 * Freescale DPAA2 Platforms Console Driver 8 * 9 * Copyright 2015-2016 Freescale Semiconductor Inc. 10 * Copyright 2018 NXP 11 * 12 * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/drivers/soc/fsl/dpaa2-console.c#8120bd469f5525da229953c1197f2b826c0109f4 13 */ 14 /* 15 * Copyright (c) 2022-2023 Bjoern A. Zeeb 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 /* 40 * Some docs are in: 41 * - https://www.nxp.com.cn/docs/en/application-note/AN13329.pdf 42 * - DPAA2UM 43 * - git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/drivers/soc/fsl/dpaa2-console.c 44 */ 45 46 #include "opt_platform.h" 47 #ifdef __notyet__ 48 #include "opt_acpi.h" 49 #endif 50 51 #include <sys/param.h> 52 #include <sys/bus.h> 53 #include <sys/conf.h> 54 #include <sys/fcntl.h> 55 #include <sys/kernel.h> 56 #include <sys/malloc.h> 57 #include <sys/module.h> 58 #include <sys/mutex.h> 59 #include <sys/rman.h> 60 #include <sys/stat.h> 61 #include <sys/uio.h> 62 63 #include <machine/bus.h> 64 #include <machine/resource.h> 65 66 #ifdef FDT 67 #include <dev/ofw/ofw_bus.h> 68 #include <dev/ofw/ofw_bus_subr.h> 69 #endif 70 71 /* Table 6-1. MC Memory Map */ 72 #define MC_REG_MCFBA 0x20 73 #define MC_REG_MCFBALR_OFF 0x00 74 #define MC_REG_MCFBALR_MASK 0xe0000000 75 #define MC_REG_MCFBAHR_OFF 0x04 76 #define MC_REG_MCFBAHR_MASK 0x0001ffff 77 78 /* Firmware Consoles. */ 79 #define MC_BUFFER_OFFSET 0x01000000 80 #define MC_BUFFER_SIZE (1024 * 1024 * 16) 81 #define MC_OFFSET_DELTA MC_BUFFER_OFFSET 82 83 #define AIOP_BUFFER_OFFSET 0x06000000 84 #define AIOP_BUFFER_SIZE (1024 * 1024 * 16) 85 #define AIOP_OFFSET_DELTA 0 86 87 /* MC and AIOP Magic words */ 88 #define MAGIC_MC 0x4d430100 89 #define MAGIC_AIOP 0X41494f50 90 91 #define LOG_HEADER_FLAG_BUFFER_WRAPAROUND \ 92 0x80000000 93 #define LAST_BYTE(a) \ 94 ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND)) 95 96 struct dpaa2_cons_dev { 97 struct cdev *cdev; 98 struct mtx mtx; 99 size_t offset; 100 uint32_t magic; 101 102 uint32_t hdr_magic; 103 uint32_t hdr_eobyte; 104 uint32_t hdr_start; 105 uint32_t hdr_len; 106 107 uoff_t start; 108 uoff_t end; 109 uoff_t eod; 110 uoff_t cur; 111 112 bus_space_tag_t bst; 113 bus_space_handle_t bsh; 114 vm_size_t size; 115 }; 116 117 struct dpaa2_cons_softc { 118 struct resource *res; 119 bus_space_tag_t bst; 120 uint64_t mcfba; 121 struct dpaa2_cons_dev mc_cd; 122 struct dpaa2_cons_dev aiop_cd; 123 }; 124 125 struct dpaa2_cons_hdr { 126 uint32_t magic; 127 uint32_t _reserved; 128 uint32_t start; 129 uint32_t len; 130 uint32_t eobyte; 131 }; 132 133 #define DPAA2_MC_READ_4(_sc, _r) bus_read_4((_sc)->res, (_r)) 134 135 /* Management interface */ 136 static d_open_t dpaa2_cons_open; 137 static d_close_t dpaa2_cons_close; 138 static d_read_t dpaa2_cons_read; 139 140 static struct cdevsw dpaa2_mc_cons_cdevsw = { 141 .d_version = D_VERSION, 142 .d_flags = 0, 143 .d_open = dpaa2_cons_open, 144 .d_close = dpaa2_cons_close, 145 .d_read = dpaa2_cons_read, 146 .d_name = "fsl_mc_console", 147 }; 148 149 static struct cdevsw dpaa2_aiop_cons_cdevsw = { 150 .d_version = D_VERSION, 151 .d_flags = 0, 152 .d_open = dpaa2_cons_open, 153 .d_close = dpaa2_cons_close, 154 .d_read = dpaa2_cons_read, 155 .d_name = "fsl_aiop_console", 156 }; 157 158 static size_t 159 dpaa2_cons_read_bs(struct dpaa2_cons_dev *cd, size_t offset, void *dst, size_t len) 160 { 161 size_t count, l; 162 uint8_t *p; 163 164 count = 0; 165 p = dst; 166 l = offset % 8; 167 if (l != 0) { 168 bus_space_read_region_1(cd->bst, cd->bsh, offset + count, p + count, l); 169 count += l; 170 len -= l; 171 } 172 173 l = len / 8; 174 if (l != 0) { 175 bus_space_read_region_8(cd->bst, cd->bsh, offset + count, (uint64_t *)(p + count), l); 176 l *= 8; 177 count += l; 178 len -= l; 179 } 180 l = len / 4; 181 if (l != 0) { 182 bus_space_read_region_4(cd->bst, cd->bsh, offset + count, (uint32_t *)(p + count), l); 183 l *= 4; 184 count += l; 185 len -= l; 186 } 187 l = len / 2; 188 if (l != 0) { 189 bus_space_read_region_2(cd->bst, cd->bsh, offset + count, (uint16_t *)(p + count), l); 190 l *= 2; 191 count += l; 192 len -= l; 193 } 194 if (len != 0) { 195 bus_space_read_region_1(cd->bst, cd->bsh, offset + count, p + count, len); 196 count += len; 197 } 198 199 return (count); 200 } 201 202 static int 203 dpaa2_cons_open(struct cdev *cdev, int flags, int fmt, struct thread *td) 204 { 205 struct dpaa2_cons_dev *cd; 206 struct dpaa2_cons_hdr hdr; 207 size_t rlen __diagused; 208 uint32_t wrapped; 209 210 if (flags & FWRITE) 211 return (EACCES); 212 213 cd = cdev->si_drv1; 214 if (cd->size == 0) 215 return (ENODEV); 216 217 mtx_lock(&cd->mtx); 218 rlen = dpaa2_cons_read_bs(cd, 0, &hdr, sizeof(hdr)); 219 KASSERT(rlen == sizeof(hdr), ("%s:%d: rlen %zu != count %zu, cdev %p " 220 "cd %p\n", __func__, __LINE__, rlen, sizeof(hdr), cdev, cd)); 221 222 cd->hdr_magic = hdr.magic; 223 if (cd->hdr_magic != cd->magic) { 224 mtx_unlock(&cd->mtx); 225 return (ENODEV); 226 } 227 228 cd->hdr_eobyte = hdr.eobyte; 229 cd->hdr_start = hdr.start; 230 cd->hdr_len = hdr.len; 231 232 cd->start = cd->hdr_start - cd->offset; 233 cd->end = cd->start + cd->hdr_len; 234 235 wrapped = cd->hdr_eobyte & LOG_HEADER_FLAG_BUFFER_WRAPAROUND; 236 cd->eod = cd->start + LAST_BYTE(cd->hdr_eobyte); 237 238 if (wrapped && cd->eod != cd->end) 239 cd->cur = cd->eod + 1; 240 else 241 cd->cur = cd->start; 242 mtx_unlock(&cd->mtx); 243 244 return (0); 245 } 246 247 static int 248 dpaa2_cons_close(struct cdev *cdev, int flags, int fmt, struct thread *td) 249 { 250 struct dpaa2_cons_dev *cd; 251 252 cd = cdev->si_drv1; 253 mtx_lock(&cd->mtx); 254 cd->hdr_magic = cd->hdr_eobyte = cd->hdr_start = cd->hdr_len = 0; 255 cd->start = cd->end = 0; 256 mtx_unlock(&cd->mtx); 257 258 return (0); 259 } 260 261 static int 262 dpaa2_cons_read(struct cdev *cdev, struct uio *uio, int flag) 263 { 264 char buf[128]; 265 struct dpaa2_cons_dev *cd; 266 size_t len, size, count; 267 size_t rlen __diagused; 268 int error; 269 270 cd = cdev->si_drv1; 271 mtx_lock(&cd->mtx); 272 if (cd->cur == cd->eod) { 273 mtx_unlock(&cd->mtx); 274 return (0); 275 } else if (cd->cur > cd->eod) { 276 len = (cd->end - cd->cur) + (cd->eod - cd->start); 277 } else { 278 len = cd->eod - cd->cur; 279 } 280 size = cd->end - cd->cur; 281 282 if (len > size) { 283 /* dump cur [size] */ 284 while (uio->uio_resid > 0) { 285 count = imin(sizeof(buf), uio->uio_resid); 286 if (count > size) 287 count = size; 288 289 rlen = dpaa2_cons_read_bs(cd, cd->cur, buf, count); 290 KASSERT(rlen == count, ("%s:%d: rlen %zu != count %zu, " 291 "cdev %p cd %p\n", __func__, __LINE__, rlen, count, 292 cdev, cd)); 293 294 cd->cur += count; 295 len -= count; 296 size -= count; 297 mtx_unlock(&cd->mtx); 298 error = uiomove(buf, count, uio); 299 if (error != 0 || uio->uio_resid == 0) 300 return (error); 301 mtx_lock(&cd->mtx); 302 } 303 cd->cur = cd->start; 304 } 305 306 /* dump cur [len] */ 307 while (len > 0 && uio->uio_resid > 0) { 308 count = imin(sizeof(buf), uio->uio_resid); 309 if (count > len) 310 count = len; 311 312 rlen = dpaa2_cons_read_bs(cd, cd->cur, buf, count); 313 KASSERT(rlen == count, ("%s:%d: rlen %zu != count %zu, cdev %p " 314 "cd %p\n", __func__, __LINE__, rlen, count, cdev, cd)); 315 316 cd->cur += count; 317 len -= count; 318 mtx_unlock(&cd->mtx); 319 error = uiomove(buf, count, uio); 320 if (error != 0 || uio->uio_resid == 0) 321 return (error); 322 mtx_lock(&cd->mtx); 323 } 324 mtx_unlock(&cd->mtx); 325 return (0); 326 } 327 328 static int 329 dpaa2_cons_create_dev(device_t dev, bus_addr_t pa, size_t size, 330 size_t offset, uint32_t magic, struct cdevsw *devsw, 331 struct dpaa2_cons_dev *cd) 332 { 333 struct dpaa2_cons_softc *sc; 334 struct dpaa2_cons_hdr hdr; 335 struct make_dev_args md_args; 336 size_t len; 337 int error; 338 339 sc = device_get_softc(dev); 340 341 error = bus_space_map(sc->bst, pa, size, 0, &cd->bsh); 342 if (error != 0) { 343 device_printf(dev, "%s: failed to map bus space %#jx/%zu: %d\n", 344 __func__, (uintmax_t)pa, size, error); 345 return (error); 346 } 347 348 cd->bst = sc->bst; 349 cd->size = size; 350 351 len = dpaa2_cons_read_bs(cd, 0, &hdr, sizeof(hdr)); 352 if (len != sizeof(hdr)) { 353 device_printf(dev, "%s: failed to read hdr for %#jx/%zu: %d\n", 354 __func__, (uintmax_t)pa, size, error); 355 bus_space_unmap(cd->bst, cd->bsh, cd->size); 356 cd->size = 0; 357 return (EIO); 358 } 359 360 /* This checks probably needs to be removed one day? */ 361 if (hdr.magic != magic) { 362 if (bootverbose) 363 device_printf(dev, "%s: magic wrong for %#jx/%zu: " 364 "%#010x != %#010x, no console?\n", __func__, 365 (uintmax_t)pa, size, hdr.magic, magic); 366 bus_space_unmap(cd->bst, cd->bsh, cd->size); 367 cd->size = 0; 368 return (ENOENT); 369 } 370 371 if (hdr.start - offset > size) { 372 device_printf(dev, "%s: range wrong for %#jx/%zu: %u - %zu > %zu\n", 373 __func__, (uintmax_t)pa, size, hdr.start, offset, size); 374 bus_space_unmap(cd->bst, cd->bsh, cd->size); 375 cd->size = 0; 376 return (ERANGE); 377 } 378 379 cd->offset = offset; 380 cd->magic = magic; 381 mtx_init(&cd->mtx, "dpaa2 cons", NULL, MTX_DEF); 382 383 make_dev_args_init(&md_args); 384 md_args.mda_devsw = devsw; 385 md_args.mda_uid = 0; 386 md_args.mda_gid = 69; 387 md_args.mda_mode = S_IRUSR | S_IRGRP; 388 md_args.mda_unit = 0; 389 md_args.mda_si_drv1 = cd; 390 error = make_dev_s(&md_args, &cd->cdev, "%s", devsw->d_name); 391 if (error != 0) { 392 device_printf(dev, "%s: make_dev_s failed for %#jx/%zu: %d\n", 393 __func__, (uintmax_t)pa, size, error); 394 mtx_destroy(&cd->mtx); 395 bus_space_unmap(cd->bst, cd->bsh, cd->size); 396 cd->size = 0; 397 return (error); 398 } 399 400 if (bootverbose) 401 device_printf(dev, "dpaa2 console %s at pa %#jx size %#010zx " 402 "(%zu) offset %zu, hdr: magic %#010x start %#010x len " 403 "%#010x eobyte %#010x\n", devsw->d_name, (uintmax_t)pa, 404 size, size, offset, hdr.magic, hdr.start, hdr.len, hdr.eobyte); 405 406 return (0); 407 } 408 409 static int 410 dpaa2_cons_attach_common(device_t dev) 411 { 412 struct dpaa2_cons_softc *sc; 413 414 sc = device_get_softc(dev); 415 416 dpaa2_cons_create_dev(dev, (bus_addr_t)(sc->mcfba + MC_BUFFER_OFFSET), 417 MC_BUFFER_SIZE, MC_OFFSET_DELTA, MAGIC_MC, 418 &dpaa2_mc_cons_cdevsw, &sc->mc_cd); 419 420 dpaa2_cons_create_dev(dev, (bus_addr_t)(sc->mcfba + AIOP_BUFFER_OFFSET), 421 AIOP_BUFFER_SIZE, AIOP_OFFSET_DELTA, MAGIC_AIOP, 422 &dpaa2_aiop_cons_cdevsw, &sc->aiop_cd); 423 424 return (0); 425 } 426 427 static void 428 dpaa2_cons_detach_common(struct dpaa2_cons_dev *cd) 429 { 430 431 bus_space_unmap(cd->bst, cd->bsh, cd->size); 432 mtx_destroy(&cd->mtx); 433 } 434 435 static int 436 dpaa2_cons_detach(device_t dev) 437 { 438 struct dpaa2_cons_softc *sc; 439 440 sc = device_get_softc(dev); 441 442 if (sc->aiop_cd.cdev != NULL) 443 destroy_dev(sc->aiop_cd.cdev); 444 if (sc->mc_cd.cdev != NULL) 445 destroy_dev(sc->mc_cd.cdev); 446 447 if (sc->aiop_cd.size != 0) 448 dpaa2_cons_detach_common(&sc->aiop_cd); 449 if (sc->mc_cd.size != 0) 450 dpaa2_cons_detach_common(&sc->mc_cd); 451 452 if (sc->res != NULL) 453 bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->res), 454 sc->res); 455 456 return (0); 457 } 458 459 #ifdef __notyet__ 460 #ifdef ACPI 461 static int 462 dpaa2_cons_acpi_probe(device_t dev) 463 { 464 465 if (!ofw_bus_status_okay(dev)) 466 return (ENXIO); 467 468 device_set_desc(dev, "DPAA2 Console Driver"); 469 return (BUS_PROBE_DEFAULT); 470 } 471 472 static int 473 dpaa2_cons_acpi_attach(device_t dev) 474 { 475 struct dpaa2_cons_softc *sc; 476 uint32_t val; 477 int error, rid; 478 479 sc = device_get_softc(dev); 480 481 rid = 0; 482 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 483 if (sc->res == NULL) { 484 device_printf(dev, "Could not allocate memory\n"); 485 return (ENXIO); 486 } 487 sc->bst = rman_get_bustag(sc->res); 488 489 val = DPAA2_MC_READ_4(sc, MC_REG_MCFBALR_OFF); 490 val &= MC_REG_MCFBALR_MASK; 491 sc->mcfba |= val; 492 val = DPAA2_MC_READ_4(sc, MC_REG_MCFBAHR_OFF); 493 val &= MC_REG_MCFBAHR_MASK; 494 sc->mcfba |= ((uint64_t)val << 32); 495 496 error = dpaa2_cons_attach_common(dev); 497 498 return (error); 499 } 500 501 static device_method_t dpaa2_cons_acpi_methods[] = { 502 /* Device interface */ 503 DEVMETHOD(device_probe, dpaa2_cons_acpi_probe), 504 DEVMETHOD(device_attach, dpaa2_cons_acpi_attach), 505 DEVMETHOD(device_detach, dpaa2_cons_detach), 506 507 DEVMETHOD_END 508 }; 509 510 DEFINE_CLASS_0(dpaa2_cons_acpi, dpaa2_cons_acpi_driver, dpaa2_cons_acpi_methods, 511 sizeof(struct dpaa2_cons_softc)); 512 513 DRIVER_MODULE(dpaa2_cons_acpi, simplebus, dpaa2_cons_acpi_driver, 0, 0); 514 MODULE_DEPEND(dpaa2_cons_acpi, dpaa2_mc, 1, 1, 1); 515 #endif 516 #endif /* 0 */ 517 518 #ifdef FDT 519 static struct ofw_compat_data compat_data[] = { 520 { "fsl,dpaa2-console", 1 }, 521 { NULL, 0 } 522 }; 523 524 static int 525 dpaa2_cons_fdt_probe(device_t dev) 526 { 527 528 if (!ofw_bus_status_okay(dev)) 529 return (ENXIO); 530 531 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 532 return (ENXIO); 533 534 device_set_desc(dev, "DPAA2 Console Driver"); 535 return (BUS_PROBE_DEFAULT); 536 } 537 538 static int 539 dpaa2_cons_fdt_attach(device_t dev) 540 { 541 struct dpaa2_cons_softc *sc; 542 uint32_t val; 543 int error, rid; 544 545 sc = device_get_softc(dev); 546 547 rid = 0; 548 sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); 549 if (sc->res == NULL) { 550 device_printf(dev, "Could not allocate memory\n"); 551 return (ENXIO); 552 } 553 sc->bst = rman_get_bustag(sc->res); 554 555 val = DPAA2_MC_READ_4(sc, MC_REG_MCFBALR_OFF); 556 val &= MC_REG_MCFBALR_MASK; 557 sc->mcfba |= val; 558 val = DPAA2_MC_READ_4(sc, MC_REG_MCFBAHR_OFF); 559 val &= MC_REG_MCFBAHR_MASK; 560 sc->mcfba |= ((uint64_t)val << 32); 561 562 error = dpaa2_cons_attach_common(dev); 563 564 return (error); 565 } 566 567 static device_method_t dpaa2_cons_fdt_methods[] = { 568 /* Device interface */ 569 DEVMETHOD(device_probe, dpaa2_cons_fdt_probe), 570 DEVMETHOD(device_attach, dpaa2_cons_fdt_attach), 571 DEVMETHOD(device_detach, dpaa2_cons_detach), 572 573 DEVMETHOD_END 574 }; 575 576 DEFINE_CLASS_0(dpaa2_cons_fdt, dpaa2_cons_fdt_driver, dpaa2_cons_fdt_methods, 577 sizeof(struct dpaa2_cons_softc)); 578 579 DRIVER_MODULE(dpaa2_cons_fdt, simplebus, dpaa2_cons_fdt_driver, 0, 0); 580 #endif 581