linux/drivers/clk/ingenic/x1830-cgu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * X1830 SoC CGU driver
   4 * Copyright (c) 2019 \xE5\x91\xA8\xE7\x90\xB0\xE6\x9D\xB0 (Zhou Yanjie) <zhouyanjie@wanyeetech.com>
   5 */
   6
   7#include <linux/clk-provider.h>
   8#include <linux/delay.h>
   9#include <linux/io.h>
  10#include <linux/of.h>
  11
  12#include <dt-bindings/clock/x1830-cgu.h>
  13
  14#include "cgu.h"
  15#include "pm.h"
  16
  17/* CGU register offsets */
  18#define CGU_REG_CPCCR           0x00
  19#define CGU_REG_CPPCR           0x0c
  20#define CGU_REG_APLL            0x10
  21#define CGU_REG_MPLL            0x14
  22#define CGU_REG_CLKGR0          0x20
  23#define CGU_REG_OPCR            0x24
  24#define CGU_REG_CLKGR1          0x28
  25#define CGU_REG_DDRCDR          0x2c
  26#define CGU_REG_USBPCR          0x3c
  27#define CGU_REG_USBRDT          0x40
  28#define CGU_REG_USBVBFIL        0x44
  29#define CGU_REG_USBPCR1         0x48
  30#define CGU_REG_MACCDR          0x54
  31#define CGU_REG_EPLL            0x58
  32#define CGU_REG_I2SCDR          0x60
  33#define CGU_REG_LPCDR           0x64
  34#define CGU_REG_MSC0CDR         0x68
  35#define CGU_REG_I2SCDR1         0x70
  36#define CGU_REG_SSICDR          0x74
  37#define CGU_REG_CIMCDR          0x7c
  38#define CGU_REG_MSC1CDR         0xa4
  39#define CGU_REG_CMP_INTR        0xb0
  40#define CGU_REG_CMP_INTRE       0xb4
  41#define CGU_REG_DRCG            0xd0
  42#define CGU_REG_CPCSR           0xd4
  43#define CGU_REG_VPLL            0xe0
  44#define CGU_REG_MACPHYC         0xe8
  45
  46/* bits within the OPCR register */
  47#define OPCR_GATE_USBPHYCLK     BIT(23)
  48#define OPCR_SPENDN0            BIT(7)
  49#define OPCR_SPENDN1            BIT(6)
  50
  51/* bits within the USBPCR register */
  52#define USBPCR_SIDDQ            BIT(21)
  53#define USBPCR_OTG_DISABLE      BIT(20)
  54
  55static struct ingenic_cgu *cgu;
  56
  57static int x1830_usb_phy_enable(struct clk_hw *hw)
  58{
  59        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
  60        void __iomem *reg_usbpcr        = cgu->base + CGU_REG_USBPCR;
  61
  62        writel((readl(reg_opcr) | OPCR_SPENDN0) & ~OPCR_GATE_USBPHYCLK, reg_opcr);
  63        writel(readl(reg_usbpcr) & ~USBPCR_OTG_DISABLE & ~USBPCR_SIDDQ, reg_usbpcr);
  64        return 0;
  65}
  66
  67static void x1830_usb_phy_disable(struct clk_hw *hw)
  68{
  69        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
  70        void __iomem *reg_usbpcr        = cgu->base + CGU_REG_USBPCR;
  71
  72        writel((readl(reg_opcr) & ~OPCR_SPENDN0) | OPCR_GATE_USBPHYCLK, reg_opcr);
  73        writel(readl(reg_usbpcr) | USBPCR_OTG_DISABLE | USBPCR_SIDDQ, reg_usbpcr);
  74}
  75
  76static int x1830_usb_phy_is_enabled(struct clk_hw *hw)
  77{
  78        void __iomem *reg_opcr          = cgu->base + CGU_REG_OPCR;
  79        void __iomem *reg_usbpcr        = cgu->base + CGU_REG_USBPCR;
  80
  81        return (readl(reg_opcr) & OPCR_SPENDN0) &&
  82                !(readl(reg_usbpcr) & USBPCR_SIDDQ) &&
  83                !(readl(reg_usbpcr) & USBPCR_OTG_DISABLE);
  84}
  85
  86static const struct clk_ops x1830_otg_phy_ops = {
  87        .enable         = x1830_usb_phy_enable,
  88        .disable        = x1830_usb_phy_disable,
  89        .is_enabled     = x1830_usb_phy_is_enabled,
  90};
  91
  92static const s8 pll_od_encoding[64] = {
  93        0x0, 0x1,  -1, 0x2,  -1,  -1,  -1, 0x3,
  94         -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x4,
  95         -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
  96         -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x5,
  97         -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
  98         -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
  99         -1,  -1,  -1,  -1,  -1,  -1,  -1,  -1,
 100         -1,  -1,  -1,  -1,  -1,  -1,  -1, 0x6,
 101};
 102
 103static const struct ingenic_cgu_clk_info x1830_cgu_clocks[] = {
 104
 105        /* External clocks */
 106
 107        [X1830_CLK_EXCLK] = { "ext", CGU_CLK_EXT },
 108        [X1830_CLK_RTCLK] = { "rtc", CGU_CLK_EXT },
 109
 110        /* PLLs */
 111
 112        [X1830_CLK_APLL] = {
 113                "apll", CGU_CLK_PLL,
 114                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 115                .pll = {
 116                        .reg = CGU_REG_APLL,
 117                        .rate_multiplier = 2,
 118                        .m_shift = 20,
 119                        .m_bits = 9,
 120                        .m_offset = 1,
 121                        .n_shift = 14,
 122                        .n_bits = 6,
 123                        .n_offset = 1,
 124                        .od_shift = 11,
 125                        .od_bits = 3,
 126                        .od_max = 64,
 127                        .od_encoding = pll_od_encoding,
 128                        .bypass_reg = CGU_REG_CPPCR,
 129                        .bypass_bit = 30,
 130                        .enable_bit = 0,
 131                        .stable_bit = 3,
 132                },
 133        },
 134
 135        [X1830_CLK_MPLL] = {
 136                "mpll", CGU_CLK_PLL,
 137                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 138                .pll = {
 139                        .reg = CGU_REG_MPLL,
 140                        .rate_multiplier = 2,
 141                        .m_shift = 20,
 142                        .m_bits = 9,
 143                        .m_offset = 1,
 144                        .n_shift = 14,
 145                        .n_bits = 6,
 146                        .n_offset = 1,
 147                        .od_shift = 11,
 148                        .od_bits = 3,
 149                        .od_max = 64,
 150                        .od_encoding = pll_od_encoding,
 151                        .bypass_reg = CGU_REG_CPPCR,
 152                        .bypass_bit = 28,
 153                        .enable_bit = 0,
 154                        .stable_bit = 3,
 155                },
 156        },
 157
 158        [X1830_CLK_EPLL] = {
 159                "epll", CGU_CLK_PLL,
 160                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 161                .pll = {
 162                        .reg = CGU_REG_EPLL,
 163                        .rate_multiplier = 2,
 164                        .m_shift = 20,
 165                        .m_bits = 9,
 166                        .m_offset = 1,
 167                        .n_shift = 14,
 168                        .n_bits = 6,
 169                        .n_offset = 1,
 170                        .od_shift = 11,
 171                        .od_bits = 3,
 172                        .od_max = 64,
 173                        .od_encoding = pll_od_encoding,
 174                        .bypass_reg = CGU_REG_CPPCR,
 175                        .bypass_bit = 24,
 176                        .enable_bit = 0,
 177                        .stable_bit = 3,
 178                },
 179        },
 180
 181        [X1830_CLK_VPLL] = {
 182                "vpll", CGU_CLK_PLL,
 183                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 184                .pll = {
 185                        .reg = CGU_REG_VPLL,
 186                        .rate_multiplier = 2,
 187                        .m_shift = 20,
 188                        .m_bits = 9,
 189                        .m_offset = 1,
 190                        .n_shift = 14,
 191                        .n_bits = 6,
 192                        .n_offset = 1,
 193                        .od_shift = 11,
 194                        .od_bits = 3,
 195                        .od_max = 64,
 196                        .od_encoding = pll_od_encoding,
 197                        .bypass_reg = CGU_REG_CPPCR,
 198                        .bypass_bit = 26,
 199                        .enable_bit = 0,
 200                        .stable_bit = 3,
 201                },
 202        },
 203
 204        /* Custom (SoC-specific) OTG PHY */
 205
 206        [X1830_CLK_OTGPHY] = {
 207                "otg_phy", CGU_CLK_CUSTOM,
 208                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 209                .custom = { &x1830_otg_phy_ops },
 210        },
 211
 212        /* Muxes & dividers */
 213
 214        [X1830_CLK_SCLKA] = {
 215                "sclk_a", CGU_CLK_MUX,
 216                .parents = { -1, X1830_CLK_EXCLK, X1830_CLK_APLL, -1 },
 217                .mux = { CGU_REG_CPCCR, 30, 2 },
 218        },
 219
 220        [X1830_CLK_CPUMUX] = {
 221                "cpu_mux", CGU_CLK_MUX,
 222                .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
 223                .mux = { CGU_REG_CPCCR, 28, 2 },
 224        },
 225
 226        [X1830_CLK_CPU] = {
 227                "cpu", CGU_CLK_DIV | CGU_CLK_GATE,
 228                .parents = { X1830_CLK_CPUMUX, -1, -1, -1 },
 229                .div = { CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1 },
 230                .gate = { CGU_REG_CLKGR1, 15 },
 231        },
 232
 233        [X1830_CLK_L2CACHE] = {
 234                "l2cache", CGU_CLK_DIV,
 235                .parents = { X1830_CLK_CPUMUX, -1, -1, -1 },
 236                .div = { CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1 },
 237        },
 238
 239        [X1830_CLK_AHB0] = {
 240                "ahb0", CGU_CLK_MUX | CGU_CLK_DIV,
 241                .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
 242                .mux = { CGU_REG_CPCCR, 26, 2 },
 243                .div = { CGU_REG_CPCCR, 8, 1, 4, 21, -1, -1 },
 244        },
 245
 246        [X1830_CLK_AHB2PMUX] = {
 247                "ahb2_apb_mux", CGU_CLK_MUX,
 248                .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
 249                .mux = { CGU_REG_CPCCR, 24, 2 },
 250        },
 251
 252        [X1830_CLK_AHB2] = {
 253                "ahb2", CGU_CLK_DIV,
 254                .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 },
 255                .div = { CGU_REG_CPCCR, 12, 1, 4, 20, -1, -1 },
 256        },
 257
 258        [X1830_CLK_PCLK] = {
 259                "pclk", CGU_CLK_DIV | CGU_CLK_GATE,
 260                .parents = { X1830_CLK_AHB2PMUX, -1, -1, -1 },
 261                .div = { CGU_REG_CPCCR, 16, 1, 4, 20, -1, -1 },
 262                .gate = { CGU_REG_CLKGR1, 14 },
 263        },
 264
 265        [X1830_CLK_DDR] = {
 266                "ddr", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
 267                .parents = { -1, X1830_CLK_SCLKA, X1830_CLK_MPLL, -1 },
 268                .mux = { CGU_REG_DDRCDR, 30, 2 },
 269                .div = { CGU_REG_DDRCDR, 0, 1, 4, 29, 28, 27 },
 270                .gate = { CGU_REG_CLKGR0, 31 },
 271        },
 272
 273        [X1830_CLK_MAC] = {
 274                "mac", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
 275                .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
 276                                         X1830_CLK_VPLL, X1830_CLK_EPLL },
 277                .mux = { CGU_REG_MACCDR, 30, 2 },
 278                .div = { CGU_REG_MACCDR, 0, 1, 8, 29, 28, 27 },
 279                .gate = { CGU_REG_CLKGR1, 4 },
 280        },
 281
 282        [X1830_CLK_LCD] = {
 283                "lcd", CGU_CLK_MUX | CGU_CLK_DIV | CGU_CLK_GATE,
 284                .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
 285                                         X1830_CLK_VPLL, X1830_CLK_EPLL },
 286                .mux = { CGU_REG_LPCDR, 30, 2 },
 287                .div = { CGU_REG_LPCDR, 0, 1, 8, 28, 27, 26 },
 288                .gate = { CGU_REG_CLKGR1, 9 },
 289        },
 290
 291        [X1830_CLK_MSCMUX] = {
 292                "msc_mux", CGU_CLK_MUX,
 293                .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
 294                                         X1830_CLK_VPLL, X1830_CLK_EPLL },
 295                .mux = { CGU_REG_MSC0CDR, 30, 2 },
 296        },
 297
 298        [X1830_CLK_MSC0] = {
 299                "msc0", CGU_CLK_DIV | CGU_CLK_GATE,
 300                .parents = { X1830_CLK_MSCMUX, -1, -1, -1 },
 301                .div = { CGU_REG_MSC0CDR, 0, 2, 8, 29, 28, 27 },
 302                .gate = { CGU_REG_CLKGR0, 4 },
 303        },
 304
 305        [X1830_CLK_MSC1] = {
 306                "msc1", CGU_CLK_DIV | CGU_CLK_GATE,
 307                .parents = { X1830_CLK_MSCMUX, -1, -1, -1 },
 308                .div = { CGU_REG_MSC1CDR, 0, 2, 8, 29, 28, 27 },
 309                .gate = { CGU_REG_CLKGR0, 5 },
 310        },
 311
 312        [X1830_CLK_SSIPLL] = {
 313                "ssi_pll", CGU_CLK_MUX | CGU_CLK_DIV,
 314                .parents = { X1830_CLK_SCLKA, X1830_CLK_MPLL,
 315                                         X1830_CLK_VPLL, X1830_CLK_EPLL },
 316                .mux = { CGU_REG_SSICDR, 30, 2 },
 317                .div = { CGU_REG_SSICDR, 0, 1, 8, 28, 27, 26 },
 318        },
 319
 320        [X1830_CLK_SSIPLL_DIV2] = {
 321                "ssi_pll_div2", CGU_CLK_FIXDIV,
 322                .parents = { X1830_CLK_SSIPLL },
 323                .fixdiv = { 2 },
 324        },
 325
 326        [X1830_CLK_SSIMUX] = {
 327                "ssi_mux", CGU_CLK_MUX,
 328                .parents = { X1830_CLK_EXCLK, X1830_CLK_SSIPLL_DIV2, -1, -1 },
 329                .mux = { CGU_REG_SSICDR, 29, 1 },
 330        },
 331
 332        [X1830_CLK_EXCLK_DIV512] = {
 333                "exclk_div512", CGU_CLK_FIXDIV,
 334                .parents = { X1830_CLK_EXCLK },
 335                .fixdiv = { 512 },
 336        },
 337
 338        [X1830_CLK_RTC] = {
 339                "rtc_ercs", CGU_CLK_MUX | CGU_CLK_GATE,
 340                .parents = { X1830_CLK_EXCLK_DIV512, X1830_CLK_RTCLK },
 341                .mux = { CGU_REG_OPCR, 2, 1},
 342                .gate = { CGU_REG_CLKGR0, 29 },
 343        },
 344
 345        /* Gate-only clocks */
 346
 347        [X1830_CLK_EMC] = {
 348                "emc", CGU_CLK_GATE,
 349                .parents = { X1830_CLK_AHB2, -1, -1, -1 },
 350                .gate = { CGU_REG_CLKGR0, 0 },
 351        },
 352
 353        [X1830_CLK_EFUSE] = {
 354                "efuse", CGU_CLK_GATE,
 355                .parents = { X1830_CLK_AHB2, -1, -1, -1 },
 356                .gate = { CGU_REG_CLKGR0, 1 },
 357        },
 358
 359        [X1830_CLK_OTG] = {
 360                "otg", CGU_CLK_GATE,
 361                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 362                .gate = { CGU_REG_CLKGR0, 3 },
 363        },
 364
 365        [X1830_CLK_SSI0] = {
 366                "ssi0", CGU_CLK_GATE,
 367                .parents = { X1830_CLK_SSIMUX, -1, -1, -1 },
 368                .gate = { CGU_REG_CLKGR0, 6 },
 369        },
 370
 371        [X1830_CLK_SMB0] = {
 372                "smb0", CGU_CLK_GATE,
 373                .parents = { X1830_CLK_PCLK, -1, -1, -1 },
 374                .gate = { CGU_REG_CLKGR0, 7 },
 375        },
 376
 377        [X1830_CLK_SMB1] = {
 378                "smb1", CGU_CLK_GATE,
 379                .parents = { X1830_CLK_PCLK, -1, -1, -1 },
 380                .gate = { CGU_REG_CLKGR0, 8 },
 381        },
 382
 383        [X1830_CLK_SMB2] = {
 384                "smb2", CGU_CLK_GATE,
 385                .parents = { X1830_CLK_PCLK, -1, -1, -1 },
 386                .gate = { CGU_REG_CLKGR0, 9 },
 387        },
 388
 389        [X1830_CLK_UART0] = {
 390                "uart0", CGU_CLK_GATE,
 391                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 392                .gate = { CGU_REG_CLKGR0, 14 },
 393        },
 394
 395        [X1830_CLK_UART1] = {
 396                "uart1", CGU_CLK_GATE,
 397                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 398                .gate = { CGU_REG_CLKGR0, 15 },
 399        },
 400
 401        [X1830_CLK_SSI1] = {
 402                "ssi1", CGU_CLK_GATE,
 403                .parents = { X1830_CLK_SSIMUX, -1, -1, -1 },
 404                .gate = { CGU_REG_CLKGR0, 19 },
 405        },
 406
 407        [X1830_CLK_SFC] = {
 408                "sfc", CGU_CLK_GATE,
 409                .parents = { X1830_CLK_SSIPLL, -1, -1, -1 },
 410                .gate = { CGU_REG_CLKGR0, 20 },
 411        },
 412
 413        [X1830_CLK_PDMA] = {
 414                "pdma", CGU_CLK_GATE,
 415                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 416                .gate = { CGU_REG_CLKGR0, 21 },
 417        },
 418
 419        [X1830_CLK_TCU] = {
 420                "tcu", CGU_CLK_GATE,
 421                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 422                .gate = { CGU_REG_CLKGR0, 30 },
 423        },
 424
 425        [X1830_CLK_DTRNG] = {
 426                "dtrng", CGU_CLK_GATE,
 427                .parents = { X1830_CLK_PCLK, -1, -1, -1 },
 428                .gate = { CGU_REG_CLKGR1, 1 },
 429        },
 430
 431        [X1830_CLK_OST] = {
 432                "ost", CGU_CLK_GATE,
 433                .parents = { X1830_CLK_EXCLK, -1, -1, -1 },
 434                .gate = { CGU_REG_CLKGR1, 11 },
 435        },
 436};
 437
 438static void __init x1830_cgu_init(struct device_node *np)
 439{
 440        int retval;
 441
 442        cgu = ingenic_cgu_new(x1830_cgu_clocks,
 443                              ARRAY_SIZE(x1830_cgu_clocks), np);
 444        if (!cgu) {
 445                pr_err("%s: failed to initialise CGU\n", __func__);
 446                return;
 447        }
 448
 449        retval = ingenic_cgu_register_clocks(cgu);
 450        if (retval) {
 451                pr_err("%s: failed to register CGU Clocks\n", __func__);
 452                return;
 453        }
 454
 455        ingenic_cgu_register_syscore_ops(cgu);
 456}
 457/*
 458 * CGU has some children devices, this is useful for probing children devices
 459 * in the case where the device node is compatible with "simple-mfd".
 460 */
 461CLK_OF_DECLARE_DRIVER(x1830_cgu, "ingenic,x1830-cgu", x1830_cgu_init);
 462