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