summaryrefslogtreecommitdiffstats
path: root/sys/arm/at91/at91_pmc.c
diff options
context:
space:
mode:
authorimp <imp@FreeBSD.org>2012-05-21 04:24:58 +0000
committerimp <imp@FreeBSD.org>2012-05-21 04:24:58 +0000
commitd9369891abf987923d688102e4b739f4cbd1fb6f (patch)
treee6877b994a5ebdacaafafe7fcfac8ffb7ba13bc0 /sys/arm/at91/at91_pmc.c
parente7da48dd43890a34e0959201b2b30b80c60a50d4 (diff)
downloadFreeBSD-src-d9369891abf987923d688102e4b739f4cbd1fb6f.zip
FreeBSD-src-d9369891abf987923d688102e4b739f4cbd1fb6f.tar.gz
Another minor re-arrangement of the code: calcualte the master clock
frequency in the at91_pmc_clock_init rather than passing it in. Allow for frequencies >= 21MHz by rounding to the nearest 500Hz (Idea from Ian Lapore whose company uses a similar arrangement in their product). at91_pmc_clock_init() is now nearly independent of the rest of the pmc driver (which means we may be able to call it much earlier in boot soon to eliminate the master clock config file requirement for printf to work during early boot and also eliminate some interdependencies with the device ordering which requires pmc to be the first device added).
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