Path: blob/master/arch/powerpc/platforms/powermac/setup.c
10818 views
/*1* Powermac setup and early boot code plus other random bits.2*3* PowerPC version4* Copyright (C) 1995-1996 Gary Thomas ([email protected])5*6* Adapted for Power Macintosh by Paul Mackerras7* Copyright (C) 1996 Paul Mackerras ([email protected])8*9* Derived from "arch/alpha/kernel/setup.c"10* Copyright (C) 1995 Linus Torvalds11*12* Maintained by Benjamin Herrenschmidt ([email protected])13*14* This program is free software; you can redistribute it and/or15* modify it under the terms of the GNU General Public License16* as published by the Free Software Foundation; either version17* 2 of the License, or (at your option) any later version.18*19*/2021/*22* bootup setup stuff..23*/2425#include <linux/init.h>26#include <linux/errno.h>27#include <linux/sched.h>28#include <linux/kernel.h>29#include <linux/mm.h>30#include <linux/stddef.h>31#include <linux/unistd.h>32#include <linux/ptrace.h>33#include <linux/user.h>34#include <linux/tty.h>35#include <linux/string.h>36#include <linux/delay.h>37#include <linux/ioport.h>38#include <linux/major.h>39#include <linux/initrd.h>40#include <linux/vt_kern.h>41#include <linux/console.h>42#include <linux/pci.h>43#include <linux/adb.h>44#include <linux/cuda.h>45#include <linux/pmu.h>46#include <linux/irq.h>47#include <linux/seq_file.h>48#include <linux/root_dev.h>49#include <linux/bitops.h>50#include <linux/suspend.h>51#include <linux/of_device.h>52#include <linux/of_platform.h>53#include <linux/memblock.h>5455#include <asm/reg.h>56#include <asm/sections.h>57#include <asm/prom.h>58#include <asm/system.h>59#include <asm/pgtable.h>60#include <asm/io.h>61#include <asm/pci-bridge.h>62#include <asm/ohare.h>63#include <asm/mediabay.h>64#include <asm/machdep.h>65#include <asm/dma.h>66#include <asm/cputable.h>67#include <asm/btext.h>68#include <asm/pmac_feature.h>69#include <asm/time.h>70#include <asm/mmu_context.h>71#include <asm/iommu.h>72#include <asm/smu.h>73#include <asm/pmc.h>74#include <asm/udbg.h>7576#include "pmac.h"7778#undef SHOW_GATWICK_IRQS7980int ppc_override_l2cr = 0;81int ppc_override_l2cr_value;82int has_l2cache = 0;8384int pmac_newworld;8586static int current_root_goodness = -1;8788extern struct machdep_calls pmac_md;8990#define DEFAULT_ROOT_DEVICE Root_SDA1 /* sda1 - slightly silly choice */9192#ifdef CONFIG_PPC6493int sccdbg;94#endif9596sys_ctrler_t sys_ctrler = SYS_CTRLER_UNKNOWN;97EXPORT_SYMBOL(sys_ctrler);9899#ifdef CONFIG_PMAC_SMU100unsigned long smu_cmdbuf_abs;101EXPORT_SYMBOL(smu_cmdbuf_abs);102#endif103104static void pmac_show_cpuinfo(struct seq_file *m)105{106struct device_node *np;107const char *pp;108int plen;109int mbmodel;110unsigned int mbflags;111char* mbname;112113mbmodel = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL,114PMAC_MB_INFO_MODEL, 0);115mbflags = pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL,116PMAC_MB_INFO_FLAGS, 0);117if (pmac_call_feature(PMAC_FTR_GET_MB_INFO, NULL, PMAC_MB_INFO_NAME,118(long) &mbname) != 0)119mbname = "Unknown";120121/* find motherboard type */122seq_printf(m, "machine\t\t: ");123np = of_find_node_by_path("/");124if (np != NULL) {125pp = of_get_property(np, "model", NULL);126if (pp != NULL)127seq_printf(m, "%s\n", pp);128else129seq_printf(m, "PowerMac\n");130pp = of_get_property(np, "compatible", &plen);131if (pp != NULL) {132seq_printf(m, "motherboard\t:");133while (plen > 0) {134int l = strlen(pp) + 1;135seq_printf(m, " %s", pp);136plen -= l;137pp += l;138}139seq_printf(m, "\n");140}141of_node_put(np);142} else143seq_printf(m, "PowerMac\n");144145/* print parsed model */146seq_printf(m, "detected as\t: %d (%s)\n", mbmodel, mbname);147seq_printf(m, "pmac flags\t: %08x\n", mbflags);148149/* find l2 cache info */150np = of_find_node_by_name(NULL, "l2-cache");151if (np == NULL)152np = of_find_node_by_type(NULL, "cache");153if (np != NULL) {154const unsigned int *ic =155of_get_property(np, "i-cache-size", NULL);156const unsigned int *dc =157of_get_property(np, "d-cache-size", NULL);158seq_printf(m, "L2 cache\t:");159has_l2cache = 1;160if (of_get_property(np, "cache-unified", NULL) != 0 && dc) {161seq_printf(m, " %dK unified", *dc / 1024);162} else {163if (ic)164seq_printf(m, " %dK instruction", *ic / 1024);165if (dc)166seq_printf(m, "%s %dK data",167(ic? " +": ""), *dc / 1024);168}169pp = of_get_property(np, "ram-type", NULL);170if (pp)171seq_printf(m, " %s", pp);172seq_printf(m, "\n");173of_node_put(np);174}175176/* Indicate newworld/oldworld */177seq_printf(m, "pmac-generation\t: %s\n",178pmac_newworld ? "NewWorld" : "OldWorld");179}180181#ifndef CONFIG_ADB_CUDA182int find_via_cuda(void)183{184struct device_node *dn = of_find_node_by_name(NULL, "via-cuda");185186if (!dn)187return 0;188of_node_put(dn);189printk("WARNING ! Your machine is CUDA-based but your kernel\n");190printk(" wasn't compiled with CONFIG_ADB_CUDA option !\n");191return 0;192}193#endif194195#ifndef CONFIG_ADB_PMU196int find_via_pmu(void)197{198struct device_node *dn = of_find_node_by_name(NULL, "via-pmu");199200if (!dn)201return 0;202of_node_put(dn);203printk("WARNING ! Your machine is PMU-based but your kernel\n");204printk(" wasn't compiled with CONFIG_ADB_PMU option !\n");205return 0;206}207#endif208209#ifndef CONFIG_PMAC_SMU210int smu_init(void)211{212/* should check and warn if SMU is present */213return 0;214}215#endif216217#ifdef CONFIG_PPC32218static volatile u32 *sysctrl_regs;219220static void __init ohare_init(void)221{222struct device_node *dn;223224/* this area has the CPU identification register225and some registers used by smp boards */226sysctrl_regs = (volatile u32 *) ioremap(0xf8000000, 0x1000);227228/*229* Turn on the L2 cache.230* We assume that we have a PSX memory controller iff231* we have an ohare I/O controller.232*/233dn = of_find_node_by_name(NULL, "ohare");234if (dn) {235of_node_put(dn);236if (((sysctrl_regs[2] >> 24) & 0xf) >= 3) {237if (sysctrl_regs[4] & 0x10)238sysctrl_regs[4] |= 0x04000020;239else240sysctrl_regs[4] |= 0x04000000;241if(has_l2cache)242printk(KERN_INFO "Level 2 cache enabled\n");243}244}245}246247static void __init l2cr_init(void)248{249/* Checks "l2cr-value" property in the registry */250if (cpu_has_feature(CPU_FTR_L2CR)) {251struct device_node *np = of_find_node_by_name(NULL, "cpus");252if (np == 0)253np = of_find_node_by_type(NULL, "cpu");254if (np != 0) {255const unsigned int *l2cr =256of_get_property(np, "l2cr-value", NULL);257if (l2cr != 0) {258ppc_override_l2cr = 1;259ppc_override_l2cr_value = *l2cr;260_set_L2CR(0);261_set_L2CR(ppc_override_l2cr_value);262}263of_node_put(np);264}265}266267if (ppc_override_l2cr)268printk(KERN_INFO "L2CR overridden (0x%x), "269"backside cache is %s\n",270ppc_override_l2cr_value,271(ppc_override_l2cr_value & 0x80000000)272? "enabled" : "disabled");273}274#endif275276static void __init pmac_setup_arch(void)277{278struct device_node *cpu, *ic;279const int *fp;280unsigned long pvr;281282pvr = PVR_VER(mfspr(SPRN_PVR));283284/* Set loops_per_jiffy to a half-way reasonable value,285for use until calibrate_delay gets called. */286loops_per_jiffy = 50000000 / HZ;287cpu = of_find_node_by_type(NULL, "cpu");288if (cpu != NULL) {289fp = of_get_property(cpu, "clock-frequency", NULL);290if (fp != NULL) {291if (pvr >= 0x30 && pvr < 0x80)292/* PPC970 etc. */293loops_per_jiffy = *fp / (3 * HZ);294else if (pvr == 4 || pvr >= 8)295/* 604, G3, G4 etc. */296loops_per_jiffy = *fp / HZ;297else298/* 601, 603, etc. */299loops_per_jiffy = *fp / (2 * HZ);300}301of_node_put(cpu);302}303304/* See if newworld or oldworld */305ic = of_find_node_with_property(NULL, "interrupt-controller");306if (ic) {307pmac_newworld = 1;308of_node_put(ic);309}310311/* Lookup PCI hosts */312pmac_pci_init();313314#ifdef CONFIG_PPC32315ohare_init();316l2cr_init();317#endif /* CONFIG_PPC32 */318319find_via_cuda();320find_via_pmu();321smu_init();322323#if defined(CONFIG_NVRAM) || defined(CONFIG_NVRAM_MODULE) || \324defined(CONFIG_PPC64)325pmac_nvram_init();326#endif327328#ifdef CONFIG_PPC32329#ifdef CONFIG_BLK_DEV_INITRD330if (initrd_start)331ROOT_DEV = Root_RAM0;332else333#endif334ROOT_DEV = DEFAULT_ROOT_DEVICE;335#endif336337#ifdef CONFIG_ADB338if (strstr(cmd_line, "adb_sync")) {339extern int __adb_probe_sync;340__adb_probe_sync = 1;341}342#endif /* CONFIG_ADB */343}344345#ifdef CONFIG_SCSI346void note_scsi_host(struct device_node *node, void *host)347{348}349EXPORT_SYMBOL(note_scsi_host);350#endif351352static int initializing = 1;353354static int pmac_late_init(void)355{356initializing = 0;357/* this is udbg (which is __init) and we can later use it during358* cpu hotplug (in smp_core99_kick_cpu) */359ppc_md.progress = NULL;360return 0;361}362machine_late_initcall(powermac, pmac_late_init);363364/*365* This is __init_refok because we check for "initializing" before366* touching any of the __init sensitive things and "initializing"367* will be false after __init time. This can't be __init because it368* can be called whenever a disk is first accessed.369*/370void __init_refok note_bootable_part(dev_t dev, int part, int goodness)371{372char *p;373374if (!initializing)375return;376if ((goodness <= current_root_goodness) &&377ROOT_DEV != DEFAULT_ROOT_DEVICE)378return;379p = strstr(boot_command_line, "root=");380if (p != NULL && (p == boot_command_line || p[-1] == ' '))381return;382383ROOT_DEV = dev + part;384current_root_goodness = goodness;385}386387#ifdef CONFIG_ADB_CUDA388static void cuda_restart(void)389{390struct adb_request req;391392cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_RESET_SYSTEM);393for (;;)394cuda_poll();395}396397static void cuda_shutdown(void)398{399struct adb_request req;400401cuda_request(&req, NULL, 2, CUDA_PACKET, CUDA_POWERDOWN);402for (;;)403cuda_poll();404}405406#else407#define cuda_restart()408#define cuda_shutdown()409#endif410411#ifndef CONFIG_ADB_PMU412#define pmu_restart()413#define pmu_shutdown()414#endif415416#ifndef CONFIG_PMAC_SMU417#define smu_restart()418#define smu_shutdown()419#endif420421static void pmac_restart(char *cmd)422{423switch (sys_ctrler) {424case SYS_CTRLER_CUDA:425cuda_restart();426break;427case SYS_CTRLER_PMU:428pmu_restart();429break;430case SYS_CTRLER_SMU:431smu_restart();432break;433default: ;434}435}436437static void pmac_power_off(void)438{439switch (sys_ctrler) {440case SYS_CTRLER_CUDA:441cuda_shutdown();442break;443case SYS_CTRLER_PMU:444pmu_shutdown();445break;446case SYS_CTRLER_SMU:447smu_shutdown();448break;449default: ;450}451}452453static void454pmac_halt(void)455{456pmac_power_off();457}458459/*460* Early initialization.461*/462static void __init pmac_init_early(void)463{464/* Enable early btext debug if requested */465if (strstr(cmd_line, "btextdbg")) {466udbg_adb_init_early();467register_early_udbg_console();468}469470/* Probe motherboard chipset */471pmac_feature_init();472473/* Initialize debug stuff */474udbg_scc_init(!!strstr(cmd_line, "sccdbg"));475udbg_adb_init(!!strstr(cmd_line, "btextdbg"));476477#ifdef CONFIG_PPC64478iommu_init_early_dart();479#endif480481/* SMP Init has to be done early as we need to patch up482* cpu_possible_mask before interrupt stacks are allocated483* or kaboom...484*/485#ifdef CONFIG_SMP486pmac_setup_smp();487#endif488}489490static int __init pmac_declare_of_platform_devices(void)491{492struct device_node *np;493494if (machine_is(chrp))495return -1;496497np = of_find_node_by_name(NULL, "valkyrie");498if (np)499of_platform_device_create(np, "valkyrie", NULL);500np = of_find_node_by_name(NULL, "platinum");501if (np)502of_platform_device_create(np, "platinum", NULL);503np = of_find_node_by_type(NULL, "smu");504if (np) {505of_platform_device_create(np, "smu", NULL);506of_node_put(np);507}508np = of_find_node_by_type(NULL, "fcu");509if (np == NULL) {510/* Some machines have strangely broken device-tree */511np = of_find_node_by_path("/u3@0,f8000000/i2c@f8001000/fan@15e");512}513if (np) {514of_platform_device_create(np, "temperature", NULL);515of_node_put(np);516}517518return 0;519}520machine_device_initcall(powermac, pmac_declare_of_platform_devices);521522#ifdef CONFIG_SERIAL_PMACZILOG_CONSOLE523/*524* This is called very early, as part of console_init() (typically just after525* time_init()). This function is respondible for trying to find a good526* default console on serial ports. It tries to match the open firmware527* default output with one of the available serial console drivers.528*/529static int __init check_pmac_serial_console(void)530{531struct device_node *prom_stdout = NULL;532int offset = 0;533const char *name;534#ifdef CONFIG_SERIAL_PMACZILOG_TTYS535char *devname = "ttyS";536#else537char *devname = "ttyPZ";538#endif539540pr_debug(" -> check_pmac_serial_console()\n");541542/* The user has requested a console so this is already set up. */543if (strstr(boot_command_line, "console=")) {544pr_debug(" console was specified !\n");545return -EBUSY;546}547548if (!of_chosen) {549pr_debug(" of_chosen is NULL !\n");550return -ENODEV;551}552553/* We are getting a weird phandle from OF ... */554/* ... So use the full path instead */555name = of_get_property(of_chosen, "linux,stdout-path", NULL);556if (name == NULL) {557pr_debug(" no linux,stdout-path !\n");558return -ENODEV;559}560prom_stdout = of_find_node_by_path(name);561if (!prom_stdout) {562pr_debug(" can't find stdout package %s !\n", name);563return -ENODEV;564}565pr_debug("stdout is %s\n", prom_stdout->full_name);566567name = of_get_property(prom_stdout, "name", NULL);568if (!name) {569pr_debug(" stdout package has no name !\n");570goto not_found;571}572573if (strcmp(name, "ch-a") == 0)574offset = 0;575else if (strcmp(name, "ch-b") == 0)576offset = 1;577else578goto not_found;579of_node_put(prom_stdout);580581pr_debug("Found serial console at %s%d\n", devname, offset);582583return add_preferred_console(devname, offset, NULL);584585not_found:586pr_debug("No preferred console found !\n");587of_node_put(prom_stdout);588return -ENODEV;589}590console_initcall(check_pmac_serial_console);591592#endif /* CONFIG_SERIAL_PMACZILOG_CONSOLE */593594/*595* Called very early, MMU is off, device-tree isn't unflattened596*/597static int __init pmac_probe(void)598{599unsigned long root = of_get_flat_dt_root();600601if (!of_flat_dt_is_compatible(root, "Power Macintosh") &&602!of_flat_dt_is_compatible(root, "MacRISC"))603return 0;604605#ifdef CONFIG_PPC64606/*607* On U3, the DART (iommu) must be allocated now since it608* has an impact on htab_initialize (due to the large page it609* occupies having to be broken up so the DART itself is not610* part of the cacheable linar mapping611*/612alloc_dart_table();613614hpte_init_native();615#endif616617#ifdef CONFIG_PPC32618/* isa_io_base gets set in pmac_pci_init */619ISA_DMA_THRESHOLD = ~0L;620DMA_MODE_READ = 1;621DMA_MODE_WRITE = 2;622#endif /* CONFIG_PPC32 */623624#ifdef CONFIG_PMAC_SMU625/*626* SMU based G5s need some memory below 2Gb, at least the current627* driver needs that. We have to allocate it now. We allocate 4k628* (1 small page) for now.629*/630smu_cmdbuf_abs = memblock_alloc_base(4096, 4096, 0x80000000UL);631#endif /* CONFIG_PMAC_SMU */632633return 1;634}635636#ifdef CONFIG_PPC64637/* Move that to pci.c */638static int pmac_pci_probe_mode(struct pci_bus *bus)639{640struct device_node *node = pci_bus_to_OF_node(bus);641642/* We need to use normal PCI probing for the AGP bus,643* since the device for the AGP bridge isn't in the tree.644* Same for the PCIe host on U4 and the HT host bridge.645*/646if (bus->self == NULL && (of_device_is_compatible(node, "u3-agp") ||647of_device_is_compatible(node, "u4-pcie") ||648of_device_is_compatible(node, "u3-ht")))649return PCI_PROBE_NORMAL;650return PCI_PROBE_DEVTREE;651}652#endif /* CONFIG_PPC64 */653654define_machine(powermac) {655.name = "PowerMac",656.probe = pmac_probe,657.setup_arch = pmac_setup_arch,658.init_early = pmac_init_early,659.show_cpuinfo = pmac_show_cpuinfo,660.init_IRQ = pmac_pic_init,661.get_irq = NULL, /* changed later */662.pci_irq_fixup = pmac_pci_irq_fixup,663.restart = pmac_restart,664.power_off = pmac_power_off,665.halt = pmac_halt,666.time_init = pmac_time_init,667.get_boot_time = pmac_get_boot_time,668.set_rtc_time = pmac_set_rtc_time,669.get_rtc_time = pmac_get_rtc_time,670.calibrate_decr = pmac_calibrate_decr,671.feature_call = pmac_do_feature_call,672.progress = udbg_progress,673#ifdef CONFIG_PPC64674.pci_probe_mode = pmac_pci_probe_mode,675.power_save = power4_idle,676.enable_pmcs = power4_enable_pmcs,677#endif /* CONFIG_PPC64 */678#ifdef CONFIG_PPC32679.pcibios_enable_device_hook = pmac_pci_enable_device_hook,680.pcibios_after_init = pmac_pcibios_after_init,681.phys_mem_access_prot = pci_phys_mem_access_prot,682#endif683};684685686