2005-07-10 22:58:12 +04:00
/*
* linux / arch / arm / mach - omap1 / id . c
*
* OMAP1 CPU identification code
*
* Copyright ( C ) 2004 Nokia Corporation
* Written by Tony Lindgren < tony @ atomide . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/init.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2009-10-20 20:40:47 +04:00
# include <plat/cpu.h>
2005-07-10 22:58:12 +04:00
2005-11-10 17:26:48 +03:00
# define OMAP_DIE_ID_0 0xfffe1800
# define OMAP_DIE_ID_1 0xfffe1804
# define OMAP_PRODUCTION_ID_0 0xfffe2000
# define OMAP_PRODUCTION_ID_1 0xfffe2004
# define OMAP32_ID_0 0xfffed400
# define OMAP32_ID_1 0xfffed404
2005-07-10 22:58:12 +04:00
struct omap_id {
u16 jtag_id ; /* Used to determine OMAP type */
u8 die_rev ; /* Processor revision */
u32 omap_id ; /* OMAP revision */
u32 type ; /* Cpu id bits [31:08], cpu class bits [07:00] */
} ;
2008-12-11 04:36:31 +03:00
static unsigned int omap_revision ;
2005-07-10 22:58:12 +04:00
/* Register values to detect the OMAP version */
static struct omap_id omap_ids [ ] __initdata = {
2005-11-10 17:26:48 +03:00
{ . jtag_id = 0xb574 , . die_rev = 0x2 , . omap_id = 0x03310315 , . type = 0x03100000 } ,
2005-07-10 22:58:12 +04:00
{ . jtag_id = 0x355f , . die_rev = 0x0 , . omap_id = 0x03320000 , . type = 0x07300100 } ,
{ . jtag_id = 0xb55f , . die_rev = 0x0 , . omap_id = 0x03320000 , . type = 0x07300300 } ,
2009-09-25 03:23:13 +04:00
{ . jtag_id = 0xb62c , . die_rev = 0x1 , . omap_id = 0x03320500 , . type = 0x08500000 } ,
2005-07-10 22:58:12 +04:00
{ . jtag_id = 0xb470 , . die_rev = 0x0 , . omap_id = 0x03310100 , . type = 0x15100000 } ,
{ . jtag_id = 0xb576 , . die_rev = 0x0 , . omap_id = 0x03320000 , . type = 0x16100000 } ,
{ . jtag_id = 0xb576 , . die_rev = 0x2 , . omap_id = 0x03320100 , . type = 0x16110000 } ,
{ . jtag_id = 0xb576 , . die_rev = 0x3 , . omap_id = 0x03320100 , . type = 0x16100c00 } ,
{ . jtag_id = 0xb576 , . die_rev = 0x0 , . omap_id = 0x03320200 , . type = 0x16100d00 } ,
{ . jtag_id = 0xb613 , . die_rev = 0x0 , . omap_id = 0x03320300 , . type = 0x1610ef00 } ,
{ . jtag_id = 0xb613 , . die_rev = 0x0 , . omap_id = 0x03320300 , . type = 0x1610ef00 } ,
{ . jtag_id = 0xb576 , . die_rev = 0x1 , . omap_id = 0x03320100 , . type = 0x16110000 } ,
{ . jtag_id = 0xb58c , . die_rev = 0x2 , . omap_id = 0x03320200 , . type = 0x16110b00 } ,
{ . jtag_id = 0xb58c , . die_rev = 0x3 , . omap_id = 0x03320200 , . type = 0x16110c00 } ,
{ . jtag_id = 0xb65f , . die_rev = 0x0 , . omap_id = 0x03320400 , . type = 0x16212300 } ,
{ . jtag_id = 0xb65f , . die_rev = 0x1 , . omap_id = 0x03320400 , . type = 0x16212300 } ,
{ . jtag_id = 0xb65f , . die_rev = 0x1 , . omap_id = 0x03320500 , . type = 0x16212300 } ,
{ . jtag_id = 0xb5f7 , . die_rev = 0x0 , . omap_id = 0x03330000 , . type = 0x17100000 } ,
{ . jtag_id = 0xb5f7 , . die_rev = 0x1 , . omap_id = 0x03330100 , . type = 0x17100000 } ,
{ . jtag_id = 0xb5f7 , . die_rev = 0x2 , . omap_id = 0x03330100 , . type = 0x17100000 } ,
} ;
2008-12-11 04:36:31 +03:00
unsigned int omap_rev ( void )
{
return omap_revision ;
}
EXPORT_SYMBOL ( omap_rev ) ;
2005-07-10 22:58:12 +04:00
/*
* Get OMAP type from PROD_ID .
* 1710 has the PROD_ID in bits 15 : 00 , not in 16 : 01 as documented in TRM .
* 1510 PROD_ID is empty , and 1610 PROD_ID does not make sense .
* Undocumented register in TEST BLOCK is used as fallback ; This seems to
* work on 1510 , 1610 & 1710. The official way hopefully will work in future
* processors .
*/
static u16 __init omap_get_jtag_id ( void )
{
u32 prod_id , omap_id ;
prod_id = omap_readl ( OMAP_PRODUCTION_ID_1 ) ;
omap_id = omap_readl ( OMAP32_ID_1 ) ;
2009-03-24 04:07:39 +03:00
/* Check for unusable OMAP_PRODUCTION_ID_1 on 1611B/5912 and 730/850 */
2005-07-10 22:58:12 +04:00
if ( ( ( prod_id > > 20 ) = = 0 ) | | ( prod_id = = omap_id ) )
prod_id = 0 ;
else
prod_id & = 0xffff ;
if ( prod_id )
return prod_id ;
/* Use OMAP32_ID_1 as fallback */
prod_id = ( ( omap_id > > 12 ) & 0xffff ) ;
return prod_id ;
}
/*
* Get OMAP revision from DIE_REV .
* Early 1710 processors may have broken OMAP_DIE_ID , it contains PROD_ID .
* Undocumented register in the TEST BLOCK is used as fallback .
* REVISIT : This does not seem to work on 1510
*/
static u8 __init omap_get_die_rev ( void )
{
u32 die_rev ;
die_rev = omap_readl ( OMAP_DIE_ID_1 ) ;
/* Check for broken OMAP_DIE_ID on early 1710 */
if ( ( ( die_rev > > 12 ) & 0xffff ) = = omap_get_jtag_id ( ) )
die_rev = 0 ;
die_rev = ( die_rev > > 17 ) & 0xf ;
if ( die_rev )
return die_rev ;
die_rev = ( omap_readl ( OMAP32_ID_1 ) > > 28 ) & 0xf ;
return die_rev ;
}
void __init omap_check_revision ( void )
{
int i ;
u16 jtag_id ;
u8 die_rev ;
u32 omap_id ;
u8 cpu_type ;
jtag_id = omap_get_jtag_id ( ) ;
die_rev = omap_get_die_rev ( ) ;
omap_id = omap_readl ( OMAP32_ID_0 ) ;
# ifdef DEBUG
2008-12-11 04:36:31 +03:00
printk ( KERN_DEBUG " OMAP_DIE_ID_0: 0x%08x \n " , omap_readl ( OMAP_DIE_ID_0 ) ) ;
printk ( KERN_DEBUG " OMAP_DIE_ID_1: 0x%08x DIE_REV: %i \n " ,
2005-07-10 22:58:12 +04:00
omap_readl ( OMAP_DIE_ID_1 ) ,
( omap_readl ( OMAP_DIE_ID_1 ) > > 17 ) & 0xf ) ;
2008-12-11 04:36:31 +03:00
printk ( KERN_DEBUG " OMAP_PRODUCTION_ID_0: 0x%08x \n " ,
omap_readl ( OMAP_PRODUCTION_ID_0 ) ) ;
printk ( KERN_DEBUG " OMAP_PRODUCTION_ID_1: 0x%08x JTAG_ID: 0x%04x \n " ,
2005-07-10 22:58:12 +04:00
omap_readl ( OMAP_PRODUCTION_ID_1 ) ,
omap_readl ( OMAP_PRODUCTION_ID_1 ) & 0xffff ) ;
2008-12-11 04:36:31 +03:00
printk ( KERN_DEBUG " OMAP32_ID_0: 0x%08x \n " , omap_readl ( OMAP32_ID_0 ) ) ;
printk ( KERN_DEBUG " OMAP32_ID_1: 0x%08x \n " , omap_readl ( OMAP32_ID_1 ) ) ;
printk ( KERN_DEBUG " JTAG_ID: 0x%04x DIE_REV: %i \n " , jtag_id , die_rev ) ;
2005-07-10 22:58:12 +04:00
# endif
system_serial_high = omap_readl ( OMAP_DIE_ID_0 ) ;
system_serial_low = omap_readl ( OMAP_DIE_ID_1 ) ;
/* First check only the major version in a safe way */
for ( i = 0 ; i < ARRAY_SIZE ( omap_ids ) ; i + + ) {
if ( jtag_id = = ( omap_ids [ i ] . jtag_id ) ) {
2008-12-11 04:36:31 +03:00
omap_revision = omap_ids [ i ] . type ;
2005-07-10 22:58:12 +04:00
break ;
}
}
/* Check if we can find the die revision */
for ( i = 0 ; i < ARRAY_SIZE ( omap_ids ) ; i + + ) {
if ( jtag_id = = omap_ids [ i ] . jtag_id & & die_rev = = omap_ids [ i ] . die_rev ) {
2008-12-11 04:36:31 +03:00
omap_revision = omap_ids [ i ] . type ;
2005-07-10 22:58:12 +04:00
break ;
}
}
/* Finally check also the omap_id */
for ( i = 0 ; i < ARRAY_SIZE ( omap_ids ) ; i + + ) {
if ( jtag_id = = omap_ids [ i ] . jtag_id
& & die_rev = = omap_ids [ i ] . die_rev
& & omap_id = = omap_ids [ i ] . omap_id ) {
2008-12-11 04:36:31 +03:00
omap_revision = omap_ids [ i ] . type ;
2005-07-10 22:58:12 +04:00
break ;
}
}
/* Add the cpu class info (7xx, 15xx, 16xx, 24xx) */
2008-12-11 04:36:31 +03:00
cpu_type = omap_revision > > 24 ;
2005-07-10 22:58:12 +04:00
switch ( cpu_type ) {
case 0x07 :
2009-03-24 04:07:39 +03:00
case 0x08 :
2008-12-11 04:36:31 +03:00
omap_revision | = 0x07 ;
2005-07-10 22:58:12 +04:00
break ;
2005-11-10 17:26:48 +03:00
case 0x03 :
2005-07-10 22:58:12 +04:00
case 0x15 :
2008-12-11 04:36:31 +03:00
omap_revision | = 0x15 ;
2005-07-10 22:58:12 +04:00
break ;
case 0x16 :
case 0x17 :
2008-12-11 04:36:31 +03:00
omap_revision | = 0x16 ;
2005-07-10 22:58:12 +04:00
break ;
default :
2008-12-11 04:36:31 +03:00
printk ( KERN_INFO " Unknown OMAP cpu type: 0x%02x \n " , cpu_type ) ;
2005-07-10 22:58:12 +04:00
}
2008-12-11 04:36:31 +03:00
printk ( KERN_INFO " OMAP%04x " , omap_revision > > 16 ) ;
if ( ( omap_revision > > 8 ) & 0xff )
printk ( KERN_INFO " %x " , ( omap_revision > > 8 ) & 0xff ) ;
printk ( KERN_INFO " revision %i handled as %02xxx id: %08x%08x \n " ,
die_rev , omap_revision & 0xff , system_serial_low ,
2005-07-10 22:58:12 +04:00
system_serial_high ) ;
}