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