summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2019-04-22 12:43:14 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2019-04-22 12:43:14 +0000
commit0353a6ec4a879cf256fc75780a908bb2154bcd34 (patch)
treebf10c3884b02ac2f4351fe710232186f88292794 /sys/dev
parentb942b726738bdd482aec441fce67524db50608a4 (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.c275
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;
}