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