1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Joshua Henderson <joshua.henderson@microchip.com> 4 * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. 5 */ 6#include <asm/mach-pic32/pic32.h> 7 8#include "pic32mzda.h" 9 10/* Oscillators, PLL & clocks */ 11#define ICLK_MASK 0x00000080 12#define PLLDIV_MASK 0x00000007 13#define CUROSC_MASK 0x00000007 14#define PLLMUL_MASK 0x0000007F 15#define PB_MASK 0x00000007 16#define FRC1 0 17#define FRC2 7 18#define SPLL 1 19#define POSC 2 20#define FRC_CLK 8000000 21 22#define PIC32_POSC_FREQ 24000000 23 24#define OSCCON 0x0000 25#define SPLLCON 0x0020 26#define PB1DIV 0x0140 27 28u32 pic32_get_sysclk(void) 29{ 30 u32 osc_freq = 0; 31 u32 pllclk; 32 u32 frcdivn; 33 u32 osccon; 34 u32 spllcon; 35 int curr_osc; 36 37 u32 plliclk; 38 u32 pllidiv; 39 u32 pllodiv; 40 u32 pllmult; 41 u32 frcdiv; 42 43 void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); 44 45 osccon = __raw_readl(osc_base + OSCCON); 46 spllcon = __raw_readl(osc_base + SPLLCON); 47 48 plliclk = (spllcon & ICLK_MASK); 49 pllidiv = ((spllcon >> 8) & PLLDIV_MASK) + 1; 50 pllodiv = ((spllcon >> 24) & PLLDIV_MASK); 51 pllmult = ((spllcon >> 16) & PLLMUL_MASK) + 1; 52 frcdiv = ((osccon >> 24) & PLLDIV_MASK); 53 54 pllclk = plliclk ? FRC_CLK : PIC32_POSC_FREQ; 55 frcdivn = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7)); 56 57 if (pllodiv < 2) 58 pllodiv = 2; 59 else if (pllodiv < 5) 60 pllodiv = (1 << pllodiv); 61 else 62 pllodiv = 32; 63 64 curr_osc = (int)((osccon >> 12) & CUROSC_MASK); 65 66 switch (curr_osc) { 67 case FRC1: 68 case FRC2: 69 osc_freq = FRC_CLK / frcdivn; 70 break; 71 case SPLL: 72 osc_freq = ((pllclk / pllidiv) * pllmult) / pllodiv; 73 break; 74 case POSC: 75 osc_freq = PIC32_POSC_FREQ; 76 break; 77 default: 78 break; 79 } 80 81 iounmap(osc_base); 82 83 return osc_freq; 84} 85 86u32 pic32_get_pbclk(int bus) 87{ 88 u32 clk_freq; 89 void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); 90 u32 pbxdiv = PB1DIV + ((bus - 1) * 0x10); 91 u32 pbdiv = (__raw_readl(osc_base + pbxdiv) & PB_MASK) + 1; 92 93 iounmap(osc_base); 94 95 clk_freq = pic32_get_sysclk(); 96 97 return clk_freq / pbdiv; 98} 99