cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ppc476.c (7250B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * PowerPC 476FPE board specific routines
      4 *
      5 * Copyright © 2013 Tony Breeds IBM Corporation
      6 * Copyright © 2013 Alistair Popple IBM Corporation
      7 *
      8 * Based on earlier code:
      9 *    Matt Porter <mporter@kernel.crashing.org>
     10 *    Copyright 2002-2005 MontaVista Software Inc.
     11 *
     12 *    Eugene Surovegin <eugene.surovegin@zultys.com> or <ebs@ebshome.net>
     13 *    Copyright (c) 2003-2005 Zultys Technologies
     14 *
     15 *    Rewritten and ported to the merged powerpc tree:
     16 *    Copyright 2007 David Gibson <dwg@au1.ibm.com>, IBM Corporation.
     17 *    Copyright © 2011 David Kliekamp IBM Corporation
     18 */
     19
     20#include <linux/init.h>
     21#include <linux/of.h>
     22#include <linux/of_address.h>
     23#include <linux/of_platform.h>
     24#include <linux/rtc.h>
     25
     26#include <asm/machdep.h>
     27#include <asm/udbg.h>
     28#include <asm/time.h>
     29#include <asm/uic.h>
     30#include <asm/ppc4xx.h>
     31#include <asm/mpic.h>
     32#include <asm/mmu.h>
     33#include <asm/swiotlb.h>
     34
     35#include <linux/pci.h>
     36#include <linux/i2c.h>
     37
     38static const struct of_device_id ppc47x_of_bus[] __initconst = {
     39	{ .compatible = "ibm,plb4", },
     40	{ .compatible = "ibm,plb6", },
     41	{ .compatible = "ibm,opb", },
     42	{ .compatible = "ibm,ebc", },
     43	{},
     44};
     45
     46/* The EEPROM is missing and the default values are bogus.  This forces USB in
     47 * to EHCI mode */
     48static void quirk_ppc_currituck_usb_fixup(struct pci_dev *dev)
     49{
     50	if (of_machine_is_compatible("ibm,currituck")) {
     51		pci_write_config_dword(dev, 0xe0, 0x0114231f);
     52		pci_write_config_dword(dev, 0xe4, 0x00006c40);
     53	}
     54}
     55DECLARE_PCI_FIXUP_HEADER(0x1033, 0x0035, quirk_ppc_currituck_usb_fixup);
     56
     57/* Akebono has an AVR microcontroller attached to the I2C bus
     58 * which is used to power off/reset the system. */
     59
     60/* AVR I2C Commands */
     61#define AVR_PWRCTL_CMD (0x26)
     62
     63/* Flags for the power control I2C commands */
     64#define AVR_PWRCTL_PWROFF (0x01)
     65#define AVR_PWRCTL_RESET (0x02)
     66
     67static struct i2c_client *avr_i2c_client;
     68static void __noreturn avr_halt_system(int pwrctl_flags)
     69{
     70	/* Request the AVR to reset the system */
     71	i2c_smbus_write_byte_data(avr_i2c_client,
     72				  AVR_PWRCTL_CMD, pwrctl_flags);
     73
     74	/* Wait for system to be reset */
     75	while (1)
     76		;
     77}
     78
     79static void avr_power_off_system(void)
     80{
     81	avr_halt_system(AVR_PWRCTL_PWROFF);
     82}
     83
     84static void __noreturn avr_reset_system(char *cmd)
     85{
     86	avr_halt_system(AVR_PWRCTL_RESET);
     87}
     88
     89static int avr_probe(struct i2c_client *client)
     90{
     91	avr_i2c_client = client;
     92	ppc_md.restart = avr_reset_system;
     93	pm_power_off = avr_power_off_system;
     94	return 0;
     95}
     96
     97static const struct i2c_device_id avr_id[] = {
     98	{ "akebono-avr", 0 },
     99	{ }
    100};
    101
    102static struct i2c_driver avr_driver = {
    103	.driver = {
    104		.name = "akebono-avr",
    105	},
    106	.probe_new = avr_probe,
    107	.id_table = avr_id,
    108};
    109
    110static int __init ppc47x_device_probe(void)
    111{
    112	i2c_add_driver(&avr_driver);
    113	of_platform_bus_probe(NULL, ppc47x_of_bus, NULL);
    114
    115	return 0;
    116}
    117machine_device_initcall(ppc47x, ppc47x_device_probe);
    118
    119static void __init ppc47x_init_irq(void)
    120{
    121	struct device_node *np;
    122
    123	/* Find top level interrupt controller */
    124	for_each_node_with_property(np, "interrupt-controller") {
    125		if (of_get_property(np, "interrupts", NULL) == NULL)
    126			break;
    127	}
    128	if (np == NULL)
    129		panic("Can't find top level interrupt controller");
    130
    131	/* Check type and do appropriate initialization */
    132	if (of_device_is_compatible(np, "chrp,open-pic")) {
    133		/* The MPIC driver will get everything it needs from the
    134		 * device-tree, just pass 0 to all arguments
    135		 */
    136		struct mpic *mpic =
    137			mpic_alloc(np, 0, MPIC_NO_RESET, 0, 0, " MPIC     ");
    138		BUG_ON(mpic == NULL);
    139		mpic_init(mpic);
    140		ppc_md.get_irq = mpic_get_irq;
    141	} else
    142		panic("Unrecognized top level interrupt controller");
    143}
    144
    145#ifdef CONFIG_SMP
    146static void smp_ppc47x_setup_cpu(int cpu)
    147{
    148	mpic_setup_this_cpu();
    149}
    150
    151static int smp_ppc47x_kick_cpu(int cpu)
    152{
    153	struct device_node *cpunode = of_get_cpu_node(cpu, NULL);
    154	const u64 *spin_table_addr_prop;
    155	u32 *spin_table;
    156	extern void start_secondary_47x(void);
    157
    158	BUG_ON(cpunode == NULL);
    159
    160	/* Assume spin table. We could test for the enable-method in
    161	 * the device-tree but currently there's little point as it's
    162	 * our only supported method
    163	 */
    164	spin_table_addr_prop =
    165		of_get_property(cpunode, "cpu-release-addr", NULL);
    166
    167	if (spin_table_addr_prop == NULL) {
    168		pr_err("CPU%d: Can't start, missing cpu-release-addr !\n",
    169		       cpu);
    170		return 1;
    171	}
    172
    173	/* Assume it's mapped as part of the linear mapping. This is a bit
    174	 * fishy but will work fine for now
    175	 *
    176	 * XXX: Is there any reason to assume differently?
    177	 */
    178	spin_table = (u32 *)__va(*spin_table_addr_prop);
    179	pr_debug("CPU%d: Spin table mapped at %p\n", cpu, spin_table);
    180
    181	spin_table[3] = cpu;
    182	smp_wmb();
    183	spin_table[1] = __pa(start_secondary_47x);
    184	mb();
    185
    186	return 0;
    187}
    188
    189static struct smp_ops_t ppc47x_smp_ops = {
    190	.probe		= smp_mpic_probe,
    191	.message_pass	= smp_mpic_message_pass,
    192	.setup_cpu	= smp_ppc47x_setup_cpu,
    193	.kick_cpu	= smp_ppc47x_kick_cpu,
    194	.give_timebase	= smp_generic_give_timebase,
    195	.take_timebase	= smp_generic_take_timebase,
    196};
    197
    198static void __init ppc47x_smp_init(void)
    199{
    200	if (mmu_has_feature(MMU_FTR_TYPE_47x))
    201		smp_ops = &ppc47x_smp_ops;
    202}
    203
    204#else /* CONFIG_SMP */
    205static void __init ppc47x_smp_init(void) { }
    206#endif /* CONFIG_SMP */
    207
    208static void __init ppc47x_setup_arch(void)
    209{
    210
    211	/* No need to check the DMA config as we /know/ our windows are all of
    212	 * RAM.  Lets hope that doesn't change */
    213	swiotlb_detect_4g();
    214
    215	ppc47x_smp_init();
    216}
    217
    218static int board_rev = -1;
    219static int __init ppc47x_get_board_rev(void)
    220{
    221	int reg;
    222	u8 __iomem *fpga;
    223	struct device_node *np = NULL;
    224
    225	if (of_machine_is_compatible("ibm,currituck")) {
    226		np = of_find_compatible_node(NULL, NULL, "ibm,currituck-fpga");
    227		reg = 0;
    228	} else if (of_machine_is_compatible("ibm,akebono")) {
    229		np = of_find_compatible_node(NULL, NULL, "ibm,akebono-fpga");
    230		reg = 2;
    231	}
    232
    233	if (!np)
    234		goto fail;
    235
    236	fpga = of_iomap(np, 0);
    237	of_node_put(np);
    238	if (!fpga)
    239		goto fail;
    240
    241	board_rev = ioread8(fpga + reg) & 0x03;
    242	pr_info("%s: Found board revision %d\n", __func__, board_rev);
    243	iounmap(fpga);
    244	return 0;
    245
    246fail:
    247	pr_info("%s: Unable to find board revision\n", __func__);
    248	return 0;
    249}
    250machine_arch_initcall(ppc47x, ppc47x_get_board_rev);
    251
    252/* Use USB controller should have been hardware swizzled but it wasn't :( */
    253static void ppc47x_pci_irq_fixup(struct pci_dev *dev)
    254{
    255	if (dev->vendor == 0x1033 && (dev->device == 0x0035 ||
    256				      dev->device == 0x00e0)) {
    257		if (board_rev == 0) {
    258			dev->irq = irq_create_mapping(NULL, 47);
    259			pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
    260		} else if (board_rev == 2) {
    261			dev->irq = irq_create_mapping(NULL, 49);
    262			pr_info("%s: Mapping irq %d\n", __func__, dev->irq);
    263		} else {
    264			pr_alert("%s: Unknown board revision\n", __func__);
    265		}
    266	}
    267}
    268
    269/*
    270 * Called very early, MMU is off, device-tree isn't unflattened
    271 */
    272static int __init ppc47x_probe(void)
    273{
    274	if (of_machine_is_compatible("ibm,akebono"))
    275		return 1;
    276
    277	if (of_machine_is_compatible("ibm,currituck")) {
    278		ppc_md.pci_irq_fixup = ppc47x_pci_irq_fixup;
    279		return 1;
    280	}
    281
    282	return 0;
    283}
    284
    285define_machine(ppc47x) {
    286	.name			= "PowerPC 47x",
    287	.probe			= ppc47x_probe,
    288	.progress		= udbg_progress,
    289	.init_IRQ		= ppc47x_init_irq,
    290	.setup_arch		= ppc47x_setup_arch,
    291	.restart		= ppc4xx_reset_system,
    292	.calibrate_decr		= generic_calibrate_decr,
    293};