2006-04-02 17:42:40 -05:00
/*
* MPC85xx setup and early boot code plus other random bits .
*
* Maintained by Kumar Gala ( see MAINTAINERS for contact information )
*
2012-03-14 18:15:27 +08:00
* Copyright 2005 , 2011 - 2012 Freescale Semiconductor Inc .
2006-04-02 17:42:40 -05:00
*
* 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/init.h>
# include <linux/errno.h>
# include <linux/reboot.h>
# include <linux/pci.h>
# include <linux/kdev_t.h>
# include <linux/major.h>
# include <linux/console.h>
# include <linux/delay.h>
# include <linux/seq_file.h>
# include <linux/initrd.h>
2007-06-06 16:26:15 -07:00
# include <linux/interrupt.h>
2006-04-02 17:42:40 -05:00
# include <linux/fsl_devices.h>
2008-06-16 15:36:17 -07:00
# include <linux/of_platform.h>
2006-04-02 17:42:40 -05:00
# include <asm/pgtable.h>
# include <asm/page.h>
2011-07-26 16:09:06 -07:00
# include <linux/atomic.h>
2006-04-02 17:42:40 -05:00
# include <asm/time.h>
# include <asm/io.h>
# include <asm/machdep.h>
# include <asm/ipic.h>
# include <asm/pci-bridge.h>
# include <asm/irq.h>
# include <mm/mmu_decl.h>
# include <asm/prom.h>
# include <asm/udbg.h>
# include <asm/mpic.h>
# include <asm/i8259.h>
# include <sysdev/fsl_soc.h>
2007-07-10 18:47:06 +08:00
# include <sysdev/fsl_pci.h>
2006-04-02 17:42:40 -05:00
2011-11-17 21:56:16 +04:00
# include "mpc85xx.h"
2012-03-06 17:06:42 +08:00
/*
* The CDS board contains an FPGA / CPLD called " Cadmus " , which collects
* various logic and performs system control functions .
* Here is the FPGA / CPLD register map .
*/
struct cadmus_reg {
u8 cm_ver ; /* Board version */
u8 cm_csr ; /* General control/status */
u8 cm_rst ; /* Reset control */
u8 cm_hsclk ; /* High speed clock */
u8 cm_hsxclk ; /* High speed clock extended */
u8 cm_led ; /* LED data */
u8 cm_pci ; /* PCI control/status */
u8 cm_dma ; /* DMA control */
u8 res [ 248 ] ; /* Total 256 bytes */
} ;
2007-10-11 09:13:41 -05:00
2012-03-06 17:06:42 +08:00
static struct cadmus_reg * cadmus ;
2006-04-02 17:42:40 -05:00
# ifdef CONFIG_PCI
# define ARCADIA_HOST_BRIDGE_IDSEL 17
# define ARCADIA_2ND_BRIDGE_IDSEL 3
2007-06-22 00:23:57 -05:00
static int mpc85xx_exclude_device ( struct pci_controller * hose ,
u_char bus , u_char devfn )
2006-04-02 17:42:40 -05:00
{
/* We explicitly do not go past the Tundra 320 Bridge */
if ( ( bus = = 1 ) & & ( PCI_SLOT ( devfn ) = = ARCADIA_2ND_BRIDGE_IDSEL ) )
return PCIBIOS_DEVICE_NOT_FOUND ;
if ( ( bus = = 0 ) & & ( PCI_SLOT ( devfn ) = = ARCADIA_2ND_BRIDGE_IDSEL ) )
return PCIBIOS_DEVICE_NOT_FOUND ;
else
return PCIBIOS_SUCCESSFUL ;
}
2007-03-23 15:43:37 -07:00
static void mpc85xx_cds_restart ( char * cmd )
{
struct pci_dev * dev ;
u_char tmp ;
if ( ( dev = pci_get_device ( PCI_VENDOR_ID_VIA , PCI_DEVICE_ID_VIA_82C686 ,
NULL ) ) ) {
/* Use the VIA Super Southbridge to force a PCI reset */
pci_read_config_byte ( dev , 0x47 , & tmp ) ;
pci_write_config_byte ( dev , 0x47 , tmp | 1 ) ;
/* Flush the outbound PCI write queues */
pci_read_config_byte ( dev , 0x47 , & tmp ) ;
/*
* At this point , the harware reset should have triggered .
* However , if it doesn ' t work for some mysterious reason ,
* just fall through to the default reset below .
*/
pci_dev_put ( dev ) ;
}
/*
* If we can ' t find the VIA chip ( maybe the P2P bridge is disabled )
* or the VIA chip reset didn ' t work , just use the default reset .
*/
2007-10-04 01:04:57 -05:00
fsl_rstcr_restart ( NULL ) ;
2007-03-23 15:43:37 -07:00
}
2007-06-01 16:05:38 +08:00
static void __init mpc85xx_cds_pci_irq_fixup ( struct pci_dev * dev )
2006-04-02 17:42:40 -05:00
{
2007-06-01 16:05:38 +08:00
u_char c ;
if ( dev - > vendor = = PCI_VENDOR_ID_VIA ) {
switch ( dev - > device ) {
case PCI_DEVICE_ID_VIA_82C586_1 :
/*
* U - Boot does not set the enable bits
* for the IDE device . Force them on here .
*/
pci_read_config_byte ( dev , 0x40 , & c ) ;
c | = 0x03 ; /* IDE: Chip Enable Bits */
pci_write_config_byte ( dev , 0x40 , c ) ;
/*
* Since only primary interface works , force the
* IDE function to standard primary IDE interrupt
* w / 8259 offset
*/
dev - > irq = 14 ;
pci_write_config_byte ( dev , PCI_INTERRUPT_LINE , dev - > irq ) ;
break ;
2006-04-02 17:42:40 -05:00
/*
2007-06-01 16:05:38 +08:00
* Force legacy USB interrupt routing
2006-04-02 17:42:40 -05:00
*/
2007-06-01 16:05:38 +08:00
case PCI_DEVICE_ID_VIA_82C586_2 :
/* There are two USB controllers.
* Identify them by functon number
2006-04-02 17:42:40 -05:00
*/
2007-07-19 10:40:53 -07:00
if ( PCI_FUNC ( dev - > devfn ) = = 3 )
2007-06-01 16:05:38 +08:00
dev - > irq = 11 ;
else
dev - > irq = 10 ;
pci_write_config_byte ( dev , PCI_INTERRUPT_LINE , dev - > irq ) ;
default :
break ;
}
2006-04-02 17:42:40 -05:00
}
2006-08-17 20:24:48 -05:00
}
2007-07-19 15:39:24 -05:00
static void __devinit skip_fake_bridge ( struct pci_dev * dev )
{
/* Make it an error to skip the fake bridge
* in pci_setup_device ( ) in probe . c */
dev - > hdr_type = 0x7f ;
}
DECLARE_PCI_FIXUP_EARLY ( 0x1957 , 0x3fff , skip_fake_bridge ) ;
DECLARE_PCI_FIXUP_EARLY ( 0x3fff , 0x1957 , skip_fake_bridge ) ;
DECLARE_PCI_FIXUP_EARLY ( 0xff3f , 0x5719 , skip_fake_bridge ) ;
2012-03-14 18:15:27 +08:00
# define PCI_DEVICE_ID_IDT_TSI310 0x01a7
/*
* Fix Tsi310 PCI - X bridge resource .
* Force the bridge to open a window from 0x0000 - 0x1fff in PCI I / O space .
* This allows legacy I / O ( i8259 , etc ) on the VIA southbridge to be accessed .
*/
void mpc85xx_cds_fixup_bus ( struct pci_bus * bus )
{
struct pci_dev * dev = bus - > self ;
struct resource * res = bus - > resource [ 0 ] ;
if ( dev ! = NULL & &
dev - > vendor = = PCI_VENDOR_ID_IBM & &
dev - > device = = PCI_DEVICE_ID_IDT_TSI310 ) {
if ( res ) {
res - > start = 0 ;
res - > end = 0x1fff ;
res - > flags = IORESOURCE_IO ;
pr_info ( " mpc85xx_cds: PCI bridge resource fixup applied \n " ) ;
pr_info ( " mpc85xx_cds: %pR \n " , res ) ;
}
}
fsl_pcibios_fixup_bus ( bus ) ;
}
2006-08-17 20:24:48 -05:00
# ifdef CONFIG_PPC_I8259
2007-06-06 16:26:15 -07:00
static void mpc85xx_8259_cascade_handler ( unsigned int irq ,
struct irq_desc * desc )
2006-08-17 20:24:48 -05:00
{
2006-10-07 22:08:26 +10:00
unsigned int cascade_irq = i8259_irq ( ) ;
2006-08-17 20:24:48 -05:00
if ( cascade_irq ! = NO_IRQ )
2007-06-06 16:26:15 -07:00
/* handle an interrupt from the 8259 */
2006-10-05 20:31:10 -05:00
generic_handle_irq ( cascade_irq ) ;
2006-08-17 20:24:48 -05:00
2007-06-06 16:26:15 -07:00
/* check for any interrupts from the shared IRQ line */
handle_fasteoi_irq ( irq , desc ) ;
2006-04-02 17:42:40 -05:00
}
2007-06-06 16:26:15 -07:00
static irqreturn_t mpc85xx_8259_cascade_action ( int irq , void * dev_id )
{
return IRQ_HANDLED ;
}
static struct irqaction mpc85xxcds_8259_irqaction = {
. handler = mpc85xx_8259_cascade_action ,
2011-10-05 02:30:49 +00:00
. flags = IRQF_SHARED | IRQF_NO_THREAD ,
2007-06-06 16:26:15 -07:00
. name = " 8259 cascade " ,
} ;
2006-08-17 20:24:48 -05:00
# endif /* PPC_I8259 */
2006-04-02 17:42:40 -05:00
# endif /* CONFIG_PCI */
2007-02-09 09:30:45 -06:00
static void __init mpc85xx_cds_pic_init ( void )
2006-04-02 17:42:40 -05:00
{
2006-08-17 20:24:48 -05:00
struct mpic * mpic ;
2011-12-22 10:19:14 +00:00
mpic = mpic_alloc ( NULL , 0 , MPIC_BIG_ENDIAN ,
2007-07-03 02:35:35 -05:00
0 , 256 , " OpenPIC " ) ;
2006-08-17 20:24:48 -05:00
BUG_ON ( mpic = = NULL ) ;
mpic_init ( mpic ) ;
2007-06-14 11:02:54 -07:00
}
2006-08-17 20:24:48 -05:00
2007-06-06 16:26:15 -07:00
# if defined(CONFIG_PPC_I8259) && defined(CONFIG_PCI)
2007-06-14 11:02:54 -07:00
static int mpc85xx_cds_8259_attach ( void )
{
int ret ;
struct device_node * np = NULL ;
struct device_node * cascade_node = NULL ;
int cascade_irq ;
2006-08-17 20:24:48 -05:00
/* Initialize the i8259 controller */
for_each_node_by_type ( np , " interrupt-controller " )
2007-05-03 17:26:52 +10:00
if ( of_device_is_compatible ( np , " chrp,iic " ) ) {
2006-08-17 20:24:48 -05:00
cascade_node = np ;
break ;
}
if ( cascade_node = = NULL ) {
printk ( KERN_DEBUG " Could not find i8259 PIC \n " ) ;
2007-06-14 11:02:54 -07:00
return - ENODEV ;
2006-08-17 20:24:48 -05:00
}
2006-04-02 17:42:40 -05:00
2006-08-17 20:24:48 -05:00
cascade_irq = irq_of_parse_and_map ( cascade_node , 0 ) ;
if ( cascade_irq = = NO_IRQ ) {
printk ( KERN_ERR " Failed to map cascade interrupt \n " ) ;
2007-06-14 11:02:54 -07:00
return - ENXIO ;
2006-08-17 20:24:48 -05:00
}
2006-04-02 17:42:40 -05:00
2006-08-17 20:24:48 -05:00
i8259_init ( cascade_node , 0 ) ;
of_node_put ( cascade_node ) ;
2007-06-06 16:26:15 -07:00
/*
* Hook the interrupt to make sure desc - > action is never NULL .
* This is required to ensure that the interrupt does not get
* disabled when the last user of the shared IRQ line frees their
* interrupt .
*/
2007-06-14 11:02:54 -07:00
if ( ( ret = setup_irq ( cascade_irq , & mpc85xxcds_8259_irqaction ) ) ) {
2007-06-06 16:26:15 -07:00
printk ( KERN_ERR " Failed to setup cascade interrupt \n " ) ;
2007-06-14 11:02:54 -07:00
return ret ;
}
/* Success. Connect our low-level cascade handler. */
2011-03-25 16:45:20 +01:00
irq_set_handler ( cascade_irq , mpc85xx_8259_cascade_handler ) ;
2007-06-14 11:02:54 -07:00
return 0 ;
2006-04-02 17:42:40 -05:00
}
2008-01-15 09:42:36 -06:00
machine_device_initcall ( mpc85xx_cds , mpc85xx_cds_8259_attach ) ;
2007-06-14 11:02:54 -07:00
# endif /* CONFIG_PPC_I8259 */
2006-04-02 17:42:40 -05:00
/*
* Setup the architecture
*/
2007-02-09 09:30:45 -06:00
static void __init mpc85xx_cds_setup_arch ( void )
2006-04-02 17:42:40 -05:00
{
struct device_node * np ;
2012-03-06 17:06:42 +08:00
int cds_pci_slot ;
2006-04-02 17:42:40 -05:00
if ( ppc_md . progress )
ppc_md . progress ( " mpc85xx_cds_setup_arch() " , 0 ) ;
2012-03-06 17:06:42 +08:00
np = of_find_compatible_node ( NULL , NULL , " fsl,mpc8548cds-fpga " ) ;
if ( ! np ) {
pr_err ( " Could not find FPGA node. \n " ) ;
return ;
}
cadmus = of_iomap ( np , 0 ) ;
of_node_put ( np ) ;
if ( ! cadmus ) {
pr_err ( " Fail to map FPGA area. \n " ) ;
return ;
}
2006-04-02 17:42:40 -05:00
if ( ppc_md . progress ) {
char buf [ 40 ] ;
2012-03-06 17:06:42 +08:00
cds_pci_slot = ( ( in_8 ( & cadmus - > cm_csr ) > > 6 ) & 0x3 ) + 1 ;
2006-04-02 17:42:40 -05:00
snprintf ( buf , 40 , " CDS Version = 0x%x in slot %d \n " ,
2012-03-06 17:06:42 +08:00
in_8 ( & cadmus - > cm_ver ) , cds_pci_slot ) ;
2006-04-02 17:42:40 -05:00
ppc_md . progress ( buf , 0 ) ;
}
# ifdef CONFIG_PCI
2007-10-04 00:28:43 -05:00
for_each_node_by_type ( np , " pci " ) {
if ( of_device_is_compatible ( np , " fsl,mpc8540-pci " ) | |
of_device_is_compatible ( np , " fsl,mpc8548-pcie " ) ) {
struct resource rsrc ;
of_address_to_resource ( np , 0 , & rsrc ) ;
if ( ( rsrc . start & 0xfffff ) = = 0x8000 )
fsl_add_bridge ( np , 1 ) ;
else
fsl_add_bridge ( np , 0 ) ;
}
2007-07-10 18:47:06 +08:00
}
2007-10-04 00:28:43 -05:00
2007-06-01 16:05:38 +08:00
ppc_md . pci_irq_fixup = mpc85xx_cds_pci_irq_fixup ;
2006-04-02 17:42:40 -05:00
ppc_md . pci_exclude_device = mpc85xx_exclude_device ;
# endif
}
2007-02-09 09:30:45 -06:00
static void mpc85xx_cds_show_cpuinfo ( struct seq_file * m )
2006-04-02 17:42:40 -05:00
{
uint pvid , svid , phid1 ;
pvid = mfspr ( SPRN_PVR ) ;
svid = mfspr ( SPRN_SVR ) ;
seq_printf ( m , " Vendor \t \t : Freescale Semiconductor \n " ) ;
2012-03-06 17:06:42 +08:00
seq_printf ( m , " Machine \t \t : MPC85xx CDS (0x%x) \n " ,
in_8 ( & cadmus - > cm_ver ) ) ;
2006-04-02 17:42:40 -05:00
seq_printf ( m , " PVR \t \t : 0x%x \n " , pvid ) ;
seq_printf ( m , " SVR \t \t : 0x%x \n " , svid ) ;
/* Display cpu Pll setting */
phid1 = mfspr ( SPRN_HID1 ) ;
seq_printf ( m , " PLL setting \t : 0x%x \n " , ( ( phid1 > > 24 ) & 0x3f ) ) ;
}
/*
* Called very early , device - tree isn ' t unflattened
*/
static int __init mpc85xx_cds_probe ( void )
{
2007-02-17 16:19:34 -06:00
unsigned long root = of_get_flat_dt_root ( ) ;
return of_flat_dt_is_compatible ( root , " MPC85xxCDS " ) ;
2006-04-02 17:42:40 -05:00
}
2011-11-17 21:56:17 +04:00
machine_device_initcall ( mpc85xx_cds , mpc85xx_common_publish_devices ) ;
2008-06-16 15:36:17 -07:00
2006-04-02 17:42:40 -05:00
define_machine ( mpc85xx_cds ) {
. name = " MPC85xx CDS " ,
. probe = mpc85xx_cds_probe ,
. setup_arch = mpc85xx_cds_setup_arch ,
. init_IRQ = mpc85xx_cds_pic_init ,
. show_cpuinfo = mpc85xx_cds_show_cpuinfo ,
. get_irq = mpic_get_irq ,
2007-03-23 15:43:37 -07:00
# ifdef CONFIG_PCI
. restart = mpc85xx_cds_restart ,
2012-03-14 18:15:27 +08:00
. pcibios_fixup_bus = mpc85xx_cds_fixup_bus ,
2007-03-23 15:43:37 -07:00
# else
2007-10-04 01:04:57 -05:00
. restart = fsl_rstcr_restart ,
2007-03-23 15:43:37 -07:00
# endif
2006-04-02 17:42:40 -05:00
. calibrate_decr = generic_calibrate_decr ,
. progress = udbg_progress ,
} ;