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(oldirq), 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_cpu_clock(&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        struct bcma_drv_cc *cc = &bus->drv_cc;
 185
 186        switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 187        case BCMA_CC_FLASHT_STSER:
 188        case BCMA_CC_FLASHT_ATSER:
 189                bcma_debug(bus, "Found serial flash\n");
 190                bcma_sflash_init(cc);
 191                break;
 192        case BCMA_CC_FLASHT_PARA:
 193                bcma_debug(bus, "Found parallel flash\n");
 194                cc->pflash.present = true;
 195                cc->pflash.window = BCMA_SOC_FLASH2;
 196                cc->pflash.window_size = BCMA_SOC_FLASH2_SZ;
 197
 198                if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
 199                     BCMA_CC_FLASH_CFG_DS) == 0)
 200                        cc->pflash.buswidth = 1;
 201                else
 202                        cc->pflash.buswidth = 2;
 203                break;
 204        default:
 205                bcma_err(bus, "Flash type not supported\n");
 206        }
 207
 208        if (cc->core->id.rev == 38 ||
 209            bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
 210                if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
 211                        bcma_debug(bus, "Found NAND flash\n");
 212                        bcma_nflash_init(cc);
 213                }
 214        }
 215}
 216
 217void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
 218{
 219        struct bcma_bus *bus = mcore->core->bus;
 220
 221        if (mcore->early_setup_done)
 222                return;
 223
 224        bcma_chipco_serial_init(&bus->drv_cc);
 225        bcma_core_mips_flash_detect(mcore);
 226
 227        mcore->early_setup_done = true;
 228}
 229
 230void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 231{
 232        struct bcma_bus *bus;
 233        struct bcma_device *core;
 234        bus = mcore->core->bus;
 235
 236        if (mcore->setup_done)
 237                return;
 238
 239        bcma_info(bus, "Initializing MIPS core...\n");
 240
 241        bcma_core_mips_early_init(mcore);
 242
 243        mcore->assigned_irqs = 1;
 244
 245        /* Assign IRQs to all cores on the bus */
 246        list_for_each_entry(core, &bus->cores, list) {
 247                int mips_irq;
 248                if (core->irq)
 249                        continue;
 250
 251                mips_irq = bcma_core_mips_irq(core);
 252                if (mips_irq > 4)
 253                        core->irq = 0;
 254                else
 255                        core->irq = mips_irq + 2;
 256                if (core->irq > 5)
 257                        continue;
 258                switch (core->id.id) {
 259                case BCMA_CORE_PCI:
 260                case BCMA_CORE_PCIE:
 261                case BCMA_CORE_ETHERNET:
 262                case BCMA_CORE_ETHERNET_GBIT:
 263                case BCMA_CORE_MAC_GBIT:
 264                case BCMA_CORE_80211:
 265                case BCMA_CORE_USB20_HOST:
 266                        /* These devices get their own IRQ line if available,
 267                         * the rest goes on IRQ0
 268                         */
 269                        if (mcore->assigned_irqs <= 4)
 270                                bcma_core_mips_set_irq(core,
 271                                                       mcore->assigned_irqs++);
 272                        break;
 273                }
 274        }
 275        bcma_info(bus, "IRQ reconfiguration done\n");
 276        bcma_core_mips_dump_irq(bus);
 277
 278        mcore->setup_done = true;
 279}
 280