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

driver_mips.c (9710B)


      1/*
      2 * Broadcom specific AMBA
      3 * Broadcom MIPS32 74K core driver
      4 *
      5 * Copyright 2009, Broadcom Corporation
      6 * Copyright 2006, 2007, Michael Buesch <mb@bu3sch.de>
      7 * Copyright 2010, Bernhard Loos <bernhardloos@googlemail.com>
      8 * Copyright 2011, Hauke Mehrtens <hauke@hauke-m.de>
      9 *
     10 * Licensed under the GNU/GPL. See COPYING for details.
     11 */
     12
     13#include "bcma_private.h"
     14
     15#include <linux/bcma/bcma.h>
     16
     17#include <linux/serial.h>
     18#include <linux/serial_core.h>
     19#include <linux/serial_reg.h>
     20#include <linux/time.h>
     21#ifdef CONFIG_BCM47XX
     22#include <linux/bcm47xx_nvram.h>
     23#endif
     24
     25enum bcma_boot_dev {
     26	BCMA_BOOT_DEV_UNK = 0,
     27	BCMA_BOOT_DEV_ROM,
     28	BCMA_BOOT_DEV_PARALLEL,
     29	BCMA_BOOT_DEV_SERIAL,
     30	BCMA_BOOT_DEV_NAND,
     31};
     32
     33/* The 47162a0 hangs when reading MIPS DMP registers registers */
     34static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
     35{
     36	return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 &&
     37	       dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K;
     38}
     39
     40/* The 5357b0 hangs when reading USB20H DMP registers */
     41static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
     42{
     43	return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
     44		dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) &&
     45	       dev->bus->chipinfo.pkg == 11 &&
     46	       dev->id.id == BCMA_CORE_USB20_HOST;
     47}
     48
     49static inline u32 mips_read32(struct bcma_drv_mips *mcore,
     50			      u16 offset)
     51{
     52	return bcma_read32(mcore->core, offset);
     53}
     54
     55static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
     56{
     57	u32 flag;
     58
     59	if (bcma_core_mips_bcm47162a0_quirk(dev))
     60		return dev->core_index;
     61	if (bcma_core_mips_bcm5357b0_quirk(dev))
     62		return dev->core_index;
     63	flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
     64
     65	if (flag)
     66		return flag & 0x1F;
     67	else
     68		return 0x3f;
     69}
     70
     71/* Get the MIPS IRQ assignment for a specified device.
     72 * If unassigned, 0 is returned.
     73 * If disabled, 5 is returned.
     74 * If not supported, 6 is returned.
     75 */
     76unsigned int bcma_core_mips_irq(struct bcma_device *dev)
     77{
     78	struct bcma_device *mdev = dev->bus->drv_mips.core;
     79	u32 irqflag;
     80	unsigned int irq;
     81
     82	irqflag = bcma_core_mips_irqflag(dev);
     83	if (irqflag == 0x3f)
     84		return 6;
     85
     86	for (irq = 0; irq <= 4; irq++)
     87		if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
     88		    (1 << irqflag))
     89			return irq;
     90
     91	return 5;
     92}
     93
     94static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
     95{
     96	unsigned int oldirq = bcma_core_mips_irq(dev);
     97	struct bcma_bus *bus = dev->bus;
     98	struct bcma_device *mdev = bus->drv_mips.core;
     99	u32 irqflag;
    100
    101	irqflag = bcma_core_mips_irqflag(dev);
    102	BUG_ON(oldirq == 6);
    103
    104	dev->irq = irq + 2;
    105
    106	/* clear the old irq */
    107	if (oldirq == 0)
    108		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
    109			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
    110			    ~(1 << irqflag));
    111	else if (oldirq != 5)
    112		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
    113
    114	/* assign the new one */
    115	if (irq == 0) {
    116		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
    117			    bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
    118			    (1 << irqflag));
    119	} else {
    120		u32 irqinitmask = bcma_read32(mdev,
    121					      BCMA_MIPS_MIPS74K_INTMASK(irq));
    122		if (irqinitmask) {
    123			struct bcma_device *core;
    124
    125			/* backplane irq line is in use, find out who uses
    126			 * it and set user to irq 0
    127			 */
    128			list_for_each_entry(core, &bus->cores, list) {
    129				if ((1 << bcma_core_mips_irqflag(core)) ==
    130				    irqinitmask) {
    131					bcma_core_mips_set_irq(core, 0);
    132					break;
    133				}
    134			}
    135		}
    136		bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
    137			     1 << irqflag);
    138	}
    139
    140	bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
    141		   dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
    142}
    143
    144static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
    145					u16 coreid, u8 unit)
    146{
    147	struct bcma_device *core;
    148
    149	core = bcma_find_core_unit(bus, coreid, unit);
    150	if (!core) {
    151		bcma_warn(bus,
    152			  "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
    153			  coreid, unit);
    154		return;
    155	}
    156
    157	bcma_core_mips_set_irq(core, irq);
    158}
    159
    160static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
    161{
    162	int i;
    163	static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
    164	char interrupts[25];
    165	char *ints = interrupts;
    166
    167	for (i = 0; i < ARRAY_SIZE(irq_name); i++)
    168		ints += sprintf(ints, " %s%c",
    169				irq_name[i], i == irq ? '*' : ' ');
    170
    171	bcma_debug(dev->bus, "core 0x%04x, irq:%s\n", dev->id.id, interrupts);
    172}
    173
    174static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
    175{
    176	struct bcma_device *core;
    177
    178	list_for_each_entry(core, &bus->cores, list) {
    179		bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
    180	}
    181}
    182
    183u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
    184{
    185	struct bcma_bus *bus = mcore->core->bus;
    186
    187	if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
    188		return bcma_pmu_get_cpu_clock(&bus->drv_cc);
    189
    190	bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
    191	return 0;
    192}
    193EXPORT_SYMBOL(bcma_cpu_clock);
    194
    195static enum bcma_boot_dev bcma_boot_dev(struct bcma_bus *bus)
    196{
    197	struct bcma_drv_cc *cc = &bus->drv_cc;
    198	u8 cc_rev = cc->core->id.rev;
    199
    200	if (cc_rev == 42) {
    201		struct bcma_device *core;
    202
    203		core = bcma_find_core(bus, BCMA_CORE_NS_ROM);
    204		if (core) {
    205			switch (bcma_aread32(core, BCMA_IOST) &
    206				BCMA_NS_ROM_IOST_BOOT_DEV_MASK) {
    207			case BCMA_NS_ROM_IOST_BOOT_DEV_NOR:
    208				return BCMA_BOOT_DEV_SERIAL;
    209			case BCMA_NS_ROM_IOST_BOOT_DEV_NAND:
    210				return BCMA_BOOT_DEV_NAND;
    211			case BCMA_NS_ROM_IOST_BOOT_DEV_ROM:
    212			default:
    213				return BCMA_BOOT_DEV_ROM;
    214			}
    215		}
    216	} else {
    217		if (cc_rev == 38) {
    218			if (cc->status & BCMA_CC_CHIPST_5357_NAND_BOOT)
    219				return BCMA_BOOT_DEV_NAND;
    220			else if (cc->status & BIT(5))
    221				return BCMA_BOOT_DEV_ROM;
    222		}
    223
    224		if ((cc->capabilities & BCMA_CC_CAP_FLASHT) ==
    225		    BCMA_CC_FLASHT_PARA)
    226			return BCMA_BOOT_DEV_PARALLEL;
    227		else
    228			return BCMA_BOOT_DEV_SERIAL;
    229	}
    230
    231	return BCMA_BOOT_DEV_SERIAL;
    232}
    233
    234static void bcma_core_mips_nvram_init(struct bcma_drv_mips *mcore)
    235{
    236	struct bcma_bus *bus = mcore->core->bus;
    237	enum bcma_boot_dev boot_dev;
    238
    239	/* Determine flash type this SoC boots from */
    240	boot_dev = bcma_boot_dev(bus);
    241	switch (boot_dev) {
    242	case BCMA_BOOT_DEV_PARALLEL:
    243	case BCMA_BOOT_DEV_SERIAL:
    244#ifdef CONFIG_BCM47XX
    245		bcm47xx_nvram_init_from_mem(BCMA_SOC_FLASH2,
    246					    BCMA_SOC_FLASH2_SZ);
    247#endif
    248		break;
    249	case BCMA_BOOT_DEV_NAND:
    250#ifdef CONFIG_BCM47XX
    251		bcm47xx_nvram_init_from_mem(BCMA_SOC_FLASH1,
    252					    BCMA_SOC_FLASH1_SZ);
    253#endif
    254		break;
    255	default:
    256		break;
    257	}
    258}
    259
    260void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
    261{
    262	struct bcma_bus *bus = mcore->core->bus;
    263
    264	if (mcore->early_setup_done)
    265		return;
    266
    267	bcma_chipco_serial_init(&bus->drv_cc);
    268	bcma_core_mips_nvram_init(mcore);
    269
    270	mcore->early_setup_done = true;
    271}
    272
    273static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
    274{
    275	struct bcma_device *cpu, *pcie, *i2s;
    276
    277	/* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
    278	 * (IRQ flags > 7 are ignored when setting the interrupt masks)
    279	 */
    280	if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
    281	    bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
    282		return;
    283
    284	cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
    285	pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
    286	i2s = bcma_find_core(bus, BCMA_CORE_I2S);
    287	if (cpu && pcie && i2s &&
    288	    bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
    289	    bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
    290	    bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
    291		bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
    292		bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
    293		bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
    294		bcma_debug(bus,
    295			   "Moved i2s interrupt to oob line 7 instead of 8\n");
    296	}
    297}
    298
    299void bcma_core_mips_init(struct bcma_drv_mips *mcore)
    300{
    301	struct bcma_bus *bus;
    302	struct bcma_device *core;
    303	bus = mcore->core->bus;
    304
    305	if (mcore->setup_done)
    306		return;
    307
    308	bcma_debug(bus, "Initializing MIPS core...\n");
    309
    310	bcma_core_mips_early_init(mcore);
    311
    312	bcma_fix_i2s_irqflag(bus);
    313
    314	switch (bus->chipinfo.id) {
    315	case BCMA_CHIP_ID_BCM4716:
    316	case BCMA_CHIP_ID_BCM4748:
    317		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
    318		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
    319		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
    320		bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
    321		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
    322		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
    323		break;
    324	case BCMA_CHIP_ID_BCM5356:
    325	case BCMA_CHIP_ID_BCM47162:
    326	case BCMA_CHIP_ID_BCM53572:
    327		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
    328		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
    329		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
    330		break;
    331	case BCMA_CHIP_ID_BCM5357:
    332	case BCMA_CHIP_ID_BCM4749:
    333		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
    334		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
    335		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
    336		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
    337		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
    338		break;
    339	case BCMA_CHIP_ID_BCM4706:
    340		bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
    341		bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
    342					    0);
    343		bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
    344		bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
    345		bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
    346					    0);
    347		break;
    348	default:
    349		list_for_each_entry(core, &bus->cores, list) {
    350			core->irq = bcma_core_irq(core, 0);
    351		}
    352		bcma_err(bus,
    353			 "Unknown device (0x%x) found, can not configure IRQs\n",
    354			 bus->chipinfo.id);
    355	}
    356	bcma_debug(bus, "IRQ reconfiguration done\n");
    357	bcma_core_mips_dump_irq(bus);
    358
    359	mcore->setup_done = true;
    360}