linux/drivers/bcma/driver_chipcommon.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * ChipCommon core driver
   4 *
   5 * Copyright 2005, Broadcom Corporation
   6 * Copyright 2006, 2007, Michael Buesch <m@bues.ch>
   7 * Copyright 2012, Hauke Mehrtens <hauke@hauke-m.de>
   8 *
   9 * Licensed under the GNU/GPL. See COPYING for details.
  10 */
  11
  12#include "bcma_private.h"
  13#include <linux/bcm47xx_wdt.h>
  14#include <linux/export.h>
  15#include <linux/platform_device.h>
  16#include <linux/bcma/bcma.h>
  17
  18static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
  19                                         u32 mask, u32 value)
  20{
  21        value &= mask;
  22        value |= bcma_cc_read32(cc, offset) & ~mask;
  23        bcma_cc_write32(cc, offset, value);
  24
  25        return value;
  26}
  27
  28static u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc)
  29{
  30        if (cc->capabilities & BCMA_CC_CAP_PMU)
  31                return bcma_pmu_get_alp_clock(cc);
  32
  33        return 20000000;
  34}
  35
  36static u32 bcma_chipco_watchdog_get_max_timer(struct bcma_drv_cc *cc)
  37{
  38        struct bcma_bus *bus = cc->core->bus;
  39        u32 nb;
  40
  41        if (cc->capabilities & BCMA_CC_CAP_PMU) {
  42                if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
  43                        nb = 32;
  44                else if (cc->core->id.rev < 26)
  45                        nb = 16;
  46                else
  47                        nb = (cc->core->id.rev >= 37) ? 32 : 24;
  48        } else {
  49                nb = 28;
  50        }
  51        if (nb == 32)
  52                return 0xffffffff;
  53        else
  54                return (1 << nb) - 1;
  55}
  56
  57static u32 bcma_chipco_watchdog_timer_set_wdt(struct bcm47xx_wdt *wdt,
  58                                              u32 ticks)
  59{
  60        struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt);
  61
  62        return bcma_chipco_watchdog_timer_set(cc, ticks);
  63}
  64
  65static u32 bcma_chipco_watchdog_timer_set_ms_wdt(struct bcm47xx_wdt *wdt,
  66                                                 u32 ms)
  67{
  68        struct bcma_drv_cc *cc = bcm47xx_wdt_get_drvdata(wdt);
  69        u32 ticks;
  70
  71        ticks = bcma_chipco_watchdog_timer_set(cc, cc->ticks_per_ms * ms);
  72        return ticks / cc->ticks_per_ms;
  73}
  74
  75static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc)
  76{
  77        struct bcma_bus *bus = cc->core->bus;
  78
  79        if (cc->capabilities & BCMA_CC_CAP_PMU) {
  80                if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
  81                        /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
  82                        return bcma_chipco_get_alp_clock(cc) / 4000;
  83                else
  84                        /* based on 32KHz ILP clock */
  85                        return 32;
  86        } else {
  87                return bcma_chipco_get_alp_clock(cc) / 1000;
  88        }
  89}
  90
  91int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
  92{
  93        struct bcm47xx_wdt wdt = {};
  94        struct platform_device *pdev;
  95
  96        wdt.driver_data = cc;
  97        wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
  98        wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
  99        wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
 100
 101        pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
 102                                             cc->core->bus->num, &wdt,
 103                                             sizeof(wdt));
 104        if (IS_ERR(pdev))
 105                return PTR_ERR(pdev);
 106
 107        cc->watchdog = pdev;
 108
 109        return 0;
 110}
 111
 112void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc)
 113{
 114        if (cc->early_setup_done)
 115                return;
 116
 117        spin_lock_init(&cc->gpio_lock);
 118
 119        if (cc->core->id.rev >= 11)
 120                cc->status = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 121        cc->capabilities = bcma_cc_read32(cc, BCMA_CC_CAP);
 122        if (cc->core->id.rev >= 35)
 123                cc->capabilities_ext = bcma_cc_read32(cc, BCMA_CC_CAP_EXT);
 124
 125        if (cc->capabilities & BCMA_CC_CAP_PMU)
 126                bcma_pmu_early_init(cc);
 127
 128        cc->early_setup_done = true;
 129}
 130
 131void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
 132{
 133        u32 leddc_on = 10;
 134        u32 leddc_off = 90;
 135
 136        if (cc->setup_done)
 137                return;
 138
 139        bcma_core_chipcommon_early_init(cc);
 140
 141        if (cc->core->id.rev >= 20) {
 142                bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, 0);
 143                bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, 0);
 144        }
 145
 146        if (cc->capabilities & BCMA_CC_CAP_PMU)
 147                bcma_pmu_init(cc);
 148        if (cc->capabilities & BCMA_CC_CAP_PCTL)
 149                bcma_err(cc->core->bus, "Power control not implemented!\n");
 150
 151        if (cc->core->id.rev >= 16) {
 152                if (cc->core->bus->sprom.leddc_on_time &&
 153                    cc->core->bus->sprom.leddc_off_time) {
 154                        leddc_on = cc->core->bus->sprom.leddc_on_time;
 155                        leddc_off = cc->core->bus->sprom.leddc_off_time;
 156                }
 157                bcma_cc_write32(cc, BCMA_CC_GPIOTIMER,
 158                        ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 159                         (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 160        }
 161        cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc);
 162
 163        cc->setup_done = true;
 164}
 165
 166/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 167u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
 168{
 169        u32 maxt;
 170        enum bcma_clkmode clkmode;
 171
 172        maxt = bcma_chipco_watchdog_get_max_timer(cc);
 173        if (cc->capabilities & BCMA_CC_CAP_PMU) {
 174                if (ticks == 1)
 175                        ticks = 2;
 176                else if (ticks > maxt)
 177                        ticks = maxt;
 178                bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
 179        } else {
 180                clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
 181                bcma_core_set_clockmode(cc->core, clkmode);
 182                if (ticks > maxt)
 183                        ticks = maxt;
 184                /* instant NMI */
 185                bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
 186        }
 187        return ticks;
 188}
 189
 190void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
 191{
 192        bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value);
 193}
 194
 195u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask)
 196{
 197        return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask;
 198}
 199
 200u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
 201{
 202        return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
 203}
 204
 205u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
 206{
 207        unsigned long flags;
 208        u32 res;
 209
 210        spin_lock_irqsave(&cc->gpio_lock, flags);
 211        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
 212        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 213
 214        return res;
 215}
 216
 217u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
 218{
 219        unsigned long flags;
 220        u32 res;
 221
 222        spin_lock_irqsave(&cc->gpio_lock, flags);
 223        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
 224        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 225
 226        return res;
 227}
 228
 229/*
 230 * If the bit is set to 0, chipcommon controlls this GPIO,
 231 * if the bit is set to 1, it is used by some part of the chip and not our code.
 232 */
 233u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
 234{
 235        unsigned long flags;
 236        u32 res;
 237
 238        spin_lock_irqsave(&cc->gpio_lock, flags);
 239        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
 240        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 241
 242        return res;
 243}
 244EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
 245
 246u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
 247{
 248        unsigned long flags;
 249        u32 res;
 250
 251        spin_lock_irqsave(&cc->gpio_lock, flags);
 252        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
 253        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 254
 255        return res;
 256}
 257
 258u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
 259{
 260        unsigned long flags;
 261        u32 res;
 262
 263        spin_lock_irqsave(&cc->gpio_lock, flags);
 264        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 265        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 266
 267        return res;
 268}
 269
 270u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value)
 271{
 272        unsigned long flags;
 273        u32 res;
 274
 275        if (cc->core->id.rev < 20)
 276                return 0;
 277
 278        spin_lock_irqsave(&cc->gpio_lock, flags);
 279        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLUP, mask, value);
 280        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 281
 282        return res;
 283}
 284
 285u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
 286{
 287        unsigned long flags;
 288        u32 res;
 289
 290        if (cc->core->id.rev < 20)
 291                return 0;
 292
 293        spin_lock_irqsave(&cc->gpio_lock, flags);
 294        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLDOWN, mask, value);
 295        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 296
 297        return res;
 298}
 299
 300#ifdef CONFIG_BCMA_DRIVER_MIPS
 301void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 302{
 303        unsigned int irq;
 304        u32 baud_base;
 305        u32 i;
 306        unsigned int ccrev = cc->core->id.rev;
 307        struct bcma_serial_port *ports = cc->serial_ports;
 308
 309        if (ccrev >= 11 && ccrev != 15) {
 310                baud_base = bcma_chipco_get_alp_clock(cc);
 311                if (ccrev >= 21) {
 312                        /* Turn off UART clock before switching clocksource. */
 313                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
 314                                       bcma_cc_read32(cc, BCMA_CC_CORECTL)
 315                                       & ~BCMA_CC_CORECTL_UARTCLKEN);
 316                }
 317                /* Set the override bit so we don't divide it */
 318                bcma_cc_write32(cc, BCMA_CC_CORECTL,
 319                               bcma_cc_read32(cc, BCMA_CC_CORECTL)
 320                               | BCMA_CC_CORECTL_UARTCLK0);
 321                if (ccrev >= 21) {
 322                        /* Re-enable the UART clock. */
 323                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
 324                                       bcma_cc_read32(cc, BCMA_CC_CORECTL)
 325                                       | BCMA_CC_CORECTL_UARTCLKEN);
 326                }
 327        } else {
 328                bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
 329                return;
 330        }
 331
 332        irq = bcma_core_mips_irq(cc->core);
 333
 334        /* Determine the registers of the UARTs */
 335        cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
 336        for (i = 0; i < cc->nr_serial_ports; i++) {
 337                ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
 338                                (i * 256);
 339                ports[i].irq = irq;
 340                ports[i].baud_base = baud_base;
 341                ports[i].reg_shift = 0;
 342        }
 343}
 344#endif /* CONFIG_BCMA_DRIVER_MIPS */
 345
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.