1 /* 2 * Joshua Henderson <joshua.henderson@microchip.com> 3 * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. 4 * 5 * This program is free software; you can distribute it and/or modify it 6 * under the terms of the GNU General Public License (Version 2) as 7 * published by the Free Software Foundation. 8 * 9 * This program is distributed in the hope it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * for more details. 13 */ 14 #include <asm/mach-pic32/pic32.h> 15 16 #include "pic32mzda.h" 17 18 /* Oscillators, PLL & clocks */ 19 #define ICLK_MASK 0x00000080 20 #define PLLDIV_MASK 0x00000007 21 #define CUROSC_MASK 0x00000007 22 #define PLLMUL_MASK 0x0000007F 23 #define PB_MASK 0x00000007 24 #define FRC1 0 25 #define FRC2 7 26 #define SPLL 1 27 #define POSC 2 28 #define FRC_CLK 8000000 29 30 #define PIC32_POSC_FREQ 24000000 31 32 #define OSCCON 0x0000 33 #define SPLLCON 0x0020 34 #define PB1DIV 0x0140 35 36 u32 pic32_get_sysclk(void) 37 { 38 u32 osc_freq = 0; 39 u32 pllclk; 40 u32 frcdivn; 41 u32 osccon; 42 u32 spllcon; 43 int curr_osc; 44 45 u32 plliclk; 46 u32 pllidiv; 47 u32 pllodiv; 48 u32 pllmult; 49 u32 frcdiv; 50 51 void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); 52 53 osccon = __raw_readl(osc_base + OSCCON); 54 spllcon = __raw_readl(osc_base + SPLLCON); 55 56 plliclk = (spllcon & ICLK_MASK); 57 pllidiv = ((spllcon >> 8) & PLLDIV_MASK) + 1; 58 pllodiv = ((spllcon >> 24) & PLLDIV_MASK); 59 pllmult = ((spllcon >> 16) & PLLMUL_MASK) + 1; 60 frcdiv = ((osccon >> 24) & PLLDIV_MASK); 61 62 pllclk = plliclk ? FRC_CLK : PIC32_POSC_FREQ; 63 frcdivn = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7)); 64 65 if (pllodiv < 2) 66 pllodiv = 2; 67 else if (pllodiv < 5) 68 pllodiv = (1 << pllodiv); 69 else 70 pllodiv = 32; 71 72 curr_osc = (int)((osccon >> 12) & CUROSC_MASK); 73 74 switch (curr_osc) { 75 case FRC1: 76 case FRC2: 77 osc_freq = FRC_CLK / frcdivn; 78 break; 79 case SPLL: 80 osc_freq = ((pllclk / pllidiv) * pllmult) / pllodiv; 81 break; 82 case POSC: 83 osc_freq = PIC32_POSC_FREQ; 84 break; 85 default: 86 break; 87 } 88 89 iounmap(osc_base); 90 91 return osc_freq; 92 } 93 94 u32 pic32_get_pbclk(int bus) 95 { 96 u32 clk_freq; 97 void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); 98 u32 pbxdiv = PB1DIV + ((bus - 1) * 0x10); 99 u32 pbdiv = (__raw_readl(osc_base + pbxdiv) & PB_MASK) + 1; 100 101 iounmap(osc_base); 102 103 clk_freq = pic32_get_sysclk(); 104 105 return clk_freq / pbdiv; 106 } 107