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