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 == 47162 && dev->bus->chipinfo.rev == 0 &&
  26               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 == 0x5357 ||
  33                dev->bus->chipinfo.id == 0x4749) &&
  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_reverse(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        pr_info("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_reverse(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        pr_err("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                pr_err("Serial flash not supported.\n");
 189                break;
 190        case BCMA_CC_FLASHT_PARA:
 191                pr_info("found parallel flash.\n");
 192                bus->drv_cc.pflash.window = 0x1c000000;
 193                bus->drv_cc.pflash.window_size = 0x02000000;
 194
 195                if ((bcma_read32(bus->drv_cc.core, BCMA_CC_FLASH_CFG) &
 196                     BCMA_CC_FLASH_CFG_DS) == 0)
 197                        bus->drv_cc.pflash.buswidth = 1;
 198                else
 199                        bus->drv_cc.pflash.buswidth = 2;
 200                break;
 201        default:
 202                pr_err("flash not supported.\n");
 203        }
 204}
 205
 206void bcma_core_mips_init(struct bcma_drv_mips *mcore)
 207{
 208        struct bcma_bus *bus;
 209        struct bcma_device *core;
 210        bus = mcore->core->bus;
 211
 212        pr_info("Initializing MIPS core...\n");
 213
 214        if (!mcore->setup_done)
 215                mcore->assigned_irqs = 1;
 216
 217        /* Assign IRQs to all cores on the bus */
 218        list_for_each_entry_reverse(core, &bus->cores, list) {
 219                int mips_irq;
 220                if (core->irq)
 221                        continue;
 222
 223                mips_irq = bcma_core_mips_irq(core);
 224                if (mips_irq > 4)
 225                        core->irq = 0;
 226                else
 227                        core->irq = mips_irq + 2;
 228                if (core->irq > 5)
 229                        continue;
 230                switch (core->id.id) {
 231                case BCMA_CORE_PCI:
 232                case BCMA_CORE_PCIE:
 233                case BCMA_CORE_ETHERNET:
 234                case BCMA_CORE_ETHERNET_GBIT:
 235                case BCMA_CORE_MAC_GBIT:
 236                case BCMA_CORE_80211:
 237                case BCMA_CORE_USB20_HOST:
 238                        /* These devices get their own IRQ line if available,
 239                         * the rest goes on IRQ0
 240                         */
 241                        if (mcore->assigned_irqs <= 4)
 242                                bcma_core_mips_set_irq(core,
 243                                                       mcore->assigned_irqs++);
 244                        break;
 245                }
 246        }
 247        pr_info("IRQ reconfiguration done\n");
 248        bcma_core_mips_dump_irq(bus);
 249
 250        if (mcore->setup_done)
 251                return;
 252
 253        bcma_chipco_serial_init(&bus->drv_cc);
 254        bcma_core_mips_flash_detect(mcore);
 255        mcore->setup_done = true;
 256}
 257