2005-04-16 15:20:36 -07: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 12:10:45 +01:00
# include <linux/io.h>
2005-04-16 15:20:36 -07:00
2008-08-05 16:14:15 +01:00
# include <mach/hardware.h>
2005-04-16 15:20:36 -07:00
# include <asm/irq.h>
# include <asm/setup.h>
# include <asm/mach-types.h>
# include <asm/pgtable.h>
# include <asm/page.h>
# include <asm/system.h>
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
# include <asm/mach/time.h>
# define IRQ_MASK 0xfe000000 /* read */
# define IRQ_MSET 0xfe000000 /* write */
# define IRQ_STAT 0xff000000 /* read */
# define IRQ_MCLR 0xff000000 /* write */
2010-11-29 10:29:25 +01:00
static void ebsa110_mask_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
2010-11-29 10:29:25 +01:00
__raw_writeb ( 1 < < d - > irq , IRQ_MCLR ) ;
2005-04-16 15:20:36 -07:00
}
2010-11-29 10:29:25 +01:00
static void ebsa110_unmask_irq ( struct irq_data * d )
2005-04-16 15:20:36 -07:00
{
2010-11-29 10:29:25 +01:00
__raw_writeb ( 1 < < d - > irq , IRQ_MSET ) ;
2005-04-16 15:20:36 -07:00
}
2006-11-23 11:41:32 +00:00
static struct irq_chip ebsa110_irq_chip = {
2010-11-29 10:29:25 +01:00
. irq_ack = ebsa110_mask_irq ,
. irq_mask = ebsa110_mask_irq ,
. irq_unmask = ebsa110_unmask_irq ,
2005-04-16 15:20:36 -07: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 13:35:09 +01:00
irq_set_chip_and_handler ( irq , & ebsa110_irq_chip ,
handle_level_irq ) ;
2005-04-16 15:20:36 -07: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 15:19:08 +01:00
{ /* IRQ_STAT/IRQ_MCLR */
. virtual = IRQ_STAT ,
. pfn = __phys_to_pfn ( TRICK4_PHYS ) ,
. length = PGDIR_SIZE ,
. type = MT_DEVICE
} , { /* IRQ_MASK/IRQ_MSET */
. virtual = IRQ_MASK ,
. pfn = __phys_to_pfn ( TRICK3_PHYS ) ,
. length = PGDIR_SIZE ,
. type = MT_DEVICE
} , { /* SOFT_BASE */
. virtual = SOFT_BASE ,
. pfn = __phys_to_pfn ( TRICK1_PHYS ) ,
. length = PGDIR_SIZE ,
. type = MT_DEVICE
} , { /* PIT_BASE */
. virtual = PIT_BASE ,
. pfn = __phys_to_pfn ( TRICK0_PHYS ) ,
. length = PGDIR_SIZE ,
. type = MT_DEVICE
} ,
2005-04-16 15:20:36 -07:00
/*
* self - decode ISAIO space
*/
2005-10-28 15:19:08 +01: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-16 15:20:36 -07:00
} ;
static void __init ebsa110_map_io ( void )
{
iotable_init ( ebsa110_io_desc , ARRAY_SIZE ( ebsa110_io_desc ) ) ;
}
# 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 .
*/
static unsigned long ebsa110_gettimeoffset ( void )
{
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 ;
return offset ;
}
static irqreturn_t
2006-10-06 10:53:39 -07:00
ebsa110_timer_interrupt ( int irq , void * dev_id )
2005-04-16 15:20:36 -07: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 10:53:39 -07:00
timer_tick ( ) ;
2005-04-16 15:20:36 -07:00
return IRQ_HANDLED ;
}
static struct irqaction ebsa110_timer_irq = {
. name = " EBSA110 Timer Tick " ,
2007-05-08 00:35:39 -07:00
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2005-06-26 17:06:36 +01:00
. handler = ebsa110_timer_interrupt ,
2005-04-16 15:20:36 -07:00
} ;
/*
* Set up timer interrupt .
*/
static void __init ebsa110_timer_init ( void )
{
/*
* 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 sys_timer ebsa110_timer = {
. init = ebsa110_timer_init ,
. offset = ebsa110_gettimeoffset ,
} ;
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 16:04:41 +01:00
. id = PLAT8250_DEV_PLATFORM ,
2005-04-16 15:20:36 -07:00
. dev = {
. platform_data = serial_platform_data ,
} ,
} ;
2005-10-31 17:14:57 +00: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 ,
} ;
2005-04-16 15:20:36 -07:00
static int __init ebsa110_init ( void )
{
2005-10-31 17:14:57 +00:00
return platform_add_devices ( ebsa110_devices , ARRAY_SIZE ( ebsa110_devices ) ) ;
2005-04-16 15:20:36 -07:00
}
arch_initcall ( ebsa110_init ) ;
MACHINE_START ( EBSA110 , " EBSA110 " )
2005-07-03 17:38:58 +01:00
/* Maintainer: Russell King */
2011-07-05 22:38:11 -04:00
. atag_offset = 0x400 ,
2005-07-03 17:38:58 +01:00
. reserve_lp0 = 1 ,
. reserve_lp2 = 1 ,
. soft_reboot = 1 ,
. map_io = ebsa110_map_io ,
. init_irq = ebsa110_init_irq ,
2005-04-16 15:20:36 -07:00
. timer = & ebsa110_timer ,
MACHINE_END