162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * This file contains the CPU initialization code.
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/types.h>
962306a36Sopenharmony_ci#include <linux/kernel.h>
1062306a36Sopenharmony_ci#include <linux/init.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/io.h>
1362306a36Sopenharmony_ci#include <linux/of.h>
1462306a36Sopenharmony_ci#include <linux/of_address.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "hardware.h"
1762306a36Sopenharmony_ci#include "common.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic int mx5_cpu_rev = -1;
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#define IIM_SREV 0x24
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic u32 imx5_read_srev_reg(const char *compat)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	void __iomem *iim_base;
2662306a36Sopenharmony_ci	struct device_node *np;
2762306a36Sopenharmony_ci	u32 srev;
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, compat);
3062306a36Sopenharmony_ci	iim_base = of_iomap(np, 0);
3162306a36Sopenharmony_ci	of_node_put(np);
3262306a36Sopenharmony_ci	WARN_ON(!iim_base);
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci	srev = readl(iim_base + IIM_SREV) & 0xff;
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	iounmap(iim_base);
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci	return srev;
3962306a36Sopenharmony_ci}
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_cistatic int get_mx51_srev(void)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	u32 rev = imx5_read_srev_reg("fsl,imx51-iim");
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	switch (rev) {
4662306a36Sopenharmony_ci	case 0x0:
4762306a36Sopenharmony_ci		return IMX_CHIP_REVISION_2_0;
4862306a36Sopenharmony_ci	case 0x10:
4962306a36Sopenharmony_ci		return IMX_CHIP_REVISION_3_0;
5062306a36Sopenharmony_ci	default:
5162306a36Sopenharmony_ci		return IMX_CHIP_REVISION_UNKNOWN;
5262306a36Sopenharmony_ci	}
5362306a36Sopenharmony_ci}
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci/*
5662306a36Sopenharmony_ci * Returns:
5762306a36Sopenharmony_ci *	the silicon revision of the cpu
5862306a36Sopenharmony_ci */
5962306a36Sopenharmony_ciint mx51_revision(void)
6062306a36Sopenharmony_ci{
6162306a36Sopenharmony_ci	if (mx5_cpu_rev == -1)
6262306a36Sopenharmony_ci		mx5_cpu_rev = get_mx51_srev();
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	return mx5_cpu_rev;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ciEXPORT_SYMBOL(mx51_revision);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci#ifdef CONFIG_NEON
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci/*
7162306a36Sopenharmony_ci * All versions of the silicon before Rev. 3 have broken NEON implementations.
7262306a36Sopenharmony_ci * Dependent on link order - so the assumption is that vfp_init is called
7362306a36Sopenharmony_ci * before us.
7462306a36Sopenharmony_ci */
7562306a36Sopenharmony_ciint __init mx51_neon_fixup(void)
7662306a36Sopenharmony_ci{
7762306a36Sopenharmony_ci	if (mx51_revision() < IMX_CHIP_REVISION_3_0 &&
7862306a36Sopenharmony_ci			(elf_hwcap & HWCAP_NEON)) {
7962306a36Sopenharmony_ci		elf_hwcap &= ~HWCAP_NEON;
8062306a36Sopenharmony_ci		pr_info("Turning off NEON support, detected broken NEON implementation\n");
8162306a36Sopenharmony_ci	}
8262306a36Sopenharmony_ci	return 0;
8362306a36Sopenharmony_ci}
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci#endif
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int get_mx53_srev(void)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	u32 rev = imx5_read_srev_reg("fsl,imx53-iim");
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci	switch (rev) {
9262306a36Sopenharmony_ci	case 0x0:
9362306a36Sopenharmony_ci		return IMX_CHIP_REVISION_1_0;
9462306a36Sopenharmony_ci	case 0x2:
9562306a36Sopenharmony_ci		return IMX_CHIP_REVISION_2_0;
9662306a36Sopenharmony_ci	case 0x3:
9762306a36Sopenharmony_ci		return IMX_CHIP_REVISION_2_1;
9862306a36Sopenharmony_ci	default:
9962306a36Sopenharmony_ci		return IMX_CHIP_REVISION_UNKNOWN;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci/*
10462306a36Sopenharmony_ci * Returns:
10562306a36Sopenharmony_ci *	the silicon revision of the cpu
10662306a36Sopenharmony_ci */
10762306a36Sopenharmony_ciint mx53_revision(void)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	if (mx5_cpu_rev == -1)
11062306a36Sopenharmony_ci		mx5_cpu_rev = get_mx53_srev();
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	return mx5_cpu_rev;
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ciEXPORT_SYMBOL(mx53_revision);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci#define ARM_GPC		0x4
11762306a36Sopenharmony_ci#define DBGEN		BIT(16)
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*
12062306a36Sopenharmony_ci * This enables the DBGEN bit in ARM_GPC register, which is
12162306a36Sopenharmony_ci * required for accessing some performance counter features.
12262306a36Sopenharmony_ci * Technically it is only required while perf is used, but to
12362306a36Sopenharmony_ci * keep the source code simple we just enable it all the time
12462306a36Sopenharmony_ci * when the kernel configuration allows using the feature.
12562306a36Sopenharmony_ci */
12662306a36Sopenharmony_civoid __init imx5_pmu_init(void)
12762306a36Sopenharmony_ci{
12862306a36Sopenharmony_ci	void __iomem *tigerp_base;
12962306a36Sopenharmony_ci	struct device_node *np;
13062306a36Sopenharmony_ci	u32 gpc;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	if (!IS_ENABLED(CONFIG_ARM_PMU))
13362306a36Sopenharmony_ci		return;
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "arm,cortex-a8-pmu");
13662306a36Sopenharmony_ci	if (!np)
13762306a36Sopenharmony_ci		return;
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci	if (!of_property_read_bool(np, "secure-reg-access"))
14062306a36Sopenharmony_ci		goto exit;
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	of_node_put(np);
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	np = of_find_compatible_node(NULL, NULL, "fsl,imx51-tigerp");
14562306a36Sopenharmony_ci	if (!np)
14662306a36Sopenharmony_ci		return;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	tigerp_base = of_iomap(np, 0);
14962306a36Sopenharmony_ci	if (!tigerp_base)
15062306a36Sopenharmony_ci		goto exit;
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	gpc = readl_relaxed(tigerp_base + ARM_GPC);
15362306a36Sopenharmony_ci	gpc |= DBGEN;
15462306a36Sopenharmony_ci	writel_relaxed(gpc, tigerp_base + ARM_GPC);
15562306a36Sopenharmony_ci	iounmap(tigerp_base);
15662306a36Sopenharmony_ciexit:
15762306a36Sopenharmony_ci	of_node_put(np);
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci}
160