162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * linux/arch/arm/mach-omap1/id.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * OMAP1 CPU identification code
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2004 Nokia Corporation
862306a36Sopenharmony_ci * Written by Tony Lindgren <tony@atomide.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/init.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/soc/ti/omap1-io.h>
1662306a36Sopenharmony_ci#include <asm/system_info.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "soc.h"
1962306a36Sopenharmony_ci#include "hardware.h"
2062306a36Sopenharmony_ci#include "common.h"
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#define OMAP_DIE_ID_0		0xfffe1800
2362306a36Sopenharmony_ci#define OMAP_DIE_ID_1		0xfffe1804
2462306a36Sopenharmony_ci#define OMAP_PRODUCTION_ID_0	0xfffe2000
2562306a36Sopenharmony_ci#define OMAP_PRODUCTION_ID_1	0xfffe2004
2662306a36Sopenharmony_ci#define OMAP32_ID_0		0xfffed400
2762306a36Sopenharmony_ci#define OMAP32_ID_1		0xfffed404
2862306a36Sopenharmony_ci
2962306a36Sopenharmony_cistruct omap_id {
3062306a36Sopenharmony_ci	u16	jtag_id;	/* Used to determine OMAP type */
3162306a36Sopenharmony_ci	u8	die_rev;	/* Processor revision */
3262306a36Sopenharmony_ci	u32	omap_id;	/* OMAP revision */
3362306a36Sopenharmony_ci	u32	type;		/* Cpu id bits [31:08], cpu class bits [07:00] */
3462306a36Sopenharmony_ci};
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_cistatic unsigned int omap_revision;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_ci/* Register values to detect the OMAP version */
3962306a36Sopenharmony_cistatic struct omap_id omap_ids[] __initdata = {
4062306a36Sopenharmony_ci	{ .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000},
4162306a36Sopenharmony_ci	{ .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100},
4262306a36Sopenharmony_ci	{ .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300},
4362306a36Sopenharmony_ci	{ .jtag_id = 0xb62c, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x08500000},
4462306a36Sopenharmony_ci	{ .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000},
4562306a36Sopenharmony_ci	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000},
4662306a36Sopenharmony_ci	{ .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000},
4762306a36Sopenharmony_ci	{ .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00},
4862306a36Sopenharmony_ci	{ .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00},
4962306a36Sopenharmony_ci	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
5062306a36Sopenharmony_ci	{ .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00},
5162306a36Sopenharmony_ci	{ .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000},
5262306a36Sopenharmony_ci	{ .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00},
5362306a36Sopenharmony_ci	{ .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00},
5462306a36Sopenharmony_ci	{ .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300},
5562306a36Sopenharmony_ci	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300},
5662306a36Sopenharmony_ci	{ .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300},
5762306a36Sopenharmony_ci	{ .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000},
5862306a36Sopenharmony_ci	{ .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000},
5962306a36Sopenharmony_ci	{ .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000},
6062306a36Sopenharmony_ci};
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ciunsigned int omap_rev(void)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	return omap_revision;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ciEXPORT_SYMBOL(omap_rev);
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci/*
6962306a36Sopenharmony_ci * Get OMAP type from PROD_ID.
7062306a36Sopenharmony_ci * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM.
7162306a36Sopenharmony_ci * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense.
7262306a36Sopenharmony_ci * Undocumented register in TEST BLOCK is used as fallback; This seems to
7362306a36Sopenharmony_ci * work on 1510, 1610 & 1710. The official way hopefully will work in future
7462306a36Sopenharmony_ci * processors.
7562306a36Sopenharmony_ci */
7662306a36Sopenharmony_cistatic u16 __init omap_get_jtag_id(void)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	u32 prod_id, omap_id;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	prod_id = omap_readl(OMAP_PRODUCTION_ID_1);
8162306a36Sopenharmony_ci	omap_id = omap_readl(OMAP32_ID_1);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	/* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730/850 */
8462306a36Sopenharmony_ci	if (((prod_id >> 20) == 0) || (prod_id == omap_id))
8562306a36Sopenharmony_ci		prod_id = 0;
8662306a36Sopenharmony_ci	else
8762306a36Sopenharmony_ci		prod_id &= 0xffff;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	if (prod_id)
9062306a36Sopenharmony_ci		return prod_id;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	/* Use OMAP32_ID_1 as fallback */
9362306a36Sopenharmony_ci	prod_id = ((omap_id >> 12) & 0xffff);
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_ci	return prod_id;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/*
9962306a36Sopenharmony_ci * Get OMAP revision from DIE_REV.
10062306a36Sopenharmony_ci * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID.
10162306a36Sopenharmony_ci * Undocumented register in the TEST BLOCK is used as fallback.
10262306a36Sopenharmony_ci * REVISIT: This does not seem to work on 1510
10362306a36Sopenharmony_ci */
10462306a36Sopenharmony_cistatic u8 __init omap_get_die_rev(void)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	u32 die_rev;
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_ci	die_rev = omap_readl(OMAP_DIE_ID_1);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci	/* Check for broken OMAP_DIE_ID on early 1710 */
11162306a36Sopenharmony_ci	if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id())
11262306a36Sopenharmony_ci		die_rev = 0;
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	die_rev = (die_rev >> 17) & 0xf;
11562306a36Sopenharmony_ci	if (die_rev)
11662306a36Sopenharmony_ci		return die_rev;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	return die_rev;
12162306a36Sopenharmony_ci}
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_civoid __init omap_check_revision(void)
12462306a36Sopenharmony_ci{
12562306a36Sopenharmony_ci	int i;
12662306a36Sopenharmony_ci	u16 jtag_id;
12762306a36Sopenharmony_ci	u8 die_rev;
12862306a36Sopenharmony_ci	u32 omap_id;
12962306a36Sopenharmony_ci	u8 cpu_type;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	jtag_id = omap_get_jtag_id();
13262306a36Sopenharmony_ci	die_rev = omap_get_die_rev();
13362306a36Sopenharmony_ci	omap_id = omap_readl(OMAP32_ID_0);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci#ifdef DEBUG
13662306a36Sopenharmony_ci	printk(KERN_DEBUG "OMAP_DIE_ID_0: 0x%08x\n", omap_readl(OMAP_DIE_ID_0));
13762306a36Sopenharmony_ci	printk(KERN_DEBUG "OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n",
13862306a36Sopenharmony_ci		omap_readl(OMAP_DIE_ID_1),
13962306a36Sopenharmony_ci	       (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf);
14062306a36Sopenharmony_ci	printk(KERN_DEBUG "OMAP_PRODUCTION_ID_0: 0x%08x\n",
14162306a36Sopenharmony_ci		omap_readl(OMAP_PRODUCTION_ID_0));
14262306a36Sopenharmony_ci	printk(KERN_DEBUG "OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n",
14362306a36Sopenharmony_ci		omap_readl(OMAP_PRODUCTION_ID_1),
14462306a36Sopenharmony_ci		omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff);
14562306a36Sopenharmony_ci	printk(KERN_DEBUG "OMAP32_ID_0: 0x%08x\n", omap_readl(OMAP32_ID_0));
14662306a36Sopenharmony_ci	printk(KERN_DEBUG "OMAP32_ID_1: 0x%08x\n", omap_readl(OMAP32_ID_1));
14762306a36Sopenharmony_ci	printk(KERN_DEBUG "JTAG_ID: 0x%04x DIE_REV: %i\n", jtag_id, die_rev);
14862306a36Sopenharmony_ci#endif
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	system_serial_high = omap_readl(OMAP_DIE_ID_0);
15162306a36Sopenharmony_ci	system_serial_low = omap_readl(OMAP_DIE_ID_1);
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/* First check only the major version in a safe way */
15462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
15562306a36Sopenharmony_ci		if (jtag_id == (omap_ids[i].jtag_id)) {
15662306a36Sopenharmony_ci			omap_revision = omap_ids[i].type;
15762306a36Sopenharmony_ci			break;
15862306a36Sopenharmony_ci		}
15962306a36Sopenharmony_ci	}
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	/* Check if we can find the die revision */
16262306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
16362306a36Sopenharmony_ci		if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) {
16462306a36Sopenharmony_ci			omap_revision = omap_ids[i].type;
16562306a36Sopenharmony_ci			break;
16662306a36Sopenharmony_ci		}
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	/* Finally check also the omap_id */
17062306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(omap_ids); i++) {
17162306a36Sopenharmony_ci		if (jtag_id == omap_ids[i].jtag_id
17262306a36Sopenharmony_ci		    && die_rev == omap_ids[i].die_rev
17362306a36Sopenharmony_ci		    && omap_id == omap_ids[i].omap_id) {
17462306a36Sopenharmony_ci			omap_revision = omap_ids[i].type;
17562306a36Sopenharmony_ci			break;
17662306a36Sopenharmony_ci		}
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	/* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
18062306a36Sopenharmony_ci	cpu_type = omap_revision >> 24;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	switch (cpu_type) {
18362306a36Sopenharmony_ci	case 0x07:
18462306a36Sopenharmony_ci	case 0x08:
18562306a36Sopenharmony_ci		omap_revision |= 0x07;
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case 0x03:
18862306a36Sopenharmony_ci	case 0x15:
18962306a36Sopenharmony_ci		omap_revision |= 0x15;
19062306a36Sopenharmony_ci		break;
19162306a36Sopenharmony_ci	case 0x16:
19262306a36Sopenharmony_ci	case 0x17:
19362306a36Sopenharmony_ci		omap_revision |= 0x16;
19462306a36Sopenharmony_ci		break;
19562306a36Sopenharmony_ci	default:
19662306a36Sopenharmony_ci		printk(KERN_INFO "Unknown OMAP cpu type: 0x%02x\n", cpu_type);
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	pr_info("OMAP%04x", omap_revision >> 16);
20062306a36Sopenharmony_ci	if ((omap_revision >> 8) & 0xff)
20162306a36Sopenharmony_ci		pr_cont("%x", (omap_revision >> 8) & 0xff);
20262306a36Sopenharmony_ci	pr_cont(" revision %i handled as %02xxx id: %08x%08x\n",
20362306a36Sopenharmony_ci	       die_rev, omap_revision & 0xff, system_serial_low,
20462306a36Sopenharmony_ci	       system_serial_high);
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
207