1 /* $OpenBSD: hiclock.c,v 1.3 2021/10/24 17:52:26 mpi Exp $ */ 2 /* 3 * Copyright (c) 2018, 2019 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 #define HREAD4(sc, reg) \ 32 (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) 33 #define HWRITE4(sc, reg, val) \ 34 bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) 35 36 /* 37 * This driver includes support for the preliminary device tree 38 * bindings used by the default UEFI firmware for the HiKey970 board. 39 * Support for these preliminary bindings will be dropped at some 40 * point in the future. 41 */ 42 43 struct hiclock_softc { 44 struct device sc_dev; 45 bus_space_tag_t sc_iot; 46 bus_space_handle_t sc_ioh; 47 bus_space_handle_t sc_ioh_set; 48 49 struct clock_device sc_cd; 50 }; 51 52 int hiclock_match(struct device *, void *, void *); 53 void hiclock_attach(struct device *, struct device *, void *); 54 55 const struct cfattach hiclock_ca = { 56 sizeof (struct hiclock_softc), hiclock_match, hiclock_attach 57 }; 58 59 struct cfdriver hiclock_cd = { 60 NULL, "hiclock", DV_DULL 61 }; 62 63 struct hiclock_compat { 64 const char *compat; 65 uint32_t (*get_frequency)(void *, uint32_t *); 66 int (*set_frequency)(void *, uint32_t *, uint32_t); 67 void (*enable)(void *, uint32_t *, int); 68 }; 69 70 uint32_t hiclock_get_frequency(void *, uint32_t *); 71 void hiclock_enable(void *, uint32_t *, int); 72 73 uint32_t hi3670_crgctrl_get_frequency(void *, uint32_t *); 74 void hi3670_crgctrl_enable(void *, uint32_t *, int); 75 uint32_t hi3670_stub_get_frequency(void *, uint32_t *); 76 int hi3670_stub_set_frequency(void *, uint32_t *, uint32_t); 77 78 struct hiclock_compat hiclock_compat[] = { 79 /* Official Linux device tree bindings. */ 80 { 81 .compat = "hisilicon,hi3670-crgctrl", 82 .get_frequency = hi3670_crgctrl_get_frequency, 83 .enable = hi3670_crgctrl_enable, 84 }, 85 { .compat = "hisilicon,hi3670-pctrl" }, 86 { .compat = "hisilicon,hi3670-pmuctrl" }, 87 { .compat = "hisilicon,hi3670-pmctrl" }, 88 { .compat = "hisilicon,hi3670-sctrl" }, 89 { .compat = "hisilicon,hi3670-iomcu" }, 90 { .compat = "hisilicon,hi3670-media1-crg" }, 91 { .compat = "hisilicon,hi3670-media2-crg" }, 92 93 /* Preliminary device tree bindings for HiKey970. */ 94 { 95 .compat = "hisilicon,kirin970-crgctrl", 96 .get_frequency = hi3670_crgctrl_get_frequency, 97 .enable = hi3670_crgctrl_enable, 98 }, 99 { .compat = "hisilicon,kirin970-pctrl" }, 100 { .compat = "hisilicon,kirin970-pmuctrl" }, 101 { .compat = "hisilicon,kirin970-pmctrl" }, 102 { .compat = "hisilicon,kirin970-sctrl" }, 103 { .compat = "hisilicon,kirin970-iomcu" }, 104 { 105 .compat = "hisilicon,kirin970-stub-clk", 106 .get_frequency = hi3670_stub_get_frequency, 107 .set_frequency = hi3670_stub_set_frequency, 108 }, 109 { .compat = "hisilicon,media1-crg" }, 110 { .compat = "hisilicon,media2-crg" }, 111 }; 112 113 int 114 hiclock_match(struct device *parent, void *match, void *aux) 115 { 116 struct fdt_attach_args *faa = aux; 117 int i; 118 119 for (i = 0; i < nitems(hiclock_compat); i++) { 120 if (OF_is_compatible(faa->fa_node, hiclock_compat[i].compat)) 121 return 10; /* Must beat syscon(4). */ 122 } 123 124 return 0; 125 } 126 127 void 128 hiclock_attach(struct device *parent, struct device *self, void *aux) 129 { 130 struct hiclock_softc *sc = (struct hiclock_softc *)self; 131 struct fdt_attach_args *faa = aux; 132 int i; 133 134 if (faa->fa_nreg < 1) { 135 printf(": no registers\n"); 136 return; 137 } 138 139 sc->sc_iot = faa->fa_iot; 140 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 141 faa->fa_reg[0].size, 0, &sc->sc_ioh)) { 142 printf(": can't map registers\n"); 143 return; 144 } 145 146 if (faa->fa_nreg > 1) { 147 if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, 148 faa->fa_reg[1].size, 0, &sc->sc_ioh_set)) { 149 printf(": can't map registers\n"); 150 bus_space_unmap(sc->sc_iot, sc->sc_ioh, 151 faa->fa_reg[0].size); 152 return; 153 } 154 } 155 156 if (OF_is_compatible(faa->fa_node, "syscon")) { 157 regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh, 158 faa->fa_reg[0].size); 159 } 160 161 printf("\n"); 162 163 sc->sc_cd.cd_node = faa->fa_node; 164 sc->sc_cd.cd_cookie = sc; 165 for (i = 0; i < nitems(hiclock_compat); i++) { 166 if (OF_is_compatible(faa->fa_node, hiclock_compat[i].compat)) { 167 sc->sc_cd.cd_get_frequency = 168 hiclock_compat[i].get_frequency; 169 sc->sc_cd.cd_set_frequency = 170 hiclock_compat[i].set_frequency; 171 sc->sc_cd.cd_enable = hiclock_compat[i].enable; 172 break; 173 } 174 } 175 if (sc->sc_cd.cd_get_frequency == NULL) 176 sc->sc_cd.cd_get_frequency = hiclock_get_frequency; 177 if (sc->sc_cd.cd_enable == NULL) 178 sc->sc_cd.cd_enable = hiclock_enable; 179 clock_register(&sc->sc_cd); 180 } 181 182 /* Generic */ 183 184 uint32_t 185 hiclock_get_frequency(void *cookie, uint32_t *cells) 186 { 187 uint32_t idx = cells[0]; 188 189 printf("%s: 0x%08x\n", __func__, idx); 190 return 0; 191 } 192 193 void 194 hiclock_enable(void *cookie, uint32_t *cells, int on) 195 { 196 uint32_t idx = cells[0]; 197 198 printf("%s: 0x%08x\n", __func__, idx); 199 } 200 201 /* Hi3670 */ 202 203 #define HI3670_CLKIN_SYS 0 204 #define HI3670_CLK_PPLL0 3 205 #define HI3670_CLK_PPLL2 5 206 #define HI3670_CLK_PPLL3 6 207 208 #define HI3670_CLK_SD_SYS 22 209 #define HI3670_CLK_SDIO_SYS 23 210 #define HI3670_CLK_GATE_ABB_USB 29 211 #define HI3670_CLK_MUX_SD_SYS 68 212 #define HI3670_CLK_MUX_SD_PLL 69 213 #define HI3670_CLK_MUX_SDIO_SYS 70 214 #define HI3670_CLK_MUX_SDIO_PLL 71 215 #define HI3670_CLK_DIV_SD 93 216 #define HI3670_CLK_DIV_SDIO 94 217 #define HI3670_HCLK_GATE_USB3OTG 147 218 #define HI3670_HCLK_GATE_USB3DVFS 148 219 #define HI3670_HCLK_GATE_SDIO 149 220 #define HI3670_CLK_GATE_SD 159 221 #define HI3670_HCLK_GATE_SD 160 222 #define HI3670_CLK_GATE_SDIO 161 223 #define HI3670_CLK_GATE_USB3OTG_REF 189 224 225 uint32_t 226 hi3670_crgctrl_get_frequency(void *cookie, uint32_t *cells) 227 { 228 struct hiclock_softc *sc = cookie; 229 uint32_t idx = cells[0]; 230 uint32_t reg, freq, div; 231 int mux; 232 233 switch (idx) { 234 case HI3670_CLKIN_SYS: 235 return 19200000; 236 case HI3670_CLK_PPLL0: 237 return 1660000000; 238 case HI3670_CLK_PPLL2: 239 return 1920000000; 240 case HI3670_CLK_PPLL3: 241 return 1200000000; 242 case HI3670_CLK_SD_SYS: 243 case HI3670_CLK_SDIO_SYS: 244 idx = HI3670_CLKIN_SYS; 245 freq = hi3670_crgctrl_get_frequency(cookie, &idx); 246 return freq / 6; 247 case HI3670_CLK_MUX_SD_SYS: 248 reg = HREAD4(sc, 0x0b8); 249 mux = (reg >> 6) & 0x1; 250 idx = mux ? HI3670_CLK_DIV_SD : HI3670_CLK_SD_SYS; 251 return hi3670_crgctrl_get_frequency(cookie, &idx); 252 case HI3670_CLK_MUX_SD_PLL: 253 reg = HREAD4(sc, 0x0b8); 254 mux = (reg >> 4) & 0x3; 255 switch (mux) { 256 case 0: 257 idx = HI3670_CLK_PPLL0; 258 break; 259 case 1: 260 idx = HI3670_CLK_PPLL3; 261 break; 262 case 2: 263 case 3: 264 idx = HI3670_CLK_PPLL2; 265 break; 266 } 267 return hi3670_crgctrl_get_frequency(cookie, &idx); 268 case HI3670_CLK_DIV_SD: 269 reg = HREAD4(sc, 0x0b8); 270 div = (reg >> 0) & 0xf; 271 idx = HI3670_CLK_MUX_SD_PLL; 272 freq = hi3670_crgctrl_get_frequency(cookie, &idx); 273 return freq / (div + 1); 274 case HI3670_CLK_GATE_SD: 275 idx = HI3670_CLK_MUX_SD_SYS; 276 return hi3670_crgctrl_get_frequency(cookie, &idx); 277 case HI3670_CLK_GATE_SDIO: 278 idx = HI3670_CLK_MUX_SDIO_SYS; 279 return hi3670_crgctrl_get_frequency(cookie, &idx); 280 } 281 282 printf("%s: 0x%08x\n", __func__, idx); 283 return 0; 284 } 285 286 void 287 hi3670_crgctrl_enable(void *cookie, uint32_t *cells, int on) 288 { 289 uint32_t idx = cells[0]; 290 291 switch (idx) { 292 case HI3670_CLK_GATE_ABB_USB: 293 case HI3670_HCLK_GATE_USB3OTG: 294 case HI3670_HCLK_GATE_USB3DVFS: 295 case HI3670_CLK_GATE_SD: 296 case HI3670_HCLK_GATE_SD: 297 case HI3670_CLK_GATE_USB3OTG_REF: 298 /* Enabled by default. */ 299 return; 300 } 301 302 printf("%s: 0x%08x\n", __func__, idx); 303 } 304 305 #define HI3670_CLK_STUB_CLUSTER0 0 306 #define HI3670_CLK_STUB_CLUSTER1 1 307 308 uint32_t 309 hi3670_stub_get_frequency(void *cookie, uint32_t *cells) 310 { 311 struct hiclock_softc *sc = cookie; 312 uint32_t idx = cells[0]; 313 uint32_t reg; 314 315 switch (idx) { 316 case HI3670_CLK_STUB_CLUSTER0: 317 reg = HREAD4(sc, 0x070); 318 return reg * 1000000; 319 case HI3670_CLK_STUB_CLUSTER1: 320 reg = HREAD4(sc, 0x074); 321 return reg * 1000000; 322 default: 323 break; 324 } 325 326 printf("%s: 0x%08x\n", __func__, idx); 327 return 0; 328 } 329 330 int 331 hi3670_stub_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) 332 { 333 struct hiclock_softc *sc = cookie; 334 uint32_t idx = cells[0]; 335 uint32_t reg; 336 337 switch (idx) { 338 case HI3670_CLK_STUB_CLUSTER0: 339 reg = freq / 16000000; 340 reg |= (0xff << 16); 341 bus_space_write_4(sc->sc_iot, sc->sc_ioh_set, 0x280, reg); 342 return 0; 343 case HI3670_CLK_STUB_CLUSTER1: 344 reg = freq / 16000000; 345 reg |= (0xff << 16); 346 bus_space_write_4(sc->sc_iot, sc->sc_ioh_set, 0x270, reg); 347 return 0; 348 default: 349 break; 350 } 351 352 printf("%s: 0x%08x\n", __func__, idx); 353 return -1; 354 } 355