1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved. |
4 | * |
5 | * This file contains the CPU initialization code. |
6 | */ |
7 | |
8 | #include <linux/types.h> |
9 | #include <linux/kernel.h> |
10 | #include <linux/init.h> |
11 | #include <linux/module.h> |
12 | #include <linux/io.h> |
13 | #include <linux/of.h> |
14 | #include <linux/of_address.h> |
15 | |
16 | #include "hardware.h" |
17 | #include "common.h" |
18 | |
19 | static int mx5_cpu_rev = -1; |
20 | |
21 | #define IIM_SREV 0x24 |
22 | |
23 | static u32 imx5_read_srev_reg(const char *compat) |
24 | { |
25 | void __iomem *iim_base; |
26 | struct device_node *np; |
27 | u32 srev; |
28 | |
29 | np = of_find_compatible_node(NULL, NULL, compat); |
30 | iim_base = of_iomap(node: np, index: 0); |
31 | of_node_put(node: np); |
32 | WARN_ON(!iim_base); |
33 | |
34 | srev = readl(addr: iim_base + IIM_SREV) & 0xff; |
35 | |
36 | iounmap(addr: iim_base); |
37 | |
38 | return srev; |
39 | } |
40 | |
41 | static int get_mx51_srev(void) |
42 | { |
43 | u32 rev = imx5_read_srev_reg(compat: "fsl,imx51-iim" ); |
44 | |
45 | switch (rev) { |
46 | case 0x0: |
47 | return IMX_CHIP_REVISION_2_0; |
48 | case 0x10: |
49 | return IMX_CHIP_REVISION_3_0; |
50 | default: |
51 | return IMX_CHIP_REVISION_UNKNOWN; |
52 | } |
53 | } |
54 | |
55 | /* |
56 | * Returns: |
57 | * the silicon revision of the cpu |
58 | */ |
59 | int mx51_revision(void) |
60 | { |
61 | if (mx5_cpu_rev == -1) |
62 | mx5_cpu_rev = get_mx51_srev(); |
63 | |
64 | return mx5_cpu_rev; |
65 | } |
66 | EXPORT_SYMBOL(mx51_revision); |
67 | |
68 | #ifdef CONFIG_NEON |
69 | |
70 | /* |
71 | * All versions of the silicon before Rev. 3 have broken NEON implementations. |
72 | * Dependent on link order - so the assumption is that vfp_init is called |
73 | * before us. |
74 | */ |
75 | int __init mx51_neon_fixup(void) |
76 | { |
77 | if (mx51_revision() < IMX_CHIP_REVISION_3_0 && |
78 | (elf_hwcap & HWCAP_NEON)) { |
79 | elf_hwcap &= ~HWCAP_NEON; |
80 | pr_info("Turning off NEON support, detected broken NEON implementation\n" ); |
81 | } |
82 | return 0; |
83 | } |
84 | |
85 | #endif |
86 | |
87 | static int get_mx53_srev(void) |
88 | { |
89 | u32 rev = imx5_read_srev_reg(compat: "fsl,imx53-iim" ); |
90 | |
91 | switch (rev) { |
92 | case 0x0: |
93 | return IMX_CHIP_REVISION_1_0; |
94 | case 0x2: |
95 | return IMX_CHIP_REVISION_2_0; |
96 | case 0x3: |
97 | return IMX_CHIP_REVISION_2_1; |
98 | default: |
99 | return IMX_CHIP_REVISION_UNKNOWN; |
100 | } |
101 | } |
102 | |
103 | /* |
104 | * Returns: |
105 | * the silicon revision of the cpu |
106 | */ |
107 | int mx53_revision(void) |
108 | { |
109 | if (mx5_cpu_rev == -1) |
110 | mx5_cpu_rev = get_mx53_srev(); |
111 | |
112 | return mx5_cpu_rev; |
113 | } |
114 | EXPORT_SYMBOL(mx53_revision); |
115 | |
116 | #define ARM_GPC 0x4 |
117 | #define DBGEN BIT(16) |
118 | |
119 | /* |
120 | * This enables the DBGEN bit in ARM_GPC register, which is |
121 | * required for accessing some performance counter features. |
122 | * Technically it is only required while perf is used, but to |
123 | * keep the source code simple we just enable it all the time |
124 | * when the kernel configuration allows using the feature. |
125 | */ |
126 | void __init imx5_pmu_init(void) |
127 | { |
128 | void __iomem *tigerp_base; |
129 | struct device_node *np; |
130 | u32 gpc; |
131 | |
132 | if (!IS_ENABLED(CONFIG_ARM_PMU)) |
133 | return; |
134 | |
135 | np = of_find_compatible_node(NULL, NULL, compat: "arm,cortex-a8-pmu" ); |
136 | if (!np) |
137 | return; |
138 | |
139 | if (!of_property_read_bool(np, propname: "secure-reg-access" )) |
140 | goto exit; |
141 | |
142 | of_node_put(node: np); |
143 | |
144 | np = of_find_compatible_node(NULL, NULL, compat: "fsl,imx51-tigerp" ); |
145 | if (!np) |
146 | return; |
147 | |
148 | tigerp_base = of_iomap(node: np, index: 0); |
149 | if (!tigerp_base) |
150 | goto exit; |
151 | |
152 | gpc = readl_relaxed(tigerp_base + ARM_GPC); |
153 | gpc |= DBGEN; |
154 | writel_relaxed(gpc, tigerp_base + ARM_GPC); |
155 | iounmap(addr: tigerp_base); |
156 | exit: |
157 | of_node_put(node: np); |
158 | |
159 | } |
160 | |