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/mtd/physmap.h>
  18#include <linux/platform_device.h>
  19#include <linux/serial.h>
  20#include <linux/serial_core.h>
  21#include <linux/serial_reg.h>
  22#include <linux/time.h>
  23
  24static const char * const part_probes[] = { "bcm47xxpart", NULL };
  25
  26static struct physmap_flash_data bcma_pflash_data = {
  27        .part_probe_types       = part_probes,
  28};
  29
  30static struct resource bcma_pflash_resource = {
  31        .name   = "bcma_pflash",
  32        .flags  = IORESOURCE_MEM,
  33};
  34
  35struct platform_device bcma_pflash_dev = {
  36        .name           = "physmap-flash",
  37        .dev            = {
  38                .platform_data  = &bcma_pflash_data,
  39        },
  40        .resource       = &bcma_pflash_resource,
  41        .num_resources  = 1,
  42};
  43
  44/* The 47162a0 hangs when reading MIPS DMP registers registers */
  45static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
  46{
  47        return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 &&
  48               dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K;
  49}
  50
  51/* The 5357b0 hangs when reading USB20H DMP registers */
  52static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
  53{
  54        return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
  55                dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) &&
  56               dev->bus->chipinfo.pkg == 11 &&
  57               dev->id.id == BCMA_CORE_USB20_HOST;
  58}
  59
  60static inline u32 mips_read32(struct bcma_drv_mips *mcore,
  61                              u16 offset)
  62{
  63        return bcma_read32(mcore->core, offset);
  64}
  65
  66static inline void mips_write32(struct bcma_drv_mips *mcore,
  67                                u16 offset,
  68                                u32 value)
  69{
  70        bcma_write32(mcore->core, offset, value);
  71}
  72
  73static const u32 ipsflag_irq_mask[] = {
  74        0,
  75        BCMA_MIPS_IPSFLAG_IRQ1,
  76        BCMA_MIPS_IPSFLAG_IRQ2,
  77        BCMA_MIPS_IPSFLAG_IRQ3,
  78        BCMA_MIPS_IPSFLAG_IRQ4,
  79};
  80
  81static const u32 ipsflag_irq_shift[] = {
  82        0,
  83        BCMA_MIPS_IPSFLAG_IRQ1_SHIFT,
  84        BCMA_MIPS_IPSFLAG_IRQ2_SHIFT,
  85        BCMA_MIPS_IPSFLAG_IRQ3_SHIFT,
  86        BCMA_MIPS_IPSFLAG_IRQ4_SHIFT,
  87};
  88
  89static u32 bcma_core_mips_irqflag(struct bcma_device *dev)
  90{
  91        u32 flag;
  92
  93        if (bcma_core_mips_bcm47162a0_quirk(dev))
  94                return dev->core_index;
  95        if (bcma_core_mips_bcm5357b0_quirk(dev))
  96                return dev->core_index;
  97        flag = bcma_aread32(dev, BCMA_MIPS_OOBSELOUTA30);
  98
  99        if (flag)
 100                return flag & 0x1F;
 101        else
 102                return 0x3f;
 103}
 104
 105/* Get the MIPS IRQ assignment for a specified device.
 106 * If unassigned, 0 is returned.
 107 * If disabled, 5 is returned.
 108 * If not supported, 6 is returned.
 109 */
 110static unsigned int bcma_core_mips_irq(struct bcma_device *dev)
 111{
 112        struct bcma_device *mdev = dev->bus->drv_mips.core;
 113        u32 irqflag;
 114        unsigned int irq;
 115
 116        irqflag = bcma_core_mips_irqflag(dev);
 117        if (irqflag == 0x3f)
 118                return 6;
 119
 120        for (irq = 0; irq <= 4; irq++)
 121                if (bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq)) &
 122                    (1 << irqflag))
 123                        return irq;
 124
 125        return 5;
 126}
 127
 128unsigned int bcma_core_irq(struct bcma_device *dev)
 129{
 130        unsigned int mips_irq = bcma_core_mips_irq(dev);
 131        return mips_irq <= 4 ? mips_irq + 2 : 0;
 132}
 133EXPORT_SYMBOL(bcma_core_irq);
 134
 135static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
 136{
 137        unsigned int oldirq = bcma_core_mips_irq(dev);
 138        struct bcma_bus *bus = dev->bus;
 139        struct bcma_device *mdev = bus->drv_mips.core;
 140        u32 irqflag;
 141
 142        irqflag = bcma_core_mips_irqflag(dev);
 143        BUG_ON(oldirq == 6);
 144
 145        dev->irq = irq + 2;
 146
 147        /* clear the old irq */
 148        if (oldirq == 0)
 149                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
 150                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) &
 151                            ~(1 << irqflag));
 152        else if (oldirq != 5)
 153                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(oldirq), 0);
 154
 155        /* assign the new one */
 156        if (irq == 0) {
 157                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0),
 158                            bcma_read32(mdev, BCMA_MIPS_MIPS74K_INTMASK(0)) |
 159                            (1 << irqflag));
 160        } else {
 161                u32 irqinitmask = bcma_read32(mdev,
 162                                              BCMA_MIPS_MIPS74K_INTMASK(irq));
 163                if (irqinitmask) {
 164                        struct bcma_device *core;
 165
 166                        /* backplane irq line is in use, find out who uses
 167                         * it and set user to irq 0
 168                         */
 169                        list_for_each_entry(core, &bus->cores, list) {
 170                                if ((1 << bcma_core_mips_irqflag(core)) ==
 171                                    irqinitmask) {
 172                                        bcma_core_mips_set_irq(core, 0);
 173                                        break;
 174                                }
 175                        }
 176                }
 177                bcma_write32(mdev, BCMA_MIPS_MIPS74K_INTMASK(irq),
 178                             1 << irqflag);
 179        }
 180
 181        bcma_debug(bus, "set_irq: core 0x%04x, irq %d => %d\n",
 182                   dev->id.id, oldirq <= 4 ? oldirq + 2 : 0, irq + 2);
 183}
 184
 185static void bcma_core_mips_set_irq_name(struct bcma_bus *bus, unsigned int irq,
 186                                        u16 coreid, u8 unit)
 187{
 188        struct bcma_device *core;
 189
 190        core = bcma_find_core_unit(bus, coreid, unit);
 191        if (!core) {
 192                bcma_warn(bus,
 193                          "Can not find core (id: 0x%x, unit %i) for IRQ configuration.\n",
 194                          coreid, unit);
 195                return;
 196        }
 197
 198        bcma_core_mips_set_irq(core, irq);
 199}
 200
 201static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
 202{
 203        int i;
 204        static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
 205        printk(KERN_DEBUG KBUILD_MODNAME ": core 0x%04x, irq :", dev->id.id);
 206        for (i = 0; i <= 6; i++)
 207                printk(" %s%s", irq_name[i], i == irq ? "*" : " ");
 208        printk("\n");
 209}
 210
 211static void bcma_core_mips_dump_irq(struct bcma_bus *bus)
 212{
 213        struct bcma_device *core;
 214
 215        list_for_each_entry(core, &bus->cores, list) {
 216                bcma_core_mips_print_irq(core, bcma_core_mips_irq(core));
 217        }
 218}
 219
 220u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
 221{
 222        struct bcma_bus *bus = mcore->core->bus;
 223
 224        if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
 225                return bcma_pmu_get_cpu_clock(&bus->drv_cc);
 226
 227        bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
 228        return 0;
 229}
 230EXPORT_SYMBOL(bcma_cpu_clock);
 231
 232static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
 233{
 234        struct bcma_bus *bus = mcore->core->bus;
 235        struct bcma_drv_cc *cc = &bus->drv_cc;
 236        struct bcma_pflash *pflash = &cc->pflash;
 237
 238        switch (cc->capabilities & BCMA_CC_CAP_FLASHT) {
 239        case BCMA_CC_FLASHT_STSER:
 240        case BCMA_CC_FLASHT_ATSER:
 241                bcma_debug(bus, "Found serial flash\n");
 242                bcma_sflash_init(cc);
 243                break;
 244        case BCMA_CC_FLASHT_PARA:
 245                bcma_debug(bus, "Found parallel flash\n");
 246                pflash->present = true;
 247                pflash->window = BCMA_SOC_FLASH2;
 248                pflash->window_size = BCMA_SOC_FLASH2_SZ;
 249
 250                if ((bcma_read32(cc->core, BCMA_CC_FLASH_CFG) &
 251                     BCMA_CC_FLASH_CFG_DS) == 0)
 252                        pflash->buswidth = 1;
 253                else
 254                        pflash->buswidth = 2;
 255
 256                bcma_pflash_data.width = pflash->buswidth;
 257                bcma_pflash_resource.start = pflash->window;
 258                bcma_pflash_resource.end = pflash->window + pflash->window_size;
 259
 260                break;
 261        default:
 262                bcma_err(bus, "Flash type not supported\n");
 263        }
 264
 265        if (cc->core->id.rev == 38 ||
 266            bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
 267                if (cc->capabilities & BCMA_CC_CAP_NFLASH) {
 268                        bcma_debug(bus, "Found NAND flash\n");
 269                        bcma_nflash_init(cc);
 270                }
 271        }
 272}
 273
 274void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
 275{
 276        struct bcma_bus *bus = mcore->core->bus;
 277
 278        if (mcore->early_setup_done)
 279                return;
 280
 281        bcma_chipco_serial_init(&bus->drv_cc);
 282        bcma_core_mips_flash_detect(mcore);
 283
 284        mcore->early_setup_done = true;
 285}
 286
 287static void bcma_fix_i2s_irqflag(struct bcma_bus *bus)
 288{
 289        struct bcma_device *cpu, *pcie, *i2s;
 290
 291        /* Fixup the interrupts in 4716/4748 for i2s core (2010 Broadcom SDK)
 292         * (IRQ flags > 7 are ignored when setting the interrupt masks)
 293         */
 294        if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4716 &&
 295            bus->chipinfo.id != BCMA_CHIP_ID_BCM4748)
 296                return;
 297
 298        cpu = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
 299        pcie = bcma_find_core(bus, BCMA_CORE_PCIE);
 300        i2s = bcma_find_core(bus, BCMA_CORE_I2S);
 301        if (cpu && pcie && i2s &&
 302            bcma_aread32(cpu, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
 303            bcma_aread32(pcie, BCMA_MIPS_OOBSELINA74) == 0x08060504 &&
 304            bcma_aread32(i2s, BCMA_MIPS_OOBSELOUTA30) == 0x88) {
 305                bcma_awrite32(cpu, BCMA_MIPS_OOBSELINA74, 0x07060504);
 306                bcma_awrite32(pcie, BCMA_MIPS_OOBSELINA74, 0x07060504);
 307                bcma_awrite32(i2s, BCMA_MIPS_OOBSELOUTA30, 0x87);
 308                bcma_debug(bus,
 309                           "Moved i2s interrupt to oob line 7 instead of 8\n");
 310        }
 311}
 312
 313void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 314{
 315        struct bcma_bus *bus;
 316        struct bcma_device *core;
 317        bus = mcore->core->bus;
 318
 319        if (mcore->setup_done)
 320                return;
 321
 322        bcma_debug(bus, "Initializing MIPS core...\n");
 323
 324        bcma_core_mips_early_init(mcore);
 325
 326        bcma_fix_i2s_irqflag(bus);
 327
 328        switch (bus->chipinfo.id) {
 329        case BCMA_CHIP_ID_BCM4716:
 330        case BCMA_CHIP_ID_BCM4748:
 331                bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
 332                bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
 333                bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
 334                bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_PCIE, 0);
 335                bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
 336                bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
 337                break;
 338        case BCMA_CHIP_ID_BCM5356:
 339        case BCMA_CHIP_ID_BCM47162:
 340        case BCMA_CHIP_ID_BCM53572:
 341                bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
 342                bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
 343                bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
 344                break;
 345        case BCMA_CHIP_ID_BCM5357:
 346        case BCMA_CHIP_ID_BCM4749:
 347                bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_80211, 0);
 348                bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_MAC_GBIT, 0);
 349                bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_USB20_HOST, 0);
 350                bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_CHIPCOMMON, 0);
 351                bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_I2S, 0);
 352                break;
 353        case BCMA_CHIP_ID_BCM4706:
 354                bcma_core_mips_set_irq_name(bus, 1, BCMA_CORE_PCIE, 0);
 355                bcma_core_mips_set_irq_name(bus, 2, BCMA_CORE_4706_MAC_GBIT,
 356                                            0);
 357                bcma_core_mips_set_irq_name(bus, 3, BCMA_CORE_PCIE, 1);
 358                bcma_core_mips_set_irq_name(bus, 4, BCMA_CORE_USB20_HOST, 0);
 359                bcma_core_mips_set_irq_name(bus, 0, BCMA_CORE_4706_CHIPCOMMON,
 360                                            0);
 361                break;
 362        default:
 363                list_for_each_entry(core, &bus->cores, list) {
 364                        core->irq = bcma_core_irq(core);
 365                }
 366                bcma_err(bus,
 367                         "Unknown device (0x%x) found, can not configure IRQs\n",
 368                         bus->chipinfo.id);
 369        }
 370        bcma_debug(bus, "IRQ reconfiguration done\n");
 371        bcma_core_mips_dump_irq(bus);
 372
 373        mcore->setup_done = true;
 374}
 375
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.