diff options
Diffstat (limited to 'arch/mips/pic32/pic32mzda/early_clk.c')
-rw-r--r-- | arch/mips/pic32/pic32mzda/early_clk.c | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/arch/mips/pic32/pic32mzda/early_clk.c b/arch/mips/pic32/pic32mzda/early_clk.c new file mode 100644 index 000000000000..96c090e9d637 --- /dev/null +++ b/arch/mips/pic32/pic32mzda/early_clk.c @@ -0,0 +1,106 @@ +/* + * Joshua Henderson <joshua.henderson@microchip.com> + * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ +#include <asm/mach-pic32/pic32.h> + +#include "pic32mzda.h" + +/* Oscillators, PLL & clocks */ +#define ICLK_MASK 0x00000080 +#define PLLDIV_MASK 0x00000007 +#define CUROSC_MASK 0x00000007 +#define PLLMUL_MASK 0x0000007F +#define PB_MASK 0x00000007 +#define FRC1 0 +#define FRC2 7 +#define SPLL 1 +#define POSC 2 +#define FRC_CLK 8000000 + +#define PIC32_POSC_FREQ 24000000 + +#define OSCCON 0x0000 +#define SPLLCON 0x0020 +#define PB1DIV 0x0140 + +u32 pic32_get_sysclk(void) +{ + u32 osc_freq = 0; + u32 pllclk; + u32 frcdivn; + u32 osccon; + u32 spllcon; + int curr_osc; + + u32 plliclk; + u32 pllidiv; + u32 pllodiv; + u32 pllmult; + u32 frcdiv; + + void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); + + osccon = __raw_readl(osc_base + OSCCON); + spllcon = __raw_readl(osc_base + SPLLCON); + + plliclk = (spllcon & ICLK_MASK); + pllidiv = ((spllcon >> 8) & PLLDIV_MASK) + 1; + pllodiv = ((spllcon >> 24) & PLLDIV_MASK); + pllmult = ((spllcon >> 16) & PLLMUL_MASK) + 1; + frcdiv = ((osccon >> 24) & PLLDIV_MASK); + + pllclk = plliclk ? FRC_CLK : PIC32_POSC_FREQ; + frcdivn = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7)); + + if (pllodiv < 2) + pllodiv = 2; + else if (pllodiv < 5) + pllodiv = (1 << pllodiv); + else + pllodiv = 32; + + curr_osc = (int)((osccon >> 12) & CUROSC_MASK); + + switch (curr_osc) { + case FRC1: + case FRC2: + osc_freq = FRC_CLK / frcdivn; + break; + case SPLL: + osc_freq = ((pllclk / pllidiv) * pllmult) / pllodiv; + break; + case POSC: + osc_freq = PIC32_POSC_FREQ; + break; + default: + break; + } + + iounmap(osc_base); + + return osc_freq; +} + +u32 pic32_get_pbclk(int bus) +{ + u32 clk_freq; + void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); + u32 pbxdiv = PB1DIV + ((bus - 1) * 0x10); + u32 pbdiv = (__raw_readl(osc_base + pbxdiv) & PB_MASK) + 1; + + iounmap(osc_base); + + clk_freq = pic32_get_sysclk(); + + return clk_freq / pbdiv; +} |