summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2020-04-28 19:26:46 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2020-04-28 19:26:46 +0000
commit5db7174cc22ac22b3ded9f83681b68e07fc84c39 (patch)
tree2a6893b2a93723ab0b1a5ad7d8005f9548e687dc /sys/dev
parentb2e1252d7e042aa45d5b9a25cbafcda195cfb0f9 (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.c48
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) {