162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 1995 Linus Torvalds 462306a36Sopenharmony_ci * Adapted from 'alpha' version by Gary Thomas 562306a36Sopenharmony_ci * Modified by Cort Dougan (cort@cs.nmt.edu) 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * bootup setup stuff.. 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/errno.h> 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/unistd.h> 1862306a36Sopenharmony_ci#include <linux/ptrace.h> 1962306a36Sopenharmony_ci#include <linux/user.h> 2062306a36Sopenharmony_ci#include <linux/tty.h> 2162306a36Sopenharmony_ci#include <linux/major.h> 2262306a36Sopenharmony_ci#include <linux/interrupt.h> 2362306a36Sopenharmony_ci#include <linux/reboot.h> 2462306a36Sopenharmony_ci#include <linux/init.h> 2562306a36Sopenharmony_ci#include <linux/pci.h> 2662306a36Sopenharmony_ci#include <generated/utsrelease.h> 2762306a36Sopenharmony_ci#include <linux/adb.h> 2862306a36Sopenharmony_ci#include <linux/module.h> 2962306a36Sopenharmony_ci#include <linux/delay.h> 3062306a36Sopenharmony_ci#include <linux/console.h> 3162306a36Sopenharmony_ci#include <linux/seq_file.h> 3262306a36Sopenharmony_ci#include <linux/root_dev.h> 3362306a36Sopenharmony_ci#include <linux/initrd.h> 3462306a36Sopenharmony_ci#include <linux/timer.h> 3562306a36Sopenharmony_ci#include <linux/of_address.h> 3662306a36Sopenharmony_ci#include <linux/of_fdt.h> 3762306a36Sopenharmony_ci#include <linux/of_irq.h> 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci#include <asm/io.h> 4062306a36Sopenharmony_ci#include <asm/pci-bridge.h> 4162306a36Sopenharmony_ci#include <asm/dma.h> 4262306a36Sopenharmony_ci#include <asm/machdep.h> 4362306a36Sopenharmony_ci#include <asm/irq.h> 4462306a36Sopenharmony_ci#include <asm/hydra.h> 4562306a36Sopenharmony_ci#include <asm/sections.h> 4662306a36Sopenharmony_ci#include <asm/time.h> 4762306a36Sopenharmony_ci#include <asm/i8259.h> 4862306a36Sopenharmony_ci#include <asm/mpic.h> 4962306a36Sopenharmony_ci#include <asm/rtas.h> 5062306a36Sopenharmony_ci#include <asm/xmon.h> 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci#include "chrp.h" 5362306a36Sopenharmony_ci#include "gg2.h" 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_civoid rtas_indicator_progress(char *, unsigned short); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ciint _chrp_type; 5862306a36Sopenharmony_ciEXPORT_SYMBOL(_chrp_type); 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_cistatic struct mpic *chrp_mpic; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci/* Used for doing CHRP event-scans */ 6362306a36Sopenharmony_ciDEFINE_PER_CPU(struct timer_list, heartbeat_timer); 6462306a36Sopenharmony_ciunsigned long event_scan_interval; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciextern unsigned long loops_per_jiffy; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci/* To be replaced by RTAS when available */ 6962306a36Sopenharmony_cistatic unsigned int __iomem *briq_SPOR; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci#ifdef CONFIG_SMP 7262306a36Sopenharmony_ciextern struct smp_ops_t chrp_smp_ops; 7362306a36Sopenharmony_ci#endif 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic const char *gg2_memtypes[4] = { 7662306a36Sopenharmony_ci "FPM", "SDRAM", "EDO", "BEDO" 7762306a36Sopenharmony_ci}; 7862306a36Sopenharmony_cistatic const char *gg2_cachesizes[4] = { 7962306a36Sopenharmony_ci "256 KB", "512 KB", "1 MB", "Reserved" 8062306a36Sopenharmony_ci}; 8162306a36Sopenharmony_cistatic const char *gg2_cachetypes[4] = { 8262306a36Sopenharmony_ci "Asynchronous", "Reserved", "Flow-Through Synchronous", 8362306a36Sopenharmony_ci "Pipelined Synchronous" 8462306a36Sopenharmony_ci}; 8562306a36Sopenharmony_cistatic const char *gg2_cachemodes[4] = { 8662306a36Sopenharmony_ci "Disabled", "Write-Through", "Copy-Back", "Transparent Mode" 8762306a36Sopenharmony_ci}; 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic const char *chrp_names[] = { 9062306a36Sopenharmony_ci "Unknown", 9162306a36Sopenharmony_ci "","","", 9262306a36Sopenharmony_ci "Motorola", 9362306a36Sopenharmony_ci "IBM or Longtrail", 9462306a36Sopenharmony_ci "Genesi Pegasos", 9562306a36Sopenharmony_ci "Total Impact Briq" 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic void chrp_show_cpuinfo(struct seq_file *m) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci int i, sdramen; 10162306a36Sopenharmony_ci unsigned int t; 10262306a36Sopenharmony_ci struct device_node *root; 10362306a36Sopenharmony_ci const char *model = ""; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_ci root = of_find_node_by_path("/"); 10662306a36Sopenharmony_ci if (root) 10762306a36Sopenharmony_ci model = of_get_property(root, "model", NULL); 10862306a36Sopenharmony_ci seq_printf(m, "machine\t\t: CHRP %s\n", model); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci /* longtrail (goldengate) stuff */ 11162306a36Sopenharmony_ci if (model && !strncmp(model, "IBM,LongTrail", 13)) { 11262306a36Sopenharmony_ci /* VLSI VAS96011/12 `Golden Gate 2' */ 11362306a36Sopenharmony_ci /* Memory banks */ 11462306a36Sopenharmony_ci sdramen = (in_le32(gg2_pci_config_base + GG2_PCI_DRAM_CTRL) 11562306a36Sopenharmony_ci >>31) & 1; 11662306a36Sopenharmony_ci for (i = 0; i < (sdramen ? 4 : 6); i++) { 11762306a36Sopenharmony_ci t = in_le32(gg2_pci_config_base+ 11862306a36Sopenharmony_ci GG2_PCI_DRAM_BANK0+ 11962306a36Sopenharmony_ci i*4); 12062306a36Sopenharmony_ci if (!(t & 1)) 12162306a36Sopenharmony_ci continue; 12262306a36Sopenharmony_ci switch ((t>>8) & 0x1f) { 12362306a36Sopenharmony_ci case 0x1f: 12462306a36Sopenharmony_ci model = "4 MB"; 12562306a36Sopenharmony_ci break; 12662306a36Sopenharmony_ci case 0x1e: 12762306a36Sopenharmony_ci model = "8 MB"; 12862306a36Sopenharmony_ci break; 12962306a36Sopenharmony_ci case 0x1c: 13062306a36Sopenharmony_ci model = "16 MB"; 13162306a36Sopenharmony_ci break; 13262306a36Sopenharmony_ci case 0x18: 13362306a36Sopenharmony_ci model = "32 MB"; 13462306a36Sopenharmony_ci break; 13562306a36Sopenharmony_ci case 0x10: 13662306a36Sopenharmony_ci model = "64 MB"; 13762306a36Sopenharmony_ci break; 13862306a36Sopenharmony_ci case 0x00: 13962306a36Sopenharmony_ci model = "128 MB"; 14062306a36Sopenharmony_ci break; 14162306a36Sopenharmony_ci default: 14262306a36Sopenharmony_ci model = "Reserved"; 14362306a36Sopenharmony_ci break; 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci seq_printf(m, "memory bank %d\t: %s %s\n", i, model, 14662306a36Sopenharmony_ci gg2_memtypes[sdramen ? 1 : ((t>>1) & 3)]); 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci /* L2 cache */ 14962306a36Sopenharmony_ci t = in_le32(gg2_pci_config_base+GG2_PCI_CC_CTRL); 15062306a36Sopenharmony_ci seq_printf(m, "board l2\t: %s %s (%s)\n", 15162306a36Sopenharmony_ci gg2_cachesizes[(t>>7) & 3], 15262306a36Sopenharmony_ci gg2_cachetypes[(t>>2) & 3], 15362306a36Sopenharmony_ci gg2_cachemodes[t & 3]); 15462306a36Sopenharmony_ci } 15562306a36Sopenharmony_ci of_node_put(root); 15662306a36Sopenharmony_ci} 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci/* 15962306a36Sopenharmony_ci * Fixes for the National Semiconductor PC78308VUL SuperI/O 16062306a36Sopenharmony_ci * 16162306a36Sopenharmony_ci * Some versions of Open Firmware incorrectly initialize the IRQ settings 16262306a36Sopenharmony_ci * for keyboard and mouse 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_cistatic inline void __init sio_write(u8 val, u8 index) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci outb(index, 0x15c); 16762306a36Sopenharmony_ci outb(val, 0x15d); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic inline u8 __init sio_read(u8 index) 17162306a36Sopenharmony_ci{ 17262306a36Sopenharmony_ci outb(index, 0x15c); 17362306a36Sopenharmony_ci return inb(0x15d); 17462306a36Sopenharmony_ci} 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_cistatic void __init sio_fixup_irq(const char *name, u8 device, u8 level, 17762306a36Sopenharmony_ci u8 type) 17862306a36Sopenharmony_ci{ 17962306a36Sopenharmony_ci u8 level0, type0, active; 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* select logical device */ 18262306a36Sopenharmony_ci sio_write(device, 0x07); 18362306a36Sopenharmony_ci active = sio_read(0x30); 18462306a36Sopenharmony_ci level0 = sio_read(0x70); 18562306a36Sopenharmony_ci type0 = sio_read(0x71); 18662306a36Sopenharmony_ci if (level0 != level || type0 != type || !active) { 18762306a36Sopenharmony_ci printk(KERN_WARNING "sio: %s irq level %d, type %d, %sactive: " 18862306a36Sopenharmony_ci "remapping to level %d, type %d, active\n", 18962306a36Sopenharmony_ci name, level0, type0, !active ? "in" : "", level, type); 19062306a36Sopenharmony_ci sio_write(0x01, 0x30); 19162306a36Sopenharmony_ci sio_write(level, 0x70); 19262306a36Sopenharmony_ci sio_write(type, 0x71); 19362306a36Sopenharmony_ci } 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic void __init sio_init(void) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct device_node *root; 19962306a36Sopenharmony_ci const char *model; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci root = of_find_node_by_path("/"); 20262306a36Sopenharmony_ci if (!root) 20362306a36Sopenharmony_ci return; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci model = of_get_property(root, "model", NULL); 20662306a36Sopenharmony_ci if (model && !strncmp(model, "IBM,LongTrail", 13)) { 20762306a36Sopenharmony_ci /* logical device 0 (KBC/Keyboard) */ 20862306a36Sopenharmony_ci sio_fixup_irq("keyboard", 0, 1, 2); 20962306a36Sopenharmony_ci /* select logical device 1 (KBC/Mouse) */ 21062306a36Sopenharmony_ci sio_fixup_irq("mouse", 1, 12, 2); 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci of_node_put(root); 21462306a36Sopenharmony_ci} 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_cistatic void __init pegasos_set_l2cr(void) 21862306a36Sopenharmony_ci{ 21962306a36Sopenharmony_ci struct device_node *np; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci /* On Pegasos, enable the l2 cache if needed, as the OF forgets it */ 22262306a36Sopenharmony_ci if (_chrp_type != _CHRP_Pegasos) 22362306a36Sopenharmony_ci return; 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci /* Enable L2 cache if needed */ 22662306a36Sopenharmony_ci np = of_find_node_by_type(NULL, "cpu"); 22762306a36Sopenharmony_ci if (np != NULL) { 22862306a36Sopenharmony_ci const unsigned int *l2cr = of_get_property(np, "l2cr", NULL); 22962306a36Sopenharmony_ci if (l2cr == NULL) { 23062306a36Sopenharmony_ci printk ("Pegasos l2cr : no cpu l2cr property found\n"); 23162306a36Sopenharmony_ci goto out; 23262306a36Sopenharmony_ci } 23362306a36Sopenharmony_ci if (!((*l2cr) & 0x80000000)) { 23462306a36Sopenharmony_ci printk ("Pegasos l2cr : L2 cache was not active, " 23562306a36Sopenharmony_ci "activating\n"); 23662306a36Sopenharmony_ci _set_L2CR(0); 23762306a36Sopenharmony_ci _set_L2CR((*l2cr) | 0x80000000); 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci } 24062306a36Sopenharmony_ciout: 24162306a36Sopenharmony_ci of_node_put(np); 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic void __noreturn briq_restart(char *cmd) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci local_irq_disable(); 24762306a36Sopenharmony_ci if (briq_SPOR) 24862306a36Sopenharmony_ci out_be32(briq_SPOR, 0); 24962306a36Sopenharmony_ci for(;;); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* 25362306a36Sopenharmony_ci * Per default, input/output-device points to the keyboard/screen 25462306a36Sopenharmony_ci * If no card is installed, the built-in serial port is used as a fallback. 25562306a36Sopenharmony_ci * But unfortunately, the firmware does not connect /chosen/{stdin,stdout} 25662306a36Sopenharmony_ci * to the built-in serial node. Instead, a /failsafe node is created. 25762306a36Sopenharmony_ci */ 25862306a36Sopenharmony_cistatic __init void chrp_init(void) 25962306a36Sopenharmony_ci{ 26062306a36Sopenharmony_ci struct device_node *node; 26162306a36Sopenharmony_ci const char *property; 26262306a36Sopenharmony_ci 26362306a36Sopenharmony_ci if (strstr(boot_command_line, "console=")) 26462306a36Sopenharmony_ci return; 26562306a36Sopenharmony_ci /* find the boot console from /chosen/stdout */ 26662306a36Sopenharmony_ci if (!of_chosen) 26762306a36Sopenharmony_ci return; 26862306a36Sopenharmony_ci node = of_find_node_by_path("/"); 26962306a36Sopenharmony_ci if (!node) 27062306a36Sopenharmony_ci return; 27162306a36Sopenharmony_ci property = of_get_property(node, "model", NULL); 27262306a36Sopenharmony_ci if (!property) 27362306a36Sopenharmony_ci goto out_put; 27462306a36Sopenharmony_ci if (strcmp(property, "Pegasos2")) 27562306a36Sopenharmony_ci goto out_put; 27662306a36Sopenharmony_ci /* this is a Pegasos2 */ 27762306a36Sopenharmony_ci property = of_get_property(of_chosen, "linux,stdout-path", NULL); 27862306a36Sopenharmony_ci if (!property) 27962306a36Sopenharmony_ci goto out_put; 28062306a36Sopenharmony_ci of_node_put(node); 28162306a36Sopenharmony_ci node = of_find_node_by_path(property); 28262306a36Sopenharmony_ci if (!node) 28362306a36Sopenharmony_ci return; 28462306a36Sopenharmony_ci if (!of_node_is_type(node, "serial")) 28562306a36Sopenharmony_ci goto out_put; 28662306a36Sopenharmony_ci /* 28762306a36Sopenharmony_ci * The 9pin connector is either /failsafe 28862306a36Sopenharmony_ci * or /pci@80000000/isa@C/serial@i2F8 28962306a36Sopenharmony_ci * The optional graphics card has also type 'serial' in VGA mode. 29062306a36Sopenharmony_ci */ 29162306a36Sopenharmony_ci if (of_node_name_eq(node, "failsafe") || of_node_name_eq(node, "serial")) 29262306a36Sopenharmony_ci add_preferred_console("ttyS", 0, NULL); 29362306a36Sopenharmony_ciout_put: 29462306a36Sopenharmony_ci of_node_put(node); 29562306a36Sopenharmony_ci} 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cistatic void __init chrp_setup_arch(void) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct device_node *root = of_find_node_by_path("/"); 30062306a36Sopenharmony_ci const char *machine = NULL; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci /* init to some ~sane value until calibrate_delay() runs */ 30362306a36Sopenharmony_ci loops_per_jiffy = 50000000/HZ; 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci if (root) 30662306a36Sopenharmony_ci machine = of_get_property(root, "model", NULL); 30762306a36Sopenharmony_ci if (machine && strncmp(machine, "Pegasos", 7) == 0) { 30862306a36Sopenharmony_ci _chrp_type = _CHRP_Pegasos; 30962306a36Sopenharmony_ci } else if (machine && strncmp(machine, "IBM", 3) == 0) { 31062306a36Sopenharmony_ci _chrp_type = _CHRP_IBM; 31162306a36Sopenharmony_ci } else if (machine && strncmp(machine, "MOT", 3) == 0) { 31262306a36Sopenharmony_ci _chrp_type = _CHRP_Motorola; 31362306a36Sopenharmony_ci } else if (machine && strncmp(machine, "TotalImpact,BRIQ-1", 18) == 0) { 31462306a36Sopenharmony_ci _chrp_type = _CHRP_briq; 31562306a36Sopenharmony_ci /* Map the SPOR register on briq and change the restart hook */ 31662306a36Sopenharmony_ci briq_SPOR = ioremap(0xff0000e8, 4); 31762306a36Sopenharmony_ci ppc_md.restart = briq_restart; 31862306a36Sopenharmony_ci } else { 31962306a36Sopenharmony_ci /* Let's assume it is an IBM chrp if all else fails */ 32062306a36Sopenharmony_ci _chrp_type = _CHRP_IBM; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci of_node_put(root); 32362306a36Sopenharmony_ci printk("chrp type = %x [%s]\n", _chrp_type, chrp_names[_chrp_type]); 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci rtas_initialize(); 32662306a36Sopenharmony_ci if (rtas_function_token(RTAS_FN_DISPLAY_CHARACTER) >= 0) 32762306a36Sopenharmony_ci ppc_md.progress = rtas_progress; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci /* use RTAS time-of-day routines if available */ 33062306a36Sopenharmony_ci if (rtas_function_token(RTAS_FN_GET_TIME_OF_DAY) != RTAS_UNKNOWN_SERVICE) { 33162306a36Sopenharmony_ci ppc_md.get_boot_time = rtas_get_boot_time; 33262306a36Sopenharmony_ci ppc_md.get_rtc_time = rtas_get_rtc_time; 33362306a36Sopenharmony_ci ppc_md.set_rtc_time = rtas_set_rtc_time; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci /* On pegasos, enable the L2 cache if not already done by OF */ 33762306a36Sopenharmony_ci pegasos_set_l2cr(); 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* 34062306a36Sopenharmony_ci * Fix the Super I/O configuration 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci sio_init(); 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* 34562306a36Sopenharmony_ci * Print the banner, then scroll down so boot progress 34662306a36Sopenharmony_ci * can be printed. -- Cort 34762306a36Sopenharmony_ci */ 34862306a36Sopenharmony_ci if (ppc_md.progress) ppc_md.progress("Linux/PPC "UTS_RELEASE"\n", 0x0); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_cistatic void chrp_8259_cascade(struct irq_desc *desc) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci struct irq_chip *chip = irq_desc_get_chip(desc); 35462306a36Sopenharmony_ci unsigned int cascade_irq = i8259_irq(); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (cascade_irq) 35762306a36Sopenharmony_ci generic_handle_irq(cascade_irq); 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci chip->irq_eoi(&desc->irq_data); 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci/* 36362306a36Sopenharmony_ci * Finds the open-pic node and sets up the mpic driver. 36462306a36Sopenharmony_ci */ 36562306a36Sopenharmony_cistatic void __init chrp_find_openpic(void) 36662306a36Sopenharmony_ci{ 36762306a36Sopenharmony_ci struct device_node *np, *root; 36862306a36Sopenharmony_ci int len, i, j; 36962306a36Sopenharmony_ci int isu_size; 37062306a36Sopenharmony_ci const unsigned int *iranges, *opprop = NULL; 37162306a36Sopenharmony_ci int oplen = 0; 37262306a36Sopenharmony_ci unsigned long opaddr; 37362306a36Sopenharmony_ci int na = 1; 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci np = of_find_node_by_type(NULL, "open-pic"); 37662306a36Sopenharmony_ci if (np == NULL) 37762306a36Sopenharmony_ci return; 37862306a36Sopenharmony_ci root = of_find_node_by_path("/"); 37962306a36Sopenharmony_ci if (root) { 38062306a36Sopenharmony_ci opprop = of_get_property(root, "platform-open-pic", &oplen); 38162306a36Sopenharmony_ci na = of_n_addr_cells(root); 38262306a36Sopenharmony_ci } 38362306a36Sopenharmony_ci if (opprop && oplen >= na * sizeof(unsigned int)) { 38462306a36Sopenharmony_ci opaddr = opprop[na-1]; /* assume 32-bit */ 38562306a36Sopenharmony_ci oplen /= na * sizeof(unsigned int); 38662306a36Sopenharmony_ci } else { 38762306a36Sopenharmony_ci struct resource r; 38862306a36Sopenharmony_ci if (of_address_to_resource(np, 0, &r)) { 38962306a36Sopenharmony_ci goto bail; 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci opaddr = r.start; 39262306a36Sopenharmony_ci oplen = 0; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci printk(KERN_INFO "OpenPIC at %lx\n", opaddr); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci iranges = of_get_property(np, "interrupt-ranges", &len); 39862306a36Sopenharmony_ci if (iranges == NULL) 39962306a36Sopenharmony_ci len = 0; /* non-distributed mpic */ 40062306a36Sopenharmony_ci else 40162306a36Sopenharmony_ci len /= 2 * sizeof(unsigned int); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* 40462306a36Sopenharmony_ci * The first pair of cells in interrupt-ranges refers to the 40562306a36Sopenharmony_ci * IDU; subsequent pairs refer to the ISUs. 40662306a36Sopenharmony_ci */ 40762306a36Sopenharmony_ci if (oplen < len) { 40862306a36Sopenharmony_ci printk(KERN_ERR "Insufficient addresses for distributed" 40962306a36Sopenharmony_ci " OpenPIC (%d < %d)\n", oplen, len); 41062306a36Sopenharmony_ci len = oplen; 41162306a36Sopenharmony_ci } 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci isu_size = 0; 41462306a36Sopenharmony_ci if (len > 0 && iranges[1] != 0) { 41562306a36Sopenharmony_ci printk(KERN_INFO "OpenPIC irqs %d..%d in IDU\n", 41662306a36Sopenharmony_ci iranges[0], iranges[0] + iranges[1] - 1); 41762306a36Sopenharmony_ci } 41862306a36Sopenharmony_ci if (len > 1) 41962306a36Sopenharmony_ci isu_size = iranges[3]; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci chrp_mpic = mpic_alloc(np, opaddr, MPIC_NO_RESET, 42262306a36Sopenharmony_ci isu_size, 0, " MPIC "); 42362306a36Sopenharmony_ci if (chrp_mpic == NULL) { 42462306a36Sopenharmony_ci printk(KERN_ERR "Failed to allocate MPIC structure\n"); 42562306a36Sopenharmony_ci goto bail; 42662306a36Sopenharmony_ci } 42762306a36Sopenharmony_ci j = na - 1; 42862306a36Sopenharmony_ci for (i = 1; i < len; ++i) { 42962306a36Sopenharmony_ci iranges += 2; 43062306a36Sopenharmony_ci j += na; 43162306a36Sopenharmony_ci printk(KERN_INFO "OpenPIC irqs %d..%d in ISU at %x\n", 43262306a36Sopenharmony_ci iranges[0], iranges[0] + iranges[1] - 1, 43362306a36Sopenharmony_ci opprop[j]); 43462306a36Sopenharmony_ci mpic_assign_isu(chrp_mpic, i - 1, opprop[j]); 43562306a36Sopenharmony_ci } 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci mpic_init(chrp_mpic); 43862306a36Sopenharmony_ci ppc_md.get_irq = mpic_get_irq; 43962306a36Sopenharmony_ci bail: 44062306a36Sopenharmony_ci of_node_put(root); 44162306a36Sopenharmony_ci of_node_put(np); 44262306a36Sopenharmony_ci} 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_cistatic void __init chrp_find_8259(void) 44562306a36Sopenharmony_ci{ 44662306a36Sopenharmony_ci struct device_node *np, *pic = NULL; 44762306a36Sopenharmony_ci unsigned long chrp_int_ack = 0; 44862306a36Sopenharmony_ci unsigned int cascade_irq; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci /* Look for cascade */ 45162306a36Sopenharmony_ci for_each_node_by_type(np, "interrupt-controller") 45262306a36Sopenharmony_ci if (of_device_is_compatible(np, "chrp,iic")) { 45362306a36Sopenharmony_ci pic = np; 45462306a36Sopenharmony_ci break; 45562306a36Sopenharmony_ci } 45662306a36Sopenharmony_ci /* Ok, 8259 wasn't found. We need to handle the case where 45762306a36Sopenharmony_ci * we have a pegasos that claims to be chrp but doesn't have 45862306a36Sopenharmony_ci * a proper interrupt tree 45962306a36Sopenharmony_ci */ 46062306a36Sopenharmony_ci if (pic == NULL && chrp_mpic != NULL) { 46162306a36Sopenharmony_ci printk(KERN_ERR "i8259: Not found in device-tree" 46262306a36Sopenharmony_ci " assuming no legacy interrupts\n"); 46362306a36Sopenharmony_ci return; 46462306a36Sopenharmony_ci } 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_ci /* Look for intack. In a perfect world, we would look for it on 46762306a36Sopenharmony_ci * the ISA bus that holds the 8259 but heh... Works that way. If 46862306a36Sopenharmony_ci * we ever see a problem, we can try to re-use the pSeries code here. 46962306a36Sopenharmony_ci * Also, Pegasos-type platforms don't have a proper node to start 47062306a36Sopenharmony_ci * from anyway 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_ci for_each_node_by_name(np, "pci") { 47362306a36Sopenharmony_ci const unsigned int *addrp = of_get_property(np, 47462306a36Sopenharmony_ci "8259-interrupt-acknowledge", NULL); 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci if (addrp == NULL) 47762306a36Sopenharmony_ci continue; 47862306a36Sopenharmony_ci chrp_int_ack = addrp[of_n_addr_cells(np)-1]; 47962306a36Sopenharmony_ci break; 48062306a36Sopenharmony_ci } 48162306a36Sopenharmony_ci of_node_put(np); 48262306a36Sopenharmony_ci if (np == NULL) 48362306a36Sopenharmony_ci printk(KERN_WARNING "Cannot find PCI interrupt acknowledge" 48462306a36Sopenharmony_ci " address, polling\n"); 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci i8259_init(pic, chrp_int_ack); 48762306a36Sopenharmony_ci if (ppc_md.get_irq == NULL) { 48862306a36Sopenharmony_ci ppc_md.get_irq = i8259_irq; 48962306a36Sopenharmony_ci irq_set_default_host(i8259_get_host()); 49062306a36Sopenharmony_ci } 49162306a36Sopenharmony_ci if (chrp_mpic != NULL) { 49262306a36Sopenharmony_ci cascade_irq = irq_of_parse_and_map(pic, 0); 49362306a36Sopenharmony_ci if (!cascade_irq) 49462306a36Sopenharmony_ci printk(KERN_ERR "i8259: failed to map cascade irq\n"); 49562306a36Sopenharmony_ci else 49662306a36Sopenharmony_ci irq_set_chained_handler(cascade_irq, 49762306a36Sopenharmony_ci chrp_8259_cascade); 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci} 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_cistatic void __init chrp_init_IRQ(void) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON) 50462306a36Sopenharmony_ci struct device_node *kbd; 50562306a36Sopenharmony_ci#endif 50662306a36Sopenharmony_ci chrp_find_openpic(); 50762306a36Sopenharmony_ci chrp_find_8259(); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci#ifdef CONFIG_SMP 51062306a36Sopenharmony_ci /* Pegasos has no MPIC, those ops would make it crash. It might be an 51162306a36Sopenharmony_ci * option to move setting them to after we probe the PIC though 51262306a36Sopenharmony_ci */ 51362306a36Sopenharmony_ci if (chrp_mpic != NULL) 51462306a36Sopenharmony_ci smp_ops = &chrp_smp_ops; 51562306a36Sopenharmony_ci#endif /* CONFIG_SMP */ 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_ci if (_chrp_type == _CHRP_Pegasos) 51862306a36Sopenharmony_ci ppc_md.get_irq = i8259_irq; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci#if defined(CONFIG_VT) && defined(CONFIG_INPUT_ADBHID) && defined(CONFIG_XMON) 52162306a36Sopenharmony_ci /* see if there is a keyboard in the device tree 52262306a36Sopenharmony_ci with a parent of type "adb" */ 52362306a36Sopenharmony_ci for_each_node_by_name(kbd, "keyboard") 52462306a36Sopenharmony_ci if (of_node_is_type(kbd->parent, "adb")) 52562306a36Sopenharmony_ci break; 52662306a36Sopenharmony_ci of_node_put(kbd); 52762306a36Sopenharmony_ci if (kbd) { 52862306a36Sopenharmony_ci if (request_irq(HYDRA_INT_ADB_NMI, xmon_irq, 0, "XMON break", 52962306a36Sopenharmony_ci NULL)) 53062306a36Sopenharmony_ci pr_err("Failed to register XMON break interrupt\n"); 53162306a36Sopenharmony_ci } 53262306a36Sopenharmony_ci#endif 53362306a36Sopenharmony_ci} 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic void __init 53662306a36Sopenharmony_cichrp_init2(void) 53762306a36Sopenharmony_ci{ 53862306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_NVRAM) 53962306a36Sopenharmony_ci chrp_nvram_init(); 54062306a36Sopenharmony_ci#endif 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci request_region(0x20,0x20,"pic1"); 54362306a36Sopenharmony_ci request_region(0xa0,0x20,"pic2"); 54462306a36Sopenharmony_ci request_region(0x00,0x20,"dma1"); 54562306a36Sopenharmony_ci request_region(0x40,0x20,"timer"); 54662306a36Sopenharmony_ci request_region(0x80,0x10,"dma page reg"); 54762306a36Sopenharmony_ci request_region(0xc0,0x20,"dma2"); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci if (ppc_md.progress) 55062306a36Sopenharmony_ci ppc_md.progress(" Have fun! ", 0x7777); 55162306a36Sopenharmony_ci} 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_cistatic int __init chrp_probe(void) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci const char *dtype = of_get_flat_dt_prop(of_get_flat_dt_root(), 55662306a36Sopenharmony_ci "device_type", NULL); 55762306a36Sopenharmony_ci if (dtype == NULL) 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci if (strcmp(dtype, "chrp")) 56062306a36Sopenharmony_ci return 0; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci DMA_MODE_READ = 0x44; 56362306a36Sopenharmony_ci DMA_MODE_WRITE = 0x48; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci pm_power_off = rtas_power_off; 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci chrp_init(); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci return 1; 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_cidefine_machine(chrp) { 57362306a36Sopenharmony_ci .name = "CHRP", 57462306a36Sopenharmony_ci .probe = chrp_probe, 57562306a36Sopenharmony_ci .setup_arch = chrp_setup_arch, 57662306a36Sopenharmony_ci .discover_phbs = chrp_find_bridges, 57762306a36Sopenharmony_ci .init = chrp_init2, 57862306a36Sopenharmony_ci .show_cpuinfo = chrp_show_cpuinfo, 57962306a36Sopenharmony_ci .init_IRQ = chrp_init_IRQ, 58062306a36Sopenharmony_ci .restart = rtas_restart, 58162306a36Sopenharmony_ci .halt = rtas_halt, 58262306a36Sopenharmony_ci .time_init = chrp_time_init, 58362306a36Sopenharmony_ci .set_rtc_time = chrp_set_rtc_time, 58462306a36Sopenharmony_ci .get_rtc_time = chrp_get_rtc_time, 58562306a36Sopenharmony_ci .phys_mem_access_prot = pci_phys_mem_access_prot, 58662306a36Sopenharmony_ci}; 587