2006-06-18 02:52:45 +04:00
/*
* MPC86xx HPCN board specific routines
*
* Recode : ZHANG WEI < wei . zhang @ freescale . com >
* Initial author : Xianghua Xiao < x . xiao @ freescale . com >
*
* Copyright 2006 Freescale Semiconductor Inc .
*
* 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 .
*/
# include <linux/stddef.h>
# include <linux/kernel.h>
# include <linux/pci.h>
# include <linux/kdev_t.h>
# include <linux/delay.h>
# include <linux/seq_file.h>
# include <asm/system.h>
# include <asm/time.h>
# include <asm/machdep.h>
# include <asm/pci-bridge.h>
# include <asm/mpc86xx.h>
# include <asm/prom.h>
# include <mm/mmu_decl.h>
# include <asm/udbg.h>
# include <asm/i8259.h>
# include <asm/mpic.h>
# include <sysdev/fsl_soc.h>
# include "mpc86xx.h"
2006-06-28 09:37:45 +04:00
# include "mpc8641_hpcn.h"
2006-06-18 02:52:45 +04:00
2006-08-01 00:35:41 +04:00
# undef DEBUG
# ifdef DEBUG
# define DBG(fmt...) do { printk(KERN_ERR fmt); } while(0)
# else
# define DBG(fmt...) do { } while(0)
# endif
2006-08-16 01:19:02 +04:00
# ifdef CONFIG_PCI
2006-10-07 16:08:26 +04:00
static void mpc86xx_8259_cascade ( unsigned int irq , struct irq_desc * desc )
2006-08-01 00:35:41 +04:00
{
2006-10-07 16:08:26 +04:00
unsigned int cascade_irq = i8259_irq ( ) ;
2006-08-01 00:35:41 +04:00
if ( cascade_irq ! = NO_IRQ )
2006-10-06 05:31:10 +04:00
generic_handle_irq ( cascade_irq ) ;
2006-08-01 00:35:41 +04:00
desc - > chip - > eoi ( irq ) ;
}
2006-08-16 01:19:02 +04:00
# endif /* CONFIG_PCI */
2006-06-18 02:52:45 +04:00
void __init
mpc86xx_hpcn_init_irq ( void )
{
struct mpic * mpic1 ;
2006-08-16 01:19:02 +04:00
struct device_node * np ;
2006-08-17 23:27:57 +04:00
struct resource res ;
2006-08-16 01:19:02 +04:00
# ifdef CONFIG_PCI
struct device_node * cascade_node = NULL ;
int cascade_irq ;
# endif
2006-06-18 02:52:45 +04:00
2006-08-17 23:27:57 +04:00
/* Determine PIC address. */
2006-08-01 00:35:41 +04:00
np = of_find_node_by_type ( NULL , " open-pic " ) ;
if ( np = = NULL )
return ;
2006-08-17 23:27:57 +04:00
of_address_to_resource ( np , 0 , & res ) ;
2006-06-18 02:52:45 +04:00
/* Alloc mpic structure and per isu has 16 INT entries. */
2006-08-17 23:27:57 +04:00
mpic1 = mpic_alloc ( np , res . start ,
2006-06-18 02:52:45 +04:00
MPIC_PRIMARY | MPIC_WANTS_RESET | MPIC_BIG_ENDIAN ,
2006-08-01 00:35:41 +04:00
16 , NR_IRQS - 4 ,
2006-06-18 02:52:45 +04:00
" MPIC " ) ;
BUG_ON ( mpic1 = = NULL ) ;
2006-08-17 23:27:57 +04:00
mpic_assign_isu ( mpic1 , 0 , res . start + 0x10000 ) ;
2006-08-01 00:35:41 +04:00
2006-06-18 02:52:45 +04:00
/* 48 Internal Interrupts */
2006-08-17 23:27:57 +04:00
mpic_assign_isu ( mpic1 , 1 , res . start + 0x10200 ) ;
mpic_assign_isu ( mpic1 , 2 , res . start + 0x10400 ) ;
mpic_assign_isu ( mpic1 , 3 , res . start + 0x10600 ) ;
2006-06-18 02:52:45 +04:00
2006-08-01 00:35:41 +04:00
/* 16 External interrupts
* Moving them from [ 0 - 15 ] to [ 64 - 79 ]
*/
2006-08-17 23:27:57 +04:00
mpic_assign_isu ( mpic1 , 4 , res . start + 0x10000 ) ;
2006-06-18 02:52:45 +04:00
mpic_init ( mpic1 ) ;
# ifdef CONFIG_PCI
2006-08-01 00:35:41 +04:00
/* Initialize i8259 controller */
for_each_node_by_type ( np , " interrupt-controller " )
2007-05-03 11:26:52 +04:00
if ( of_device_is_compatible ( np , " chrp,iic " ) ) {
2006-08-01 00:35:41 +04:00
cascade_node = np ;
break ;
}
if ( cascade_node = = NULL ) {
printk ( KERN_DEBUG " mpc86xxhpcn: no ISA interrupt controller \n " ) ;
return ;
}
2006-06-18 02:52:45 +04:00
2006-08-01 00:35:41 +04:00
cascade_irq = irq_of_parse_and_map ( cascade_node , 0 ) ;
if ( cascade_irq = = NO_IRQ ) {
printk ( KERN_ERR " mpc86xxhpcn: failed to map cascade interrupt " ) ;
return ;
}
DBG ( " mpc86xxhpcn: cascade mapped to irq %d \n " , cascade_irq ) ;
2006-06-18 02:52:45 +04:00
2006-08-01 00:35:41 +04:00
i8259_init ( cascade_node , 0 ) ;
2007-02-17 01:17:41 +03:00
of_node_put ( cascade_node ) ;
2006-08-01 00:35:41 +04:00
set_irq_chained_handler ( cascade_irq , mpc86xx_8259_cascade ) ;
# endif
}
2006-06-18 02:52:45 +04:00
# ifdef CONFIG_PCI
2006-08-01 00:35:41 +04:00
enum pirq { PIRQA = 8 , PIRQB , PIRQC , PIRQD , PIRQE , PIRQF , PIRQG , PIRQH } ;
const unsigned char uli1575_irq_route_table [ 16 ] = {
0 , /* 0: Reserved */
0x8 , /* 1: 0b1000 */
0 , /* 2: Reserved */
0x2 , /* 3: 0b0010 */
0x4 , /* 4: 0b0100 */
0x5 , /* 5: 0b0101 */
0x7 , /* 6: 0b0111 */
0x6 , /* 7: 0b0110 */
0 , /* 8: Reserved */
0x1 , /* 9: 0b0001 */
0x3 , /* 10: 0b0011 */
0x9 , /* 11: 0b1001 */
0xb , /* 12: 0b1011 */
0 , /* 13: Reserved */
0xd , /* 14, 0b1101 */
0xf , /* 15, 0b1111 */
} ;
static int __devinit
get_pci_irq_from_of ( struct pci_controller * hose , int slot , int pin )
2006-06-18 02:52:45 +04:00
{
2006-08-01 00:35:41 +04:00
struct of_irq oirq ;
u32 laddr [ 3 ] ;
struct device_node * hosenode = hose ? hose - > arch_data : NULL ;
if ( ! hosenode ) return - EINVAL ;
laddr [ 0 ] = ( hose - > first_busno < < 16 ) | ( PCI_DEVFN ( slot , 0 ) < < 8 ) ;
laddr [ 1 ] = laddr [ 2 ] = 0 ;
2006-09-01 19:17:20 +04:00
of_irq_map_raw ( hosenode , & pin , 1 , laddr , & oirq ) ;
2006-08-01 00:35:41 +04:00
DBG ( " mpc86xx_hpcn: pci irq addr %x, slot %d, pin %d, irq %d \n " ,
laddr [ 0 ] , slot , pin , oirq . specifier [ 0 ] ) ;
return oirq . specifier [ 0 ] ;
2006-06-18 02:52:45 +04:00
}
2006-08-01 00:35:41 +04:00
static void __devinit quirk_uli1575 ( struct pci_dev * dev )
2006-06-28 09:37:45 +04:00
{
unsigned short temp ;
2006-08-01 00:35:41 +04:00
struct pci_controller * hose = pci_bus_to_host ( dev - > bus ) ;
2007-05-03 01:53:38 +04:00
unsigned char irq2pin [ 16 ] , c ;
2006-08-01 00:35:41 +04:00
unsigned long pirq_map_word = 0 ;
u32 irq ;
int i ;
2006-06-18 02:52:45 +04:00
2006-06-28 09:37:45 +04:00
/*
2006-08-01 00:35:41 +04:00
* ULI1575 interrupts route setup
*/
memset ( irq2pin , 0 , 16 ) ; /* Initialize default value 0 */
/*
* PIRQA - > PIRQD mapping read from OF - tree
*
* interrupts for PCI slot0 - - PIRQA / PIRQB / PIRQC / PIRQD
* PCI slot1 - - PIRQB / PIRQC / PIRQD / PIRQA
*/
for ( i = 0 ; i < 4 ; i + + ) {
irq = get_pci_irq_from_of ( hose , 17 , i + 1 ) ;
if ( irq > 0 & & irq < 16 )
irq2pin [ irq ] = PIRQA + i ;
else
printk ( KERN_WARNING " ULI1575 device "
" (slot %d, pin %d) irq %d is invalid. \n " ,
17 , i , irq ) ;
}
/*
* PIRQE - > PIRQF mapping set manually
2006-06-28 09:37:45 +04:00
*
* IRQ pin IRQ #
* PIRQE - - - - 9
* PIRQF - - - - 10
* PIRQG - - - - 11
* PIRQH - - - - 12
*/
2006-08-01 00:35:41 +04:00
for ( i = 0 ; i < 4 ; i + + ) irq2pin [ i + 9 ] = PIRQE + i ;
/* Set IRQ-PIRQ Mapping to ULI1575 */
for ( i = 0 ; i < 16 ; i + + )
if ( irq2pin [ i ] )
pirq_map_word | = ( uli1575_irq_route_table [ i ] & 0xf )
< < ( ( irq2pin [ i ] - PIRQA ) * 4 ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* ULI1575 IRQ mapping conf register default value is 0xb9317542 */
DBG ( " Setup ULI1575 IRQ mapping configuration register value = 0x%x \n " ,
pirq_map_word ) ;
pci_write_config_dword ( dev , 0x48 , pirq_map_word ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
# define ULI1575_SET_DEV_IRQ(slot, pin, reg) \
do { \
int irq ; \
irq = get_pci_irq_from_of ( hose , slot , pin ) ; \
if ( irq > 0 & & irq < 16 ) \
pci_write_config_byte ( dev , reg , irq2pin [ irq ] ) ; \
else \
printk ( KERN_WARNING " ULI1575 device " \
" (slot %d, pin %d) irq %d is invalid. \n " , \
slot , pin , irq ) ; \
} while ( 0 )
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* USB 1.1 OHCI controller 1, slot 28, pin 1 */
ULI1575_SET_DEV_IRQ ( 28 , 1 , 0x86 ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* USB 1.1 OHCI controller 2, slot 28, pin 2 */
ULI1575_SET_DEV_IRQ ( 28 , 2 , 0x87 ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* USB 1.1 OHCI controller 3, slot 28, pin 3 */
ULI1575_SET_DEV_IRQ ( 28 , 3 , 0x88 ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* USB 2.0 controller, slot 28, pin 4 */
irq = get_pci_irq_from_of ( hose , 28 , 4 ) ;
if ( irq > = 0 & & irq < = 15 )
pci_write_config_dword ( dev , 0x74 , uli1575_irq_route_table [ irq ] ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* Audio controller, slot 29, pin 1 */
ULI1575_SET_DEV_IRQ ( 29 , 1 , 0x8a ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* Modem controller, slot 29, pin 2 */
ULI1575_SET_DEV_IRQ ( 29 , 2 , 0x8b ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* HD audio controller, slot 29, pin 3 */
ULI1575_SET_DEV_IRQ ( 29 , 3 , 0x8c ) ;
2006-06-28 09:37:45 +04:00
2006-08-01 00:35:41 +04:00
/* SMB interrupt: slot 30, pin 1 */
ULI1575_SET_DEV_IRQ ( 30 , 1 , 0x8e ) ;
/* PMU ACPI SCI interrupt: slot 30, pin 2 */
ULI1575_SET_DEV_IRQ ( 30 , 2 , 0x8f ) ;
/* Serial ATA interrupt: slot 31, pin 1 */
ULI1575_SET_DEV_IRQ ( 31 , 1 , 0x8d ) ;
2006-06-28 09:37:45 +04:00
/* Primary PATA IDE IRQ: 14
* Secondary PATA IDE IRQ : 15
*/
2006-08-01 00:35:41 +04:00
pci_write_config_byte ( dev , 0x44 , 0x30 | uli1575_irq_route_table [ 14 ] ) ;
pci_write_config_byte ( dev , 0x75 , uli1575_irq_route_table [ 15 ] ) ;
2006-06-28 09:37:45 +04:00
/* Set IRQ14 and IRQ15 to legacy IRQs */
pci_read_config_word ( dev , 0x46 , & temp ) ;
temp | = 0xc000 ;
pci_write_config_word ( dev , 0x46 , temp ) ;
/* Set i8259 interrupt trigger
* IRQ 3 : Level
* IRQ 4 : Level
* IRQ 5 : Level
* IRQ 6 : Level
* IRQ 7 : Level
* IRQ 9 : Level
* IRQ 10 : Level
* IRQ 11 : Level
* IRQ 12 : Level
* IRQ 14 : Edge
* IRQ 15 : Edge
*/
outb ( 0xfa , 0x4d0 ) ;
outb ( 0x1e , 0x4d1 ) ;
2006-08-01 00:35:41 +04:00
# undef ULI1575_SET_DEV_IRQ
2007-05-03 01:53:38 +04:00
/* Disable the HD interface and enable the AC97 interface. */
pci_read_config_byte ( dev , 0xb8 , & c ) ;
c & = 0x7f ;
pci_write_config_byte ( dev , 0xb8 , c ) ;
2006-06-28 09:37:45 +04:00
}
static void __devinit quirk_uli5288 ( struct pci_dev * dev )
2006-06-18 02:52:45 +04:00
{
2006-06-28 09:37:45 +04:00
unsigned char c ;
pci_read_config_byte ( dev , 0x83 , & c ) ;
c | = 0x80 ;
pci_write_config_byte ( dev , 0x83 , c ) ;
pci_write_config_byte ( dev , 0x09 , 0x01 ) ;
pci_write_config_byte ( dev , 0x0a , 0x06 ) ;
pci_read_config_byte ( dev , 0x83 , & c ) ;
c & = 0x7f ;
pci_write_config_byte ( dev , 0x83 , c ) ;
2006-06-18 02:52:45 +04:00
2006-06-28 09:37:45 +04:00
pci_read_config_byte ( dev , 0x84 , & c ) ;
c | = 0x01 ;
pci_write_config_byte ( dev , 0x84 , c ) ;
2006-06-18 02:52:45 +04:00
}
2006-06-28 09:37:45 +04:00
static void __devinit quirk_uli5229 ( struct pci_dev * dev )
{
unsigned short temp ;
pci_write_config_word ( dev , 0x04 , 0x0405 ) ;
pci_read_config_word ( dev , 0x4a , & temp ) ;
temp | = 0x1000 ;
pci_write_config_word ( dev , 0x4a , temp ) ;
}
static void __devinit early_uli5249 ( struct pci_dev * dev )
{
unsigned char temp ;
pci_write_config_word ( dev , 0x04 , 0x0007 ) ;
pci_read_config_byte ( dev , 0x7c , & temp ) ;
pci_write_config_byte ( dev , 0x7c , 0x80 ) ;
pci_write_config_byte ( dev , 0x09 , 0x01 ) ;
pci_write_config_byte ( dev , 0x7c , temp ) ;
dev - > class | = 0x1 ;
}
2006-08-01 00:35:41 +04:00
DECLARE_PCI_FIXUP_HEADER ( PCI_VENDOR_ID_AL , 0x1575 , quirk_uli1575 ) ;
2006-06-28 09:37:45 +04:00
DECLARE_PCI_FIXUP_HEADER ( PCI_VENDOR_ID_AL , 0x5288 , quirk_uli5288 ) ;
DECLARE_PCI_FIXUP_HEADER ( PCI_VENDOR_ID_AL , 0x5229 , quirk_uli5229 ) ;
DECLARE_PCI_FIXUP_EARLY ( PCI_VENDOR_ID_AL , 0x5249 , early_uli5249 ) ;
2006-06-18 02:52:45 +04:00
# endif /* CONFIG_PCI */
static void __init
mpc86xx_hpcn_setup_arch ( void )
{
struct device_node * np ;
if ( ppc_md . progress )
ppc_md . progress ( " mpc86xx_hpcn_setup_arch() " , 0 ) ;
np = of_find_node_by_type ( NULL , " cpu " ) ;
if ( np ! = 0 ) {
2006-07-12 09:39:42 +04:00
const unsigned int * fp ;
2006-06-18 02:52:45 +04:00
2007-04-03 16:26:41 +04:00
fp = of_get_property ( np , " clock-frequency " , NULL ) ;
2006-06-18 02:52:45 +04:00
if ( fp ! = 0 )
loops_per_jiffy = * fp / HZ ;
else
loops_per_jiffy = 50000000 / HZ ;
of_node_put ( np ) ;
}
# ifdef CONFIG_PCI
for ( np = NULL ; ( np = of_find_node_by_type ( np , " pci " ) ) ! = NULL ; )
2007-06-18 03:06:54 +04:00
mpc86xx_add_bridge ( np ) ;
2006-06-18 02:52:45 +04:00
# endif
printk ( " MPC86xx HPCN board from Freescale Semiconductor \n " ) ;
# ifdef CONFIG_SMP
mpc86xx_smp_init ( ) ;
# endif
}
void
mpc86xx_hpcn_show_cpuinfo ( struct seq_file * m )
{
struct device_node * root ;
uint memsize = total_memory ;
const char * model = " " ;
uint svid = mfspr ( SPRN_SVR ) ;
seq_printf ( m , " Vendor \t \t : Freescale Semiconductor \n " ) ;
root = of_find_node_by_path ( " / " ) ;
if ( root )
2007-04-03 16:26:41 +04:00
model = of_get_property ( root , " model " , NULL ) ;
2006-06-18 02:52:45 +04:00
seq_printf ( m , " Machine \t \t : %s \n " , model ) ;
of_node_put ( root ) ;
seq_printf ( m , " SVR \t \t : 0x%x \n " , svid ) ;
seq_printf ( m , " Memory \t \t : %d MB \n " , memsize / ( 1024 * 1024 ) ) ;
}
/*
* Called very early , device - tree isn ' t unflattened
*/
static int __init mpc86xx_hpcn_probe ( void )
{
unsigned long root = of_get_flat_dt_root ( ) ;
if ( of_flat_dt_is_compatible ( root , " mpc86xx " ) )
return 1 ; /* Looks good */
return 0 ;
}
void
mpc86xx_restart ( char * cmd )
{
void __iomem * rstcr ;
rstcr = ioremap ( get_immrbase ( ) + MPC86XX_RSTCR_OFFSET , 0x100 ) ;
local_irq_disable ( ) ;
/* Assert reset request to Reset Control Register */
out_be32 ( rstcr , 0x2 ) ;
/* not reached */
}
long __init
mpc86xx_time_init ( void )
{
unsigned int temp ;
/* Set the time base to zero */
mtspr ( SPRN_TBWL , 0 ) ;
mtspr ( SPRN_TBWU , 0 ) ;
temp = mfspr ( SPRN_HID0 ) ;
temp | = HID0_TBEN ;
mtspr ( SPRN_HID0 , temp ) ;
asm volatile ( " isync " ) ;
return 0 ;
}
define_machine ( mpc86xx_hpcn ) {
. name = " MPC86xx HPCN " ,
. probe = mpc86xx_hpcn_probe ,
. setup_arch = mpc86xx_hpcn_setup_arch ,
. init_IRQ = mpc86xx_hpcn_init_irq ,
. show_cpuinfo = mpc86xx_hpcn_show_cpuinfo ,
. get_irq = mpic_get_irq ,
. restart = mpc86xx_restart ,
. time_init = mpc86xx_time_init ,
. calibrate_decr = generic_calibrate_decr ,
. progress = udbg_progress ,
} ;