1 /* $OpenBSD: rkemmcphy.c,v 1.4 2021/10/24 17:52:26 mpi Exp $ */ 2 /* 3 * Copyright (c) 2019 Patrick Wildt <patrick@blueri.se> 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/fdt.h> 23 24 #include <dev/ofw/openfirm.h> 25 #include <dev/ofw/ofw_clock.h> 26 #include <dev/ofw/ofw_misc.h> 27 #include <dev/ofw/fdt.h> 28 29 /* Registers */ 30 #define GRF_EMMCPHY_CON0 0x00 31 #define GRF_EMMCPHY_CON0_OTAPDLYSEL_4 (0x4 << 7) 32 #define GRF_EMMCPHY_CON0_OTAPDLYENA_EN (1 << 11) 33 #define GRF_EMMCPHY_CON0_FREQSEL_200M (0x0 << 12) 34 #define GRF_EMMCPHY_CON0_FREQSEL_50M (0x1 << 12) 35 #define GRF_EMMCPHY_CON0_FREQSEL_100M (0x2 << 12) 36 #define GRF_EMMCPHY_CON0_FREQSEL_150M (0x3 << 12) 37 #define GRF_EMMCPHY_CON0_OTAPDLYSEL_CLR (0xf << 23) 38 #define GRF_EMMCPHY_CON0_OTAPDLYENA_CLR (1 << 27) 39 #define GRF_EMMCPHY_CON0_FREQSEL_CLR (0x3 << 28) 40 #define GRF_EMMCPHY_CON1 0x04 41 #define GRF_EMMCPHY_CON2 0x08 42 #define GRF_EMMCPHY_CON3 0x0c 43 #define GRF_EMMCPHY_CON4 0x10 44 #define GRF_EMMCPHY_CON5 0x14 45 #define GRF_EMMCPHY_CON6 0x18 46 #define GRF_EMMCPHY_CON6_PDB_OFF (0 << 0) 47 #define GRF_EMMCPHY_CON6_PDB_ON (1 << 0) 48 #define GRF_EMMCPHY_CON6_ENDLL_OFF (0 << 1) 49 #define GRF_EMMCPHY_CON6_ENDLL_ON (1 << 1) 50 #define GRF_EMMCPHY_CON6_DR_50OHM (0x0 << 4) 51 #define GRF_EMMCPHY_CON6_DR_33OHM (0x1 << 4) 52 #define GRF_EMMCPHY_CON6_DR_66OHM (0x2 << 4) 53 #define GRF_EMMCPHY_CON6_DR_100OHM (0x3 << 4) 54 #define GRF_EMMCPHY_CON6_DR_40OHM (0x4 << 4) 55 #define GRF_EMMCPHY_CON6_PDB_CLR (1 << 16) 56 #define GRF_EMMCPHY_CON6_ENDLL_CLR (1 << 17) 57 #define GRF_EMMCPHY_CON6_DR_CLR (0x7 << 20) 58 #define GRF_EMMCPHY_STATUS 0x20 59 #define GRF_EMMCPHY_STATUS_DLLRDY (1 << 5) 60 #define GRF_EMMCPHY_STATUS_CALDONE (1 << 6) 61 62 #define HREAD4(sc, reg) \ 63 (regmap_read_4((sc)->sc_rm, (sc)->sc_off + (reg))) 64 #define HWRITE4(sc, reg, val) \ 65 regmap_write_4((sc)->sc_rm, (sc)->sc_off + (reg), (val)) 66 67 struct rkemmcphy_softc { 68 struct device sc_dev; 69 struct regmap *sc_rm; 70 bus_size_t sc_off; 71 72 struct phy_device sc_pd; 73 }; 74 75 int rkemmcphy_match(struct device *, void *, void *); 76 void rkemmcphy_attach(struct device *, struct device *, void *); 77 78 const struct cfattach rkemmcphy_ca = { 79 sizeof (struct rkemmcphy_softc), rkemmcphy_match, rkemmcphy_attach 80 }; 81 82 struct cfdriver rkemmcphy_cd = { 83 NULL, "rkemmcphy", DV_DULL 84 }; 85 86 int rkemmcphy_enable(void *, uint32_t *); 87 88 int 89 rkemmcphy_match(struct device *parent, void *match, void *aux) 90 { 91 struct fdt_attach_args *faa = aux; 92 93 return OF_is_compatible(faa->fa_node, "rockchip,rk3399-emmc-phy"); 94 } 95 96 void 97 rkemmcphy_attach(struct device *parent, struct device *self, void *aux) 98 { 99 struct rkemmcphy_softc *sc = (struct rkemmcphy_softc *)self; 100 struct fdt_attach_args *faa = aux; 101 102 if (faa->fa_nreg < 1) { 103 printf(": no registers\n"); 104 return; 105 } 106 sc->sc_off = faa->fa_reg[0].addr; 107 108 sc->sc_rm = regmap_bynode(OF_parent(faa->fa_node)); 109 if (sc->sc_rm == NULL) { 110 printf(": can't map registers\n"); 111 return; 112 } 113 114 printf("\n"); 115 116 sc->sc_pd.pd_node = faa->fa_node; 117 sc->sc_pd.pd_cookie = sc; 118 sc->sc_pd.pd_enable = rkemmcphy_enable; 119 phy_register(&sc->sc_pd); 120 } 121 122 int 123 rkemmcphy_enable(void *cookie, uint32_t *cells) 124 { 125 struct rkemmcphy_softc *sc = cookie; 126 uint32_t impedance, freqsel, freq, reg; 127 int node = sc->sc_pd.pd_node; 128 int i; 129 130 impedance = OF_getpropint(node, "drive-impedance-ohm", 0); 131 freq = clock_get_frequency(node, "emmcclk"); 132 133 switch (impedance) { 134 case 100: 135 impedance = GRF_EMMCPHY_CON6_DR_100OHM; 136 break; 137 case 66: 138 impedance = GRF_EMMCPHY_CON6_DR_66OHM; 139 break; 140 case 50: 141 impedance = GRF_EMMCPHY_CON6_DR_50OHM; 142 break; 143 case 40: 144 impedance = GRF_EMMCPHY_CON6_DR_40OHM; 145 break; 146 case 33: 147 impedance = GRF_EMMCPHY_CON6_DR_33OHM; 148 break; 149 default: 150 impedance = GRF_EMMCPHY_CON6_DR_50OHM; 151 break; 152 } 153 154 if (freq == 0) { 155 freqsel = GRF_EMMCPHY_CON0_FREQSEL_200M; 156 } else if (freq < 75000000) { 157 freqsel = GRF_EMMCPHY_CON0_FREQSEL_50M; 158 } else if (freq < 125000000) { 159 freqsel = GRF_EMMCPHY_CON0_FREQSEL_100M; 160 } else if (freq < 175000000) { 161 freqsel = GRF_EMMCPHY_CON0_FREQSEL_150M; 162 } else { 163 freqsel = GRF_EMMCPHY_CON0_FREQSEL_200M; 164 } 165 166 HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_DR_CLR | impedance); 167 168 HWRITE4(sc, GRF_EMMCPHY_CON0, 169 GRF_EMMCPHY_CON0_OTAPDLYENA_CLR | GRF_EMMCPHY_CON0_OTAPDLYENA_EN); 170 HWRITE4(sc, GRF_EMMCPHY_CON0, 171 GRF_EMMCPHY_CON0_OTAPDLYSEL_CLR | GRF_EMMCPHY_CON0_OTAPDLYSEL_4); 172 173 HWRITE4(sc, GRF_EMMCPHY_CON6, 174 GRF_EMMCPHY_CON6_PDB_CLR | GRF_EMMCPHY_CON6_PDB_OFF | 175 GRF_EMMCPHY_CON6_ENDLL_CLR | GRF_EMMCPHY_CON6_ENDLL_OFF); 176 177 delay(3); 178 HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_PDB_CLR | 179 GRF_EMMCPHY_CON6_PDB_ON); 180 181 for (i = 5; i > 0; i--) { 182 reg = HREAD4(sc, GRF_EMMCPHY_STATUS); 183 if (reg & GRF_EMMCPHY_STATUS_CALDONE) 184 break; 185 delay(10); 186 } 187 if (i == 0) 188 printf("%s: timeout\n", sc->sc_dev.dv_xname); 189 190 HWRITE4(sc, GRF_EMMCPHY_CON0, GRF_EMMCPHY_CON0_FREQSEL_CLR | freqsel); 191 HWRITE4(sc, GRF_EMMCPHY_CON6, GRF_EMMCPHY_CON6_ENDLL_CLR | 192 GRF_EMMCPHY_CON6_ENDLL_ON); 193 194 if (freq != 0) { 195 for (i = 5; i > 0; i--) { 196 reg = HREAD4(sc, GRF_EMMCPHY_STATUS); 197 if (reg & GRF_EMMCPHY_STATUS_DLLRDY) 198 break; 199 delay(10 * 1000); 200 } 201 if (i == 0) 202 printf("%s: timeout\n", sc->sc_dev.dv_xname); 203 } 204 205 return 0; 206 } 207