18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Powermac setup and early boot code plus other random bits. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * PowerPC version 68c2ecf20Sopenharmony_ci * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Adapted for Power Macintosh by Paul Mackerras 98c2ecf20Sopenharmony_ci * Copyright (C) 1996 Paul Mackerras (paulus@samba.org) 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * Derived from "arch/alpha/kernel/setup.c" 128c2ecf20Sopenharmony_ci * Copyright (C) 1995 Linus Torvalds 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Maintained by Benjamin Herrenschmidt (benh@kernel.crashing.org) 158c2ecf20Sopenharmony_ci */ 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci/* 188c2ecf20Sopenharmony_ci * bootup setup stuff.. 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/errno.h> 238c2ecf20Sopenharmony_ci#include <linux/sched.h> 248c2ecf20Sopenharmony_ci#include <linux/kernel.h> 258c2ecf20Sopenharmony_ci#include <linux/mm.h> 268c2ecf20Sopenharmony_ci#include <linux/stddef.h> 278c2ecf20Sopenharmony_ci#include <linux/unistd.h> 288c2ecf20Sopenharmony_ci#include <linux/ptrace.h> 298c2ecf20Sopenharmony_ci#include <linux/export.h> 308c2ecf20Sopenharmony_ci#include <linux/user.h> 318c2ecf20Sopenharmony_ci#include <linux/tty.h> 328c2ecf20Sopenharmony_ci#include <linux/string.h> 338c2ecf20Sopenharmony_ci#include <linux/delay.h> 348c2ecf20Sopenharmony_ci#include <linux/ioport.h> 358c2ecf20Sopenharmony_ci#include <linux/major.h> 368c2ecf20Sopenharmony_ci#include <linux/initrd.h> 378c2ecf20Sopenharmony_ci#include <linux/vt_kern.h> 388c2ecf20Sopenharmony_ci#include <linux/console.h> 398c2ecf20Sopenharmony_ci#include <linux/pci.h> 408c2ecf20Sopenharmony_ci#include <linux/adb.h> 418c2ecf20Sopenharmony_ci#include <linux/cuda.h> 428c2ecf20Sopenharmony_ci#include <linux/pmu.h> 438c2ecf20Sopenharmony_ci#include <linux/irq.h> 448c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 458c2ecf20Sopenharmony_ci#include <linux/root_dev.h> 468c2ecf20Sopenharmony_ci#include <linux/bitops.h> 478c2ecf20Sopenharmony_ci#include <linux/suspend.h> 488c2ecf20Sopenharmony_ci#include <linux/of_device.h> 498c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#include <asm/reg.h> 528c2ecf20Sopenharmony_ci#include <asm/sections.h> 538c2ecf20Sopenharmony_ci#include <asm/prom.h> 548c2ecf20Sopenharmony_ci#include <asm/io.h> 558c2ecf20Sopenharmony_ci#include <asm/pci-bridge.h> 568c2ecf20Sopenharmony_ci#include <asm/ohare.h> 578c2ecf20Sopenharmony_ci#include <asm/mediabay.h> 588c2ecf20Sopenharmony_ci#include <asm/machdep.h> 598c2ecf20Sopenharmony_ci#include <asm/dma.h> 608c2ecf20Sopenharmony_ci#include <asm/cputable.h> 618c2ecf20Sopenharmony_ci#include <asm/btext.h> 628c2ecf20Sopenharmony_ci#include <asm/pmac_feature.h> 638c2ecf20Sopenharmony_ci#include <asm/time.h> 648c2ecf20Sopenharmony_ci#include <asm/mmu_context.h> 658c2ecf20Sopenharmony_ci#include <asm/iommu.h> 668c2ecf20Sopenharmony_ci#include <asm/smu.h> 678c2ecf20Sopenharmony_ci#include <asm/pmc.h> 688c2ecf20Sopenharmony_ci#include <asm/udbg.h> 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci#include "pmac.h" 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#undef SHOW_GATWICK_IRQS 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ciint ppc_override_l2cr = 0; 758c2ecf20Sopenharmony_ciint ppc_override_l2cr_value; 768c2ecf20Sopenharmony_ciint has_l2cache = 0; 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ciint pmac_newworld; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_cistatic int current_root_goodness = -1; 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ciextern struct machdep_calls pmac_md; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */ 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 878c2ecf20Sopenharmony_ciint sccdbg; 888c2ecf20Sopenharmony_ci#endif 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cisys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN; 918c2ecf20Sopenharmony_ciEXPORT_SYMBOL(sys_ctrler); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_cistatic void pmac_show_cpuinfo(struct seq_file *m) 948c2ecf20Sopenharmony_ci{ 958c2ecf20Sopenharmony_ci struct device_node *np; 968c2ecf20Sopenharmony_ci const char *pp; 978c2ecf20Sopenharmony_ci int plen; 988c2ecf20Sopenharmony_ci int mbmodel; 998c2ecf20Sopenharmony_ci unsigned int mbflags; 1008c2ecf20Sopenharmony_ci char* mbname; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, 1038c2ecf20Sopenharmony_ci PMAC_MB_INFO_MODEL, 0); 1048c2ecf20Sopenharmony_ci mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, 1058c2ecf20Sopenharmony_ci PMAC_MB_INFO_FLAGS, 0); 1068c2ecf20Sopenharmony_ci if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME, 1078c2ecf20Sopenharmony_ci (long) &mbname) != 0) 1088c2ecf20Sopenharmony_ci mbname = "Unknown"; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* find motherboard type */ 1118c2ecf20Sopenharmony_ci seq_printf(m, "machine\t\t: "); 1128c2ecf20Sopenharmony_ci np = of_find_node_by_path("/"); 1138c2ecf20Sopenharmony_ci if (np != NULL) { 1148c2ecf20Sopenharmony_ci pp = of_get_property(np, "model", NULL); 1158c2ecf20Sopenharmony_ci if (pp != NULL) 1168c2ecf20Sopenharmony_ci seq_printf(m, "%s\n", pp); 1178c2ecf20Sopenharmony_ci else 1188c2ecf20Sopenharmony_ci seq_printf(m, "PowerMac\n"); 1198c2ecf20Sopenharmony_ci pp = of_get_property(np, "compatible", &plen); 1208c2ecf20Sopenharmony_ci if (pp != NULL) { 1218c2ecf20Sopenharmony_ci seq_printf(m, "motherboard\t:"); 1228c2ecf20Sopenharmony_ci while (plen > 0) { 1238c2ecf20Sopenharmony_ci int l = strlen(pp) + 1; 1248c2ecf20Sopenharmony_ci seq_printf(m, " %s", pp); 1258c2ecf20Sopenharmony_ci plen -= l; 1268c2ecf20Sopenharmony_ci pp += l; 1278c2ecf20Sopenharmony_ci } 1288c2ecf20Sopenharmony_ci seq_printf(m, "\n"); 1298c2ecf20Sopenharmony_ci } 1308c2ecf20Sopenharmony_ci of_node_put(np); 1318c2ecf20Sopenharmony_ci } else 1328c2ecf20Sopenharmony_ci seq_printf(m, "PowerMac\n"); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci /* print parsed model */ 1358c2ecf20Sopenharmony_ci seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname); 1368c2ecf20Sopenharmony_ci seq_printf(m, "pmac flags\t: %08x\n", mbflags); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci /* find l2 cache info */ 1398c2ecf20Sopenharmony_ci np = of_find_node_by_name(NULL, "l2-cache"); 1408c2ecf20Sopenharmony_ci if (np == NULL) 1418c2ecf20Sopenharmony_ci np = of_find_node_by_type(NULL, "cache"); 1428c2ecf20Sopenharmony_ci if (np != NULL) { 1438c2ecf20Sopenharmony_ci const unsigned int *ic = 1448c2ecf20Sopenharmony_ci of_get_property(np, "i-cache-size", NULL); 1458c2ecf20Sopenharmony_ci const unsigned int *dc = 1468c2ecf20Sopenharmony_ci of_get_property(np, "d-cache-size", NULL); 1478c2ecf20Sopenharmony_ci seq_printf(m, "L2 cache\t:"); 1488c2ecf20Sopenharmony_ci has_l2cache = 1; 1498c2ecf20Sopenharmony_ci if (of_get_property(np, "cache-unified", NULL) && dc) { 1508c2ecf20Sopenharmony_ci seq_printf(m, " %dK unified", *dc / 1024); 1518c2ecf20Sopenharmony_ci } else { 1528c2ecf20Sopenharmony_ci if (ic) 1538c2ecf20Sopenharmony_ci seq_printf(m, " %dK instruction", *ic / 1024); 1548c2ecf20Sopenharmony_ci if (dc) 1558c2ecf20Sopenharmony_ci seq_printf(m, "%s %dK data", 1568c2ecf20Sopenharmony_ci (ic? " +": ""), *dc / 1024); 1578c2ecf20Sopenharmony_ci } 1588c2ecf20Sopenharmony_ci pp = of_get_property(np, "ram-type", NULL); 1598c2ecf20Sopenharmony_ci if (pp) 1608c2ecf20Sopenharmony_ci seq_printf(m, " %s", pp); 1618c2ecf20Sopenharmony_ci seq_printf(m, "\n"); 1628c2ecf20Sopenharmony_ci of_node_put(np); 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci /* Indicate newworld/oldworld */ 1668c2ecf20Sopenharmony_ci seq_printf(m, "pmac-generation\t: %s\n", 1678c2ecf20Sopenharmony_ci pmac_newworld ? "NewWorld" : "OldWorld"); 1688c2ecf20Sopenharmony_ci} 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci#ifndef CONFIG_ADB_CUDA 1718c2ecf20Sopenharmony_ciint find_via_cuda(void) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci struct device_node *dn = of_find_node_by_name(NULL, "via-cuda"); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (!dn) 1768c2ecf20Sopenharmony_ci return 0; 1778c2ecf20Sopenharmony_ci of_node_put(dn); 1788c2ecf20Sopenharmony_ci printk("WARNING ! Your machine is CUDA-based but your kernel\n"); 1798c2ecf20Sopenharmony_ci printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n"); 1808c2ecf20Sopenharmony_ci return 0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci#endif 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci#ifndef CONFIG_ADB_PMU 1858c2ecf20Sopenharmony_ciint find_via_pmu(void) 1868c2ecf20Sopenharmony_ci{ 1878c2ecf20Sopenharmony_ci struct device_node *dn = of_find_node_by_name(NULL, "via-pmu"); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!dn) 1908c2ecf20Sopenharmony_ci return 0; 1918c2ecf20Sopenharmony_ci of_node_put(dn); 1928c2ecf20Sopenharmony_ci printk("WARNING ! Your machine is PMU-based but your kernel\n"); 1938c2ecf20Sopenharmony_ci printk(" wasn't compiled with CONFIG_ADB_PMU option !\n"); 1948c2ecf20Sopenharmony_ci return 0; 1958c2ecf20Sopenharmony_ci} 1968c2ecf20Sopenharmony_ci#endif 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci#ifndef CONFIG_PMAC_SMU 1998c2ecf20Sopenharmony_ciint smu_init(void) 2008c2ecf20Sopenharmony_ci{ 2018c2ecf20Sopenharmony_ci /* should check and warn if SMU is present */ 2028c2ecf20Sopenharmony_ci return 0; 2038c2ecf20Sopenharmony_ci} 2048c2ecf20Sopenharmony_ci#endif 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 2078c2ecf20Sopenharmony_cistatic volatile u32 *sysctrl_regs; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic void __init ohare_init(void) 2108c2ecf20Sopenharmony_ci{ 2118c2ecf20Sopenharmony_ci struct device_node *dn; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci /* this area has the CPU identification register 2148c2ecf20Sopenharmony_ci and some registers used by smp boards */ 2158c2ecf20Sopenharmony_ci sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * Turn on the L2 cache. 2198c2ecf20Sopenharmony_ci * We assume that we have a PSX memory controller iff 2208c2ecf20Sopenharmony_ci * we have an ohare I/O controller. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci dn = of_find_node_by_name(NULL, "ohare"); 2238c2ecf20Sopenharmony_ci if (dn) { 2248c2ecf20Sopenharmony_ci of_node_put(dn); 2258c2ecf20Sopenharmony_ci if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) { 2268c2ecf20Sopenharmony_ci if (sysctrl_regs[4] & 0x10) 2278c2ecf20Sopenharmony_ci sysctrl_regs[4] |= 0x04000020; 2288c2ecf20Sopenharmony_ci else 2298c2ecf20Sopenharmony_ci sysctrl_regs[4] |= 0x04000000; 2308c2ecf20Sopenharmony_ci if(has_l2cache) 2318c2ecf20Sopenharmony_ci printk(KERN_INFO "Level 2 cache enabled\n"); 2328c2ecf20Sopenharmony_ci } 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_cistatic void __init l2cr_init(void) 2378c2ecf20Sopenharmony_ci{ 2388c2ecf20Sopenharmony_ci /* Checks "l2cr-value" property in the registry */ 2398c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_L2CR)) { 2408c2ecf20Sopenharmony_ci struct device_node *np; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci for_each_of_cpu_node(np) { 2438c2ecf20Sopenharmony_ci const unsigned int *l2cr = 2448c2ecf20Sopenharmony_ci of_get_property(np, "l2cr-value", NULL); 2458c2ecf20Sopenharmony_ci if (l2cr) { 2468c2ecf20Sopenharmony_ci ppc_override_l2cr = 1; 2478c2ecf20Sopenharmony_ci ppc_override_l2cr_value = *l2cr; 2488c2ecf20Sopenharmony_ci _set_L2CR(0); 2498c2ecf20Sopenharmony_ci _set_L2CR(ppc_override_l2cr_value); 2508c2ecf20Sopenharmony_ci } 2518c2ecf20Sopenharmony_ci of_node_put(np); 2528c2ecf20Sopenharmony_ci break; 2538c2ecf20Sopenharmony_ci } 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (ppc_override_l2cr) 2578c2ecf20Sopenharmony_ci printk(KERN_INFO "L2CR overridden (0x%x), " 2588c2ecf20Sopenharmony_ci "backside cache is %s\n", 2598c2ecf20Sopenharmony_ci ppc_override_l2cr_value, 2608c2ecf20Sopenharmony_ci (ppc_override_l2cr_value & 0x80000000) 2618c2ecf20Sopenharmony_ci ? "enabled" : "disabled"); 2628c2ecf20Sopenharmony_ci} 2638c2ecf20Sopenharmony_ci#endif 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic void __init pmac_setup_arch(void) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci struct device_node *cpu, *ic; 2688c2ecf20Sopenharmony_ci const int *fp; 2698c2ecf20Sopenharmony_ci unsigned long pvr; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci pvr = PVR_VER(mfspr(SPRN_PVR)); 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* Set loops_per_jiffy to a half-way reasonable value, 2748c2ecf20Sopenharmony_ci for use until calibrate_delay gets called. */ 2758c2ecf20Sopenharmony_ci loops_per_jiffy = 50000000 / HZ; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci for_each_of_cpu_node(cpu) { 2788c2ecf20Sopenharmony_ci fp = of_get_property(cpu, "clock-frequency", NULL); 2798c2ecf20Sopenharmony_ci if (fp != NULL) { 2808c2ecf20Sopenharmony_ci if (pvr >= 0x30 && pvr < 0x80) 2818c2ecf20Sopenharmony_ci /* PPC970 etc. */ 2828c2ecf20Sopenharmony_ci loops_per_jiffy = *fp / (3 * HZ); 2838c2ecf20Sopenharmony_ci else if (pvr == 4 || pvr >= 8) 2848c2ecf20Sopenharmony_ci /* 604, G3, G4 etc. */ 2858c2ecf20Sopenharmony_ci loops_per_jiffy = *fp / HZ; 2868c2ecf20Sopenharmony_ci else 2878c2ecf20Sopenharmony_ci /* 603, etc. */ 2888c2ecf20Sopenharmony_ci loops_per_jiffy = *fp / (2 * HZ); 2898c2ecf20Sopenharmony_ci of_node_put(cpu); 2908c2ecf20Sopenharmony_ci break; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci } 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* See if newworld or oldworld */ 2958c2ecf20Sopenharmony_ci ic = of_find_node_with_property(NULL, "interrupt-controller"); 2968c2ecf20Sopenharmony_ci if (ic) { 2978c2ecf20Sopenharmony_ci pmac_newworld = 1; 2988c2ecf20Sopenharmony_ci of_node_put(ic); 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci /* Lookup PCI hosts */ 3028c2ecf20Sopenharmony_ci pmac_pci_init(); 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 3058c2ecf20Sopenharmony_ci ohare_init(); 3068c2ecf20Sopenharmony_ci l2cr_init(); 3078c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC32 */ 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci find_via_cuda(); 3108c2ecf20Sopenharmony_ci find_via_pmu(); 3118c2ecf20Sopenharmony_ci smu_init(); 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci#if IS_ENABLED(CONFIG_NVRAM) 3148c2ecf20Sopenharmony_ci pmac_nvram_init(); 3158c2ecf20Sopenharmony_ci#endif 3168c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 3178c2ecf20Sopenharmony_ci#ifdef CONFIG_BLK_DEV_INITRD 3188c2ecf20Sopenharmony_ci if (initrd_start) 3198c2ecf20Sopenharmony_ci ROOT_DEV = Root_RAM0; 3208c2ecf20Sopenharmony_ci else 3218c2ecf20Sopenharmony_ci#endif 3228c2ecf20Sopenharmony_ci ROOT_DEV = DEFAULT_ROOT_DEVICE; 3238c2ecf20Sopenharmony_ci#endif 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci#ifdef CONFIG_ADB 3268c2ecf20Sopenharmony_ci if (strstr(boot_command_line, "adb_sync")) { 3278c2ecf20Sopenharmony_ci extern int __adb_probe_sync; 3288c2ecf20Sopenharmony_ci __adb_probe_sync = 1; 3298c2ecf20Sopenharmony_ci } 3308c2ecf20Sopenharmony_ci#endif /* CONFIG_ADB */ 3318c2ecf20Sopenharmony_ci} 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci#ifdef CONFIG_SCSI 3348c2ecf20Sopenharmony_civoid note_scsi_host(struct device_node *node, void *host) 3358c2ecf20Sopenharmony_ci{ 3368c2ecf20Sopenharmony_ci} 3378c2ecf20Sopenharmony_ciEXPORT_SYMBOL(note_scsi_host); 3388c2ecf20Sopenharmony_ci#endif 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic int initializing = 1; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_cistatic int pmac_late_init(void) 3438c2ecf20Sopenharmony_ci{ 3448c2ecf20Sopenharmony_ci initializing = 0; 3458c2ecf20Sopenharmony_ci return 0; 3468c2ecf20Sopenharmony_ci} 3478c2ecf20Sopenharmony_cimachine_late_initcall(powermac, pmac_late_init); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_civoid note_bootable_part(dev_t dev, int part, int goodness); 3508c2ecf20Sopenharmony_ci/* 3518c2ecf20Sopenharmony_ci * This is __ref because we check for "initializing" before 3528c2ecf20Sopenharmony_ci * touching any of the __init sensitive things and "initializing" 3538c2ecf20Sopenharmony_ci * will be false after __init time. This can't be __init because it 3548c2ecf20Sopenharmony_ci * can be called whenever a disk is first accessed. 3558c2ecf20Sopenharmony_ci */ 3568c2ecf20Sopenharmony_civoid __ref note_bootable_part(dev_t dev, int part, int goodness) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci char *p; 3598c2ecf20Sopenharmony_ci 3608c2ecf20Sopenharmony_ci if (!initializing) 3618c2ecf20Sopenharmony_ci return; 3628c2ecf20Sopenharmony_ci if ((goodness <= current_root_goodness) && 3638c2ecf20Sopenharmony_ci ROOT_DEV != DEFAULT_ROOT_DEVICE) 3648c2ecf20Sopenharmony_ci return; 3658c2ecf20Sopenharmony_ci p = strstr(boot_command_line, "root="); 3668c2ecf20Sopenharmony_ci if (p != NULL && (p == boot_command_line || p[-1] == ' ')) 3678c2ecf20Sopenharmony_ci return; 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci ROOT_DEV = dev + part; 3708c2ecf20Sopenharmony_ci current_root_goodness = goodness; 3718c2ecf20Sopenharmony_ci} 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci#ifdef CONFIG_ADB_CUDA 3748c2ecf20Sopenharmony_cistatic void __noreturn cuda_restart(void) 3758c2ecf20Sopenharmony_ci{ 3768c2ecf20Sopenharmony_ci struct adb_request req; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM); 3798c2ecf20Sopenharmony_ci for (;;) 3808c2ecf20Sopenharmony_ci cuda_poll(); 3818c2ecf20Sopenharmony_ci} 3828c2ecf20Sopenharmony_ci 3838c2ecf20Sopenharmony_cistatic void __noreturn cuda_shutdown(void) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci struct adb_request req; 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN); 3888c2ecf20Sopenharmony_ci for (;;) 3898c2ecf20Sopenharmony_ci cuda_poll(); 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci#else 3938c2ecf20Sopenharmony_ci#define cuda_restart() 3948c2ecf20Sopenharmony_ci#define cuda_shutdown() 3958c2ecf20Sopenharmony_ci#endif 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci#ifndef CONFIG_ADB_PMU 3988c2ecf20Sopenharmony_ci#define pmu_restart() 3998c2ecf20Sopenharmony_ci#define pmu_shutdown() 4008c2ecf20Sopenharmony_ci#endif 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci#ifndef CONFIG_PMAC_SMU 4038c2ecf20Sopenharmony_ci#define smu_restart() 4048c2ecf20Sopenharmony_ci#define smu_shutdown() 4058c2ecf20Sopenharmony_ci#endif 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_cistatic void __noreturn pmac_restart(char *cmd) 4088c2ecf20Sopenharmony_ci{ 4098c2ecf20Sopenharmony_ci switch (sys_ctrler) { 4108c2ecf20Sopenharmony_ci case SYS_CTRLER_CUDA: 4118c2ecf20Sopenharmony_ci cuda_restart(); 4128c2ecf20Sopenharmony_ci break; 4138c2ecf20Sopenharmony_ci case SYS_CTRLER_PMU: 4148c2ecf20Sopenharmony_ci pmu_restart(); 4158c2ecf20Sopenharmony_ci break; 4168c2ecf20Sopenharmony_ci case SYS_CTRLER_SMU: 4178c2ecf20Sopenharmony_ci smu_restart(); 4188c2ecf20Sopenharmony_ci break; 4198c2ecf20Sopenharmony_ci default: ; 4208c2ecf20Sopenharmony_ci } 4218c2ecf20Sopenharmony_ci while (1) ; 4228c2ecf20Sopenharmony_ci} 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_cistatic void __noreturn pmac_power_off(void) 4258c2ecf20Sopenharmony_ci{ 4268c2ecf20Sopenharmony_ci switch (sys_ctrler) { 4278c2ecf20Sopenharmony_ci case SYS_CTRLER_CUDA: 4288c2ecf20Sopenharmony_ci cuda_shutdown(); 4298c2ecf20Sopenharmony_ci break; 4308c2ecf20Sopenharmony_ci case SYS_CTRLER_PMU: 4318c2ecf20Sopenharmony_ci pmu_shutdown(); 4328c2ecf20Sopenharmony_ci break; 4338c2ecf20Sopenharmony_ci case SYS_CTRLER_SMU: 4348c2ecf20Sopenharmony_ci smu_shutdown(); 4358c2ecf20Sopenharmony_ci break; 4368c2ecf20Sopenharmony_ci default: ; 4378c2ecf20Sopenharmony_ci } 4388c2ecf20Sopenharmony_ci while (1) ; 4398c2ecf20Sopenharmony_ci} 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_cistatic void __noreturn 4428c2ecf20Sopenharmony_cipmac_halt(void) 4438c2ecf20Sopenharmony_ci{ 4448c2ecf20Sopenharmony_ci pmac_power_off(); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci/* 4488c2ecf20Sopenharmony_ci * Early initialization. 4498c2ecf20Sopenharmony_ci */ 4508c2ecf20Sopenharmony_cistatic void __init pmac_init(void) 4518c2ecf20Sopenharmony_ci{ 4528c2ecf20Sopenharmony_ci /* Enable early btext debug if requested */ 4538c2ecf20Sopenharmony_ci if (strstr(boot_command_line, "btextdbg")) { 4548c2ecf20Sopenharmony_ci udbg_adb_init_early(); 4558c2ecf20Sopenharmony_ci register_early_udbg_console(); 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci /* Probe motherboard chipset */ 4598c2ecf20Sopenharmony_ci pmac_feature_init(); 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci /* Initialize debug stuff */ 4628c2ecf20Sopenharmony_ci udbg_scc_init(!!strstr(boot_command_line, "sccdbg")); 4638c2ecf20Sopenharmony_ci udbg_adb_init(!!strstr(boot_command_line, "btextdbg")); 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 4668c2ecf20Sopenharmony_ci iommu_init_early_dart(&pmac_pci_controller_ops); 4678c2ecf20Sopenharmony_ci#endif 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* SMP Init has to be done early as we need to patch up 4708c2ecf20Sopenharmony_ci * cpu_possible_mask before interrupt stacks are allocated 4718c2ecf20Sopenharmony_ci * or kaboom... 4728c2ecf20Sopenharmony_ci */ 4738c2ecf20Sopenharmony_ci#ifdef CONFIG_SMP 4748c2ecf20Sopenharmony_ci pmac_setup_smp(); 4758c2ecf20Sopenharmony_ci#endif 4768c2ecf20Sopenharmony_ci} 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_cistatic int __init pmac_declare_of_platform_devices(void) 4798c2ecf20Sopenharmony_ci{ 4808c2ecf20Sopenharmony_ci struct device_node *np; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci np = of_find_node_by_name(NULL, "valkyrie"); 4838c2ecf20Sopenharmony_ci if (np) { 4848c2ecf20Sopenharmony_ci of_platform_device_create(np, "valkyrie", NULL); 4858c2ecf20Sopenharmony_ci of_node_put(np); 4868c2ecf20Sopenharmony_ci } 4878c2ecf20Sopenharmony_ci np = of_find_node_by_name(NULL, "platinum"); 4888c2ecf20Sopenharmony_ci if (np) { 4898c2ecf20Sopenharmony_ci of_platform_device_create(np, "platinum", NULL); 4908c2ecf20Sopenharmony_ci of_node_put(np); 4918c2ecf20Sopenharmony_ci } 4928c2ecf20Sopenharmony_ci np = of_find_node_by_type(NULL, "smu"); 4938c2ecf20Sopenharmony_ci if (np) { 4948c2ecf20Sopenharmony_ci of_platform_device_create(np, "smu", NULL); 4958c2ecf20Sopenharmony_ci of_node_put(np); 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci np = of_find_node_by_type(NULL, "fcu"); 4988c2ecf20Sopenharmony_ci if (np == NULL) { 4998c2ecf20Sopenharmony_ci /* Some machines have strangely broken device-tree */ 5008c2ecf20Sopenharmony_ci np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e"); 5018c2ecf20Sopenharmony_ci } 5028c2ecf20Sopenharmony_ci if (np) { 5038c2ecf20Sopenharmony_ci of_platform_device_create(np, "temperature", NULL); 5048c2ecf20Sopenharmony_ci of_node_put(np); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci} 5098c2ecf20Sopenharmony_cimachine_device_initcall(powermac, pmac_declare_of_platform_devices); 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE 5128c2ecf20Sopenharmony_ci/* 5138c2ecf20Sopenharmony_ci * This is called very early, as part of console_init() (typically just after 5148c2ecf20Sopenharmony_ci * time_init()). This function is respondible for trying to find a good 5158c2ecf20Sopenharmony_ci * default console on serial ports. It tries to match the open firmware 5168c2ecf20Sopenharmony_ci * default output with one of the available serial console drivers. 5178c2ecf20Sopenharmony_ci */ 5188c2ecf20Sopenharmony_cistatic int __init check_pmac_serial_console(void) 5198c2ecf20Sopenharmony_ci{ 5208c2ecf20Sopenharmony_ci struct device_node *prom_stdout = NULL; 5218c2ecf20Sopenharmony_ci int offset = 0; 5228c2ecf20Sopenharmony_ci const char *name; 5238c2ecf20Sopenharmony_ci#ifdef CONFIG_SERIAL_PMACZILOG_TTYS 5248c2ecf20Sopenharmony_ci char *devname = "ttyS"; 5258c2ecf20Sopenharmony_ci#else 5268c2ecf20Sopenharmony_ci char *devname = "ttyPZ"; 5278c2ecf20Sopenharmony_ci#endif 5288c2ecf20Sopenharmony_ci 5298c2ecf20Sopenharmony_ci pr_debug(" -> check_pmac_serial_console()\n"); 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci /* The user has requested a console so this is already set up. */ 5328c2ecf20Sopenharmony_ci if (strstr(boot_command_line, "console=")) { 5338c2ecf20Sopenharmony_ci pr_debug(" console was specified !\n"); 5348c2ecf20Sopenharmony_ci return -EBUSY; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci if (!of_chosen) { 5388c2ecf20Sopenharmony_ci pr_debug(" of_chosen is NULL !\n"); 5398c2ecf20Sopenharmony_ci return -ENODEV; 5408c2ecf20Sopenharmony_ci } 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci /* We are getting a weird phandle from OF ... */ 5438c2ecf20Sopenharmony_ci /* ... So use the full path instead */ 5448c2ecf20Sopenharmony_ci name = of_get_property(of_chosen, "linux,stdout-path", NULL); 5458c2ecf20Sopenharmony_ci if (name == NULL) { 5468c2ecf20Sopenharmony_ci pr_debug(" no linux,stdout-path !\n"); 5478c2ecf20Sopenharmony_ci return -ENODEV; 5488c2ecf20Sopenharmony_ci } 5498c2ecf20Sopenharmony_ci prom_stdout = of_find_node_by_path(name); 5508c2ecf20Sopenharmony_ci if (!prom_stdout) { 5518c2ecf20Sopenharmony_ci pr_debug(" can't find stdout package %s !\n", name); 5528c2ecf20Sopenharmony_ci return -ENODEV; 5538c2ecf20Sopenharmony_ci } 5548c2ecf20Sopenharmony_ci pr_debug("stdout is %pOF\n", prom_stdout); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci if (of_node_name_eq(prom_stdout, "ch-a")) 5578c2ecf20Sopenharmony_ci offset = 0; 5588c2ecf20Sopenharmony_ci else if (of_node_name_eq(prom_stdout, "ch-b")) 5598c2ecf20Sopenharmony_ci offset = 1; 5608c2ecf20Sopenharmony_ci else 5618c2ecf20Sopenharmony_ci goto not_found; 5628c2ecf20Sopenharmony_ci of_node_put(prom_stdout); 5638c2ecf20Sopenharmony_ci 5648c2ecf20Sopenharmony_ci pr_debug("Found serial console at %s%d\n", devname, offset); 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci return add_preferred_console(devname, offset, NULL); 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci not_found: 5698c2ecf20Sopenharmony_ci pr_debug("No preferred console found !\n"); 5708c2ecf20Sopenharmony_ci of_node_put(prom_stdout); 5718c2ecf20Sopenharmony_ci return -ENODEV; 5728c2ecf20Sopenharmony_ci} 5738c2ecf20Sopenharmony_ciconsole_initcall(check_pmac_serial_console); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */ 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci/* 5788c2ecf20Sopenharmony_ci * Called very early, MMU is off, device-tree isn't unflattened 5798c2ecf20Sopenharmony_ci */ 5808c2ecf20Sopenharmony_cistatic int __init pmac_probe(void) 5818c2ecf20Sopenharmony_ci{ 5828c2ecf20Sopenharmony_ci if (!of_machine_is_compatible("Power Macintosh") && 5838c2ecf20Sopenharmony_ci !of_machine_is_compatible("MacRISC")) 5848c2ecf20Sopenharmony_ci return 0; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 5878c2ecf20Sopenharmony_ci /* isa_io_base gets set in pmac_pci_init */ 5888c2ecf20Sopenharmony_ci DMA_MODE_READ = 1; 5898c2ecf20Sopenharmony_ci DMA_MODE_WRITE = 2; 5908c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC32 */ 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci pm_power_off = pmac_power_off; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci pmac_init(); 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci return 1; 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_cidefine_machine(powermac) { 6008c2ecf20Sopenharmony_ci .name = "PowerMac", 6018c2ecf20Sopenharmony_ci .probe = pmac_probe, 6028c2ecf20Sopenharmony_ci .setup_arch = pmac_setup_arch, 6038c2ecf20Sopenharmony_ci .show_cpuinfo = pmac_show_cpuinfo, 6048c2ecf20Sopenharmony_ci .init_IRQ = pmac_pic_init, 6058c2ecf20Sopenharmony_ci .get_irq = NULL, /* changed later */ 6068c2ecf20Sopenharmony_ci .pci_irq_fixup = pmac_pci_irq_fixup, 6078c2ecf20Sopenharmony_ci .restart = pmac_restart, 6088c2ecf20Sopenharmony_ci .halt = pmac_halt, 6098c2ecf20Sopenharmony_ci .time_init = pmac_time_init, 6108c2ecf20Sopenharmony_ci .get_boot_time = pmac_get_boot_time, 6118c2ecf20Sopenharmony_ci .set_rtc_time = pmac_set_rtc_time, 6128c2ecf20Sopenharmony_ci .get_rtc_time = pmac_get_rtc_time, 6138c2ecf20Sopenharmony_ci .calibrate_decr = pmac_calibrate_decr, 6148c2ecf20Sopenharmony_ci .feature_call = pmac_do_feature_call, 6158c2ecf20Sopenharmony_ci .progress = udbg_progress, 6168c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC64 6178c2ecf20Sopenharmony_ci .power_save = power4_idle, 6188c2ecf20Sopenharmony_ci .enable_pmcs = power4_enable_pmcs, 6198c2ecf20Sopenharmony_ci#endif /* CONFIG_PPC64 */ 6208c2ecf20Sopenharmony_ci#ifdef CONFIG_PPC32 6218c2ecf20Sopenharmony_ci .pcibios_after_init = pmac_pcibios_after_init, 6228c2ecf20Sopenharmony_ci .phys_mem_access_prot = pci_phys_mem_access_prot, 6238c2ecf20Sopenharmony_ci#endif 6248c2ecf20Sopenharmony_ci}; 625