2005-04-17 02:20:36 +04:00
/*
* linux / arch / arm / mach - h720x / cpu - h7202 . c
*
* Copyright ( C ) 2003 Thomas Gleixner < tglx @ linutronix . de >
* 2003 Robert Schwebel < r . schwebel @ pengutronix . de >
* 2004 Sascha Hauer < s . hauer @ pengutronix . de >
*
* processor specific stuff for the Hynix h7202
*
* 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/init.h>
# include <linux/interrupt.h>
# include <linux/module.h>
# include <asm/types.h>
2008-08-05 19:14:15 +04:00
# include <mach/hardware.h>
2005-04-17 02:20:36 +04:00
# include <asm/irq.h>
2008-08-05 19:14:15 +04:00
# include <mach/irqs.h>
2005-04-17 02:20:36 +04:00
# include <asm/mach/irq.h>
# include <asm/mach/time.h>
# include <linux/device.h>
# include <linux/serial_8250.h>
# include "common.h"
static struct resource h7202ps2_resources [ ] = {
[ 0 ] = {
. start = 0x8002c000 ,
. end = 0x8002c040 ,
. flags = IORESOURCE_MEM ,
} ,
[ 1 ] = {
. start = IRQ_PS2 ,
. end = IRQ_PS2 ,
. flags = IORESOURCE_IRQ ,
} ,
} ;
static struct platform_device h7202ps2_device = {
. name = " h7202ps2 " ,
. id = - 1 ,
. num_resources = ARRAY_SIZE ( h7202ps2_resources ) ,
. resource = h7202ps2_resources ,
} ;
static struct plat_serial8250_port serial_platform_data [ ] = {
{
. membase = ( void * ) SERIAL0_VIRT ,
. mapbase = SERIAL0_BASE ,
. irq = IRQ_UART0 ,
. uartclk = 2 * 1843200 ,
. regshift = 2 ,
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST ,
} ,
{
. membase = ( void * ) SERIAL1_VIRT ,
. mapbase = SERIAL1_BASE ,
. irq = IRQ_UART1 ,
. uartclk = 2 * 1843200 ,
. regshift = 2 ,
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST ,
} ,
# ifdef CONFIG_H7202_SERIAL23
{
. membase = ( void * ) SERIAL2_VIRT ,
. mapbase = SERIAL2_BASE ,
. irq = IRQ_UART2 ,
. uartclk = 2 * 1843200 ,
. regshift = 2 ,
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST ,
} ,
{
. membase = ( void * ) SERIAL3_VIRT ,
. mapbase = SERIAL3_BASE ,
. irq = IRQ_UART3 ,
. uartclk = 2 * 1843200 ,
. regshift = 2 ,
. iotype = UPIO_MEM ,
. flags = UPF_BOOT_AUTOCONF | UPF_SKIP_TEST ,
} ,
# endif
{ } ,
} ;
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 ,
} ,
} ;
static struct platform_device * devices [ ] __initdata = {
& h7202ps2_device ,
& serial_device ,
} ;
/* Although we have two interrupt lines for the timers, we only have one
* status register which clears all pending timer interrupts on reading . So
* we have to handle all timer interrupts in one place .
*/
static void
2006-11-23 14:41:32 +03:00
h7202_timerx_demux_handler ( unsigned int irq_unused , struct irq_desc * desc )
2005-04-17 02:20:36 +04:00
{
unsigned int mask , irq ;
mask = CPU_REG ( TIMER_VIRT , TIMER_TOPSTAT ) ;
if ( mask & TSTAT_T0INT ) {
2006-10-06 21:53:39 +04:00
timer_tick ( ) ;
2005-04-17 02:20:36 +04:00
if ( mask = = TSTAT_T0INT )
return ;
}
mask > > = 1 ;
irq = IRQ_TIMER1 ;
while ( mask ) {
if ( mask & 1 )
2008-10-09 16:36:24 +04:00
generic_handle_irq ( irq ) ;
2005-04-17 02:20:36 +04:00
irq + + ;
mask > > = 1 ;
}
}
/*
* Timer interrupt handler
*/
static irqreturn_t
2006-10-06 21:53:39 +04:00
h7202_timer_interrupt ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
2006-10-06 21:53:39 +04:00
h7202_timerx_demux_handler ( 0 , NULL ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
/*
2007-05-11 23:40:30 +04:00
* mask multiplexed timer IRQs
2005-04-17 02:20:36 +04:00
*/
2011-03-28 12:54:40 +04:00
static void inline __mask_timerx_irq ( unsigned int irq )
2005-04-17 02:20:36 +04:00
{
unsigned int bit ;
2011-03-28 12:54:40 +04:00
bit = 2 < < ( ( irq = = IRQ_TIMER64B ) ? 4 : ( irq - IRQ_TIMER1 ) ) ;
2005-04-17 02:20:36 +04:00
CPU_REG ( TIMER_VIRT , TIMER_TOPCTRL ) & = ~ bit ;
}
2011-03-28 12:54:40 +04:00
static void inline mask_timerx_irq ( struct irq_data * d )
{
__mask_timerx_irq ( d - > irq ) ;
}
2005-04-17 02:20:36 +04:00
/*
2007-05-11 23:40:30 +04:00
* unmask multiplexed timer IRQs
2005-04-17 02:20:36 +04:00
*/
2010-11-29 12:31:06 +03:00
static void inline unmask_timerx_irq ( struct irq_data * d )
2005-04-17 02:20:36 +04:00
{
unsigned int bit ;
2010-11-29 12:31:06 +03:00
bit = 2 < < ( ( d - > irq = = IRQ_TIMER64B ) ? 4 : ( d - > irq - IRQ_TIMER1 ) ) ;
2005-04-17 02:20:36 +04:00
CPU_REG ( TIMER_VIRT , TIMER_TOPCTRL ) | = bit ;
}
2006-11-23 14:41:32 +03:00
static struct irq_chip h7202_timerx_chip = {
2010-11-29 12:31:06 +03:00
. irq_ack = mask_timerx_irq ,
. irq_mask = mask_timerx_irq ,
. irq_unmask = unmask_timerx_irq ,
2005-04-17 02:20:36 +04:00
} ;
static struct irqaction h7202_timer_irq = {
. name = " h7202 Timer Tick " ,
2007-05-08 11:35:39 +04:00
. flags = IRQF_DISABLED | IRQF_TIMER | IRQF_IRQPOLL ,
2005-06-26 20:06:36 +04:00
. handler = h7202_timer_interrupt ,
2005-04-17 02:20:36 +04:00
} ;
/*
* Setup TIMER0 as system timer
*/
void __init h7202_init_time ( void )
{
CPU_REG ( TIMER_VIRT , TM0_PERIOD ) = LATCH ;
CPU_REG ( TIMER_VIRT , TM0_CTRL ) = TM_RESET ;
CPU_REG ( TIMER_VIRT , TM0_CTRL ) = TM_REPEAT | TM_START ;
CPU_REG ( TIMER_VIRT , TIMER_TOPCTRL ) = ENABLE_TM0_INTR | TIMER_ENABLE_BIT ;
setup_irq ( IRQ_TIMER0 , & h7202_timer_irq ) ;
}
struct sys_timer h7202_timer = {
. init = h7202_init_time ,
. offset = h720x_gettimeoffset ,
} ;
void __init h7202_init_irq ( void )
{
int irq ;
CPU_REG ( GPIO_E_VIRT , GPIO_MASK ) = 0x0 ;
for ( irq = IRQ_TIMER1 ;
irq < IRQ_CHAINED_TIMERX ( NR_TIMERX_IRQS ) ; irq + + ) {
2011-03-28 12:54:40 +04:00
__mask_timerx_irq ( irq ) ;
2011-03-24 15:35:09 +03:00
irq_set_chip_and_handler ( irq , & h7202_timerx_chip ,
handle_edge_irq ) ;
2005-04-17 02:20:36 +04:00
set_irq_flags ( irq , IRQF_VALID ) ;
}
2011-03-24 15:25:22 +03:00
irq_set_chained_handler ( IRQ_TIMERX , h7202_timerx_demux_handler ) ;
2005-04-17 02:20:36 +04:00
h720x_init_irq ( ) ;
}
void __init init_hw_h7202 ( void )
{
/* Enable clocks */
CPU_REG ( PMU_BASE , PMU_PLL_CTRL ) | = PLL_2_EN | PLL_1_EN | PLL_3_MUTE ;
CPU_REG ( SERIAL0_VIRT , SERIAL_ENABLE ) = SERIAL_ENABLE_EN ;
CPU_REG ( SERIAL1_VIRT , SERIAL_ENABLE ) = SERIAL_ENABLE_EN ;
# ifdef CONFIG_H7202_SERIAL23
CPU_REG ( SERIAL2_VIRT , SERIAL_ENABLE ) = SERIAL_ENABLE_EN ;
CPU_REG ( SERIAL3_VIRT , SERIAL_ENABLE ) = SERIAL_ENABLE_EN ;
CPU_IO ( GPIO_AMULSEL ) = AMULSEL_USIN2 | AMULSEL_USOUT2 |
AMULSEL_USIN3 | AMULSEL_USOUT3 ;
# endif
( void ) platform_add_devices ( devices , ARRAY_SIZE ( devices ) ) ;
}