diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -204,6 +204,7 @@ dev/dpaa2/dpaa2_bp.c optional soc_nxp_ls dpaa2 dev/dpaa2/dpaa2_cmd_if.m optional soc_nxp_ls dpaa2 dev/dpaa2/dpaa2_con.c optional soc_nxp_ls dpaa2 +dev/dpaa2/dpaa2_console.c optional soc_nxp_ls dpaa2 fdt dev/dpaa2/dpaa2_io.c optional soc_nxp_ls dpaa2 dev/dpaa2/dpaa2_mac.c optional soc_nxp_ls dpaa2 dev/dpaa2/dpaa2_mc.c optional soc_nxp_ls dpaa2 diff --git a/sys/dev/dpaa2/dpaa2_console.c b/sys/dev/dpaa2/dpaa2_console.c new file mode 100644 --- /dev/null +++ b/sys/dev/dpaa2/dpaa2_console.c @@ -0,0 +1,581 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause AND BSD-2-Clause + */ +/* + * // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) + * + * Freescale DPAA2 Platforms Console Driver + * + * Copyright 2015-2016 Freescale Semiconductor Inc. + * Copyright 2018 NXP + * + * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/drivers/soc/fsl/dpaa2-console.c#8120bd469f5525da229953c1197f2b826c0109f4 + */ +/* + * Copyright (c) 2022-2023 Bjoern A. Zeeb + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Some docs are in: + * - https://www.nxp.com.cn/docs/en/application-note/AN13329.pdf + * - DPAA2UM + * - git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/drivers/soc/fsl/dpaa2-console.c + */ + +#include "opt_platform.h" +#ifdef __notyet__ +#include "opt_acpi.h" +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef FDT +#include +#include +#endif + +/* Table 6-1. MC Memory Map */ +#define MC_REG_MCFBA 0x20 +#define MC_REG_MCFBALR_OFF 0x00 +#define MC_REG_MCFBALR_MASK 0xe0000000 +#define MC_REG_MCFBAHR_OFF 0x04 +#define MC_REG_MCFBAHR_MASK 0x0001ffff + +/* Firmware Consoles. */ +#define MC_BUFFER_OFFSET 0x01000000 +#define MC_BUFFER_SIZE (1024 * 1024 * 16) +#define MC_OFFSET_DELTA MC_BUFFER_OFFSET + +#define AIOP_BUFFER_OFFSET 0x06000000 +#define AIOP_BUFFER_SIZE (1024 * 1024 * 16) +#define AIOP_OFFSET_DELTA 0 + +/* MC and AIOP Magic words */ +#define MAGIC_MC 0x4d430100 +#define MAGIC_AIOP 0X41494f50 + +#define LOG_HEADER_FLAG_BUFFER_WRAPAROUND \ + 0x80000000 +#define LAST_BYTE(a) \ + ((a) & ~(LOG_HEADER_FLAG_BUFFER_WRAPAROUND)) + +struct dpaa2_cons_dev { + struct cdev *cdev; + struct mtx mtx; + size_t offset; + uint32_t magic; + + uint32_t hdr_magic; + uint32_t hdr_eobyte; + uint32_t hdr_start; + uint32_t hdr_len; + + uoff_t start; + uoff_t end; + uoff_t eod; + uoff_t cur; + + bus_space_tag_t bst; + bus_space_handle_t bsh; + vm_size_t size; +}; + +struct dpaa2_cons_softc { + struct resource *res; + bus_space_tag_t bst; + uint64_t mcfba; + struct dpaa2_cons_dev mc_cd; + struct dpaa2_cons_dev aiop_cd; +}; + +struct dpaa2_cons_hdr { + uint32_t magic; + uint32_t _reserved; + uint32_t start; + uint32_t len; + uint32_t eobyte; +}; + +#define DPAA2_MC_READ_4(_sc, _r) bus_read_4((_sc)->res, (_r)) + +/* Management interface */ +static d_open_t dpaa2_cons_open; +static d_close_t dpaa2_cons_close; +static d_read_t dpaa2_cons_read; + +static struct cdevsw dpaa2_mc_cons_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = dpaa2_cons_open, + .d_close = dpaa2_cons_close, + .d_read = dpaa2_cons_read, + .d_name = "fsl_mc_console", +}; + +static struct cdevsw dpaa2_aiop_cons_cdevsw = { + .d_version = D_VERSION, + .d_flags = 0, + .d_open = dpaa2_cons_open, + .d_close = dpaa2_cons_close, + .d_read = dpaa2_cons_read, + .d_name = "fsl_aiop_console", +}; + +static size_t +dpaa2_cons_read_bs(struct dpaa2_cons_dev *cd, size_t offset, void *dst, size_t len) +{ + size_t count, l; + uint8_t *p; + + count = 0; + p = dst; + l = offset % 8; + if (l != 0) { + bus_space_read_region_1(cd->bst, cd->bsh, offset + count, p + count, l); + count += l; + len -= l; + } + + l = len / 8; + if (l != 0) { + bus_space_read_region_8(cd->bst, cd->bsh, offset + count, (uint64_t *)(p + count), l); + l *= 8; + count += l; + len -= l; + } + l = len / 4; + if (l != 0) { + bus_space_read_region_4(cd->bst, cd->bsh, offset + count, (uint32_t *)(p + count), l); + l *= 4; + count += l; + len -= l; + } + l = len / 2; + if (l != 0) { + bus_space_read_region_2(cd->bst, cd->bsh, offset + count, (uint16_t *)(p + count), l); + l *= 2; + count += l; + len -= l; + } + if (len != 0) { + bus_space_read_region_1(cd->bst, cd->bsh, offset + count, p + count, len); + count += len; + } + + return (count); +} + +static int +dpaa2_cons_open(struct cdev *cdev, int flags, int fmt, struct thread *td) +{ + struct dpaa2_cons_dev *cd; + struct dpaa2_cons_hdr hdr; + size_t rlen __diagused; + uint32_t wrapped; + + if (flags & FWRITE) + return (EACCES); + + cd = cdev->si_drv1; + if (cd->size == 0) + return (ENODEV); + + mtx_lock(&cd->mtx); + rlen = dpaa2_cons_read_bs(cd, 0, &hdr, sizeof(hdr)); + KASSERT(rlen == sizeof(hdr), ("%s:%d: rlen %zu != count %zu, cdev %p " + "cd %p\n", __func__, __LINE__, rlen, sizeof(hdr), cdev, cd)); + + cd->hdr_magic = hdr.magic; + if (cd->hdr_magic != cd->magic) { + mtx_unlock(&cd->mtx); + return (ENODEV); + } + + cd->hdr_eobyte = hdr.eobyte; + cd->hdr_start = hdr.start; + cd->hdr_len = hdr.len; + + cd->start = cd->hdr_start - cd->offset; + cd->end = cd->start + cd->hdr_len; + + wrapped = cd->hdr_eobyte & LOG_HEADER_FLAG_BUFFER_WRAPAROUND; + cd->eod = cd->start + LAST_BYTE(cd->hdr_eobyte); + + if (wrapped && cd->eod != cd->end) + cd->cur = cd->eod + 1; + else + cd->cur = cd->start; + mtx_unlock(&cd->mtx); + + return (0); +} + +static int +dpaa2_cons_close(struct cdev *cdev, int flags, int fmt, struct thread *td) +{ + struct dpaa2_cons_dev *cd; + + cd = cdev->si_drv1; + mtx_lock(&cd->mtx); + cd->hdr_magic = cd->hdr_eobyte = cd->hdr_start = cd->hdr_len = 0; + cd->start = cd->end = 0; + mtx_unlock(&cd->mtx); + + return (0); +} + +static int +dpaa2_cons_read(struct cdev *cdev, struct uio *uio, int flag) +{ + char buf[128]; + struct dpaa2_cons_dev *cd; + size_t len, size, count; + size_t rlen __diagused; + int error; + + cd = cdev->si_drv1; + mtx_lock(&cd->mtx); + if (cd->cur == cd->eod) { + mtx_unlock(&cd->mtx); + return (0); + } else if (cd->cur > cd->eod) { + len = (cd->end - cd->cur) + (cd->eod - cd->start); + } else { + len = cd->eod - cd->cur; + } + size = cd->end - cd->cur; + + if (len > size) { + /* dump cur [size] */ + while (uio->uio_resid > 0) { + count = imin(sizeof(buf), uio->uio_resid); + if (count > size) + count = size; + + rlen = dpaa2_cons_read_bs(cd, cd->cur, buf, count); + KASSERT(rlen == count, ("%s:%d: rlen %zu != count %zu, " + "cdev %p cd %p\n", __func__, __LINE__, rlen, count, + cdev, cd)); + + cd->cur += count; + len -= count; + size -= count; + mtx_unlock(&cd->mtx); + error = uiomove(buf, count, uio); + if (error != 0 || uio->uio_resid == 0) + return (error); + mtx_lock(&cd->mtx); + } + cd->cur = cd->start; + } + + /* dump cur [len] */ + while (len > 0 && uio->uio_resid > 0) { + count = imin(sizeof(buf), uio->uio_resid); + if (count > len) + count = len; + + rlen = dpaa2_cons_read_bs(cd, cd->cur, buf, count); + KASSERT(rlen == count, ("%s:%d: rlen %zu != count %zu, cdev %p " + "cd %p\n", __func__, __LINE__, rlen, count, cdev, cd)); + + cd->cur += count; + len -= count; + mtx_unlock(&cd->mtx); + error = uiomove(buf, count, uio); + if (error != 0 || uio->uio_resid == 0) + return (error); + mtx_lock(&cd->mtx); + } + mtx_unlock(&cd->mtx); + return (0); +} + +static int +dpaa2_cons_create_dev(device_t dev, bus_addr_t pa, size_t size, + size_t offset, uint32_t magic, struct cdevsw *devsw, + struct dpaa2_cons_dev *cd) +{ + struct dpaa2_cons_softc *sc; + struct dpaa2_cons_hdr hdr; + struct make_dev_args md_args; + size_t len; + int error; + + sc = device_get_softc(dev); + + error = bus_space_map(sc->bst, pa, size, 0, &cd->bsh); + if (error != 0) { + device_printf(dev, "%s: failed to map bus space %#jx/%zu: %d\n", + __func__, (uintmax_t)pa, size, error); + return (error); + } + + cd->bst = sc->bst; + cd->size = size; + + len = dpaa2_cons_read_bs(cd, 0, &hdr, sizeof(hdr)); + if (len != sizeof(hdr)) { + device_printf(dev, "%s: failed to read hdr for %#jx/%zu: %d\n", + __func__, (uintmax_t)pa, size, error); + bus_space_unmap(cd->bst, cd->bsh, cd->size); + cd->size = 0; + return (EIO); + } + + /* This checks probably needs to be removed one day? */ + if (hdr.magic != magic) { + if (bootverbose) + device_printf(dev, "%s: magic wrong for %#jx/%zu: " + "%#010x != %#010x, no console?\n", __func__, + (uintmax_t)pa, size, hdr.magic, magic); + bus_space_unmap(cd->bst, cd->bsh, cd->size); + cd->size = 0; + return (ENOENT); + } + + if (hdr.start - offset > size) { + device_printf(dev, "%s: range wrong for %#jx/%zu: %u - %zu > %zu\n", + __func__, (uintmax_t)pa, size, hdr.start, offset, size); + bus_space_unmap(cd->bst, cd->bsh, cd->size); + cd->size = 0; + return (ERANGE); + } + + cd->offset = offset; + cd->magic = magic; + mtx_init(&cd->mtx, "dpaa2 cons", NULL, MTX_DEF); + + make_dev_args_init(&md_args); + md_args.mda_devsw = devsw; + md_args.mda_uid = 0; + md_args.mda_gid = 69; + md_args.mda_mode = S_IRUSR | S_IRGRP; + md_args.mda_unit = 0; + md_args.mda_si_drv1 = cd; + error = make_dev_s(&md_args, &cd->cdev, "%s", devsw->d_name); + if (error != 0) { + device_printf(dev, "%s: make_dev_s failed for %#jx/%zu: %d\n", + __func__, (uintmax_t)pa, size, error); + mtx_destroy(&cd->mtx); + bus_space_unmap(cd->bst, cd->bsh, cd->size); + cd->size = 0; + return (error); + } + + if (bootverbose) + device_printf(dev, "dpaa2 console %s at pa %#jx size %#010zx " + "(%zu) offset %zu, hdr: magic %#010x start %#010x len " + "%#010x eobyte %#010x\n", devsw->d_name, (uintmax_t)pa, + size, size, offset, hdr.magic, hdr.start, hdr.len, hdr.eobyte); + + return (0); +} + +static int +dpaa2_cons_attach_common(device_t dev) +{ + struct dpaa2_cons_softc *sc; + + sc = device_get_softc(dev); + + dpaa2_cons_create_dev(dev, (bus_addr_t)(sc->mcfba + MC_BUFFER_OFFSET), + MC_BUFFER_SIZE, MC_OFFSET_DELTA, MAGIC_MC, + &dpaa2_mc_cons_cdevsw, &sc->mc_cd); + + dpaa2_cons_create_dev(dev, (bus_addr_t)(sc->mcfba + AIOP_BUFFER_OFFSET), + AIOP_BUFFER_SIZE, AIOP_OFFSET_DELTA, MAGIC_AIOP, + &dpaa2_aiop_cons_cdevsw, &sc->aiop_cd); + + return (0); +} + +static void +dpaa2_cons_detach_common(struct dpaa2_cons_dev *cd) +{ + + bus_space_unmap(cd->bst, cd->bsh, cd->size); + mtx_destroy(&cd->mtx); +} + +static int +dpaa2_cons_detach(device_t dev) +{ + struct dpaa2_cons_softc *sc; + + sc = device_get_softc(dev); + + if (sc->aiop_cd.cdev != NULL) + destroy_dev(sc->aiop_cd.cdev); + if (sc->mc_cd.cdev != NULL) + destroy_dev(sc->mc_cd.cdev); + + if (sc->aiop_cd.size != 0) + dpaa2_cons_detach_common(&sc->aiop_cd); + if (sc->mc_cd.size != 0) + dpaa2_cons_detach_common(&sc->mc_cd); + + if (sc->res != NULL) + bus_release_resource(dev, SYS_RES_MEMORY, rman_get_rid(sc->res), + sc->res); + + return (0); +} + +#ifdef __notyet__ +#ifdef ACPI +static int +dpaa2_cons_acpi_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + device_set_desc(dev, "DPAA2 Console Driver"); + return (BUS_PROBE_DEFAULT); +} + +static int +dpaa2_cons_acpi_attach(device_t dev) +{ + struct dpaa2_cons_softc *sc; + uint32_t val; + int error, rid; + + sc = device_get_softc(dev); + + rid = 0; + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "Could not allocate memory\n"); + return (ENXIO); + } + sc->bst = rman_get_bustag(sc->res); + + val = DPAA2_MC_READ_4(sc, MC_REG_MCFBALR_OFF); + val &= MC_REG_MCFBALR_MASK; + sc->mcfba |= val; + val = DPAA2_MC_READ_4(sc, MC_REG_MCFBAHR_OFF); + val &= MC_REG_MCFBAHR_MASK; + sc->mcfba |= ((uint64_t)val << 32); + + error = dpaa2_cons_attach_common(dev); + + return (error); +} + +static device_method_t dpaa2_cons_acpi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, dpaa2_cons_acpi_probe), + DEVMETHOD(device_attach, dpaa2_cons_acpi_attach), + DEVMETHOD(device_detach, dpaa2_cons_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(dpaa2_cons_acpi, dpaa2_cons_acpi_driver, dpaa2_cons_acpi_methods, + sizeof(struct dpaa2_cons_softc)); + +DRIVER_MODULE(dpaa2_cons_acpi, simplebus, dpaa2_cons_acpi_driver, 0, 0); +MODULE_DEPEND(dpaa2_cons_acpi, dpaa2_mc, 1, 1, 1); +#endif +#endif /* 0 */ + +#ifdef FDT +static struct ofw_compat_data compat_data[] = { + { "fsl,dpaa2-console", 1 }, + { NULL, 0 } +}; + +static int +dpaa2_cons_fdt_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + + device_set_desc(dev, "DPAA2 Console Driver"); + return (BUS_PROBE_DEFAULT); +} + +static int +dpaa2_cons_fdt_attach(device_t dev) +{ + struct dpaa2_cons_softc *sc; + uint32_t val; + int error, rid; + + sc = device_get_softc(dev); + + rid = 0; + sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (sc->res == NULL) { + device_printf(dev, "Could not allocate memory\n"); + return (ENXIO); + } + sc->bst = rman_get_bustag(sc->res); + + val = DPAA2_MC_READ_4(sc, MC_REG_MCFBALR_OFF); + val &= MC_REG_MCFBALR_MASK; + sc->mcfba |= val; + val = DPAA2_MC_READ_4(sc, MC_REG_MCFBAHR_OFF); + val &= MC_REG_MCFBAHR_MASK; + sc->mcfba |= ((uint64_t)val << 32); + + error = dpaa2_cons_attach_common(dev); + + return (error); +} + +static device_method_t dpaa2_cons_fdt_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, dpaa2_cons_fdt_probe), + DEVMETHOD(device_attach, dpaa2_cons_fdt_attach), + DEVMETHOD(device_detach, dpaa2_cons_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(dpaa2_cons_fdt, dpaa2_cons_fdt_driver, dpaa2_cons_fdt_methods, + sizeof(struct dpaa2_cons_softc)); + +DRIVER_MODULE(dpaa2_cons_fdt, simplebus, dpaa2_cons_fdt_driver, 0, 0); +#endif diff --git a/sys/modules/dpaa2/Makefile b/sys/modules/dpaa2/Makefile --- a/sys/modules/dpaa2/Makefile +++ b/sys/modules/dpaa2/Makefile @@ -17,6 +17,8 @@ SRCS+= dpaa2_mc_if.c dpaa2_mc_if.h SRCS+= memac_mdio_common.c memac_mdio_if.c memac_mdio_if.h +SRCS+= dpaa2_console.c + SRCS+= bus_if.h device_if.h miibus_if.h SRCS+= pcib_if.h pci_if.h SRCS+= opt_acpi.h opt_platform.h