1/*- 2 * Copyright (c) 2011 3 * Ben Gray <ben.r.gray@gmail.com>. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28#include <sys/cdefs.h> 29__FBSDID("$FreeBSD: releng/10.2/sys/arm/ti/ti_cpuid.c 259329 2013-12-13 20:43:11Z ian $"); 30 31#include <sys/param.h> 32#include <sys/systm.h> 33#include <sys/kernel.h> 34#include <sys/module.h> 35#include <sys/bus.h> 36#include <sys/resource.h> 37#include <sys/rman.h> 38#include <sys/lock.h> 39#include <sys/mutex.h> 40 41#include <machine/bus.h> 42#include <machine/fdt.h> 43#include <machine/cpu.h> 44#include <machine/cpufunc.h> 45#include <machine/resource.h> 46#include <machine/intr.h> 47 48#include <arm/ti/tivar.h> 49#include <arm/ti/ti_cpuid.h> 50 51#include <arm/ti/omap4/omap4_reg.h> 52#include <arm/ti/omap3/omap3_reg.h> 53#include <arm/ti/am335x/am335x_reg.h> 54 55#define OMAP4_STD_FUSE_DIE_ID_0 0x2200 56#define OMAP4_ID_CODE 0x2204 57#define OMAP4_STD_FUSE_DIE_ID_1 0x2208 58#define OMAP4_STD_FUSE_DIE_ID_2 0x220C 59#define OMAP4_STD_FUSE_DIE_ID_3 0x2210 60#define OMAP4_STD_FUSE_PROD_ID_0 0x2214 61#define OMAP4_STD_FUSE_PROD_ID_1 0x2218 62 63#define OMAP3_ID_CODE 0xA204 64 65static uint32_t chip_revision = 0xffffffff; 66 67/** 68 * ti_revision - Returns the revision number of the device 69 * 70 * Simply returns an identifier for the revision of the chip we are running 71 * on. 72 * 73 * RETURNS 74 * A 32-bit identifier for the current chip 75 */ 76uint32_t 77ti_revision(void) 78{ 79 return chip_revision; 80} 81 82/** 83 * omap4_get_revision - determines omap4 revision 84 * 85 * Reads the registers to determine the revision of the chip we are currently 86 * running on. Stores the information in global variables. 87 * 88 * 89 */ 90static void 91omap4_get_revision(void) 92{ 93 uint32_t id_code; 94 uint32_t revision; 95 uint32_t hawkeye; 96 bus_space_handle_t bsh; 97 98 /* The chip revsion is read from the device identification registers and 99 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to 100 * 0x4A00_2218. This is part of the L4_CORE memory range and should have 101 * been mapped in by the machdep.c code. 102 * 103 * STD_FUSE_DIE_ID_0 0x4A00 2200 104 * ID_CODE 0x4A00 2204 (this is the only one we need) 105 * STD_FUSE_DIE_ID_1 0x4A00 2208 106 * STD_FUSE_DIE_ID_2 0x4A00 220C 107 * STD_FUSE_DIE_ID_3 0x4A00 2210 108 * STD_FUSE_PROD_ID_0 0x4A00 2214 109 * STD_FUSE_PROD_ID_1 0x4A00 2218 110 */ 111 /* FIXME Should we map somewhere else? */ 112 bus_space_map(fdtbus_bs_tag,OMAP44XX_L4_CORE_HWBASE, 0x4000, 0, &bsh); 113 id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP4_ID_CODE); 114 bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000); 115 116 hawkeye = ((id_code >> 12) & 0xffff); 117 revision = ((id_code >> 28) & 0xf); 118 119 /* Apparently according to the linux code there were some ES2.0 samples that 120 * have the wrong id code and report themselves as ES1.0 silicon. So used 121 * the ARM cpuid to get the correct revision. 122 */ 123 if (revision == 0) { 124 id_code = cpufunc_id(); 125 revision = (id_code & 0xf) - 1; 126 } 127 128 switch (hawkeye) { 129 case 0xB852: 130 switch (revision) { 131 case 0: 132 chip_revision = OMAP4430_REV_ES1_0; 133 break; 134 case 1: 135 chip_revision = OMAP4430_REV_ES2_1; 136 break; 137 default: 138 chip_revision = OMAP4430_REV_UNKNOWN; 139 break; 140 } 141 break; 142 143 case 0xB95C: 144 switch (revision) { 145 case 3: 146 chip_revision = OMAP4430_REV_ES2_1; 147 break; 148 case 4: 149 chip_revision = OMAP4430_REV_ES2_2; 150 break; 151 case 6: 152 chip_revision = OMAP4430_REV_ES2_3; 153 break; 154 default: 155 chip_revision = OMAP4430_REV_UNKNOWN; 156 break; 157 } 158 break; 159 160 case 0xB94E: 161 switch (revision) { 162 case 0: 163 chip_revision = OMAP4460_REV_ES1_0; 164 break; 165 case 2: 166 chip_revision = OMAP4460_REV_ES1_1; 167 break; 168 default: 169 chip_revision = OMAP4460_REV_UNKNOWN; 170 break; 171 } 172 break; 173 174 case 0xB975: 175 switch (revision) { 176 case 0: 177 chip_revision = OMAP4470_REV_ES1_0; 178 break; 179 default: 180 chip_revision = OMAP4470_REV_UNKNOWN; 181 break; 182 } 183 break; 184 185 default: 186 /* Default to the latest revision if we can't determine type */ 187 chip_revision = OMAP_UNKNOWN_DEV; 188 break; 189 } 190 if (chip_revision != OMAP_UNKNOWN_DEV) { 191 printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n", 192 OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), 193 OMAP_REV_MINOR(chip_revision)); 194 } 195 else { 196 printf("Texas Instruments unknown OMAP chip: %04x, rev %d\n", 197 hawkeye, revision); 198 } 199} 200 201/** 202 * omap3_get_revision - determines omap3 revision 203 * 204 * Reads the registers to determine the revision of the chip we are currently 205 * running on. Stores the information in global variables. 206 * 207 * WARNING: This function currently only really works for OMAP3530 devices. 208 * 209 * 210 * 211 */ 212static void 213omap3_get_revision(void) 214{ 215 uint32_t id_code; 216 uint32_t revision; 217 uint32_t hawkeye; 218 bus_space_handle_t bsh; 219 220 /* The chip revsion is read from the device identification registers and 221 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to 222 * 0x4A00_2218. This is part of the L4_CORE memory range and should have 223 * been mapped in by the machdep.c code. 224 * 225 * CONTROL_IDCODE 0x4830 A204 (this is the only one we need) 226 * 227 * 228 */ 229 bus_space_map(fdtbus_bs_tag, OMAP35XX_L4_WAKEUP_HWBASE, 0x10000, 0, &bsh); 230 id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP3_ID_CODE); 231 bus_space_unmap(fdtbus_bs_tag, bsh, 0x10000); 232 233 hawkeye = ((id_code >> 12) & 0xffff); 234 revision = ((id_code >> 28) & 0xf); 235 236 switch (hawkeye) { 237 case 0xB6D6: 238 chip_revision = OMAP3350_REV_ES1_0; 239 break; 240 case 0xB7AE: 241 if (revision == 1) 242 chip_revision = OMAP3530_REV_ES2_0; 243 else if (revision == 2) 244 chip_revision = OMAP3530_REV_ES2_1; 245 else if (revision == 3) 246 chip_revision = OMAP3530_REV_ES3_0; 247 else if (revision == 4) 248 chip_revision = OMAP3530_REV_ES3_1; 249 else if (revision == 7) 250 chip_revision = OMAP3530_REV_ES3_1_2; 251 break; 252 default: 253 /* Default to the latest revision if we can't determine type */ 254 chip_revision = OMAP3530_REV_ES3_1_2; 255 break; 256 } 257 printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n", 258 OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), 259 OMAP_REV_MINOR(chip_revision)); 260} 261 262static void 263am335x_get_revision(void) 264{ 265 uint32_t dev_feature; 266 uint8_t cpu_last_char; 267 bus_space_handle_t bsh; 268 269 bus_space_map(fdtbus_bs_tag, AM335X_CONTROL_BASE, AM335X_CONTROL_SIZE, 0, &bsh); 270 chip_revision = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEVICE_ID); 271 dev_feature = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEV_FEATURE); 272 bus_space_unmap(fdtbus_bs_tag, bsh, AM335X_CONTROL_SIZE); 273 274 switch (dev_feature) { 275 case 0x00FF0382: 276 cpu_last_char='2'; 277 break; 278 case 0x20FF0382: 279 cpu_last_char='4'; 280 break; 281 case 0x00FF0383: 282 cpu_last_char='6'; 283 break; 284 case 0x00FE0383: 285 cpu_last_char='7'; 286 break; 287 case 0x20FF0383: 288 cpu_last_char='8'; 289 break; 290 case 0x20FE0383: 291 cpu_last_char='9'; 292 break; 293 default: 294 cpu_last_char='x'; 295 } 296 297 printf("Texas Instruments AM335%c Processor, Revision ES1.%u\n", 298 cpu_last_char, AM335X_DEVREV(chip_revision)); 299} 300 301/** 302 * ti_cpu_ident - attempts to identify the chip we are running on 303 * @dummy: ignored 304 * 305 * This function is called before any of the driver are initialised, however 306 * the basic virt to phys maps have been setup in machdep.c so we can still 307 * access the required registers, we just have to use direct register reads 308 * and writes rather than going through the bus stuff. 309 * 310 * 311 */ 312static void 313ti_cpu_ident(void *dummy) 314{ 315 switch(ti_chip()) { 316 case CHIP_OMAP_3: 317 omap3_get_revision(); 318 break; 319 case CHIP_OMAP_4: 320 omap4_get_revision(); 321 break; 322 case CHIP_AM335X: 323 am335x_get_revision(); 324 break; 325 default: 326 panic("Unknown chip type, fixme!\n"); 327 } 328} 329 330SYSINIT(ti_cpu_ident, SI_SUB_CPU, SI_ORDER_SECOND, ti_cpu_ident, NULL); 331