Date: Sun, 20 Oct 2019 11:11:32 +0000 (UTC) From: Michal Meloun <mmel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r353774 - in head/sys: conf dev/pci Message-ID: <201910201111.x9KBBWXP049070@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: mmel Date: Sun Oct 20 11:11:32 2019 New Revision: 353774 URL: https://svnweb.freebsd.org/changeset/base/353774 Log: Add driver for DesignWare PCIE core, and its Armada 8K specific attachement. MFC after: 3 weeks Added: head/sys/dev/pci/pci_dw.c (contents, props changed) head/sys/dev/pci/pci_dw.h (contents, props changed) head/sys/dev/pci/pci_dw_if.m (contents, props changed) head/sys/dev/pci/pci_dw_mv.c (contents, props changed) Modified: head/sys/conf/files.arm64 Modified: head/sys/conf/files.arm64 ============================================================================== --- head/sys/conf/files.arm64 Sun Oct 20 10:48:27 2019 (r353773) +++ head/sys/conf/files.arm64 Sun Oct 20 11:11:32 2019 (r353774) @@ -246,6 +246,9 @@ dev/ofw/ofwpci.c optional fdt pci dev/pci/pci_host_generic.c optional pci dev/pci/pci_host_generic_acpi.c optional pci acpi dev/pci/pci_host_generic_fdt.c optional pci fdt +dev/pci/pci_dw_mv.c optional pci fdt +dev/pci/pci_dw.c optional pci fdt +dev/pci/pci_dw_if.m optional pci fdt dev/psci/psci.c standard dev/psci/smccc_arm64.S standard dev/psci/smccc.c standard Added: head/sys/dev/pci/pci_dw.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/pci/pci_dw.c Sun Oct 20 11:11:32 2019 (r353774) @@ -0,0 +1,697 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> + * + * 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. + * + */ + +/* Base class for all Synopsys DesignWare PCI/PCIe drivers */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/devmap.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/lock.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/rman.h> + +#include <machine/bus.h> +#include <machine/intr.h> +#include <machine/resource.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#include <dev/ofw/ofw_pci.h> +#include <dev/ofw/ofwpci.h> +#include <dev/pci/pcivar.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcib_private.h> +#include <dev/pci/pci_dw.h> + +#include "pcib_if.h" +#include "pci_dw_if.h" + +#define DEBUG +#ifdef DEBUG +#define debugf(fmt, args...) do { printf(fmt,##args); } while (0) +#else +#define debugf(fmt, args...) +#endif + +#define DBI_WR1(sc, reg, val) pci_dw_dbi_wr1((sc)->dev, reg, val) +#define DBI_WR2(sc, reg, val) pci_dw_dbi_wr2((sc)->dev, reg, val) +#define DBI_WR4(sc, reg, val) pci_dw_dbi_wr4((sc)->dev, reg, val) +#define DBI_RD1(sc, reg) pci_dw_dbi_rd1((sc)->dev, reg) +#define DBI_RD2(sc, reg) pci_dw_dbi_rd2((sc)->dev, reg) +#define DBI_RD4(sc, reg) pci_dw_dbi_rd4((sc)->dev, reg) + +#define PCI_BUS_SHIFT 20 +#define PCI_SLOT_SHIFT 15 +#define PCI_FUNC_SHIFT 12 +#define PCI_BUS_MASK 0xFF +#define PCI_SLOT_MASK 0x1F +#define PCI_FUNC_MASK 0x07 +#define PCI_REG_MASK 0xFFF + + +#define IATU_CFG_BUS(bus) ((uint64_t)((bus) & 0xff) << 24) +#define IATU_CFG_SLOT(slot) ((uint64_t)((slot) & 0x1f) << 19) +#define IATU_CFG_FUNC(func) ((uint64_t)((func) & 0x07) << 16) + + + +static uint32_t +pci_dw_dbi_read(device_t dev, u_int reg, int width) +{ + struct pci_dw_softc *sc; + + sc = device_get_softc(dev); + MPASS(sc->dbi_res != NULL); + + switch (width) { + case 4: + return (bus_read_4(sc->dbi_res, reg)); + case 2: + return (bus_read_2(sc->dbi_res, reg)); + case 1: + return (bus_read_1(sc->dbi_res, reg)); + default: + device_printf(sc->dev, "Unsupported width: %d\n", width); + return (0xFFFFFFFF); + } +} + +static void +pci_dw_dbi_write(device_t dev, u_int reg, uint32_t val, int width) +{ + struct pci_dw_softc *sc; + + sc = device_get_softc(dev); + MPASS(sc->dbi_res != NULL); + + switch (width) { + case 4: + bus_write_4(sc->dbi_res, reg, val); + break; + case 2: + bus_write_2(sc->dbi_res, reg, val); + break; + case 1: + bus_write_1(sc->dbi_res, reg, val); + break; + default: + device_printf(sc->dev, "Unsupported width: %d\n", width); + break; + } +} + + +static void +pci_dw_dbi_protect(struct pci_dw_softc *sc, bool protect) +{ + uint32_t reg; + + reg = DBI_RD4(sc, DW_MISC_CONTROL_1); + if (protect) + reg &= ~DBI_RO_WR_EN; + else + reg |= DBI_RO_WR_EN; + DBI_WR4(sc, DW_MISC_CONTROL_1, reg); +} + +static bool +pci_dw_check_dev(struct pci_dw_softc *sc, u_int bus, u_int slot, u_int func, + u_int reg) +{ + bool status; + int rv; + + if (bus < sc->bus_start || bus > sc->bus_end || slot > PCI_SLOTMAX || + func > PCI_FUNCMAX || reg > PCI_REGMAX) + return (false); + + /* link is needed for access to all non-root busses */ + if (bus != sc->root_bus) { + rv = PCI_DW_GET_LINK(sc->dev, &status); + if (rv != 0 || !status) + return (false); + return (true); + } + + /* we have only 1 device with 1 function root port */ + if (slot > 0 || func > 0) + return (false); + return (true); +} + +/* Map one uoutbound ATU region */ +static int +pci_dw_map_out_atu(struct pci_dw_softc *sc, int idx, int type, + uint64_t pa, uint64_t pci_addr, uint32_t size) +{ + uint32_t reg; + int i; + + if (size == 0) + return (0); + + DBI_WR4(sc, DW_IATU_VIEWPORT, IATU_REGION_INDEX(idx)); + DBI_WR4(sc, DW_IATU_LWR_BASE_ADDR, pa & 0xFFFFFFFF); + DBI_WR4(sc, DW_IATU_UPPER_BASE_ADDR, (pa >> 32) & 0xFFFFFFFF); + DBI_WR4(sc, DW_IATU_LIMIT_ADDR, (pa + size - 1) & 0xFFFFFFFF); + DBI_WR4(sc, DW_IATU_LWR_TARGET_ADDR, pci_addr & 0xFFFFFFFF); + DBI_WR4(sc, DW_IATU_UPPER_TARGET_ADDR, (pci_addr >> 32) & 0xFFFFFFFF); + DBI_WR4(sc, DW_IATU_CTRL1, IATU_CTRL1_TYPE(type)); + DBI_WR4(sc, DW_IATU_CTRL2, IATU_CTRL2_REGION_EN); + + /* Wait until setup becomes valid */ + for (i = 10; i > 0; i--) { + reg = DBI_RD4(sc, DW_IATU_CTRL2); + if (reg & IATU_CTRL2_REGION_EN) + return (0); + DELAY(5); + } + device_printf(sc->dev, + "Cannot map outbound region(%d) in iATU\n", idx); + return (ETIMEDOUT); +} + +static int +pci_dw_setup_hw(struct pci_dw_softc *sc) +{ + uint32_t reg; + int rv; + + pci_dw_dbi_protect(sc, false); + + /* Setup config registers */ + DBI_WR1(sc, PCIR_CLASS, PCIC_BRIDGE); + DBI_WR1(sc, PCIR_SUBCLASS, PCIS_BRIDGE_PCI); + DBI_WR4(sc, PCIR_BAR(0), 4); + DBI_WR4(sc, PCIR_BAR(1), 0); + DBI_WR1(sc, PCIR_INTPIN, 1); + DBI_WR1(sc, PCIR_PRIBUS_1, sc->root_bus); + DBI_WR1(sc, PCIR_SECBUS_1, sc->sub_bus); + DBI_WR1(sc, PCIR_SUBBUS_1, sc->bus_end); + DBI_WR2(sc, PCIR_COMMAND, + PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | + PCIM_CMD_BUSMASTEREN | PCIM_CMD_SERRESPEN); + pci_dw_dbi_protect(sc, true); + + /* Setup outbound memory window */ + rv = pci_dw_map_out_atu(sc, 0, IATU_CTRL1_TYPE_MEM, + sc->mem_range.host, sc->mem_range.pci, sc->mem_range.size); + if (rv != 0) + return (rv); + + /* If we have enouht viewports ..*/ + if (sc->num_viewport >= 3) { + /* Setup outbound I/O window */ + rv = pci_dw_map_out_atu(sc, 0, IATU_CTRL1_TYPE_MEM, + sc->io_range.host, sc->io_range.pci, sc->io_range.size); + if (rv != 0) + return (rv); + } + /* XXX Should we handle also prefetch memory? */ + + + /* Adjust number of lanes */ + reg = DBI_RD4(sc, DW_PORT_LINK_CTRL); + reg &= ~PORT_LINK_CAPABLE(~0); + switch (sc->num_lanes) { + case 1: + reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_1); + break; + case 2: + reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_2); + break; + case 4: + reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_4); + break; + case 8: + reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_8); + break; + case 16: + reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_16); + break; + case 32: + reg |= PORT_LINK_CAPABLE(PORT_LINK_CAPABLE_32); + break; + default: + device_printf(sc->dev, + "'num-lanes' property have invalid value: %d\n", + sc->num_lanes); + return (EINVAL); + } + DBI_WR4(sc, DW_PORT_LINK_CTRL, reg); + + + /* And link width */ + reg = DBI_RD4(sc, DW_GEN2_CTRL); + reg &= ~GEN2_CTRL_NUM_OF_LANES(~0); + switch (sc->num_lanes) { + case 1: + reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_1); + break; + case 2: + reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_2); + break; + case 4: + reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_4); + break; + case 8: + reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_8); + break; + case 16: + reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_16); + break; + case 32: + reg |= GEN2_CTRL_NUM_OF_LANES(GEN2_CTRL_NUM_OF_LANES_32); + break; + } + DBI_WR4(sc, DW_GEN2_CTRL, reg); + + reg = DBI_RD4(sc, DW_GEN2_CTRL); + reg |= DIRECT_SPEED_CHANGE; + DBI_WR4(sc, DW_GEN2_CTRL, reg); + + + return (0); +} + +static int +pci_dw_decode_ranges(struct pci_dw_softc *sc, struct ofw_pci_range *ranges, + int nranges) +{ + int i; + + for (i = 0; i < nranges; i++) { + if ((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == + OFW_PCI_PHYS_HI_SPACE_IO) { + if (sc->io_range.size != 0) { + device_printf(sc->dev, + "Duplicated IO range found in DT\n"); + return (ENXIO); + } + sc->io_range = ranges[i]; + } + if (((ranges[i].pci_hi & OFW_PCI_PHYS_HI_SPACEMASK) == + OFW_PCI_PHYS_HI_SPACE_MEM32)) { + if (ranges[i].pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) { + if (sc->pref_mem_range.size != 0) { + device_printf(sc->dev, + "Duplicated memory range found " + "in DT\n"); + return (ENXIO); + } + sc->pref_mem_range = ranges[i]; + } else { + if (sc->mem_range.size != 0) { + device_printf(sc->dev, + "Duplicated memory range found " + "in DT\n"); + return (ENXIO); + } + sc->mem_range = ranges[i]; + } + } + } + if ((sc->io_range.size == 0) || (sc->mem_range.size == 0)) { + device_printf(sc->dev, + " Not all required ranges are found in DT\n"); + return (ENXIO); + } + return (0); +} + + + +/*----------------------------------------------------------------------------- + * + * P C I B I N T E R F A C E + */ + +static uint32_t +pci_dw_read_config(device_t dev, u_int bus, u_int slot, + u_int func, u_int reg, int bytes) +{ + struct pci_dw_softc *sc; + struct resource *res; + uint32_t data; + uint64_t addr; + int type, rv; + + sc = device_get_softc(dev); + + if (!pci_dw_check_dev(sc, bus, slot, func, reg)) + return (0xFFFFFFFFU); + + if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || + (reg > PCI_REGMAX)) + return (0xFFFFFFFFU); + + if (bus == sc->root_bus) { + res = (sc->dbi_res); + } else { + addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | + IATU_CFG_FUNC(func); + if (bus == sc->sub_bus) + type = IATU_CTRL1_TYPE_CFG0; + else + type = IATU_CTRL1_TYPE_CFG1; + rv = pci_dw_map_out_atu(sc, 1, type, + sc->cfg_pa, addr, sc->cfg_size); + if (rv != 0) + return (0xFFFFFFFFU); + res = sc->cfg_res; + } + + switch (bytes) { + case 1: + data = bus_read_1(res, reg); + break; + case 2: + data = bus_read_2(res, reg); + break; + case 4: + data = bus_read_4(res, reg); + break; + default: + data = 0xFFFFFFFFU; + } + + return (data); + +} + +static void +pci_dw_write_config(device_t dev, u_int bus, u_int slot, + u_int func, u_int reg, uint32_t val, int bytes) +{ + struct pci_dw_softc *sc; + struct resource *res; + uint64_t addr; + int type, rv; + + sc = device_get_softc(dev); + if (!pci_dw_check_dev(sc, bus, slot, func, reg)) + return; + + if ((slot > PCI_SLOTMAX) || (func > PCI_FUNCMAX) || + (reg > PCI_REGMAX)) + return; + + if (bus == sc->root_bus) { + res = (sc->dbi_res); + } else { + addr = IATU_CFG_BUS(bus) | IATU_CFG_SLOT(slot) | + IATU_CFG_FUNC(func); + if (bus == sc->sub_bus) + type = IATU_CTRL1_TYPE_CFG0; + else + type = IATU_CTRL1_TYPE_CFG1; + rv = pci_dw_map_out_atu(sc, 1, type, + sc->cfg_pa, addr, sc->cfg_size); + if (rv != 0) + return ; + res = sc->cfg_res; + } + + + switch (bytes) { + case 1: + bus_write_1(res, reg, val); + break; + case 2: + bus_write_2(res, reg, val); + break; + case 4: + bus_write_4(res, reg, val); + break; + default: + break; + } +} + +static int +pci_dw_alloc_msi(device_t pci, device_t child, int count, + int maxcount, int *irqs) +{ + phandle_t msi_parent; + int rv; + + rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), + &msi_parent, NULL); + if (rv != 0) + return (rv); + + return (intr_alloc_msi(pci, child, msi_parent, count, maxcount, + irqs)); +} + +static int +pci_dw_release_msi(device_t pci, device_t child, int count, int *irqs) +{ + phandle_t msi_parent; + int rv; + + rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), + &msi_parent, NULL); + if (rv != 0) + return (rv); + return (intr_release_msi(pci, child, msi_parent, count, irqs)); +} + +static int +pci_dw_map_msi(device_t pci, device_t child, int irq, uint64_t *addr, + uint32_t *data) +{ + phandle_t msi_parent; + int rv; + + rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), + &msi_parent, NULL); + if (rv != 0) + return (rv); + + return (intr_map_msi(pci, child, msi_parent, irq, addr, data)); +} + +static int +pci_dw_alloc_msix(device_t pci, device_t child, int *irq) +{ + phandle_t msi_parent; + int rv; + + rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), + &msi_parent, NULL); + if (rv != 0) + return (rv); + return (intr_alloc_msix(pci, child, msi_parent, irq)); +} + +static int +pci_dw_release_msix(device_t pci, device_t child, int irq) +{ + phandle_t msi_parent; + int rv; + + rv = ofw_bus_msimap(ofw_bus_get_node(pci), pci_get_rid(child), + &msi_parent, NULL); + if (rv != 0) + return (rv); + return (intr_release_msix(pci, child, msi_parent, irq)); +} + +static int +pci_dw_get_id(device_t pci, device_t child, enum pci_id_type type, + uintptr_t *id) +{ + phandle_t node; + int rv; + uint32_t rid; + uint16_t pci_rid; + + if (type != PCI_ID_MSI) + return (pcib_get_id(pci, child, type, id)); + + node = ofw_bus_get_node(pci); + pci_rid = pci_get_rid(child); + + rv = ofw_bus_msimap(node, pci_rid, NULL, &rid); + if (rv != 0) + return (rv); + *id = rid; + + return (0); +} + +/*----------------------------------------------------------------------------- + * + * B U S / D E V I C E I N T E R F A C E + */ +static bus_dma_tag_t +pci_dw_get_dma_tag(device_t dev, device_t child) +{ + struct pci_dw_softc *sc; + + sc = device_get_softc(dev); + return (sc->dmat); +} + +int +pci_dw_init(device_t dev) +{ + struct pci_dw_softc *sc; + int rv, rid; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->node = ofw_bus_get_node(dev); + + mtx_init(&sc->mtx, "pci_dw_mtx", NULL, MTX_DEF); + + /* XXXn Should not be this configurable ? */ + sc->bus_start = 0; + sc->bus_end = 255; + sc->root_bus = 0; + sc->sub_bus = 1; + + /* Read FDT properties */ + if (!sc->coherent) + sc->coherent = OF_hasprop(sc->node, "dma-coherent"); + + rv = OF_getencprop(sc->node, "num-viewport", &sc->num_viewport, + sizeof(sc->num_viewport)); + if (rv != sizeof(sc->num_viewport)) + sc->num_viewport = 2; + + rv = OF_getencprop(sc->node, "num-lanes", &sc->num_lanes, + sizeof(sc->num_viewport)); + if (rv != sizeof(sc->num_lanes)) + sc->num_lanes = 1; + if (sc->num_lanes != 1 && sc->num_lanes != 2 && + sc->num_lanes != 4 && sc->num_lanes != 8) { + device_printf(dev, + "invalid number of lanes: %d\n",sc->num_lanes); + sc->num_lanes = 0; + rv = ENXIO; + goto out; + } + + rid = 0; + rv = ofw_bus_find_string_index(sc->node, "reg-names", "config", &rid); + if (rv != 0) { + device_printf(dev, "Cannot get config space memory\n"); + rv = ENXIO; + goto out; + } + sc->cfg_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->cfg_res == NULL) { + device_printf(dev, "Cannot allocate config space(rid: %d)\n", + rid); + rv = ENXIO; + goto out; + } + + /* Fill up config region related variables */ + sc->cfg_size = rman_get_size(sc->cfg_res); + sc->cfg_pa = rman_get_start(sc->cfg_res) ; + + if (bootverbose) + device_printf(dev, "Bus is%s cache-coherent\n", + sc->coherent ? "" : " not"); + rv = bus_dma_tag_create(bus_get_dma_tag(dev), /* parent */ + 1, 0, /* alignment, bounds */ + BUS_SPACE_MAXADDR, /* lowaddr */ + BUS_SPACE_MAXADDR, /* highaddr */ + NULL, NULL, /* filter, filterarg */ + BUS_SPACE_MAXSIZE, /* maxsize */ + BUS_SPACE_UNRESTRICTED, /* nsegments */ + BUS_SPACE_MAXSIZE, /* maxsegsize */ + sc->coherent ? BUS_DMA_COHERENT : 0, /* flags */ + NULL, NULL, /* lockfunc, lockarg */ + &sc->dmat); + if (rv != 0) + goto out; + + rv = ofw_pci_init(dev); + if (rv != 0) + goto out; + rv = pci_dw_decode_ranges(sc, sc->ofw_pci.sc_range, + sc->ofw_pci.sc_nrange); + if (rv != 0) + goto out; + + rv = pci_dw_setup_hw(sc); + if (rv != 0) + goto out; + + device_add_child(dev, "pci", -1); + + return (bus_generic_attach(dev)); +out: + /* XXX Cleanup */ + return (rv); +} + +static device_method_t pci_dw_methods[] = { + + /* Bus interface */ + DEVMETHOD(bus_get_dma_tag, pci_dw_get_dma_tag), + + /* pcib interface */ + DEVMETHOD(pcib_read_config, pci_dw_read_config), + DEVMETHOD(pcib_write_config, pci_dw_write_config), + DEVMETHOD(pcib_alloc_msi, pci_dw_alloc_msi), + DEVMETHOD(pcib_release_msi, pci_dw_release_msi), + DEVMETHOD(pcib_alloc_msix, pci_dw_alloc_msix), + DEVMETHOD(pcib_release_msix, pci_dw_release_msix), + DEVMETHOD(pcib_map_msi, pci_dw_map_msi), + DEVMETHOD(pcib_get_id, pci_dw_get_id), + + /* OFW bus interface */ + DEVMETHOD(ofw_bus_get_compat, ofw_bus_gen_get_compat), + DEVMETHOD(ofw_bus_get_model, ofw_bus_gen_get_model), + DEVMETHOD(ofw_bus_get_name, ofw_bus_gen_get_name), + DEVMETHOD(ofw_bus_get_node, ofw_bus_gen_get_node), + DEVMETHOD(ofw_bus_get_type, ofw_bus_gen_get_type), + + /* PCI DW interface */ + DEVMETHOD(pci_dw_dbi_read, pci_dw_dbi_read), + DEVMETHOD(pci_dw_dbi_write, pci_dw_dbi_write), + DEVMETHOD_END +}; + +DEFINE_CLASS_1(pcib, pci_dw_driver, pci_dw_methods, + sizeof(struct pci_dw_softc), ofw_pci_driver); Added: head/sys/dev/pci/pci_dw.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/pci/pci_dw.h Sun Oct 20 11:11:32 2019 (r353774) @@ -0,0 +1,158 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> + * + * 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. + * + * + * $FreeBSD$ + * + */ + +#ifndef _PCI_DW_H_ +#define _PCI_DW_H_ + +#include "pci_dw_if.h" + + +/* DesignWare CIe configuration registers */ +#define DW_PORT_LINK_CTRL 0x710 +#define PORT_LINK_CAPABLE(n) (((n) & 0x3F) << 16) +#define PORT_LINK_CAPABLE_1 0x01 +#define PORT_LINK_CAPABLE_2 0x03 +#define PORT_LINK_CAPABLE_4 0x07 +#define PORT_LINK_CAPABLE_8 0x0F +#define PORT_LINK_CAPABLE_16 0x1F +#define PORT_LINK_CAPABLE_32 0x3F + + +#define DW_GEN2_CTRL 0x80C +#define DIRECT_SPEED_CHANGE (1 << 17) +#define GEN2_CTRL_NUM_OF_LANES(n) (((n) & 0x3F) << 8) +#define GEN2_CTRL_NUM_OF_LANES_1 0x01 +#define GEN2_CTRL_NUM_OF_LANES_2 0x03 +#define GEN2_CTRL_NUM_OF_LANES_4 0x07 +#define GEN2_CTRL_NUM_OF_LANES_8 0x0F +#define GEN2_CTRL_NUM_OF_LANES_16 0x1F +#define GEN2_CTRL_NUM_OF_LANES_32 0x3F + +#define DW_MSI_ADDR_LO 0x820 +#define DW_MSI_ADDR_HI 0x824 +#define DW_MSI_INTR0_ENABLE 0x828 +#define DW_MSI_INTR0_MASK 0x82C +#define DW_MSI_INTR0_STATUS 0x830 + + +#define DW_MISC_CONTROL_1 0x8BC +#define DBI_RO_WR_EN (1 << 0) + +#define DW_IATU_VIEWPORT 0x900 +#define IATU_REGION_INBOUND (1U << 31) +#define IATU_REGION_INDEX(x) ((x) & 0x7) +#define DW_IATU_CTRL1 0x904 +#define IATU_CTRL1_TYPE(x) ((x) & 0x1F) +#define IATU_CTRL1_TYPE_MEM 0x0 +#define IATU_CTRL1_TYPE_IO 0x2 +#define IATU_CTRL1_TYPE_CFG0 0x4 +#define IATU_CTRL1_TYPE_CFG1 0x5 +#define DW_IATU_CTRL2 0x908 +#define IATU_CTRL2_REGION_EN (1U << 31) +#define DW_IATU_LWR_BASE_ADDR 0x90C +#define DW_IATU_UPPER_BASE_ADDR 0x910 +#define DW_IATU_LIMIT_ADDR 0x914 +#define DW_IATU_LWR_TARGET_ADDR 0x918 +#define DW_IATU_UPPER_TARGET_ADDR 0x91C + + +struct pci_dw_softc { + struct ofw_pci_softc ofw_pci; /* Must be first */ + + /* Filled by attachement stub */ + struct resource *dbi_res; + + /* pci_dw variables */ + device_t dev; + phandle_t node; + struct mtx mtx; + struct resource *cfg_res; + + struct ofw_pci_range mem_range; + struct ofw_pci_range pref_mem_range; + struct ofw_pci_range io_range; + + bool coherent; + bus_dma_tag_t dmat; + + int num_lanes; + int num_viewport; + bus_addr_t cfg_pa; /* PA of config memoty */ + bus_size_t cfg_size; /* size of config region */ + + u_int bus_start; + u_int bus_end; + u_int root_bus; + u_int sub_bus; +}; + +DECLARE_CLASS(pci_dw_driver); + + +static inline void +pci_dw_dbi_wr4(device_t dev, u_int reg, uint32_t val) +{ + PCI_DW_DBI_WRITE(dev, reg, val, 4); +} + +static inline void +pci_dw_dbi_wr2(device_t dev, u_int reg, uint16_t val) +{ + PCI_DW_DBI_WRITE(dev, reg, val, 2); +} + +static inline void +pci_dw_dbi_wr1(device_t dev, u_int reg, uint8_t val) +{ + PCI_DW_DBI_WRITE(dev, reg, val, 1); +} + +static inline uint32_t +pci_dw_dbi_rd4(device_t dev, u_int reg) +{ + return (PCI_DW_DBI_READ(dev, reg, 4)); +} + +static inline uint16_t +pci_dw_dbi_rd2(device_t dev, u_int reg) +{ + return ((uint16_t)PCI_DW_DBI_READ(dev, reg, 2)); +} + +static inline uint8_t +pci_dw_dbi_rd1(device_t dev, u_int reg) +{ + return ((uint8_t)PCI_DW_DBI_READ(dev, reg, 1)); +} + +int pci_dw_init(device_t); + +#endif /* __PCI_HOST_GENERIC_H_ */ Added: head/sys/dev/pci/pci_dw_if.m ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/pci/pci_dw_if.m Sun Oct 20 11:11:32 2019 (r353774) @@ -0,0 +1,73 @@ +#- +# Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> +# All rights reserved. +# +# 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. +# +# $FreeBSD$ +# + +#include <machine/bus.h> + +INTERFACE pci_dw; + + +/** + * Read from dbi space. + * The reg argument is a byte offset into dbi space. + * The width argument (which should be 1, 2 or 4) specifies how + * many bytes to read from that offset. + */ +METHOD uint32_t dbi_read{ + device_t dev; + u_int reg; + int width; +}; + +/** + * Write to dbi space. + * The reg argument is a byte offset into dbi space. + * The width argument (which should be 1, 2 or 4) specifies how + * many bytes to write to that offset. + */ +METHOD void dbi_write{ + device_t dev; + u_int reg; + uint32_t value; + int width; +}; + +/** + * Start or stop link + */ +METHOD int set_link{ + device_t dev; + bool start; +}; + +/** + * Query link status (up/down) + */ +METHOD int get_link{ + device_t dev; + bool *status; +}; Added: head/sys/dev/pci/pci_dw_mv.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/pci/pci_dw_mv.c Sun Oct 20 11:11:32 2019 (r353774) @@ -0,0 +1,328 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Michal Meloun <mmel@FreeBSD.org> + * + * 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. + * + */ + +/* Armada 8k DesignWare PCIe driver */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/devmap.h> +#include <sys/proc.h> +#include <sys/kernel.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <sys/mutex.h> +#include <sys/rman.h> +#include <sys/sysctl.h> + +#include <machine/bus.h> +#include <machine/intr.h> *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201910201111.x9KBBWXP049070>