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: stable/11/sys/arm/ti/ti_cpuid.c 308325 2016-11-05 04:30:44Z mmel $"); 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/resource.h> 44#include <machine/intr.h> 45 46#include <arm/ti/tivar.h> 47#include <arm/ti/ti_cpuid.h> 48 49#include <arm/ti/omap4/omap4_reg.h> 50#include <arm/ti/am335x/am335x_reg.h> 51 52#define OMAP4_STD_FUSE_DIE_ID_0 0x2200 53#define OMAP4_ID_CODE 0x2204 54#define OMAP4_STD_FUSE_DIE_ID_1 0x2208 55#define OMAP4_STD_FUSE_DIE_ID_2 0x220C 56#define OMAP4_STD_FUSE_DIE_ID_3 0x2210 57#define OMAP4_STD_FUSE_PROD_ID_0 0x2214 58#define OMAP4_STD_FUSE_PROD_ID_1 0x2218 59 60#define OMAP3_ID_CODE 0xA204 61 62static uint32_t chip_revision = 0xffffffff; 63 64/** 65 * ti_revision - Returns the revision number of the device 66 * 67 * Simply returns an identifier for the revision of the chip we are running 68 * on. 69 * 70 * RETURNS 71 * A 32-bit identifier for the current chip 72 */ 73uint32_t 74ti_revision(void) 75{ 76 return chip_revision; 77} 78 79/** 80 * omap4_get_revision - determines omap4 revision 81 * 82 * Reads the registers to determine the revision of the chip we are currently 83 * running on. Stores the information in global variables. 84 * 85 * 86 */ 87static void 88omap4_get_revision(void) 89{ 90 uint32_t id_code; 91 uint32_t revision; 92 uint32_t hawkeye; 93 bus_space_handle_t bsh; 94 95 /* The chip revsion is read from the device identification registers and 96 * the JTAG (?) tap registers, which are located in address 0x4A00_2200 to 97 * 0x4A00_2218. This is part of the L4_CORE memory range and should have 98 * been mapped in by the machdep.c code. 99 * 100 * STD_FUSE_DIE_ID_0 0x4A00 2200 101 * ID_CODE 0x4A00 2204 (this is the only one we need) 102 * STD_FUSE_DIE_ID_1 0x4A00 2208 103 * STD_FUSE_DIE_ID_2 0x4A00 220C 104 * STD_FUSE_DIE_ID_3 0x4A00 2210 105 * STD_FUSE_PROD_ID_0 0x4A00 2214 106 * STD_FUSE_PROD_ID_1 0x4A00 2218 107 */ 108 /* FIXME Should we map somewhere else? */ 109 bus_space_map(fdtbus_bs_tag,OMAP44XX_L4_CORE_HWBASE, 0x4000, 0, &bsh); 110 id_code = bus_space_read_4(fdtbus_bs_tag, bsh, OMAP4_ID_CODE); 111 bus_space_unmap(fdtbus_bs_tag, bsh, 0x4000); 112 113 hawkeye = ((id_code >> 12) & 0xffff); 114 revision = ((id_code >> 28) & 0xf); 115 116 /* Apparently according to the linux code there were some ES2.0 samples that 117 * have the wrong id code and report themselves as ES1.0 silicon. So used 118 * the ARM cpuid to get the correct revision. 119 */ 120 if (revision == 0) { 121 id_code = cpu_ident(); 122 revision = (id_code & 0xf) - 1; 123 } 124 125 switch (hawkeye) { 126 case 0xB852: 127 switch (revision) { 128 case 0: 129 chip_revision = OMAP4430_REV_ES1_0; 130 break; 131 case 1: 132 chip_revision = OMAP4430_REV_ES2_1; 133 break; 134 default: 135 chip_revision = OMAP4430_REV_UNKNOWN; 136 break; 137 } 138 break; 139 140 case 0xB95C: 141 switch (revision) { 142 case 3: 143 chip_revision = OMAP4430_REV_ES2_1; 144 break; 145 case 4: 146 chip_revision = OMAP4430_REV_ES2_2; 147 break; 148 case 6: 149 chip_revision = OMAP4430_REV_ES2_3; 150 break; 151 default: 152 chip_revision = OMAP4430_REV_UNKNOWN; 153 break; 154 } 155 break; 156 157 case 0xB94E: 158 switch (revision) { 159 case 0: 160 chip_revision = OMAP4460_REV_ES1_0; 161 break; 162 case 2: 163 chip_revision = OMAP4460_REV_ES1_1; 164 break; 165 default: 166 chip_revision = OMAP4460_REV_UNKNOWN; 167 break; 168 } 169 break; 170 171 case 0xB975: 172 switch (revision) { 173 case 0: 174 chip_revision = OMAP4470_REV_ES1_0; 175 break; 176 default: 177 chip_revision = OMAP4470_REV_UNKNOWN; 178 break; 179 } 180 break; 181 182 default: 183 /* Default to the latest revision if we can't determine type */ 184 chip_revision = OMAP_UNKNOWN_DEV; 185 break; 186 } 187 if (chip_revision != OMAP_UNKNOWN_DEV) { 188 printf("Texas Instruments OMAP%04x Processor, Revision ES%u.%u\n", 189 OMAP_REV_DEVICE(chip_revision), OMAP_REV_MAJOR(chip_revision), 190 OMAP_REV_MINOR(chip_revision)); 191 } 192 else { 193 printf("Texas Instruments unknown OMAP chip: %04x, rev %d\n", 194 hawkeye, revision); 195 } 196} 197 198static void 199am335x_get_revision(void) 200{ 201 uint32_t dev_feature; 202 uint8_t cpu_last_char; 203 bus_space_handle_t bsh; 204 205 bus_space_map(fdtbus_bs_tag, AM335X_CONTROL_BASE, AM335X_CONTROL_SIZE, 0, &bsh); 206 chip_revision = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEVICE_ID); 207 dev_feature = bus_space_read_4(fdtbus_bs_tag, bsh, AM335X_CONTROL_DEV_FEATURE); 208 bus_space_unmap(fdtbus_bs_tag, bsh, AM335X_CONTROL_SIZE); 209 210 switch (dev_feature) { 211 case 0x00FF0382: 212 cpu_last_char='2'; 213 break; 214 case 0x20FF0382: 215 cpu_last_char='4'; 216 break; 217 case 0x00FF0383: 218 cpu_last_char='6'; 219 break; 220 case 0x00FE0383: 221 cpu_last_char='7'; 222 break; 223 case 0x20FF0383: 224 cpu_last_char='8'; 225 break; 226 case 0x20FE0383: 227 cpu_last_char='9'; 228 break; 229 default: 230 cpu_last_char='x'; 231 } 232 233 printf("Texas Instruments AM335%c Processor, Revision ES1.%u\n", 234 cpu_last_char, AM335X_DEVREV(chip_revision)); 235} 236 237/** 238 * ti_cpu_ident - attempts to identify the chip we are running on 239 * @dummy: ignored 240 * 241 * This function is called before any of the driver are initialised, however 242 * the basic virt to phys maps have been setup in machdep.c so we can still 243 * access the required registers, we just have to use direct register reads 244 * and writes rather than going through the bus stuff. 245 * 246 * 247 */ 248static void 249ti_cpu_ident(void *dummy) 250{ 251 switch(ti_chip()) { 252 case CHIP_OMAP_4: 253 omap4_get_revision(); 254 break; 255 case CHIP_AM335X: 256 am335x_get_revision(); 257 break; 258 default: 259 panic("Unknown chip type, fixme!\n"); 260 } 261} 262 263SYSINIT(ti_cpu_ident, SI_SUB_CPU, SI_ORDER_SECOND, ti_cpu_ident, NULL); 264