uboot/board/freescale/s32v234evb/clock.c
<<
>>
Prefs
   1/*
   2 * (C) Copyright 2015, Freescale Semiconductor, Inc.
   3 *
   4 * SPDX-License-Identifier:     GPL-2.0+
   5 */
   6
   7#include <asm/io.h>
   8#include <asm/arch/imx-regs.h>
   9#include <asm/arch/mc_cgm_regs.h>
  10#include <asm/arch/mc_me_regs.h>
  11#include <asm/arch/clock.h>
  12
  13/*
  14 * Select the clock reference for required pll.
  15 * pll - ARM_PLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_PLL.
  16 * refclk_freq - input referece clock frequency (FXOSC - 40 MHZ, FIRC - 48 MHZ)
  17 */
  18static int select_pll_source_clk(enum pll_type pll, u32 refclk_freq)
  19{
  20        u32 clk_src;
  21        u32 pll_idx;
  22        volatile struct src *src = (struct src *)SRC_SOC_BASE_ADDR;
  23
  24        /* select the pll clock source */
  25        switch (refclk_freq) {
  26        case FIRC_CLK_FREQ:
  27                clk_src = SRC_GPR1_FIRC_CLK_SOURCE;
  28                break;
  29        case XOSC_CLK_FREQ:
  30                clk_src = SRC_GPR1_XOSC_CLK_SOURCE;
  31                break;
  32        default:
  33                /* The clock frequency for the source clock is unknown */
  34                return -1;
  35        }
  36        /*
  37         * The hardware definition is not uniform, it has to calculate again
  38         * the recurrence formula.
  39         */
  40        switch (pll) {
  41        case PERIPH_PLL:
  42                pll_idx = 3;
  43                break;
  44        case ENET_PLL:
  45                pll_idx = 1;
  46                break;
  47        case DDR_PLL:
  48                pll_idx = 2;
  49                break;
  50        default:
  51                pll_idx = pll;
  52        }
  53
  54        writel(readl(&src->gpr1) | SRC_GPR1_PLL_SOURCE(pll_idx, clk_src),
  55               &src->gpr1);
  56
  57        return 0;
  58}
  59
  60static void entry_to_target_mode(u32 mode)
  61{
  62        writel(mode | MC_ME_MCTL_KEY, MC_ME_MCTL);
  63        writel(mode | MC_ME_MCTL_INVERTEDKEY, MC_ME_MCTL);
  64        while ((readl(MC_ME_GS) & MC_ME_GS_S_MTRANS) != 0x00000000) ;
  65}
  66
  67/*
  68 * Program the pll according to the input parameters.
  69 * pll - ARM_PLL, PERIPH_PLL, ENET_PLL, DDR_PLL, VIDEO_PLL.
  70 * refclk_freq - input reference clock frequency (FXOSC - 40 MHZ, FIRC - 48 MHZ)
  71 * freq - expected output frequency for PHY0
  72 * freq1 - expected output frequency for PHY1
  73 * dfs_nr - number of DFS modules for current PLL
  74 * dfs - array with the activation dfs field, mfn and mfi
  75 * plldv_prediv - divider of clkfreq_ref
  76 * plldv_mfd - loop multiplication factor divider
  77 * pllfd_mfn - numerator loop multiplication factor divider
  78 * Please consult the PLLDIG chapter of platform manual
  79 * before to use this function.
  80 *)
  81 */
  82static int program_pll(enum pll_type pll, u32 refclk_freq, u32 freq0, u32 freq1,
  83                       u32 dfs_nr, u32 dfs[][DFS_PARAMS_Nr], u32 plldv_prediv,
  84                       u32 plldv_mfd, u32 pllfd_mfn)
  85{
  86        u32 i, rfdphi1, rfdphi, dfs_on = 0, fvco;
  87
  88        /*
  89         * This formula is from platform reference manual (Rev. 1, 6/2015), PLLDIG chapter.
  90         */
  91        fvco =
  92            (refclk_freq / plldv_prediv) * (plldv_mfd +
  93                                            pllfd_mfn / (float)20480);
  94
  95        /*
  96         * VCO should have value in [ PLL_MIN_FREQ, PLL_MAX_FREQ ]. Please consult
  97         * the platform DataSheet in order to determine the allowed values.
  98         */
  99
 100        if (fvco < PLL_MIN_FREQ || fvco > PLL_MAX_FREQ) {
 101                return -1;
 102        }
 103
 104        if (select_pll_source_clk(pll, refclk_freq) < 0) {
 105                return -1;
 106        }
 107
 108        rfdphi = fvco / freq0;
 109
 110        rfdphi1 = (freq1 == 0) ? 0 : fvco / freq1;
 111
 112        writel(PLLDIG_PLLDV_RFDPHI1_SET(rfdphi1) |
 113               PLLDIG_PLLDV_RFDPHI_SET(rfdphi) |
 114               PLLDIG_PLLDV_PREDIV_SET(plldv_prediv) |
 115               PLLDIG_PLLDV_MFD(plldv_mfd), PLLDIG_PLLDV(pll));
 116
 117        writel(readl(PLLDIG_PLLFD(pll)) | PLLDIG_PLLFD_MFN_SET(pllfd_mfn) |
 118               PLLDIG_PLLFD_SMDEN, PLLDIG_PLLFD(pll));
 119
 120        /* switch on the pll in current mode */
 121        writel(readl(MC_ME_RUNn_MC(0)) | MC_ME_RUNMODE_MC_PLL(pll),
 122               MC_ME_RUNn_MC(0));
 123
 124        entry_to_target_mode(MC_ME_MCTL_RUN0);
 125
 126        /* Only ARM_PLL, ENET_PLL and DDR_PLL */
 127        if ((pll == ARM_PLL) || (pll == ENET_PLL) || (pll == DDR_PLL)) {
 128                /* DFS clk enable programming */
 129                writel(DFS_CTRL_DLL_RESET, DFS_CTRL(pll));
 130
 131                writel(DFS_DLLPRG1_CPICTRL_SET(0x5) |
 132                       DFS_DLLPRG1_VSETTLCTRL_SET(0x1) |
 133                       DFS_DLLPRG1_CALBYPEN_SET(0x0) |
 134                       DFS_DLLPRG1_DACIN_SET(0x1) | DFS_DLLPRG1_LCKWT_SET(0x0) |
 135                       DFS_DLLPRG1_V2IGC_SET(0x5), DFS_DLLPRG1(pll));
 136
 137                for (i = 0; i < dfs_nr; i++) {
 138                        if (dfs[i][0]) {
 139                                writel(DFS_DVPORTn_MFI_SET(dfs[i][2]) |
 140                                       DFS_DVPORTn_MFN_SET(dfs[i][1]),
 141                                       DFS_DVPORTn(pll, i));
 142                                dfs_on |= (dfs[i][0] << i);
 143                        }
 144                }
 145
 146                writel(readl(DFS_CTRL(pll)) & ~DFS_CTRL_DLL_RESET,
 147                       DFS_CTRL(pll));
 148                writel(readl(DFS_PORTRESET(pll)) &
 149                       ~DFS_PORTRESET_PORTRESET_SET(dfs_on),
 150                       DFS_PORTRESET(pll));
 151                while ((readl(DFS_PORTSR(pll)) & dfs_on) != dfs_on) ;
 152        }
 153
 154        entry_to_target_mode(MC_ME_MCTL_RUN0);
 155
 156        return 0;
 157
 158}
 159
 160static void aux_source_clk_config(uintptr_t cgm_addr, u8 ac, u32 source)
 161{
 162        /* select the clock source */
 163        writel(MC_CGM_ACn_SEL_SET(source), CGM_ACn_SC(cgm_addr, ac));
 164}
 165
 166static void aux_div_clk_config(uintptr_t cgm_addr, u8 ac, u8 dc, u32 divider)
 167{
 168        /* set the divider */
 169        writel(MC_CGM_ACn_DCm_DE | MC_CGM_ACn_DCm_PREDIV(divider),
 170               CGM_ACn_DCm(cgm_addr, ac, dc));
 171}
 172
 173static void setup_sys_clocks(void)
 174{
 175
 176        /* set ARM PLL DFS 1 as SYSCLK */
 177        writel((readl(MC_ME_RUNn_MC(0)) & ~MC_ME_RUNMODE_MC_SYSCLK_MASK) |
 178               MC_ME_RUNMODE_MC_SYSCLK(0x2), MC_ME_RUNn_MC(0));
 179
 180        entry_to_target_mode(MC_ME_MCTL_RUN0);
 181
 182        /* select sysclks  ARMPLL, ARMPLLDFS2, ARMPLLDFS3 */
 183        writel(MC_ME_RUNMODE_SEC_CC_I_SYSCLK
 184               (0x2,
 185                MC_ME_RUNMODE_SEC_CC_I_SYSCLK1_OFFSET) |
 186               MC_ME_RUNMODE_SEC_CC_I_SYSCLK(0x2,
 187                                             MC_ME_RUNMODE_SEC_CC_I_SYSCLK2_OFFSET)
 188               | MC_ME_RUNMODE_SEC_CC_I_SYSCLK(0x2,
 189                                               MC_ME_RUNMODE_SEC_CC_I_SYSCLK3_OFFSET),
 190               MC_ME_RUNn_SEC_CC_I(0));
 191
 192        /* setup the sys clock divider for CORE_CLK (1000MHz) */
 193        writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x0),
 194               CGM_SC_DCn(MC_CGM1_BASE_ADDR, 0));
 195
 196        /* setup the sys clock divider for CORE2_CLK (500MHz) */
 197        writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x1),
 198               CGM_SC_DCn(MC_CGM1_BASE_ADDR, 1));
 199        /* setup the sys clock divider for SYS3_CLK (266 MHz) */
 200        writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x0),
 201               CGM_SC_DCn(MC_CGM0_BASE_ADDR, 0));
 202
 203        /* setup the sys clock divider for SYS6_CLK (133 Mhz) */
 204        writel(MC_CGM_SC_DCn_DE | MC_CGM_SC_DCn_PREDIV(0x1),
 205               CGM_SC_DCn(MC_CGM0_BASE_ADDR, 1));
 206
 207        entry_to_target_mode(MC_ME_MCTL_RUN0);
 208
 209}
 210
 211static void setup_aux_clocks(void)
 212{
 213        /*
 214         * setup the aux clock divider for PERI_CLK
 215         * (source: PERIPH_PLL_PHI_0/5, PERI_CLK - 80 MHz)
 216         */
 217        aux_source_clk_config(MC_CGM0_BASE_ADDR, 5, MC_CGM_ACn_SEL_PERPLLDIVX);
 218        aux_div_clk_config(MC_CGM0_BASE_ADDR, 5, 0, 4);
 219
 220        /* setup the aux clock divider for LIN_CLK (40MHz) */
 221        aux_source_clk_config(MC_CGM0_BASE_ADDR, 3, MC_CGM_ACn_SEL_PERPLLDIVX);
 222        aux_div_clk_config(MC_CGM0_BASE_ADDR, 3, 0, 1);
 223
 224        /* setup the aux clock divider for ENET_TIME_CLK (50MHz) */
 225        aux_source_clk_config(MC_CGM0_BASE_ADDR, 7, MC_CGM_ACn_SEL_ENETPLL);
 226        aux_div_clk_config(MC_CGM0_BASE_ADDR, 7, 1, 9);
 227
 228        /* setup the aux clock divider for ENET_CLK (50MHz) */
 229        aux_source_clk_config(MC_CGM2_BASE_ADDR, 2, MC_CGM_ACn_SEL_ENETPLL);
 230        aux_div_clk_config(MC_CGM2_BASE_ADDR, 2, 0, 9);
 231
 232        /* setup the aux clock divider for SDHC_CLK (50 MHz). */
 233        aux_source_clk_config(MC_CGM0_BASE_ADDR, 15, MC_CGM_ACn_SEL_ENETPLL);
 234        aux_div_clk_config(MC_CGM0_BASE_ADDR, 15, 0, 9);
 235
 236        /* setup the aux clock divider for DDR_CLK (533MHz) and APEX_SYS_CLK (266MHz) */
 237        aux_source_clk_config(MC_CGM0_BASE_ADDR, 8, MC_CGM_ACn_SEL_DDRPLL);
 238        aux_div_clk_config(MC_CGM0_BASE_ADDR, 8, 0, 0);
 239        /* setup the aux clock divider for DDR4_CLK (133,25MHz) */
 240        aux_div_clk_config(MC_CGM0_BASE_ADDR, 8, 1, 3);
 241
 242        entry_to_target_mode(MC_ME_MCTL_RUN0);
 243
 244}
 245
 246static void enable_modules_clock(void)
 247{
 248        /* PIT0 */
 249        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL58);
 250        /* PIT1 */
 251        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL170);
 252        /* LINFLEX0 */
 253        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL83);
 254        /* LINFLEX1 */
 255        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL188);
 256        /* ENET */
 257        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL50);
 258        /* SDHC */
 259        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL93);
 260        /* IIC0 */
 261        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL81);
 262        /* IIC1 */
 263        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL184);
 264        /* IIC2 */
 265        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL186);
 266        /* MMDC0 */
 267        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL54);
 268        /* MMDC1 */
 269        writeb(MC_ME_PCTLn_RUNPCm(0), MC_ME_PCTL162);
 270
 271        entry_to_target_mode(MC_ME_MCTL_RUN0);
 272}
 273
 274void clock_init(void)
 275{
 276        unsigned int arm_dfs[ARM_PLL_PHI1_DFS_Nr][DFS_PARAMS_Nr] = {
 277                {ARM_PLL_PHI1_DFS1_EN, ARM_PLL_PHI1_DFS1_MFN,
 278                 ARM_PLL_PHI1_DFS1_MFI},
 279                {ARM_PLL_PHI1_DFS2_EN, ARM_PLL_PHI1_DFS2_MFN,
 280                 ARM_PLL_PHI1_DFS2_MFI},
 281                {ARM_PLL_PHI1_DFS3_EN, ARM_PLL_PHI1_DFS3_MFN,
 282                 ARM_PLL_PHI1_DFS3_MFI}
 283        };
 284
 285        unsigned int enet_dfs[ENET_PLL_PHI1_DFS_Nr][DFS_PARAMS_Nr] = {
 286                {ENET_PLL_PHI1_DFS1_EN, ENET_PLL_PHI1_DFS1_MFN,
 287                 ENET_PLL_PHI1_DFS1_MFI},
 288                {ENET_PLL_PHI1_DFS2_EN, ENET_PLL_PHI1_DFS2_MFN,
 289                 ENET_PLL_PHI1_DFS2_MFI},
 290                {ENET_PLL_PHI1_DFS3_EN, ENET_PLL_PHI1_DFS3_MFN,
 291                 ENET_PLL_PHI1_DFS3_MFI},
 292                {ENET_PLL_PHI1_DFS4_EN, ENET_PLL_PHI1_DFS4_MFN,
 293                 ENET_PLL_PHI1_DFS4_MFI}
 294        };
 295
 296        unsigned int ddr_dfs[DDR_PLL_PHI1_DFS_Nr][DFS_PARAMS_Nr] = {
 297                {DDR_PLL_PHI1_DFS1_EN, DDR_PLL_PHI1_DFS1_MFN,
 298                 DDR_PLL_PHI1_DFS1_MFI},
 299                {DDR_PLL_PHI1_DFS2_EN, DDR_PLL_PHI1_DFS2_MFN,
 300                 DDR_PLL_PHI1_DFS2_MFI},
 301                {DDR_PLL_PHI1_DFS3_EN, DDR_PLL_PHI1_DFS3_MFN,
 302                 DDR_PLL_PHI1_DFS3_MFI}
 303        };
 304
 305        writel(MC_ME_RUN_PCn_DRUN | MC_ME_RUN_PCn_RUN0 | MC_ME_RUN_PCn_RUN1 |
 306               MC_ME_RUN_PCn_RUN2 | MC_ME_RUN_PCn_RUN3, MC_ME_RUN_PCn(0));
 307
 308        /* turn on FXOSC */
 309        writel(MC_ME_RUNMODE_MC_MVRON | MC_ME_RUNMODE_MC_XOSCON |
 310               MC_ME_RUNMODE_MC_FIRCON | MC_ME_RUNMODE_MC_SYSCLK(0x1),
 311               MC_ME_RUNn_MC(0));
 312
 313        entry_to_target_mode(MC_ME_MCTL_RUN0);
 314
 315        program_pll(ARM_PLL, XOSC_CLK_FREQ, ARM_PLL_PHI0_FREQ,
 316                    ARM_PLL_PHI1_FREQ, ARM_PLL_PHI1_DFS_Nr, arm_dfs,
 317                    ARM_PLL_PLLDV_PREDIV, ARM_PLL_PLLDV_MFD, ARM_PLL_PLLDV_MFN);
 318
 319        setup_sys_clocks();
 320
 321        program_pll(PERIPH_PLL, XOSC_CLK_FREQ, PERIPH_PLL_PHI0_FREQ,
 322                    PERIPH_PLL_PHI1_FREQ, PERIPH_PLL_PHI1_DFS_Nr, NULL,
 323                    PERIPH_PLL_PLLDV_PREDIV, PERIPH_PLL_PLLDV_MFD,
 324                    PERIPH_PLL_PLLDV_MFN);
 325
 326        program_pll(ENET_PLL, XOSC_CLK_FREQ, ENET_PLL_PHI0_FREQ,
 327                    ENET_PLL_PHI1_FREQ, ENET_PLL_PHI1_DFS_Nr, enet_dfs,
 328                    ENET_PLL_PLLDV_PREDIV, ENET_PLL_PLLDV_MFD,
 329                    ENET_PLL_PLLDV_MFN);
 330
 331        program_pll(DDR_PLL, XOSC_CLK_FREQ, DDR_PLL_PHI0_FREQ,
 332                    DDR_PLL_PHI1_FREQ, DDR_PLL_PHI1_DFS_Nr, ddr_dfs,
 333                    DDR_PLL_PLLDV_PREDIV, DDR_PLL_PLLDV_MFD, DDR_PLL_PLLDV_MFN);
 334
 335        program_pll(VIDEO_PLL, XOSC_CLK_FREQ, VIDEO_PLL_PHI0_FREQ,
 336                    VIDEO_PLL_PHI1_FREQ, VIDEO_PLL_PHI1_DFS_Nr, NULL,
 337                    VIDEO_PLL_PLLDV_PREDIV, VIDEO_PLL_PLLDV_MFD,
 338                    VIDEO_PLL_PLLDV_MFN);
 339
 340        setup_aux_clocks();
 341
 342        enable_modules_clock();
 343
 344}
 345