162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/arch/powerpc/platforms/cell/cell_setup.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 1995 Linus Torvalds 662306a36Sopenharmony_ci * Adapted from 'alpha' version by Gary Thomas 762306a36Sopenharmony_ci * Modified by Cort Dougan (cort@cs.nmt.edu) 862306a36Sopenharmony_ci * Modified by PPC64 Team, IBM Corp 962306a36Sopenharmony_ci * Modified by Cell Team, IBM Deutschland Entwicklung GmbH 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci#undef DEBUG 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/sched.h> 1462306a36Sopenharmony_ci#include <linux/kernel.h> 1562306a36Sopenharmony_ci#include <linux/mm.h> 1662306a36Sopenharmony_ci#include <linux/stddef.h> 1762306a36Sopenharmony_ci#include <linux/export.h> 1862306a36Sopenharmony_ci#include <linux/unistd.h> 1962306a36Sopenharmony_ci#include <linux/user.h> 2062306a36Sopenharmony_ci#include <linux/reboot.h> 2162306a36Sopenharmony_ci#include <linux/init.h> 2262306a36Sopenharmony_ci#include <linux/delay.h> 2362306a36Sopenharmony_ci#include <linux/irq.h> 2462306a36Sopenharmony_ci#include <linux/seq_file.h> 2562306a36Sopenharmony_ci#include <linux/root_dev.h> 2662306a36Sopenharmony_ci#include <linux/console.h> 2762306a36Sopenharmony_ci#include <linux/mutex.h> 2862306a36Sopenharmony_ci#include <linux/memory_hotplug.h> 2962306a36Sopenharmony_ci#include <linux/of_platform.h> 3062306a36Sopenharmony_ci#include <linux/platform_device.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include <asm/mmu.h> 3362306a36Sopenharmony_ci#include <asm/processor.h> 3462306a36Sopenharmony_ci#include <asm/io.h> 3562306a36Sopenharmony_ci#include <asm/rtas.h> 3662306a36Sopenharmony_ci#include <asm/pci-bridge.h> 3762306a36Sopenharmony_ci#include <asm/iommu.h> 3862306a36Sopenharmony_ci#include <asm/dma.h> 3962306a36Sopenharmony_ci#include <asm/machdep.h> 4062306a36Sopenharmony_ci#include <asm/time.h> 4162306a36Sopenharmony_ci#include <asm/nvram.h> 4262306a36Sopenharmony_ci#include <asm/cputable.h> 4362306a36Sopenharmony_ci#include <asm/ppc-pci.h> 4462306a36Sopenharmony_ci#include <asm/irq.h> 4562306a36Sopenharmony_ci#include <asm/spu.h> 4662306a36Sopenharmony_ci#include <asm/spu_priv1.h> 4762306a36Sopenharmony_ci#include <asm/udbg.h> 4862306a36Sopenharmony_ci#include <asm/mpic.h> 4962306a36Sopenharmony_ci#include <asm/cell-regs.h> 5062306a36Sopenharmony_ci#include <asm/io-workarounds.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#include "cell.h" 5362306a36Sopenharmony_ci#include "interrupt.h" 5462306a36Sopenharmony_ci#include "pervasive.h" 5562306a36Sopenharmony_ci#include "ras.h" 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci#ifdef DEBUG 5862306a36Sopenharmony_ci#define DBG(fmt...) udbg_printf(fmt) 5962306a36Sopenharmony_ci#else 6062306a36Sopenharmony_ci#define DBG(fmt...) 6162306a36Sopenharmony_ci#endif 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void cell_show_cpuinfo(struct seq_file *m) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct device_node *root; 6662306a36Sopenharmony_ci const char *model = ""; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci root = of_find_node_by_path("/"); 6962306a36Sopenharmony_ci if (root) 7062306a36Sopenharmony_ci model = of_get_property(root, "model", NULL); 7162306a36Sopenharmony_ci seq_printf(m, "machine\t\t: CHRP %s\n", model); 7262306a36Sopenharmony_ci of_node_put(root); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic void cell_progress(char *s, unsigned short hex) 7662306a36Sopenharmony_ci{ 7762306a36Sopenharmony_ci printk("*** %04x : %s\n", hex, s ? s : ""); 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic void cell_fixup_pcie_rootcomplex(struct pci_dev *dev) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct pci_controller *hose; 8362306a36Sopenharmony_ci const char *s; 8462306a36Sopenharmony_ci int i; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!machine_is(cell)) 8762306a36Sopenharmony_ci return; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci /* We're searching for a direct child of the PHB */ 9062306a36Sopenharmony_ci if (dev->bus->self != NULL || dev->devfn != 0) 9162306a36Sopenharmony_ci return; 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci hose = pci_bus_to_host(dev->bus); 9462306a36Sopenharmony_ci if (hose == NULL) 9562306a36Sopenharmony_ci return; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Only on PCIE */ 9862306a36Sopenharmony_ci if (!of_device_is_compatible(hose->dn, "pciex")) 9962306a36Sopenharmony_ci return; 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci /* And only on axon */ 10262306a36Sopenharmony_ci s = of_get_property(hose->dn, "model", NULL); 10362306a36Sopenharmony_ci if (!s || strcmp(s, "Axon") != 0) 10462306a36Sopenharmony_ci return; 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) { 10762306a36Sopenharmony_ci dev->resource[i].start = dev->resource[i].end = 0; 10862306a36Sopenharmony_ci dev->resource[i].flags = 0; 10962306a36Sopenharmony_ci } 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci printk(KERN_DEBUG "PCI: Hiding resources on Axon PCIE RC %s\n", 11262306a36Sopenharmony_ci pci_name(dev)); 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ciDECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, cell_fixup_pcie_rootcomplex); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_cistatic int cell_setup_phb(struct pci_controller *phb) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci const char *model; 11962306a36Sopenharmony_ci struct device_node *np; 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci int rc = rtas_setup_phb(phb); 12262306a36Sopenharmony_ci if (rc) 12362306a36Sopenharmony_ci return rc; 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci phb->controller_ops = cell_pci_controller_ops; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci np = phb->dn; 12862306a36Sopenharmony_ci model = of_get_property(np, "model", NULL); 12962306a36Sopenharmony_ci if (model == NULL || !of_node_name_eq(np, "pci")) 13062306a36Sopenharmony_ci return 0; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci /* Setup workarounds for spider */ 13362306a36Sopenharmony_ci if (strcmp(model, "Spider")) 13462306a36Sopenharmony_ci return 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci iowa_register_bus(phb, &spiderpci_ops, &spiderpci_iowa_init, 13762306a36Sopenharmony_ci (void *)SPIDER_PCI_REG_BASE); 13862306a36Sopenharmony_ci return 0; 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cistatic const struct of_device_id cell_bus_ids[] __initconst = { 14262306a36Sopenharmony_ci { .type = "soc", }, 14362306a36Sopenharmony_ci { .compatible = "soc", }, 14462306a36Sopenharmony_ci { .type = "spider", }, 14562306a36Sopenharmony_ci { .type = "axon", }, 14662306a36Sopenharmony_ci { .type = "plb5", }, 14762306a36Sopenharmony_ci { .type = "plb4", }, 14862306a36Sopenharmony_ci { .type = "opb", }, 14962306a36Sopenharmony_ci { .type = "ebc", }, 15062306a36Sopenharmony_ci {}, 15162306a36Sopenharmony_ci}; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_cistatic int __init cell_publish_devices(void) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct device_node *root = of_find_node_by_path("/"); 15662306a36Sopenharmony_ci struct device_node *np; 15762306a36Sopenharmony_ci int node; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci /* Publish OF platform devices for southbridge IOs */ 16062306a36Sopenharmony_ci of_platform_bus_probe(NULL, cell_bus_ids, NULL); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* On spider based blades, we need to manually create the OF 16362306a36Sopenharmony_ci * platform devices for the PCI host bridges 16462306a36Sopenharmony_ci */ 16562306a36Sopenharmony_ci for_each_child_of_node(root, np) { 16662306a36Sopenharmony_ci if (!of_node_is_type(np, "pci") && !of_node_is_type(np, "pciex")) 16762306a36Sopenharmony_ci continue; 16862306a36Sopenharmony_ci of_platform_device_create(np, NULL, NULL); 16962306a36Sopenharmony_ci } 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_ci of_node_put(root); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci /* There is no device for the MIC memory controller, thus we create 17462306a36Sopenharmony_ci * a platform device for it to attach the EDAC driver to. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci for_each_online_node(node) { 17762306a36Sopenharmony_ci if (cbe_get_cpu_mic_tm_regs(cbe_node_to_cpu(node)) == NULL) 17862306a36Sopenharmony_ci continue; 17962306a36Sopenharmony_ci platform_device_register_simple("cbe-mic", node, NULL, 0); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci 18262306a36Sopenharmony_ci return 0; 18362306a36Sopenharmony_ci} 18462306a36Sopenharmony_cimachine_subsys_initcall(cell, cell_publish_devices); 18562306a36Sopenharmony_ci 18662306a36Sopenharmony_cistatic void __init mpic_init_IRQ(void) 18762306a36Sopenharmony_ci{ 18862306a36Sopenharmony_ci struct device_node *dn; 18962306a36Sopenharmony_ci struct mpic *mpic; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci for_each_node_by_name(dn, "interrupt-controller") { 19262306a36Sopenharmony_ci if (!of_device_is_compatible(dn, "CBEA,platform-open-pic")) 19362306a36Sopenharmony_ci continue; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci /* The MPIC driver will get everything it needs from the 19662306a36Sopenharmony_ci * device-tree, just pass 0 to all arguments 19762306a36Sopenharmony_ci */ 19862306a36Sopenharmony_ci mpic = mpic_alloc(dn, 0, MPIC_SECONDARY | MPIC_NO_RESET, 19962306a36Sopenharmony_ci 0, 0, " MPIC "); 20062306a36Sopenharmony_ci if (mpic == NULL) 20162306a36Sopenharmony_ci continue; 20262306a36Sopenharmony_ci mpic_init(mpic); 20362306a36Sopenharmony_ci } 20462306a36Sopenharmony_ci} 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_cistatic void __init cell_init_irq(void) 20862306a36Sopenharmony_ci{ 20962306a36Sopenharmony_ci iic_init_IRQ(); 21062306a36Sopenharmony_ci spider_init_IRQ(); 21162306a36Sopenharmony_ci mpic_init_IRQ(); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_cistatic void __init cell_set_dabrx(void) 21562306a36Sopenharmony_ci{ 21662306a36Sopenharmony_ci mtspr(SPRN_DABRX, DABRX_KERNEL | DABRX_USER); 21762306a36Sopenharmony_ci} 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_cistatic void __init cell_setup_arch(void) 22062306a36Sopenharmony_ci{ 22162306a36Sopenharmony_ci#ifdef CONFIG_SPU_BASE 22262306a36Sopenharmony_ci spu_priv1_ops = &spu_priv1_mmio_ops; 22362306a36Sopenharmony_ci spu_management_ops = &spu_management_of_ops; 22462306a36Sopenharmony_ci#endif 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci cbe_regs_init(); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci cell_set_dabrx(); 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci#ifdef CONFIG_CBE_RAS 23162306a36Sopenharmony_ci cbe_ras_init(); 23262306a36Sopenharmony_ci#endif 23362306a36Sopenharmony_ci 23462306a36Sopenharmony_ci#ifdef CONFIG_SMP 23562306a36Sopenharmony_ci smp_init_cell(); 23662306a36Sopenharmony_ci#endif 23762306a36Sopenharmony_ci /* init to some ~sane value until calibrate_delay() runs */ 23862306a36Sopenharmony_ci loops_per_jiffy = 50000000; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Find and initialize PCI host bridges */ 24162306a36Sopenharmony_ci init_pci_config_tokens(); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci cbe_pervasive_init(); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci mmio_nvram_init(); 24662306a36Sopenharmony_ci} 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_cistatic int __init cell_probe(void) 24962306a36Sopenharmony_ci{ 25062306a36Sopenharmony_ci if (!of_machine_is_compatible("IBM,CBEA") && 25162306a36Sopenharmony_ci !of_machine_is_compatible("IBM,CPBW-1.0")) 25262306a36Sopenharmony_ci return 0; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci pm_power_off = rtas_power_off; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci return 1; 25762306a36Sopenharmony_ci} 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_cidefine_machine(cell) { 26062306a36Sopenharmony_ci .name = "Cell", 26162306a36Sopenharmony_ci .probe = cell_probe, 26262306a36Sopenharmony_ci .setup_arch = cell_setup_arch, 26362306a36Sopenharmony_ci .show_cpuinfo = cell_show_cpuinfo, 26462306a36Sopenharmony_ci .restart = rtas_restart, 26562306a36Sopenharmony_ci .halt = rtas_halt, 26662306a36Sopenharmony_ci .get_boot_time = rtas_get_boot_time, 26762306a36Sopenharmony_ci .get_rtc_time = rtas_get_rtc_time, 26862306a36Sopenharmony_ci .set_rtc_time = rtas_set_rtc_time, 26962306a36Sopenharmony_ci .progress = cell_progress, 27062306a36Sopenharmony_ci .init_IRQ = cell_init_irq, 27162306a36Sopenharmony_ci .pci_setup_phb = cell_setup_phb, 27262306a36Sopenharmony_ci}; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_cistruct pci_controller_ops cell_pci_controller_ops; 275