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_setup_arch(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        tsi108_csr_vir_base = get_vir_csrbase();
 119
 120        /* setup PCI host bridge */
 121        holly_remap_bridge();
 122
 123        np = of_find_node_by_type(NULL, "pci");
 124        if (np)
 125                tsi108_setup_pci(np, HOLLY_PCI_CFG_PHYS, 1);
 126
 127        ppc_md.pci_exclude_device = holly_exclude_device;
 128        if (ppc_md.progress)
 129                ppc_md.progress("tsi108: resources set", 0x100);
 130
 131        printk(KERN_INFO "PPC750GX/CL Platform\n");
 132}
 133
 134/*
 135 * Interrupt setup and service.  Interrupts on the holly come
 136 * from the four external INT pins, PCI interrupts are routed via
 137 * PCI interrupt control registers, it generates internal IRQ23
 138 *
 139 * Interrupt routing on the Holly Board:
 140 * TSI108:PB_INT[0] -> CPU0:INT#
 141 * TSI108:PB_INT[1] -> CPU0:MCP#
 142 * TSI108:PB_INT[2] -> N/C
 143 * TSI108:PB_INT[3] -> N/C
 144 */
 145static void __init holly_init_IRQ(void)
 146{
 147        struct mpic *mpic;
 148#ifdef CONFIG_PCI
 149        unsigned int cascade_pci_irq;
 150        struct device_node *tsi_pci;
 151        struct device_node *cascade_node = NULL;
 152#endif
 153
 154        mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
 155                        MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
 156                        24, 0,
 157                        "Tsi108_PIC");
 158
 159        BUG_ON(mpic == NULL);
 160
 161        mpic_assign_isu(mpic, 0, mpic->paddr + 0x100);
 162
 163        mpic_init(mpic);
 164
 165#ifdef CONFIG_PCI
 166        tsi_pci = of_find_node_by_type(NULL, "pci");
 167        if (tsi_pci == NULL) {
 168                printk(KERN_ERR "%s: No tsi108 pci node found !\n", __func__);
 169                return;
 170        }
 171
 172        cascade_node = of_find_node_by_type(NULL, "pic-router");
 173        if (cascade_node == NULL) {
 174                printk(KERN_ERR "%s: No tsi108 pci cascade node found !\n", __func__);
 175                return;
 176        }
 177
 178        cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0);
 179        pr_debug("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq);
 180        tsi108_pci_int_init(cascade_node);
 181        irq_set_handler_data(cascade_pci_irq, mpic);
 182        irq_set_chained_handler(cascade_pci_irq, tsi108_irq_cascade);
 183#endif
 184        /* Configure MPIC outputs to CPU0 */
 185        tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
 186}
 187
 188static void holly_show_cpuinfo(struct seq_file *m)
 189{
 190        seq_printf(m, "vendor\t\t: IBM\n");
 191        seq_printf(m, "machine\t\t: PPC750 GX/CL\n");
 192}
 193
 194static void __noreturn holly_restart(char *cmd)
 195{
 196        __be32 __iomem *ocn_bar1 = NULL;
 197        unsigned long bar;
 198        struct device_node *bridge = NULL;
 199        const void *prop;
 200        int size;
 201        phys_addr_t addr = 0xc0000000;
 202
 203        local_irq_disable();
 204
 205        bridge = of_find_node_by_type(NULL, "tsi-bridge");
 206        if (bridge) {
 207                prop = of_get_property(bridge, "reg", &size);
 208                addr = of_translate_address(bridge, prop);
 209        }
 210        addr += (TSI108_PB_OFFSET + 0x414);
 211
 212        ocn_bar1 = ioremap(addr, 0x4);
 213
 214        /* Turn on the BOOT bit so the addresses are correctly
 215         * routed to the HLP interface */
 216        bar = ioread32be(ocn_bar1);
 217        bar |= 2;
 218        iowrite32be(bar, ocn_bar1);
 219        iosync();
 220
 221        /* Set SRR0 to the reset vector and turn on MSR_IP */
 222        mtspr(SPRN_SRR0, 0xfff00100);
 223        mtspr(SPRN_SRR1, MSR_IP);
 224
 225        /* Do an rfi to jump back to firmware.  Somewhat evil,
 226         * but it works
 227         */
 228        __asm__ __volatile__("rfi" : : : "memory");
 229
 230        /* Spin until reset happens.  Shouldn't really get here */
 231        for (;;) ;
 232}
 233
 234/*
 235 * Called very early, device-tree isn't unflattened
 236 */
 237static int __init holly_probe(void)
 238{
 239        if (!of_machine_is_compatible("ibm,holly"))
 240                return 0;
 241        return 1;
 242}
 243
 244static int ppc750_machine_check_exception(struct pt_regs *regs)
 245{
 246        const struct exception_table_entry *entry;
 247
 248        /* Are we prepared to handle this fault */
 249        if ((entry = search_exception_tables(regs->nip)) != NULL) {
 250                tsi108_clear_pci_cfg_error();
 251                regs->msr |= MSR_RI;
 252                regs->nip = extable_fixup(entry);
 253                return 1;
 254        }
 255        return 0;
 256}
 257
 258define_machine(holly){
 259        .name                           = "PPC750 GX/CL TSI",
 260        .probe                          = holly_probe,
 261        .setup_arch                     = holly_setup_arch,
 262        .init_IRQ                       = holly_init_IRQ,
 263        .show_cpuinfo                   = holly_show_cpuinfo,
 264        .get_irq                        = mpic_get_irq,
 265        .restart                        = holly_restart,
 266        .calibrate_decr                 = generic_calibrate_decr,
 267        .machine_check_exception        = ppc750_machine_check_exception,
 268        .progress                       = udbg_progress,
 269};
 270