linux/drivers/bcma/driver_mips.c
<<
>>
Prefs
   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
  22/* The 47162a0 hangs when reading MIPS DMP registers registers */
  23static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
  24{
  25        return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 &&
  26               dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K;
  27}
  28
  29/* The 5357b0 hangs when reading USB20H DMP registers */
  30static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
  31{
  32        return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
  33                dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) &&
  34               dev->bus->chipinfo.pkg == 11 &&
  35               dev->id.id == BCMA_CORE_USB20_HOST;
  36}
  37
  38static inline u32 mips_read32(struct bcma_drv_mips *mcore,
  39                              u16 offset)
  40{
  41        return bcma_read32(mcore->core, offset);
  42}
  43
  44static inline void mips_write32(struct bcma_drv_mips *mcore,
  45                                u16 offset,
  46                                u32 value)
  47{
  48        bcma_write32(mcore->core, offset, value);
  49}
  50
  51static const u32 ipsflag_irq_mask[] = {
  52        0,
  53        BCMA_MIPS_IPSFLAG_IRQ1,
  54        BCMA_MIPS_IPSFLAG_IRQ2,
  55        BCMA_MIPS_IPSFLAG_IRQ3,
  56        BCMA_MIPS_IPSFLAG_IRQ4,
  57};
  58
  59static const u32 ipsflag_irq_shift[] = {
  60        0,
  61        BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
  62        BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
  63        BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
  64        BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
  65};
  66
  67static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
  68{
  69        u32 flag;
  70
  71        if (bcma_core_mips_bcm47162a0_quirk(dev))
  72                return dev->core_index;
  73        if (bcma_core_mips_bcm5357b0_quirk(dev))
  74                return dev->core_index;
  75        flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
  76
  77        return flag & 0x1F;
  78}
  79
  80/* Get the MIPS IRQ assignment for a specified device.
  81 * If unassigned, 0 is returned.
  82 */
  83unsigned int bcma_core_mips_irq(struct bcma_device *dev)
  84{
  85        struct bcma_device *mdev = dev->bus->drv_mips.core;
  86        u32 irqflag;
  87        unsigned int irq;
  88
  89        irqflag = bcma_core_mips_irqflag(dev);
  90
  91        for (irq = 1; irq <= 4; irq++)
  92                if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
  93                    (1 << irqflag))
  94                        return irq;
  95
  96        return 0;
  97}
  98EXPORT_SYMBOL(bcma_core_mips_irq);
  99
 100static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
 101{
 102        unsigned int oldirq = bcma_core_mips_irq(dev);
 103        struct bcma_bus *bus = dev->bus;
 104        struct bcma_device *mdev = bus->drv_mips.core;
 105        u32 irqflag;
 106
 107        irqflag = bcma_core_mips_irqflag(dev);
 108        BUG_ON(oldirq == 6);
 109
 110        dev->irq = irq + 2;
 111
 112        /* clear the old irq */
 113        if (oldirq == 0)
 114                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
 115                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
 116                            ~(1 << irqflag));
 117        else
 118                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq), 0);
 119
 120        /* assign the new one */
 121        if (irq == 0) {
 122                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
 123                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
 124                            (1 << irqflag));
 125        } else {
 126                u32 oldirqflag = bcma_read32(mdev,
 127                                             BCMA_MIPS_MIPS74K_INTMASK(irq));
 128                if (oldirqflag) {
 129                        struct bcma_device *core;
 130
 131                        /* backplane irq line is in use, find out who uses
 132                         * it and set user to irq 0
 133                         */
 134                        list_for_each_entry(core, &bus->cores, list) {
 135                                if ((1 << bcma_core_mips_irqflag(core)) ==
 136                                    oldirqflag) {
 137                                        bcma_core_mips_set_irq(core, 0);
 138                                        break;
 139                                }
 140                        }
 141                }
 142                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
 143                             1 << irqflag);
 144        }
 145
 146        bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
 147                  dev->id.id, oldirq + 2, irq + 2);
 148}
 149
 150static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
 151{
 152        int i;
 153        static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
 154        printk(KERN_INFO KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
 155        for (i = 0; i <= 6; i++)
 156                printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
 157        printk("\n");
 158}
 159
 160static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
 161{
 162        struct bcma_device *core;
 163
 164        list_for_each_entry(core, &bus->cores, list) {
 165                bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
 166        }
 167}
 168
 169u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
 170{
 171        struct bcma_bus *bus = mcore->core->bus;
 172
 173        if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
 174                return bcma_pmu_get_clockcpu(&bus->drv_cc);
 175
 176        bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
 177        return 0;
 178}
 179EXPORT_SYMBOL(bcma_cpu_clock);
 180
 181static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 182{
 183        struct bcma_bus *bus = mcore->core->bus;
 184
 185        switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
 186        case BCMA_CC_FLASHT_STSER:
 187        case BCMA_CC_FLASHT_ATSER:
 188                bcma_debug(bus, "Found serial flash\n");
 189                bcma_sflash_init(&bus->drv_cc);
 190                break;
 191        case BCMA_CC_FLASHT_PARA:
 192                bcma_debug(bus, "Found parallel flash\n");
 193                bus->drv_cc.pflash.window = 0x1c000000;
 194                bus->drv_cc.pflash.window_size = 0x02000000;
 195
 196                if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
 197                     BCMA_CC_FLASH_CFG_DS) == 0)
 198                        bus->drv_cc.pflash.buswidth = 1;
 199                else
 200                        bus->drv_cc.pflash.buswidth = 2;
 201                break;
 202        default:
 203                bcma_err(bus, "Flash type not supported\n");
 204        }
 205
 206        if (bus->drv_cc.core->id.rev == 38 ||
 207            bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
 208                if (bus->drv_cc.capabilities & BCMA_CC_CAP_NFLASH) {
 209                        bcma_debug(bus, "Found NAND flash\n");
 210                        bcma_nflash_init(&bus->drv_cc);
 211                }
 212        }
 213}
 214
 215void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 216{
 217        struct bcma_bus *bus;
 218        struct bcma_device *core;
 219        bus = mcore->core->bus;
 220
 221        bcma_info(bus, "Initializing MIPS core...\n");
 222
 223        if (!mcore->setup_done)
 224                mcore->assigned_irqs = 1;
 225
 226        /* Assign IRQs to all cores on the bus */
 227        list_for_each_entry(core, &bus->cores, list) {
 228                int mips_irq;
 229                if (core->irq)
 230                        continue;
 231
 232                mips_irq = bcma_core_mips_irq(core);
 233                if (mips_irq > 4)
 234                        core->irq = 0;
 235                else
 236                        core->irq = mips_irq + 2;
 237                if (core->irq > 5)
 238                        continue;
 239                switch (core->id.id) {
 240                case BCMA_CORE_PCI:
 241                case BCMA_CORE_PCIE:
 242                case BCMA_CORE_ETHERNET:
 243                case BCMA_CORE_ETHERNET_GBIT:
 244                case BCMA_CORE_MAC_GBIT:
 245                case BCMA_CORE_80211:
 246                case BCMA_CORE_USB20_HOST:
 247                        /* These devices get their own IRQ line if available,
 248                         * the rest goes on IRQ0
 249                         */
 250                        if (mcore->assigned_irqs <= 4)
 251                                bcma_core_mips_set_irq(core,
 252                                                       mcore->assigned_irqs++);
 253                        break;
 254                }
 255        }
 256        bcma_info(bus, "IRQ reconfiguration done\n");
 257        bcma_core_mips_dump_irq(bus);
 258
 259        if (mcore->setup_done)
 260                return;
 261
 262        bcma_chipco_serial_init(&bus->drv_cc);
 263        bcma_core_mips_flash_detect(mcore);
 264        mcore->setup_done = true;
 265}
 266
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.