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