diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-04-22 12:43:14 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-04-22 12:43:14 +0000 |
commit | 0353a6ec4a879cf256fc75780a908bb2154bcd34 (patch) | |
tree | bf10c3884b02ac2f4351fe710232186f88292794 /sys/dev | |
parent | b942b726738bdd482aec441fce67524db50608a4 (diff) |
Add support for official Linux device tree bindings and implement support
for the "stub" clocks that handle the CPU clock frequency on the Hi3670.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/fdt/hiclock.c | 275 |
1 files changed, 195 insertions, 80 deletions
diff --git a/sys/dev/fdt/hiclock.c b/sys/dev/fdt/hiclock.c index b6a60cb4132..caa4e16c9db 100644 --- a/sys/dev/fdt/hiclock.c +++ b/sys/dev/fdt/hiclock.c @@ -1,6 +1,6 @@ -/* $OpenBSD: hiclock.c,v 1.1 2018/08/27 20:05:06 kettenis Exp $ */ +/* $OpenBSD: hiclock.c,v 1.2 2019/04/22 12:43:13 kettenis Exp $ */ /* - * Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org> + * Copyright (c) 2018, 2019 Mark Kettenis <kettenis@openbsd.org> * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -34,16 +34,17 @@ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) /* - * This driver is based on preliminary device tree bindings and will - * almost certainly need changes once the official bindings land in - * mainline Linux. Support for these preliminary bindings will be - * dropped as soon as official bindings are available. + * This driver includes support for the preliminary device tree + * bindings used by the default UEFI firmware for the HiKey970 board. + * Support for these preliminary bindings will be dropped at some + * point in the future. */ struct hiclock_softc { struct device sc_dev; bus_space_tag_t sc_iot; bus_space_handle_t sc_ioh; + bus_space_handle_t sc_ioh_set; struct clock_device sc_cd; }; @@ -59,25 +60,66 @@ struct cfdriver hiclock_cd = { NULL, "hiclock", DV_DULL }; -uint32_t kirin970_crgctrl_get_frequency(void *, uint32_t *); -void kirin970_crgctrl_enable(void *, uint32_t *, int); +struct hiclock_compat { + const char *compat; + uint32_t (*get_frequency)(void *, uint32_t *); + int (*set_frequency)(void *, uint32_t *, uint32_t); + void (*enable)(void *, uint32_t *, int); +}; + uint32_t hiclock_get_frequency(void *, uint32_t *); void hiclock_enable(void *, uint32_t *, int); +uint32_t hi3670_crgctrl_get_frequency(void *, uint32_t *); +void hi3670_crgctrl_enable(void *, uint32_t *, int); +uint32_t hi3670_stub_get_frequency(void *, uint32_t *); +int hi3670_stub_set_frequency(void *, uint32_t *, uint32_t); + +struct hiclock_compat hiclock_compat[] = { + /* Official Linux device tree bindings. */ + { + .compat = "hisilicon,hi3670-crgctrl", + .get_frequency = hi3670_crgctrl_get_frequency, + .enable = hi3670_crgctrl_enable, + }, + { .compat = "hisilicon,hi3670-pctrl" }, + { .compat = "hisilicon,hi3670-pmuctrl" }, + { .compat = "hisilicon,hi3670-pmctrl" }, + { .compat = "hisilicon,hi3670-sctrl" }, + { .compat = "hisilicon,hi3670-iomcu" }, + { .compat = "hisilicon,hi3670-media1-crg" }, + { .compat = "hisilicon,hi3670-media2-crg" }, + + /* Preliminary device tree bindings for HiKey970. */ + { + .compat = "hisilicon,kirin970-crgctrl", + .get_frequency = hi3670_crgctrl_get_frequency, + .enable = hi3670_crgctrl_enable, + }, + { .compat = "hisilicon,kirin970-pctrl" }, + { .compat = "hisilicon,kirin970-pmuctrl" }, + { .compat = "hisilicon,kirin970-pmctrl" }, + { .compat = "hisilicon,kirin970-sctrl" }, + { .compat = "hisilicon,kirin970-iomcu" }, + { + .compat = "hisilicon,kirin970-stub-clk", + .get_frequency = hi3670_stub_get_frequency, + .set_frequency = hi3670_stub_set_frequency, + }, + { .compat = "hisilicon,media1-crg" }, + { .compat = "hisilicon,media2-crg" }, +}; + int hiclock_match(struct device *parent, void *match, void *aux) { struct fdt_attach_args *faa = aux; + int i; - if (OF_is_compatible(faa->fa_node, "hisilicon,kirin970-crgctrl") || - OF_is_compatible(faa->fa_node, "hisilicon,kirin970-pctrl") || - OF_is_compatible(faa->fa_node, "hisilicon,kirin970-pmuctrl") || - OF_is_compatible(faa->fa_node, "hisilicon,kirin970-pmctrl") || - OF_is_compatible(faa->fa_node, "hisilicon,kirin970-sctrl") || - OF_is_compatible(faa->fa_node, "hisilicon,kirin970-iomcu") || - OF_is_compatible(faa->fa_node, "hisilicon,media1-crg") || - OF_is_compatible(faa->fa_node, "hisilicon,media2-crg")) - return 10; /* Must beat syscon(4). */ + for (i = 0; i < nitems(hiclock_compat); i++) { + if (OF_is_compatible(faa->fa_node, hiclock_compat[i].compat)) + return 10; /* Must beat syscon(4). */ + } return 0; } @@ -87,6 +129,7 @@ hiclock_attach(struct device *parent, struct device *self, void *aux) { struct hiclock_softc *sc = (struct hiclock_softc *)self; struct fdt_attach_args *faa = aux; + int i; if (faa->fa_nreg < 1) { printf(": no registers\n"); @@ -100,6 +143,16 @@ hiclock_attach(struct device *parent, struct device *self, void *aux) return; } + if (faa->fa_nreg > 1) { + if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, + faa->fa_reg[1].size, 0, &sc->sc_ioh_set)) { + printf(": can't map registers\n"); + bus_space_unmap(sc->sc_iot, sc->sc_ioh, + faa->fa_reg[0].size); + return; + } + } + if (OF_is_compatible(faa->fa_node, "syscon")) { regmap_register(faa->fa_node, sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size); @@ -109,40 +162,68 @@ hiclock_attach(struct device *parent, struct device *self, void *aux) sc->sc_cd.cd_node = faa->fa_node; sc->sc_cd.cd_cookie = sc; - if (OF_is_compatible(faa->fa_node, "hisilicon,kirin970-crgctrl")) { - sc->sc_cd.cd_get_frequency = kirin970_crgctrl_get_frequency; - sc->sc_cd.cd_enable = kirin970_crgctrl_enable; - } else { - sc->sc_cd.cd_get_frequency = hiclock_get_frequency; - sc->sc_cd.cd_enable = hiclock_enable; + for (i = 0; i < nitems(hiclock_compat); i++) { + if (OF_is_compatible(faa->fa_node, hiclock_compat[i].compat)) { + sc->sc_cd.cd_get_frequency = + hiclock_compat[i].get_frequency; + sc->sc_cd.cd_set_frequency = + hiclock_compat[i].set_frequency; + sc->sc_cd.cd_enable = hiclock_compat[i].enable; + break; + } } + if (sc->sc_cd.cd_get_frequency == NULL) + sc->sc_cd.cd_get_frequency = hiclock_get_frequency; + if (sc->sc_cd.cd_enable == NULL) + sc->sc_cd.cd_enable = hiclock_enable; clock_register(&sc->sc_cd); } -#define KIRIN970_CLKIN_SYS 0 -#define KIRIN970_CLK_PPLL0 3 -#define KIRIN970_CLK_PPLL2 5 -#define KIRIN970_CLK_PPLL3 6 - -#define KIRIN970_CLK_SD_SYS 22 -#define KIRIN970_CLK_SDIO_SYS 23 -#define KIRIN970_CLK_GATE_ABB_USB 29 -#define KIRIN970_CLK_MUX_SD_SYS 68 -#define KIRIN970_CLK_MUX_SD_PLL 69 -#define KIRIN970_CLK_MUX_SDIO_SYS 70 -#define KIRIN970_CLK_MUX_SDIO_PLL 71 -#define KIRIN970_CLK_DIV_SD 93 -#define KIRIN970_CLK_DIV_SDIO 94 -#define KIRIN970_HCLK_GATE_USB3OTG 147 -#define KIRIN970_HCLK_GATE_USB3DVFS 148 -#define KIRIN970_HCLK_GATE_SDIO 149 -#define KIRIN970_CLK_GATE_SD 159 -#define KIRIN970_HCLK_GATE_SD 160 -#define KIRIN970_CLK_GATE_SDIO 161 -#define KIRIN970_CLK_GATE_USB3OTG_REF 189 +/* Generic */ uint32_t -kirin970_crgctrl_get_frequency(void *cookie, uint32_t *cells) +hiclock_get_frequency(void *cookie, uint32_t *cells) +{ + uint32_t idx = cells[0]; + + printf("%s: 0x%08x\n", __func__, idx); + return 0; +} + +void +hiclock_enable(void *cookie, uint32_t *cells, int on) +{ + uint32_t idx = cells[0]; + + printf("%s: 0x%08x\n", __func__, idx); +} + +/* Hi3670 */ + +#define HI3670_CLKIN_SYS 0 +#define HI3670_CLK_PPLL0 3 +#define HI3670_CLK_PPLL2 5 +#define HI3670_CLK_PPLL3 6 + +#define HI3670_CLK_SD_SYS 22 +#define HI3670_CLK_SDIO_SYS 23 +#define HI3670_CLK_GATE_ABB_USB 29 +#define HI3670_CLK_MUX_SD_SYS 68 +#define HI3670_CLK_MUX_SD_PLL 69 +#define HI3670_CLK_MUX_SDIO_SYS 70 +#define HI3670_CLK_MUX_SDIO_PLL 71 +#define HI3670_CLK_DIV_SD 93 +#define HI3670_CLK_DIV_SDIO 94 +#define HI3670_HCLK_GATE_USB3OTG 147 +#define HI3670_HCLK_GATE_USB3DVFS 148 +#define HI3670_HCLK_GATE_SDIO 149 +#define HI3670_CLK_GATE_SD 159 +#define HI3670_HCLK_GATE_SD 160 +#define HI3670_CLK_GATE_SDIO 161 +#define HI3670_CLK_GATE_USB3OTG_REF 189 + +uint32_t +hi3670_crgctrl_get_frequency(void *cookie, uint32_t *cells) { struct hiclock_softc *sc = cookie; uint32_t idx = cells[0]; @@ -150,52 +231,52 @@ kirin970_crgctrl_get_frequency(void *cookie, uint32_t *cells) int mux; switch (idx) { - case KIRIN970_CLKIN_SYS: + case HI3670_CLKIN_SYS: return 19200000; - case KIRIN970_CLK_PPLL0: + case HI3670_CLK_PPLL0: return 1660000000; - case KIRIN970_CLK_PPLL2: + case HI3670_CLK_PPLL2: return 1920000000; - case KIRIN970_CLK_PPLL3: + case HI3670_CLK_PPLL3: return 1200000000; - case KIRIN970_CLK_SD_SYS: - case KIRIN970_CLK_SDIO_SYS: - idx = KIRIN970_CLKIN_SYS; - freq = kirin970_crgctrl_get_frequency(cookie, &idx); + case HI3670_CLK_SD_SYS: + case HI3670_CLK_SDIO_SYS: + idx = HI3670_CLKIN_SYS; + freq = hi3670_crgctrl_get_frequency(cookie, &idx); return freq / 6; - case KIRIN970_CLK_MUX_SD_SYS: + case HI3670_CLK_MUX_SD_SYS: reg = HREAD4(sc, 0x0b8); mux = (reg >> 6) & 0x1; - idx = mux ? KIRIN970_CLK_DIV_SD : KIRIN970_CLK_SD_SYS; - return kirin970_crgctrl_get_frequency(cookie, &idx); - case KIRIN970_CLK_MUX_SD_PLL: + idx = mux ? HI3670_CLK_DIV_SD : HI3670_CLK_SD_SYS; + return hi3670_crgctrl_get_frequency(cookie, &idx); + case HI3670_CLK_MUX_SD_PLL: reg = HREAD4(sc, 0x0b8); mux = (reg >> 4) & 0x3; switch (mux) { case 0: - idx = KIRIN970_CLK_PPLL0; + idx = HI3670_CLK_PPLL0; break; case 1: - idx = KIRIN970_CLK_PPLL3; + idx = HI3670_CLK_PPLL3; break; case 2: case 3: - idx = KIRIN970_CLK_PPLL2; + idx = HI3670_CLK_PPLL2; break; } - return kirin970_crgctrl_get_frequency(cookie, &idx); - case KIRIN970_CLK_DIV_SD: + return hi3670_crgctrl_get_frequency(cookie, &idx); + case HI3670_CLK_DIV_SD: reg = HREAD4(sc, 0x0b8); div = (reg >> 0) & 0xf; - idx = KIRIN970_CLK_MUX_SD_PLL; - freq = kirin970_crgctrl_get_frequency(cookie, &idx); + idx = HI3670_CLK_MUX_SD_PLL; + freq = hi3670_crgctrl_get_frequency(cookie, &idx); return freq / (div + 1); - case KIRIN970_CLK_GATE_SD: - idx = KIRIN970_CLK_MUX_SD_SYS; - return kirin970_crgctrl_get_frequency(cookie, &idx); - case KIRIN970_CLK_GATE_SDIO: - idx = KIRIN970_CLK_MUX_SDIO_SYS; - return kirin970_crgctrl_get_frequency(cookie, &idx); + case HI3670_CLK_GATE_SD: + idx = HI3670_CLK_MUX_SD_SYS; + return hi3670_crgctrl_get_frequency(cookie, &idx); + case HI3670_CLK_GATE_SDIO: + idx = HI3670_CLK_MUX_SDIO_SYS; + return hi3670_crgctrl_get_frequency(cookie, &idx); } printf("%s: 0x%08x\n", __func__, idx); @@ -203,17 +284,17 @@ kirin970_crgctrl_get_frequency(void *cookie, uint32_t *cells) } void -kirin970_crgctrl_enable(void *cookie, uint32_t *cells, int on) +hi3670_crgctrl_enable(void *cookie, uint32_t *cells, int on) { uint32_t idx = cells[0]; switch (idx) { - case KIRIN970_CLK_GATE_ABB_USB: - case KIRIN970_HCLK_GATE_USB3OTG: - case KIRIN970_HCLK_GATE_USB3DVFS: - case KIRIN970_CLK_GATE_SD: - case KIRIN970_HCLK_GATE_SD: - case KIRIN970_CLK_GATE_USB3OTG_REF: + case HI3670_CLK_GATE_ABB_USB: + case HI3670_HCLK_GATE_USB3OTG: + case HI3670_HCLK_GATE_USB3DVFS: + case HI3670_CLK_GATE_SD: + case HI3670_HCLK_GATE_SD: + case HI3670_CLK_GATE_USB3OTG_REF: /* Enabled by default. */ return; } @@ -221,19 +302,53 @@ kirin970_crgctrl_enable(void *cookie, uint32_t *cells, int on) printf("%s: 0x%08x\n", __func__, idx); } +#define HI3670_CLK_STUB_CLUSTER0 0 +#define HI3670_CLK_STUB_CLUSTER1 1 + uint32_t -hiclock_get_frequency(void *cookie, uint32_t *cells) +hi3670_stub_get_frequency(void *cookie, uint32_t *cells) { + struct hiclock_softc *sc = cookie; uint32_t idx = cells[0]; + uint32_t reg; + + switch (idx) { + case HI3670_CLK_STUB_CLUSTER0: + reg = HREAD4(sc, 0x070); + return reg * 1000000; + case HI3670_CLK_STUB_CLUSTER1: + reg = HREAD4(sc, 0x074); + return reg * 1000000; + default: + break; + } printf("%s: 0x%08x\n", __func__, idx); return 0; } -void -hiclock_enable(void *cookie, uint32_t *cells, int on) +int +hi3670_stub_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) { + struct hiclock_softc *sc = cookie; uint32_t idx = cells[0]; + uint32_t reg; + + switch (idx) { + case HI3670_CLK_STUB_CLUSTER0: + reg = freq / 16000000; + reg |= (0xff << 16); + bus_space_write_4(sc->sc_iot, sc->sc_ioh_set, 0x280, reg); + return 0; + case HI3670_CLK_STUB_CLUSTER1: + reg = freq / 16000000; + reg |= (0xff << 16); + bus_space_write_4(sc->sc_iot, sc->sc_ioh_set, 0x270, reg); + return 0; + default: + break; + } printf("%s: 0x%08x\n", __func__, idx); + return -1; } |