summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2018-12-30 23:54:28 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2018-12-30 23:54:28 +0000
commitf1a07f36ab5f4b8f7226b2ae8dee9d199e7a17ac (patch)
tree49017257b7c94d6e9304b936a7a7f988e50754a4 /sys
parentdb726b386f94ac470222bfe9b252040b9dd84a8f (diff)
More RK3328 clock stuff.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/fdt/rkclock.c141
-rw-r--r--sys/dev/fdt/rkclock_clocks.h5
2 files changed, 137 insertions, 9 deletions
diff --git a/sys/dev/fdt/rkclock.c b/sys/dev/fdt/rkclock.c
index 24f07b59d5d..339a37d7e3d 100644
--- a/sys/dev/fdt/rkclock.c
+++ b/sys/dev/fdt/rkclock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rkclock.c,v 1.30 2018/12/30 18:18:54 kettenis Exp $ */
+/* $OpenBSD: rkclock.c,v 1.31 2018/12/30 23:54:27 kettenis Exp $ */
/*
* Copyright (c) 2017, 2018 Mark Kettenis <kettenis@openbsd.org>
*
@@ -66,6 +66,8 @@
#define RK3328_CRU_CRU_MODE_SLOW 0x0
#define RK3328_CRU_CRU_MODE_NORMAL 0x1
#define RK3328_CRU_CLKSEL_CON(i) (0x0100 + (i) * 4)
+#define RK3328_CRU_BUS_ACLK_DIV_CON_MASK (0x3 << 8)
+#define RK3328_CRU_BUS_ACLK_DIV_CON_SHIFT 8
#define RK3328_CRU_CORE_CLK_PLL_SEL_MASK (0x3 << 6)
#define RK3328_CRU_CORE_CLK_PLL_SEL_SHIFT 6
#define RK3328_CRU_CLK_CORE_DIV_CON_MASK (0x1f << 0)
@@ -74,6 +76,10 @@
#define RK3328_CRU_ACLK_CORE_DIV_CON_SHIFT 4
#define RK3328_CRU_CLK_CORE_DBG_DIV_CON_MASK (0xf << 0)
#define RK3328_CRU_CLK_CORE_DBG_DIV_CON_SHIFT 0
+#define RK3328_CRU_UART_CLK_SEL_MASK (0x3 << 8)
+#define RK3328_CRU_UART_CLK_SEL_24MHZ (0x2 << 8)
+#define RK3328_CRU_PERIPH_ACLK_DIV_CON_MASK (0x3 << 8)
+#define RK3328_CRU_PERIPH_ACLK_DIV_CON_SHIFT 8
#define RK3328_CRU_CLKGATE_CON(i) (0x0200 + (i) * 4)
#define RK3328_CRU_SOFTRST_CON(i) (0x0300 + (i) * 4)
@@ -140,6 +146,8 @@ struct rkclock_softc {
bus_space_tag_t sc_iot;
bus_space_handle_t sc_ioh;
+ uint32_t sc_phandle;
+
struct clock_device sc_cd;
struct reset_device sc_rd;
};
@@ -164,6 +172,7 @@ void rk3288_reset(void *, uint32_t *, int);
void rk3328_init(struct rkclock_softc *);
uint32_t rk3328_get_frequency(void *, uint32_t *);
int rk3328_set_frequency(void *, uint32_t *, uint32_t);
+int rk3328_set_parent(void *, uint32_t *, uint32_t *);
void rk3328_enable(void *, uint32_t *, int);
void rk3328_reset(void *, uint32_t *, int);
@@ -186,6 +195,7 @@ struct rkclock_compat {
void (*enable)(void *, uint32_t *, int);
uint32_t (*get_frequency)(void *, uint32_t *);
int (*set_frequency)(void *, uint32_t *, uint32_t);
+ int (*set_parent)(void *, uint32_t *, uint32_t *);
void (*reset)(void *, uint32_t *, int);
};
@@ -193,22 +203,26 @@ struct rkclock_compat rkclock_compat[] = {
{
"rockchip,rk3288-cru", 0, rk3288_init,
rk3288_enable, rk3288_get_frequency,
- rk3288_set_frequency, rk3288_reset
+ rk3288_set_frequency, NULL,
+ rk3288_reset
},
{
"rockchip,rk3328-cru", 0, rk3328_init,
rk3328_enable, rk3328_get_frequency,
- rk3328_set_frequency, rk3328_reset
+ rk3328_set_frequency, rk3328_set_parent,
+ rk3328_reset
},
{
"rockchip,rk3399-cru", 1, rk3399_init,
rk3399_enable, rk3399_get_frequency,
- rk3399_set_frequency, rk3399_reset,
+ rk3399_set_frequency, NULL,
+ rk3399_reset
},
{
"rockchip,rk3399-pmucru", 1, rk3399_pmu_init,
rk3399_pmu_enable, rk3399_pmu_get_frequency,
- rk3399_pmu_set_frequency, rk3399_pmu_reset
+ rk3399_pmu_set_frequency, NULL,
+ rk3399_pmu_reset
}
};
@@ -239,7 +253,6 @@ rkclock_attach(struct device *parent, struct device *self, void *aux)
}
sc->sc_iot = faa->fa_iot;
-
if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
printf(": can't map registers\n");
@@ -248,6 +261,8 @@ rkclock_attach(struct device *parent, struct device *self, void *aux)
printf("\n");
+ sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0);
+
for (i = 0; i < nitems(rkclock_compat); i++) {
if (OF_is_compatible(faa->fa_node, rkclock_compat[i].compat)) {
break;
@@ -263,6 +278,7 @@ rkclock_attach(struct device *parent, struct device *self, void *aux)
sc->sc_cd.cd_enable = rkclock_compat[i].enable;
sc->sc_cd.cd_get_frequency = rkclock_compat[i].get_frequency;
sc->sc_cd.cd_set_frequency = rkclock_compat[i].set_frequency;
+ sc->sc_cd.cd_set_parent = rkclock_compat[i].set_parent;
clock_register(&sc->sc_cd);
sc->sc_rd.rd_node = faa->fa_node;
@@ -357,7 +373,7 @@ rk3288_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq)
nr = 1; no = 8;
break;
default:
- printf("%s: %d MHz\n", __func__, freq);
+ printf("%s: %u Hz\n", __func__, freq);
return -1;
}
@@ -767,7 +783,7 @@ rk3328_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq)
postdiv1 = postdiv2 = 4; refdiv = 1;
break;
default:
- printf("%s: %d MHz\n", __func__, freq);
+ printf("%s: %u Hz\n", __func__, freq);
return -1;
}
@@ -849,6 +865,40 @@ rk3328_get_i2c(struct rkclock_softc *sc, size_t base, int shift)
}
uint32_t
+rk3328_div_con(struct rkclock_softc *sc, int idx, uint32_t freq)
+{
+ uint32_t parent_freq, div;
+
+ parent_freq = rk3328_get_frequency(sc, &idx);
+ div = (parent_freq + freq - 1) / freq;
+ return (div > 0 ? div - 1 : 0);
+}
+
+int
+rk3328_set_uart_parent(struct rkclock_softc *sc, bus_size_t clksel,
+ uint32_t *pcells)
+{
+ char name[32];
+ int node;
+
+ /* We only support switching to the 24 MHz clock. */
+ node = OF_getnodebyphandle(pcells[0]);
+ if (node == 0)
+ return -1;
+ name[0] = 0;
+ OF_getprop(node, "clock-output-names", name, sizeof(name));
+ name[sizeof(name) - 1] = 0;
+ if (strcmp(name, "xin24m") != 0)
+ return -1;
+
+ HWRITE4(sc, clksel,
+ RK3328_CRU_UART_CLK_SEL_MASK << 16 |
+ RK3328_CRU_UART_CLK_SEL_24MHZ);
+
+ return 0;
+}
+
+uint32_t
rk3328_get_frequency(void *cookie, uint32_t *cells)
{
struct rkclock_softc *sc = cookie;
@@ -916,6 +966,7 @@ rk3328_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
{
struct rkclock_softc *sc = cookie;
uint32_t idx = cells[0];
+ uint32_t reg, mux, div_con;
switch (idx) {
case RK3328_PLL_APLL:
@@ -930,12 +981,84 @@ rk3328_set_frequency(void *cookie, uint32_t *cells, uint32_t freq)
return rk3328_set_pll(sc, RK3328_CRU_NPLL_CON(0), freq);
case RK3328_ARMCLK:
return rk3328_set_armclk(sc, freq);
+ case RK3328_CLK_UART0:
+ case RK3328_CLK_UART1:
+ case RK3328_CLK_UART2:
+ if (freq == rk3328_get_frequency(sc, &idx))
+ return 0;
+ break;
+ case RK3328_ACLK_BUS_PRE:
+ reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(0));
+ mux = (reg >> 13) & 0x3;
+ switch (mux) {
+ case 0:
+ idx = RK3328_PLL_CPLL;
+ break;
+ case 1:
+ idx = RK3328_PLL_GPLL;
+ break;
+ case 2:
+ idx = RK3328_HDMIPHY;
+ break;
+ default:
+ goto fail;
+ }
+ div_con = rk3328_div_con(sc, idx, freq);
+ HWRITE4(sc, RK3328_CRU_CLKSEL_CON(0),
+ RK3328_CRU_BUS_ACLK_DIV_CON_MASK << 16 |
+ div_con << RK3328_CRU_BUS_ACLK_DIV_CON_SHIFT);
+ return 0;
+ case RK3328_ACLK_PERI_PRE:
+ reg = HREAD4(sc, RK3328_CRU_CLKSEL_CON(28));
+ mux = (reg >> 6) & 0x3;
+ switch (mux) {
+ case 0:
+ idx = RK3328_PLL_CPLL;
+ break;
+ case 1:
+ idx = RK3328_PLL_GPLL;
+ break;
+ case 2:
+ idx = RK3328_HDMIPHY;
+ break;
+ default:
+ goto fail;
+ }
+ div_con = rk3328_div_con(sc, idx, freq);
+ HWRITE4(sc, RK3328_CRU_CLKSEL_CON(28),
+ RK3328_CRU_PERIPH_ACLK_DIV_CON_MASK << 16 |
+ div_con << RK3328_CRU_PERIPH_ACLK_DIV_CON_SHIFT);
+ return 0;
}
+fail:
printf("%s: 0x%08x\n", __func__, idx);
return -1;
}
+int
+rk3328_set_parent(void *cookie, uint32_t *cells, uint32_t *pcells)
+{
+ struct rkclock_softc *sc = cookie;
+ uint32_t idx = cells[0];
+
+ switch (idx) {
+ case RK3328_CLK_UART0:
+ return rk3328_set_uart_parent(sc,
+ RK3328_CRU_CLKSEL_CON(14), pcells);
+ case RK3328_CLK_UART1:
+ return rk3328_set_uart_parent(sc,
+ RK3328_CRU_CLKSEL_CON(16), pcells);
+ case RK3328_CLK_UART2:
+ return rk3328_set_uart_parent(sc,
+ RK3328_CRU_CLKSEL_CON(18), pcells);
+ }
+
+ printf("%s: 0x%08x 0x%08x 0x%08x\n", __func__, idx, pcells[0],
+ pcells[0] == sc->sc_phandle ? pcells[1] : -1);
+ return -1;
+}
+
void
rk3328_enable(void *cookie, uint32_t *cells, int on)
{
@@ -1076,7 +1199,7 @@ rk3399_set_pll(struct rkclock_softc *sc, bus_size_t base, uint32_t freq)
postdiv1 = postdiv2 = 4; refdiv = 1;
break;
default:
- printf("%s: %d MHz\n", __func__, freq);
+ printf("%s: %d Hz\n", __func__, freq);
return -1;
}
diff --git a/sys/dev/fdt/rkclock_clocks.h b/sys/dev/fdt/rkclock_clocks.h
index e3c9dc52a57..4f8c491f248 100644
--- a/sys/dev/fdt/rkclock_clocks.h
+++ b/sys/dev/fdt/rkclock_clocks.h
@@ -58,6 +58,11 @@
#define RK3328_CLK_I2C2 57
#define RK3328_CLK_I2C3 58
+#define RK3328_ACLK_BUS_PRE 136
+#define RK3328_ACLK_PERI_PRE 137
+
+#define RK3328_HDMIPHY 122
+
/*
* RK3399 clocks.
*/