summaryrefslogtreecommitdiffstats
path: root/sys/arm/at91/at91_pmc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm/at91/at91_pmc.c')
-rw-r--r--sys/arm/at91/at91_pmc.c116
1 files changed, 64 insertions, 52 deletions
diff --git a/sys/arm/at91/at91_pmc.c b/sys/arm/at91/at91_pmc.c
index 6e1db33..cff3396 100644
--- a/sys/arm/at91/at91_pmc.c
+++ b/sys/arm/at91/at91_pmc.c
@@ -388,12 +388,66 @@ fail:
return (0);
}
+#if !defined(AT91C_MAIN_CLOCK)
+static const unsigned int at91_main_clock_tbl[] = {
+ 3000000, 3276800, 3686400, 3840000, 4000000,
+ 4433619, 4915200, 5000000, 5242880, 6000000,
+ 6144000, 6400000, 6553600, 7159090, 7372800,
+ 7864320, 8000000, 9830400, 10000000, 11059200,
+ 12000000, 12288000, 13560000, 14318180, 14745600,
+ 16000000, 17344700, 18432000, 20000000
+};
+#define MAIN_CLOCK_TBL_LEN (sizeof(at91_main_clock_tbl) / sizeof(*at91_main_clock_tbl))
+
+static unsigned int
+at91_pmc_sense_main_clock(struct at91_pmc_softc *sc)
+{
+ unsigned int ckgr_val;
+ unsigned int diff, matchdiff, freq;
+ int i;
+
+ ckgr_val = (RD4(sc, CKGR_MCFR) & CKGR_MCFR_MAINF_MASK) << 11;
+
+ /*
+ * Clocks up to 50MHz can be connected to some models. If
+ * the frequency is >= 21MHz, assume that the slow clock can
+ * measure it correctly, and that any error can be adequately
+ * compensated for by roudning to the nearest 500Hz. Users
+ * with fast, or odd-ball clocks will need to set
+ * AT91C_MASTER_CLOCK in the kernel config file.
+ */
+ if (ckgr_val >= 21000000)
+ return ((ckgr_val + 250) / 500 * 500);
+
+ /*
+ * Try to find the standard frequency that match best.
+ */
+ freq = at91_main_clock_tbl[0];
+ matchdiff = abs(ckgr_val - at91_main_clock_tbl[0]);
+ for (i = 1; i < MAIN_CLOCK_TBL_LEN; i++) {
+ diff = abs(ckgr_val - at91_main_clock_tbl[i]);
+ if (diff < matchdiff) {
+ freq = at91_main_clock_tbl[i];
+ matchdiff = diff;
+ }
+ }
+ return (freq);
+}
+#endif
+
static void
-at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock)
+at91_pmc_init_clock(struct at91_pmc_softc *sc)
{
+ unsigned int main_clock;
uint32_t mckr;
uint32_t mdiv;
+#if !defined(AT91C_MAIN_CLOCK)
+ main_clock = at91_pmc_sense_main_clock(pmc_softc);
+#else
+ main_clock = AT91C_MAIN_CLOCK;
+#endif
+
if (at91_is_sam9() || at91_is_sam9xe()) {
uhpck.pmc_mask = PMC_SCER_UHP_SAM9;
udpck.pmc_mask = PMC_SCER_UDP_SAM9;
@@ -449,11 +503,9 @@ at91_pmc_init_clock(struct at91_pmc_softc *sc, unsigned int main_clock)
at91_master_clock = mck.hz;
- device_printf(sc->dev,
- "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n",
- main_clock,
- plla.hz / 1000000,
- cpu.hz / 1000000, mck.hz / 1000000);
+ /* These clocks refrenced by "special" names */
+ at91_pmc_clock_alias("ohci0", "ohci_clk");
+ at91_pmc_clock_alias("udp0", "udp_clk");
/* Turn off "Progamable" clocks */
WR4(sc, PMC_SCDR, PMC_SCER_PCK0 | PMC_SCER_PCK1 | PMC_SCER_PCK2 |
@@ -505,46 +557,9 @@ at91_pmc_probe(device_t dev)
return (0);
}
-#if !defined(AT91C_MAIN_CLOCK)
-static const unsigned int at91_mainf_tbl[] = {
- 3000000, 3276800, 3686400, 3840000, 4000000,
- 4433619, 4915200, 5000000, 5242880, 6000000,
- 6144000, 6400000, 6553600, 7159090, 7372800,
- 7864320, 8000000, 9830400, 10000000, 11059200,
- 12000000, 12288000, 13560000, 14318180, 14745600,
- 16000000, 17344700, 18432000, 20000000
-};
-#define MAINF_TBL_LEN (sizeof(at91_mainf_tbl) / sizeof(*at91_mainf_tbl))
-
-static unsigned int
-at91_pmc_sense_mainf(struct at91_pmc_softc *sc)
-{
- unsigned int ckgr_val;
- unsigned int diff, matchdiff;
- int i, match;
-
- ckgr_val = (RD4(sc, CKGR_MCFR) & CKGR_MCFR_MAINF_MASK) << 11;
-
- /*
- * Try to find the standard frequency that match best.
- */
- match = 0;
- matchdiff = abs(ckgr_val - at91_mainf_tbl[0]);
- for (i = 1; i < MAINF_TBL_LEN; i++) {
- diff = abs(ckgr_val - at91_mainf_tbl[i]);
- if (diff < matchdiff) {
- match = i;
- matchdiff = diff;
- }
- }
- return (at91_mainf_tbl[match]);
-}
-#endif
-
static int
at91_pmc_attach(device_t dev)
{
- unsigned int mainf;
int err;
pmc_softc = device_get_softc(dev);
@@ -555,16 +570,13 @@ at91_pmc_attach(device_t dev)
/*
* Configure main clock frequency.
*/
-#if !defined(AT91C_MAIN_CLOCK)
- mainf = at91_pmc_sense_mainf(pmc_softc);
-#else
- mainf = AT91C_MAIN_CLOCK;
-#endif
- at91_pmc_init_clock(pmc_softc, mainf);
+ at91_pmc_init_clock(pmc_softc);
- /* These clocks refrenced by "special" names */
- at91_pmc_clock_alias("ohci0", "ohci_clk");
- at91_pmc_clock_alias("udp0", "udp_clk");
+ device_printf(dev,
+ "Primary: %d Hz PLLA: %d MHz CPU: %d MHz MCK: %d MHz\n",
+ main_ck.hz,
+ plla.hz / 1000000,
+ cpu.hz / 1000000, mck.hz / 1000000);
return (0);
}
OpenPOWER on IntegriCloud