GNU Linux-libre 6.7.9-gnu
[releases.git] / arch / mips / pic32 / pic32mzda / early_clk.c
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
28 u32 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
86 u32 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 }