Fixed MTP to work with TWRP

This commit is contained in:
awab228 2018-06-19 23:16:04 +02:00
commit f6dfaef42e
50820 changed files with 20846062 additions and 0 deletions

View file

@ -0,0 +1,118 @@
config EMBEDDED6xx
bool "Embedded 6xx/7xx/7xxx-based boards"
depends on 6xx && BROKEN_ON_SMP
config LINKSTATION
bool "Linkstation / Kurobox(HG) from Buffalo"
depends on EMBEDDED6xx
select MPIC
select FSL_SOC
select PPC_UDBG_16550 if SERIAL_8250
select DEFAULT_UIMAGE
select MPC10X_BRIDGE
help
Select LINKSTATION if configuring for one of PPC- (MPC8241)
based NAS systems from Buffalo Technology. So far only
KuroboxHG has been tested. In the future classical Kurobox,
Linkstation-I HD-HLAN and HD-HGLAN versions, and PPC-based
Terastation systems should be supported too.
config STORCENTER
bool "IOMEGA StorCenter"
depends on EMBEDDED6xx
select MPIC
select FSL_SOC
select PPC_UDBG_16550 if SERIAL_8250
select MPC10X_BRIDGE
help
Select STORCENTER if configuring for the iomega StorCenter
with an 8241 CPU in it.
config MPC7448HPC2
bool "Freescale MPC7448HPC2(Taiga)"
depends on EMBEDDED6xx
select TSI108_BRIDGE
select DEFAULT_UIMAGE
select PPC_UDBG_16550
help
Select MPC7448HPC2 if configuring for Freescale MPC7448HPC2 (Taiga)
platform
config PPC_HOLLY
bool "PPC750GX/CL with TSI10x bridge (Hickory/Holly)"
depends on EMBEDDED6xx
select TSI108_BRIDGE
select PPC_UDBG_16550
help
Select PPC_HOLLY if configuring for an IBM 750GX/CL Eval
Board with TSI108/9 bridge (Hickory/Holly)
config PPC_C2K
bool "SBS/GEFanuc C2K board"
depends on EMBEDDED6xx
select MV64X60
select NOT_COHERENT_CACHE
select MTD_CFI_I4
help
This option enables support for the GE Fanuc C2K board (formerly
an SBS board).
config MVME5100
bool "Motorola/Emerson MVME5100"
depends on EMBEDDED6xx
select MPIC
select PCI
select PPC_INDIRECT_PCI
select PPC_I8259
select PPC_NATIVE
select PPC_UDBG_16550
help
This option enables support for the Motorola (now Emerson) MVME5100
board.
config TSI108_BRIDGE
bool
select PCI
select MPIC
select MPIC_WEIRD
config MPC10X_BRIDGE
bool
select PPC_INDIRECT_PCI
config MV64X60
bool
select PPC_INDIRECT_PCI
select CHECK_CACHE_COHERENCY
config GAMECUBE_COMMON
bool
config USBGECKO_UDBG
bool "USB Gecko udbg console for the Nintendo GameCube/Wii"
depends on GAMECUBE_COMMON
help
If you say yes to this option, support will be included for the
USB Gecko adapter as an udbg console.
The USB Gecko is a EXI to USB Serial converter that can be plugged
into a memcard slot in the Nintendo GameCube/Wii.
This driver bypasses the EXI layer completely.
If in doubt, say N here.
config GAMECUBE
bool "Nintendo-GameCube"
depends on EMBEDDED6xx
select GAMECUBE_COMMON
help
Select GAMECUBE if configuring for the Nintendo GameCube.
More information at: <http://gc-linux.sourceforge.net/>
config WII
bool "Nintendo-Wii"
depends on EMBEDDED6xx
select GAMECUBE_COMMON
help
Select WII if configuring for the Nintendo Wii.
More information at: <http://gc-linux.sourceforge.net/>

View file

@ -0,0 +1,13 @@
#
# Makefile for the 6xx/7xx/7xxxx linux kernel.
#
obj-$(CONFIG_MPC7448HPC2) += mpc7448_hpc2.o
obj-$(CONFIG_LINKSTATION) += linkstation.o ls_uart.o
obj-$(CONFIG_STORCENTER) += storcenter.o
obj-$(CONFIG_PPC_HOLLY) += holly.o
obj-$(CONFIG_PPC_C2K) += c2k.o
obj-$(CONFIG_USBGECKO_UDBG) += usbgecko_udbg.o
obj-$(CONFIG_GAMECUBE_COMMON) += flipper-pic.o
obj-$(CONFIG_GAMECUBE) += gamecube.o
obj-$(CONFIG_WII) += wii.o hlwd-pic.o
obj-$(CONFIG_MVME5100) += mvme5100.o

View file

@ -0,0 +1,148 @@
/*
* Board setup routines for the GEFanuc C2K board
*
* Author: Remi Machet <rmachet@slac.stanford.edu>
*
* Originated from prpmc2800.c
*
* 2008 (c) Stanford University
* 2007 (c) MontaVista, Software, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/seq_file.h>
#include <linux/time.h>
#include <linux/of.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/time.h>
#include <mm/mmu_decl.h>
#include <sysdev/mv64x60.h>
#define MV64x60_MPP_CNTL_0 0x0000
#define MV64x60_MPP_CNTL_2 0x0008
#define MV64x60_GPP_IO_CNTL 0x0000
#define MV64x60_GPP_LEVEL_CNTL 0x0010
#define MV64x60_GPP_VALUE_SET 0x0018
static void __iomem *mv64x60_mpp_reg_base;
static void __iomem *mv64x60_gpp_reg_base;
static void __init c2k_setup_arch(void)
{
struct device_node *np;
phys_addr_t paddr;
const unsigned int *reg;
/*
* ioremap mpp and gpp registers in case they are later
* needed by c2k_reset_board().
*/
np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-mpp");
reg = of_get_property(np, "reg", NULL);
paddr = of_translate_address(np, reg);
of_node_put(np);
mv64x60_mpp_reg_base = ioremap(paddr, reg[1]);
np = of_find_compatible_node(NULL, NULL, "marvell,mv64360-gpp");
reg = of_get_property(np, "reg", NULL);
paddr = of_translate_address(np, reg);
of_node_put(np);
mv64x60_gpp_reg_base = ioremap(paddr, reg[1]);
#ifdef CONFIG_PCI
mv64x60_pci_init();
#endif
}
static void c2k_reset_board(void)
{
u32 temp;
local_irq_disable();
temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0);
temp &= 0xFFFF0FFF;
out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_0, temp);
temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL);
temp |= 0x00000004;
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp);
temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL);
temp |= 0x00000004;
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp);
temp = in_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2);
temp &= 0xFFFF0FFF;
out_le32(mv64x60_mpp_reg_base + MV64x60_MPP_CNTL_2, temp);
temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL);
temp |= 0x00080000;
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_LEVEL_CNTL, temp);
temp = in_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL);
temp |= 0x00080000;
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_IO_CNTL, temp);
out_le32(mv64x60_gpp_reg_base + MV64x60_GPP_VALUE_SET, 0x00080004);
}
static void c2k_restart(char *cmd)
{
c2k_reset_board();
msleep(100);
panic("restart failed\n");
}
#ifdef CONFIG_NOT_COHERENT_CACHE
#define COHERENCY_SETTING "off"
#else
#define COHERENCY_SETTING "on"
#endif
void c2k_show_cpuinfo(struct seq_file *m)
{
seq_printf(m, "Vendor\t\t: GEFanuc\n");
seq_printf(m, "coherency\t: %s\n", COHERENCY_SETTING);
}
/*
* Called very early, device-tree isn't unflattened
*/
static int __init c2k_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "GEFanuc,C2K"))
return 0;
printk(KERN_INFO "Detected a GEFanuc C2K board\n");
_set_L2CR(0);
_set_L2CR(L2CR_L2E | L2CR_L2PE | L2CR_L2I);
return 1;
}
define_machine(c2k) {
.name = "C2K",
.probe = c2k_probe,
.setup_arch = c2k_setup_arch,
.init_early = mv64x60_init_early,
.show_cpuinfo = c2k_show_cpuinfo,
.init_IRQ = mv64x60_init_irq,
.get_irq = mv64x60_get_irq,
.restart = c2k_restart,
.calibrate_decr = generic_calibrate_decr,
};

View file

@ -0,0 +1,255 @@
/*
* arch/powerpc/platforms/embedded6xx/flipper-pic.c
*
* Nintendo GameCube/Wii "Flipper" interrupt controller support.
* Copyright (C) 2004-2009 The GameCube Linux Team
* Copyright (C) 2007,2008,2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#define DRV_MODULE_NAME "flipper-pic"
#define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <asm/io.h>
#include "flipper-pic.h"
#define FLIPPER_NR_IRQS 32
/*
* Each interrupt has a corresponding bit in both
* the Interrupt Cause (ICR) and Interrupt Mask (IMR) registers.
*
* Enabling/disabling an interrupt line involves setting/clearing
* the corresponding bit in IMR.
* Except for the RSW interrupt, all interrupts get deasserted automatically
* when the source deasserts the interrupt.
*/
#define FLIPPER_ICR 0x00
#define FLIPPER_ICR_RSS (1<<16) /* reset switch state */
#define FLIPPER_IMR 0x04
#define FLIPPER_RESET 0x24
/*
* IRQ chip hooks.
*
*/
static void flipper_pic_mask_and_ack(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
u32 mask = 1 << irq;
clrbits32(io_base + FLIPPER_IMR, mask);
/* this is at least needed for RSW */
out_be32(io_base + FLIPPER_ICR, mask);
}
static void flipper_pic_ack(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
/* this is at least needed for RSW */
out_be32(io_base + FLIPPER_ICR, 1 << irq);
}
static void flipper_pic_mask(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
clrbits32(io_base + FLIPPER_IMR, 1 << irq);
}
static void flipper_pic_unmask(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
setbits32(io_base + FLIPPER_IMR, 1 << irq);
}
static struct irq_chip flipper_pic = {
.name = "flipper-pic",
.irq_ack = flipper_pic_ack,
.irq_mask_ack = flipper_pic_mask_and_ack,
.irq_mask = flipper_pic_mask,
.irq_unmask = flipper_pic_unmask,
};
/*
* IRQ host hooks.
*
*/
static struct irq_domain *flipper_irq_host;
static int flipper_pic_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
irq_set_chip_data(virq, h->host_data);
irq_set_status_flags(virq, IRQ_LEVEL);
irq_set_chip_and_handler(virq, &flipper_pic, handle_level_irq);
return 0;
}
static int flipper_pic_match(struct irq_domain *h, struct device_node *np)
{
return 1;
}
static const struct irq_domain_ops flipper_irq_domain_ops = {
.map = flipper_pic_map,
.match = flipper_pic_match,
};
/*
* Platform hooks.
*
*/
static void __flipper_quiesce(void __iomem *io_base)
{
/* mask and ack all IRQs */
out_be32(io_base + FLIPPER_IMR, 0x00000000);
out_be32(io_base + FLIPPER_ICR, 0xffffffff);
}
struct irq_domain * __init flipper_pic_init(struct device_node *np)
{
struct device_node *pi;
struct irq_domain *irq_domain = NULL;
struct resource res;
void __iomem *io_base;
int retval;
pi = of_get_parent(np);
if (!pi) {
pr_err("no parent found\n");
goto out;
}
if (!of_device_is_compatible(pi, "nintendo,flipper-pi")) {
pr_err("unexpected parent compatible\n");
goto out;
}
retval = of_address_to_resource(pi, 0, &res);
if (retval) {
pr_err("no io memory range found\n");
goto out;
}
io_base = ioremap(res.start, resource_size(&res));
pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base);
__flipper_quiesce(io_base);
irq_domain = irq_domain_add_linear(np, FLIPPER_NR_IRQS,
&flipper_irq_domain_ops, io_base);
if (!irq_domain) {
pr_err("failed to allocate irq_domain\n");
return NULL;
}
out:
return irq_domain;
}
unsigned int flipper_pic_get_irq(void)
{
void __iomem *io_base = flipper_irq_host->host_data;
int irq;
u32 irq_status;
irq_status = in_be32(io_base + FLIPPER_ICR) &
in_be32(io_base + FLIPPER_IMR);
if (irq_status == 0)
return NO_IRQ; /* no more IRQs pending */
irq = __ffs(irq_status);
return irq_linear_revmap(flipper_irq_host, irq);
}
/*
* Probe function.
*
*/
void __init flipper_pic_probe(void)
{
struct device_node *np;
np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-pic");
BUG_ON(!np);
flipper_irq_host = flipper_pic_init(np);
BUG_ON(!flipper_irq_host);
irq_set_default_host(flipper_irq_host);
of_node_put(np);
}
/*
* Misc functions related to the flipper chipset.
*
*/
/**
* flipper_quiesce() - quiesce flipper irq controller
*
* Mask and ack all interrupt sources.
*
*/
void flipper_quiesce(void)
{
void __iomem *io_base = flipper_irq_host->host_data;
__flipper_quiesce(io_base);
}
/*
* Resets the platform.
*/
void flipper_platform_reset(void)
{
void __iomem *io_base;
if (flipper_irq_host && flipper_irq_host->host_data) {
io_base = flipper_irq_host->host_data;
out_8(io_base + FLIPPER_RESET, 0x00);
}
}
/*
* Returns non-zero if the reset button is pressed.
*/
int flipper_is_reset_button_pressed(void)
{
void __iomem *io_base;
u32 icr;
if (flipper_irq_host && flipper_irq_host->host_data) {
io_base = flipper_irq_host->host_data;
icr = in_be32(io_base + FLIPPER_ICR);
return !(icr & FLIPPER_ICR_RSS);
}
return 0;
}

View file

@ -0,0 +1,25 @@
/*
* arch/powerpc/platforms/embedded6xx/flipper-pic.h
*
* Nintendo GameCube/Wii "Flipper" interrupt controller support.
* Copyright (C) 2004-2009 The GameCube Linux Team
* Copyright (C) 2007,2008,2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#ifndef __FLIPPER_PIC_H
#define __FLIPPER_PIC_H
unsigned int flipper_pic_get_irq(void);
void __init flipper_pic_probe(void);
void flipper_quiesce(void);
void flipper_platform_reset(void);
int flipper_is_reset_button_pressed(void);
#endif

View file

@ -0,0 +1,107 @@
/*
* arch/powerpc/platforms/embedded6xx/gamecube.c
*
* Nintendo GameCube board-specific support
* Copyright (C) 2004-2009 The GameCube Linux Team
* Copyright (C) 2007,2008,2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/kexec.h>
#include <linux/seq_file.h>
#include <linux/of_platform.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/time.h>
#include <asm/udbg.h>
#include "flipper-pic.h"
#include "usbgecko_udbg.h"
static void gamecube_spin(void)
{
/* spin until power button pressed */
for (;;)
cpu_relax();
}
static void gamecube_restart(char *cmd)
{
local_irq_disable();
flipper_platform_reset();
gamecube_spin();
}
static void gamecube_power_off(void)
{
local_irq_disable();
gamecube_spin();
}
static void gamecube_halt(void)
{
gamecube_restart(NULL);
}
static void __init gamecube_init_early(void)
{
ug_udbg_init();
}
static int __init gamecube_probe(void)
{
unsigned long dt_root;
dt_root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(dt_root, "nintendo,gamecube"))
return 0;
return 1;
}
static void gamecube_shutdown(void)
{
flipper_quiesce();
}
define_machine(gamecube) {
.name = "gamecube",
.probe = gamecube_probe,
.init_early = gamecube_init_early,
.restart = gamecube_restart,
.power_off = gamecube_power_off,
.halt = gamecube_halt,
.init_IRQ = flipper_pic_probe,
.get_irq = flipper_pic_get_irq,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
.machine_shutdown = gamecube_shutdown,
};
static const struct of_device_id gamecube_of_bus[] = {
{ .compatible = "nintendo,flipper", },
{ },
};
static int __init gamecube_device_probe(void)
{
if (!machine_is(gamecube))
return 0;
of_platform_bus_probe(NULL, gamecube_of_bus, NULL);
return 0;
}
device_initcall(gamecube_device_probe);

View file

@ -0,0 +1,236 @@
/*
* arch/powerpc/platforms/embedded6xx/hlwd-pic.c
*
* Nintendo Wii "Hollywood" interrupt controller support.
* Copyright (C) 2009 The GameCube Linux Team
* Copyright (C) 2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#define DRV_MODULE_NAME "hlwd-pic"
#define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt
#include <linux/kernel.h>
#include <linux/irq.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <asm/io.h>
#include "hlwd-pic.h"
#define HLWD_NR_IRQS 32
/*
* Each interrupt has a corresponding bit in both
* the Interrupt Cause (ICR) and Interrupt Mask (IMR) registers.
*
* Enabling/disabling an interrupt line involves asserting/clearing
* the corresponding bit in IMR. ACK'ing a request simply involves
* asserting the corresponding bit in ICR.
*/
#define HW_BROADWAY_ICR 0x00
#define HW_BROADWAY_IMR 0x04
/*
* IRQ chip hooks.
*
*/
static void hlwd_pic_mask_and_ack(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
u32 mask = 1 << irq;
clrbits32(io_base + HW_BROADWAY_IMR, mask);
out_be32(io_base + HW_BROADWAY_ICR, mask);
}
static void hlwd_pic_ack(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
out_be32(io_base + HW_BROADWAY_ICR, 1 << irq);
}
static void hlwd_pic_mask(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
clrbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
}
static void hlwd_pic_unmask(struct irq_data *d)
{
int irq = irqd_to_hwirq(d);
void __iomem *io_base = irq_data_get_irq_chip_data(d);
setbits32(io_base + HW_BROADWAY_IMR, 1 << irq);
}
static struct irq_chip hlwd_pic = {
.name = "hlwd-pic",
.irq_ack = hlwd_pic_ack,
.irq_mask_ack = hlwd_pic_mask_and_ack,
.irq_mask = hlwd_pic_mask,
.irq_unmask = hlwd_pic_unmask,
};
/*
* IRQ host hooks.
*
*/
static struct irq_domain *hlwd_irq_host;
static int hlwd_pic_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hwirq)
{
irq_set_chip_data(virq, h->host_data);
irq_set_status_flags(virq, IRQ_LEVEL);
irq_set_chip_and_handler(virq, &hlwd_pic, handle_level_irq);
return 0;
}
static const struct irq_domain_ops hlwd_irq_domain_ops = {
.map = hlwd_pic_map,
};
static unsigned int __hlwd_pic_get_irq(struct irq_domain *h)
{
void __iomem *io_base = h->host_data;
int irq;
u32 irq_status;
irq_status = in_be32(io_base + HW_BROADWAY_ICR) &
in_be32(io_base + HW_BROADWAY_IMR);
if (irq_status == 0)
return NO_IRQ; /* no more IRQs pending */
irq = __ffs(irq_status);
return irq_linear_revmap(h, irq);
}
static void hlwd_pic_irq_cascade(unsigned int cascade_virq,
struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
struct irq_domain *irq_domain = irq_get_handler_data(cascade_virq);
unsigned int virq;
raw_spin_lock(&desc->lock);
chip->irq_mask(&desc->irq_data); /* IRQ_LEVEL */
raw_spin_unlock(&desc->lock);
virq = __hlwd_pic_get_irq(irq_domain);
if (virq != NO_IRQ)
generic_handle_irq(virq);
else
pr_err("spurious interrupt!\n");
raw_spin_lock(&desc->lock);
chip->irq_ack(&desc->irq_data); /* IRQ_LEVEL */
if (!irqd_irq_disabled(&desc->irq_data) && chip->irq_unmask)
chip->irq_unmask(&desc->irq_data);
raw_spin_unlock(&desc->lock);
}
/*
* Platform hooks.
*
*/
static void __hlwd_quiesce(void __iomem *io_base)
{
/* mask and ack all IRQs */
out_be32(io_base + HW_BROADWAY_IMR, 0);
out_be32(io_base + HW_BROADWAY_ICR, 0xffffffff);
}
struct irq_domain *hlwd_pic_init(struct device_node *np)
{
struct irq_domain *irq_domain;
struct resource res;
void __iomem *io_base;
int retval;
retval = of_address_to_resource(np, 0, &res);
if (retval) {
pr_err("no io memory range found\n");
return NULL;
}
io_base = ioremap(res.start, resource_size(&res));
if (!io_base) {
pr_err("ioremap failed\n");
return NULL;
}
pr_info("controller at 0x%08x mapped to 0x%p\n", res.start, io_base);
__hlwd_quiesce(io_base);
irq_domain = irq_domain_add_linear(np, HLWD_NR_IRQS,
&hlwd_irq_domain_ops, io_base);
if (!irq_domain) {
pr_err("failed to allocate irq_domain\n");
iounmap(io_base);
return NULL;
}
return irq_domain;
}
unsigned int hlwd_pic_get_irq(void)
{
return __hlwd_pic_get_irq(hlwd_irq_host);
}
/*
* Probe function.
*
*/
void hlwd_pic_probe(void)
{
struct irq_domain *host;
struct device_node *np;
const u32 *interrupts;
int cascade_virq;
for_each_compatible_node(np, NULL, "nintendo,hollywood-pic") {
interrupts = of_get_property(np, "interrupts", NULL);
if (interrupts) {
host = hlwd_pic_init(np);
BUG_ON(!host);
cascade_virq = irq_of_parse_and_map(np, 0);
irq_set_handler_data(cascade_virq, host);
irq_set_chained_handler(cascade_virq,
hlwd_pic_irq_cascade);
hlwd_irq_host = host;
break;
}
}
}
/**
* hlwd_quiesce() - quiesce hollywood irq controller
*
* Mask and ack all interrupt sources.
*
*/
void hlwd_quiesce(void)
{
void __iomem *io_base = hlwd_irq_host->host_data;
__hlwd_quiesce(io_base);
}

View file

@ -0,0 +1,22 @@
/*
* arch/powerpc/platforms/embedded6xx/hlwd-pic.h
*
* Nintendo Wii "Hollywood" interrupt controller support.
* Copyright (C) 2009 The GameCube Linux Team
* Copyright (C) 2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#ifndef __HLWD_PIC_H
#define __HLWD_PIC_H
extern unsigned int hlwd_pic_get_irq(void);
extern void hlwd_pic_probe(void);
extern void hlwd_quiesce(void);
#endif

View file

@ -0,0 +1,285 @@
/*
* Board setup routines for the IBM 750GX/CL platform w/ TSI10x bridge
*
* Copyright 2007 IBM Corporation
*
* Stephen Winiecki <stevewin@us.ibm.com>
* Josh Boyer <jwboyer@linux.vnet.ibm.com>
*
* Based on code from mpc7448_hpc2.c
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/console.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <linux/of_platform.h>
#include <linux/module.h>
#include <asm/time.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/tsi108.h>
#include <asm/pci-bridge.h>
#include <asm/reg.h>
#include <mm/mmu_decl.h>
#include <asm/tsi108_irq.h>
#include <asm/tsi108_pci.h>
#include <asm/mpic.h>
#undef DEBUG
#define HOLLY_PCI_CFG_PHYS 0x7c000000
int holly_exclude_device(struct pci_controller *hose, u_char bus, u_char devfn)
{
if (bus == 0 && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
else
return PCIBIOS_SUCCESSFUL;
}
static void holly_remap_bridge(void)
{
u32 lut_val, lut_addr;
int i;
printk(KERN_INFO "Remapping PCI bridge\n");
/* Re-init the PCI bridge and LUT registers to have mappings that don't
* rely on PIBS
*/
lut_addr = 0x900;
for (i = 0; i < 31; i++) {
tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000201);
lut_addr += 4;
tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
lut_addr += 4;
}
/* Reserve the last LUT entry for PCI I/O space */
tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x00000241);
lut_addr += 4;
tsi108_write_reg(TSI108_PB_OFFSET + lut_addr, 0x0);
/* Map PCI I/O space */
tsi108_write_reg(TSI108_PCI_PFAB_IO_UPPER, 0x0);
tsi108_write_reg(TSI108_PCI_PFAB_IO, 0x1);
/* Map PCI CFG space */
tsi108_write_reg(TSI108_PCI_PFAB_BAR0_UPPER, 0x0);
tsi108_write_reg(TSI108_PCI_PFAB_BAR0, 0x7c000000 | 0x01);
/* We don't need MEM32 and PRM remapping so disable them */
tsi108_write_reg(TSI108_PCI_PFAB_MEM32, 0x0);
tsi108_write_reg(TSI108_PCI_PFAB_PFM3, 0x0);
tsi108_write_reg(TSI108_PCI_PFAB_PFM4, 0x0);
/* Set P2O_BAR0 */
tsi108_write_reg(TSI108_PCI_P2O_BAR0_UPPER, 0x0);
tsi108_write_reg(TSI108_PCI_P2O_BAR0, 0xc0000000);
/* Init the PCI LUTs to do no remapping */
lut_addr = 0x500;
lut_val = 0x00000002;
for (i = 0; i < 32; i++) {
tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, lut_val);
lut_addr += 4;
tsi108_write_reg(TSI108_PCI_OFFSET + lut_addr, 0x40000000);
lut_addr += 4;
lut_val += 0x02000000;
}
tsi108_write_reg(TSI108_PCI_P2O_PAGE_SIZES, 0x00007900);
/* Set 64-bit PCI bus address for system memory */
tsi108_write_reg(TSI108_PCI_P2O_BAR2_UPPER, 0x0);
tsi108_write_reg(TSI108_PCI_P2O_BAR2, 0x0);
}
static void __init holly_setup_arch(void)
{
struct device_node *np;
if (ppc_md.progress)
ppc_md.progress("holly_setup_arch():set_bridge", 0);
tsi108_csr_vir_base = get_vir_csrbase();
/* setup PCI host bridge */
holly_remap_bridge();
np = of_find_node_by_type(NULL, "pci");
if (np)
tsi108_setup_pci(np, HOLLY_PCI_CFG_PHYS, 1);
ppc_md.pci_exclude_device = holly_exclude_device;
if (ppc_md.progress)
ppc_md.progress("tsi108: resources set", 0x100);
printk(KERN_INFO "PPC750GX/CL Platform\n");
}
/*
* Interrupt setup and service. Interrupts on the holly come
* from the four external INT pins, PCI interrupts are routed via
* PCI interrupt control registers, it generates internal IRQ23
*
* Interrupt routing on the Holly Board:
* TSI108:PB_INT[0] -> CPU0:INT#
* TSI108:PB_INT[1] -> CPU0:MCP#
* TSI108:PB_INT[2] -> N/C
* TSI108:PB_INT[3] -> N/C
*/
static void __init holly_init_IRQ(void)
{
struct mpic *mpic;
#ifdef CONFIG_PCI
unsigned int cascade_pci_irq;
struct device_node *tsi_pci;
struct device_node *cascade_node = NULL;
#endif
mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
24, 0,
"Tsi108_PIC");
BUG_ON(mpic == NULL);
mpic_assign_isu(mpic, 0, mpic->paddr + 0x100);
mpic_init(mpic);
#ifdef CONFIG_PCI
tsi_pci = of_find_node_by_type(NULL, "pci");
if (tsi_pci == NULL) {
printk(KERN_ERR "%s: No tsi108 pci node found !\n", __func__);
return;
}
cascade_node = of_find_node_by_type(NULL, "pic-router");
if (cascade_node == NULL) {
printk(KERN_ERR "%s: No tsi108 pci cascade node found !\n", __func__);
return;
}
cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0);
pr_debug("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__, (u32) cascade_pci_irq);
tsi108_pci_int_init(cascade_node);
irq_set_handler_data(cascade_pci_irq, mpic);
irq_set_chained_handler(cascade_pci_irq, tsi108_irq_cascade);
#endif
/* Configure MPIC outputs to CPU0 */
tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
}
void holly_show_cpuinfo(struct seq_file *m)
{
seq_printf(m, "vendor\t\t: IBM\n");
seq_printf(m, "machine\t\t: PPC750 GX/CL\n");
}
void holly_restart(char *cmd)
{
__be32 __iomem *ocn_bar1 = NULL;
unsigned long bar;
struct device_node *bridge = NULL;
const void *prop;
int size;
phys_addr_t addr = 0xc0000000;
local_irq_disable();
bridge = of_find_node_by_type(NULL, "tsi-bridge");
if (bridge) {
prop = of_get_property(bridge, "reg", &size);
addr = of_translate_address(bridge, prop);
}
addr += (TSI108_PB_OFFSET + 0x414);
ocn_bar1 = ioremap(addr, 0x4);
/* Turn on the BOOT bit so the addresses are correctly
* routed to the HLP interface */
bar = ioread32be(ocn_bar1);
bar |= 2;
iowrite32be(bar, ocn_bar1);
iosync();
/* Set SRR0 to the reset vector and turn on MSR_IP */
mtspr(SPRN_SRR0, 0xfff00100);
mtspr(SPRN_SRR1, MSR_IP);
/* Do an rfi to jump back to firmware. Somewhat evil,
* but it works
*/
__asm__ __volatile__("rfi" : : : "memory");
/* Spin until reset happens. Shouldn't really get here */
for (;;) ;
}
void holly_power_off(void)
{
local_irq_disable();
/* No way to shut power off with software */
for (;;) ;
}
void holly_halt(void)
{
holly_power_off();
}
/*
* Called very early, device-tree isn't unflattened
*/
static int __init holly_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "ibm,holly"))
return 0;
return 1;
}
static int ppc750_machine_check_exception(struct pt_regs *regs)
{
const struct exception_table_entry *entry;
/* Are we prepared to handle this fault */
if ((entry = search_exception_tables(regs->nip)) != NULL) {
tsi108_clear_pci_cfg_error();
regs->msr |= MSR_RI;
regs->nip = entry->fixup;
return 1;
}
return 0;
}
define_machine(holly){
.name = "PPC750 GX/CL TSI",
.probe = holly_probe,
.setup_arch = holly_setup_arch,
.init_IRQ = holly_init_IRQ,
.show_cpuinfo = holly_show_cpuinfo,
.get_irq = mpic_get_irq,
.restart = holly_restart,
.calibrate_decr = generic_calibrate_decr,
.machine_check_exception = ppc750_machine_check_exception,
.progress = udbg_progress,
};

View file

@ -0,0 +1,164 @@
/*
* Board setup routines for the Buffalo Linkstation / Kurobox Platform.
*
* Copyright (C) 2006 G. Liakhovetski (g.liakhovetski@gmx.de)
*
* Based on sandpoint.c by Mark A. Greer
*
* 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/kernel.h>
#include <linux/initrd.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/prom.h>
#include <asm/mpic.h>
#include <asm/pci-bridge.h>
#include "mpc10x.h"
static const struct of_device_id of_bus_ids[] __initconst = {
{ .type = "soc", },
{ .compatible = "simple-bus", },
{},
};
static int __init declare_of_platform_devices(void)
{
of_platform_bus_probe(NULL, of_bus_ids, NULL);
return 0;
}
machine_device_initcall(linkstation, declare_of_platform_devices);
static int __init linkstation_add_bridge(struct device_node *dev)
{
#ifdef CONFIG_PCI
int len;
struct pci_controller *hose;
const int *bus_range;
printk("Adding PCI host bridge %s\n", dev->full_name);
bus_range = of_get_property(dev, "bus-range", &len);
if (bus_range == NULL || len < 2 * sizeof(int))
printk(KERN_WARNING "Can't get bus-range for %s, assume"
" bus 0\n", dev->full_name);
hose = pcibios_alloc_controller(dev);
if (hose == NULL)
return -ENOMEM;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
setup_indirect_pci(hose, 0xfec00000, 0xfee00000, 0);
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, 1);
#endif
return 0;
}
static void __init linkstation_setup_arch(void)
{
struct device_node *np;
/* Lookup PCI host bridges */
for_each_compatible_node(np, "pci", "mpc10x-pci")
linkstation_add_bridge(np);
printk(KERN_INFO "BUFFALO Network Attached Storage Series\n");
printk(KERN_INFO "(C) 2002-2005 BUFFALO INC.\n");
}
/*
* Interrupt setup and service. Interrupts on the linkstation come
* from the four PCI slots plus onboard 8241 devices: I2C, DUART.
*/
static void __init linkstation_init_IRQ(void)
{
struct mpic *mpic;
mpic = mpic_alloc(NULL, 0, 0, 4, 0, " EPIC ");
BUG_ON(mpic == NULL);
/* PCI IRQs */
mpic_assign_isu(mpic, 0, mpic->paddr + 0x10200);
/* I2C */
mpic_assign_isu(mpic, 1, mpic->paddr + 0x11000);
/* ttyS0, ttyS1 */
mpic_assign_isu(mpic, 2, mpic->paddr + 0x11100);
mpic_init(mpic);
}
extern void avr_uart_configure(void);
extern void avr_uart_send(const char);
static void linkstation_restart(char *cmd)
{
local_irq_disable();
/* Reset system via AVR */
avr_uart_configure();
/* Send reboot command */
avr_uart_send('C');
for(;;) /* Spin until reset happens */
avr_uart_send('G'); /* "kick" */
}
static void linkstation_power_off(void)
{
local_irq_disable();
/* Power down system via AVR */
avr_uart_configure();
/* send shutdown command */
avr_uart_send('E');
for(;;) /* Spin until power-off happens */
avr_uart_send('G'); /* "kick" */
/* NOTREACHED */
}
static void linkstation_halt(void)
{
linkstation_power_off();
/* NOTREACHED */
}
static void linkstation_show_cpuinfo(struct seq_file *m)
{
seq_printf(m, "vendor\t\t: Buffalo Technology\n");
seq_printf(m, "machine\t\t: Linkstation I/Kurobox(HG)\n");
}
static int __init linkstation_probe(void)
{
unsigned long root;
root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "linkstation"))
return 0;
return 1;
}
define_machine(linkstation){
.name = "Buffalo Linkstation",
.probe = linkstation_probe,
.setup_arch = linkstation_setup_arch,
.init_IRQ = linkstation_init_IRQ,
.show_cpuinfo = linkstation_show_cpuinfo,
.get_irq = mpic_get_irq,
.restart = linkstation_restart,
.power_off = linkstation_power_off,
.halt = linkstation_halt,
.calibrate_decr = generic_calibrate_decr,
};

View file

@ -0,0 +1,142 @@
/*
* AVR power-management chip interface for the Buffalo Linkstation /
* Kurobox Platform.
*
* Author: 2006 (c) G. Liakhovetski
* g.liakhovetski@gmx.de
*
* 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/workqueue.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/serial_reg.h>
#include <linux/serial_8250.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/termbits.h>
#include "mpc10x.h"
static void __iomem *avr_addr;
static unsigned long avr_clock;
static struct work_struct wd_work;
static void wd_stop(struct work_struct *unused)
{
const char string[] = "AAAAFFFFJJJJ>>>>VVVV>>>>ZZZZVVVVKKKK";
int i = 0, rescue = 8;
int len = strlen(string);
while (rescue--) {
int j;
char lsr = in_8(avr_addr + UART_LSR);
if (lsr & (UART_LSR_THRE | UART_LSR_TEMT)) {
for (j = 0; j < 16 && i < len; j++, i++)
out_8(avr_addr + UART_TX, string[i]);
if (i == len) {
/* Read "OK" back: 4ms for the last "KKKK"
plus a couple bytes back */
msleep(7);
printk("linkstation: disarming the AVR watchdog: ");
while (in_8(avr_addr + UART_LSR) & UART_LSR_DR)
printk("%c", in_8(avr_addr + UART_RX));
break;
}
}
msleep(17);
}
printk("\n");
}
#define AVR_QUOT(clock) ((clock) + 8 * 9600) / (16 * 9600)
void avr_uart_configure(void)
{
unsigned char cval = UART_LCR_WLEN8;
unsigned int quot = AVR_QUOT(avr_clock);
if (!avr_addr || !avr_clock)
return;
out_8(avr_addr + UART_LCR, cval); /* initialise UART */
out_8(avr_addr + UART_MCR, 0);
out_8(avr_addr + UART_IER, 0);
cval |= UART_LCR_STOP | UART_LCR_PARITY | UART_LCR_EPAR;
out_8(avr_addr + UART_LCR, cval); /* Set character format */
out_8(avr_addr + UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */
out_8(avr_addr + UART_DLL, quot & 0xff); /* LS of divisor */
out_8(avr_addr + UART_DLM, quot >> 8); /* MS of divisor */
out_8(avr_addr + UART_LCR, cval); /* reset DLAB */
out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
}
void avr_uart_send(const char c)
{
if (!avr_addr || !avr_clock)
return;
out_8(avr_addr + UART_TX, c);
out_8(avr_addr + UART_TX, c);
out_8(avr_addr + UART_TX, c);
out_8(avr_addr + UART_TX, c);
}
static void __init ls_uart_init(void)
{
local_irq_disable();
#ifndef CONFIG_SERIAL_8250
out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO); /* enable FIFO */
out_8(avr_addr + UART_FCR, UART_FCR_ENABLE_FIFO |
UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); /* clear FIFOs */
out_8(avr_addr + UART_FCR, 0);
out_8(avr_addr + UART_IER, 0);
/* Clear up interrupts */
(void) in_8(avr_addr + UART_LSR);
(void) in_8(avr_addr + UART_RX);
(void) in_8(avr_addr + UART_IIR);
(void) in_8(avr_addr + UART_MSR);
#endif
avr_uart_configure();
local_irq_enable();
}
static int __init ls_uarts_init(void)
{
struct device_node *avr;
phys_addr_t phys_addr;
int len;
avr = of_find_node_by_path("/soc10x/serial@80004500");
if (!avr)
return -EINVAL;
avr_clock = *(u32*)of_get_property(avr, "clock-frequency", &len);
phys_addr = ((u32*)of_get_property(avr, "reg", &len))[0];
if (!avr_clock || !phys_addr)
return -EINVAL;
avr_addr = ioremap(phys_addr, 32);
if (!avr_addr)
return -EFAULT;
ls_uart_init();
INIT_WORK(&wd_work, wd_stop);
schedule_work(&wd_work);
return 0;
}
machine_late_initcall(linkstation, ls_uarts_init);

View file

@ -0,0 +1,169 @@
/*
* Common routines for the Motorola SPS MPC106/8240/107 Host bridge/Mem
* ctlr/EPIC/etc.
*
* Author: Mark A. Greer
* mgreer@mvista.com
*
* 2001 (c) MontaVista, Software, Inc. 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.
*/
#ifndef __PPC_KERNEL_MPC10X_H
#define __PPC_KERNEL_MPC10X_H
#include <linux/pci_ids.h>
#include <asm/pci-bridge.h>
/*
* The values here don't completely map everything but should work in most
* cases.
*
* MAP A (PReP Map)
* Processor: 0x80000000 - 0x807fffff -> PCI I/O: 0x00000000 - 0x007fffff
* Processor: 0xc0000000 - 0xdfffffff -> PCI MEM: 0x00000000 - 0x1fffffff
* PCI MEM: 0x80000000 -> Processor System Memory: 0x00000000
* EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
*
* MAP B (CHRP Map)
* Processor: 0xfe000000 - 0xfebfffff -> PCI I/O: 0x00000000 - 0x00bfffff
* Processor: 0x80000000 - 0xbfffffff -> PCI MEM: 0x80000000 - 0xbfffffff
* PCI MEM: 0x00000000 -> Processor System Memory: 0x00000000
* EUMB mapped to: ioremap_base - 0x00100000 (ioremap_base - 1 MB)
*/
/*
* Define the vendor/device IDs for the various bridges--should be added to
* <linux/pci_ids.h>
*/
#define MPC10X_BRIDGE_106 ((PCI_DEVICE_ID_MOTOROLA_MPC106 << 16) | \
PCI_VENDOR_ID_MOTOROLA)
#define MPC10X_BRIDGE_8240 ((0x0003 << 16) | PCI_VENDOR_ID_MOTOROLA)
#define MPC10X_BRIDGE_107 ((0x0004 << 16) | PCI_VENDOR_ID_MOTOROLA)
#define MPC10X_BRIDGE_8245 ((0x0006 << 16) | PCI_VENDOR_ID_MOTOROLA)
/* Define the type of map to use */
#define MPC10X_MEM_MAP_A 1
#define MPC10X_MEM_MAP_B 2
/* Map A (PReP Map) Defines */
#define MPC10X_MAPA_CNFG_ADDR 0x80000cf8
#define MPC10X_MAPA_CNFG_DATA 0x80000cfc
#define MPC10X_MAPA_ISA_IO_BASE 0x80000000
#define MPC10X_MAPA_ISA_MEM_BASE 0xc0000000
#define MPC10X_MAPA_DRAM_OFFSET 0x80000000
#define MPC10X_MAPA_PCI_INTACK_ADDR 0xbffffff0
#define MPC10X_MAPA_PCI_IO_START 0x00000000
#define MPC10X_MAPA_PCI_IO_END (0x00800000 - 1)
#define MPC10X_MAPA_PCI_MEM_START 0x00000000
#define MPC10X_MAPA_PCI_MEM_END (0x20000000 - 1)
#define MPC10X_MAPA_PCI_MEM_OFFSET (MPC10X_MAPA_ISA_MEM_BASE - \
MPC10X_MAPA_PCI_MEM_START)
/* Map B (CHRP Map) Defines */
#define MPC10X_MAPB_CNFG_ADDR 0xfec00000
#define MPC10X_MAPB_CNFG_DATA 0xfee00000
#define MPC10X_MAPB_ISA_IO_BASE 0xfe000000
#define MPC10X_MAPB_ISA_MEM_BASE 0x80000000
#define MPC10X_MAPB_DRAM_OFFSET 0x00000000
#define MPC10X_MAPB_PCI_INTACK_ADDR 0xfef00000
#define MPC10X_MAPB_PCI_IO_START 0x00000000
#define MPC10X_MAPB_PCI_IO_END (0x00c00000 - 1)
#define MPC10X_MAPB_PCI_MEM_START 0x80000000
#define MPC10X_MAPB_PCI_MEM_END (0xc0000000 - 1)
#define MPC10X_MAPB_PCI_MEM_OFFSET (MPC10X_MAPB_ISA_MEM_BASE - \
MPC10X_MAPB_PCI_MEM_START)
/* Miscellaneous Configuration register offsets */
#define MPC10X_CFG_PIR_REG 0x09
#define MPC10X_CFG_PIR_HOST_BRIDGE 0x00
#define MPC10X_CFG_PIR_AGENT 0x01
#define MPC10X_CFG_EUMBBAR 0x78
#define MPC10X_CFG_PICR1_REG 0xa8
#define MPC10X_CFG_PICR1_ADDR_MAP_MASK 0x00010000
#define MPC10X_CFG_PICR1_ADDR_MAP_A 0x00010000
#define MPC10X_CFG_PICR1_ADDR_MAP_B 0x00000000
#define MPC10X_CFG_PICR1_SPEC_PCI_RD 0x00000004
#define MPC10X_CFG_PICR1_ST_GATH_EN 0x00000040
#define MPC10X_CFG_PICR2_REG 0xac
#define MPC10X_CFG_PICR2_COPYBACK_OPT 0x00000001
#define MPC10X_CFG_MAPB_OPTIONS_REG 0xe0
#define MPC10X_CFG_MAPB_OPTIONS_CFAE 0x80 /* CPU_FD_ALIAS_EN */
#define MPC10X_CFG_MAPB_OPTIONS_PFAE 0x40 /* PCI_FD_ALIAS_EN */
#define MPC10X_CFG_MAPB_OPTIONS_DR 0x20 /* DLL_RESET */
#define MPC10X_CFG_MAPB_OPTIONS_PCICH 0x08 /* PCI_COMPATIBILITY_HOLE */
#define MPC10X_CFG_MAPB_OPTIONS_PROCCH 0x04 /* PROC_COMPATIBILITY_HOLE */
/* Define offsets for the memory controller registers in the config space */
#define MPC10X_MCTLR_MEM_START_1 0x80 /* Banks 0-3 */
#define MPC10X_MCTLR_MEM_START_2 0x84 /* Banks 4-7 */
#define MPC10X_MCTLR_EXT_MEM_START_1 0x88 /* Banks 0-3 */
#define MPC10X_MCTLR_EXT_MEM_START_2 0x8c /* Banks 4-7 */
#define MPC10X_MCTLR_MEM_END_1 0x90 /* Banks 0-3 */
#define MPC10X_MCTLR_MEM_END_2 0x94 /* Banks 4-7 */
#define MPC10X_MCTLR_EXT_MEM_END_1 0x98 /* Banks 0-3 */
#define MPC10X_MCTLR_EXT_MEM_END_2 0x9c /* Banks 4-7 */
#define MPC10X_MCTLR_MEM_BANK_ENABLES 0xa0
/* Define some offset in the EUMB */
#define MPC10X_EUMB_SIZE 0x00100000 /* Total EUMB size (1MB) */
#define MPC10X_EUMB_MU_OFFSET 0x00000000 /* Msg Unit reg offset */
#define MPC10X_EUMB_MU_SIZE 0x00001000 /* Msg Unit reg size */
#define MPC10X_EUMB_DMA_OFFSET 0x00001000 /* DMA Unit reg offset */
#define MPC10X_EUMB_DMA_SIZE 0x00001000 /* DMA Unit reg size */
#define MPC10X_EUMB_ATU_OFFSET 0x00002000 /* Addr xlate reg offset */
#define MPC10X_EUMB_ATU_SIZE 0x00001000 /* Addr xlate reg size */
#define MPC10X_EUMB_I2C_OFFSET 0x00003000 /* I2C Unit reg offset */
#define MPC10X_EUMB_I2C_SIZE 0x00001000 /* I2C Unit reg size */
#define MPC10X_EUMB_DUART_OFFSET 0x00004000 /* DUART Unit reg offset (8245) */
#define MPC10X_EUMB_DUART_SIZE 0x00001000 /* DUART Unit reg size (8245) */
#define MPC10X_EUMB_EPIC_OFFSET 0x00040000 /* EPIC offset in EUMB */
#define MPC10X_EUMB_EPIC_SIZE 0x00030000 /* EPIC size */
#define MPC10X_EUMB_PM_OFFSET 0x000fe000 /* Performance Monitor reg offset (8245) */
#define MPC10X_EUMB_PM_SIZE 0x00001000 /* Performance Monitor reg size (8245) */
#define MPC10X_EUMB_WP_OFFSET 0x000ff000 /* Data path diagnostic, watchpoint reg offset */
#define MPC10X_EUMB_WP_SIZE 0x00001000 /* Data path diagnostic, watchpoint reg size */
/*
* Define some recommended places to put the EUMB regs.
* For both maps, recommend putting the EUMB from 0xeff00000 to 0xefffffff.
*/
extern unsigned long ioremap_base;
#define MPC10X_MAPA_EUMB_BASE (ioremap_base - MPC10X_EUMB_SIZE)
#define MPC10X_MAPB_EUMB_BASE MPC10X_MAPA_EUMB_BASE
enum ppc_sys_devices {
MPC10X_IIC1,
MPC10X_DMA0,
MPC10X_DMA1,
MPC10X_UART0,
MPC10X_UART1,
NUM_PPC_SYS_DEVS,
};
int mpc10x_bridge_init(struct pci_controller *hose,
uint current_map,
uint new_map,
uint phys_eumb_base);
unsigned long mpc10x_get_mem_size(uint mem_map);
int mpc10x_enable_store_gathering(struct pci_controller *hose);
int mpc10x_disable_store_gathering(struct pci_controller *hose);
/* For MPC107 boards that use the built-in openpic */
void mpc10x_set_openpic(void);
#endif /* __PPC_KERNEL_MPC10X_H */

View file

@ -0,0 +1,207 @@
/*
* mpc7448_hpc2.c
*
* Board setup routines for the Freescale mpc7448hpc2(taiga) platform
*
* Author: Jacob Pan
* jacob.pan@freescale.com
* Author: Xianghua Xiao
* x.xiao@freescale.com
* Maintainer: Roy Zang <tie-fei.zang@freescale.com>
* Add Flat Device Tree support fot mpc7448hpc2 board
*
* Copyright 2004-2006 Freescale Semiconductor, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/kdev_t.h>
#include <linux/console.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/root_dev.h>
#include <linux/serial.h>
#include <linux/tty.h>
#include <linux/serial_core.h>
#include <asm/time.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/tsi108.h>
#include <asm/pci-bridge.h>
#include <asm/reg.h>
#include <mm/mmu_decl.h>
#include <asm/tsi108_pci.h>
#include <asm/tsi108_irq.h>
#include <asm/mpic.h>
#undef DEBUG
#ifdef DEBUG
#define DBG(fmt...) do { printk(fmt); } while(0)
#else
#define DBG(fmt...) do { } while(0)
#endif
#define MPC7448HPC2_PCI_CFG_PHYS 0xfb000000
int mpc7448_hpc2_exclude_device(struct pci_controller *hose,
u_char bus, u_char devfn)
{
if (bus == 0 && PCI_SLOT(devfn) == 0)
return PCIBIOS_DEVICE_NOT_FOUND;
else
return PCIBIOS_SUCCESSFUL;
}
static void __init mpc7448_hpc2_setup_arch(void)
{
struct device_node *np;
if (ppc_md.progress)
ppc_md.progress("mpc7448_hpc2_setup_arch():set_bridge", 0);
tsi108_csr_vir_base = get_vir_csrbase();
/* setup PCI host bridge */
#ifdef CONFIG_PCI
for_each_compatible_node(np, "pci", "tsi108-pci")
tsi108_setup_pci(np, MPC7448HPC2_PCI_CFG_PHYS, 0);
ppc_md.pci_exclude_device = mpc7448_hpc2_exclude_device;
if (ppc_md.progress)
ppc_md.progress("tsi108: resources set", 0x100);
#endif
printk(KERN_INFO "MPC7448HPC2 (TAIGA) Platform\n");
printk(KERN_INFO
"Jointly ported by Freescale and Tundra Semiconductor\n");
printk(KERN_INFO
"Enabling L2 cache then enabling the HID0 prefetch engine.\n");
}
/*
* Interrupt setup and service. Interrupts on the mpc7448_hpc2 come
* from the four external INT pins, PCI interrupts are routed via
* PCI interrupt control registers, it generates internal IRQ23
*
* Interrupt routing on the Taiga Board:
* TSI108:PB_INT[0] -> CPU0:INT#
* TSI108:PB_INT[1] -> CPU0:MCP#
* TSI108:PB_INT[2] -> N/C
* TSI108:PB_INT[3] -> N/C
*/
static void __init mpc7448_hpc2_init_IRQ(void)
{
struct mpic *mpic;
#ifdef CONFIG_PCI
unsigned int cascade_pci_irq;
struct device_node *tsi_pci;
struct device_node *cascade_node = NULL;
#endif
mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
MPIC_SPV_EOI | MPIC_NO_PTHROU_DIS | MPIC_REGSET_TSI108,
24, 0,
"Tsi108_PIC");
BUG_ON(mpic == NULL);
mpic_assign_isu(mpic, 0, mpic->paddr + 0x100);
mpic_init(mpic);
#ifdef CONFIG_PCI
tsi_pci = of_find_node_by_type(NULL, "pci");
if (tsi_pci == NULL) {
printk("%s: No tsi108 pci node found !\n", __func__);
return;
}
cascade_node = of_find_node_by_type(NULL, "pic-router");
if (cascade_node == NULL) {
printk("%s: No tsi108 pci cascade node found !\n", __func__);
return;
}
cascade_pci_irq = irq_of_parse_and_map(tsi_pci, 0);
DBG("%s: tsi108 cascade_pci_irq = 0x%x\n", __func__,
(u32) cascade_pci_irq);
tsi108_pci_int_init(cascade_node);
irq_set_handler_data(cascade_pci_irq, mpic);
irq_set_chained_handler(cascade_pci_irq, tsi108_irq_cascade);
#endif
/* Configure MPIC outputs to CPU0 */
tsi108_write_reg(TSI108_MPIC_OFFSET + 0x30c, 0);
}
void mpc7448_hpc2_show_cpuinfo(struct seq_file *m)
{
seq_printf(m, "vendor\t\t: Freescale Semiconductor\n");
}
void mpc7448_hpc2_restart(char *cmd)
{
local_irq_disable();
/* Set exception prefix high - to the firmware */
_nmask_and_or_msr(0, MSR_IP);
for (;;) ; /* Spin until reset happens */
}
void mpc7448_hpc2_power_off(void)
{
local_irq_disable();
for (;;) ; /* No way to shut power off with software */
}
void mpc7448_hpc2_halt(void)
{
mpc7448_hpc2_power_off();
}
/*
* Called very early, device-tree isn't unflattened
*/
static int __init mpc7448_hpc2_probe(void)
{
unsigned long root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(root, "mpc74xx"))
return 0;
return 1;
}
static int mpc7448_machine_check_exception(struct pt_regs *regs)
{
const struct exception_table_entry *entry;
/* Are we prepared to handle this fault */
if ((entry = search_exception_tables(regs->nip)) != NULL) {
tsi108_clear_pci_cfg_error();
regs->msr |= MSR_RI;
regs->nip = entry->fixup;
return 1;
}
return 0;
}
define_machine(mpc7448_hpc2){
.name = "MPC7448 HPC2",
.probe = mpc7448_hpc2_probe,
.setup_arch = mpc7448_hpc2_setup_arch,
.init_IRQ = mpc7448_hpc2_init_IRQ,
.show_cpuinfo = mpc7448_hpc2_show_cpuinfo,
.get_irq = mpic_get_irq,
.restart = mpc7448_hpc2_restart,
.calibrate_decr = generic_calibrate_decr,
.machine_check_exception= mpc7448_machine_check_exception,
.progress = udbg_progress,
};

View file

@ -0,0 +1,221 @@
/*
* Board setup routines for the Motorola/Emerson MVME5100.
*
* Copyright 2013 CSC Australia Pty. Ltd.
*
* Based on earlier code by:
*
* Matt Porter, MontaVista Software Inc.
* Copyright 2001 MontaVista Software Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* Author: Stephen Chivers <schivers@csc.com>
*
*/
#include <linux/of_platform.h>
#include <asm/i8259.h>
#include <asm/pci-bridge.h>
#include <asm/mpic.h>
#include <asm/prom.h>
#include <mm/mmu_decl.h>
#include <asm/udbg.h>
#define HAWK_MPIC_SIZE 0x00040000U
#define MVME5100_PCI_MEM_OFFSET 0x00000000
/* Board register addresses. */
#define BOARD_STATUS_REG 0xfef88080
#define BOARD_MODFAIL_REG 0xfef88090
#define BOARD_MODRST_REG 0xfef880a0
#define BOARD_TBEN_REG 0xfef880c0
#define BOARD_SW_READ_REG 0xfef880e0
#define BOARD_GEO_ADDR_REG 0xfef880e8
#define BOARD_EXT_FEATURE1_REG 0xfef880f0
#define BOARD_EXT_FEATURE2_REG 0xfef88100
static phys_addr_t pci_membase;
static u_char *restart;
static void mvme5100_8259_cascade(unsigned int irq, struct irq_desc *desc)
{
struct irq_chip *chip = irq_desc_get_chip(desc);
unsigned int cascade_irq = i8259_irq();
if (cascade_irq != NO_IRQ)
generic_handle_irq(cascade_irq);
chip->irq_eoi(&desc->irq_data);
}
static void __init mvme5100_pic_init(void)
{
struct mpic *mpic;
struct device_node *np;
struct device_node *cp = NULL;
unsigned int cirq;
unsigned long intack = 0;
const u32 *prop = NULL;
np = of_find_node_by_type(NULL, "open-pic");
if (!np) {
pr_err("Could not find open-pic node\n");
return;
}
mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC ");
BUG_ON(mpic == NULL);
of_node_put(np);
mpic_assign_isu(mpic, 0, pci_membase + 0x10000);
mpic_init(mpic);
cp = of_find_compatible_node(NULL, NULL, "chrp,iic");
if (cp == NULL) {
pr_warn("mvme5100_pic_init: couldn't find i8259\n");
return;
}
cirq = irq_of_parse_and_map(cp, 0);
if (cirq == NO_IRQ) {
pr_warn("mvme5100_pic_init: no cascade interrupt?\n");
return;
}
np = of_find_compatible_node(NULL, "pci", "mpc10x-pci");
if (np) {
prop = of_get_property(np, "8259-interrupt-acknowledge", NULL);
if (prop)
intack = prop[0];
of_node_put(np);
}
if (intack)
pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n",
intack);
i8259_init(cp, intack);
of_node_put(cp);
irq_set_chained_handler(cirq, mvme5100_8259_cascade);
}
static int __init mvme5100_add_bridge(struct device_node *dev)
{
const int *bus_range;
int len;
struct pci_controller *hose;
unsigned short devid;
pr_info("Adding PCI host bridge %s\n", dev->full_name);
bus_range = of_get_property(dev, "bus-range", &len);
hose = pcibios_alloc_controller(dev);
if (hose == NULL)
return -ENOMEM;
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0);
pci_process_bridge_OF_ranges(hose, dev, 1);
early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid);
if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) {
pr_err("HAWK PHB not present?\n");
return 0;
}
early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
if (pci_membase == 0) {
pr_err("HAWK PHB mibar not correctly set?\n");
return 0;
}
pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase);
return 0;
}
static const struct of_device_id mvme5100_of_bus_ids[] __initconst = {
{ .compatible = "hawk-bridge", },
{},
};
/*
* Setup the architecture
*/
static void __init mvme5100_setup_arch(void)
{
struct device_node *np;
if (ppc_md.progress)
ppc_md.progress("mvme5100_setup_arch()", 0);
for_each_compatible_node(np, "pci", "hawk-pci")
mvme5100_add_bridge(np);
restart = ioremap(BOARD_MODRST_REG, 4);
}
static void mvme5100_show_cpuinfo(struct seq_file *m)
{
seq_puts(m, "Vendor\t\t: Motorola/Emerson\n");
seq_puts(m, "Machine\t\t: MVME5100\n");
}
static void mvme5100_restart(char *cmd)
{
local_irq_disable();
mtmsr(mfmsr() | MSR_IP);
out_8((u_char *) restart, 0x01);
while (1)
;
}
/*
* Called very early, device-tree isn't unflattened
*/
static int __init mvme5100_probe(void)
{
unsigned long root = of_get_flat_dt_root();
return of_flat_dt_is_compatible(root, "MVME5100");
}
static int __init probe_of_platform_devices(void)
{
of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL);
return 0;
}
machine_device_initcall(mvme5100, probe_of_platform_devices);
define_machine(mvme5100) {
.name = "MVME5100",
.probe = mvme5100_probe,
.setup_arch = mvme5100_setup_arch,
.init_IRQ = mvme5100_pic_init,
.show_cpuinfo = mvme5100_show_cpuinfo,
.get_irq = mpic_get_irq,
.restart = mvme5100_restart,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
};

View file

@ -0,0 +1,125 @@
/*
* Board setup routines for the storcenter
*
* Copyright 2007 (C) Oyvind Repvik (nail@nslu2-linux.org)
* Copyright 2007 Andy Wilcox, Jon Loeliger
*
* Based on linkstation.c by G. Liakhovetski
*
* 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/kernel.h>
#include <linux/pci.h>
#include <linux/initrd.h>
#include <linux/of_platform.h>
#include <asm/time.h>
#include <asm/prom.h>
#include <asm/mpic.h>
#include <asm/pci-bridge.h>
#include "mpc10x.h"
static const struct of_device_id storcenter_of_bus[] __initconst = {
{ .name = "soc", },
{},
};
static int __init storcenter_device_probe(void)
{
of_platform_bus_probe(NULL, storcenter_of_bus, NULL);
return 0;
}
machine_device_initcall(storcenter, storcenter_device_probe);
static int __init storcenter_add_bridge(struct device_node *dev)
{
#ifdef CONFIG_PCI
int len;
struct pci_controller *hose;
const int *bus_range;
printk("Adding PCI host bridge %s\n", dev->full_name);
hose = pcibios_alloc_controller(dev);
if (hose == NULL)
return -ENOMEM;
bus_range = of_get_property(dev, "bus-range", &len);
hose->first_busno = bus_range ? bus_range[0] : 0;
hose->last_busno = bus_range ? bus_range[1] : 0xff;
setup_indirect_pci(hose, MPC10X_MAPB_CNFG_ADDR, MPC10X_MAPB_CNFG_DATA, 0);
/* Interpret the "ranges" property */
/* This also maps the I/O region and sets isa_io/mem_base */
pci_process_bridge_OF_ranges(hose, dev, 1);
#endif
return 0;
}
static void __init storcenter_setup_arch(void)
{
struct device_node *np;
/* Lookup PCI host bridges */
for_each_compatible_node(np, "pci", "mpc10x-pci")
storcenter_add_bridge(np);
printk(KERN_INFO "IOMEGA StorCenter\n");
}
/*
* Interrupt setup and service. Interrupts on the turbostation come
* from the four PCI slots plus onboard 8241 devices: I2C, DUART.
*/
static void __init storcenter_init_IRQ(void)
{
struct mpic *mpic;
mpic = mpic_alloc(NULL, 0, 0, 16, 0, " OpenPIC ");
BUG_ON(mpic == NULL);
/*
* 16 Serial Interrupts followed by 16 Internal Interrupts.
* I2C is the second internal, so it is at 17, 0x11020.
*/
mpic_assign_isu(mpic, 0, mpic->paddr + 0x10200);
mpic_assign_isu(mpic, 1, mpic->paddr + 0x11000);
mpic_init(mpic);
}
static void storcenter_restart(char *cmd)
{
local_irq_disable();
/* Set exception prefix high - to the firmware */
_nmask_and_or_msr(0, MSR_IP);
/* Wait for reset to happen */
for (;;) ;
}
static int __init storcenter_probe(void)
{
unsigned long root = of_get_flat_dt_root();
return of_flat_dt_is_compatible(root, "iomega,storcenter");
}
define_machine(storcenter){
.name = "IOMEGA StorCenter",
.probe = storcenter_probe,
.setup_arch = storcenter_setup_arch,
.init_IRQ = storcenter_init_IRQ,
.get_irq = mpic_get_irq,
.restart = storcenter_restart,
.calibrate_decr = generic_calibrate_decr,
};

View file

@ -0,0 +1,328 @@
/*
* arch/powerpc/platforms/embedded6xx/usbgecko_udbg.c
*
* udbg serial input/output routines for the USB Gecko adapter.
* Copyright (C) 2008-2009 The GameCube Linux Team
* Copyright (C) 2008,2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#include <mm/mmu_decl.h>
#include <asm/io.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/fixmap.h>
#include "usbgecko_udbg.h"
#define EXI_CLK_32MHZ 5
#define EXI_CSR 0x00
#define EXI_CSR_CLKMASK (0x7<<4)
#define EXI_CSR_CLK_32MHZ (EXI_CLK_32MHZ<<4)
#define EXI_CSR_CSMASK (0x7<<7)
#define EXI_CSR_CS_0 (0x1<<7) /* Chip Select 001 */
#define EXI_CR 0x0c
#define EXI_CR_TSTART (1<<0)
#define EXI_CR_WRITE (1<<2)
#define EXI_CR_READ_WRITE (2<<2)
#define EXI_CR_TLEN(len) (((len)-1)<<4)
#define EXI_DATA 0x10
#define UG_READ_ATTEMPTS 100
#define UG_WRITE_ATTEMPTS 100
static void __iomem *ug_io_base;
/*
* Performs one input/output transaction between the exi host and the usbgecko.
*/
static u32 ug_io_transaction(u32 in)
{
u32 __iomem *csr_reg = ug_io_base + EXI_CSR;
u32 __iomem *data_reg = ug_io_base + EXI_DATA;
u32 __iomem *cr_reg = ug_io_base + EXI_CR;
u32 csr, data, cr;
/* select */
csr = EXI_CSR_CLK_32MHZ | EXI_CSR_CS_0;
out_be32(csr_reg, csr);
/* read/write */
data = in;
out_be32(data_reg, data);
cr = EXI_CR_TLEN(2) | EXI_CR_READ_WRITE | EXI_CR_TSTART;
out_be32(cr_reg, cr);
while (in_be32(cr_reg) & EXI_CR_TSTART)
barrier();
/* deselect */
out_be32(csr_reg, 0);
/* result */
data = in_be32(data_reg);
return data;
}
/*
* Returns true if an usbgecko adapter is found.
*/
static int ug_is_adapter_present(void)
{
if (!ug_io_base)
return 0;
return ug_io_transaction(0x90000000) == 0x04700000;
}
/*
* Returns true if the TX fifo is ready for transmission.
*/
static int ug_is_txfifo_ready(void)
{
return ug_io_transaction(0xc0000000) & 0x04000000;
}
/*
* Tries to transmit a character.
* If the TX fifo is not ready the result is undefined.
*/
static void ug_raw_putc(char ch)
{
ug_io_transaction(0xb0000000 | (ch << 20));
}
/*
* Transmits a character.
* It silently fails if the TX fifo is not ready after a number of retries.
*/
static void ug_putc(char ch)
{
int count = UG_WRITE_ATTEMPTS;
if (!ug_io_base)
return;
if (ch == '\n')
ug_putc('\r');
while (!ug_is_txfifo_ready() && count--)
barrier();
if (count >= 0)
ug_raw_putc(ch);
}
/*
* Returns true if the RX fifo is ready for transmission.
*/
static int ug_is_rxfifo_ready(void)
{
return ug_io_transaction(0xd0000000) & 0x04000000;
}
/*
* Tries to receive a character.
* If a character is unavailable the function returns -1.
*/
static int ug_raw_getc(void)
{
u32 data = ug_io_transaction(0xa0000000);
if (data & 0x08000000)
return (data >> 16) & 0xff;
else
return -1;
}
/*
* Receives a character.
* It fails if the RX fifo is not ready after a number of retries.
*/
static int ug_getc(void)
{
int count = UG_READ_ATTEMPTS;
if (!ug_io_base)
return -1;
while (!ug_is_rxfifo_ready() && count--)
barrier();
return ug_raw_getc();
}
/*
* udbg functions.
*
*/
/*
* Transmits a character.
*/
void ug_udbg_putc(char ch)
{
ug_putc(ch);
}
/*
* Receives a character. Waits until a character is available.
*/
static int ug_udbg_getc(void)
{
int ch;
while ((ch = ug_getc()) == -1)
barrier();
return ch;
}
/*
* Receives a character. If a character is not available, returns -1.
*/
static int ug_udbg_getc_poll(void)
{
if (!ug_is_rxfifo_ready())
return -1;
return ug_getc();
}
/*
* Retrieves and prepares the virtual address needed to access the hardware.
*/
static void __iomem *ug_udbg_setup_exi_io_base(struct device_node *np)
{
void __iomem *exi_io_base = NULL;
phys_addr_t paddr;
const unsigned int *reg;
reg = of_get_property(np, "reg", NULL);
if (reg) {
paddr = of_translate_address(np, reg);
if (paddr)
exi_io_base = ioremap(paddr, reg[1]);
}
return exi_io_base;
}
/*
* Checks if a USB Gecko adapter is inserted in any memory card slot.
*/
static void __iomem *ug_udbg_probe(void __iomem *exi_io_base)
{
int i;
/* look for a usbgecko on memcard slots A and B */
for (i = 0; i < 2; i++) {
ug_io_base = exi_io_base + 0x14 * i;
if (ug_is_adapter_present())
break;
}
if (i == 2)
ug_io_base = NULL;
return ug_io_base;
}
/*
* USB Gecko udbg support initialization.
*/
void __init ug_udbg_init(void)
{
struct device_node *np;
void __iomem *exi_io_base;
if (ug_io_base)
udbg_printf("%s: early -> final\n", __func__);
np = of_find_compatible_node(NULL, NULL, "nintendo,flipper-exi");
if (!np) {
udbg_printf("%s: EXI node not found\n", __func__);
goto done;
}
exi_io_base = ug_udbg_setup_exi_io_base(np);
if (!exi_io_base) {
udbg_printf("%s: failed to setup EXI io base\n", __func__);
goto done;
}
if (!ug_udbg_probe(exi_io_base)) {
udbg_printf("usbgecko_udbg: not found\n");
iounmap(exi_io_base);
} else {
udbg_putc = ug_udbg_putc;
udbg_getc = ug_udbg_getc;
udbg_getc_poll = ug_udbg_getc_poll;
udbg_printf("usbgecko_udbg: ready\n");
}
done:
if (np)
of_node_put(np);
return;
}
#ifdef CONFIG_PPC_EARLY_DEBUG_USBGECKO
static phys_addr_t __init ug_early_grab_io_addr(void)
{
#if defined(CONFIG_GAMECUBE)
return 0x0c000000;
#elif defined(CONFIG_WII)
return 0x0d000000;
#else
#error Invalid platform for USB Gecko based early debugging.
#endif
}
/*
* USB Gecko early debug support initialization for udbg.
*/
void __init udbg_init_usbgecko(void)
{
void __iomem *early_debug_area;
void __iomem *exi_io_base;
/*
* At this point we have a BAT already setup that enables I/O
* to the EXI hardware.
*
* The BAT uses a virtual address range reserved at the fixmap.
* This must match the virtual address configured in
* head_32.S:setup_usbgecko_bat().
*/
early_debug_area = (void __iomem *)__fix_to_virt(FIX_EARLY_DEBUG_BASE);
exi_io_base = early_debug_area + 0x00006800;
/* try to detect a USB Gecko */
if (!ug_udbg_probe(exi_io_base))
return;
/* we found a USB Gecko, load udbg hooks */
udbg_putc = ug_udbg_putc;
udbg_getc = ug_udbg_getc;
udbg_getc_poll = ug_udbg_getc_poll;
/*
* Prepare again the same BAT for MMU_init.
* This allows udbg I/O to continue working after the MMU is
* turned on for real.
* It is safe to continue using the same virtual address as it is
* a reserved fixmap area.
*/
setbat(1, (unsigned long)early_debug_area,
ug_early_grab_io_addr(), 128*1024, PAGE_KERNEL_NCG);
}
#endif /* CONFIG_PPC_EARLY_DEBUG_USBGECKO */

View file

@ -0,0 +1,32 @@
/*
* arch/powerpc/platforms/embedded6xx/usbgecko_udbg.h
*
* udbg serial input/output routines for the USB Gecko adapter.
* Copyright (C) 2008-2009 The GameCube Linux Team
* Copyright (C) 2008,2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#ifndef __USBGECKO_UDBG_H
#define __USBGECKO_UDBG_H
#ifdef CONFIG_USBGECKO_UDBG
extern void __init ug_udbg_init(void);
#else
static inline void __init ug_udbg_init(void)
{
}
#endif /* CONFIG_USBGECKO_UDBG */
void __init udbg_init_usbgecko(void);
#endif /* __USBGECKO_UDBG_H */

View file

@ -0,0 +1,252 @@
/*
* arch/powerpc/platforms/embedded6xx/wii.c
*
* Nintendo Wii board-specific support
* Copyright (C) 2008-2009 The GameCube Linux Team
* Copyright (C) 2008,2009 Albert Herranz
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
*/
#define DRV_MODULE_NAME "wii"
#define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/irq.h>
#include <linux/seq_file.h>
#include <linux/of_platform.h>
#include <linux/memblock.h>
#include <mm/mmu_decl.h>
#include <asm/io.h>
#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/time.h>
#include <asm/udbg.h>
#include "flipper-pic.h"
#include "hlwd-pic.h"
#include "usbgecko_udbg.h"
/* control block */
#define HW_CTRL_COMPATIBLE "nintendo,hollywood-control"
#define HW_CTRL_RESETS 0x94
#define HW_CTRL_RESETS_SYS (1<<0)
/* gpio */
#define HW_GPIO_COMPATIBLE "nintendo,hollywood-gpio"
#define HW_GPIO_BASE(idx) (idx * 0x20)
#define HW_GPIO_OUT(idx) (HW_GPIO_BASE(idx) + 0)
#define HW_GPIO_DIR(idx) (HW_GPIO_BASE(idx) + 4)
#define HW_GPIO_SHUTDOWN (1<<1)
#define HW_GPIO_SLOT_LED (1<<5)
#define HW_GPIO_SENSOR_BAR (1<<8)
static void __iomem *hw_ctrl;
static void __iomem *hw_gpio;
unsigned long wii_hole_start;
unsigned long wii_hole_size;
static int __init page_aligned(unsigned long x)
{
return !(x & (PAGE_SIZE-1));
}
void __init wii_memory_fixups(void)
{
struct memblock_region *p = memblock.memory.regions;
/*
* This is part of a workaround to allow the use of two
* discontinuous RAM ranges on the Wii, even if this is
* currently unsupported on 32-bit PowerPC Linux.
*
* We coalesce the two memory ranges of the Wii into a
* single range, then create a reservation for the "hole"
* between both ranges.
*/
BUG_ON(memblock.memory.cnt != 2);
BUG_ON(!page_aligned(p[0].base) || !page_aligned(p[1].base));
/* trim unaligned tail */
memblock_remove(ALIGN(p[1].base + p[1].size, PAGE_SIZE),
(phys_addr_t)ULLONG_MAX);
/* determine hole, add & reserve them */
wii_hole_start = ALIGN(p[0].base + p[0].size, PAGE_SIZE);
wii_hole_size = p[1].base - wii_hole_start;
memblock_add(wii_hole_start, wii_hole_size);
memblock_reserve(wii_hole_start, wii_hole_size);
BUG_ON(memblock.memory.cnt != 1);
__memblock_dump_all();
/* allow ioremapping the address space in the hole */
__allow_ioremap_reserved = 1;
}
unsigned long __init wii_mmu_mapin_mem2(unsigned long top)
{
unsigned long delta, size, bl;
unsigned long max_size = (256<<20);
/* MEM2 64MB@0x10000000 */
delta = wii_hole_start + wii_hole_size;
size = top - delta;
for (bl = 128<<10; bl < max_size; bl <<= 1) {
if (bl * 2 > size)
break;
}
setbat(4, PAGE_OFFSET+delta, delta, bl, PAGE_KERNEL_X);
return delta + bl;
}
static void wii_spin(void)
{
local_irq_disable();
for (;;)
cpu_relax();
}
static void __iomem *wii_ioremap_hw_regs(char *name, char *compatible)
{
void __iomem *hw_regs = NULL;
struct device_node *np;
struct resource res;
int error = -ENODEV;
np = of_find_compatible_node(NULL, NULL, compatible);
if (!np) {
pr_err("no compatible node found for %s\n", compatible);
goto out;
}
error = of_address_to_resource(np, 0, &res);
if (error) {
pr_err("no valid reg found for %s\n", np->name);
goto out_put;
}
hw_regs = ioremap(res.start, resource_size(&res));
if (hw_regs) {
pr_info("%s at 0x%08x mapped to 0x%p\n", name,
res.start, hw_regs);
}
out_put:
of_node_put(np);
out:
return hw_regs;
}
static void __init wii_setup_arch(void)
{
hw_ctrl = wii_ioremap_hw_regs("hw_ctrl", HW_CTRL_COMPATIBLE);
hw_gpio = wii_ioremap_hw_regs("hw_gpio", HW_GPIO_COMPATIBLE);
if (hw_gpio) {
/* turn off the front blue led and IR light */
clrbits32(hw_gpio + HW_GPIO_OUT(0),
HW_GPIO_SLOT_LED | HW_GPIO_SENSOR_BAR);
}
}
static void wii_restart(char *cmd)
{
local_irq_disable();
if (hw_ctrl) {
/* clear the system reset pin to cause a reset */
clrbits32(hw_ctrl + HW_CTRL_RESETS, HW_CTRL_RESETS_SYS);
}
wii_spin();
}
static void wii_power_off(void)
{
local_irq_disable();
if (hw_gpio) {
/* make sure that the poweroff GPIO is configured as output */
setbits32(hw_gpio + HW_GPIO_DIR(1), HW_GPIO_SHUTDOWN);
/* drive the poweroff GPIO high */
setbits32(hw_gpio + HW_GPIO_OUT(1), HW_GPIO_SHUTDOWN);
}
wii_spin();
}
static void wii_halt(void)
{
if (ppc_md.restart)
ppc_md.restart(NULL);
wii_spin();
}
static void __init wii_init_early(void)
{
ug_udbg_init();
}
static void __init wii_pic_probe(void)
{
flipper_pic_probe();
hlwd_pic_probe();
}
static int __init wii_probe(void)
{
unsigned long dt_root;
dt_root = of_get_flat_dt_root();
if (!of_flat_dt_is_compatible(dt_root, "nintendo,wii"))
return 0;
return 1;
}
static void wii_shutdown(void)
{
hlwd_quiesce();
flipper_quiesce();
}
define_machine(wii) {
.name = "wii",
.probe = wii_probe,
.init_early = wii_init_early,
.setup_arch = wii_setup_arch,
.restart = wii_restart,
.power_off = wii_power_off,
.halt = wii_halt,
.init_IRQ = wii_pic_probe,
.get_irq = flipper_pic_get_irq,
.calibrate_decr = generic_calibrate_decr,
.progress = udbg_progress,
.machine_shutdown = wii_shutdown,
};
static const struct of_device_id wii_of_bus[] = {
{ .compatible = "nintendo,hollywood", },
{ },
};
static int __init wii_device_probe(void)
{
if (!machine_is(wii))
return 0;
of_platform_bus_probe(NULL, wii_of_bus, NULL);
return 0;
}
device_initcall(wii_device_probe);