linux/drivers/clk/ingenic/jz4760-cgu.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * JZ4760 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 <linux/clk.h>
  14
  15#include <dt-bindings/clock/jz4760-cgu.h>
  16
  17#include "cgu.h"
  18#include "pm.h"
  19
  20#define MHZ (1000 * 1000)
  21
  22/*
  23 * CPM registers offset address definition
  24 */
  25#define CGU_REG_CPCCR           0x00
  26#define CGU_REG_LCR             0x04
  27#define CGU_REG_CPPCR0          0x10
  28#define CGU_REG_CLKGR0          0x20
  29#define CGU_REG_OPCR            0x24
  30#define CGU_REG_CLKGR1          0x28
  31#define CGU_REG_CPPCR1          0x30
  32#define CGU_REG_USBPCR          0x3c
  33#define CGU_REG_USBCDR          0x50
  34#define CGU_REG_I2SCDR          0x60
  35#define CGU_REG_LPCDR           0x64
  36#define CGU_REG_MSCCDR          0x68
  37#define CGU_REG_UHCCDR          0x6c
  38#define CGU_REG_SSICDR          0x74
  39#define CGU_REG_CIMCDR          0x7c
  40#define CGU_REG_GPSCDR          0x80
  41#define CGU_REG_PCMCDR          0x84
  42#define CGU_REG_GPUCDR          0x88
  43
  44static const s8 pll_od_encoding[8] = {
  45        0x0, 0x1, -1, 0x2, -1, -1, -1, 0x3,
  46};
  47
  48static const u8 jz4760_cgu_cpccr_div_table[] = {
  49        1, 2, 3, 4, 6, 8,
  50};
  51
  52static const u8 jz4760_cgu_pll_half_div_table[] = {
  53        2, 1,
  54};
  55
  56static void
  57jz4760_cgu_calc_m_n_od(const struct ingenic_cgu_pll_info *pll_info,
  58                       unsigned long rate, unsigned long parent_rate,
  59                       unsigned int *pm, unsigned int *pn, unsigned int *pod)
  60{
  61        unsigned int m, n, od, m_max = (1 << pll_info->m_bits) - 2;
  62
  63        /* The frequency after the N divider must be between 1 and 50 MHz. */
  64        n = parent_rate / (1 * MHZ);
  65
  66        /* The N divider must be >= 2. */
  67        n = clamp_val(n, 2, 1 << pll_info->n_bits);
  68
  69        for (;; n >>= 1) {
  70                od = (unsigned int)-1;
  71
  72                do {
  73                        m = (rate / MHZ) * (1 << ++od) * n / (parent_rate / MHZ);
  74                } while ((m > m_max || m & 1) && (od < 4));
  75
  76                if (od < 4 && m >= 4 && m <= m_max)
  77                        break;
  78        }
  79
  80        *pm = m;
  81        *pn = n;
  82        *pod = 1 << od;
  83}
  84
  85static const struct ingenic_cgu_clk_info jz4760_cgu_clocks[] = {
  86
  87        /* External clocks */
  88
  89        [JZ4760_CLK_EXT] = { "ext", CGU_CLK_EXT },
  90        [JZ4760_CLK_OSC32K] = { "osc32k", CGU_CLK_EXT },
  91
  92        /* PLLs */
  93
  94        [JZ4760_CLK_PLL0] = {
  95                "pll0", CGU_CLK_PLL,
  96                .parents = { JZ4760_CLK_EXT },
  97                .pll = {
  98                        .reg = CGU_REG_CPPCR0,
  99                        .rate_multiplier = 1,
 100                        .m_shift = 23,
 101                        .m_bits = 8,
 102                        .m_offset = 0,
 103                        .n_shift = 18,
 104                        .n_bits = 4,
 105                        .n_offset = 0,
 106                        .od_shift = 16,
 107                        .od_bits = 2,
 108                        .od_max = 8,
 109                        .od_encoding = pll_od_encoding,
 110                        .bypass_reg = CGU_REG_CPPCR0,
 111                        .bypass_bit = 9,
 112                        .enable_bit = 8,
 113                        .stable_bit = 10,
 114                        .calc_m_n_od = jz4760_cgu_calc_m_n_od,
 115                },
 116        },
 117
 118        [JZ4760_CLK_PLL1] = {
 119                /* TODO: PLL1 can depend on PLL0 */
 120                "pll1", CGU_CLK_PLL,
 121                .parents = { JZ4760_CLK_EXT },
 122                .pll = {
 123                        .reg = CGU_REG_CPPCR1,
 124                        .rate_multiplier = 1,
 125                        .m_shift = 23,
 126                        .m_bits = 8,
 127                        .m_offset = 0,
 128                        .n_shift = 18,
 129                        .n_bits = 4,
 130                        .n_offset = 0,
 131                        .od_shift = 16,
 132                        .od_bits = 2,
 133                        .od_max = 8,
 134                        .od_encoding = pll_od_encoding,
 135                        .bypass_bit = -1,
 136                        .enable_bit = 7,
 137                        .stable_bit = 6,
 138                        .calc_m_n_od = jz4760_cgu_calc_m_n_od,
 139                },
 140        },
 141
 142        /* Main clocks */
 143
 144        [JZ4760_CLK_CCLK] = {
 145                "cclk", CGU_CLK_DIV,
 146                .parents = { JZ4760_CLK_PLL0, },
 147                .div = {
 148                        CGU_REG_CPCCR, 0, 1, 4, 22, -1, -1, 0,
 149                        jz4760_cgu_cpccr_div_table,
 150                },
 151        },
 152        [JZ4760_CLK_HCLK] = {
 153                "hclk", CGU_CLK_DIV,
 154                .parents = { JZ4760_CLK_PLL0, },
 155                .div = {
 156                        CGU_REG_CPCCR, 4, 1, 4, 22, -1, -1, 0,
 157                        jz4760_cgu_cpccr_div_table,
 158                },
 159        },
 160        [JZ4760_CLK_SCLK] = {
 161                "sclk", CGU_CLK_DIV,
 162                .parents = { JZ4760_CLK_PLL0, },
 163                .div = {
 164                        CGU_REG_CPCCR, 24, 1, 4, 22, -1, -1, 0,
 165                        jz4760_cgu_cpccr_div_table,
 166                },
 167        },
 168        [JZ4760_CLK_H2CLK] = {
 169                "h2clk", CGU_CLK_DIV,
 170                .parents = { JZ4760_CLK_PLL0, },
 171                .div = {
 172                        CGU_REG_CPCCR, 16, 1, 4, 22, -1, -1, 0,
 173                        jz4760_cgu_cpccr_div_table,
 174                },
 175        },
 176        [JZ4760_CLK_MCLK] = {
 177                "mclk", CGU_CLK_DIV,
 178                .parents = { JZ4760_CLK_PLL0, },
 179                .div = {
 180                        CGU_REG_CPCCR, 12, 1, 4, 22, -1, -1, 0,
 181                        jz4760_cgu_cpccr_div_table,
 182                },
 183        },
 184        [JZ4760_CLK_PCLK] = {
 185                "pclk", CGU_CLK_DIV,
 186                .parents = { JZ4760_CLK_PLL0, },
 187                .div = {
 188                        CGU_REG_CPCCR, 8, 1, 4, 22, -1, -1, 0,
 189                        jz4760_cgu_cpccr_div_table,
 190                },
 191        },
 192
 193        /* Divided clocks */
 194
 195        [JZ4760_CLK_PLL0_HALF] = {
 196                "pll0_half", CGU_CLK_DIV,
 197                .parents = { JZ4760_CLK_PLL0 },
 198                .div = {
 199                        CGU_REG_CPCCR, 21, 1, 1, 22, -1, -1, 0,
 200                        jz4760_cgu_pll_half_div_table,
 201                },
 202        },
 203
 204        /* Those divided clocks can connect to PLL0 or PLL1 */
 205
 206        [JZ4760_CLK_UHC] = {
 207                "uhc", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 208                .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
 209                .mux = { CGU_REG_UHCCDR, 31, 1 },
 210                .div = { CGU_REG_UHCCDR, 0, 1, 4, -1, -1, -1 },
 211                .gate = { CGU_REG_CLKGR0, 24 },
 212        },
 213        [JZ4760_CLK_GPU] = {
 214                "gpu", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 215                .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
 216                .mux = { CGU_REG_GPUCDR, 31, 1 },
 217                .div = { CGU_REG_GPUCDR, 0, 1, 3, -1, -1, -1 },
 218                .gate = { CGU_REG_CLKGR1, 9 },
 219        },
 220        [JZ4760_CLK_LPCLK_DIV] = {
 221                "lpclk_div", CGU_CLK_DIV | CGU_CLK_MUX,
 222                .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
 223                .mux = { CGU_REG_LPCDR, 29, 1 },
 224                .div = { CGU_REG_LPCDR, 0, 1, 11, -1, -1, -1 },
 225        },
 226        [JZ4760_CLK_TVE] = {
 227                "tve", CGU_CLK_GATE | CGU_CLK_MUX,
 228                .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_EXT, },
 229                .mux = { CGU_REG_LPCDR, 31, 1 },
 230                .gate = { CGU_REG_CLKGR0, 27 },
 231        },
 232        [JZ4760_CLK_LPCLK] = {
 233                "lpclk", CGU_CLK_GATE | CGU_CLK_MUX,
 234                .parents = { JZ4760_CLK_LPCLK_DIV, JZ4760_CLK_TVE, },
 235                .mux = { CGU_REG_LPCDR, 30, 1 },
 236                .gate = { CGU_REG_CLKGR0, 28 },
 237        },
 238        [JZ4760_CLK_GPS] = {
 239                "gps", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 240                .parents = { JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1, },
 241                .mux = { CGU_REG_GPSCDR, 31, 1 },
 242                .div = { CGU_REG_GPSCDR, 0, 1, 4, -1, -1, -1 },
 243                .gate = { CGU_REG_CLKGR0, 22 },
 244        },
 245
 246        /* Those divided clocks can connect to EXT, PLL0 or PLL1 */
 247
 248        [JZ4760_CLK_PCM] = {
 249                "pcm", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 250                .parents = { JZ4760_CLK_EXT, -1,
 251                        JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
 252                .mux = { CGU_REG_PCMCDR, 30, 2 },
 253                .div = { CGU_REG_PCMCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
 254                .gate = { CGU_REG_CLKGR1, 8 },
 255        },
 256        [JZ4760_CLK_I2S] = {
 257                "i2s", CGU_CLK_DIV | CGU_CLK_MUX,
 258                .parents = { JZ4760_CLK_EXT, -1,
 259                        JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
 260                .mux = { CGU_REG_I2SCDR, 30, 2 },
 261                .div = { CGU_REG_I2SCDR, 0, 1, 9, -1, -1, -1, BIT(0) },
 262        },
 263        [JZ4760_CLK_OTG] = {
 264                "usb", CGU_CLK_DIV | CGU_CLK_GATE | CGU_CLK_MUX,
 265                .parents = { JZ4760_CLK_EXT, -1,
 266                        JZ4760_CLK_PLL0_HALF, JZ4760_CLK_PLL1 },
 267                .mux = { CGU_REG_USBCDR, 30, 2 },
 268                .div = { CGU_REG_USBCDR, 0, 1, 8, -1, -1, -1 },
 269                .gate = { CGU_REG_CLKGR0, 2 },
 270        },
 271
 272        /* Those divided clocks can connect to EXT or PLL0 */
 273        [JZ4760_CLK_MMC_MUX] = {
 274                "mmc_mux", CGU_CLK_MUX | CGU_CLK_DIV,
 275                .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
 276                .mux = { CGU_REG_MSCCDR, 31, 1 },
 277                .div = { CGU_REG_MSCCDR, 0, 1, 6, -1, -1, -1, BIT(0) },
 278        },
 279        [JZ4760_CLK_SSI_MUX] = {
 280                "ssi_mux", CGU_CLK_DIV | CGU_CLK_MUX,
 281                .parents = { JZ4760_CLK_EXT, JZ4760_CLK_PLL0_HALF, },
 282                .mux = { CGU_REG_SSICDR, 31, 1 },
 283                .div = { CGU_REG_SSICDR, 0, 1, 6, -1, -1, -1, BIT(0) },
 284        },
 285
 286        /* These divided clock can connect to PLL0 only */
 287        [JZ4760_CLK_CIM] = {
 288                "cim", CGU_CLK_DIV | CGU_CLK_GATE,
 289                .parents = { JZ4760_CLK_PLL0_HALF },
 290                .div = { CGU_REG_CIMCDR, 0, 1, 8, -1, -1, -1 },
 291                .gate = { CGU_REG_CLKGR0, 26 },
 292        },
 293
 294        /* Gate-only clocks */
 295
 296        [JZ4760_CLK_SSI0] = {
 297                "ssi0", CGU_CLK_GATE,
 298                .parents = { JZ4760_CLK_SSI_MUX, },
 299                .gate = { CGU_REG_CLKGR0, 4 },
 300        },
 301        [JZ4760_CLK_SSI1] = {
 302                "ssi1", CGU_CLK_GATE,
 303                .parents = { JZ4760_CLK_SSI_MUX, },
 304                .gate = { CGU_REG_CLKGR0, 19 },
 305        },
 306        [JZ4760_CLK_SSI2] = {
 307                "ssi2", CGU_CLK_GATE,
 308                .parents = { JZ4760_CLK_SSI_MUX, },
 309                .gate = { CGU_REG_CLKGR0, 20 },
 310        },
 311        [JZ4760_CLK_DMA] = {
 312                "dma", CGU_CLK_GATE,
 313                .parents = { JZ4760_CLK_H2CLK, },
 314                .gate = { CGU_REG_CLKGR0, 21 },
 315        },
 316        [JZ4760_CLK_I2C0] = {
 317                "i2c0", CGU_CLK_GATE,
 318                .parents = { JZ4760_CLK_EXT, },
 319                .gate = { CGU_REG_CLKGR0, 5 },
 320        },
 321        [JZ4760_CLK_I2C1] = {
 322                "i2c1", CGU_CLK_GATE,
 323                .parents = { JZ4760_CLK_EXT, },
 324                .gate = { CGU_REG_CLKGR0, 6 },
 325        },
 326        [JZ4760_CLK_UART0] = {
 327                "uart0", CGU_CLK_GATE,
 328                .parents = { JZ4760_CLK_EXT, },
 329                .gate = { CGU_REG_CLKGR0, 15 },
 330        },
 331        [JZ4760_CLK_UART1] = {
 332                "uart1", CGU_CLK_GATE,
 333                .parents = { JZ4760_CLK_EXT, },
 334                .gate = { CGU_REG_CLKGR0, 16 },
 335        },
 336        [JZ4760_CLK_UART2] = {
 337                "uart2", CGU_CLK_GATE,
 338                .parents = { JZ4760_CLK_EXT, },
 339                .gate = { CGU_REG_CLKGR0, 17 },
 340        },
 341        [JZ4760_CLK_UART3] = {
 342                "uart3", CGU_CLK_GATE,
 343                .parents = { JZ4760_CLK_EXT, },
 344                .gate = { CGU_REG_CLKGR0, 18 },
 345        },
 346        [JZ4760_CLK_IPU] = {
 347                "ipu", CGU_CLK_GATE,
 348                .parents = { JZ4760_CLK_HCLK, },
 349                .gate = { CGU_REG_CLKGR0, 29 },
 350        },
 351        [JZ4760_CLK_ADC] = {
 352                "adc", CGU_CLK_GATE,
 353                .parents = { JZ4760_CLK_EXT, },
 354                .gate = { CGU_REG_CLKGR0, 14 },
 355        },
 356        [JZ4760_CLK_AIC] = {
 357                "aic", CGU_CLK_GATE,
 358                .parents = { JZ4760_CLK_EXT, },
 359                .gate = { CGU_REG_CLKGR0, 8 },
 360        },
 361        [JZ4760_CLK_VPU] = {
 362                "vpu", CGU_CLK_GATE,
 363                .parents = { JZ4760_CLK_HCLK, },
 364                .gate = { CGU_REG_LCR, 30, false, 150 },
 365        },
 366        [JZ4760_CLK_MMC0] = {
 367                "mmc0", CGU_CLK_GATE,
 368                .parents = { JZ4760_CLK_MMC_MUX, },
 369                .gate = { CGU_REG_CLKGR0, 3 },
 370        },
 371        [JZ4760_CLK_MMC1] = {
 372                "mmc1", CGU_CLK_GATE,
 373                .parents = { JZ4760_CLK_MMC_MUX, },
 374                .gate = { CGU_REG_CLKGR0, 11 },
 375        },
 376        [JZ4760_CLK_MMC2] = {
 377                "mmc2", CGU_CLK_GATE,
 378                .parents = { JZ4760_CLK_MMC_MUX, },
 379                .gate = { CGU_REG_CLKGR0, 12 },
 380        },
 381        [JZ4760_CLK_UHC_PHY] = {
 382                "uhc_phy", CGU_CLK_GATE,
 383                .parents = { JZ4760_CLK_UHC, },
 384                .gate = { CGU_REG_OPCR, 5 },
 385        },
 386        [JZ4760_CLK_OTG_PHY] = {
 387                "usb_phy", CGU_CLK_GATE,
 388                .parents = { JZ4760_CLK_OTG },
 389                .gate = { CGU_REG_OPCR, 7, true, 50 },
 390        },
 391
 392        /* Custom clocks */
 393        [JZ4760_CLK_EXT512] = {
 394                "ext/512", CGU_CLK_FIXDIV,
 395                .parents = { JZ4760_CLK_EXT },
 396                .fixdiv = { 512 },
 397        },
 398        [JZ4760_CLK_RTC] = {
 399                "rtc", CGU_CLK_MUX,
 400                .parents = { JZ4760_CLK_EXT512, JZ4760_CLK_OSC32K, },
 401                .mux = { CGU_REG_OPCR, 2, 1},
 402        },
 403};
 404
 405static void __init jz4760_cgu_init(struct device_node *np)
 406{
 407        struct ingenic_cgu *cgu;
 408        int retval;
 409
 410        cgu = ingenic_cgu_new(jz4760_cgu_clocks,
 411                              ARRAY_SIZE(jz4760_cgu_clocks), np);
 412        if (!cgu) {
 413                pr_err("%s: failed to initialise CGU\n", __func__);
 414                return;
 415        }
 416
 417        retval = ingenic_cgu_register_clocks(cgu);
 418        if (retval)
 419                pr_err("%s: failed to register CGU Clocks\n", __func__);
 420
 421        ingenic_cgu_register_syscore_ops(cgu);
 422}
 423
 424/* We only probe via devicetree, no need for a platform driver */
 425CLK_OF_DECLARE_DRIVER(jz4760_cgu, "ingenic,jz4760-cgu", jz4760_cgu_init);
 426
 427/* JZ4760B has some small differences, but we don't implement them. */
 428CLK_OF_DECLARE_DRIVER(jz4760b_cgu, "ingenic,jz4760b-cgu", jz4760_cgu_init);
 429