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                u32 pullup = 0, pulldown = 0;
 144
 145                if (cc->core->bus->chipinfo.id == BCMA_CHIP_ID_BCM43142) {
 146                        pullup = 0x402e0;
 147                        pulldown = 0x20500;
 148                }
 149
 150                bcma_cc_write32(cc, BCMA_CC_GPIOPULLUP, pullup);
 151                bcma_cc_write32(cc, BCMA_CC_GPIOPULLDOWN, pulldown);
 152        }
 153
 154        if (cc->capabilities & BCMA_CC_CAP_PMU)
 155                bcma_pmu_init(cc);
 156        if (cc->capabilities & BCMA_CC_CAP_PCTL)
 157                bcma_err(cc->core->bus, "Power control not implemented!\n");
 158
 159        if (cc->core->id.rev >= 16) {
 160                if (cc->core->bus->sprom.leddc_on_time &&
 161                    cc->core->bus->sprom.leddc_off_time) {
 162                        leddc_on = cc->core->bus->sprom.leddc_on_time;
 163                        leddc_off = cc->core->bus->sprom.leddc_off_time;
 164                }
 165                bcma_cc_write32(cc, BCMA_CC_GPIOTIMER,
 166                        ((leddc_on << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
 167                         (leddc_off << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT)));
 168        }
 169        cc->ticks_per_ms = bcma_chipco_watchdog_ticks_per_ms(cc);
 170
 171        cc->setup_done = true;
 172}
 173
 174/* Set chip watchdog reset timer to fire in 'ticks' backplane cycles */
 175u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
 176{
 177        u32 maxt;
 178        enum bcma_clkmode clkmode;
 179
 180        maxt = bcma_chipco_watchdog_get_max_timer(cc);
 181        if (cc->capabilities & BCMA_CC_CAP_PMU) {
 182                if (ticks == 1)
 183                        ticks = 2;
 184                else if (ticks > maxt)
 185                        ticks = maxt;
 186                bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
 187        } else {
 188                clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
 189                bcma_core_set_clockmode(cc->core, clkmode);
 190                if (ticks > maxt)
 191                        ticks = maxt;
 192                /* instant NMI */
 193                bcma_cc_write32(cc, BCMA_CC_WATCHDOG, ticks);
 194        }
 195        return ticks;
 196}
 197
 198void bcma_chipco_irq_mask(struct bcma_drv_cc *cc, u32 mask, u32 value)
 199{
 200        bcma_cc_write32_masked(cc, BCMA_CC_IRQMASK, mask, value);
 201}
 202
 203u32 bcma_chipco_irq_status(struct bcma_drv_cc *cc, u32 mask)
 204{
 205        return bcma_cc_read32(cc, BCMA_CC_IRQSTAT) & mask;
 206}
 207
 208u32 bcma_chipco_gpio_in(struct bcma_drv_cc *cc, u32 mask)
 209{
 210        return bcma_cc_read32(cc, BCMA_CC_GPIOIN) & mask;
 211}
 212
 213u32 bcma_chipco_gpio_out(struct bcma_drv_cc *cc, u32 mask, u32 value)
 214{
 215        unsigned long flags;
 216        u32 res;
 217
 218        spin_lock_irqsave(&cc->gpio_lock, flags);
 219        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUT, mask, value);
 220        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 221
 222        return res;
 223}
 224EXPORT_SYMBOL_GPL(bcma_chipco_gpio_out);
 225
 226u32 bcma_chipco_gpio_outen(struct bcma_drv_cc *cc, u32 mask, u32 value)
 227{
 228        unsigned long flags;
 229        u32 res;
 230
 231        spin_lock_irqsave(&cc->gpio_lock, flags);
 232        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOOUTEN, mask, value);
 233        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 234
 235        return res;
 236}
 237EXPORT_SYMBOL_GPL(bcma_chipco_gpio_outen);
 238
 239/*
 240 * If the bit is set to 0, chipcommon controlls this GPIO,
 241 * if the bit is set to 1, it is used by some part of the chip and not our code.
 242 */
 243u32 bcma_chipco_gpio_control(struct bcma_drv_cc *cc, u32 mask, u32 value)
 244{
 245        unsigned long flags;
 246        u32 res;
 247
 248        spin_lock_irqsave(&cc->gpio_lock, flags);
 249        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOCTL, mask, value);
 250        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 251
 252        return res;
 253}
 254EXPORT_SYMBOL_GPL(bcma_chipco_gpio_control);
 255
 256u32 bcma_chipco_gpio_intmask(struct bcma_drv_cc *cc, u32 mask, u32 value)
 257{
 258        unsigned long flags;
 259        u32 res;
 260
 261        spin_lock_irqsave(&cc->gpio_lock, flags);
 262        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOIRQ, mask, value);
 263        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 264
 265        return res;
 266}
 267
 268u32 bcma_chipco_gpio_polarity(struct bcma_drv_cc *cc, u32 mask, u32 value)
 269{
 270        unsigned long flags;
 271        u32 res;
 272
 273        spin_lock_irqsave(&cc->gpio_lock, flags);
 274        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPOL, mask, value);
 275        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 276
 277        return res;
 278}
 279
 280u32 bcma_chipco_gpio_pullup(struct bcma_drv_cc *cc, u32 mask, u32 value)
 281{
 282        unsigned long flags;
 283        u32 res;
 284
 285        if (cc->core->id.rev < 20)
 286                return 0;
 287
 288        spin_lock_irqsave(&cc->gpio_lock, flags);
 289        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLUP, mask, value);
 290        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 291
 292        return res;
 293}
 294
 295u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value)
 296{
 297        unsigned long flags;
 298        u32 res;
 299
 300        if (cc->core->id.rev < 20)
 301                return 0;
 302
 303        spin_lock_irqsave(&cc->gpio_lock, flags);
 304        res = bcma_cc_write32_masked(cc, BCMA_CC_GPIOPULLDOWN, mask, value);
 305        spin_unlock_irqrestore(&cc->gpio_lock, flags);
 306
 307        return res;
 308}
 309
 310#ifdef CONFIG_BCMA_DRIVER_MIPS
 311void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
 312{
 313        unsigned int irq;
 314        u32 baud_base;
 315        u32 i;
 316        unsigned int ccrev = cc->core->id.rev;
 317        struct bcma_serial_port *ports = cc->serial_ports;
 318
 319        if (ccrev >= 11 && ccrev != 15) {
 320                baud_base = bcma_chipco_get_alp_clock(cc);
 321                if (ccrev >= 21) {
 322                        /* Turn off UART clock before switching clocksource. */
 323                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
 324                                       bcma_cc_read32(cc, BCMA_CC_CORECTL)
 325                                       & ~BCMA_CC_CORECTL_UARTCLKEN);
 326                }
 327                /* Set the override bit so we don't divide it */
 328                bcma_cc_write32(cc, BCMA_CC_CORECTL,
 329                               bcma_cc_read32(cc, BCMA_CC_CORECTL)
 330                               | BCMA_CC_CORECTL_UARTCLK0);
 331                if (ccrev >= 21) {
 332                        /* Re-enable the UART clock. */
 333                        bcma_cc_write32(cc, BCMA_CC_CORECTL,
 334                                       bcma_cc_read32(cc, BCMA_CC_CORECTL)
 335                                       | BCMA_CC_CORECTL_UARTCLKEN);
 336                }
 337        } else {
 338                bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
 339                return;
 340        }
 341
 342        irq = bcma_core_irq(cc->core);
 343
 344        /* Determine the registers of the UARTs */
 345        cc->nr_serial_ports = (cc->capabilities & BCMA_CC_CAP_NRUART);
 346        for (i = 0; i < cc->nr_serial_ports; i++) {
 347                ports[i].regs = cc->core->io_addr + BCMA_CC_UART0_DATA +
 348                                (i * 256);
 349                ports[i].irq = irq;
 350                ports[i].baud_base = baud_base;
 351                ports[i].reg_shift = 0;
 352        }
 353}
 354#endif /* CONFIG_BCMA_DRIVER_MIPS */
 355
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.