linux/drivers/ssb/driver_mipscore.c
<<
>>
Prefs
   1/*
   2 * Sonics Silicon Backplane
   3 * Broadcom MIPS core driver
   4 *
   5 * Copyright 2005, Broadcom Corporation
   6 * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
   7 *
   8 * Licensed under the GNU/GPL. See COPYING for details.
   9 */
  10
  11#include <linux/ssb/ssb.h>
  12
  13#include <linux/serial.h>
  14#include <linux/serial_core.h>
  15#include <linux/serial_reg.h>
  16#include <linux/time.h>
  17
  18#include "ssb_private.h"
  19
  20
  21static inline u32 mips_read32(struct ssb_mipscore *mcore,
  22                              u16 offset)
  23{
  24        return ssb_read32(mcore->dev, offset);
  25}
  26
  27static inline void mips_write32(struct ssb_mipscore *mcore,
  28                                u16 offset,
  29                                u32 value)
  30{
  31        ssb_write32(mcore->dev, offset, value);
  32}
  33
  34static const u32 ipsflag_irq_mask[] = {
  35        0,
  36        SSB_IPSFLAG_IRQ1,
  37        SSB_IPSFLAG_IRQ2,
  38        SSB_IPSFLAG_IRQ3,
  39        SSB_IPSFLAG_IRQ4,
  40};
  41
  42static const u32 ipsflag_irq_shift[] = {
  43        0,
  44        SSB_IPSFLAG_IRQ1_SHIFT,
  45        SSB_IPSFLAG_IRQ2_SHIFT,
  46        SSB_IPSFLAG_IRQ3_SHIFT,
  47        SSB_IPSFLAG_IRQ4_SHIFT,
  48};
  49
  50static inline u32 ssb_irqflag(struct ssb_device *dev)
  51{
  52        u32 tpsflag = ssb_read32(dev, SSB_TPSFLAG);
  53        if (tpsflag)
  54                return ssb_read32(dev, SSB_TPSFLAG) & SSB_TPSFLAG_BPFLAG;
  55        else
  56                /* not irq supported */
  57                return 0x3f;
  58}
  59
  60static struct ssb_device *find_device(struct ssb_device *rdev, int irqflag)
  61{
  62        struct ssb_bus *bus = rdev->bus;
  63        int i;
  64        for (i = 0; i < bus->nr_devices; i++) {
  65                struct ssb_device *dev;
  66                dev = &(bus->devices[i]);
  67                if (ssb_irqflag(dev) == irqflag)
  68                        return dev;
  69        }
  70        return NULL;
  71}
  72
  73/* Get the MIPS IRQ assignment for a specified device.
  74 * If unassigned, 0 is returned.
  75 * If disabled, 5 is returned.
  76 * If not supported, 6 is returned.
  77 */
  78unsigned int ssb_mips_irq(struct ssb_device *dev)
  79{
  80        struct ssb_bus *bus = dev->bus;
  81        struct ssb_device *mdev = bus->mipscore.dev;
  82        u32 irqflag;
  83        u32 ipsflag;
  84        u32 tmp;
  85        unsigned int irq;
  86
  87        irqflag = ssb_irqflag(dev);
  88        if (irqflag == 0x3f)
  89                return 6;
  90        ipsflag = ssb_read32(bus->mipscore.dev, SSB_IPSFLAG);
  91        for (irq = 1; irq <= 4; irq++) {
  92                tmp = ((ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq]);
  93                if (tmp == irqflag)
  94                        break;
  95        }
  96        if (irq == 5) {
  97                if ((1 << irqflag) & ssb_read32(mdev, SSB_INTVEC))
  98                        irq = 0;
  99        }
 100
 101        return irq;
 102}
 103
 104static void clear_irq(struct ssb_bus *bus, unsigned int irq)
 105{
 106        struct ssb_device *dev = bus->mipscore.dev;
 107
 108        /* Clear the IRQ in the MIPScore backplane registers */
 109        if (irq == 0) {
 110                ssb_write32(dev, SSB_INTVEC, 0);
 111        } else {
 112                ssb_write32(dev, SSB_IPSFLAG,
 113                            ssb_read32(dev, SSB_IPSFLAG) |
 114                            ipsflag_irq_mask[irq]);
 115        }
 116}
 117
 118static void set_irq(struct ssb_device *dev, unsigned int irq)
 119{
 120        unsigned int oldirq = ssb_mips_irq(dev);
 121        struct ssb_bus *bus = dev->bus;
 122        struct ssb_device *mdev = bus->mipscore.dev;
 123        u32 irqflag = ssb_irqflag(dev);
 124
 125        BUG_ON(oldirq == 6);
 126
 127        dev->irq = irq + 2;
 128
 129        /* clear the old irq */
 130        if (oldirq == 0)
 131                ssb_write32(mdev, SSB_INTVEC, (~(1 << irqflag) & ssb_read32(mdev, SSB_INTVEC)));
 132        else if (oldirq != 5)
 133                clear_irq(bus, oldirq);
 134
 135        /* assign the new one */
 136        if (irq == 0) {
 137                ssb_write32(mdev, SSB_INTVEC, ((1 << irqflag) | ssb_read32(mdev, SSB_INTVEC)));
 138        } else {
 139                u32 ipsflag = ssb_read32(mdev, SSB_IPSFLAG);
 140                if ((ipsflag & ipsflag_irq_mask[irq]) != ipsflag_irq_mask[irq]) {
 141                        u32 oldipsflag = (ipsflag & ipsflag_irq_mask[irq]) >> ipsflag_irq_shift[irq];
 142                        struct ssb_device *olddev = find_device(dev, oldipsflag);
 143                        if (olddev)
 144                                set_irq(olddev, 0);
 145                }
 146                irqflag <<= ipsflag_irq_shift[irq];
 147                irqflag |= (ipsflag & ~ipsflag_irq_mask[irq]);
 148                ssb_write32(mdev, SSB_IPSFLAG, irqflag);
 149        }
 150        ssb_dprintk(KERN_INFO PFX
 151                    "set_irq: core 0x%04x, irq %d => %d\n",
 152                    dev->id.coreid, oldirq+2, irq+2);
 153}
 154
 155static void print_irq(struct ssb_device *dev, unsigned int irq)
 156{
 157        int i;
 158        static const char *irq_name[] = {"2(S)", "3", "4", "5", "6", "D", "I"};
 159        ssb_dprintk(KERN_INFO PFX
 160                "core 0x%04x, irq :", dev->id.coreid);
 161        for (i = 0; i <= 6; i++) {
 162                ssb_dprintk(" %s%s", irq_name[i], i==irq?"*":" ");
 163        }
 164        ssb_dprintk("\n");
 165}
 166
 167static void dump_irq(struct ssb_bus *bus)
 168{
 169        int i;
 170        for (i = 0; i < bus->nr_devices; i++) {
 171                struct ssb_device *dev;
 172                dev = &(bus->devices[i]);
 173                print_irq(dev, ssb_mips_irq(dev));
 174        }
 175}
 176
 177static void ssb_mips_serial_init(struct ssb_mipscore *mcore)
 178{
 179        struct ssb_bus *bus = mcore->dev->bus;
 180
 181        if (bus->extif.dev)
 182                mcore->nr_serial_ports = ssb_extif_serial_init(&bus->extif, mcore->serial_ports);
 183        else if (bus->chipco.dev)
 184                mcore->nr_serial_ports = ssb_chipco_serial_init(&bus->chipco, mcore->serial_ports);
 185        else
 186                mcore->nr_serial_ports = 0;
 187}
 188
 189static void ssb_mips_flash_detect(struct ssb_mipscore *mcore)
 190{
 191        struct ssb_bus *bus = mcore->dev->bus;
 192
 193        /* When there is no chipcommon on the bus there is 4MB flash */
 194        if (!bus->chipco.dev) {
 195                mcore->flash_buswidth = 2;
 196                mcore->flash_window = SSB_FLASH1;
 197                mcore->flash_window_size = SSB_FLASH1_SZ;
 198                return;
 199        }
 200
 201        /* There is ChipCommon, so use it to read info about flash */
 202        switch (bus->chipco.capabilities & SSB_CHIPCO_CAP_FLASHT) {
 203        case SSB_CHIPCO_FLASHT_STSER:
 204        case SSB_CHIPCO_FLASHT_ATSER:
 205                pr_err("Serial flash not supported\n");
 206                break;
 207        case SSB_CHIPCO_FLASHT_PARA:
 208                pr_debug("Found parallel flash\n");
 209                mcore->flash_window = SSB_FLASH2;
 210                mcore->flash_window_size = SSB_FLASH2_SZ;
 211                if ((ssb_read32(bus->chipco.dev, SSB_CHIPCO_FLASH_CFG)
 212                               & SSB_CHIPCO_CFG_DS16) == 0)
 213                        mcore->flash_buswidth = 1;
 214                else
 215                        mcore->flash_buswidth = 2;
 216                break;
 217        }
 218}
 219
 220u32 ssb_cpu_clock(struct ssb_mipscore *mcore)
 221{
 222        struct ssb_bus *bus = mcore->dev->bus;
 223        u32 pll_type, n, m, rate = 0;
 224
 225        if (bus->chipco.capabilities & SSB_CHIPCO_CAP_PMU)
 226                return ssb_pmu_get_cpu_clock(&bus->chipco);
 227
 228        if (bus->extif.dev) {
 229                ssb_extif_get_clockcontrol(&bus->extif, &pll_type, &n, &m);
 230        } else if (bus->chipco.dev) {
 231                ssb_chipco_get_clockcpu(&bus->chipco, &pll_type, &n, &m);
 232        } else
 233                return 0;
 234
 235        if ((pll_type == SSB_PLLTYPE_5) || (bus->chip_id == 0x5365)) {
 236                rate = 200000000;
 237        } else {
 238                rate = ssb_calc_clock_rate(pll_type, n, m);
 239        }
 240
 241        if (pll_type == SSB_PLLTYPE_6) {
 242                rate *= 2;
 243        }
 244
 245        return rate;
 246}
 247
 248void ssb_mipscore_init(struct ssb_mipscore *mcore)
 249{
 250        struct ssb_bus *bus;
 251        struct ssb_device *dev;
 252        unsigned long hz, ns;
 253        unsigned int irq, i;
 254
 255        if (!mcore->dev)
 256                return; /* We don't have a MIPS core */
 257
 258        ssb_dprintk(KERN_INFO PFX "Initializing MIPS core...\n");
 259
 260        bus = mcore->dev->bus;
 261        hz = ssb_clockspeed(bus);
 262        if (!hz)
 263                hz = 100000000;
 264        ns = 1000000000 / hz;
 265
 266        if (bus->extif.dev)
 267                ssb_extif_timing_init(&bus->extif, ns);
 268        else if (bus->chipco.dev)
 269                ssb_chipco_timing_init(&bus->chipco, ns);
 270
 271        /* Assign IRQs to all cores on the bus, start with irq line 2, because serial usually takes 1 */
 272        for (irq = 2, i = 0; i < bus->nr_devices; i++) {
 273                int mips_irq;
 274                dev = &(bus->devices[i]);
 275                mips_irq = ssb_mips_irq(dev);
 276                if (mips_irq > 4)
 277                        dev->irq = 0;
 278                else
 279                        dev->irq = mips_irq + 2;
 280                if (dev->irq > 5)
 281                        continue;
 282                switch (dev->id.coreid) {
 283                case SSB_DEV_USB11_HOST:
 284                        /* shouldn't need a separate irq line for non-4710, most of them have a proper
 285                         * external usb controller on the pci */
 286                        if ((bus->chip_id == 0x4710) && (irq <= 4)) {
 287                                set_irq(dev, irq++);
 288                        }
 289                        break;
 290                case SSB_DEV_PCI:
 291                case SSB_DEV_ETHERNET:
 292                case SSB_DEV_ETHERNET_GBIT:
 293                case SSB_DEV_80211:
 294                case SSB_DEV_USB20_HOST:
 295                        /* These devices get their own IRQ line if available, the rest goes on IRQ0 */
 296                        if (irq <= 4) {
 297                                set_irq(dev, irq++);
 298                                break;
 299                        }
 300                        /* fallthrough */
 301                case SSB_DEV_EXTIF:
 302                        set_irq(dev, 0);
 303                        break;
 304                }
 305        }
 306        ssb_dprintk(KERN_INFO PFX "after irq reconfiguration\n");
 307        dump_irq(bus);
 308
 309        ssb_mips_serial_init(mcore);
 310        ssb_mips_flash_detect(mcore);
 311}
 312
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.