linux/drivers/bcma/driver_chipcommon_pmu.c
<<
>>
Prefs
   1/*
   2 * Broadcom specific AMBA
   3 * ChipCommon Power Management Unit driver
   4 *
   5 * Copyright 2009, Michael Buesch <m@bues.ch>
   6 * Copyright 2007, Broadcom Corporation
   7 *
   8 * Licensed under the GNU/GPL. See COPYING for details.
   9 */
  10
  11#include "bcma_private.h"
  12#include <linux/export.h>
  13#include <linux/bcma/bcma.h>
  14
  15static u32 bcma_chipco_pll_read(struct bcma_drv_cc *cc, u32 offset)
  16{
  17        bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
  18        bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
  19        return bcma_cc_read32(cc, BCMA_CC_PLLCTL_DATA);
  20}
  21
  22void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset, u32 value)
  23{
  24        bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
  25        bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
  26        bcma_cc_write32(cc, BCMA_CC_PLLCTL_DATA, value);
  27}
  28EXPORT_SYMBOL_GPL(bcma_chipco_pll_write);
  29
  30void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
  31                             u32 set)
  32{
  33        bcma_cc_write32(cc, BCMA_CC_PLLCTL_ADDR, offset);
  34        bcma_cc_read32(cc, BCMA_CC_PLLCTL_ADDR);
  35        bcma_cc_maskset32(cc, BCMA_CC_PLLCTL_DATA, mask, set);
  36}
  37EXPORT_SYMBOL_GPL(bcma_chipco_pll_maskset);
  38
  39void bcma_chipco_chipctl_maskset(struct bcma_drv_cc *cc,
  40                                 u32 offset, u32 mask, u32 set)
  41{
  42        bcma_cc_write32(cc, BCMA_CC_CHIPCTL_ADDR, offset);
  43        bcma_cc_read32(cc, BCMA_CC_CHIPCTL_ADDR);
  44        bcma_cc_maskset32(cc, BCMA_CC_CHIPCTL_DATA, mask, set);
  45}
  46EXPORT_SYMBOL_GPL(bcma_chipco_chipctl_maskset);
  47
  48void bcma_chipco_regctl_maskset(struct bcma_drv_cc *cc, u32 offset, u32 mask,
  49                                u32 set)
  50{
  51        bcma_cc_write32(cc, BCMA_CC_REGCTL_ADDR, offset);
  52        bcma_cc_read32(cc, BCMA_CC_REGCTL_ADDR);
  53        bcma_cc_maskset32(cc, BCMA_CC_REGCTL_DATA, mask, set);
  54}
  55EXPORT_SYMBOL_GPL(bcma_chipco_regctl_maskset);
  56
  57static void bcma_pmu_pll_init(struct bcma_drv_cc *cc)
  58{
  59        struct bcma_bus *bus = cc->core->bus;
  60
  61        switch (bus->chipinfo.id) {
  62        case 0x4313:
  63        case 0x4331:
  64        case 43224:
  65        case 43225:
  66                break;
  67        default:
  68                pr_err("PLL init unknown for device 0x%04X\n",
  69                        bus->chipinfo.id);
  70        }
  71}
  72
  73static void bcma_pmu_resources_init(struct bcma_drv_cc *cc)
  74{
  75        struct bcma_bus *bus = cc->core->bus;
  76        u32 min_msk = 0, max_msk = 0;
  77
  78        switch (bus->chipinfo.id) {
  79        case 0x4313:
  80                min_msk = 0x200D;
  81                max_msk = 0xFFFF;
  82                break;
  83        case 43224:
  84        case 43225:
  85                break;
  86        default:
  87                pr_err("PMU resource config unknown for device 0x%04X\n",
  88                        bus->chipinfo.id);
  89        }
  90
  91        /* Set the resource masks. */
  92        if (min_msk)
  93                bcma_cc_write32(cc, BCMA_CC_PMU_MINRES_MSK, min_msk);
  94        if (max_msk)
  95                bcma_cc_write32(cc, BCMA_CC_PMU_MAXRES_MSK, max_msk);
  96}
  97
  98void bcma_pmu_swreg_init(struct bcma_drv_cc *cc)
  99{
 100        struct bcma_bus *bus = cc->core->bus;
 101
 102        switch (bus->chipinfo.id) {
 103        case 0x4313:
 104        case 0x4331:
 105        case 43224:
 106        case 43225:
 107                break;
 108        default:
 109                pr_err("PMU switch/regulators init unknown for device "
 110                        "0x%04X\n", bus->chipinfo.id);
 111        }
 112}
 113
 114/* Disable to allow reading SPROM. Don't know the adventages of enabling it. */
 115void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable)
 116{
 117        struct bcma_bus *bus = cc->core->bus;
 118        u32 val;
 119
 120        val = bcma_cc_read32(cc, BCMA_CC_CHIPCTL);
 121        if (enable) {
 122                val |= BCMA_CHIPCTL_4331_EXTPA_EN;
 123                if (bus->chipinfo.pkg == 9 || bus->chipinfo.pkg == 11)
 124                        val |= BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
 125        } else {
 126                val &= ~BCMA_CHIPCTL_4331_EXTPA_EN;
 127                val &= ~BCMA_CHIPCTL_4331_EXTPA_ON_GPIO2_5;
 128        }
 129        bcma_cc_write32(cc, BCMA_CC_CHIPCTL, val);
 130}
 131
 132void bcma_pmu_workarounds(struct bcma_drv_cc *cc)
 133{
 134        struct bcma_bus *bus = cc->core->bus;
 135
 136        switch (bus->chipinfo.id) {
 137        case 0x4313:
 138                bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x7);
 139                break;
 140        case 0x4331:
 141                /* BCM4331 workaround is SPROM-related, we put it in sprom.c */
 142                break;
 143        case 43224:
 144                if (bus->chipinfo.rev == 0) {
 145                        pr_err("Workarounds for 43224 rev 0 not fully "
 146                                "implemented\n");
 147                        bcma_chipco_chipctl_maskset(cc, 0, ~0, 0x00F000F0);
 148                } else {
 149                        bcma_chipco_chipctl_maskset(cc, 0, ~0, 0xF0);
 150                }
 151                break;
 152        case 43225:
 153                break;
 154        default:
 155                pr_err("Workarounds unknown for device 0x%04X\n",
 156                        bus->chipinfo.id);
 157        }
 158}
 159
 160void bcma_pmu_init(struct bcma_drv_cc *cc)
 161{
 162        u32 pmucap;
 163
 164        pmucap = bcma_cc_read32(cc, BCMA_CC_PMU_CAP);
 165        cc->pmu.rev = (pmucap & BCMA_CC_PMU_CAP_REVISION);
 166
 167        pr_debug("Found rev %u PMU (capabilities 0x%08X)\n", cc->pmu.rev,
 168                 pmucap);
 169
 170        if (cc->pmu.rev == 1)
 171                bcma_cc_mask32(cc, BCMA_CC_PMU_CTL,
 172                              ~BCMA_CC_PMU_CTL_NOILPONW);
 173        else
 174                bcma_cc_set32(cc, BCMA_CC_PMU_CTL,
 175                             BCMA_CC_PMU_CTL_NOILPONW);
 176
 177        if (cc->core->id.id == 0x4329 && cc->core->id.rev == 2)
 178                pr_err("Fix for 4329b0 bad LPOM state not implemented!\n");
 179
 180        bcma_pmu_pll_init(cc);
 181        bcma_pmu_resources_init(cc);
 182        bcma_pmu_swreg_init(cc);
 183        bcma_pmu_workarounds(cc);
 184}
 185
 186u32 bcma_pmu_alp_clock(struct bcma_drv_cc *cc)
 187{
 188        struct bcma_bus *bus = cc->core->bus;
 189
 190        switch (bus->chipinfo.id) {
 191        case 0x4716:
 192        case 0x4748:
 193        case 47162:
 194        case 0x4313:
 195        case 0x5357:
 196        case 0x4749:
 197        case 53572:
 198                /* always 20Mhz */
 199                return 20000 * 1000;
 200        case 0x5356:
 201        case 0x5300:
 202                /* always 25Mhz */
 203                return 25000 * 1000;
 204        default:
 205                pr_warn("No ALP clock specified for %04X device, "
 206                        "pmu rev. %d, using default %d Hz\n",
 207                        bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_ALP_CLOCK);
 208        }
 209        return BCMA_CC_PMU_ALP_CLOCK;
 210}
 211
 212/* Find the output of the "m" pll divider given pll controls that start with
 213 * pllreg "pll0" i.e. 12 for main 6 for phy, 0 for misc.
 214 */
 215static u32 bcma_pmu_clock(struct bcma_drv_cc *cc, u32 pll0, u32 m)
 216{
 217        u32 tmp, div, ndiv, p1, p2, fc;
 218        struct bcma_bus *bus = cc->core->bus;
 219
 220        BUG_ON((pll0 & 3) || (pll0 > BCMA_CC_PMU4716_MAINPLL_PLL0));
 221
 222        BUG_ON(!m || m > 4);
 223
 224        if (bus->chipinfo.id == 0x5357 || bus->chipinfo.id == 0x4749) {
 225                /* Detect failure in clock setting */
 226                tmp = bcma_cc_read32(cc, BCMA_CC_CHIPSTAT);
 227                if (tmp & 0x40000)
 228                        return 133 * 1000000;
 229        }
 230
 231        tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_P1P2_OFF);
 232        p1 = (tmp & BCMA_CC_PPL_P1_MASK) >> BCMA_CC_PPL_P1_SHIFT;
 233        p2 = (tmp & BCMA_CC_PPL_P2_MASK) >> BCMA_CC_PPL_P2_SHIFT;
 234
 235        tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_M14_OFF);
 236        div = (tmp >> ((m - 1) * BCMA_CC_PPL_MDIV_WIDTH)) &
 237                BCMA_CC_PPL_MDIV_MASK;
 238
 239        tmp = bcma_chipco_pll_read(cc, pll0 + BCMA_CC_PPL_NM5_OFF);
 240        ndiv = (tmp & BCMA_CC_PPL_NDIV_MASK) >> BCMA_CC_PPL_NDIV_SHIFT;
 241
 242        /* Do calculation in Mhz */
 243        fc = bcma_pmu_alp_clock(cc) / 1000000;
 244        fc = (p1 * ndiv * fc) / p2;
 245
 246        /* Return clock in Hertz */
 247        return (fc / div) * 1000000;
 248}
 249
 250/* query bus clock frequency for PMU-enabled chipcommon */
 251u32 bcma_pmu_get_clockcontrol(struct bcma_drv_cc *cc)
 252{
 253        struct bcma_bus *bus = cc->core->bus;
 254
 255        switch (bus->chipinfo.id) {
 256        case 0x4716:
 257        case 0x4748:
 258        case 47162:
 259                return bcma_pmu_clock(cc, BCMA_CC_PMU4716_MAINPLL_PLL0,
 260                                      BCMA_CC_PMU5_MAINPLL_SSB);
 261        case 0x5356:
 262                return bcma_pmu_clock(cc, BCMA_CC_PMU5356_MAINPLL_PLL0,
 263                                      BCMA_CC_PMU5_MAINPLL_SSB);
 264        case 0x5357:
 265        case 0x4749:
 266                return bcma_pmu_clock(cc, BCMA_CC_PMU5357_MAINPLL_PLL0,
 267                                      BCMA_CC_PMU5_MAINPLL_SSB);
 268        case 0x5300:
 269                return bcma_pmu_clock(cc, BCMA_CC_PMU4706_MAINPLL_PLL0,
 270                                      BCMA_CC_PMU5_MAINPLL_SSB);
 271        case 53572:
 272                return 75000000;
 273        default:
 274                pr_warn("No backplane clock specified for %04X device, "
 275                        "pmu rev. %d, using default %d Hz\n",
 276                        bus->chipinfo.id, cc->pmu.rev, BCMA_CC_PMU_HT_CLOCK);
 277        }
 278        return BCMA_CC_PMU_HT_CLOCK;
 279}
 280
 281/* query cpu clock frequency for PMU-enabled chipcommon */
 282u32 bcma_pmu_get_clockcpu(struct bcma_drv_cc *cc)
 283{
 284        struct bcma_bus *bus = cc->core->bus;
 285
 286        if (bus->chipinfo.id == 53572)
 287                return 300000000;
 288
 289        if (cc->pmu.rev >= 5) {
 290                u32 pll;
 291                switch (bus->chipinfo.id) {
 292                case 0x5356:
 293                        pll = BCMA_CC_PMU5356_MAINPLL_PLL0;
 294                        break;
 295                case 0x5357:
 296                case 0x4749:
 297                        pll = BCMA_CC_PMU5357_MAINPLL_PLL0;
 298                        break;
 299                default:
 300                        pll = BCMA_CC_PMU4716_MAINPLL_PLL0;
 301                        break;
 302                }
 303
 304                /* TODO: if (bus->chipinfo.id == 0x5300)
 305                  return si_4706_pmu_clock(sih, osh, cc, PMU4706_MAINPLL_PLL0, PMU5_MAINPLL_CPU); */
 306                return bcma_pmu_clock(cc, pll, BCMA_CC_PMU5_MAINPLL_CPU);
 307        }
 308
 309        return bcma_pmu_get_clockcontrol(cc);
 310}
 311