Index: sys/amd64/conf/GENERIC =================================================================== --- sys/amd64/conf/GENERIC +++ sys/amd64/conf/GENERIC @@ -240,6 +240,7 @@ # Serial (COM) ports device uart # Generic UART driver +device intellpss # Intel Low Power SubSystem # Parallel port device ppc Index: sys/conf/files.x86 =================================================================== --- sys/conf/files.x86 +++ sys/conf/files.x86 @@ -144,6 +144,8 @@ dev/imcsmb/imcsmb.c optional imcsmb dev/imcsmb/imcsmb_pci.c optional imcsmb pci dev/intel/spi.c optional intelspi +dev/intel/lpss.c optional intellpss +dev/uart/uart_dev_lpss_pci.c optional uart pci intellpss dev/io/iodev.c optional io dev/iommu/busdma_iommu.c optional acpi iommu pci dev/iommu/iommu_gas.c optional acpi iommu pci Index: sys/dev/intel/lpss.h =================================================================== --- /dev/null +++ sys/dev/intel/lpss.h @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG + * + * 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. + * + */ + +#ifndef _LPSS_H_ +#define _LPSS_H_ + +enum lpss_type { + LPSS_TYPE_I2C = 0x0, + LPSS_TYPE_UART, + LPSS_TYPE_SPI, +}; + +#define LPSS_REGS_BASE 0x200 +#define LPSS_REGS_SIZE 0x100 +#define LPSS_REGS_NUM (LPSS_REGS_SIZE / sizeof(uint32_t)) + +struct lpss_softc { + device_t dev; + struct resource *res; + uint64_t base_freq; + uint64_t freq; + enum lpss_type type; + uint32_t regs[LPSS_REGS_NUM]; +}; + +uint64_t lpss_get_freq(struct lpss_softc *sc); +int lpss_attach_uart(struct lpss_softc *sc); +int lpss_resume(struct lpss_softc *sc); +int lpss_suspend(struct lpss_softc *sc); + +#endif /* _LPSS_H_ */ Index: sys/dev/intel/lpss.c =================================================================== --- /dev/null +++ sys/dev/intel/lpss.c @@ -0,0 +1,122 @@ +/*- + * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG + * + * 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. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static void +lpss_get_type(struct lpss_softc *sc) +{ + + sc->type = bus_read_4(sc->res, LPSS_CAPS); + sc->type = (sc->type >> LPSS_CAPS_TYPE_SHIFT) & LPSS_CAPS_TYPE_MASK; +} + +static void +lpss_remap(struct lpss_softc *sc) +{ + + bus_write_4(sc->res, LPSS_REMAP_ADDR, + rman_get_start(sc->res)); +} + +static void +lpss_reset(struct lpss_softc *sc) +{ + + bus_write_4(sc->res, LPSS_RESET, 0); + bus_write_4(sc->res, LPSS_RESET, + LPSS_RESET_FUNC | LPSS_RESET_IDMA); +} + +uint64_t +lpss_get_freq(struct lpss_softc *sc) +{ + uint64_t freq, m, n; + uint32_t reg; + + reg = bus_read_4(sc->res, LPSS_CLK); + + freq = sc->base_freq; + m = (reg >> LPSS_CLK_MSHIFT) & LPSS_CLK_MMASK; + n = (reg >> LPSS_CLK_NSHIFT) & LPSS_CLK_NMASK; + if (m != 0 && n != 0) { + freq *= m; + freq /= n; + } + + return (freq); +} + +int +lpss_attach_uart(struct lpss_softc *sc) +{ + + lpss_get_type(sc); + if (sc->type != LPSS_TYPE_UART) { + device_printf(sc->dev, "Not a UART\n"); + return (ENXIO); + } + + lpss_reset(sc); + lpss_remap(sc); + + return (0); +} + +int +lpss_resume(struct lpss_softc *sc) +{ + int i; + + for (i = 0; i < LPSS_REGS_NUM; i++) + bus_write_4(sc->res, LPSS_REGS_BASE + i * sizeof(uint32_t), + sc->regs[i]); + return (0); +} + +int +lpss_suspend(struct lpss_softc *sc) +{ + int i; + + for (i = 0; i < LPSS_REGS_NUM; i++) + sc->regs[i] = bus_read_4(sc->res, + LPSS_REGS_BASE + i * sizeof(uint32_t)); + return (0); +} Index: sys/dev/intel/lpssreg.h =================================================================== --- /dev/null +++ sys/dev/intel/lpssreg.h @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG + * + * 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. + * + */ + +#ifndef _LPSSREG_H_ +#define _LPSSREG_H_ + +#define LPSS_CLK 0x200 +#define LPSS_CLK_MSHIFT 1 +#define LPSS_CLK_MMASK 0x3FFF +#define LPSS_CLK_NSHIFT 16 +#define LPSS_CLK_NMASK 0x3FFF + +#define LPSS_RESET 0x204 +#define LPSS_RESET_FUNC (3 << 0) +#define LPSS_RESET_IDMA (1 << 2) + +#define LPSS_REMAP_ADDR 0x240 + +#define LPSS_CAPS 0x2FC +#define LPSS_CAPS_TYPE_SHIFT 4 +#define LPSS_CAPS_TYPE_MASK 0xF +#define LPSS_CAPS_NO_IDMA (1 << 8) + +#endif /* _LPSSREG_H_ */ + Index: sys/dev/uart/uart_bus_pci.c =================================================================== --- sys/dev/uart/uart_bus_pci.c +++ sys/dev/uart/uart_bus_pci.c @@ -149,24 +149,8 @@ { 0x8086, 0x2a07, 0xffff, 0, "Intel AMT - PM965/GM965 KT Controller", 0x10 }, { 0x8086, 0x2a47, 0xffff, 0, "Mobile 4 Series Chipset KT Controller", 0x10 }, { 0x8086, 0x2e17, 0xffff, 0, "4 Series Chipset Serial KT Controller", 0x10 }, -{ 0x8086, 0x31bc, 0xffff, 0, "Intel Gemini Lake SIO/LPSS UART 0", 0x10, - 24 * DEFAULT_RCLK, 2 }, -{ 0x8086, 0x31be, 0xffff, 0, "Intel Gemini Lake SIO/LPSS UART 1", 0x10, - 24 * DEFAULT_RCLK, 2 }, -{ 0x8086, 0x31c0, 0xffff, 0, "Intel Gemini Lake SIO/LPSS UART 2", 0x10, - 24 * DEFAULT_RCLK, 2 }, -{ 0x8086, 0x31ee, 0xffff, 0, "Intel Gemini Lake SIO/LPSS UART 3", 0x10, - 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x3b67, 0xffff, 0, "5 Series/3400 Series Chipset KT Controller", 0x10 }, -{ 0x8086, 0x5abc, 0xffff, 0, "Intel Apollo Lake SIO/LPSS UART 0", 0x10, - 24 * DEFAULT_RCLK, 2 }, -{ 0x8086, 0x5abe, 0xffff, 0, "Intel Apollo Lake SIO/LPSS UART 1", 0x10, - 24 * DEFAULT_RCLK, 2 }, -{ 0x8086, 0x5ac0, 0xffff, 0, "Intel Apollo Lake SIO/LPSS UART 2", 0x10, - 24 * DEFAULT_RCLK, 2 }, -{ 0x8086, 0x5aee, 0xffff, 0, "Intel Apollo Lake SIO/LPSS UART 3", 0x10, - 24 * DEFAULT_RCLK, 2 }, { 0x8086, 0x8811, 0xffff, 0, "Intel EG20T Serial Port 0", 0x10 }, { 0x8086, 0x8812, 0xffff, 0, "Intel EG20T Serial Port 1", 0x10 }, { 0x8086, 0x8813, 0xffff, 0, "Intel EG20T Serial Port 2", 0x10 }, Index: sys/dev/uart/uart_dev_lpss_pci.c =================================================================== --- /dev/null +++ sys/dev/uart/uart_dev_lpss_pci.c @@ -0,0 +1,203 @@ +/*- + * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG + * + * 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. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include "uart_if.h" + +struct uart_lpss_softc { + struct ns8250_softc ns8250; + struct lpss_softc lpss; +}; + +static kobj_method_t uart_lpss_ns8250_methods[] = { + KOBJMETHOD(uart_probe, ns8250_bus_probe), + KOBJMETHOD(uart_attach, ns8250_bus_attach), + KOBJMETHOD(uart_detach, ns8250_bus_detach), + KOBJMETHOD(uart_flush, ns8250_bus_flush), + KOBJMETHOD(uart_getsig, ns8250_bus_getsig), + KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl), + KOBJMETHOD(uart_ipend, ns8250_bus_ipend), + KOBJMETHOD(uart_param, ns8250_bus_param), + KOBJMETHOD(uart_receive, ns8250_bus_receive), + KOBJMETHOD(uart_setsig, ns8250_bus_setsig), + KOBJMETHOD(uart_transmit, ns8250_bus_transmit), + KOBJMETHOD(uart_grab, ns8250_bus_grab), + KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab), + KOBJMETHOD_END +}; + +struct uart_class uart_lpss_class = { + "lpss", + uart_lpss_ns8250_methods, + sizeof(struct lpss_softc), + .uc_ops = &uart_ns8250_ops, + .uc_range = 8, + .uc_rclk = 1843200, + .uc_rshift = 2, + .uc_riowidth = 4, +}; + +struct pci_id { + uint16_t vendor; + uint16_t device; + const char *desc; + uint64_t base_freq; +}; + +static const struct pci_id uart_lpss_ids[] = { + { 0x8086, 0x31bc, "Intel Gemini Lake SIO/LPSS UART 0", 100000000}, + { 0x8086, 0x31be, "Intel Gemini Lake SIO/LPSS UART 1", 100000000}, + { 0x8086, 0x31c0, "Intel Gemini Lake SIO/LPSS UART 2", 100000000}, + { 0x8086, 0x31ee, "Intel Gemini Lake SIO/LPSS UART 3", 100000000}, + { 0x8086, 0x5abc, "Intel Apollo Lake SIO/LPSS UART 0", 100000000}, + { 0x8086, 0x5abe, "Intel Apollo Lake SIO/LPSS UART 1", 100000000}, + { 0x8086, 0x5ac0, "Intel Apollo Lake SIO/LPSS UART 2", 100000000}, + { 0x8086, 0x5aee, "Intel Apollo Lake SIO/LPSS UART 3", 100000000}, + { 0xffff, 0, NULL} +}; + +static int +uart_lpss_probe(device_t dev) +{ + struct uart_lpss_softc *sc; + uint64_t freq; + uint16_t device, vendor; + int error, i, rid; + + sc = device_get_softc(dev); + vendor = pci_get_vendor(dev); + device = pci_get_device(dev); + for (i = 0; i < nitems(uart_lpss_ids) - 1; i++) { + if (vendor == uart_lpss_ids[i].vendor && + device == uart_lpss_ids[i].device) + break; + } + if (uart_lpss_ids[i].vendor == 0xffff) + return (ENXIO); + sc->ns8250.base.sc_class = &uart_lpss_class; + rid = 0x10; + sc->lpss.dev = dev; + sc->lpss.base_freq = uart_lpss_ids[i].base_freq; + sc->lpss.res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, + &rid, RF_ACTIVE); + freq = lpss_get_freq(&sc->lpss); + bus_release_resource(dev, SYS_RES_MEMORY, rid, sc->lpss.res); + error = uart_bus_probe(dev, 2, 4, (int)freq, rid, 0, 0); + if (error != 0) + return (error); + device_set_desc(dev, uart_lpss_ids[i].desc); + return (0); +} + +static int +uart_lpss_attach(device_t dev) +{ + struct uart_lpss_softc *sc; + int count, error; + + sc = device_get_softc(dev); + + if (pci_msi_count(dev) == 1) { + if (pci_alloc_msi(dev, &count) == 0) { + sc->ns8250.base.sc_irid = 1; + if (bootverbose) + device_printf(dev, "Using %d MSI message\n", count); + } + } + sc->lpss.dev = dev; + sc->lpss.res = sc->ns8250.base.sc_rres; + error = lpss_attach_uart(&sc->lpss); + if (error != 0) { + pci_release_msi(dev); + return (error); + } + return (uart_bus_attach(dev)); +} + +static int +uart_lpss_detach(device_t dev) +{ + + return (uart_bus_detach(dev)); +} + +static int +uart_lpss_resume(device_t dev) +{ + struct uart_lpss_softc *sc; + + sc = device_get_softc(dev); + lpss_resume(&sc->lpss); + return (uart_bus_resume(dev)); +} + +static int +uart_lpss_suspend(device_t dev) +{ + struct uart_lpss_softc *sc; + + sc = device_get_softc(dev); + lpss_suspend(&sc->lpss); + return (0); +} + +static device_method_t uart_lpss_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, uart_lpss_probe), + DEVMETHOD(device_attach, uart_lpss_attach), + DEVMETHOD(device_detach, uart_lpss_detach), + DEVMETHOD(device_resume, uart_lpss_resume), + DEVMETHOD(device_suspend, uart_lpss_suspend), + DEVMETHOD_END +}; + +static driver_t uart_lpss_driver = { + uart_driver_name, + uart_lpss_methods, + sizeof(struct uart_lpss_softc) +}; + +DRIVER_MODULE(uart_lpss, pci, uart_lpss_driver, uart_devclass, 0, 0);