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