2005-07-10 22:58:15 +04:00
/*
* linux / arch / arm / plat - omap / common . c
*
* Code common to all OMAP machines .
2009-05-29 01:16:04 +04:00
* The file is created by Tony Lindgren < tony @ atomide . com >
*
* Copyright ( C ) 2009 Texas Instruments
* Added OMAP4 support - Santosh Shilimkar < santosh . shilimkar @ ti . com >
2005-07-10 22:58:15 +04:00
*
* 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>
# include <linux/delay.h>
# include <linux/console.h>
# include <linux/serial.h>
# include <linux/tty.h>
# include <linux/serial_8250.h>
# include <linux/serial_reg.h>
2006-01-07 19:15:52 +03:00
# include <linux/clk.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2005-07-10 22:58:15 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-07-10 22:58:15 +04:00
# include <asm/system.h>
# include <asm/pgtable.h>
# include <asm/mach/map.h>
2005-09-07 20:20:26 +04:00
# include <asm/setup.h>
2005-07-10 22:58:15 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/common.h>
# include <mach/board.h>
# include <mach/control.h>
# include <mach/mux.h>
# include <mach/fpga.h>
2005-07-10 22:58:15 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/clock.h>
2005-07-10 22:58:15 +04:00
2008-03-18 11:04:51 +03:00
# if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
# include ".. / mach-omap2 / sdrc.h"
# endif
2005-07-10 22:58:15 +04:00
# define NO_LENGTH_CHECK 0xffffffff
2005-09-07 20:20:26 +04:00
unsigned char omap_bootloader_tag [ 512 ] ;
int omap_bootloader_tag_len ;
2005-07-10 22:58:15 +04:00
struct omap_board_config_kernel * omap_board_config ;
2005-09-07 20:20:26 +04:00
int omap_board_config_size ;
2005-07-10 22:58:15 +04:00
static const void * get_config ( u16 tag , size_t len , int skip , size_t * len_out )
{
struct omap_board_config_kernel * kinfo = NULL ;
int i ;
# ifdef CONFIG_OMAP_BOOT_TAG
struct omap_board_config_entry * info = NULL ;
if ( omap_bootloader_tag_len > 4 )
info = ( struct omap_board_config_entry * ) omap_bootloader_tag ;
while ( info ! = NULL ) {
u8 * next ;
if ( info - > tag = = tag ) {
if ( skip = = 0 )
break ;
skip - - ;
}
if ( ( info - > len & 0x03 ) ! = 0 ) {
/* We bail out to avoid an alignment fault */
printk ( KERN_ERR " OMAP peripheral config: Length (%d) not word-aligned (tag %04x) \n " ,
info - > len , info - > tag ) ;
return NULL ;
}
next = ( u8 * ) info + sizeof ( * info ) + info - > len ;
if ( next > = omap_bootloader_tag + omap_bootloader_tag_len )
info = NULL ;
else
info = ( struct omap_board_config_entry * ) next ;
}
if ( info ! = NULL ) {
/* Check the length as a lame attempt to check for
2007-05-11 23:40:30 +04:00
* binary inconsistency . */
2005-07-10 22:58:15 +04:00
if ( len ! = NO_LENGTH_CHECK ) {
/* Word-align len */
if ( len & 0x03 )
len = ( len + 3 ) & ~ 0x03 ;
if ( info - > len ! = len ) {
printk ( KERN_ERR " OMAP peripheral config: Length mismatch with tag %x (want %d, got %d) \n " ,
tag , len , info - > len ) ;
return NULL ;
}
}
if ( len_out ! = NULL )
* len_out = info - > len ;
return info - > data ;
}
# endif
/* Try to find the config from the board-specific structures
* in the kernel . */
for ( i = 0 ; i < omap_board_config_size ; i + + ) {
if ( omap_board_config [ i ] . tag = = tag ) {
2006-12-08 00:58:10 +03:00
if ( skip = = 0 ) {
kinfo = & omap_board_config [ i ] ;
break ;
} else {
skip - - ;
}
2005-07-10 22:58:15 +04:00
}
}
if ( kinfo = = NULL )
return NULL ;
return kinfo - > data ;
}
const void * __omap_get_config ( u16 tag , size_t len , int nr )
{
return get_config ( tag , len , nr , NULL ) ;
}
EXPORT_SYMBOL ( __omap_get_config ) ;
const void * omap_get_var_config ( u16 tag , size_t * len )
{
return get_config ( tag , NO_LENGTH_CHECK , 0 , len ) ;
}
EXPORT_SYMBOL ( omap_get_var_config ) ;
static int __init omap_add_serial_console ( void )
{
2005-11-10 17:26:50 +03:00
const struct omap_serial_console_config * con_info ;
const struct omap_uart_config * uart_info ;
static char speed [ 11 ] , * opt = NULL ;
int line , i , uart_idx ;
uart_info = omap_get_config ( OMAP_TAG_UART , struct omap_uart_config ) ;
con_info = omap_get_config ( OMAP_TAG_SERIAL_CONSOLE ,
struct omap_serial_console_config ) ;
if ( uart_info = = NULL | | con_info = = NULL )
return 0 ;
if ( con_info - > console_uart = = 0 )
return 0 ;
if ( con_info - > console_speed ) {
snprintf ( speed , sizeof ( speed ) , " %u " , con_info - > console_speed ) ;
opt = speed ;
}
2005-07-10 22:58:15 +04:00
2005-11-10 17:26:50 +03:00
uart_idx = con_info - > console_uart - 1 ;
if ( uart_idx > = OMAP_MAX_NR_PORTS ) {
printk ( KERN_INFO " Console: external UART#%d. "
" Not adding it as console this time. \n " ,
uart_idx + 1 ) ;
return 0 ;
}
if ( ! ( uart_info - > enabled_uarts & ( 1 < < uart_idx ) ) ) {
printk ( KERN_ERR " Console: Selected UART#%d is "
" not enabled for this platform \n " ,
uart_idx + 1 ) ;
return - 1 ;
}
line = 0 ;
for ( i = 0 ; i < uart_idx ; i + + ) {
if ( uart_info - > enabled_uarts & ( 1 < < i ) )
line + + ;
2005-07-10 22:58:15 +04:00
}
2005-11-10 17:26:50 +03:00
return add_preferred_console ( " ttyS " , line , opt ) ;
2005-07-10 22:58:15 +04:00
}
console_initcall ( omap_add_serial_console ) ;
2007-03-08 22:32:19 +03:00
/*
* 32 KHz clocksource . . . always available , on pretty most chips except
* OMAP 730 and 1510. Other timers could be used as clocksources , with
* higher resolution in free - running counter modes ( e . g . 12 MHz xtal ) ,
* but systems won ' t necessarily want to spend resources that way .
*/
2009-05-25 22:26:41 +04:00
# define OMAP16XX_TIMER_32K_SYNCHRONIZED 0xfffbc410
2007-03-08 22:32:19 +03:00
2009-05-25 22:26:41 +04:00
# if !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX))
2007-03-08 22:32:19 +03:00
# include <linux/clocksource.h>
2009-05-25 22:26:41 +04:00
# ifdef CONFIG_ARCH_OMAP16XX
static cycle_t omap16xx_32k_read ( struct clocksource * cs )
{
return omap_readl ( OMAP16XX_TIMER_32K_SYNCHRONIZED ) ;
}
# else
# define omap16xx_32k_read NULL
# endif
# ifdef CONFIG_ARCH_OMAP2420
static cycle_t omap2420_32k_read ( struct clocksource * cs )
{
return omap_readl ( OMAP2420_32KSYNCT_BASE + 0x10 ) ;
}
# else
# define omap2420_32k_read NULL
# endif
# ifdef CONFIG_ARCH_OMAP2430
static cycle_t omap2430_32k_read ( struct clocksource * cs )
{
return omap_readl ( OMAP2430_32KSYNCT_BASE + 0x10 ) ;
}
# else
# define omap2430_32k_read NULL
# endif
# ifdef CONFIG_ARCH_OMAP34XX
static cycle_t omap34xx_32k_read ( struct clocksource * cs )
2007-03-08 22:32:19 +03:00
{
2009-05-25 22:26:41 +04:00
return omap_readl ( OMAP3430_32KSYNCT_BASE + 0x10 ) ;
}
# else
# define omap34xx_32k_read NULL
# endif
2009-05-29 01:16:04 +04:00
# ifdef CONFIG_ARCH_OMAP4
static cycle_t omap44xx_32k_read ( struct clocksource * cs )
{
return omap_readl ( OMAP4430_32KSYNCT_BASE + 0x10 ) ;
}
# else
# define omap44xx_32k_read NULL
# endif
2009-05-25 22:26:41 +04:00
/*
* Kernel assumes that sched_clock can be called early but may not have
* things ready yet .
*/
static cycle_t omap_32k_read_dummy ( struct clocksource * cs )
{
return 0 ;
2007-03-08 22:32:19 +03:00
}
static struct clocksource clocksource_32k = {
. name = " 32k_counter " ,
. rating = 250 ,
2009-05-25 22:26:41 +04:00
. read = omap_32k_read_dummy ,
2007-03-08 22:32:19 +03:00
. mask = CLOCKSOURCE_MASK ( 32 ) ,
. shift = 10 ,
. flags = CLOCK_SOURCE_IS_CONTINUOUS ,
} ;
2007-11-13 10:24:03 +03:00
/*
* Returns current time from boot in nsecs . It ' s OK for this to wrap
* around for now , as it ' s just a relative time stamp .
*/
unsigned long long sched_clock ( void )
{
2009-03-04 21:07:41 +03:00
unsigned long long ret ;
2009-05-25 22:26:41 +04:00
ret = ( unsigned long long ) clocksource_32k . read ( & clocksource_32k ) ;
2009-03-04 21:07:41 +03:00
ret = ( ret * clocksource_32k . mult_orig ) > > clocksource_32k . shift ;
return ret ;
2007-11-13 10:24:03 +03:00
}
2007-03-08 22:32:19 +03:00
static int __init omap_init_clocksource_32k ( void )
{
static char err [ ] __initdata = KERN_ERR
" %s: can't register clocksource! \n " ;
2008-03-18 11:04:51 +03:00
if ( cpu_is_omap16xx ( ) | | cpu_class_is_omap2 ( ) ) {
struct clk * sync_32k_ick ;
2009-05-25 22:26:41 +04:00
if ( cpu_is_omap16xx ( ) )
clocksource_32k . read = omap16xx_32k_read ;
else if ( cpu_is_omap2420 ( ) )
clocksource_32k . read = omap2420_32k_read ;
else if ( cpu_is_omap2430 ( ) )
clocksource_32k . read = omap2430_32k_read ;
else if ( cpu_is_omap34xx ( ) )
clocksource_32k . read = omap34xx_32k_read ;
2009-05-29 01:16:04 +04:00
else if ( cpu_is_omap44xx ( ) )
clocksource_32k . read = omap44xx_32k_read ;
2009-05-25 22:26:41 +04:00
else
return - ENODEV ;
2008-03-18 11:04:51 +03:00
sync_32k_ick = clk_get ( NULL , " omap_32ksync_ick " ) ;
if ( sync_32k_ick )
clk_enable ( sync_32k_ick ) ;
2007-03-08 22:32:19 +03:00
clocksource_32k . mult = clocksource_hz2mult ( 32768 ,
clocksource_32k . shift ) ;
if ( clocksource_register ( & clocksource_32k ) )
printk ( err , clocksource_32k . name ) ;
}
return 0 ;
}
arch_initcall ( omap_init_clocksource_32k ) ;
2009-05-25 22:26:41 +04:00
# endif /* !(defined(CONFIG_ARCH_OMAP730) || defined(CONFIG_ARCH_OMAP15XX)) */
2008-03-18 11:04:51 +03:00
/* Global address base setup code */
2008-07-03 13:24:44 +04:00
# if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
2009-05-25 22:26:48 +04:00
static void __init __omap2_set_globals ( struct omap_globals * omap2_globals )
2008-07-03 13:24:44 +04:00
{
2008-10-06 16:49:16 +04:00
omap2_set_globals_tap ( omap2_globals ) ;
2009-01-28 22:27:37 +03:00
omap2_set_globals_sdrc ( omap2_globals ) ;
2008-07-03 13:24:44 +04:00
omap2_set_globals_control ( omap2_globals ) ;
omap2_set_globals_prcm ( omap2_globals ) ;
}
# endif
2008-03-18 11:04:51 +03:00
# if defined(CONFIG_ARCH_OMAP2420)
2008-07-03 13:24:44 +04:00
static struct omap_globals omap242x_globals = {
2008-10-06 16:49:16 +04:00
. class = OMAP242X_CLASS ,
2008-09-02 01:07:37 +04:00
. tap = OMAP2_IO_ADDRESS ( 0x48014000 ) ,
. sdrc = OMAP2_IO_ADDRESS ( OMAP2420_SDRC_BASE ) ,
. sms = OMAP2_IO_ADDRESS ( OMAP2420_SMS_BASE ) ,
. ctrl = OMAP2_IO_ADDRESS ( OMAP2420_CTRL_BASE ) ,
. prm = OMAP2_IO_ADDRESS ( OMAP2420_PRM_BASE ) ,
. cm = OMAP2_IO_ADDRESS ( OMAP2420_CM_BASE ) ,
2008-07-03 13:24:44 +04:00
} ;
2008-03-18 11:04:51 +03:00
void __init omap2_set_globals_242x ( void )
{
2009-05-25 22:26:48 +04:00
__omap2_set_globals ( & omap242x_globals ) ;
2008-03-18 11:04:51 +03:00
}
# endif
# if defined(CONFIG_ARCH_OMAP2430)
2008-07-03 13:24:44 +04:00
static struct omap_globals omap243x_globals = {
2008-10-06 16:49:16 +04:00
. class = OMAP243X_CLASS ,
2008-09-02 01:07:37 +04:00
. tap = OMAP2_IO_ADDRESS ( 0x4900a000 ) ,
. sdrc = OMAP2_IO_ADDRESS ( OMAP243X_SDRC_BASE ) ,
. sms = OMAP2_IO_ADDRESS ( OMAP243X_SMS_BASE ) ,
. ctrl = OMAP2_IO_ADDRESS ( OMAP243X_CTRL_BASE ) ,
. prm = OMAP2_IO_ADDRESS ( OMAP2430_PRM_BASE ) ,
. cm = OMAP2_IO_ADDRESS ( OMAP2430_CM_BASE ) ,
2008-07-03 13:24:44 +04:00
} ;
2008-03-18 11:04:51 +03:00
void __init omap2_set_globals_243x ( void )
{
2009-05-25 22:26:48 +04:00
__omap2_set_globals ( & omap243x_globals ) ;
2008-03-18 11:04:51 +03:00
}
# endif
# if defined(CONFIG_ARCH_OMAP3430)
2008-07-03 13:24:44 +04:00
static struct omap_globals omap343x_globals = {
2008-10-06 16:49:16 +04:00
. class = OMAP343X_CLASS ,
2008-09-02 01:07:37 +04:00
. tap = OMAP2_IO_ADDRESS ( 0x4830A000 ) ,
. sdrc = OMAP2_IO_ADDRESS ( OMAP343X_SDRC_BASE ) ,
. sms = OMAP2_IO_ADDRESS ( OMAP343X_SMS_BASE ) ,
. ctrl = OMAP2_IO_ADDRESS ( OMAP343X_CTRL_BASE ) ,
. prm = OMAP2_IO_ADDRESS ( OMAP3430_PRM_BASE ) ,
. cm = OMAP2_IO_ADDRESS ( OMAP3430_CM_BASE ) ,
2008-07-03 13:24:44 +04:00
} ;
2008-03-18 11:04:51 +03:00
void __init omap2_set_globals_343x ( void )
{
2009-05-25 22:26:48 +04:00
__omap2_set_globals ( & omap343x_globals ) ;
2008-03-18 11:04:51 +03:00
}
# endif
2009-05-29 01:16:04 +04:00
# if defined(CONFIG_ARCH_OMAP4)
static struct omap_globals omap4_globals = {
. class = OMAP443X_CLASS ,
. tap = OMAP2_IO_ADDRESS ( 0x4830a000 ) ,
. ctrl = OMAP2_IO_ADDRESS ( OMAP443X_CTRL_BASE ) ,
. prm = OMAP2_IO_ADDRESS ( OMAP4430_PRM_BASE ) ,
. cm = OMAP2_IO_ADDRESS ( OMAP4430_CM_BASE ) ,
} ;
void __init omap2_set_globals_443x ( void )
{
omap2_set_globals_tap ( & omap4_globals ) ;
omap2_set_globals_control ( & omap4_globals ) ;
}
# endif