1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * PowerQUICC II support functions |
4 | * |
5 | * Author: Scott Wood <scottwood@freescale.com> |
6 | * |
7 | * Copyright (c) 2007 Freescale Semiconductor, Inc. |
8 | */ |
9 | |
10 | #include "ops.h" |
11 | #include "types.h" |
12 | #include "fsl-soc.h" |
13 | #include "pq2.h" |
14 | #include "stdio.h" |
15 | #include "io.h" |
16 | |
17 | #define PQ2_SCCR (0x10c80/4) /* System Clock Configuration Register */ |
18 | #define PQ2_SCMR (0x10c88/4) /* System Clock Mode Register */ |
19 | |
20 | static int pq2_corecnf_map[] = { |
21 | 3, 2, 2, 2, 4, 4, 5, 9, 6, 11, 8, 10, 3, 12, 7, -1, |
22 | 6, 5, 13, 2, 14, 4, 15, 9, 0, 11, 8, 10, 16, 12, 7, -1 |
23 | }; |
24 | |
25 | /* Get various clocks from crystal frequency. |
26 | * Returns zero on failure and non-zero on success. |
27 | */ |
28 | int pq2_get_clocks(u32 crystal, u32 *sysfreq, u32 *corefreq, |
29 | u32 *timebase, u32 *brgfreq) |
30 | { |
31 | u32 *immr; |
32 | u32 sccr, scmr, mainclk, busclk; |
33 | int corecnf, busdf, plldf, pllmf, dfbrg; |
34 | |
35 | immr = fsl_get_immr(); |
36 | if (!immr) { |
37 | printf(fmt: "pq2_get_clocks: Couldn't get IMMR base.\r\n" ); |
38 | return 0; |
39 | } |
40 | |
41 | sccr = in_be32(addr: &immr[PQ2_SCCR]); |
42 | scmr = in_be32(addr: &immr[PQ2_SCMR]); |
43 | |
44 | dfbrg = sccr & 3; |
45 | corecnf = (scmr >> 24) & 0x1f; |
46 | busdf = (scmr >> 20) & 0xf; |
47 | plldf = (scmr >> 12) & 1; |
48 | pllmf = scmr & 0xfff; |
49 | |
50 | mainclk = crystal * (pllmf + 1) / (plldf + 1); |
51 | busclk = mainclk / (busdf + 1); |
52 | |
53 | if (sysfreq) |
54 | *sysfreq = mainclk / 2; |
55 | if (timebase) |
56 | *timebase = busclk / 4; |
57 | if (brgfreq) |
58 | *brgfreq = mainclk / (1 << ((dfbrg + 1) * 2)); |
59 | |
60 | if (corefreq) { |
61 | int coremult = pq2_corecnf_map[corecnf]; |
62 | |
63 | if (coremult < 0) |
64 | *corefreq = mainclk / 2; |
65 | else if (coremult == 0) |
66 | return 0; |
67 | else |
68 | *corefreq = busclk * coremult / 2; |
69 | } |
70 | |
71 | return 1; |
72 | } |
73 | |
74 | /* Set common device tree fields based on the given clock frequencies. */ |
75 | void pq2_set_clocks(u32 sysfreq, u32 corefreq, u32 timebase, u32 brgfreq) |
76 | { |
77 | void *node; |
78 | |
79 | dt_fixup_cpu_clocks(cpufreq: corefreq, tbfreq: timebase, busfreq: sysfreq); |
80 | |
81 | node = finddevice(name: "/soc/cpm" ); |
82 | if (node) |
83 | setprop(devp: node, name: "clock-frequency" , buf: &sysfreq, buflen: 4); |
84 | |
85 | node = finddevice(name: "/soc/cpm/brg" ); |
86 | if (node) |
87 | setprop(devp: node, name: "clock-frequency" , buf: &brgfreq, buflen: 4); |
88 | } |
89 | |
90 | int pq2_fixup_clocks(u32 crystal) |
91 | { |
92 | u32 sysfreq, corefreq, timebase, brgfreq; |
93 | |
94 | if (!pq2_get_clocks(crystal, sysfreq: &sysfreq, corefreq: &corefreq, timebase: &timebase, brgfreq: &brgfreq)) |
95 | return 0; |
96 | |
97 | pq2_set_clocks(sysfreq, corefreq, timebase, brgfreq); |
98 | return 1; |
99 | } |
100 | |