1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * linux/arch/arm/mach-omap1/id.c |
4 | * |
5 | * OMAP1 CPU identification code |
6 | * |
7 | * Copyright (C) 2004 Nokia Corporation |
8 | * Written by Tony Lindgren <tony@atomide.com> |
9 | */ |
10 | |
11 | #include <linux/module.h> |
12 | #include <linux/kernel.h> |
13 | #include <linux/init.h> |
14 | #include <linux/io.h> |
15 | #include <linux/soc/ti/omap1-io.h> |
16 | #include <asm/system_info.h> |
17 | |
18 | #include "soc.h" |
19 | #include "hardware.h" |
20 | #include "common.h" |
21 | |
22 | #define OMAP_DIE_ID_0 0xfffe1800 |
23 | #define OMAP_DIE_ID_1 0xfffe1804 |
24 | #define OMAP_PRODUCTION_ID_0 0xfffe2000 |
25 | #define OMAP_PRODUCTION_ID_1 0xfffe2004 |
26 | #define OMAP32_ID_0 0xfffed400 |
27 | #define OMAP32_ID_1 0xfffed404 |
28 | |
29 | struct omap_id { |
30 | u16 jtag_id; /* Used to determine OMAP type */ |
31 | u8 die_rev; /* Processor revision */ |
32 | u32 omap_id; /* OMAP revision */ |
33 | u32 type; /* Cpu id bits [31:08], cpu class bits [07:00] */ |
34 | }; |
35 | |
36 | static unsigned int omap_revision; |
37 | |
38 | /* Register values to detect the OMAP version */ |
39 | static struct omap_id omap_ids[] __initdata = { |
40 | { .jtag_id = 0xb574, .die_rev = 0x2, .omap_id = 0x03310315, .type = 0x03100000}, |
41 | { .jtag_id = 0x355f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300100}, |
42 | { .jtag_id = 0xb55f, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x07300300}, |
43 | { .jtag_id = 0xb62c, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x08500000}, |
44 | { .jtag_id = 0xb470, .die_rev = 0x0, .omap_id = 0x03310100, .type = 0x15100000}, |
45 | { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320000, .type = 0x16100000}, |
46 | { .jtag_id = 0xb576, .die_rev = 0x2, .omap_id = 0x03320100, .type = 0x16110000}, |
47 | { .jtag_id = 0xb576, .die_rev = 0x3, .omap_id = 0x03320100, .type = 0x16100c00}, |
48 | { .jtag_id = 0xb576, .die_rev = 0x0, .omap_id = 0x03320200, .type = 0x16100d00}, |
49 | { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, |
50 | { .jtag_id = 0xb613, .die_rev = 0x0, .omap_id = 0x03320300, .type = 0x1610ef00}, |
51 | { .jtag_id = 0xb576, .die_rev = 0x1, .omap_id = 0x03320100, .type = 0x16110000}, |
52 | { .jtag_id = 0xb58c, .die_rev = 0x2, .omap_id = 0x03320200, .type = 0x16110b00}, |
53 | { .jtag_id = 0xb58c, .die_rev = 0x3, .omap_id = 0x03320200, .type = 0x16110c00}, |
54 | { .jtag_id = 0xb65f, .die_rev = 0x0, .omap_id = 0x03320400, .type = 0x16212300}, |
55 | { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320400, .type = 0x16212300}, |
56 | { .jtag_id = 0xb65f, .die_rev = 0x1, .omap_id = 0x03320500, .type = 0x16212300}, |
57 | { .jtag_id = 0xb5f7, .die_rev = 0x0, .omap_id = 0x03330000, .type = 0x17100000}, |
58 | { .jtag_id = 0xb5f7, .die_rev = 0x1, .omap_id = 0x03330100, .type = 0x17100000}, |
59 | { .jtag_id = 0xb5f7, .die_rev = 0x2, .omap_id = 0x03330100, .type = 0x17100000}, |
60 | }; |
61 | |
62 | unsigned int omap_rev(void) |
63 | { |
64 | return omap_revision; |
65 | } |
66 | EXPORT_SYMBOL(omap_rev); |
67 | |
68 | /* |
69 | * Get OMAP type from PROD_ID. |
70 | * 1710 has the PROD_ID in bits 15:00, not in 16:01 as documented in TRM. |
71 | * 1510 PROD_ID is empty, and 1610 PROD_ID does not make sense. |
72 | * Undocumented register in TEST BLOCK is used as fallback; This seems to |
73 | * work on 1510, 1610 & 1710. The official way hopefully will work in future |
74 | * processors. |
75 | */ |
76 | static u16 __init omap_get_jtag_id(void) |
77 | { |
78 | u32 prod_id, omap_id; |
79 | |
80 | prod_id = omap_readl(OMAP_PRODUCTION_ID_1); |
81 | omap_id = omap_readl(OMAP32_ID_1); |
82 | |
83 | /* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730/850 */ |
84 | if (((prod_id >> 20) == 0) || (prod_id == omap_id)) |
85 | prod_id = 0; |
86 | else |
87 | prod_id &= 0xffff; |
88 | |
89 | if (prod_id) |
90 | return prod_id; |
91 | |
92 | /* Use OMAP32_ID_1 as fallback */ |
93 | prod_id = ((omap_id >> 12) & 0xffff); |
94 | |
95 | return prod_id; |
96 | } |
97 | |
98 | /* |
99 | * Get OMAP revision from DIE_REV. |
100 | * Early 1710 processors may have broken OMAP_DIE_ID, it contains PROD_ID. |
101 | * Undocumented register in the TEST BLOCK is used as fallback. |
102 | * REVISIT: This does not seem to work on 1510 |
103 | */ |
104 | static u8 __init omap_get_die_rev(void) |
105 | { |
106 | u32 die_rev; |
107 | |
108 | die_rev = omap_readl(OMAP_DIE_ID_1); |
109 | |
110 | /* Check for broken OMAP_DIE_ID on early 1710 */ |
111 | if (((die_rev >> 12) & 0xffff) == omap_get_jtag_id()) |
112 | die_rev = 0; |
113 | |
114 | die_rev = (die_rev >> 17) & 0xf; |
115 | if (die_rev) |
116 | return die_rev; |
117 | |
118 | die_rev = (omap_readl(OMAP32_ID_1) >> 28) & 0xf; |
119 | |
120 | return die_rev; |
121 | } |
122 | |
123 | void __init omap_check_revision(void) |
124 | { |
125 | int i; |
126 | u16 jtag_id; |
127 | u8 die_rev; |
128 | u32 omap_id; |
129 | u8 cpu_type; |
130 | |
131 | jtag_id = omap_get_jtag_id(); |
132 | die_rev = omap_get_die_rev(); |
133 | omap_id = omap_readl(OMAP32_ID_0); |
134 | |
135 | #ifdef DEBUG |
136 | printk(KERN_DEBUG "OMAP_DIE_ID_0: 0x%08x\n" , omap_readl(OMAP_DIE_ID_0)); |
137 | printk(KERN_DEBUG "OMAP_DIE_ID_1: 0x%08x DIE_REV: %i\n" , |
138 | omap_readl(OMAP_DIE_ID_1), |
139 | (omap_readl(OMAP_DIE_ID_1) >> 17) & 0xf); |
140 | printk(KERN_DEBUG "OMAP_PRODUCTION_ID_0: 0x%08x\n" , |
141 | omap_readl(OMAP_PRODUCTION_ID_0)); |
142 | printk(KERN_DEBUG "OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x\n" , |
143 | omap_readl(OMAP_PRODUCTION_ID_1), |
144 | omap_readl(OMAP_PRODUCTION_ID_1) & 0xffff); |
145 | printk(KERN_DEBUG "OMAP32_ID_0: 0x%08x\n" , omap_readl(OMAP32_ID_0)); |
146 | printk(KERN_DEBUG "OMAP32_ID_1: 0x%08x\n" , omap_readl(OMAP32_ID_1)); |
147 | printk(KERN_DEBUG "JTAG_ID: 0x%04x DIE_REV: %i\n" , jtag_id, die_rev); |
148 | #endif |
149 | |
150 | system_serial_high = omap_readl(OMAP_DIE_ID_0); |
151 | system_serial_low = omap_readl(OMAP_DIE_ID_1); |
152 | |
153 | /* First check only the major version in a safe way */ |
154 | for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { |
155 | if (jtag_id == (omap_ids[i].jtag_id)) { |
156 | omap_revision = omap_ids[i].type; |
157 | break; |
158 | } |
159 | } |
160 | |
161 | /* Check if we can find the die revision */ |
162 | for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { |
163 | if (jtag_id == omap_ids[i].jtag_id && die_rev == omap_ids[i].die_rev) { |
164 | omap_revision = omap_ids[i].type; |
165 | break; |
166 | } |
167 | } |
168 | |
169 | /* Finally check also the omap_id */ |
170 | for (i = 0; i < ARRAY_SIZE(omap_ids); i++) { |
171 | if (jtag_id == omap_ids[i].jtag_id |
172 | && die_rev == omap_ids[i].die_rev |
173 | && omap_id == omap_ids[i].omap_id) { |
174 | omap_revision = omap_ids[i].type; |
175 | break; |
176 | } |
177 | } |
178 | |
179 | /* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */ |
180 | cpu_type = omap_revision >> 24; |
181 | |
182 | switch (cpu_type) { |
183 | case 0x07: |
184 | case 0x08: |
185 | omap_revision |= 0x07; |
186 | break; |
187 | case 0x03: |
188 | case 0x15: |
189 | omap_revision |= 0x15; |
190 | break; |
191 | case 0x16: |
192 | case 0x17: |
193 | omap_revision |= 0x16; |
194 | break; |
195 | default: |
196 | printk(KERN_INFO "Unknown OMAP cpu type: 0x%02x\n" , cpu_type); |
197 | } |
198 | |
199 | pr_info("OMAP%04x" , omap_revision >> 16); |
200 | if ((omap_revision >> 8) & 0xff) |
201 | pr_cont("%x" , (omap_revision >> 8) & 0xff); |
202 | pr_cont(" revision %i handled as %02xxx id: %08x%08x\n" , |
203 | die_rev, omap_revision & 0xff, system_serial_low, |
204 | system_serial_high); |
205 | } |
206 | |
207 | |