ppc476.c 7.3 KB
Newer Older
1
/*
2
 * PowerPC 476FPE board specific routines
3
 *
4 5
 * Copyright © 2013 Tony Breeds IBM Corporation
 * Copyright © 2013 Alistair Popple IBM Corporation
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
 *
 * Based on earlier code:
 *    Matt Porter <mporter@kernel.crashing.org>
 *    Copyright 2002-2005 MontaVista Software Inc.
 *
 *    Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
 *    Copyright (c) 2003-2005 Zultys Technologies
 *
 *    Rewritten and ported to the merged powerpc tree:
 *    Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
 *    Copyright © 2011 David Kliekamp IBM Corporation
 *
 * 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/init.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/rtc.h>

#include <asm/machdep.h>
#include <asm/prom.h>
#include <asm/udbg.h>
#include <asm/time.h>
#include <asm/uic.h>
#include <asm/ppc4xx.h>
#include <asm/mpic.h>
#include <asm/mmu.h>

#include <linux/pci.h>
39
#include <linux/i2c.h>
40

41
static const struct of_device_id ppc47x_of_bus[] __initconst = {
42 43 44 45 46 47 48 49 50
	{ .compatible = "ibm,plb4", },
	{ .compatible = "ibm,plb6", },
	{ .compatible = "ibm,opb", },
	{ .compatible = "ibm,ebc", },
	{},
};

/* The EEPROM is missing and the default values are bogus.  This forces USB in
 * to EHCI mode */
51
static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
52 53 54 55 56 57 58 59
{
	if (of_machine_is_compatible("ibm,currituck")) {
		pci_write_config_dword(dev, 0xe0, 0x0114231f);
		pci_write_config_dword(dev, 0xe4, 0x00006c40);
	}
}
DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);

60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
/* Akebono has an AVR microcontroller attached to the I2C bus
 * which is used to power off/reset the system. */

/* AVR I2C Commands */
#define AVR_PWRCTL_CMD (0x26)

/* Flags for the power control I2C commands */
#define AVR_PWRCTL_PWROFF (0x01)
#define AVR_PWRCTL_RESET (0x02)

static struct i2c_client *avr_i2c_client;
static void avr_halt_system(int pwrctl_flags)
{
	/* Request the AVR to reset the system */
	i2c_smbus_write_byte_data(avr_i2c_client,
				  AVR_PWRCTL_CMD, pwrctl_flags);

	/* Wait for system to be reset */
	while (1)
		;
}

static void avr_power_off_system(void)
{
	avr_halt_system(AVR_PWRCTL_PWROFF);
}

static void avr_reset_system(char *cmd)
{
	avr_halt_system(AVR_PWRCTL_RESET);
}

static int avr_probe(struct i2c_client *client,
			    const struct i2c_device_id *id)
{
	avr_i2c_client = client;
	ppc_md.restart = avr_reset_system;
97
	pm_power_off = avr_power_off_system;
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
	return 0;
}

static const struct i2c_device_id avr_id[] = {
	{ "akebono-avr", 0 },
	{ }
};

static struct i2c_driver avr_driver = {
	.driver = {
		.name = "akebono-avr",
	},
	.probe = avr_probe,
	.id_table = avr_id,
};

114 115
static int __init ppc47x_device_probe(void)
{
116
	i2c_add_driver(&avr_driver);
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
	of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);

	return 0;
}
machine_device_initcall(ppc47x, ppc47x_device_probe);

static void __init ppc47x_init_irq(void)
{
	struct device_node *np;

	/* Find top level interrupt controller */
	for_each_node_with_property(np, "interrupt-controller") {
		if (of_get_property(np, "interrupts", NULL) == NULL)
			break;
	}
	if (np == NULL)
		panic("Can't find top level interrupt controller");

	/* Check type and do appropriate initialization */
	if (of_device_is_compatible(np, "chrp,open-pic")) {
		/* The MPIC driver will get everything it needs from the
		 * device-tree, just pass 0 to all arguments
		 */
		struct mpic *mpic =
141
			mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");
142 143 144 145 146 147 148 149
		BUG_ON(mpic == NULL);
		mpic_init(mpic);
		ppc_md.get_irq = mpic_get_irq;
	} else
		panic("Unrecognized top level interrupt controller");
}

#ifdef CONFIG_SMP
150
static void smp_ppc47x_setup_cpu(int cpu)
151 152 153 154
{
	mpic_setup_this_cpu();
}

155
static int smp_ppc47x_kick_cpu(int cpu)
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
{
	struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
	const u64 *spin_table_addr_prop;
	u32 *spin_table;
	extern void start_secondary_47x(void);

	BUG_ON(cpunode == NULL);

	/* Assume spin table. We could test for the enable-method in
	 * the device-tree but currently there's little point as it's
	 * our only supported method
	 */
	spin_table_addr_prop =
		of_get_property(cpunode, "cpu-release-addr", NULL);

	if (spin_table_addr_prop == NULL) {
		pr_err("CPU%d: Can't start, missing cpu-release-addr !\n",
		       cpu);
		return 1;
	}

	/* Assume it's mapped as part of the linear mapping. This is a bit
	 * fishy but will work fine for now
	 *
	 * XXX: Is there any reason to assume differently?
	 */
	spin_table = (u32 *)__va(*spin_table_addr_prop);
	pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table);

	spin_table[3] = cpu;
	smp_wmb();
	spin_table[1] = __pa(start_secondary_47x);
	mb();

	return 0;
}

static struct smp_ops_t ppc47x_smp_ops = {
	.probe		= smp_mpic_probe,
	.message_pass	= smp_mpic_message_pass,
	.setup_cpu	= smp_ppc47x_setup_cpu,
	.kick_cpu	= smp_ppc47x_kick_cpu,
	.give_timebase	= smp_generic_give_timebase,
	.take_timebase	= smp_generic_take_timebase,
};

static void __init ppc47x_smp_init(void)
{
	if (mmu_has_feature(MMU_FTR_TYPE_47x))
		smp_ops = &ppc47x_smp_ops;
}

#else /* CONFIG_SMP */
static void __init ppc47x_smp_init(void) { }
#endif /* CONFIG_SMP */

static void __init ppc47x_setup_arch(void)
{

	/* No need to check the DMA config as we /know/ our windows are all of
216
	 * RAM.  Lets hope that doesn't change */
217 218
	swiotlb_detect_4g();

219 220 221
	ppc47x_smp_init();
}

222 223 224
static int board_rev = -1;
static int __init ppc47x_get_board_rev(void)
{
225 226 227 228 229 230 231 232 233 234 235
	int reg;
	u8 *fpga;
	struct device_node *np = NULL;

	if (of_machine_is_compatible("ibm,currituck")) {
		np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
		reg = 0;
	} else if (of_machine_is_compatible("ibm,akebono")) {
		np = of_find_compatible_node(NULL, NULL, "ibm,akebono-fpga");
		reg = 2;
	}
236 237 238 239

	if (!np)
		goto fail;

240
	fpga = (u8 *) of_iomap(np, 0);
241 242 243 244
	of_node_put(np);
	if (!fpga)
		goto fail;

245
	board_rev = ioread8(fpga + reg) & 0x03;
246 247 248 249 250 251 252 253 254 255
	pr_info("%s: Found board revision %d\n", __func__, board_rev);
	iounmap(fpga);
	return 0;

fail:
	pr_info("%s: Unable to find board revision\n", __func__);
	return 0;
}
machine_arch_initcall(ppc47x, ppc47x_get_board_rev);

256 257 258 259
/* Use USB controller should have been hardware swizzled but it wasn't :( */
static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
{
	if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
260
				      dev->device == 0x00e0)) {
261 262 263 264 265 266 267 268 269
		if (board_rev == 0) {
			dev->irq = irq_create_mapping(NULL, 47);
			pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
		} else if (board_rev == 2) {
			dev->irq = irq_create_mapping(NULL, 49);
			pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
		} else {
			pr_alert("%s: Unknown board revision\n", __func__);
		}
270 271 272
	}
}

273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
/*
 * Called very early, MMU is off, device-tree isn't unflattened
 */
static int __init ppc47x_probe(void)
{
	unsigned long root = of_get_flat_dt_root();

	if (of_flat_dt_is_compatible(root, "ibm,akebono"))
		return 1;

	if (of_flat_dt_is_compatible(root, "ibm,currituck")) {
		ppc_md.pci_irq_fixup = ppc47x_pci_irq_fixup;
		return 1;
	}

	return 0;
}

291 292 293 294 295 296 297 298 299
define_machine(ppc47x) {
	.name			= "PowerPC 47x",
	.probe			= ppc47x_probe,
	.progress		= udbg_progress,
	.init_IRQ		= ppc47x_init_irq,
	.setup_arch		= ppc47x_setup_arch,
	.restart		= ppc4xx_reset_system,
	.calibrate_decr		= generic_calibrate_decr,
};