From: Benjamin Herrenschmidt <benh@kernel.crashing.org> This patch, mostly from Sven Luther and reworked by me, adds support for Pegasos machines to the ppc32 arch. The patch contains all of the arch code. I'll send separately a few driver changes as well. Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> Signed-off-by: Andrew Morton <akpm@osdl.org> --- 25-akpm/arch/ppc/platforms/chrp_pci.c | 38 ++++++++++++++-- 25-akpm/arch/ppc/platforms/chrp_setup.c | 76 +++++++++++++++++++++++++++----- 25-akpm/arch/ppc/platforms/chrp_time.c | 2 25-akpm/arch/ppc/syslib/prom_init.c | 22 +++++++-- 25-akpm/include/asm-ppc/processor.h | 2 5 files changed, 120 insertions(+), 20 deletions(-) diff -puN arch/ppc/platforms/chrp_pci.c~ppc32-add-support-for-pegasos-machines arch/ppc/platforms/chrp_pci.c --- 25/arch/ppc/platforms/chrp_pci.c~ppc32-add-support-for-pegasos-machines 2005-01-23 21:49:40.957745560 -0800 +++ 25-akpm/arch/ppc/platforms/chrp_pci.c 2005-01-23 21:49:40.968743888 -0800 @@ -97,8 +97,10 @@ int __chrp rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 *val) { + struct pci_controller *hose = bus->sysdata; unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) - | ((bus->number & 0xff) << 16); + | (((bus->number - hose->first_busno) & 0xff) << 16) + | (hose->index << 24); unsigned long ret = ~0UL; int rval; @@ -111,8 +113,10 @@ int __chrp rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { + struct pci_controller *hose = bus->sysdata; unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) - | ((bus->number & 0xff) << 16); + | (((bus->number - hose->first_busno) & 0xff) << 16) + | (hose->index << 24); int rval; rval = call_rtas("write-pci-config", 3, 1, NULL, addr, len, val); @@ -186,6 +190,22 @@ setup_python(struct pci_controller *hose iounmap(reg); } +/* Marvell Discovery II based Pegasos 2 */ +static void __init setup_peg2(struct pci_controller *hose, struct device_node *dev) +{ + struct device_node *root = find_path_device("/"); + struct device_node *rtas; + + rtas = of_find_node_by_name (root, "rtas"); + if (rtas) { + hose->ops = &rtas_pci_ops; + } else { + printk ("RTAS supporting Pegasos OF not found, please upgrade" + " your firmware\n"); + } + pci_assign_all_busses = 1; +} + void __init chrp_find_bridges(void) { @@ -195,7 +215,7 @@ chrp_find_bridges(void) struct pci_controller *hose; unsigned int *dma; char *model, *machine; - int is_longtrail = 0, is_mot = 0; + int is_longtrail = 0, is_mot = 0, is_pegasos = 0; struct device_node *root = find_path_device("/"); /* @@ -207,6 +227,10 @@ chrp_find_bridges(void) if (machine != NULL) { is_longtrail = strncmp(machine, "IBM,LongTrail", 13) == 0; is_mot = strncmp(machine, "MOT", 3) == 0; + if (strncmp(machine, "Pegasos2", 8) == 0) + is_pegasos = 2; + else if (strncmp(machine, "Pegasos", 7) == 0) + is_pegasos = 1; } for (dev = root->child; dev != NULL; dev = dev->sibling) { if (dev->type == NULL || strcmp(dev->type, "pci") != 0) @@ -257,6 +281,10 @@ chrp_find_bridges(void) hose->ops = &gg2_pci_ops; hose->cfg_data = p; gg2_pci_config_base = p; + } else if (is_pegasos == 1) { + setup_indirect_pci(hose, 0xfec00cf8, 0xfee00cfc); + } else if (is_pegasos == 2) { + setup_peg2(hose, dev); } else { printk("No methods for %s (model %s), using RTAS\n", dev->full_name, model); @@ -275,5 +303,7 @@ chrp_find_bridges(void) } } - ppc_md.pcibios_fixup = chrp_pcibios_fixup; + /* Do not fixup interrupts from OF tree on pegasos */ + if (is_pegasos != 0) + ppc_md.pcibios_fixup = chrp_pcibios_fixup; } diff -puN arch/ppc/platforms/chrp_setup.c~ppc32-add-support-for-pegasos-machines arch/ppc/platforms/chrp_setup.c --- 25/arch/ppc/platforms/chrp_setup.c~ppc32-add-support-for-pegasos-machines 2005-01-23 21:49:40.959745256 -0800 +++ 25-akpm/arch/ppc/platforms/chrp_setup.c 2005-01-23 21:49:40.969743736 -0800 @@ -37,6 +37,7 @@ #include <linux/seq_file.h> #include <linux/root_dev.h> #include <linux/initrd.h> +#include <linux/module.h> #include <asm/io.h> #include <asm/pgtable.h> @@ -68,6 +69,9 @@ void btext_progress(char *, unsigned sho extern unsigned long pmac_find_end_of_memory(void); extern int of_show_percpuinfo(struct seq_file *, int); +int _chrp_type; +EXPORT_SYMBOL(_chrp_type); + /* * XXX this should be in xmon.h, but putting it there means xmon.h * has to include <linux/interrupt.h> (to get irqreturn_t), which @@ -214,8 +218,33 @@ static void __init sio_init(void) } -void __init -chrp_setup_arch(void) +static void __init pegasos_set_l2cr(void) +{ + struct device_node *np; + + /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */ + if (_chrp_type != _CHRP_Pegasos) + return; + + /* Enable L2 cache if needed */ + np = find_type_devices("cpu"); + if (np != NULL) { + unsigned int *l2cr = (unsigned int *) + get_property (np, "l2cr", NULL); + if (l2cr == NULL) { + printk ("Pegasos l2cr : no cpu l2cr property found\n"); + return; + } + if (!((*l2cr) & 0x80000000)) { + printk ("Pegasos l2cr : L2 cache was not active, " + "activating\n"); + _set_L2CR(0); + _set_L2CR((*l2cr) | 0x80000000); + } + } +} + +void __init chrp_setup_arch(void) { struct device_node *device; @@ -232,6 +261,9 @@ chrp_setup_arch(void) #endif ROOT_DEV = Root_SDA2; /* sda2 (sda1 is for the kernel) */ + /* On pegasos, enable the L2 cache if not already done by OF */ + pegasos_set_l2cr(); + /* Lookup PCI host bridges */ chrp_find_bridges(); @@ -402,15 +434,17 @@ void __init chrp_init_IRQ(void) chrp_find_openpic(); - prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); - OpenPIC_InitSenses = init_senses; - OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; - - openpic_init(NUM_8259_INTERRUPTS); - /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ - openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", - i8259_irq); + if (OpenPIC_Addr) { + prom_get_irq_senses(init_senses, NUM_8259_INTERRUPTS, NR_IRQS); + OpenPIC_InitSenses = init_senses; + OpenPIC_NumInitSenses = NR_IRQS - NUM_8259_INTERRUPTS; + + openpic_init(NUM_8259_INTERRUPTS); + /* We have a cascade on OpenPIC IRQ 0, Linux IRQ 16 */ + openpic_hookup_cascade(NUM_8259_INTERRUPTS, "82c59 cascade", + i8259_irq); + } for (i = 0; i < NUM_8259_INTERRUPTS; i++) irq_desc[i].handler = &i8259_pic; i8259_init(chrp_int_ack); @@ -450,6 +484,9 @@ void __init chrp_init(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7) { + struct device_node *root = find_path_device ("/"); + char *machine = NULL; + #ifdef CONFIG_BLK_DEV_INITRD /* take care of initrd if we have one */ if ( r6 ) @@ -464,12 +501,29 @@ chrp_init(unsigned long r3, unsigned lon DMA_MODE_WRITE = 0x48; isa_io_base = CHRP_ISA_IO_BASE; /* default value */ + if (root) + machine = get_property(root, "model", NULL); + if (machine && strncmp(machine, "Pegasos", 7) == 0) { + _chrp_type = _CHRP_Pegasos; + } else if (machine && strncmp(machine, "IBM", 3) == 0) { + _chrp_type = _CHRP_IBM; + } else if (machine && strncmp(machine, "MOT", 3) == 0) { + _chrp_type = _CHRP_Motorola; + } else { + /* Let's assume it is an IBM chrp if all else fails */ + _chrp_type = _CHRP_IBM; + } + ppc_md.setup_arch = chrp_setup_arch; ppc_md.show_percpuinfo = of_show_percpuinfo; ppc_md.show_cpuinfo = chrp_show_cpuinfo; + ppc_md.irq_canonicalize = chrp_irq_canonicalize; ppc_md.init_IRQ = chrp_init_IRQ; - ppc_md.get_irq = openpic_get_irq; + if (_chrp_type == _CHRP_Pegasos) + ppc_md.get_irq = i8259_irq; + else + ppc_md.get_irq = openpic_get_irq; ppc_md.init = chrp_init2; diff -puN arch/ppc/platforms/chrp_time.c~ppc32-add-support-for-pegasos-machines arch/ppc/platforms/chrp_time.c --- 25/arch/ppc/platforms/chrp_time.c~ppc32-add-support-for-pegasos-machines 2005-01-23 21:49:40.960745104 -0800 +++ 25-akpm/arch/ppc/platforms/chrp_time.c 2005-01-23 21:49:40.968743888 -0800 @@ -41,6 +41,8 @@ long __init chrp_time_init(void) int base; rtcs = find_compatible_devices("rtc", "pnpPNP,b00"); + if (rtcs == NULL) + rtcs = find_compatible_devices("rtc", "ds1385-rtc"); if (rtcs == NULL || rtcs->addrs == NULL) return 0; base = rtcs->addrs[0].address; diff -puN arch/ppc/syslib/prom_init.c~ppc32-add-support-for-pegasos-machines arch/ppc/syslib/prom_init.c --- 25/arch/ppc/syslib/prom_init.c~ppc32-add-support-for-pegasos-machines 2005-01-23 21:49:40.962744800 -0800 +++ 25-akpm/arch/ppc/syslib/prom_init.c 2005-01-23 21:49:40.967744040 -0800 @@ -810,6 +810,9 @@ prom_init(int r3, int r4, prom_entry pp) char *p, *d; unsigned long phys; void *result[3]; + char model[32]; + phandle node; + int rc; /* Default */ phys = (unsigned long) &_stext; @@ -866,11 +869,20 @@ prom_init(int r3, int r4, prom_entry pp) klimit = (char *) (mem - offset); - /* If we are already running at 0xc0000000, we assume we were - * loaded by an OF bootloader which did set a BAT for us. - * This breaks OF translate so we force phys to be 0. - */ - if (offset == 0) { + node = call_prom("finddevice", 1, 1, "/"); + rc = call_prom("getprop", 4, 1, node, "model", model, sizeof(model)); + if (rc > 0 && !strncmp (model, "Pegasos", 7) + && strncmp (model, "Pegasos2", 8)) { + /* Pegasos 1 has a broken translate method in the OF, + * and furthermore the BATs are mapped 1:1 so the phys + * address calculated above is correct, so let's use + * it directly. + */ + } else if (offset == 0) { + /* If we are already running at 0xc0000000, we assume we were + * loaded by an OF bootloader which did set a BAT for us. + * This breaks OF translate so we force phys to be 0. + */ prom_print("(already at 0xc0000000) phys=0\n"); phys = 0; } else if ((int) call_prom("getprop", 4, 1, prom_chosen, "mmu", diff -puN include/asm-ppc/processor.h~ppc32-add-support-for-pegasos-machines include/asm-ppc/processor.h --- 25/include/asm-ppc/processor.h~ppc32-add-support-for-pegasos-machines 2005-01-23 21:49:40.963744648 -0800 +++ 25-akpm/include/asm-ppc/processor.h 2005-01-23 21:49:40.970743584 -0800 @@ -34,6 +34,7 @@ /* these are arbitrary */ #define _CHRP_Motorola 0x04 /* motorola chrp, the cobra */ #define _CHRP_IBM 0x05 /* IBM chrp, the longtrail and longtrail 2 */ +#define _CHRP_Pegasos 0x06 /* Genesi/bplan's Pegasos and Pegasos2 */ #define _GLOBAL(n)\ .stabs __stringify(n:F-1),N_FUN,0,0,n;\ @@ -54,6 +55,7 @@ extern int _machine; /* what kind of prep workstation we are */ extern int _prep_type; +extern int _chrp_type; /* * This is used to identify the board type from a given PReP board _