The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/arm64/rockchip/rk3568_pcie.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause
    3  *
    4  * Copyright (c) 2021, 2022 Soren Schmidt <sos@deepcore.dk>
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   26  *
   27  */
   28 
   29 #include <sys/param.h>
   30 #include <sys/systm.h>
   31 #include <sys/endian.h>
   32 #include <sys/kernel.h>
   33 #include <sys/module.h>
   34 #include <sys/bus.h>
   35 #include <sys/proc.h>
   36 #include <sys/rman.h>
   37 #include <sys/intr.h>
   38 #include <sys/mutex.h>
   39 #include <sys/gpio.h>
   40 
   41 #include <dev/gpio/gpiobusvar.h>
   42 #include <dev/ofw/ofw_bus.h>
   43 #include <dev/ofw/ofw_bus_subr.h>
   44 #include <dev/ofw/ofw_pci.h>
   45 #include <dev/ofw/ofwpci.h>
   46 
   47 #include <dev/pci/pcivar.h>
   48 #include <dev/pci/pcireg.h>
   49 #include <dev/pci/pcib_private.h>
   50 #include <dev/pci/pci_dw.h>
   51 
   52 #include <dev/extres/clk/clk.h>
   53 #include <dev/extres/phy/phy.h>
   54 #include <dev/extres/regulator/regulator.h>
   55 #include <dev/extres/hwreset/hwreset.h>
   56 
   57 #include <machine/bus.h>
   58 #include <machine/intr.h>
   59 
   60 #include <vm/vm.h>
   61 #include <vm/vm_extern.h>
   62 #include <vm/vm_kern.h>
   63 #include <vm/pmap.h>
   64 
   65 #include "pcib_if.h"
   66 
   67 /* APB Registers */
   68 #define PCIE_CLIENT_GENERAL_CON         0x0000
   69 #define  DEVICE_TYPE_MASK               0x00f0
   70 #define  DEVICE_TYPE_RC                 (1<<6)
   71 #define  LINK_REQ_RST_GRT               (1<<3)
   72 #define  LTSSM_ENABLE                   (1<<2)
   73 #define PCIE_CLIENT_INTR_MASK_MSG_RX    0x0018
   74 #define PCIE_CLIENT_INTR_MASK_LEGACY    0x001c
   75 #define PCIE_CLIENT_INTR_MASK_ERR       0x0020
   76 #define PCIE_CLIENT_INTR_MASK_MISC      0x0024
   77 #define PCIE_CLIENT_INTR_MASK_PMC       0x0028
   78 #define PCIE_CLIENT_GENERAL_DEBUG_INFO  0x0104
   79 #define PCIE_CLIENT_HOT_RESET_CTRL      0x0180
   80 #define  APP_LSSTM_ENABLE_ENHANCE       (1<<4)
   81 #define PCIE_CLIENT_LTSSM_STATUS        0x0300
   82 #define  RDLH_LINK_UP                   (1<<17)
   83 #define  SMLH_LINK_UP                   (1<<16)
   84 #define  SMLH_LTSSM_STATE_MASK          0x003f
   85 #define  SMLH_LTSSM_STATE_LINK_UP       ((1<<4) | (1<<0))
   86 
   87 struct rk3568_pcie_softc {
   88         struct pci_dw_softc             dw_sc;  /* Must be first */
   89         device_t                        dev;
   90         int                             apb_rid;
   91         struct resource                 *apb_res;
   92         int                             dbi_rid;
   93         struct resource                 *dbi_res;
   94         int                             irq_rid;
   95         struct resource                 *irq_res;
   96         void                            *irq_handle;
   97         phandle_t                       node;
   98         struct gpiobus_pin              *reset_gpio;
   99         clk_t                           aclk_mst, aclk_slv, aclk_dbi, pclk, aux;
  100         regulator_t                     regulator;
  101         hwreset_t                       hwreset;
  102         phy_t                           phy;
  103 };
  104 
  105 static struct ofw_compat_data compat_data[] = {
  106         {"rockchip,rk3568-pcie",        1},
  107         {NULL,                          0}
  108 };
  109 
  110 
  111 static void
  112 rk3568_intr(void *data)
  113 {
  114         struct rk3568_pcie_softc *sc = data;
  115 
  116         device_printf(sc->dev, "INTERRUPT!!\n");
  117 }
  118 
  119 static int
  120 rk3568_pcie_get_link(device_t dev, bool *status)
  121 {
  122         struct rk3568_pcie_softc *sc = device_get_softc(dev);
  123         uint32_t val;
  124         
  125         val = bus_read_4(sc->apb_res, PCIE_CLIENT_LTSSM_STATUS);
  126         if (((val & (RDLH_LINK_UP | SMLH_LINK_UP)) ==
  127             (RDLH_LINK_UP | SMLH_LINK_UP)) &&
  128             ((val & SMLH_LTSSM_STATE_MASK) == SMLH_LTSSM_STATE_LINK_UP))
  129                 *status = true;
  130         else
  131                 *status = false;
  132         return (0);
  133 }
  134 
  135 static int
  136 rk3568_pcie_init_soc(device_t dev)
  137 {
  138         struct rk3568_pcie_softc *sc = device_get_softc(dev);
  139         int err, count;
  140         bool status;
  141 
  142         /* Assert reset */
  143         if (hwreset_assert(sc->hwreset))
  144                 device_printf(dev, "Could not assert reset\n");
  145 
  146         /* Powerup PCIe */
  147         if (regulator_enable(sc->regulator))
  148                 device_printf(dev, "Cannot enable regulator\n");
  149 
  150         /* Enable PHY */
  151         if (phy_enable(sc->phy))
  152                 device_printf(dev, "Cannot enable phy\n");
  153 
  154         /* Deassert reset */
  155         if (hwreset_deassert(sc->hwreset))
  156                 device_printf(dev, "Could not deassert reset\n");
  157 
  158         /* Enable clocks */
  159         if ((err = clk_enable(sc->aclk_mst))) {
  160                 device_printf(dev, "Could not enable aclk_mst clk\n");
  161                 return (ENXIO);
  162         }
  163         if ((err = clk_enable(sc->aclk_slv))) {
  164                 device_printf(dev, "Could not enable aclk_slv clk\n");
  165                 return (ENXIO);
  166         }
  167         if ((err = clk_enable(sc->aclk_dbi))) {
  168                 device_printf(dev, "Could not enable aclk_dbi clk\n");
  169                 return (ENXIO);
  170         }
  171         if ((err = clk_enable(sc->pclk))) {
  172                 device_printf(dev, "Could not enable pclk clk\n");
  173                 return (ENXIO);
  174         }
  175         if ((err = clk_enable(sc->aux))) {
  176                 device_printf(dev, "Could not enable aux clk\n");
  177                 return (ENXIO);
  178         }
  179 
  180         /* Set Root Complex (RC) mode */
  181         bus_write_4(sc->apb_res, PCIE_CLIENT_HOT_RESET_CTRL,
  182             (APP_LSSTM_ENABLE_ENHANCE << 16) | APP_LSSTM_ENABLE_ENHANCE);
  183         bus_write_4(sc->apb_res, PCIE_CLIENT_GENERAL_CON,
  184             (DEVICE_TYPE_MASK << 16) | DEVICE_TYPE_RC);
  185 
  186         /* Assert reset PCIe */
  187         if ((err = gpio_pin_set_active(sc->reset_gpio, false)))
  188                 device_printf(dev, "reset_gpio set failed\n");
  189 
  190         /* Start Link Training and Status State Machine (LTSSM) */
  191         bus_write_4(sc->apb_res, PCIE_CLIENT_GENERAL_CON,
  192             (LINK_REQ_RST_GRT | LTSSM_ENABLE) << 16 |
  193             (LINK_REQ_RST_GRT | LTSSM_ENABLE));
  194         DELAY(100000);
  195 
  196         /* Release reset */
  197         if ((err = gpio_pin_set_active(sc->reset_gpio, true)))
  198                 device_printf(dev, "reset_gpio release failed\n");
  199 
  200         /* Wait for link up/stable */
  201         for (count = 20; count; count--) {
  202                 rk3568_pcie_get_link(dev, &status);
  203                 if (status)
  204                         break;
  205                 DELAY(100000);
  206                 if (count == 0) {
  207                         device_printf(dev, "Link up timeout!\n");
  208                         return (ENXIO);
  209                 }
  210         }
  211 
  212         if ((err = pci_dw_init(dev)))
  213                 return (ENXIO);
  214 
  215         /* Delay to have things settle */
  216         DELAY(100000);
  217 
  218         /* Enable all MSG interrupts */
  219         bus_write_4(sc->apb_res, PCIE_CLIENT_INTR_MASK_MSG_RX, 0x7fff0000);
  220 
  221         /* Enable all Legacy interrupts */
  222         bus_write_4(sc->apb_res, PCIE_CLIENT_INTR_MASK_LEGACY, 0x00ff0000);
  223 
  224         /* Enable all Error interrupts */
  225         bus_write_4(sc->apb_res, PCIE_CLIENT_INTR_MASK_ERR, 0x0fff0000);
  226 
  227         return (0);
  228 }
  229 
  230 static int
  231 rk3568_pcie_detach(device_t dev)
  232 {
  233         struct rk3568_pcie_softc *sc = device_get_softc(dev);
  234 
  235         /* Release allocated resources */
  236         if (sc->irq_handle)
  237                 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
  238         if (sc->phy)
  239                 phy_release(sc->phy);
  240         if (sc->aux)
  241                 clk_release(sc->aux);
  242         if (sc->pclk)
  243                 clk_release(sc->pclk);
  244         if (sc->aclk_dbi)
  245                 clk_release(sc->aclk_dbi);
  246         if (sc->aclk_slv)
  247                 clk_release(sc->aclk_slv);
  248         if (sc->aclk_mst)
  249                 clk_release(sc->aclk_mst);
  250         if (sc->hwreset)
  251                 hwreset_release(sc->hwreset);
  252         if (sc->regulator)
  253                 regulator_release(sc->regulator);
  254         if (sc->irq_res)
  255                 bus_release_resource(dev, SYS_RES_IRQ, sc->irq_rid,
  256                     sc->irq_res);
  257         if (sc->dbi_res)
  258                 bus_release_resource(dev, SYS_RES_MEMORY, sc->dbi_rid,
  259                     sc->dbi_res);
  260         if (sc->apb_res)
  261                 bus_release_resource(dev, SYS_RES_MEMORY, sc->apb_rid,
  262                     sc->apb_res);
  263         return (0);
  264 }
  265 
  266 static int
  267 rk3568_pcie_attach(device_t dev)
  268 {
  269         struct rk3568_pcie_softc *sc = device_get_softc(dev);
  270         int error;
  271 
  272         sc->dev = dev;
  273         sc->node = ofw_bus_get_node(dev);
  274 
  275         /* Setup resources */
  276         if ((error = ofw_bus_find_string_index(sc->node, "reg-names", "apb",
  277             &sc->apb_rid))) {
  278                 device_printf(dev, "Cannot get APB memory: %d\n", error);
  279                 goto fail;
  280         }
  281         if (!(sc->apb_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  282             &sc->apb_rid, RF_ACTIVE))) {
  283                 device_printf(dev, "Cannot allocate APB resource\n");
  284                 goto fail;
  285         }
  286         if ((error = ofw_bus_find_string_index(sc->node, "reg-names", "dbi",
  287             &sc->dbi_rid))) {
  288                 device_printf(dev, "Cannot get DBI memory: %d\n", error);
  289                 goto fail;
  290         }
  291         if (!(sc->dw_sc.dbi_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  292             &sc->dbi_rid, RF_ACTIVE))) {
  293                 device_printf(dev, "Cannot allocate DBI resource\n");
  294                 goto fail;
  295         }
  296 
  297         if (!(sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ,
  298             &sc->irq_rid, RF_ACTIVE | RF_SHAREABLE))) {
  299                 device_printf(dev, "Cannot allocate IRQ resource\n");
  300                 goto fail;
  301         }
  302 
  303         /* Get regulator if present */
  304         if (regulator_get_by_ofw_property(dev, 0, "vpcie3v3-supply",
  305             &sc->regulator)) {
  306                 device_printf(dev, "Cannot get regulator\n");
  307                 goto fail;
  308         }
  309 
  310         /* Get reset */
  311         if (hwreset_get_by_ofw_name(dev, 0, "pipe", &sc->hwreset)) {
  312                 device_printf(dev, "Can not get reset\n");
  313                 goto fail;
  314         }
  315 
  316         /* Get GPIO reset */
  317         if (OF_hasprop(sc->node, "reset-gpios")) {
  318                 if (gpio_pin_get_by_ofw_property(dev, sc->node, "reset-gpios",
  319                     &sc->reset_gpio)) {
  320                         device_printf(dev, "Cannot get reset-gpios\n");
  321                         goto fail;
  322                 }
  323                 gpio_pin_setflags(sc->reset_gpio, GPIO_PIN_OUTPUT);
  324                 gpio_pin_set_active(sc->reset_gpio, true);
  325         }
  326 
  327         /* Get clocks */
  328         if (clk_get_by_ofw_name(dev, 0, "aclk_mst", &sc->aclk_mst)) {
  329                 device_printf(dev, "Can not get aclk_mst clk\n");
  330                 goto fail;
  331         }
  332         if (clk_get_by_ofw_name(dev, 0, "aclk_slv", &sc->aclk_slv)) {
  333                 device_printf(dev, "Can not get aclk_slv clk\n");
  334                 goto fail;
  335         }
  336         if (clk_get_by_ofw_name(dev, 0, "aclk_dbi", &sc->aclk_dbi)) {
  337                 device_printf(dev, "Can not get aclk_dbi clk\n");
  338                 goto fail;
  339         }
  340         if (clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk)) {
  341                 device_printf(dev, "Can not get pclk clk\n");
  342                 goto fail;
  343         }
  344         if (clk_get_by_ofw_name(dev, 0, "aux", &sc->aux)) {
  345                 device_printf(dev, "Can not get aux clk\n");
  346                 goto fail;
  347         }
  348 
  349         /* Get PHY */
  350         if (phy_get_by_ofw_name(dev, 0, "pcie-phy", &sc->phy)) {
  351                 device_printf(dev, "Cannot get 'pcie-phy'\n");
  352                 goto fail;
  353         }
  354 
  355         if ((error = rk3568_pcie_init_soc(dev)))
  356                 goto fail;
  357 
  358         /* Enable interrupt */
  359         if ((bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  360             NULL, rk3568_intr, sc, &sc->irq_handle))) {
  361                 device_printf(dev, "unable to setup interrupt\n");
  362                 goto fail;
  363         }
  364 
  365         return (bus_generic_attach(dev));
  366 fail:
  367         rk3568_pcie_detach(dev);
  368         return (ENXIO);
  369 }
  370 
  371 static int
  372 rk3568_pcie_probe(device_t dev)
  373 {
  374 
  375         if (!ofw_bus_status_okay(dev))
  376                 return (ENXIO);
  377         if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
  378                 return (ENXIO);
  379         device_set_desc(dev, "RockChip RK3568 PCI-express controller");
  380         return (BUS_PROBE_DEFAULT);
  381 }
  382 
  383 static device_method_t rk3568_pcie_methods[] = {
  384         /* Device interface */
  385         DEVMETHOD(device_probe,         rk3568_pcie_probe),
  386         DEVMETHOD(device_attach,        rk3568_pcie_attach),
  387         DEVMETHOD(device_detach,        rk3568_pcie_detach),
  388 
  389         /* PCI DW interface */
  390         DEVMETHOD(pci_dw_get_link,      rk3568_pcie_get_link),
  391 
  392         DEVMETHOD_END
  393 };
  394 
  395 DEFINE_CLASS_1(pcib, rk3568_pcie_driver, rk3568_pcie_methods,
  396     sizeof(struct rk3568_pcie_softc), pci_dw_driver);
  397 DRIVER_MODULE(mv_pcie, simplebus, rk3568_pcie_driver, NULL, NULL);

Cache object: c1e34ad9689a53ae70006e015650f61b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.