linux/drivers/clk/clk-nomadik.c
<<
>>
Prefs
   1/*
   2 * Nomadik clock implementation
   3 * Copyright (C) 2013 ST-Ericsson AB
   4 * License terms: GNU General Public License (GPL) version 2
   5 * Author: Linus Walleij <linus.walleij@linaro.org>
   6 */
   7
   8#define pr_fmt(fmt) "Nomadik SRC clocks: " fmt
   9
  10#include <linux/bitops.h>
  11#include <linux/clk.h>
  12#include <linux/clkdev.h>
  13#include <linux/err.h>
  14#include <linux/io.h>
  15#include <linux/clk-provider.h>
  16#include <linux/of.h>
  17#include <linux/of_address.h>
  18#include <linux/debugfs.h>
  19#include <linux/seq_file.h>
  20#include <linux/spinlock.h>
  21#include <linux/reboot.h>
  22
  23/*
  24 * The Nomadik clock tree is described in the STN8815A12 DB V4.2
  25 * reference manual for the chip, page 94 ff.
  26 * Clock IDs are in the STn8815 Reference Manual table 3, page 27.
  27 */
  28
  29#define SRC_CR                  0x00U
  30#define SRC_XTALCR              0x0CU
  31#define SRC_XTALCR_XTALTIMEN    BIT(20)
  32#define SRC_XTALCR_SXTALDIS     BIT(19)
  33#define SRC_XTALCR_MXTALSTAT    BIT(2)
  34#define SRC_XTALCR_MXTALEN      BIT(1)
  35#define SRC_XTALCR_MXTALOVER    BIT(0)
  36#define SRC_PLLCR               0x10U
  37#define SRC_PLLCR_PLLTIMEN      BIT(29)
  38#define SRC_PLLCR_PLL2EN        BIT(28)
  39#define SRC_PLLCR_PLL1STAT      BIT(2)
  40#define SRC_PLLCR_PLL1EN        BIT(1)
  41#define SRC_PLLCR_PLL1OVER      BIT(0)
  42#define SRC_PLLFR               0x14U
  43#define SRC_PCKEN0              0x24U
  44#define SRC_PCKDIS0             0x28U
  45#define SRC_PCKENSR0            0x2CU
  46#define SRC_PCKSR0              0x30U
  47#define SRC_PCKEN1              0x34U
  48#define SRC_PCKDIS1             0x38U
  49#define SRC_PCKENSR1            0x3CU
  50#define SRC_PCKSR1              0x40U
  51
  52/* Lock protecting the SRC_CR register */
  53static DEFINE_SPINLOCK(src_lock);
  54/* Base address of the SRC */
  55static void __iomem *src_base;
  56
  57/**
  58 * struct clk_pll1 - Nomadik PLL1 clock
  59 * @hw: corresponding clock hardware entry
  60 * @id: PLL instance: 1 or 2
  61 */
  62struct clk_pll {
  63        struct clk_hw hw;
  64        int id;
  65};
  66
  67/**
  68 * struct clk_src - Nomadik src clock
  69 * @hw: corresponding clock hardware entry
  70 * @id: the clock ID
  71 * @group1: true if the clock is in group1, else it is in group0
  72 * @clkbit: bit 0...31 corresponding to the clock in each clock register
  73 */
  74struct clk_src {
  75        struct clk_hw hw;
  76        int id;
  77        bool group1;
  78        u32 clkbit;
  79};
  80
  81#define to_pll(_hw) container_of(_hw, struct clk_pll, hw)
  82#define to_src(_hw) container_of(_hw, struct clk_src, hw)
  83
  84static int pll_clk_enable(struct clk_hw *hw)
  85{
  86        struct clk_pll *pll = to_pll(hw);
  87        u32 val;
  88
  89        spin_lock(&src_lock);
  90        val = readl(src_base + SRC_PLLCR);
  91        if (pll->id == 1) {
  92                if (val & SRC_PLLCR_PLL1OVER) {
  93                        val |= SRC_PLLCR_PLL1EN;
  94                        writel(val, src_base + SRC_PLLCR);
  95                }
  96        } else if (pll->id == 2) {
  97                val |= SRC_PLLCR_PLL2EN;
  98                writel(val, src_base + SRC_PLLCR);
  99        }
 100        spin_unlock(&src_lock);
 101        return 0;
 102}
 103
 104static void pll_clk_disable(struct clk_hw *hw)
 105{
 106        struct clk_pll *pll = to_pll(hw);
 107        u32 val;
 108
 109        spin_lock(&src_lock);
 110        val = readl(src_base + SRC_PLLCR);
 111        if (pll->id == 1) {
 112                if (val & SRC_PLLCR_PLL1OVER) {
 113                        val &= ~SRC_PLLCR_PLL1EN;
 114                        writel(val, src_base + SRC_PLLCR);
 115                }
 116        } else if (pll->id == 2) {
 117                val &= ~SRC_PLLCR_PLL2EN;
 118                writel(val, src_base + SRC_PLLCR);
 119        }
 120        spin_unlock(&src_lock);
 121}
 122
 123static int pll_clk_is_enabled(struct clk_hw *hw)
 124{
 125        struct clk_pll *pll = to_pll(hw);
 126        u32 val;
 127
 128        val = readl(src_base + SRC_PLLCR);
 129        if (pll->id == 1) {
 130                if (val & SRC_PLLCR_PLL1OVER)
 131                        return !!(val & SRC_PLLCR_PLL1EN);
 132        } else if (pll->id == 2) {
 133                return !!(val & SRC_PLLCR_PLL2EN);
 134        }
 135        return 1;
 136}
 137
 138static unsigned long pll_clk_recalc_rate(struct clk_hw *hw,
 139                                          unsigned long parent_rate)
 140{
 141        struct clk_pll *pll = to_pll(hw);
 142        u32 val;
 143
 144        val = readl(src_base + SRC_PLLFR);
 145
 146        if (pll->id == 1) {
 147                u8 mul;
 148                u8 div;
 149
 150                mul = (val >> 8) & 0x3FU;
 151                mul += 2;
 152                div = val & 0x07U;
 153                return (parent_rate * mul) >> div;
 154        }
 155
 156        if (pll->id == 2) {
 157                u8 mul;
 158
 159                mul = (val >> 24) & 0x3FU;
 160                mul += 2;
 161                return (parent_rate * mul);
 162        }
 163
 164        /* Unknown PLL */
 165        return 0;
 166}
 167
 168
 169static const struct clk_ops pll_clk_ops = {
 170        .enable = pll_clk_enable,
 171        .disable = pll_clk_disable,
 172        .is_enabled = pll_clk_is_enabled,
 173        .recalc_rate = pll_clk_recalc_rate,
 174};
 175
 176static struct clk * __init
 177pll_clk_register(struct device *dev, const char *name,
 178                 const char *parent_name, u32 id)
 179{
 180        struct clk *clk;
 181        struct clk_pll *pll;
 182        struct clk_init_data init;
 183
 184        if (id != 1 && id != 2) {
 185                pr_err("%s: the Nomadik has only PLL 1 & 2\n", __func__);
 186                return ERR_PTR(-EINVAL);
 187        }
 188
 189        pll = kzalloc(sizeof(*pll), GFP_KERNEL);
 190        if (!pll) {
 191                pr_err("%s: could not allocate PLL clk\n", __func__);
 192                return ERR_PTR(-ENOMEM);
 193        }
 194
 195        init.name = name;
 196        init.ops = &pll_clk_ops;
 197        init.parent_names = (parent_name ? &parent_name : NULL);
 198        init.num_parents = (parent_name ? 1 : 0);
 199        pll->hw.init = &init;
 200        pll->id = id;
 201
 202        pr_debug("register PLL1 clock \"%s\"\n", name);
 203
 204        clk = clk_register(dev, &pll->hw);
 205        if (IS_ERR(clk))
 206                kfree(pll);
 207
 208        return clk;
 209}
 210
 211/*
 212 * The Nomadik SRC clocks are gated, but not in the sense that
 213 * you read-modify-write a register. Instead there are separate
 214 * clock enable and clock disable registers. Writing a '1' bit in
 215 * the enable register for a certain clock ungates that clock without
 216 * affecting the other clocks. The disable register works the opposite
 217 * way.
 218 */
 219
 220static int src_clk_enable(struct clk_hw *hw)
 221{
 222        struct clk_src *sclk = to_src(hw);
 223        u32 enreg = sclk->group1 ? SRC_PCKEN1 : SRC_PCKEN0;
 224        u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
 225
 226        writel(sclk->clkbit, src_base + enreg);
 227        /* spin until enabled */
 228        while (!(readl(src_base + sreg) & sclk->clkbit))
 229                cpu_relax();
 230        return 0;
 231}
 232
 233static void src_clk_disable(struct clk_hw *hw)
 234{
 235        struct clk_src *sclk = to_src(hw);
 236        u32 disreg = sclk->group1 ? SRC_PCKDIS1 : SRC_PCKDIS0;
 237        u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
 238
 239        writel(sclk->clkbit, src_base + disreg);
 240        /* spin until disabled */
 241        while (readl(src_base + sreg) & sclk->clkbit)
 242                cpu_relax();
 243}
 244
 245static int src_clk_is_enabled(struct clk_hw *hw)
 246{
 247        struct clk_src *sclk = to_src(hw);
 248        u32 sreg = sclk->group1 ? SRC_PCKSR1 : SRC_PCKSR0;
 249        u32 val = readl(src_base + sreg);
 250
 251        return !!(val & sclk->clkbit);
 252}
 253
 254static unsigned long
 255src_clk_recalc_rate(struct clk_hw *hw,
 256                    unsigned long parent_rate)
 257{
 258        return parent_rate;
 259}
 260
 261static const struct clk_ops src_clk_ops = {
 262        .enable = src_clk_enable,
 263        .disable = src_clk_disable,
 264        .is_enabled = src_clk_is_enabled,
 265        .recalc_rate = src_clk_recalc_rate,
 266};
 267
 268static struct clk * __init
 269src_clk_register(struct device *dev, const char *name,
 270                 const char *parent_name, u8 id)
 271{
 272        struct clk *clk;
 273        struct clk_src *sclk;
 274        struct clk_init_data init;
 275
 276        sclk = kzalloc(sizeof(*sclk), GFP_KERNEL);
 277        if (!sclk) {
 278                pr_err("could not allocate SRC clock %s\n",
 279                        name);
 280                return ERR_PTR(-ENOMEM);
 281        }
 282        init.name = name;
 283        init.ops = &src_clk_ops;
 284        /* Do not force-disable the static SDRAM controller */
 285        if (id == 2)
 286                init.flags = CLK_IGNORE_UNUSED;
 287        else
 288                init.flags = 0;
 289        init.parent_names = (parent_name ? &parent_name : NULL);
 290        init.num_parents = (parent_name ? 1 : 0);
 291        sclk->hw.init = &init;
 292        sclk->id = id;
 293        sclk->group1 = (id > 31);
 294        sclk->clkbit = BIT(id & 0x1f);
 295
 296        pr_debug("register clock \"%s\" ID: %d group: %d bits: %08x\n",
 297                 name, id, sclk->group1, sclk->clkbit);
 298
 299        clk = clk_register(dev, &sclk->hw);
 300        if (IS_ERR(clk))
 301                kfree(sclk);
 302
 303        return clk;
 304}
 305
 306#ifdef CONFIG_DEBUG_FS
 307
 308static u32 src_pcksr0_boot;
 309static u32 src_pcksr1_boot;
 310
 311static const char * const src_clk_names[] = {
 312        "HCLKDMA0  ",
 313        "HCLKSMC   ",
 314        "HCLKSDRAM ",
 315        "HCLKDMA1  ",
 316        "HCLKCLCD  ",
 317        "PCLKIRDA  ",
 318        "PCLKSSP   ",
 319        "PCLKUART0 ",
 320        "PCLKSDI   ",
 321        "PCLKI2C0  ",
 322        "PCLKI2C1  ",
 323        "PCLKUART1 ",
 324        "PCLMSP0   ",
 325        "HCLKUSB   ",
 326        "HCLKDIF   ",
 327        "HCLKSAA   ",
 328        "HCLKSVA   ",
 329        "PCLKHSI   ",
 330        "PCLKXTI   ",
 331        "PCLKUART2 ",
 332        "PCLKMSP1  ",
 333        "PCLKMSP2  ",
 334        "PCLKOWM   ",
 335        "HCLKHPI   ",
 336        "PCLKSKE   ",
 337        "PCLKHSEM  ",
 338        "HCLK3D    ",
 339        "HCLKHASH  ",
 340        "HCLKCRYP  ",
 341        "PCLKMSHC  ",
 342        "HCLKUSBM  ",
 343        "HCLKRNG   ",
 344        "RESERVED  ",
 345        "RESERVED  ",
 346        "RESERVED  ",
 347        "RESERVED  ",
 348        "CLDCLK    ",
 349        "IRDACLK   ",
 350        "SSPICLK   ",
 351        "UART0CLK  ",
 352        "SDICLK    ",
 353        "I2C0CLK   ",
 354        "I2C1CLK   ",
 355        "UART1CLK  ",
 356        "MSPCLK0   ",
 357        "USBCLK    ",
 358        "DIFCLK    ",
 359        "IPI2CCLK  ",
 360        "IPBMCCLK  ",
 361        "HSICLKRX  ",
 362        "HSICLKTX  ",
 363        "UART2CLK  ",
 364        "MSPCLK1   ",
 365        "MSPCLK2   ",
 366        "OWMCLK    ",
 367        "RESERVED  ",
 368        "SKECLK    ",
 369        "RESERVED  ",
 370        "3DCLK     ",
 371        "PCLKMSP3  ",
 372        "MSPCLK3   ",
 373        "MSHCCLK   ",
 374        "USBMCLK   ",
 375        "RNGCCLK   ",
 376};
 377
 378static int nomadik_src_clk_show(struct seq_file *s, void *what)
 379{
 380        int i;
 381        u32 src_pcksr0 = readl(src_base + SRC_PCKSR0);
 382        u32 src_pcksr1 = readl(src_base + SRC_PCKSR1);
 383        u32 src_pckensr0 = readl(src_base + SRC_PCKENSR0);
 384        u32 src_pckensr1 = readl(src_base + SRC_PCKENSR1);
 385
 386        seq_printf(s, "Clock:      Boot:   Now:    Request: ASKED:\n");
 387        for (i = 0; i < ARRAY_SIZE(src_clk_names); i++) {
 388                u32 pcksrb = (i < 0x20) ? src_pcksr0_boot : src_pcksr1_boot;
 389                u32 pcksr = (i < 0x20) ? src_pcksr0 : src_pcksr1;
 390                u32 pckreq = (i < 0x20) ? src_pckensr0 : src_pckensr1;
 391                u32 mask = BIT(i & 0x1f);
 392
 393                seq_printf(s, "%s  %s     %s     %s\n",
 394                           src_clk_names[i],
 395                           (pcksrb & mask) ? "on " : "off",
 396                           (pcksr & mask) ? "on " : "off",
 397                           (pckreq & mask) ? "on " : "off");
 398        }
 399        return 0;
 400}
 401
 402static int nomadik_src_clk_open(struct inode *inode, struct file *file)
 403{
 404        return single_open(file, nomadik_src_clk_show, NULL);
 405}
 406
 407static const struct file_operations nomadik_src_clk_debugfs_ops = {
 408        .open           = nomadik_src_clk_open,
 409        .read           = seq_read,
 410        .llseek         = seq_lseek,
 411        .release        = single_release,
 412};
 413
 414static int __init nomadik_src_clk_init_debugfs(void)
 415{
 416        src_pcksr0_boot = readl(src_base + SRC_PCKSR0);
 417        src_pcksr1_boot = readl(src_base + SRC_PCKSR1);
 418        debugfs_create_file("nomadik-src-clk", S_IFREG | S_IRUGO,
 419                            NULL, NULL, &nomadik_src_clk_debugfs_ops);
 420        return 0;
 421}
 422
 423module_init(nomadik_src_clk_init_debugfs);
 424
 425#endif
 426
 427static void __init of_nomadik_pll_setup(struct device_node *np)
 428{
 429        struct clk *clk = ERR_PTR(-EINVAL);
 430        const char *clk_name = np->name;
 431        const char *parent_name;
 432        u32 pll_id;
 433
 434        if (of_property_read_u32(np, "pll-id", &pll_id)) {
 435                pr_err("%s: PLL \"%s\" missing pll-id property\n",
 436                        __func__, clk_name);
 437                return;
 438        }
 439        parent_name = of_clk_get_parent_name(np, 0);
 440        clk = pll_clk_register(NULL, clk_name, parent_name, pll_id);
 441        if (!IS_ERR(clk))
 442                of_clk_add_provider(np, of_clk_src_simple_get, clk);
 443}
 444
 445static void __init of_nomadik_hclk_setup(struct device_node *np)
 446{
 447        struct clk *clk = ERR_PTR(-EINVAL);
 448        const char *clk_name = np->name;
 449        const char *parent_name;
 450
 451        parent_name = of_clk_get_parent_name(np, 0);
 452        /*
 453         * The HCLK divides PLL1 with 1 (passthru), 2, 3 or 4.
 454         */
 455        clk = clk_register_divider(NULL, clk_name, parent_name,
 456                           0, src_base + SRC_CR,
 457                           13, 2,
 458                           CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
 459                           &src_lock);
 460        if (!IS_ERR(clk))
 461                of_clk_add_provider(np, of_clk_src_simple_get, clk);
 462}
 463
 464static void __init of_nomadik_src_clk_setup(struct device_node *np)
 465{
 466        struct clk *clk = ERR_PTR(-EINVAL);
 467        const char *clk_name = np->name;
 468        const char *parent_name;
 469        u32 clk_id;
 470
 471        if (of_property_read_u32(np, "clock-id", &clk_id)) {
 472                pr_err("%s: SRC clock \"%s\" missing clock-id property\n",
 473                        __func__, clk_name);
 474                return;
 475        }
 476        parent_name = of_clk_get_parent_name(np, 0);
 477        clk = src_clk_register(NULL, clk_name, parent_name, clk_id);
 478        if (!IS_ERR(clk))
 479                of_clk_add_provider(np, of_clk_src_simple_get, clk);
 480}
 481
 482static const __initconst struct of_device_id nomadik_src_match[] = {
 483        { .compatible = "stericsson,nomadik-src" },
 484        { /* sentinel */ }
 485};
 486
 487static const __initconst struct of_device_id nomadik_src_clk_match[] = {
 488        {
 489                .compatible = "fixed-clock",
 490                .data = of_fixed_clk_setup,
 491        },
 492        {
 493                .compatible = "fixed-factor-clock",
 494                .data = of_fixed_factor_clk_setup,
 495        },
 496        {
 497                .compatible = "st,nomadik-pll-clock",
 498                .data = of_nomadik_pll_setup,
 499        },
 500        {
 501                .compatible = "st,nomadik-hclk-clock",
 502                .data = of_nomadik_hclk_setup,
 503        },
 504        {
 505                .compatible = "st,nomadik-src-clock",
 506                .data = of_nomadik_src_clk_setup,
 507        },
 508        { /* sentinel */ }
 509};
 510
 511static int nomadik_clk_reboot_handler(struct notifier_block *this,
 512                                unsigned long code,
 513                                void *unused)
 514{
 515        u32 val;
 516
 517        /* The main chrystal need to be enabled for reboot to work */
 518        val = readl(src_base + SRC_XTALCR);
 519        val &= ~SRC_XTALCR_MXTALOVER;
 520        val |= SRC_XTALCR_MXTALEN;
 521        pr_crit("force-enabling MXTALO\n");
 522        writel(val, src_base + SRC_XTALCR);
 523        return NOTIFY_OK;
 524}
 525
 526static struct notifier_block nomadik_clk_reboot_notifier = {
 527        .notifier_call = nomadik_clk_reboot_handler,
 528};
 529
 530void __init nomadik_clk_init(void)
 531{
 532        struct device_node *np;
 533        u32 val;
 534
 535        np = of_find_matching_node(NULL, nomadik_src_match);
 536        if (!np) {
 537                pr_crit("no matching node for SRC, aborting clock init\n");
 538                return;
 539        }
 540        src_base = of_iomap(np, 0);
 541        if (!src_base) {
 542                pr_err("%s: must have src parent node with REGS (%s)\n",
 543                       __func__, np->name);
 544                return;
 545        }
 546        val = readl(src_base + SRC_XTALCR);
 547        pr_info("SXTALO is %s\n",
 548                (val & SRC_XTALCR_SXTALDIS) ? "disabled" : "enabled");
 549        pr_info("MXTAL is %s\n",
 550                (val & SRC_XTALCR_MXTALSTAT) ? "enabled" : "disabled");
 551        if (of_property_read_bool(np, "disable-sxtalo")) {
 552                /* The machine uses an external oscillator circuit */
 553                val |= SRC_XTALCR_SXTALDIS;
 554                pr_info("disabling SXTALO\n");
 555        }
 556        if (of_property_read_bool(np, "disable-mxtalo")) {
 557                /* Disable this too: also run by external oscillator */
 558                val |= SRC_XTALCR_MXTALOVER;
 559                val &= ~SRC_XTALCR_MXTALEN;
 560                pr_info("disabling MXTALO\n");
 561        }
 562        writel(val, src_base + SRC_XTALCR);
 563        register_reboot_notifier(&nomadik_clk_reboot_notifier);
 564
 565        of_clk_init(nomadik_src_clk_match);
 566}
 567
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.