18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2014, NVIDIA CORPORATION.  All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/of.h>
88c2ecf20Sopenharmony_ci#include <linux/of_address.h>
98c2ecf20Sopenharmony_ci#include <linux/io.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci#include <soc/tegra/fuse.h>
128c2ecf20Sopenharmony_ci#include <soc/tegra/common.h>
138c2ecf20Sopenharmony_ci
148c2ecf20Sopenharmony_ci#include "fuse.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#define FUSE_SKU_INFO	0x10
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#define PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT	4
198c2ecf20Sopenharmony_ci#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG	\
208c2ecf20Sopenharmony_ci	(0xf << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
218c2ecf20Sopenharmony_ci#define PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT	\
228c2ecf20Sopenharmony_ci	(0x3 << PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT)
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistatic bool long_ram_code;
258c2ecf20Sopenharmony_cistatic u32 strapping;
268c2ecf20Sopenharmony_cistatic u32 chipid;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_ciu32 tegra_read_chipid(void)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	WARN(!chipid, "Tegra APB MISC not yet available\n");
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci	return chipid;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ciu8 tegra_get_chip_id(void)
368c2ecf20Sopenharmony_ci{
378c2ecf20Sopenharmony_ci	return (tegra_read_chipid() >> 8) & 0xff;
388c2ecf20Sopenharmony_ci}
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_ciu8 tegra_get_major_rev(void)
418c2ecf20Sopenharmony_ci{
428c2ecf20Sopenharmony_ci	return (tegra_read_chipid() >> 4) & 0xf;
438c2ecf20Sopenharmony_ci}
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ciu8 tegra_get_minor_rev(void)
468c2ecf20Sopenharmony_ci{
478c2ecf20Sopenharmony_ci	return (tegra_read_chipid() >> 16) & 0xf;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ciu8 tegra_get_platform(void)
518c2ecf20Sopenharmony_ci{
528c2ecf20Sopenharmony_ci	return (tegra_read_chipid() >> 20) & 0xf;
538c2ecf20Sopenharmony_ci}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cibool tegra_is_silicon(void)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	switch (tegra_get_chip_id()) {
588c2ecf20Sopenharmony_ci	case TEGRA194:
598c2ecf20Sopenharmony_ci	case TEGRA234:
608c2ecf20Sopenharmony_ci		if (tegra_get_platform() == 0)
618c2ecf20Sopenharmony_ci			return true;
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci		return false;
648c2ecf20Sopenharmony_ci	}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	/*
678c2ecf20Sopenharmony_ci	 * Chips prior to Tegra194 have a different way of determining whether
688c2ecf20Sopenharmony_ci	 * they are silicon or not. Since we never supported simulation on the
698c2ecf20Sopenharmony_ci	 * older Tegra chips, don't bother extracting the information and just
708c2ecf20Sopenharmony_ci	 * report that we're running on silicon.
718c2ecf20Sopenharmony_ci	 */
728c2ecf20Sopenharmony_ci	return true;
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ciu32 tegra_read_straps(void)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	WARN(!chipid, "Tegra ABP MISC not yet available\n");
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	return strapping;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ciu32 tegra_read_ram_code(void)
838c2ecf20Sopenharmony_ci{
848c2ecf20Sopenharmony_ci	u32 straps = tegra_read_straps();
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (long_ram_code)
878c2ecf20Sopenharmony_ci		straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_LONG;
888c2ecf20Sopenharmony_ci	else
898c2ecf20Sopenharmony_ci		straps &= PMC_STRAPPING_OPT_A_RAM_CODE_MASK_SHORT;
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci	return straps >> PMC_STRAPPING_OPT_A_RAM_CODE_SHIFT;
928c2ecf20Sopenharmony_ci}
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cistatic const struct of_device_id apbmisc_match[] __initconst = {
958c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra20-apbmisc", },
968c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra186-misc", },
978c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra194-misc", },
988c2ecf20Sopenharmony_ci	{ .compatible = "nvidia,tegra234-misc", },
998c2ecf20Sopenharmony_ci	{},
1008c2ecf20Sopenharmony_ci};
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_civoid __init tegra_init_revision(void)
1038c2ecf20Sopenharmony_ci{
1048c2ecf20Sopenharmony_ci	u8 chip_id, minor_rev;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	chip_id = tegra_get_chip_id();
1078c2ecf20Sopenharmony_ci	minor_rev = tegra_get_minor_rev();
1088c2ecf20Sopenharmony_ci
1098c2ecf20Sopenharmony_ci	switch (minor_rev) {
1108c2ecf20Sopenharmony_ci	case 1:
1118c2ecf20Sopenharmony_ci		tegra_sku_info.revision = TEGRA_REVISION_A01;
1128c2ecf20Sopenharmony_ci		break;
1138c2ecf20Sopenharmony_ci	case 2:
1148c2ecf20Sopenharmony_ci		tegra_sku_info.revision = TEGRA_REVISION_A02;
1158c2ecf20Sopenharmony_ci		break;
1168c2ecf20Sopenharmony_ci	case 3:
1178c2ecf20Sopenharmony_ci		if (chip_id == TEGRA20 && (tegra_fuse_read_spare(18) ||
1188c2ecf20Sopenharmony_ci					   tegra_fuse_read_spare(19)))
1198c2ecf20Sopenharmony_ci			tegra_sku_info.revision = TEGRA_REVISION_A03p;
1208c2ecf20Sopenharmony_ci		else
1218c2ecf20Sopenharmony_ci			tegra_sku_info.revision = TEGRA_REVISION_A03;
1228c2ecf20Sopenharmony_ci		break;
1238c2ecf20Sopenharmony_ci	case 4:
1248c2ecf20Sopenharmony_ci		tegra_sku_info.revision = TEGRA_REVISION_A04;
1258c2ecf20Sopenharmony_ci		break;
1268c2ecf20Sopenharmony_ci	default:
1278c2ecf20Sopenharmony_ci		tegra_sku_info.revision = TEGRA_REVISION_UNKNOWN;
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	tegra_sku_info.sku_id = tegra_fuse_read_early(FUSE_SKU_INFO);
1318c2ecf20Sopenharmony_ci}
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_civoid __init tegra_init_apbmisc(void)
1348c2ecf20Sopenharmony_ci{
1358c2ecf20Sopenharmony_ci	void __iomem *apbmisc_base, *strapping_base;
1368c2ecf20Sopenharmony_ci	struct resource apbmisc, straps;
1378c2ecf20Sopenharmony_ci	struct device_node *np;
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	np = of_find_matching_node(NULL, apbmisc_match);
1408c2ecf20Sopenharmony_ci	if (!np) {
1418c2ecf20Sopenharmony_ci		/*
1428c2ecf20Sopenharmony_ci		 * Fall back to legacy initialization for 32-bit ARM only. All
1438c2ecf20Sopenharmony_ci		 * 64-bit ARM device tree files for Tegra are required to have
1448c2ecf20Sopenharmony_ci		 * an APBMISC node.
1458c2ecf20Sopenharmony_ci		 *
1468c2ecf20Sopenharmony_ci		 * This is for backwards-compatibility with old device trees
1478c2ecf20Sopenharmony_ci		 * that didn't contain an APBMISC node.
1488c2ecf20Sopenharmony_ci		 */
1498c2ecf20Sopenharmony_ci		if (IS_ENABLED(CONFIG_ARM) && soc_is_tegra()) {
1508c2ecf20Sopenharmony_ci			/* APBMISC registers (chip revision, ...) */
1518c2ecf20Sopenharmony_ci			apbmisc.start = 0x70000800;
1528c2ecf20Sopenharmony_ci			apbmisc.end = 0x70000863;
1538c2ecf20Sopenharmony_ci			apbmisc.flags = IORESOURCE_MEM;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci			/* strapping options */
1568c2ecf20Sopenharmony_ci			if (of_machine_is_compatible("nvidia,tegra124")) {
1578c2ecf20Sopenharmony_ci				straps.start = 0x7000e864;
1588c2ecf20Sopenharmony_ci				straps.end = 0x7000e867;
1598c2ecf20Sopenharmony_ci			} else {
1608c2ecf20Sopenharmony_ci				straps.start = 0x70000008;
1618c2ecf20Sopenharmony_ci				straps.end = 0x7000000b;
1628c2ecf20Sopenharmony_ci			}
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci			straps.flags = IORESOURCE_MEM;
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci			pr_warn("Using APBMISC region %pR\n", &apbmisc);
1678c2ecf20Sopenharmony_ci			pr_warn("Using strapping options registers %pR\n",
1688c2ecf20Sopenharmony_ci				&straps);
1698c2ecf20Sopenharmony_ci		} else {
1708c2ecf20Sopenharmony_ci			/*
1718c2ecf20Sopenharmony_ci			 * At this point we're not running on Tegra, so play
1728c2ecf20Sopenharmony_ci			 * nice with multi-platform kernels.
1738c2ecf20Sopenharmony_ci			 */
1748c2ecf20Sopenharmony_ci			return;
1758c2ecf20Sopenharmony_ci		}
1768c2ecf20Sopenharmony_ci	} else {
1778c2ecf20Sopenharmony_ci		/*
1788c2ecf20Sopenharmony_ci		 * Extract information from the device tree if we've found a
1798c2ecf20Sopenharmony_ci		 * matching node.
1808c2ecf20Sopenharmony_ci		 */
1818c2ecf20Sopenharmony_ci		if (of_address_to_resource(np, 0, &apbmisc) < 0) {
1828c2ecf20Sopenharmony_ci			pr_err("failed to get APBMISC registers\n");
1838c2ecf20Sopenharmony_ci			return;
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		if (of_address_to_resource(np, 1, &straps) < 0) {
1878c2ecf20Sopenharmony_ci			pr_err("failed to get strapping options registers\n");
1888c2ecf20Sopenharmony_ci			return;
1898c2ecf20Sopenharmony_ci		}
1908c2ecf20Sopenharmony_ci	}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	apbmisc_base = ioremap(apbmisc.start, resource_size(&apbmisc));
1938c2ecf20Sopenharmony_ci	if (!apbmisc_base) {
1948c2ecf20Sopenharmony_ci		pr_err("failed to map APBMISC registers\n");
1958c2ecf20Sopenharmony_ci	} else {
1968c2ecf20Sopenharmony_ci		chipid = readl_relaxed(apbmisc_base + 4);
1978c2ecf20Sopenharmony_ci		iounmap(apbmisc_base);
1988c2ecf20Sopenharmony_ci	}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	strapping_base = ioremap(straps.start, resource_size(&straps));
2018c2ecf20Sopenharmony_ci	if (!strapping_base) {
2028c2ecf20Sopenharmony_ci		pr_err("failed to map strapping options registers\n");
2038c2ecf20Sopenharmony_ci	} else {
2048c2ecf20Sopenharmony_ci		strapping = readl_relaxed(strapping_base);
2058c2ecf20Sopenharmony_ci		iounmap(strapping_base);
2068c2ecf20Sopenharmony_ci	}
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	long_ram_code = of_property_read_bool(np, "nvidia,long-ram-code");
2098c2ecf20Sopenharmony_ci}
210