diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2020-04-28 19:26:46 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2020-04-28 19:26:46 +0000 |
commit | 5db7174cc22ac22b3ded9f83681b68e07fc84c39 (patch) | |
tree | 2a6893b2a93723ab0b1a5ad7d8005f9548e687dc /sys/dev | |
parent | b2e1252d7e042aa45d5b9a25cbafcda195cfb0f9 (diff) |
Calculate divisor for i.MX8M composite clocks. So far we have set
fixed values for the divisors, but the imxesdhc(4) nodes for
SD Cards usually have an assigned clock rate of 200 MHz instead of
400 MHz. So instead of just clearing the divisor, we should set it
according to what is asked. This also allows us to add the clock
for the second imxesdhc(4) node to the list, which I have previously
skipped, since otherwise the controller would have been clocked too
high.
ok kettenis@
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/fdt/imxccm.c | 48 |
1 files changed, 35 insertions, 13 deletions
diff --git a/sys/dev/fdt/imxccm.c b/sys/dev/fdt/imxccm.c index 1ee24f06caa..beb246ea022 100644 --- a/sys/dev/fdt/imxccm.c +++ b/sys/dev/fdt/imxccm.c @@ -1,4 +1,4 @@ -/* $OpenBSD: imxccm.c,v 1.20 2020/04/26 13:31:48 patrick Exp $ */ +/* $OpenBSD: imxccm.c,v 1.21 2020/04/28 19:26:45 patrick Exp $ */ /* * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> * @@ -254,6 +254,7 @@ uint32_t imxccm_imx8mq_pwm(struct imxccm_softc *sc, uint32_t); uint32_t imxccm_imx8mq_uart(struct imxccm_softc *sc, uint32_t); uint32_t imxccm_imx8mq_usdhc(struct imxccm_softc *sc, uint32_t); uint32_t imxccm_imx8mq_usb(struct imxccm_softc *sc, uint32_t); +int imxccm_imx8m_set_div(struct imxccm_softc *, uint32_t, uint64_t, uint64_t); void imxccm_enable(void *, uint32_t *, int); uint32_t imxccm_get_frequency(void *, uint32_t *); int imxccm_set_frequency(void *, uint32_t *, uint32_t); @@ -1155,6 +1156,34 @@ imxccm_imx8mq_set_pll(struct imxccm_softc *sc, uint32_t idx, uint64_t freq) return 0; } +int +imxccm_imx8m_set_div(struct imxccm_softc *sc, uint32_t idx, uint64_t freq, + uint64_t parent_freq) +{ + uint64_t div; + uint32_t reg; + + if (parent_freq < freq) { + printf("%s: parent frequency too low (0x%08x)\n", + __func__, idx); + return -1; + } + + /* divisor can only be changed if enabled */ + imxccm_enable(sc, &idx, 1); + + div = 0; + while (parent_freq / (div + 1) > freq) + div++; + reg = HREAD4(sc, sc->sc_divs[idx].reg); + reg &= ~(sc->sc_divs[idx].mask << sc->sc_divs[idx].shift); + reg |= (div << sc->sc_divs[idx].shift); + HWRITE4(sc, sc->sc_divs[idx].reg, reg); + HCLR4(sc, sc->sc_predivs[idx].reg, + sc->sc_predivs[idx].mask << sc->sc_predivs[idx].shift); + return 0; +} + void imxccm_enable_parent(struct imxccm_softc *sc, uint32_t parent, int on) { @@ -1544,12 +1573,8 @@ imxccm_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) case IMX8MM_CLK_USDHC1: case IMX8MM_CLK_USDHC2: case IMX8MM_CLK_USDHC3: - imxccm_enable(cookie, &idx, 1); - HCLR4(sc, sc->sc_divs[idx].reg, - sc->sc_divs[idx].mask << sc->sc_divs[idx].shift); - HCLR4(sc, sc->sc_predivs[idx].reg, - sc->sc_predivs[idx].mask << sc->sc_predivs[idx].shift); - return 0; + parent_freq = imxccm_imx8mm_usdhc(sc, idx); + return imxccm_imx8m_set_div(sc, idx, freq, parent_freq); } } else if (sc->sc_divs == imx8mq_divs) { switch (idx) { @@ -1574,12 +1599,9 @@ imxccm_set_frequency(void *cookie, uint32_t *cells, uint32_t freq) break; return 0; case IMX8MQ_CLK_USDHC1: - imxccm_enable(cookie, &idx, 1); - HCLR4(sc, sc->sc_divs[idx].reg, - sc->sc_divs[idx].mask << sc->sc_divs[idx].shift); - HCLR4(sc, sc->sc_predivs[idx].reg, - sc->sc_predivs[idx].mask << sc->sc_predivs[idx].shift); - return 0; + case IMX8MQ_CLK_USDHC2: + parent_freq = imxccm_imx8mq_usdhc(sc, idx); + return imxccm_imx8m_set_div(sc, idx, freq, parent_freq); } } else if (sc->sc_divs == imx7d_divs) { switch (idx) { |