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
19static int mx5_cpu_rev = -1;
20
21#define IIM_SREV 0x24
22
23static 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(np, 0);
31	of_node_put(np);
32	WARN_ON(!iim_base);
33
34	srev = readl(iim_base + IIM_SREV) & 0xff;
35
36	iounmap(iim_base);
37
38	return srev;
39}
40
41static int get_mx51_srev(void)
42{
43	u32 rev = imx5_read_srev_reg("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 */
59int mx51_revision(void)
60{
61	if (mx5_cpu_rev == -1)
62		mx5_cpu_rev = get_mx51_srev();
63
64	return mx5_cpu_rev;
65}
66EXPORT_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 */
75int __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
87static int get_mx53_srev(void)
88{
89	u32 rev = imx5_read_srev_reg("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 */
107int mx53_revision(void)
108{
109	if (mx5_cpu_rev == -1)
110		mx5_cpu_rev = get_mx53_srev();
111
112	return mx5_cpu_rev;
113}
114EXPORT_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 */
126void __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, "arm,cortex-a8-pmu");
136	if (!np)
137		return;
138
139	if (!of_property_read_bool(np, "secure-reg-access"))
140		goto exit;
141
142	of_node_put(np);
143
144	np = of_find_compatible_node(NULL, NULL, "fsl,imx51-tigerp");
145	if (!np)
146		return;
147
148	tigerp_base = of_iomap(np, 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(tigerp_base);
156exit:
157	of_node_put(np);
158
159}
160