linux/arch/powerpc/platforms/embedded6xx/holly.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Board setup routines for the IBM 750GX/CL platform w/ TSI10x bridge
   4 *
   5 * Copyright 2007 IBM Corporation
   6 *
   7 * Stephen Winiecki <stevewin@us.ibm.com>
   8 * Josh Boyer <jwboyer@linux.vnet.ibm.com>
   9 *
  10 * Based on code from mpc7448_hpc2.c
  11 */
  12
  13#include <linux/stddef.h>
  14#include <linux/kernel.h>
  15#include <linux/pci.h>
  16#include <linux/kdev_t.h>
  17#include <linux/console.h>
  18#include <linux/delay.h>
  19#include <linux/irq.h>
  20#include <linux/seq_file.h>
  21#include <linux/root_dev.h>
  22#include <linux/serial.h>
  23#include <linux/tty.h>
  24#include <linux/serial_core.h>
  25#include <linux/of_platform.h>
  26#include <linux/extable.h>
  27
  28#include <asm/time.h>
  29#include <asm/machdep.h>
  30#include <asm/prom.h>
  31#include <asm/udbg.h>
  32#include <asm/tsi108.h>
  33#include <asm/pci-bridge.h>
  34#include <asm/reg.h>
  35#include <mm/mmu_decl.h>
  36#include <asm/tsi108_irq.h>
  37#include <asm/tsi108_pci.h>
  38#include <asm/mpic.h>
  39
  40#undef DEBUG
  41
  42#define HOLLY_PCI_CFG_PHYS 0x7c000000
  43
  44static int holly_exclude_device(struct pci_controller *hose, u_char bus,
  45                                u_char devfn)
  46{
  47        if (bus == 0 && PCI_SLOT(devfn) == 0)
  48                return PCIBIOS_DEVICE_NOT_FOUND;
  49        else
  50                return PCIBIOS_SUCCESSFUL;
  51}
  52
  53static void holly_remap_bridge(void)
  54{
  55        u32 lut_val, lut_addr;
  56        int i;
  57
  58        printk(KERN_INFO "Remapping PCI bridge\n");
  59
  60        /* Re-init the PCI bridge and LUT registers to have mappings that don't
  61         * rely on PIBS
  62         */
  63        lut_addr = 0x900;
  64        for (i = 0; i < 31; i++) {
  65                tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000201);
  66                lut_addr += 4;
  67                tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
  68                lut_addr += 4;
  69        }
  70
  71        /* Reserve the last LUT entry for PCI I/O space */
  72        tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000241);
  73        lut_addr += 4;
  74        tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
  75
  76        /* Map PCI I/O space */
  77        tsi108_write_reg(TSI108_PCI_PFAB_IO_UPPER, 0x0);
  78        tsi108_write_reg(TSI108_PCI_PFAB_IO, 0x1);
  79
  80        /* Map PCI CFG space */
  81        tsi108_write_reg(TSI108_PCI_PFAB_BAR0_UPPER, 0x0);
  82        tsi108_write_reg(TSI108_PCI_PFAB_BAR0, 0x7c000000 | 0x01);
  83
  84        /* We don't need MEM32 and PRM remapping so disable them */
  85        tsi108_write_reg(TSI108_PCI_PFAB_MEM32, 0x0);
  86        tsi108_write_reg(TSI108_PCI_PFAB_PFM3, 0x0);
  87        tsi108_write_reg(TSI108_PCI_PFAB_PFM4, 0x0);
  88
  89        /* Set P2O_BAR0 */
  90        tsi108_write_reg(TSI108_PCI_P2O_BAR0_UPPER, 0x0);
  91        tsi108_write_reg(TSI108_PCI_P2O_BAR0, 0xc0000000);
  92
  93        /* Init the PCI LUTs to do no remapping */
  94        lut_addr = 0x500;
  95        lut_val = 0x00000002;
  96
  97        for (i = 0; i < 32; i++) {
  98                tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, lut_val);
  99                lut_addr += 4;
 100                tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, 0x40000000);
 101                lut_addr += 4;
 102                lut_val += 0x02000000;
 103        }
 104        tsi108_write_reg(TSI108_PCI_P2O_PAGE_SIZES, 0x00007900);
 105
 106        /* Set 64-bit PCI bus address for system memory */
 107        tsi108_write_reg(TSI108_PCI_P2O_BAR2_UPPER, 0x0);
 108        tsi108_write_reg(TSI108_PCI_P2O_BAR2, 0x0);
 109}
 110
 111static void __init holly_init_pci(void)
 112{
 113        struct device_node *np;
 114
 115        if (ppc_md.progress)
 116                ppc_md.progress("holly_setup_arch():set_bridge", 0);
 117
 118        /* setup PCI host bridge */
 119        holly_remap_bridge();
 120
 121        np = of_find_node_by_type(NULL, "pci");
 122        if (np)
 123                tsi108_setup_pci(np, HOLLY_PCI_CFG_PHYS, 1);
 124
 125        ppc_md.pci_exclude_device = holly_exclude_device;
 126        if (ppc_md.progress)
 127                ppc_md.progress("tsi108: resources set", 0x100);
 128}
 129
 130static void __init holly_setup_arch(void)
 131{
 132        tsi108_csr_vir_base = get_vir_csrbase();
 133
 134        printk(KERN_INFO "PPC750GX/CL Platform\n");
 135}
 136
 137/*
 138 * Interrupt setup and service.  Interrupts on the holly come
 139 * from the four external INT pins, PCI interrupts are routed via
 140 * PCI interrupt control registers, it generates internal IRQ23
 141 *
 142 * Interrupt routing on the Holly Board:
 143 * TSI108:PB_INT[0] -> CPU0:INT#
 144 * TSI108:PB_INT[1] -> CPU0:MCP#
 145 * TSI108:PB_INT[2] -> N/C
 146 * TSI108:PB_INT[3] -> N/C
 147 */
 148static void __init holly_init_IRQ(void)
 149{
 150        struct mpic *mpic;
 151#ifdef CONFIG_PCI
 152        unsigned int cascade_pci_irq;
 153        struct device_node *tsi_pci;
 154        struct device_node *cascade_node = NULL;
 155#endif
 156
 157        mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
 158                        MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
 159                        24, 0,
 160                        "Tsi108_PIC");
 161
 162        BUG_ON(mpic == NULL);
 163
 164        mpic_assign_isu(mpic, 0, mpic->paddr + 0x100);
 165
 166        mpic_init(mpic);
 167
 168#ifdef CONFIG_PCI
 169        tsi_pci = of_find_node_by_type(NULL, "pci");
 170        if (tsi_pci == NULL) {
 171                printk(KERN_ERR "%s: No tsi108 pci node found !\n", __func__);
 172                return;
 173        }
 174
 175        cascade_node = of_find_node_by_type(NULL, "pic-router");
 176        if (cascade_node == NULL) {
 177                printk(KERN_ERR "%s: No tsi108 pci cascade node found !\n", __func__);
 178                return;
 179        }
 180
 181        cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0);
 182        pr_debug("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq);
 183        tsi108_pci_int_init(cascade_node);
 184        irq_set_handler_data(cascade_pci_irq, mpic);
 185        irq_set_chained_handler(cascade_pci_irq, tsi108_irq_cascade);
 186#endif
 187        /* Configure MPIC outputs to CPU0 */
 188        tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
 189}
 190
 191static void holly_show_cpuinfo(struct seq_file *m)
 192{
 193        seq_printf(m, "vendor\t\t: IBM\n");
 194        seq_printf(m, "machine\t\t: PPC750 GX/CL\n");
 195}
 196
 197static void __noreturn holly_restart(char *cmd)
 198{
 199        __be32 __iomem *ocn_bar1 = NULL;
 200        unsigned long bar;
 201        struct device_node *bridge = NULL;
 202        const void *prop;
 203        int size;
 204        phys_addr_t addr = 0xc0000000;
 205
 206        local_irq_disable();
 207
 208        bridge = of_find_node_by_type(NULL, "tsi-bridge");
 209        if (bridge) {
 210                prop = of_get_property(bridge, "reg", &size);
 211                addr = of_translate_address(bridge, prop);
 212        }
 213        addr += (TSI108_PB_OFFSET + 0x414);
 214
 215        ocn_bar1 = ioremap(addr, 0x4);
 216
 217        /* Turn on the BOOT bit so the addresses are correctly
 218         * routed to the HLP interface */
 219        bar = ioread32be(ocn_bar1);
 220        bar |= 2;
 221        iowrite32be(bar, ocn_bar1);
 222        iosync();
 223
 224        /* Set SRR0 to the reset vector and turn on MSR_IP */
 225        mtspr(SPRN_SRR0, 0xfff00100);
 226        mtspr(SPRN_SRR1, MSR_IP);
 227
 228        /* Do an rfi to jump back to firmware.  Somewhat evil,
 229         * but it works
 230         */
 231        __asm__ __volatile__("rfi" : : : "memory");
 232
 233        /* Spin until reset happens.  Shouldn't really get here */
 234        for (;;) ;
 235}
 236
 237/*
 238 * Called very early, device-tree isn't unflattened
 239 */
 240static int __init holly_probe(void)
 241{
 242        if (!of_machine_is_compatible("ibm,holly"))
 243                return 0;
 244        return 1;
 245}
 246
 247static int ppc750_machine_check_exception(struct pt_regs *regs)
 248{
 249        const struct exception_table_entry *entry;
 250
 251        /* Are we prepared to handle this fault */
 252        if ((entry = search_exception_tables(regs->nip)) != NULL) {
 253                tsi108_clear_pci_cfg_error();
 254                regs_set_return_msr(regs, regs->msr | MSR_RI);
 255                regs_set_return_ip(regs, extable_fixup(entry));
 256                return 1;
 257        }
 258        return 0;
 259}
 260
 261define_machine(holly){
 262        .name                           = "PPC750 GX/CL TSI",
 263        .probe                          = holly_probe,
 264        .setup_arch                     = holly_setup_arch,
 265        .discover_phbs                  = holly_init_pci,
 266        .init_IRQ                       = holly_init_IRQ,
 267        .show_cpuinfo                   = holly_show_cpuinfo,
 268        .get_irq                        = mpic_get_irq,
 269        .restart                        = holly_restart,
 270        .calibrate_decr                 = generic_calibrate_decr,
 271        .machine_check_exception        = ppc750_machine_check_exception,
 272        .progress                       = udbg_progress,
 273};
 274