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 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 */ 28 29 #include <sys/param.h> 30 #include <sys/bus.h> 31 #include <sys/kernel.h> 32 #include <sys/module.h> 33 #include <sys/mutex.h> 34 #include <sys/rman.h> 35 #include <machine/bus.h> 36 37 #include <dev/ofw/openfirm.h> 38 #include <dev/ofw/ofw_bus.h> 39 #include <dev/ofw/ofw_bus_subr.h> 40 41 #include <dev/fdt/simple_mfd.h> 42 43 #include <dev/clk/clk.h> 44 #include <dev/hwreset/hwreset.h> 45 #include <dev/regulator/regulator.h> 46 #include <dev/extres/syscon/syscon.h> 47 #include <dev/phy/phy.h> 48 49 #include <contrib/device-tree/include/dt-bindings/phy/phy.h> 50 51 #include "syscon_if.h" 52 #include "phydev_if.h" 53 #include "phynode_if.h" 54 55 #define GRF_PCIE30PHY_CON1 0x04 56 #define GRF_PCIE30PHY_CON4 0x10 57 #define GRF_PCIE30PHY_CON5 0x14 58 #define GRF_PCIE30PHY_CON6 0x18 59 #define GRF_BIFURCATION_LANE_1 0 60 #define GRF_BIFURCATION_LANE_2 1 61 #define GRF_PCIE30PHY_WR_EN (0xf << 16) 62 #define GRF_PCIE30PHY_CON9 0x24 63 #define GRF_PCIE30PHY_DA_OCM_MASK (1 << (15 + 16)) 64 #define GRF_PCIE30PHY_DA_OCM ((1 << 15) | GRF_PCIE30PHY_DA_OCM_MASK) 65 #define GRF_PCIE30PHY_STATUS0 0x80 66 #define SRAM_INIT_DONE (1 << 14) 67 68 static struct ofw_compat_data compat_data[] = { 69 {"rockchip,rk3568-pcie3-phy", 1}, 70 {NULL, 0} 71 }; 72 73 struct rk3568_pciephy_softc { 74 device_t dev; 75 phandle_t node; 76 struct resource *mem; 77 struct phynode *phynode; 78 struct syscon *phy_grf; 79 clk_t refclk_m; 80 clk_t refclk_n; 81 clk_t pclk; 82 hwreset_t phy_reset; 83 }; 84 85 86 static void 87 rk3568_pciephy_bifurcate(device_t dev, int control, uint32_t lane) 88 { 89 struct rk3568_pciephy_softc *sc = device_get_softc(dev); 90 91 switch (lane) { 92 case 0: 93 SYSCON_WRITE_4(sc->phy_grf, control, GRF_PCIE30PHY_WR_EN); 94 return; 95 case 1: 96 SYSCON_WRITE_4(sc->phy_grf, control, 97 GRF_PCIE30PHY_WR_EN | GRF_BIFURCATION_LANE_1); 98 break; 99 case 2: 100 SYSCON_WRITE_4(sc->phy_grf, control, 101 GRF_PCIE30PHY_WR_EN | GRF_BIFURCATION_LANE_2); 102 break; 103 default: 104 device_printf(dev, "Illegal lane %d\n", lane); 105 return; 106 } 107 if (bootverbose) 108 device_printf(dev, "lane %d @ pcie3x%d\n", lane, 109 (control == GRF_PCIE30PHY_CON5) ? 1 : 2); 110 } 111 112 /* PHY class and methods */ 113 static int 114 rk3568_pciephy_enable(struct phynode *phynode, bool enable) 115 { 116 device_t dev = phynode_get_device(phynode); 117 struct rk3568_pciephy_softc *sc = device_get_softc(dev); 118 int count; 119 120 if (enable) { 121 /* Pull PHY out of reset */ 122 hwreset_deassert(sc->phy_reset); 123 124 /* Poll for SRAM loaded and ready */ 125 for (count = 100; count; count--) { 126 if (SYSCON_READ_4(sc->phy_grf, GRF_PCIE30PHY_STATUS0) & 127 SRAM_INIT_DONE) 128 break; 129 DELAY(10000); 130 if (count == 0) { 131 device_printf(dev, "SRAM init timeout!\n"); 132 return (ENXIO); 133 } 134 } 135 } 136 return (0); 137 } 138 139 static phynode_method_t rk3568_pciephy_phynode_methods[] = { 140 PHYNODEMETHOD(phynode_enable, rk3568_pciephy_enable), 141 142 PHYNODEMETHOD_END 143 }; 144 DEFINE_CLASS_1(rk3568_pciephy_phynode, rk3568_pciephy_phynode_class, 145 rk3568_pciephy_phynode_methods, 0, phynode_class); 146 147 148 /* Device class and methods */ 149 static int 150 rk3568_pciephy_probe(device_t dev) 151 { 152 153 if (!ofw_bus_status_okay(dev)) 154 return (ENXIO); 155 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) 156 return (ENXIO); 157 device_set_desc(dev, "RockChip PCIe PHY"); 158 return (BUS_PROBE_DEFAULT); 159 } 160 161 static int 162 rk3568_pciephy_attach(device_t dev) 163 { 164 struct rk3568_pciephy_softc *sc = device_get_softc(dev); 165 struct phynode_init_def phy_init; 166 struct phynode *phynode; 167 uint32_t data_lanes[2] = { 0, 0 }; 168 int rid = 0; 169 170 sc->dev = dev; 171 sc->node = ofw_bus_get_node(dev); 172 173 /* Get memory resource */ 174 if (!(sc->mem = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 175 RF_ACTIVE))) { 176 device_printf(dev, "Cannot allocate memory resources\n"); 177 return (ENXIO); 178 } 179 180 /* Get syncons handle */ 181 if (OF_hasprop(sc->node, "rockchip,phy-grf") && 182 syscon_get_by_ofw_property(dev, sc->node, "rockchip,phy-grf", 183 &sc->phy_grf)) 184 return (ENXIO); 185 186 /* Get & enable clocks */ 187 if (clk_get_by_ofw_name(dev, 0, "refclk_m", &sc->refclk_m)) { 188 device_printf(dev, "getting refclk_m failed\n"); 189 return (ENXIO); 190 } 191 if (clk_enable(sc->refclk_m)) 192 device_printf(dev, "enable refclk_m failed\n"); 193 if (clk_get_by_ofw_name(dev, 0, "refclk_n", &sc->refclk_n)) { 194 device_printf(dev, "getting refclk_n failed\n"); 195 return (ENXIO); 196 } 197 if (clk_enable(sc->refclk_n)) 198 device_printf(dev, "enable refclk_n failed\n"); 199 if (clk_get_by_ofw_name(dev, 0, "pclk", &sc->pclk)) { 200 device_printf(dev, "getting pclk failed\n"); 201 return (ENXIO); 202 } 203 if (clk_enable(sc->pclk)) 204 device_printf(dev, "enable pclk failed\n"); 205 206 /* Get & assert reset */ 207 if (hwreset_get_by_ofw_idx(dev, sc->node, 0, &sc->phy_reset)) { 208 device_printf(dev, "Cannot get reset\n"); 209 } else 210 hwreset_assert(sc->phy_reset); 211 212 /* Set RC/EP mode not implemented yet (RC mode only) */ 213 214 /* Set bifurcation according to "data-lanes" entry */ 215 if (OF_hasprop(sc->node, "data-lanes")) { 216 OF_getencprop(sc->node, "data-lanes", data_lanes, 217 sizeof(data_lanes)); 218 } else 219 if (bootverbose) 220 device_printf(dev, "lane 1 & 2 @pcie3x2\n"); 221 222 /* Deassert PCIe PMA output clamp mode */ 223 SYSCON_WRITE_4(sc->phy_grf, GRF_PCIE30PHY_CON9, GRF_PCIE30PHY_DA_OCM); 224 225 /* Configure PHY HW accordingly */ 226 rk3568_pciephy_bifurcate(dev, GRF_PCIE30PHY_CON5, data_lanes[0]); 227 rk3568_pciephy_bifurcate(dev, GRF_PCIE30PHY_CON6, data_lanes[1]); 228 229 if (data_lanes[0] || data_lanes[1]) 230 SYSCON_WRITE_4(sc->phy_grf, GRF_PCIE30PHY_CON1, 231 GRF_PCIE30PHY_DA_OCM); 232 else 233 SYSCON_WRITE_4(sc->phy_grf, GRF_PCIE30PHY_CON1, 234 GRF_PCIE30PHY_DA_OCM_MASK); 235 236 bzero(&phy_init, sizeof(phy_init)); 237 phy_init.id = PHY_NONE; 238 phy_init.ofw_node = sc->node; 239 if (!(phynode = phynode_create(dev, &rk3568_pciephy_phynode_class, 240 &phy_init))) { 241 device_printf(dev, "failed to create pciephy PHY\n"); 242 return (ENXIO); 243 } 244 if (!phynode_register(phynode)) { 245 device_printf(dev, "failed to register pciephy PHY\n"); 246 return (ENXIO); 247 } 248 sc->phynode = phynode; 249 250 return (0); 251 } 252 253 static device_method_t rk3568_pciephy_methods[] = { 254 DEVMETHOD(device_probe, rk3568_pciephy_probe), 255 DEVMETHOD(device_attach, rk3568_pciephy_attach), 256 257 DEVMETHOD_END 258 }; 259 260 DEFINE_CLASS_1(rk3568_pciephy, rk3568_pciephy_driver, rk3568_pciephy_methods, 261 sizeof(struct simple_mfd_softc), simple_mfd_driver); 262 EARLY_DRIVER_MODULE(rk3568_pciephy, simplebus, rk3568_pciephy_driver, 263 0, 0, BUS_PASS_RESOURCE + BUS_PASS_ORDER_LATE); 264