162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Joshua Henderson <joshua.henderson@microchip.com> 462306a36Sopenharmony_ci * Copyright (C) 2015 Microchip Technology Inc. All rights reserved. 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include <asm/mach-pic32/pic32.h> 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "pic32mzda.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci/* Oscillators, PLL & clocks */ 1162306a36Sopenharmony_ci#define ICLK_MASK 0x00000080 1262306a36Sopenharmony_ci#define PLLDIV_MASK 0x00000007 1362306a36Sopenharmony_ci#define CUROSC_MASK 0x00000007 1462306a36Sopenharmony_ci#define PLLMUL_MASK 0x0000007F 1562306a36Sopenharmony_ci#define PB_MASK 0x00000007 1662306a36Sopenharmony_ci#define FRC1 0 1762306a36Sopenharmony_ci#define FRC2 7 1862306a36Sopenharmony_ci#define SPLL 1 1962306a36Sopenharmony_ci#define POSC 2 2062306a36Sopenharmony_ci#define FRC_CLK 8000000 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#define PIC32_POSC_FREQ 24000000 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#define OSCCON 0x0000 2562306a36Sopenharmony_ci#define SPLLCON 0x0020 2662306a36Sopenharmony_ci#define PB1DIV 0x0140 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ciu32 pic32_get_sysclk(void) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci u32 osc_freq = 0; 3162306a36Sopenharmony_ci u32 pllclk; 3262306a36Sopenharmony_ci u32 frcdivn; 3362306a36Sopenharmony_ci u32 osccon; 3462306a36Sopenharmony_ci u32 spllcon; 3562306a36Sopenharmony_ci int curr_osc; 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci u32 plliclk; 3862306a36Sopenharmony_ci u32 pllidiv; 3962306a36Sopenharmony_ci u32 pllodiv; 4062306a36Sopenharmony_ci u32 pllmult; 4162306a36Sopenharmony_ci u32 frcdiv; 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci osccon = __raw_readl(osc_base + OSCCON); 4662306a36Sopenharmony_ci spllcon = __raw_readl(osc_base + SPLLCON); 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci plliclk = (spllcon & ICLK_MASK); 4962306a36Sopenharmony_ci pllidiv = ((spllcon >> 8) & PLLDIV_MASK) + 1; 5062306a36Sopenharmony_ci pllodiv = ((spllcon >> 24) & PLLDIV_MASK); 5162306a36Sopenharmony_ci pllmult = ((spllcon >> 16) & PLLMUL_MASK) + 1; 5262306a36Sopenharmony_ci frcdiv = ((osccon >> 24) & PLLDIV_MASK); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci pllclk = plliclk ? FRC_CLK : PIC32_POSC_FREQ; 5562306a36Sopenharmony_ci frcdivn = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7)); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (pllodiv < 2) 5862306a36Sopenharmony_ci pllodiv = 2; 5962306a36Sopenharmony_ci else if (pllodiv < 5) 6062306a36Sopenharmony_ci pllodiv = (1 << pllodiv); 6162306a36Sopenharmony_ci else 6262306a36Sopenharmony_ci pllodiv = 32; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci curr_osc = (int)((osccon >> 12) & CUROSC_MASK); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci switch (curr_osc) { 6762306a36Sopenharmony_ci case FRC1: 6862306a36Sopenharmony_ci case FRC2: 6962306a36Sopenharmony_ci osc_freq = FRC_CLK / frcdivn; 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci case SPLL: 7262306a36Sopenharmony_ci osc_freq = ((pllclk / pllidiv) * pllmult) / pllodiv; 7362306a36Sopenharmony_ci break; 7462306a36Sopenharmony_ci case POSC: 7562306a36Sopenharmony_ci osc_freq = PIC32_POSC_FREQ; 7662306a36Sopenharmony_ci break; 7762306a36Sopenharmony_ci default: 7862306a36Sopenharmony_ci break; 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci iounmap(osc_base); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci return osc_freq; 8462306a36Sopenharmony_ci} 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ciu32 pic32_get_pbclk(int bus) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci u32 clk_freq; 8962306a36Sopenharmony_ci void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200); 9062306a36Sopenharmony_ci u32 pbxdiv = PB1DIV + ((bus - 1) * 0x10); 9162306a36Sopenharmony_ci u32 pbdiv = (__raw_readl(osc_base + pbxdiv) & PB_MASK) + 1; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci iounmap(osc_base); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci clk_freq = pic32_get_sysclk(); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci return clk_freq / pbdiv; 9862306a36Sopenharmony_ci} 99