linux/drivers/clk/ingenic/jz4770-cgu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * JZ4770 SoC CGU driver
   4 * Copyright 2018, Paul Cercueil <paul@crapouillou.net>
   5 */
   6
   7#include <linux/bitops.h>
   8#include <linux/clk-provider.h>
   9#include <linux/delay.h>
  10#include <linux/io.h>
  11#include <linux/of.h>
  12
  13#include <dt-bindings/clock/jz4770-cgu.h>
  14
  15#include "cgu.h"
  16#include "pm.h"
  17
  18/*
  19 * CPM registers offset address definition
  20 */
  21#define CGU_REG_CPCCR           0x00
  22#define CGU_REG_LCR             0x04
  23#define CGU_REG_CPPCR0          0x10
  24#define CGU_REG_CLKGR0          0x20
  25#define CGU_REG_OPCR            0x24
  26#define CGU_REG_CLKGR1          0x28
  27#define CGU_REG_CPPCR1          0x30
  28#define CGU_REG_USBPCR1         0x48
  29#define CGU_REG_USBCDR          0x50
  30#define CGU_REG_I2SCDR          0x60
  31#define CGU_REG_LPCDR           0x64
  32#define CGU_REG_MSC0CDR         0x68
  33#define CGU_REG_UHCCDR          0x6c
  34#define CGU_REG_SSICDR          0x74
  35#define CGU_REG_CIMCDR          0x7c
  36#define CGU_REG_GPSCDR          0x80
  37#define CGU_REG_PCMCDR          0x84
  38#define CGU_REG_GPUCDR          0x88
  39#define CGU_REG_MSC1CDR         0xA4
  40#define CGU_REG_MSC2CDR         0xA8
  41#define CGU_REG_BCHCDR          0xAC
  42
  43/* bits within the OPCR register */
  44#define OPCR_SPENDH             BIT(5)          /* UHC PHY suspend */
  45
  46/* bits within the USBPCR1 register */
  47#define USBPCR1_UHC_POWER       BIT(5)          /* UHC PHY power down */
  48
  49static struct ingenic_cgu *cgu;
  50
  51static int jz4770_uhc_phy_enable(struct clk_hw *hw)
  52{
  53        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
  54        void __iomem *reg_usbpcr1       = cgu->base + CGU_REG_USBPCR1;
  55
  56        writel(readl(reg_opcr) & ~OPCR_SPENDH, reg_opcr);
  57        writel(readl(reg_usbpcr1) | USBPCR1_UHC_POWER, reg_usbpcr1);
  58        return 0;
  59}
  60
  61static void jz4770_uhc_phy_disable(struct clk_hw *hw)
  62{
  63        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
  64        void __iomem *reg_usbpcr1       = cgu->base + CGU_REG_USBPCR1;
  65
  66        writel(readl(reg_usbpcr1) & ~USBPCR1_UHC_POWER, reg_usbpcr1);
  67        writel(readl(reg_opcr) | OPCR_SPENDH, reg_opcr);
  68}
  69
  70static int jz4770_uhc_phy_is_enabled(struct clk_hw *hw)
  71{
  72        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
  73        void __iomem *reg_usbpcr1       = cgu->base + CGU_REG_USBPCR1;
  74
  75        return !(readl(reg_opcr) & OPCR_SPENDH) &&
  76                (readl(reg_usbpcr1) & USBPCR1_UHC_POWER);
  77}
  78
  79static const struct clk_ops jz4770_uhc_phy_ops = {
  80        .enable = jz4770_uhc_phy_enable,
  81        .disable = jz4770_uhc_phy_disable,
  82        .is_enabled = jz4770_uhc_phy_is_enabled,
  83};
  84
  85static const s8 pll_od_encoding[8] = {
  86        0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
  87};
  88
  89static const u8 jz4770_cgu_cpccr_div_table[] = {
  90        1, 2, 3, 4, 6, 8, 12,
  91};
  92
  93static const struct ingenic_cgu_clk_info jz4770_cgu_clocks[] = {
  94
  95        /* External clocks */
  96
  97        [JZ4770_CLK_EXT] = { "ext", CGU_CLK_EXT },
  98        [JZ4770_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
  99
 100        /* PLLs */
 101
 102        [JZ4770_CLK_PLL0] = {
 103                "pll0", CGU_CLK_PLL,
 104                .parents = { JZ4770_CLK_EXT },
 105                .pll = {
 106                        .reg = CGU_REG_CPPCR0,
 107                        .rate_multiplier = 1,
 108                        .m_shift = 24,
 109                        .m_bits = 7,
 110                        .m_offset = 1,
 111                        .n_shift = 18,
 112                        .n_bits = 5,
 113                        .n_offset = 1,
 114                        .od_shift = 16,
 115                        .od_bits = 2,
 116                        .od_max = 8,
 117                        .od_encoding = pll_od_encoding,
 118                        .bypass_reg = CGU_REG_CPPCR0,
 119                        .bypass_bit = 9,
 120                        .enable_bit = 8,
 121                        .stable_bit = 10,
 122                },
 123        },
 124
 125        [JZ4770_CLK_PLL1] = {
 126                /* TODO: PLL1 can depend on PLL0 */
 127                "pll1", CGU_CLK_PLL,
 128                .parents = { JZ4770_CLK_EXT },
 129                .pll = {
 130                        .reg = CGU_REG_CPPCR1,
 131                        .rate_multiplier = 1,
 132                        .m_shift = 24,
 133                        .m_bits = 7,
 134                        .m_offset = 1,
 135                        .n_shift = 18,
 136                        .n_bits = 5,
 137                        .n_offset = 1,
 138                        .od_shift = 16,
 139                        .od_bits = 2,
 140                        .od_max = 8,
 141                        .od_encoding = pll_od_encoding,
 142                        .bypass_bit = -1,
 143                        .enable_bit = 7,
 144                        .stable_bit = 6,
 145                },
 146        },
 147
 148        /* Main clocks */
 149
 150        [JZ4770_CLK_CCLK] = {
 151                "cclk", CGU_CLK_DIV,
 152                .parents = { JZ4770_CLK_PLL0, },
 153                .div = {
 154                        CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
 155                        jz4770_cgu_cpccr_div_table,
 156                },
 157        },
 158        [JZ4770_CLK_H0CLK] = {
 159                "h0clk", CGU_CLK_DIV,
 160                .parents = { JZ4770_CLK_PLL0, },
 161                .div = {
 162                        CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
 163                        jz4770_cgu_cpccr_div_table,
 164                },
 165        },
 166        [JZ4770_CLK_H1CLK] = {
 167                "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
 168                .parents = { JZ4770_CLK_PLL0, },
 169                .div = {
 170                        CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
 171                        jz4770_cgu_cpccr_div_table,
 172                },
 173                .gate = { CGU_REG_CLKGR1, 7 },
 174        },
 175        [JZ4770_CLK_H2CLK] = {
 176                "h2clk", CGU_CLK_DIV,
 177                .parents = { JZ4770_CLK_PLL0, },
 178                .div = {
 179                        CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
 180                        jz4770_cgu_cpccr_div_table,
 181                },
 182        },
 183        [JZ4770_CLK_C1CLK] = {
 184                "c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
 185                .parents = { JZ4770_CLK_PLL0, },
 186                .div = {
 187                        CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
 188                        jz4770_cgu_cpccr_div_table,
 189                },
 190                .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
 191        },
 192        [JZ4770_CLK_PCLK] = {
 193                "pclk", CGU_CLK_DIV,
 194                .parents = { JZ4770_CLK_PLL0, },
 195                .div = {
 196                        CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
 197                        jz4770_cgu_cpccr_div_table,
 198                },
 199        },
 200
 201        /* Those divided clocks can connect to PLL0 or PLL1 */
 202
 203        [JZ4770_CLK_MMC0_MUX] = {
 204                "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 205                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 206                .mux = { CGU_REG_MSC0CDR, 30, 1 },
 207                .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
 208                .gate = { CGU_REG_MSC0CDR, 31 },
 209        },
 210        [JZ4770_CLK_MMC1_MUX] = {
 211                "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 212                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 213                .mux = { CGU_REG_MSC1CDR, 30, 1 },
 214                .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
 215                .gate = { CGU_REG_MSC1CDR, 31 },
 216        },
 217        [JZ4770_CLK_MMC2_MUX] = {
 218                "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 219                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 220                .mux = { CGU_REG_MSC2CDR, 30, 1 },
 221                .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
 222                .gate = { CGU_REG_MSC2CDR, 31 },
 223        },
 224        [JZ4770_CLK_CIM] = {
 225                "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 226                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 227                .mux = { CGU_REG_CIMCDR, 31, 1 },
 228                .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
 229                .gate = { CGU_REG_CLKGR0, 26 },
 230        },
 231        [JZ4770_CLK_UHC] = {
 232                "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 233                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 234                .mux = { CGU_REG_UHCCDR, 29, 1 },
 235                .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
 236                .gate = { CGU_REG_CLKGR0, 24 },
 237        },
 238        [JZ4770_CLK_GPU] = {
 239                "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 240                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
 241                .mux = { CGU_REG_GPUCDR, 31, 1 },
 242                .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
 243                .gate = { CGU_REG_CLKGR1, 9 },
 244        },
 245        [JZ4770_CLK_BCH] = {
 246                "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 247                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 248                .mux = { CGU_REG_BCHCDR, 31, 1 },
 249                .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
 250                .gate = { CGU_REG_CLKGR0, 1 },
 251        },
 252        [JZ4770_CLK_LPCLK_MUX] = {
 253                "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 254                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 255                .mux = { CGU_REG_LPCDR, 29, 1 },
 256                .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
 257                .gate = { CGU_REG_CLKGR0, 28 },
 258        },
 259        [JZ4770_CLK_GPS] = {
 260                "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 261                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 262                .mux = { CGU_REG_GPSCDR, 31, 1 },
 263                .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
 264                .gate = { CGU_REG_CLKGR0, 22 },
 265        },
 266
 267        /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
 268
 269        [JZ4770_CLK_SSI_MUX] = {
 270                "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
 271                .parents = { JZ4770_CLK_EXT, -1,
 272                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 273                .mux = { CGU_REG_SSICDR, 30, 2 },
 274                .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
 275        },
 276        [JZ4770_CLK_PCM_MUX] = {
 277                "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
 278                .parents = { JZ4770_CLK_EXT, -1,
 279                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 280                .mux = { CGU_REG_PCMCDR, 30, 2 },
 281                .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
 282        },
 283        [JZ4770_CLK_I2S] = {
 284                "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 285                .parents = { JZ4770_CLK_EXT, -1,
 286                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 287                .mux = { CGU_REG_I2SCDR, 30, 2 },
 288                .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
 289                .gate = { CGU_REG_CLKGR1, 13 },
 290        },
 291        [JZ4770_CLK_OTG] = {
 292                "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 293                .parents = { JZ4770_CLK_EXT, -1,
 294                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 295                .mux = { CGU_REG_USBCDR, 30, 2 },
 296                .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
 297                .gate = { CGU_REG_CLKGR0, 2 },
 298        },
 299
 300        /* Gate-only clocks */
 301
 302        [JZ4770_CLK_SSI0] = {
 303                "ssi0", CGU_CLK_GATE,
 304                .parents = { JZ4770_CLK_SSI_MUX, },
 305                .gate = { CGU_REG_CLKGR0, 4 },
 306        },
 307        [JZ4770_CLK_SSI1] = {
 308                "ssi1", CGU_CLK_GATE,
 309                .parents = { JZ4770_CLK_SSI_MUX, },
 310                .gate = { CGU_REG_CLKGR0, 19 },
 311        },
 312        [JZ4770_CLK_SSI2] = {
 313                "ssi2", CGU_CLK_GATE,
 314                .parents = { JZ4770_CLK_SSI_MUX, },
 315                .gate = { CGU_REG_CLKGR0, 20 },
 316        },
 317        [JZ4770_CLK_PCM0] = {
 318                "pcm0", CGU_CLK_GATE,
 319                .parents = { JZ4770_CLK_PCM_MUX, },
 320                .gate = { CGU_REG_CLKGR1, 8 },
 321        },
 322        [JZ4770_CLK_PCM1] = {
 323                "pcm1", CGU_CLK_GATE,
 324                .parents = { JZ4770_CLK_PCM_MUX, },
 325                .gate = { CGU_REG_CLKGR1, 10 },
 326        },
 327        [JZ4770_CLK_DMA] = {
 328                "dma", CGU_CLK_GATE,
 329                .parents = { JZ4770_CLK_H2CLK, },
 330                .gate = { CGU_REG_CLKGR0, 21 },
 331        },
 332        [JZ4770_CLK_I2C0] = {
 333                "i2c0", CGU_CLK_GATE,
 334                .parents = { JZ4770_CLK_EXT, },
 335                .gate = { CGU_REG_CLKGR0, 5 },
 336        },
 337        [JZ4770_CLK_I2C1] = {
 338                "i2c1", CGU_CLK_GATE,
 339                .parents = { JZ4770_CLK_EXT, },
 340                .gate = { CGU_REG_CLKGR0, 6 },
 341        },
 342        [JZ4770_CLK_I2C2] = {
 343                "i2c2", CGU_CLK_GATE,
 344                .parents = { JZ4770_CLK_EXT, },
 345                .gate = { CGU_REG_CLKGR1, 15 },
 346        },
 347        [JZ4770_CLK_UART0] = {
 348                "uart0", CGU_CLK_GATE,
 349                .parents = { JZ4770_CLK_EXT, },
 350                .gate = { CGU_REG_CLKGR0, 15 },
 351        },
 352        [JZ4770_CLK_UART1] = {
 353                "uart1", CGU_CLK_GATE,
 354                .parents = { JZ4770_CLK_EXT, },
 355                .gate = { CGU_REG_CLKGR0, 16 },
 356        },
 357        [JZ4770_CLK_UART2] = {
 358                "uart2", CGU_CLK_GATE,
 359                .parents = { JZ4770_CLK_EXT, },
 360                .gate = { CGU_REG_CLKGR0, 17 },
 361        },
 362        [JZ4770_CLK_UART3] = {
 363                "uart3", CGU_CLK_GATE,
 364                .parents = { JZ4770_CLK_EXT, },
 365                .gate = { CGU_REG_CLKGR0, 18 },
 366        },
 367        [JZ4770_CLK_IPU] = {
 368                "ipu", CGU_CLK_GATE,
 369                .parents = { JZ4770_CLK_H0CLK, },
 370                .gate = { CGU_REG_CLKGR0, 29 },
 371        },
 372        [JZ4770_CLK_ADC] = {
 373                "adc", CGU_CLK_GATE,
 374                .parents = { JZ4770_CLK_EXT, },
 375                .gate = { CGU_REG_CLKGR0, 14 },
 376        },
 377        [JZ4770_CLK_AIC] = {
 378                "aic", CGU_CLK_GATE,
 379                .parents = { JZ4770_CLK_EXT, },
 380                .gate = { CGU_REG_CLKGR0, 8 },
 381        },
 382        [JZ4770_CLK_AUX] = {
 383                "aux", CGU_CLK_GATE,
 384                .parents = { JZ4770_CLK_C1CLK, },
 385                .gate = { CGU_REG_CLKGR1, 14 },
 386        },
 387        [JZ4770_CLK_VPU] = {
 388                "vpu", CGU_CLK_GATE,
 389                .parents = { JZ4770_CLK_H1CLK, },
 390                .gate = { CGU_REG_LCR, 30, false, 150 },
 391        },
 392        [JZ4770_CLK_MMC0] = {
 393                "mmc0", CGU_CLK_GATE,
 394                .parents = { JZ4770_CLK_MMC0_MUX, },
 395                .gate = { CGU_REG_CLKGR0, 3 },
 396        },
 397        [JZ4770_CLK_MMC1] = {
 398                "mmc1", CGU_CLK_GATE,
 399                .parents = { JZ4770_CLK_MMC1_MUX, },
 400                .gate = { CGU_REG_CLKGR0, 11 },
 401        },
 402        [JZ4770_CLK_MMC2] = {
 403                "mmc2", CGU_CLK_GATE,
 404                .parents = { JZ4770_CLK_MMC2_MUX, },
 405                .gate = { CGU_REG_CLKGR0, 12 },
 406        },
 407        [JZ4770_CLK_OTG_PHY] = {
 408                "usb_phy", CGU_CLK_GATE,
 409                .parents = { JZ4770_CLK_OTG },
 410                .gate = { CGU_REG_OPCR, 7, true, 50 },
 411        },
 412
 413        /* Custom clocks */
 414
 415        [JZ4770_CLK_UHC_PHY] = {
 416                "uhc_phy", CGU_CLK_CUSTOM,
 417                .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
 418                .custom = { &jz4770_uhc_phy_ops },
 419        },
 420
 421        [JZ4770_CLK_EXT512] = {
 422                "ext/512", CGU_CLK_FIXDIV,
 423                .parents = { JZ4770_CLK_EXT },
 424                .fixdiv = { 512 },
 425        },
 426
 427        [JZ4770_CLK_RTC] = {
 428                "rtc", CGU_CLK_MUX,
 429                .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
 430                .mux = { CGU_REG_OPCR, 2, 1},
 431        },
 432};
 433
 434static void __init jz4770_cgu_init(struct device_node *np)
 435{
 436        int retval;
 437
 438        cgu = ingenic_cgu_new(jz4770_cgu_clocks,
 439                              ARRAY_SIZE(jz4770_cgu_clocks), np);
 440        if (!cgu) {
 441                pr_err("%s: failed to initialise CGU\n", __func__);
 442                return;
 443        }
 444
 445        retval = ingenic_cgu_register_clocks(cgu);
 446        if (retval)
 447                pr_err("%s: failed to register CGU Clocks\n", __func__);
 448
 449        ingenic_cgu_register_syscore_ops(cgu);
 450}
 451
 452/* We only probe via devicetree, no need for a platform driver */
 453CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
 454