1 /* $OpenBSD: rkpciephy.c,v 1.1 2023/03/19 11:17:16 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2023 Mark Kettenis <kettenis@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 22 #include <machine/intr.h> 23 #include <machine/bus.h> 24 #include <machine/fdt.h> 25 26 #include <dev/ofw/openfirm.h> 27 #include <dev/ofw/ofw_clock.h> 28 #include <dev/ofw/ofw_misc.h> 29 #include <dev/ofw/fdt.h> 30 31 /* GRF registers */ 32 #define GRF_PCIE30PHY_CON(idx) ((idx) * 4) 33 /* CON1 */ 34 #define GRF_PCIE30PHY_DA_OCM 0x80008000 35 /* CON5 */ 36 #define GRF_PCIE30PHY_LANE0_LINK_NUM_MASK (0xf << 16) 37 #define GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT 0 38 /* CON6 */ 39 #define GRF_PCIE30PHY_LANE1_LINK_NUM_MASK (0xf << 16) 40 #define GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT 0 41 /* STATUS0 */ 42 #define GRF_PCIE30PHY_STATUS0 0x80 43 #define GRF_PCIE30PHY_SRAM_INIT_DONE (1 << 14) 44 45 struct rkpciephy_softc { 46 struct device sc_dev; 47 bus_space_tag_t sc_iot; 48 bus_space_handle_t sc_ioh; 49 50 struct phy_device sc_pd; 51 }; 52 53 int rkpciephy_match(struct device *, void *, void *); 54 void rkpciephy_attach(struct device *, struct device *, void *); 55 56 const struct cfattach rkpciephy_ca = { 57 sizeof (struct rkpciephy_softc), rkpciephy_match, rkpciephy_attach 58 }; 59 60 struct cfdriver rkpciephy_cd = { 61 NULL, "rkpciephy", DV_DULL 62 }; 63 64 int rkpciephy_enable(void *, uint32_t *); 65 66 int 67 rkpciephy_match(struct device *parent, void *match, void *aux) 68 { 69 struct fdt_attach_args *faa = aux; 70 71 return OF_is_compatible(faa->fa_node, "rockchip,rk3568-pcie3-phy"); 72 } 73 74 void 75 rkpciephy_attach(struct device *parent, struct device *self, void *aux) 76 { 77 struct rkpciephy_softc *sc = (struct rkpciephy_softc *)self; 78 struct fdt_attach_args *faa = aux; 79 80 printf("\n"); 81 82 sc->sc_pd.pd_node = faa->fa_node; 83 sc->sc_pd.pd_cookie = sc; 84 sc->sc_pd.pd_enable = rkpciephy_enable; 85 phy_register(&sc->sc_pd); 86 } 87 88 int 89 rkpciephy_enable(void *cookie, uint32_t *cells) 90 { 91 struct rkpciephy_softc *sc = cookie; 92 struct regmap *rm; 93 int node = sc->sc_pd.pd_node; 94 uint32_t data_lanes[2] = { 0, 0 }; 95 uint32_t grf, stat; 96 int timo; 97 98 grf = OF_getpropint(node, "rockchip,phy-grf", 0); 99 rm = regmap_byphandle(grf); 100 if (rm == NULL) 101 return ENXIO; 102 103 clock_enable_all(node); 104 reset_assert(node, "phy"); 105 delay(1); 106 107 regmap_write_4(rm, GRF_PCIE30PHY_CON(9), GRF_PCIE30PHY_DA_OCM); 108 109 OF_getpropintarray(node, "data-lanes", data_lanes, sizeof(data_lanes)); 110 if (data_lanes[0] > 0) { 111 regmap_write_4(rm, GRF_PCIE30PHY_CON(5), 112 GRF_PCIE30PHY_LANE0_LINK_NUM_MASK | 113 (data_lanes[0] - 1) << GRF_PCIE30PHY_LANE0_LINK_NUM_SHIFT); 114 } 115 if (data_lanes[1] > 0) { 116 regmap_write_4(rm, GRF_PCIE30PHY_CON(6), 117 GRF_PCIE30PHY_LANE1_LINK_NUM_MASK | 118 (data_lanes[1] - 1) << GRF_PCIE30PHY_LANE1_LINK_NUM_SHIFT); 119 } 120 if (data_lanes[0] > 1 || data_lanes[1] > 1) 121 regmap_write_4(rm, GRF_PCIE30PHY_CON(1), GRF_PCIE30PHY_DA_OCM); 122 123 reset_deassert(node, "phy"); 124 125 for (timo = 500; timo > 0; timo--) { 126 stat = regmap_read_4(rm, GRF_PCIE30PHY_STATUS0); 127 if (stat & GRF_PCIE30PHY_SRAM_INIT_DONE) 128 break; 129 delay(100); 130 } 131 if (timo == 0) { 132 printf("%s: timeout\n", sc->sc_dev.dv_xname); 133 return ETIMEDOUT; 134 } 135 136 return 0; 137 } 138