2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - ebsa110 / core . c
*
* Copyright ( C ) 1998 - 2001 Russell King
*
* 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 .
*
* Extra MM routines for the EBSA - 110 architecture
*/
# include <linux/kernel.h>
# include <linux/mm.h>
# include <linux/interrupt.h>
# include <linux/serial_8250.h>
# include <linux/init.h>
2008-09-06 15:10:45 +04:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/irq.h>
# include <asm/setup.h>
# include <asm/mach-types.h>
# include <asm/pgtable.h>
# include <asm/page.h>
2012-03-28 21:30:01 +04:00
# include <asm/system_misc.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
# include <asm/mach/time.h>
2011-06-10 14:13:05 +04:00
# include "core.h"
2005-04-17 02:20:36 +04:00
2010-11-29 12:29:25 +03:00
static void ebsa110_mask_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:29:25 +03:00
__raw_writeb ( 1 < < d - > irq , IRQ_MCLR ) ;
2005-04-17 02:20:36 +04:00
}
2010-11-29 12:29:25 +03:00
static void ebsa110_unmask_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
2010-11-29 12:29:25 +03:00
__raw_writeb ( 1 < < d - > irq , IRQ_MSET ) ;
2005-04-17 02:20:36 +04:00
}
2006-11-23 14:41:32 +03:00
static struct irq_chip ebsa110_irq_chip = {
2010-11-29 12:29:25 +03:00
. irq_ack = ebsa110_mask_irq ,
. irq_mask = ebsa110_mask_irq ,
. irq_unmask = ebsa110_unmask_irq ,
2005-04-17 02:20:36 +04:00
} ;
static void __init ebsa110_init_irq ( void )
{
unsigned long flags ;
unsigned int irq ;
local_irq_save ( flags ) ;
__raw_writeb ( 0xff , IRQ_MCLR ) ;
__raw_writeb ( 0x55 , IRQ_MSET ) ;
__raw_writeb ( 0x00 , IRQ_MSET ) ;
if ( __raw_readb ( IRQ_MASK ) ! = 0x55 )
while ( 1 ) ;
__raw_writeb ( 0xff , IRQ_MCLR ) ; /* clear all interrupt enables */
local_irq_restore ( flags ) ;
for ( irq = 0 ; irq < NR_IRQS ; irq + + ) {
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( irq , & ebsa110_irq_chip ,
handle_level_irq ) ;
2005-04-17 02:20:36 +04:00
set_irq_flags ( irq , IRQF_VALID | IRQF_PROBE ) ;
}
}
static struct map_desc ebsa110_io_desc [ ] __initdata = {
/*
* sparse external - decode ISAIO space
*/
2005-10-28 18:19:08 +04:00
{ /* IRQ_STAT/IRQ_MCLR */
2012-09-15 00:11:12 +04:00
. virtual = ( unsigned long ) IRQ_STAT ,
2005-10-28 18:19:08 +04:00
. pfn = __phys_to_pfn ( TRICK4_PHYS ) ,
2011-06-10 15:35:45 +04:00
. length = TRICK4_SIZE ,
2005-10-28 18:19:08 +04:00
. type = MT_DEVICE
} , { /* IRQ_MASK/IRQ_MSET */
2012-09-15 00:11:12 +04:00
. virtual = ( unsigned long ) IRQ_MASK ,
2005-10-28 18:19:08 +04:00
. pfn = __phys_to_pfn ( TRICK3_PHYS ) ,
2011-06-10 15:35:45 +04:00
. length = TRICK3_SIZE ,
2005-10-28 18:19:08 +04:00
. type = MT_DEVICE
} , { /* SOFT_BASE */
2012-09-15 00:11:12 +04:00
. virtual = ( unsigned long ) SOFT_BASE ,
2005-10-28 18:19:08 +04:00
. pfn = __phys_to_pfn ( TRICK1_PHYS ) ,
2011-06-10 15:35:45 +04:00
. length = TRICK1_SIZE ,
2005-10-28 18:19:08 +04:00
. type = MT_DEVICE
} , { /* PIT_BASE */
2012-09-15 00:11:12 +04:00
. virtual = ( unsigned long ) PIT_BASE ,
2005-10-28 18:19:08 +04:00
. pfn = __phys_to_pfn ( TRICK0_PHYS ) ,
2011-06-10 15:35:45 +04:00
. length = TRICK0_SIZE ,
2005-10-28 18:19:08 +04:00
. type = MT_DEVICE
} ,
2005-04-17 02:20:36 +04:00
/*
* self - decode ISAIO space
*/
2005-10-28 18:19:08 +04:00
{
. virtual = ISAIO_BASE ,
. pfn = __phys_to_pfn ( ISAIO_PHYS ) ,
. length = ISAIO_SIZE ,
. type = MT_DEVICE
} , {
. virtual = ISAMEM_BASE ,
. pfn = __phys_to_pfn ( ISAMEM_PHYS ) ,
. length = ISAMEM_SIZE ,
. type = MT_DEVICE
}
2005-04-17 02:20:36 +04:00
} ;
static void __init ebsa110_map_io ( void )
{
iotable_init ( ebsa110_io_desc , ARRAY_SIZE ( ebsa110_io_desc ) ) ;
}
2013-05-16 22:40:22 +04:00
static void __iomem * ebsa110_ioremap_caller ( phys_addr_t cookie , size_t size ,
2012-03-07 07:34:19 +04:00
unsigned int flags , void * caller )
{
return ( void __iomem * ) cookie ;
}
static void ebsa110_iounmap ( volatile void __iomem * io_addr )
{ }
static void __init ebsa110_init_early ( void )
{
arch_ioremap_caller = ebsa110_ioremap_caller ;
arch_iounmap = ebsa110_iounmap ;
}
2005-04-17 02:20:36 +04:00
# define PIT_CTRL (PIT_BASE + 0x0d)
# define PIT_T2 (PIT_BASE + 0x09)
# define PIT_T1 (PIT_BASE + 0x05)
# define PIT_T0 (PIT_BASE + 0x01)
/*
* This is the rate at which your MCLK signal toggles ( in Hz )
* This was measured on a 10 digit frequency counter sampling
* over 1 second .
*/
# define MCLK 47894000
/*
* This is the rate at which the PIT timers get clocked
*/
# define CLKBY7 (MCLK / 7)
/*
* This is the counter value . We tick at 200 Hz on this platform .
*/
# define COUNT ((CLKBY7 + (HZ / 2)) / HZ)
/*
* Get the time offset from the system PIT . Note that if we have missed an
* interrupt , then the PIT counter will roll over ( ie , be negative ) .
* This actually works out to be convenient .
*/
2012-11-08 22:51:58 +04:00
static u32 ebsa110_gettimeoffset ( void )
2005-04-17 02:20:36 +04:00
{
unsigned long offset , count ;
__raw_writeb ( 0x40 , PIT_CTRL ) ;
count = __raw_readb ( PIT_T1 ) ;
count | = __raw_readb ( PIT_T1 ) < < 8 ;
/*
* If count > COUNT , make the number negative .
*/
if ( count > COUNT )
count | = 0xffff0000 ;
offset = COUNT ;
offset - = count ;
/*
* ` offset ' is in units of timer counts . Convert
* offset to units of microseconds .
*/
offset = offset * ( 1000000 / HZ ) / COUNT ;
2012-11-08 22:51:58 +04:00
return offset * 1000 ;
2005-04-17 02:20:36 +04:00
}
static irqreturn_t
2006-10-06 21:53:39 +04:00
ebsa110_timer_interrupt ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
u32 count ;
/* latch and read timer 1 */
__raw_writeb ( 0x40 , PIT_CTRL ) ;
count = __raw_readb ( PIT_T1 ) ;
count | = __raw_readb ( PIT_T1 ) < < 8 ;
count + = COUNT ;
__raw_writeb ( count & 0xff , PIT_T1 ) ;
__raw_writeb ( count > > 8 , PIT_T1 ) ;
2006-10-06 21:53:39 +04:00
timer_tick ( ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
static struct irqaction ebsa110_timer_irq = {
. name = " EBSA110 Timer Tick " ,
2014-03-05 01:04:50 +04:00
. flags = IRQF_TIMER | IRQF_IRQPOLL ,
2005-06-26 20:06:36 +04:00
. handler = ebsa110_timer_interrupt ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Set up timer interrupt .
*/
2012-11-08 23:40:59 +04:00
void __init ebsa110_timer_init ( void )
2005-04-17 02:20:36 +04:00
{
2012-11-08 22:51:58 +04:00
arch_gettimeoffset = ebsa110_gettimeoffset ;
2005-04-17 02:20:36 +04:00
/*
* Timer 1 , mode 2 , LSB / MSB
*/
__raw_writeb ( 0x70 , PIT_CTRL ) ;
__raw_writeb ( COUNT & 0xff , PIT_T1 ) ;
__raw_writeb ( COUNT > > 8 , PIT_T1 ) ;
setup_irq ( IRQ_EBSA110_TIMER0 , & ebsa110_timer_irq ) ;
}
static struct plat_serial8250_port serial_platform_data [ ] = {
{
. iobase = 0x3f8 ,
. irq = 1 ,
. uartclk = 1843200 ,
. regshift = 0 ,
. iotype = UPIO_PORT ,
. flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST ,
} ,
{
. iobase = 0x2f8 ,
. irq = 2 ,
. uartclk = 1843200 ,
. regshift = 0 ,
. iotype = UPIO_PORT ,
. flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST ,
} ,
{ } ,
} ;
static struct platform_device serial_device = {
. name = " serial8250 " ,
2005-09-08 19:04:41 +04:00
. id = PLAT8250_DEV_PLATFORM ,
2005-04-17 02:20:36 +04:00
. dev = {
. platform_data = serial_platform_data ,
} ,
} ;
2005-10-31 20:14:57 +03:00
static struct resource am79c961_resources [ ] = {
{
. start = 0x220 ,
. end = 0x238 ,
. flags = IORESOURCE_IO ,
} , {
. start = IRQ_EBSA110_ETHERNET ,
. end = IRQ_EBSA110_ETHERNET ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct platform_device am79c961_device = {
. name = " am79c961 " ,
. id = - 1 ,
. num_resources = ARRAY_SIZE ( am79c961_resources ) ,
. resource = am79c961_resources ,
} ;
static struct platform_device * ebsa110_devices [ ] = {
& serial_device ,
& am79c961_device ,
} ;
2011-08-02 20:52:48 +04:00
/*
* EBSA110 idling methodology :
*
* We can not execute the " wait for interrupt " instruction since that
* will stop our MCLK signal ( which provides the clock for the glue
* logic , and therefore the timer interrupt ) .
*
* Instead , we spin , polling the IRQ_STAT register for the occurrence
* of any interrupt with core clock down to the memory clock .
*/
static void ebsa110_idle ( void )
{
const char * irq_stat = ( char * ) 0xff000000 ;
/* disable clock switching */
asm volatile ( " mcr p15, 0, ip, c15, c2, 2 " : : : " cc " ) ;
/* wait for an interrupt to occur */
while ( ! * irq_stat ) ;
/* enable clock switching */
asm volatile ( " mcr p15, 0, ip, c15, c1, 2 " : : : " cc " ) ;
}
2005-04-17 02:20:36 +04:00
static int __init ebsa110_init ( void )
{
2011-08-02 20:52:48 +04:00
arm_pm_idle = ebsa110_idle ;
2005-10-31 20:14:57 +03:00
return platform_add_devices ( ebsa110_devices , ARRAY_SIZE ( ebsa110_devices ) ) ;
2005-04-17 02:20:36 +04:00
}
arch_initcall ( ebsa110_init ) ;
2013-07-09 03:01:40 +04:00
static void ebsa110_restart ( enum reboot_mode mode , const char * cmd )
2011-11-03 23:50:44 +04:00
{
soft_restart ( 0x80000000 ) ;
}
2005-04-17 02:20:36 +04:00
MACHINE_START ( EBSA110 , " EBSA110 " )
2005-07-03 20:38:58 +04:00
/* Maintainer: Russell King */
2011-07-06 06:38:11 +04:00
. atag_offset = 0x400 ,
2005-07-03 20:38:58 +04:00
. reserve_lp0 = 1 ,
. reserve_lp2 = 1 ,
. map_io = ebsa110_map_io ,
2012-03-07 07:34:19 +04:00
. init_early = ebsa110_init_early ,
2005-07-03 20:38:58 +04:00
. init_irq = ebsa110_init_irq ,
2012-11-08 23:40:59 +04:00
. init_time = ebsa110_timer_init ,
2011-11-03 23:50:44 +04:00
. restart = ebsa110_restart ,
2005-04-17 02:20:36 +04:00
MACHINE_END