/* * Efika 5K2 platform code * Some code really inspired from the lite5200b platform. * * Copyright (C) 2006 bplan GmbH * * This file is licensed under the terms of the GNU General Public License * version 2. This program is licensed "as is" without any warranty of any * kind, whether express or implied. */ #include <linux/init.h> #include <generated/utsrelease.h> #include <linux/pci.h> #include <linux/of.h> #include <asm/dma.h> #include <asm/time.h> #include <asm/machdep.h> #include <asm/rtas.h> #include <asm/mpc52xx.h> #define EFIKA_PLATFORM_NAME "Efika" /* ------------------------------------------------------------------------ */ /* PCI accesses thru RTAS */ /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PCI /* * Access functions for PCI config space using RTAS calls. */ static int rtas_read_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 * val) { struct pci_controller *hose = pci_bus_to_host(bus); unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | (((bus->number - hose->first_busno) & 0xff) << 16) | (hose->global_number << 24); int ret = -1; int rval; rval = rtas_call(rtas_function_token(RTAS_FN_READ_PCI_CONFIG), 2, 2, &ret, addr, len); *val = ret; return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; } static int rtas_write_config(struct pci_bus *bus, unsigned int devfn, int offset, int len, u32 val) { struct pci_controller *hose = pci_bus_to_host(bus); unsigned long addr = (offset & 0xff) | ((devfn & 0xff) << 8) | (((bus->number - hose->first_busno) & 0xff) << 16) | (hose->global_number << 24); int rval; rval = rtas_call(rtas_function_token(RTAS_FN_WRITE_PCI_CONFIG), 3, 1, NULL, addr, len, val); return rval ? PCIBIOS_DEVICE_NOT_FOUND : PCIBIOS_SUCCESSFUL; } static struct pci_ops rtas_pci_ops = { .read = rtas_read_config, .write = rtas_write_config, }; static void __init efika_pcisetup(void) { const int *bus_range; int len; struct pci_controller *hose; struct device_node *root; struct device_node *pcictrl; root = of_find_node_by_path("/"); if (root == NULL) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Unable to find the root node\n"); return; } for_each_child_of_node(root, pcictrl) if (of_node_name_eq(pcictrl, "pci")) break; of_node_put(root); if (pcictrl == NULL) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Unable to find the PCI bridge node\n"); return; } bus_range = of_get_property(pcictrl, "bus-range", &len); if (bus_range == NULL || len < 2 * sizeof(int)) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't get bus-range for %pOF\n", pcictrl); goto out_put; } if (bus_range[1] == bus_range[0]) printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI bus %d", bus_range[0]); else printk(KERN_INFO EFIKA_PLATFORM_NAME ": PCI buses %d..%d", bus_range[0], bus_range[1]); printk(" controlled by %pOF\n", pcictrl); printk("\n"); hose = pcibios_alloc_controller(pcictrl); if (!hose) { printk(KERN_WARNING EFIKA_PLATFORM_NAME ": Can't allocate PCI controller structure for %pOF\n", pcictrl); goto out_put; } hose->first_busno = bus_range[0]; hose->last_busno = bus_range[1]; hose->ops = &rtas_pci_ops; pci_process_bridge_OF_ranges(hose, pcictrl, 0); return; out_put: of_node_put(pcictrl); } #else static void __init efika_pcisetup(void) {} #endif /* ------------------------------------------------------------------------ */ /* Platform setup */ /* ------------------------------------------------------------------------ */ static void efika_show_cpuinfo(struct seq_file *m) { struct device_node *root; const char *revision; const char *codegendescription; const char *codegenvendor; root = of_find_node_by_path("/"); if (!root) return; revision = of_get_property(root, "revision", NULL); codegendescription = of_get_property(root, "CODEGEN,description", NULL); codegenvendor = of_get_property(root, "CODEGEN,vendor", NULL); if (codegendescription) seq_printf(m, "machine\t\t: %s\n", codegendescription); else seq_printf(m, "machine\t\t: Efika\n"); if (revision) seq_printf(m, "revision\t: %s\n", revision); if (codegenvendor) seq_printf(m, "vendor\t\t: %s\n", codegenvendor); of_node_put(root); } #ifdef CONFIG_PM static void efika_suspend_prepare(void __iomem *mbar) { u8 pin = 4; /* GPIO_WKUP_4 (GPIO_PSC6_0 - IRDA_RX) */ u8 level = 1; /* wakeup on high level */ /* IOW. to wake it up, short pins 1 and 3 on IRDA connector */ mpc52xx_set_wakeup_gpio(pin, level); } #endif static void __init efika_setup_arch(void) { rtas_initialize(); /* Map important registers from the internal memory map */ mpc52xx_map_common_devices(); #ifdef CONFIG_PM mpc52xx_suspend.board_suspend_prepare = efika_suspend_prepare; mpc52xx_pm_init(); #endif if (ppc_md.progress) ppc_md.progress("Linux/PPC " UTS_RELEASE " running on Efika ;-)\n", 0x0); } static int __init efika_probe(void) { const char *model = of_get_property(of_root, "model", NULL); if (model == NULL) return 0; if (strcmp(model, "EFIKA5K2")) return 0; DMA_MODE_READ = 0x44; DMA_MODE_WRITE = 0x48; pm_power_off = rtas_power_off; return 1; } define_machine(efika) { .name = EFIKA_PLATFORM_NAME, .probe = efika_probe, .setup_arch = efika_setup_arch, .discover_phbs = efika_pcisetup, .init = mpc52xx_declare_of_platform_devices, .show_cpuinfo = efika_show_cpuinfo, .init_IRQ = mpc52xx_init_irq, .get_irq = mpc52xx_get_irq, .restart = rtas_restart, .halt = rtas_halt, .set_rtc_time = rtas_set_rtc_time, .get_rtc_time = rtas_get_rtc_time, .progress = rtas_progress, .get_boot_time = rtas_get_boot_time, #ifdef CONFIG_PCI .phys_mem_access_prot = pci_phys_mem_access_prot, #endif };