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_reg = CGU_REG_CPPCR1,
 143                        .no_bypass_bit = true,
 144                        .enable_bit = 7,
 145                        .stable_bit = 6,
 146                },
 147        },
 148
 149        /* Main clocks */
 150
 151        [JZ4770_CLK_CCLK] = {
 152                "cclk", CGU_CLK_DIV,
 153                .parents = { JZ4770_CLK_PLL0, },
 154                .div = {
 155                        CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1,
 156                        jz4770_cgu_cpccr_div_table,
 157                },
 158        },
 159        [JZ4770_CLK_H0CLK] = {
 160                "h0clk", CGU_CLK_DIV,
 161                .parents = { JZ4770_CLK_PLL0, },
 162                .div = {
 163                        CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1,
 164                        jz4770_cgu_cpccr_div_table,
 165                },
 166        },
 167        [JZ4770_CLK_H1CLK] = {
 168                "h1clk", CGU_CLK_DIV | CGU_CLK_GATE,
 169                .parents = { JZ4770_CLK_PLL0, },
 170                .div = {
 171                        CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1,
 172                        jz4770_cgu_cpccr_div_table,
 173                },
 174                .gate = { CGU_REG_CLKGR1, 7 },
 175        },
 176        [JZ4770_CLK_H2CLK] = {
 177                "h2clk", CGU_CLK_DIV,
 178                .parents = { JZ4770_CLK_PLL0, },
 179                .div = {
 180                        CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1,
 181                        jz4770_cgu_cpccr_div_table,
 182                },
 183        },
 184        [JZ4770_CLK_C1CLK] = {
 185                "c1clk", CGU_CLK_DIV | CGU_CLK_GATE,
 186                .parents = { JZ4770_CLK_PLL0, },
 187                .div = {
 188                        CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1,
 189                        jz4770_cgu_cpccr_div_table,
 190                },
 191                .gate = { CGU_REG_OPCR, 31, true }, // disable CCLK stop on idle
 192        },
 193        [JZ4770_CLK_PCLK] = {
 194                "pclk", CGU_CLK_DIV,
 195                .parents = { JZ4770_CLK_PLL0, },
 196                .div = {
 197                        CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1,
 198                        jz4770_cgu_cpccr_div_table,
 199                },
 200        },
 201
 202        /* Those divided clocks can connect to PLL0 or PLL1 */
 203
 204        [JZ4770_CLK_MMC0_MUX] = {
 205                "mmc0_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 206                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 207                .mux = { CGU_REG_MSC0CDR, 30, 1 },
 208                .div = { CGU_REG_MSC0CDR, 0, 1, 7, -1, -1, 31 },
 209                .gate = { CGU_REG_MSC0CDR, 31 },
 210        },
 211        [JZ4770_CLK_MMC1_MUX] = {
 212                "mmc1_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 213                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 214                .mux = { CGU_REG_MSC1CDR, 30, 1 },
 215                .div = { CGU_REG_MSC1CDR, 0, 1, 7, -1, -1, 31 },
 216                .gate = { CGU_REG_MSC1CDR, 31 },
 217        },
 218        [JZ4770_CLK_MMC2_MUX] = {
 219                "mmc2_mux", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 220                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 221                .mux = { CGU_REG_MSC2CDR, 30, 1 },
 222                .div = { CGU_REG_MSC2CDR, 0, 1, 7, -1, -1, 31 },
 223                .gate = { CGU_REG_MSC2CDR, 31 },
 224        },
 225        [JZ4770_CLK_CIM] = {
 226                "cim", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 227                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 228                .mux = { CGU_REG_CIMCDR, 31, 1 },
 229                .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
 230                .gate = { CGU_REG_CLKGR0, 26 },
 231        },
 232        [JZ4770_CLK_UHC] = {
 233                "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 234                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 235                .mux = { CGU_REG_UHCCDR, 29, 1 },
 236                .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
 237                .gate = { CGU_REG_CLKGR0, 24 },
 238        },
 239        [JZ4770_CLK_GPU] = {
 240                "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 241                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, -1 },
 242                .mux = { CGU_REG_GPUCDR, 31, 1 },
 243                .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
 244                .gate = { CGU_REG_CLKGR1, 9 },
 245        },
 246        [JZ4770_CLK_BCH] = {
 247                "bch", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 248                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 249                .mux = { CGU_REG_BCHCDR, 31, 1 },
 250                .div = { CGU_REG_BCHCDR, 0, 1, 3, -1, -1, -1 },
 251                .gate = { CGU_REG_CLKGR0, 1 },
 252        },
 253        [JZ4770_CLK_LPCLK_MUX] = {
 254                "lpclk", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 255                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 256                .mux = { CGU_REG_LPCDR, 29, 1 },
 257                .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
 258                .gate = { CGU_REG_CLKGR0, 28 },
 259        },
 260        [JZ4770_CLK_GPS] = {
 261                "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 262                .parents = { JZ4770_CLK_PLL0, JZ4770_CLK_PLL1, },
 263                .mux = { CGU_REG_GPSCDR, 31, 1 },
 264                .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
 265                .gate = { CGU_REG_CLKGR0, 22 },
 266        },
 267
 268        /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
 269
 270        [JZ4770_CLK_SSI_MUX] = {
 271                "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
 272                .parents = { JZ4770_CLK_EXT, -1,
 273                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 274                .mux = { CGU_REG_SSICDR, 30, 2 },
 275                .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1 },
 276        },
 277        [JZ4770_CLK_PCM_MUX] = {
 278                "pcm_mux", CGU_CLK_DIV | CGU_CLK_MUX,
 279                .parents = { JZ4770_CLK_EXT, -1,
 280                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 281                .mux = { CGU_REG_PCMCDR, 30, 2 },
 282                .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1 },
 283        },
 284        [JZ4770_CLK_I2S] = {
 285                "i2s", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 286                .parents = { JZ4770_CLK_EXT, -1,
 287                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 288                .mux = { CGU_REG_I2SCDR, 30, 2 },
 289                .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1 },
 290                .gate = { CGU_REG_CLKGR1, 13 },
 291        },
 292        [JZ4770_CLK_OTG] = {
 293                "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 294                .parents = { JZ4770_CLK_EXT, -1,
 295                        JZ4770_CLK_PLL0, JZ4770_CLK_PLL1 },
 296                .mux = { CGU_REG_USBCDR, 30, 2 },
 297                .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
 298                .gate = { CGU_REG_CLKGR0, 2 },
 299        },
 300
 301        /* Gate-only clocks */
 302
 303        [JZ4770_CLK_SSI0] = {
 304                "ssi0", CGU_CLK_GATE,
 305                .parents = { JZ4770_CLK_SSI_MUX, },
 306                .gate = { CGU_REG_CLKGR0, 4 },
 307        },
 308        [JZ4770_CLK_SSI1] = {
 309                "ssi1", CGU_CLK_GATE,
 310                .parents = { JZ4770_CLK_SSI_MUX, },
 311                .gate = { CGU_REG_CLKGR0, 19 },
 312        },
 313        [JZ4770_CLK_SSI2] = {
 314                "ssi2", CGU_CLK_GATE,
 315                .parents = { JZ4770_CLK_SSI_MUX, },
 316                .gate = { CGU_REG_CLKGR0, 20 },
 317        },
 318        [JZ4770_CLK_PCM0] = {
 319                "pcm0", CGU_CLK_GATE,
 320                .parents = { JZ4770_CLK_PCM_MUX, },
 321                .gate = { CGU_REG_CLKGR1, 8 },
 322        },
 323        [JZ4770_CLK_PCM1] = {
 324                "pcm1", CGU_CLK_GATE,
 325                .parents = { JZ4770_CLK_PCM_MUX, },
 326                .gate = { CGU_REG_CLKGR1, 10 },
 327        },
 328        [JZ4770_CLK_DMA] = {
 329                "dma", CGU_CLK_GATE,
 330                .parents = { JZ4770_CLK_H2CLK, },
 331                .gate = { CGU_REG_CLKGR0, 21 },
 332        },
 333        [JZ4770_CLK_I2C0] = {
 334                "i2c0", CGU_CLK_GATE,
 335                .parents = { JZ4770_CLK_EXT, },
 336                .gate = { CGU_REG_CLKGR0, 5 },
 337        },
 338        [JZ4770_CLK_I2C1] = {
 339                "i2c1", CGU_CLK_GATE,
 340                .parents = { JZ4770_CLK_EXT, },
 341                .gate = { CGU_REG_CLKGR0, 6 },
 342        },
 343        [JZ4770_CLK_I2C2] = {
 344                "i2c2", CGU_CLK_GATE,
 345                .parents = { JZ4770_CLK_EXT, },
 346                .gate = { CGU_REG_CLKGR1, 15 },
 347        },
 348        [JZ4770_CLK_UART0] = {
 349                "uart0", CGU_CLK_GATE,
 350                .parents = { JZ4770_CLK_EXT, },
 351                .gate = { CGU_REG_CLKGR0, 15 },
 352        },
 353        [JZ4770_CLK_UART1] = {
 354                "uart1", CGU_CLK_GATE,
 355                .parents = { JZ4770_CLK_EXT, },
 356                .gate = { CGU_REG_CLKGR0, 16 },
 357        },
 358        [JZ4770_CLK_UART2] = {
 359                "uart2", CGU_CLK_GATE,
 360                .parents = { JZ4770_CLK_EXT, },
 361                .gate = { CGU_REG_CLKGR0, 17 },
 362        },
 363        [JZ4770_CLK_UART3] = {
 364                "uart3", CGU_CLK_GATE,
 365                .parents = { JZ4770_CLK_EXT, },
 366                .gate = { CGU_REG_CLKGR0, 18 },
 367        },
 368        [JZ4770_CLK_IPU] = {
 369                "ipu", CGU_CLK_GATE,
 370                .parents = { JZ4770_CLK_H0CLK, },
 371                .gate = { CGU_REG_CLKGR0, 29 },
 372        },
 373        [JZ4770_CLK_ADC] = {
 374                "adc", CGU_CLK_GATE,
 375                .parents = { JZ4770_CLK_EXT, },
 376                .gate = { CGU_REG_CLKGR0, 14 },
 377        },
 378        [JZ4770_CLK_AIC] = {
 379                "aic", CGU_CLK_GATE,
 380                .parents = { JZ4770_CLK_EXT, },
 381                .gate = { CGU_REG_CLKGR0, 8 },
 382        },
 383        [JZ4770_CLK_AUX] = {
 384                "aux", CGU_CLK_GATE,
 385                .parents = { JZ4770_CLK_C1CLK, },
 386                .gate = { CGU_REG_CLKGR1, 14 },
 387        },
 388        [JZ4770_CLK_VPU] = {
 389                "vpu", CGU_CLK_GATE,
 390                .parents = { JZ4770_CLK_H1CLK, },
 391                .gate = { CGU_REG_LCR, 30, false, 150 },
 392        },
 393        [JZ4770_CLK_MMC0] = {
 394                "mmc0", CGU_CLK_GATE,
 395                .parents = { JZ4770_CLK_MMC0_MUX, },
 396                .gate = { CGU_REG_CLKGR0, 3 },
 397        },
 398        [JZ4770_CLK_MMC1] = {
 399                "mmc1", CGU_CLK_GATE,
 400                .parents = { JZ4770_CLK_MMC1_MUX, },
 401                .gate = { CGU_REG_CLKGR0, 11 },
 402        },
 403        [JZ4770_CLK_MMC2] = {
 404                "mmc2", CGU_CLK_GATE,
 405                .parents = { JZ4770_CLK_MMC2_MUX, },
 406                .gate = { CGU_REG_CLKGR0, 12 },
 407        },
 408        [JZ4770_CLK_OTG_PHY] = {
 409                "usb_phy", CGU_CLK_GATE,
 410                .parents = { JZ4770_CLK_OTG },
 411                .gate = { CGU_REG_OPCR, 7, true, 50 },
 412        },
 413
 414        /* Custom clocks */
 415
 416        [JZ4770_CLK_UHC_PHY] = {
 417                "uhc_phy", CGU_CLK_CUSTOM,
 418                .parents = { JZ4770_CLK_UHC, -1, -1, -1 },
 419                .custom = { &jz4770_uhc_phy_ops },
 420        },
 421
 422        [JZ4770_CLK_EXT512] = {
 423                "ext/512", CGU_CLK_FIXDIV,
 424                .parents = { JZ4770_CLK_EXT },
 425                .fixdiv = { 512 },
 426        },
 427
 428        [JZ4770_CLK_RTC] = {
 429                "rtc", CGU_CLK_MUX,
 430                .parents = { JZ4770_CLK_EXT512, JZ4770_CLK_OSC32K, },
 431                .mux = { CGU_REG_OPCR, 2, 1},
 432        },
 433};
 434
 435static void __init jz4770_cgu_init(struct device_node *np)
 436{
 437        int retval;
 438
 439        cgu = ingenic_cgu_new(jz4770_cgu_clocks,
 440                              ARRAY_SIZE(jz4770_cgu_clocks), np);
 441        if (!cgu) {
 442                pr_err("%s: failed to initialise CGU\n", __func__);
 443                return;
 444        }
 445
 446        retval = ingenic_cgu_register_clocks(cgu);
 447        if (retval)
 448                pr_err("%s: failed to register CGU Clocks\n", __func__);
 449
 450        ingenic_cgu_register_syscore_ops(cgu);
 451}
 452
 453/* We only probe via devicetree, no need for a platform driver */
 454CLK_OF_DECLARE_DRIVER(jz4770_cgu, "ingenic,jz4770-cgu", jz4770_cgu_init);
 455