18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Joshua Henderson <joshua.henderson@microchip.com>
48c2ecf20Sopenharmony_ci * Copyright (C) 2015 Microchip Technology Inc.  All rights reserved.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci#include <asm/mach-pic32/pic32.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#include "pic32mzda.h"
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci/* Oscillators, PLL & clocks */
118c2ecf20Sopenharmony_ci#define ICLK_MASK	0x00000080
128c2ecf20Sopenharmony_ci#define PLLDIV_MASK	0x00000007
138c2ecf20Sopenharmony_ci#define CUROSC_MASK	0x00000007
148c2ecf20Sopenharmony_ci#define PLLMUL_MASK	0x0000007F
158c2ecf20Sopenharmony_ci#define PB_MASK		0x00000007
168c2ecf20Sopenharmony_ci#define FRC1		0
178c2ecf20Sopenharmony_ci#define FRC2		7
188c2ecf20Sopenharmony_ci#define SPLL		1
198c2ecf20Sopenharmony_ci#define POSC		2
208c2ecf20Sopenharmony_ci#define FRC_CLK		8000000
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define PIC32_POSC_FREQ	24000000
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#define OSCCON		0x0000
258c2ecf20Sopenharmony_ci#define SPLLCON		0x0020
268c2ecf20Sopenharmony_ci#define PB1DIV		0x0140
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciu32 pic32_get_sysclk(void)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	u32 osc_freq = 0;
318c2ecf20Sopenharmony_ci	u32 pllclk;
328c2ecf20Sopenharmony_ci	u32 frcdivn;
338c2ecf20Sopenharmony_ci	u32 osccon;
348c2ecf20Sopenharmony_ci	u32 spllcon;
358c2ecf20Sopenharmony_ci	int curr_osc;
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	u32 plliclk;
388c2ecf20Sopenharmony_ci	u32 pllidiv;
398c2ecf20Sopenharmony_ci	u32 pllodiv;
408c2ecf20Sopenharmony_ci	u32 pllmult;
418c2ecf20Sopenharmony_ci	u32 frcdiv;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_ci	void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200);
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci	osccon = __raw_readl(osc_base + OSCCON);
468c2ecf20Sopenharmony_ci	spllcon = __raw_readl(osc_base + SPLLCON);
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ci	plliclk = (spllcon & ICLK_MASK);
498c2ecf20Sopenharmony_ci	pllidiv = ((spllcon >> 8) & PLLDIV_MASK) + 1;
508c2ecf20Sopenharmony_ci	pllodiv = ((spllcon >> 24) & PLLDIV_MASK);
518c2ecf20Sopenharmony_ci	pllmult = ((spllcon >> 16) & PLLMUL_MASK) + 1;
528c2ecf20Sopenharmony_ci	frcdiv = ((osccon >> 24) & PLLDIV_MASK);
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	pllclk = plliclk ? FRC_CLK : PIC32_POSC_FREQ;
558c2ecf20Sopenharmony_ci	frcdivn = ((1 << frcdiv) + 1) + (128 * (frcdiv == 7));
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	if (pllodiv < 2)
588c2ecf20Sopenharmony_ci		pllodiv = 2;
598c2ecf20Sopenharmony_ci	else if (pllodiv < 5)
608c2ecf20Sopenharmony_ci		pllodiv = (1 << pllodiv);
618c2ecf20Sopenharmony_ci	else
628c2ecf20Sopenharmony_ci		pllodiv = 32;
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci	curr_osc = (int)((osccon >> 12) & CUROSC_MASK);
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	switch (curr_osc) {
678c2ecf20Sopenharmony_ci	case FRC1:
688c2ecf20Sopenharmony_ci	case FRC2:
698c2ecf20Sopenharmony_ci		osc_freq = FRC_CLK / frcdivn;
708c2ecf20Sopenharmony_ci		break;
718c2ecf20Sopenharmony_ci	case SPLL:
728c2ecf20Sopenharmony_ci		osc_freq = ((pllclk / pllidiv) * pllmult) / pllodiv;
738c2ecf20Sopenharmony_ci		break;
748c2ecf20Sopenharmony_ci	case POSC:
758c2ecf20Sopenharmony_ci		osc_freq = PIC32_POSC_FREQ;
768c2ecf20Sopenharmony_ci		break;
778c2ecf20Sopenharmony_ci	default:
788c2ecf20Sopenharmony_ci		break;
798c2ecf20Sopenharmony_ci	}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	iounmap(osc_base);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	return osc_freq;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ciu32 pic32_get_pbclk(int bus)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	u32 clk_freq;
898c2ecf20Sopenharmony_ci	void __iomem *osc_base = ioremap(PIC32_BASE_OSC, 0x200);
908c2ecf20Sopenharmony_ci	u32 pbxdiv = PB1DIV + ((bus - 1) * 0x10);
918c2ecf20Sopenharmony_ci	u32 pbdiv = (__raw_readl(osc_base + pbxdiv) & PB_MASK) + 1;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	iounmap(osc_base);
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	clk_freq = pic32_get_sysclk();
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return clk_freq / pbdiv;
988c2ecf20Sopenharmony_ci}
99