2005-04-16 15:20:36 -07:00
/*
* linux / arch / arm / mach - integrator / integrator_ap . c
*
* Copyright ( C ) 2000 - 2003 Deep Blue Solutions Ltd
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
*/
# include <linux/types.h>
# include <linux/kernel.h>
# include <linux/init.h>
# include <linux/list.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <linux/slab.h>
# include <linux/string.h>
2011-04-22 22:02:55 +02:00
# include <linux/syscore_ops.h>
2006-01-07 13:52:45 +00:00
# include <linux/amba/bus.h>
# include <linux/amba/kmi.h>
2008-09-06 12:10:45 +01:00
# include <linux/io.h>
2014-05-29 16:44:27 -05:00
# include <linux/irqchip.h>
2011-05-18 10:51:52 +01:00
# include <linux/mtd/physmap.h>
2012-06-11 17:33:12 +02:00
# include <linux/platform_data/clk-integrator.h>
2012-09-06 09:08:24 +01:00
# include <linux/of_irq.h>
# include <linux/of_address.h>
2012-09-06 09:08:47 +01:00
# include <linux/of_platform.h>
2012-11-02 01:31:10 +01:00
# include <linux/stat.h>
2012-11-17 19:24:23 +01:00
# include <linux/termios.h>
2005-04-16 15:20:36 -07:00
# include <asm/setup.h>
2005-10-30 15:03:48 -08:00
# include <asm/param.h> /* HZ */
2005-04-16 15:20:36 -07:00
# include <asm/mach-types.h>
# include <asm/mach/arch.h>
# include <asm/mach/irq.h>
# include <asm/mach/map.h>
# include <asm/mach/time.h>
2014-02-13 21:26:24 +01:00
# include "hardware.h"
2013-06-16 02:44:27 +02:00
# include "cm.h"
2010-05-22 18:18:57 +01:00
# include "common.h"
2013-03-19 19:58:49 +01:00
# include "pci_v3.h"
2014-02-13 20:01:41 +01:00
# include "lm.h"
2010-05-22 18:18:57 +01:00
2012-11-04 20:49:15 +01:00
/* Base address to the AP system controller */
2012-11-17 19:24:23 +01:00
void __iomem * ap_syscon_base ;
2013-06-17 23:58:25 +02:00
/* Base address to the external bus interface */
static void __iomem * ebi_base ;
2012-11-04 20:49:15 +01:00
/*
2005-04-16 15:20:36 -07:00
* All IO addresses are mapped onto VA 0xFFF x . xxxx , where x . xxxx
* is the ( PA > > 12 ) .
*
* Setup a VA for the Integrator interrupt controller ( for header # 0 ,
* just for now ) .
*/
2011-01-19 15:32:15 +00:00
# define VA_IC_BASE __io_address(INTEGRATOR_IC_BASE)
2005-04-16 15:20:36 -07:00
/*
* Logical Physical
* ef000000 Cache flush
* f1100000 11000000 System controller registers
* f1300000 13000000 Counter / Timer
* f1400000 14000000 Interrupt controller
* f1600000 16000000 UART 0
* f1700000 17000000 UART 1
* f1a00000 1 a000000 Debug LEDs
* f1b00000 1 b000000 GPIO
*/
2013-02-14 13:50:57 +01:00
static struct map_desc ap_io_desc [ ] __initdata __maybe_unused = {
2005-10-28 15:19:10 +01:00
{
. virtual = IO_ADDRESS ( INTEGRATOR_IC_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_IC_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_UART0_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_UART0_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
. virtual = IO_ADDRESS ( INTEGRATOR_DBG_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_DBG_BASE ) ,
. length = SZ_4K ,
. type = MT_DEVICE
} , {
2010-01-17 19:59:58 +00:00
. virtual = IO_ADDRESS ( INTEGRATOR_AP_GPIO_BASE ) ,
. pfn = __phys_to_pfn ( INTEGRATOR_AP_GPIO_BASE ) ,
2005-10-28 15:19:10 +01:00
. length = SZ_4K ,
. type = MT_DEVICE
}
2005-04-16 15:20:36 -07:00
} ;
static void __init ap_map_io ( void )
{
iotable_init ( ap_io_desc , ARRAY_SIZE ( ap_io_desc ) ) ;
2013-03-19 19:58:49 +01:00
pci_v3_early_init ( ) ;
2005-04-16 15:20:36 -07:00
}
# ifdef CONFIG_PM
static unsigned long ic_irq_enable ;
2011-04-22 22:02:55 +02:00
static int irq_suspend ( void )
2005-04-16 15:20:36 -07:00
{
ic_irq_enable = readl ( VA_IC_BASE + IRQ_ENABLE ) ;
return 0 ;
}
2011-04-22 22:02:55 +02:00
static void irq_resume ( void )
2005-04-16 15:20:36 -07:00
{
/* disable all irq sources */
2013-06-16 02:44:27 +02:00
cm_clear_irqs ( ) ;
2005-04-16 15:20:36 -07:00
writel ( - 1 , VA_IC_BASE + IRQ_ENABLE_CLEAR ) ;
writel ( - 1 , VA_IC_BASE + FIQ_ENABLE_CLEAR ) ;
writel ( ic_irq_enable , VA_IC_BASE + IRQ_ENABLE_SET ) ;
}
# else
# define irq_suspend NULL
# define irq_resume NULL
# endif
2011-04-22 22:02:55 +02:00
static struct syscore_ops irq_syscore_ops = {
2005-04-16 15:20:36 -07:00
. suspend = irq_suspend ,
. resume = irq_resume ,
} ;
2011-04-22 22:02:55 +02:00
static int __init irq_syscore_init ( void )
2005-04-16 15:20:36 -07:00
{
2011-04-22 22:02:55 +02:00
register_syscore_ops ( & irq_syscore_ops ) ;
return 0 ;
2005-04-16 15:20:36 -07:00
}
2011-04-22 22:02:55 +02:00
device_initcall ( irq_syscore_init ) ;
2005-04-16 15:20:36 -07:00
/*
* Flash handling .
*/
2011-05-18 10:51:52 +01:00
static int ap_flash_init ( struct platform_device * dev )
2005-04-16 15:20:36 -07:00
{
u32 tmp ;
2012-11-04 20:49:15 +01:00
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP ,
ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET ) ;
2005-04-16 15:20:36 -07:00
2013-06-17 23:58:25 +02:00
tmp = readl ( ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) |
INTEGRATOR_EBI_WRITE_ENABLE ;
writel ( tmp , ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) ;
2005-04-16 15:20:36 -07:00
2013-06-17 23:58:25 +02:00
if ( ! ( readl ( ebi_base + INTEGRATOR_EBI_CSR1_OFFSET )
& INTEGRATOR_EBI_WRITE_ENABLE ) ) {
writel ( 0xa05f , ebi_base + INTEGRATOR_EBI_LOCK_OFFSET ) ;
writel ( tmp , ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) ;
writel ( 0 , ebi_base + INTEGRATOR_EBI_LOCK_OFFSET ) ;
2005-04-16 15:20:36 -07:00
}
return 0 ;
}
2011-05-18 10:51:52 +01:00
static void ap_flash_exit ( struct platform_device * dev )
2005-04-16 15:20:36 -07:00
{
u32 tmp ;
2012-11-04 20:49:15 +01:00
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN | INTEGRATOR_SC_CTRL_nFLWP ,
ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET ) ;
2005-04-16 15:20:36 -07:00
2013-06-17 23:58:25 +02:00
tmp = readl ( ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) &
~ INTEGRATOR_EBI_WRITE_ENABLE ;
writel ( tmp , ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) ;
2005-04-16 15:20:36 -07:00
2013-06-17 23:58:25 +02:00
if ( readl ( ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) &
INTEGRATOR_EBI_WRITE_ENABLE ) {
writel ( 0xa05f , ebi_base + INTEGRATOR_EBI_LOCK_OFFSET ) ;
writel ( tmp , ebi_base + INTEGRATOR_EBI_CSR1_OFFSET ) ;
writel ( 0 , ebi_base + INTEGRATOR_EBI_LOCK_OFFSET ) ;
2005-04-16 15:20:36 -07:00
}
}
2011-05-18 10:51:55 +01:00
static void ap_flash_set_vpp ( struct platform_device * pdev , int on )
2005-04-16 15:20:36 -07:00
{
2012-11-04 20:49:15 +01:00
if ( on )
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN ,
ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET ) ;
else
writel ( INTEGRATOR_SC_CTRL_nFLVPPEN ,
ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET ) ;
2005-04-16 15:20:36 -07:00
}
2011-05-18 10:51:52 +01:00
static struct physmap_flash_data ap_flash_data = {
2005-04-16 15:20:36 -07:00
. width = 4 ,
. init = ap_flash_init ,
. exit = ap_flash_exit ,
. set_vpp = ap_flash_set_vpp ,
} ;
2012-11-17 19:24:23 +01:00
/*
* For the PL010 found in the Integrator / AP some of the UART control is
* implemented in the system controller and accessed using a callback
* from the driver .
*/
static void integrator_uart_set_mctrl ( struct amba_device * dev ,
void __iomem * base , unsigned int mctrl )
{
unsigned int ctrls = 0 , ctrlc = 0 , rts_mask , dtr_mask ;
u32 phybase = dev - > res . start ;
if ( phybase = = INTEGRATOR_UART0_BASE ) {
/* UART0 */
rts_mask = 1 < < 4 ;
dtr_mask = 1 < < 5 ;
} else {
/* UART1 */
rts_mask = 1 < < 6 ;
dtr_mask = 1 < < 7 ;
}
if ( mctrl & TIOCM_RTS )
ctrlc | = rts_mask ;
else
ctrls | = rts_mask ;
if ( mctrl & TIOCM_DTR )
ctrlc | = dtr_mask ;
else
ctrls | = dtr_mask ;
__raw_writel ( ctrls , ap_syscon_base + INTEGRATOR_SC_CTRLS_OFFSET ) ;
__raw_writel ( ctrlc , ap_syscon_base + INTEGRATOR_SC_CTRLC_OFFSET ) ;
}
struct amba_pl010_data ap_uart_data = {
. set_mctrl = integrator_uart_set_mctrl ,
} ;
2012-06-11 17:33:12 +02:00
void __init ap_init_early ( void )
{
}
2012-09-06 09:08:24 +01:00
static void __init ap_init_irq_of ( void )
{
2013-06-16 02:44:27 +02:00
cm_init ( ) ;
2014-05-29 16:44:27 -05:00
irqchip_init ( ) ;
2012-09-06 09:08:24 +01:00
}
2012-09-06 09:08:47 +01:00
/* For the Device Tree, add in the UART callbacks as AUXDATA */
static struct of_dev_auxdata ap_auxdata_lookup [ ] __initdata = {
OF_DEV_AUXDATA ( " arm,primecell " , INTEGRATOR_RTC_BASE ,
" rtc " , NULL ) ,
OF_DEV_AUXDATA ( " arm,primecell " , INTEGRATOR_UART0_BASE ,
2012-11-17 19:24:23 +01:00
" uart0 " , & ap_uart_data ) ,
2012-09-06 09:08:47 +01:00
OF_DEV_AUXDATA ( " arm,primecell " , INTEGRATOR_UART1_BASE ,
2012-11-17 19:24:23 +01:00
" uart1 " , & ap_uart_data ) ,
2012-09-06 09:08:47 +01:00
OF_DEV_AUXDATA ( " arm,primecell " , KMI0_BASE ,
" kmi0 " , NULL ) ,
OF_DEV_AUXDATA ( " arm,primecell " , KMI1_BASE ,
" kmi1 " , NULL ) ,
2012-09-06 09:09:11 +01:00
OF_DEV_AUXDATA ( " cfi-flash " , INTEGRATOR_FLASH_BASE ,
" physmap-flash " , & ap_flash_data ) ,
2012-09-06 09:08:47 +01:00
{ /* sentinel */ } ,
} ;
2013-10-10 18:24:58 +02:00
static const struct of_device_id ap_syscon_match [ ] = {
{ . compatible = " arm,integrator-ap-syscon " } ,
{ } ,
} ;
2013-06-17 23:58:25 +02:00
static const struct of_device_id ebi_match [ ] = {
{ . compatible = " arm,external-bus-interface " } ,
{ } ,
} ;
2012-09-06 09:08:47 +01:00
static void __init ap_init_of ( void )
{
unsigned long sc_dec ;
2012-11-02 01:31:10 +01:00
struct device_node * syscon ;
2013-06-17 23:58:25 +02:00
struct device_node * ebi ;
2012-09-06 09:08:47 +01:00
int i ;
2014-06-24 14:08:07 +02:00
syscon = of_find_matching_node ( NULL , ap_syscon_match ) ;
2012-11-02 01:31:10 +01:00
if ( ! syscon )
return ;
2014-06-24 14:08:07 +02:00
ebi = of_find_matching_node ( NULL , ebi_match ) ;
2013-06-17 23:58:25 +02:00
if ( ! ebi )
return ;
2012-11-02 01:31:10 +01:00
ap_syscon_base = of_iomap ( syscon , 0 ) ;
if ( ! ap_syscon_base )
return ;
2013-06-17 23:58:25 +02:00
ebi_base = of_iomap ( ebi , 0 ) ;
if ( ! ebi_base )
return ;
2012-11-02 01:31:10 +01:00
2014-06-24 14:08:07 +02:00
of_platform_populate ( NULL , of_default_bus_match_table ,
ap_auxdata_lookup , NULL ) ;
2012-11-04 20:49:15 +01:00
sc_dec = readl ( ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET ) ;
2012-09-06 09:08:47 +01:00
for ( i = 0 ; i < 4 ; i + + ) {
struct lm_device * lmdev ;
if ( ( sc_dec & ( 16 < < i ) ) = = 0 )
continue ;
lmdev = kzalloc ( sizeof ( struct lm_device ) , GFP_KERNEL ) ;
if ( ! lmdev )
continue ;
lmdev - > resource . start = 0xc0000000 + 0x10000000 * i ;
lmdev - > resource . end = lmdev - > resource . start + 0x0fffffff ;
lmdev - > resource . flags = IORESOURCE_MEM ;
2013-06-15 23:56:32 +02:00
lmdev - > irq = irq_of_parse_and_map ( syscon , i ) ;
2012-09-06 09:08:47 +01:00
lmdev - > id = i ;
lm_device_register ( lmdev ) ;
}
}
2012-09-06 09:08:24 +01:00
static const char * ap_dt_board_compat [ ] = {
" arm,integrator-ap " ,
NULL ,
} ;
DT_MACHINE_START ( INTEGRATOR_AP_DT , " ARM Integrator/AP (Device Tree) " )
. reserve = integrator_reserve ,
. map_io = ap_map_io ,
. init_early = ap_init_early ,
. init_irq = ap_init_irq_of ,
2012-09-06 09:08:47 +01:00
. init_machine = ap_init_of ,
2012-09-06 09:08:24 +01:00
. dt_compat = ap_dt_board_compat ,
MACHINE_END