linux/arch/mips/bcm63xx/clk.c
<<
>>
Prefs
   1/*
   2 * This file is subject to the terms and conditions of the GNU General Public
   3 * License.  See the file "COPYING" in the main directory of this archive
   4 * for more details.
   5 *
   6 * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
   7 */
   8
   9#include <linux/module.h>
  10#include <linux/mutex.h>
  11#include <linux/err.h>
  12#include <linux/clk.h>
  13#include <linux/delay.h>
  14#include <bcm63xx_cpu.h>
  15#include <bcm63xx_io.h>
  16#include <bcm63xx_regs.h>
  17#include <bcm63xx_reset.h>
  18
  19struct clk {
  20        void            (*set)(struct clk *, int);
  21        unsigned int    rate;
  22        unsigned int    usage;
  23        int             id;
  24};
  25
  26static DEFINE_MUTEX(clocks_mutex);
  27
  28
  29static void clk_enable_unlocked(struct clk *clk)
  30{
  31        if (clk->set && (clk->usage++) == 0)
  32                clk->set(clk, 1);
  33}
  34
  35static void clk_disable_unlocked(struct clk *clk)
  36{
  37        if (clk->set && (--clk->usage) == 0)
  38                clk->set(clk, 0);
  39}
  40
  41static void bcm_hwclock_set(u32 mask, int enable)
  42{
  43        u32 reg;
  44
  45        reg = bcm_perf_readl(PERF_CKCTL_REG);
  46        if (enable)
  47                reg |= mask;
  48        else
  49                reg &= ~mask;
  50        bcm_perf_writel(reg, PERF_CKCTL_REG);
  51}
  52
  53/*
  54 * Ethernet MAC "misc" clock: dma clocks and main clock on 6348
  55 */
  56static void enet_misc_set(struct clk *clk, int enable)
  57{
  58        u32 mask;
  59
  60        if (BCMCPU_IS_6338())
  61                mask = CKCTL_6338_ENET_EN;
  62        else if (BCMCPU_IS_6345())
  63                mask = CKCTL_6345_ENET_EN;
  64        else if (BCMCPU_IS_6348())
  65                mask = CKCTL_6348_ENET_EN;
  66        else
  67                /* BCMCPU_IS_6358 */
  68                mask = CKCTL_6358_EMUSB_EN;
  69        bcm_hwclock_set(mask, enable);
  70}
  71
  72static struct clk clk_enet_misc = {
  73        .set    = enet_misc_set,
  74};
  75
  76/*
  77 * Ethernet MAC clocks: only revelant on 6358, silently enable misc
  78 * clocks
  79 */
  80static void enetx_set(struct clk *clk, int enable)
  81{
  82        if (enable)
  83                clk_enable_unlocked(&clk_enet_misc);
  84        else
  85                clk_disable_unlocked(&clk_enet_misc);
  86
  87        if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
  88                u32 mask;
  89
  90                if (clk->id == 0)
  91                        mask = CKCTL_6358_ENET0_EN;
  92                else
  93                        mask = CKCTL_6358_ENET1_EN;
  94                bcm_hwclock_set(mask, enable);
  95        }
  96}
  97
  98static struct clk clk_enet0 = {
  99        .id     = 0,
 100        .set    = enetx_set,
 101};
 102
 103static struct clk clk_enet1 = {
 104        .id     = 1,
 105        .set    = enetx_set,
 106};
 107
 108/*
 109 * Ethernet PHY clock
 110 */
 111static void ephy_set(struct clk *clk, int enable)
 112{
 113        if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
 114                bcm_hwclock_set(CKCTL_6358_EPHY_EN, enable);
 115}
 116
 117
 118static struct clk clk_ephy = {
 119        .set    = ephy_set,
 120};
 121
 122/*
 123 * Ethernet switch clock
 124 */
 125static void enetsw_set(struct clk *clk, int enable)
 126{
 127        if (BCMCPU_IS_6328())
 128                bcm_hwclock_set(CKCTL_6328_ROBOSW_EN, enable);
 129        else if (BCMCPU_IS_6362())
 130                bcm_hwclock_set(CKCTL_6362_ROBOSW_EN, enable);
 131        else if (BCMCPU_IS_6368())
 132                bcm_hwclock_set(CKCTL_6368_ROBOSW_EN |
 133                                CKCTL_6368_SWPKT_USB_EN |
 134                                CKCTL_6368_SWPKT_SAR_EN,
 135                                enable);
 136        else
 137                return;
 138
 139        if (enable) {
 140                /* reset switch core afer clock change */
 141                bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 1);
 142                msleep(10);
 143                bcm63xx_core_set_reset(BCM63XX_RESET_ENETSW, 0);
 144                msleep(10);
 145        }
 146}
 147
 148static struct clk clk_enetsw = {
 149        .set    = enetsw_set,
 150};
 151
 152/*
 153 * PCM clock
 154 */
 155static void pcm_set(struct clk *clk, int enable)
 156{
 157        if (BCMCPU_IS_3368())
 158                bcm_hwclock_set(CKCTL_3368_PCM_EN, enable);
 159        if (BCMCPU_IS_6358())
 160                bcm_hwclock_set(CKCTL_6358_PCM_EN, enable);
 161}
 162
 163static struct clk clk_pcm = {
 164        .set    = pcm_set,
 165};
 166
 167/*
 168 * USB host clock
 169 */
 170static void usbh_set(struct clk *clk, int enable)
 171{
 172        if (BCMCPU_IS_6328())
 173                bcm_hwclock_set(CKCTL_6328_USBH_EN, enable);
 174        else if (BCMCPU_IS_6348())
 175                bcm_hwclock_set(CKCTL_6348_USBH_EN, enable);
 176        else if (BCMCPU_IS_6362())
 177                bcm_hwclock_set(CKCTL_6362_USBH_EN, enable);
 178        else if (BCMCPU_IS_6368())
 179                bcm_hwclock_set(CKCTL_6368_USBH_EN, enable);
 180}
 181
 182static struct clk clk_usbh = {
 183        .set    = usbh_set,
 184};
 185
 186/*
 187 * USB device clock
 188 */
 189static void usbd_set(struct clk *clk, int enable)
 190{
 191        if (BCMCPU_IS_6328())
 192                bcm_hwclock_set(CKCTL_6328_USBD_EN, enable);
 193        else if (BCMCPU_IS_6362())
 194                bcm_hwclock_set(CKCTL_6362_USBD_EN, enable);
 195        else if (BCMCPU_IS_6368())
 196                bcm_hwclock_set(CKCTL_6368_USBD_EN, enable);
 197}
 198
 199static struct clk clk_usbd = {
 200        .set    = usbd_set,
 201};
 202
 203/*
 204 * SPI clock
 205 */
 206static void spi_set(struct clk *clk, int enable)
 207{
 208        u32 mask;
 209
 210        if (BCMCPU_IS_6338())
 211                mask = CKCTL_6338_SPI_EN;
 212        else if (BCMCPU_IS_6348())
 213                mask = CKCTL_6348_SPI_EN;
 214        else if (BCMCPU_IS_3368() || BCMCPU_IS_6358())
 215                mask = CKCTL_6358_SPI_EN;
 216        else if (BCMCPU_IS_6362())
 217                mask = CKCTL_6362_SPI_EN;
 218        else
 219                /* BCMCPU_IS_6368 */
 220                mask = CKCTL_6368_SPI_EN;
 221        bcm_hwclock_set(mask, enable);
 222}
 223
 224static struct clk clk_spi = {
 225        .set    = spi_set,
 226};
 227
 228/*
 229 * HSSPI clock
 230 */
 231static void hsspi_set(struct clk *clk, int enable)
 232{
 233        u32 mask;
 234
 235        if (BCMCPU_IS_6328())
 236                mask = CKCTL_6328_HSSPI_EN;
 237        else if (BCMCPU_IS_6362())
 238                mask = CKCTL_6362_HSSPI_EN;
 239        else
 240                return;
 241
 242        bcm_hwclock_set(mask, enable);
 243}
 244
 245static struct clk clk_hsspi = {
 246        .set    = hsspi_set,
 247};
 248
 249
 250/*
 251 * XTM clock
 252 */
 253static void xtm_set(struct clk *clk, int enable)
 254{
 255        if (!BCMCPU_IS_6368())
 256                return;
 257
 258        bcm_hwclock_set(CKCTL_6368_SAR_EN |
 259                        CKCTL_6368_SWPKT_SAR_EN, enable);
 260
 261        if (enable) {
 262                /* reset sar core afer clock change */
 263                bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 1);
 264                mdelay(1);
 265                bcm63xx_core_set_reset(BCM63XX_RESET_SAR, 0);
 266                mdelay(1);
 267        }
 268}
 269
 270
 271static struct clk clk_xtm = {
 272        .set    = xtm_set,
 273};
 274
 275/*
 276 * IPsec clock
 277 */
 278static void ipsec_set(struct clk *clk, int enable)
 279{
 280        if (BCMCPU_IS_6362())
 281                bcm_hwclock_set(CKCTL_6362_IPSEC_EN, enable);
 282        else if (BCMCPU_IS_6368())
 283                bcm_hwclock_set(CKCTL_6368_IPSEC_EN, enable);
 284}
 285
 286static struct clk clk_ipsec = {
 287        .set    = ipsec_set,
 288};
 289
 290/*
 291 * PCIe clock
 292 */
 293
 294static void pcie_set(struct clk *clk, int enable)
 295{
 296        if (BCMCPU_IS_6328())
 297                bcm_hwclock_set(CKCTL_6328_PCIE_EN, enable);
 298        else if (BCMCPU_IS_6362())
 299                bcm_hwclock_set(CKCTL_6362_PCIE_EN, enable);
 300}
 301
 302static struct clk clk_pcie = {
 303        .set    = pcie_set,
 304};
 305
 306/*
 307 * Internal peripheral clock
 308 */
 309static struct clk clk_periph = {
 310        .rate   = (50 * 1000 * 1000),
 311};
 312
 313
 314/*
 315 * Linux clock API implementation
 316 */
 317int clk_enable(struct clk *clk)
 318{
 319        mutex_lock(&clocks_mutex);
 320        clk_enable_unlocked(clk);
 321        mutex_unlock(&clocks_mutex);
 322        return 0;
 323}
 324
 325EXPORT_SYMBOL(clk_enable);
 326
 327void clk_disable(struct clk *clk)
 328{
 329        mutex_lock(&clocks_mutex);
 330        clk_disable_unlocked(clk);
 331        mutex_unlock(&clocks_mutex);
 332}
 333
 334EXPORT_SYMBOL(clk_disable);
 335
 336unsigned long clk_get_rate(struct clk *clk)
 337{
 338        return clk->rate;
 339}
 340
 341EXPORT_SYMBOL(clk_get_rate);
 342
 343int clk_set_rate(struct clk *clk, unsigned long rate)
 344{
 345        return 0;
 346}
 347EXPORT_SYMBOL_GPL(clk_set_rate);
 348
 349long clk_round_rate(struct clk *clk, unsigned long rate)
 350{
 351        return 0;
 352}
 353EXPORT_SYMBOL_GPL(clk_round_rate);
 354
 355struct clk *clk_get(struct device *dev, const char *id)
 356{
 357        if (!strcmp(id, "enet0"))
 358                return &clk_enet0;
 359        if (!strcmp(id, "enet1"))
 360                return &clk_enet1;
 361        if (!strcmp(id, "enetsw"))
 362                return &clk_enetsw;
 363        if (!strcmp(id, "ephy"))
 364                return &clk_ephy;
 365        if (!strcmp(id, "usbh"))
 366                return &clk_usbh;
 367        if (!strcmp(id, "usbd"))
 368                return &clk_usbd;
 369        if (!strcmp(id, "spi"))
 370                return &clk_spi;
 371        if (!strcmp(id, "hsspi"))
 372                return &clk_hsspi;
 373        if (!strcmp(id, "xtm"))
 374                return &clk_xtm;
 375        if (!strcmp(id, "periph"))
 376                return &clk_periph;
 377        if ((BCMCPU_IS_3368() || BCMCPU_IS_6358()) && !strcmp(id, "pcm"))
 378                return &clk_pcm;
 379        if ((BCMCPU_IS_6362() || BCMCPU_IS_6368()) && !strcmp(id, "ipsec"))
 380                return &clk_ipsec;
 381        if ((BCMCPU_IS_6328() || BCMCPU_IS_6362()) && !strcmp(id, "pcie"))
 382                return &clk_pcie;
 383        return ERR_PTR(-ENOENT);
 384}
 385
 386EXPORT_SYMBOL(clk_get);
 387
 388void clk_put(struct clk *clk)
 389{
 390}
 391
 392EXPORT_SYMBOL(clk_put);
 393
 394#define HSSPI_PLL_HZ_6328       133333333
 395#define HSSPI_PLL_HZ_6362       400000000
 396
 397static int __init bcm63xx_clk_init(void)
 398{
 399        switch (bcm63xx_get_cpu_id()) {
 400        case BCM6328_CPU_ID:
 401                clk_hsspi.rate = HSSPI_PLL_HZ_6328;
 402                break;
 403        case BCM6362_CPU_ID:
 404                clk_hsspi.rate = HSSPI_PLL_HZ_6362;
 405                break;
 406        }
 407
 408        return 0;
 409}
 410arch_initcall(bcm63xx_clk_init);
 411