uboot/arch/arm/mach-omap2/am33xx/clock.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * clock.c
   4 *
   5 * Clock initialization for AM33XX boards.
   6 * Derived from OMAP4 boards
   7 *
   8 * Copyright (C) 2013, Texas Instruments, Incorporated - http://www.ti.com/
   9 */
  10#include <common.h>
  11#include <hang.h>
  12#include <init.h>
  13#include <log.h>
  14#include <asm/arch/cpu.h>
  15#include <asm/arch/clock.h>
  16#include <asm/arch/hardware.h>
  17#include <asm/arch/sys_proto.h>
  18#include <asm/io.h>
  19
  20static void setup_post_dividers(const struct dpll_regs *dpll_regs,
  21                         const struct dpll_params *params)
  22{
  23        /* Setup post-dividers */
  24        if (params->m2 >= 0)
  25                writel(params->m2, dpll_regs->cm_div_m2_dpll);
  26        if (params->m3 >= 0)
  27                writel(params->m3, dpll_regs->cm_div_m3_dpll);
  28        if (params->m4 >= 0)
  29                writel(params->m4, dpll_regs->cm_div_m4_dpll);
  30        if (params->m5 >= 0)
  31                writel(params->m5, dpll_regs->cm_div_m5_dpll);
  32        if (params->m6 >= 0)
  33                writel(params->m6, dpll_regs->cm_div_m6_dpll);
  34}
  35
  36static inline void do_lock_dpll(const struct dpll_regs *dpll_regs)
  37{
  38        clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
  39                        CM_CLKMODE_DPLL_DPLL_EN_MASK,
  40                        DPLL_EN_LOCK << CM_CLKMODE_DPLL_EN_SHIFT);
  41}
  42
  43static inline void wait_for_lock(const struct dpll_regs *dpll_regs)
  44{
  45        if (!wait_on_value(ST_DPLL_CLK_MASK, ST_DPLL_CLK_MASK,
  46                           (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
  47                printf("DPLL locking failed for 0x%x\n",
  48                       dpll_regs->cm_clkmode_dpll);
  49                hang();
  50        }
  51}
  52
  53static inline void do_bypass_dpll(const struct dpll_regs *dpll_regs)
  54{
  55        clrsetbits_le32(dpll_regs->cm_clkmode_dpll,
  56                        CM_CLKMODE_DPLL_DPLL_EN_MASK,
  57                        DPLL_EN_MN_BYPASS << CM_CLKMODE_DPLL_EN_SHIFT);
  58}
  59
  60static inline void wait_for_bypass(const struct dpll_regs *dpll_regs)
  61{
  62        if (!wait_on_value(ST_DPLL_CLK_MASK, 0,
  63                           (void *)dpll_regs->cm_idlest_dpll, LDELAY)) {
  64                printf("Bypassing DPLL failed 0x%x\n",
  65                       dpll_regs->cm_clkmode_dpll);
  66        }
  67}
  68
  69static void bypass_dpll(const struct dpll_regs *dpll_regs)
  70{
  71        do_bypass_dpll(dpll_regs);
  72        wait_for_bypass(dpll_regs);
  73}
  74
  75void do_setup_dpll(const struct dpll_regs *dpll_regs,
  76                   const struct dpll_params *params)
  77{
  78        u32 temp;
  79
  80        if (!params)
  81                return;
  82
  83        temp = readl(dpll_regs->cm_clksel_dpll);
  84
  85        bypass_dpll(dpll_regs);
  86
  87        /* Set M & N */
  88        temp &= ~CM_CLKSEL_DPLL_M_MASK;
  89        temp |= (params->m << CM_CLKSEL_DPLL_M_SHIFT) & CM_CLKSEL_DPLL_M_MASK;
  90
  91        temp &= ~CM_CLKSEL_DPLL_N_MASK;
  92        temp |= (params->n << CM_CLKSEL_DPLL_N_SHIFT) & CM_CLKSEL_DPLL_N_MASK;
  93
  94        writel(temp, dpll_regs->cm_clksel_dpll);
  95
  96        setup_post_dividers(dpll_regs, params);
  97
  98        /* Wait till the DPLL locks */
  99        do_lock_dpll(dpll_regs);
 100        wait_for_lock(dpll_regs);
 101}
 102
 103static void setup_dplls(void)
 104{
 105        const struct dpll_params *params;
 106
 107        params = get_dpll_core_params();
 108        do_setup_dpll(&dpll_core_regs, params);
 109
 110        params = get_dpll_mpu_params();
 111        do_setup_dpll(&dpll_mpu_regs, params);
 112
 113        params = get_dpll_per_params();
 114        do_setup_dpll(&dpll_per_regs, params);
 115        writel(0x300, &cmwkup->clkdcoldodpllper);
 116
 117        params = get_dpll_ddr_params();
 118        do_setup_dpll(&dpll_ddr_regs, params);
 119}
 120
 121static inline void wait_for_clk_enable(u32 *clkctrl_addr)
 122{
 123        u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_DISABLED;
 124        u32 bound = LDELAY;
 125
 126        while ((idlest == MODULE_CLKCTRL_IDLEST_DISABLED) ||
 127                (idlest == MODULE_CLKCTRL_IDLEST_TRANSITIONING)) {
 128                clkctrl = readl(clkctrl_addr);
 129                idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
 130                         MODULE_CLKCTRL_IDLEST_SHIFT;
 131                if (--bound == 0) {
 132                        printf("Clock enable failed for 0x%p idlest 0x%x\n",
 133                               clkctrl_addr, clkctrl);
 134                        return;
 135                }
 136        }
 137}
 138
 139static inline void enable_clock_module(u32 *const clkctrl_addr, u32 enable_mode,
 140                                       u32 wait_for_enable)
 141{
 142        clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
 143                        enable_mode << MODULE_CLKCTRL_MODULEMODE_SHIFT);
 144        debug("Enable clock module - %p\n", clkctrl_addr);
 145        if (wait_for_enable)
 146                wait_for_clk_enable(clkctrl_addr);
 147}
 148
 149static inline void wait_for_clk_disable(u32 *clkctrl_addr)
 150{
 151        u32 clkctrl, idlest = MODULE_CLKCTRL_IDLEST_FULLY_FUNCTIONAL;
 152        u32 bound = LDELAY;
 153
 154        while ((idlest != MODULE_CLKCTRL_IDLEST_DISABLED)) {
 155                clkctrl = readl(clkctrl_addr);
 156                idlest = (clkctrl & MODULE_CLKCTRL_IDLEST_MASK) >>
 157                          MODULE_CLKCTRL_IDLEST_SHIFT;
 158                if (--bound == 0) {
 159                        printf("Clock disable failed for 0x%p idlest 0x%x\n",
 160                               clkctrl_addr, clkctrl);
 161                         return;
 162                }
 163        }
 164}
 165static inline void disable_clock_module(u32 *const clkctrl_addr,
 166                                        u32 wait_for_disable)
 167{
 168        clrsetbits_le32(clkctrl_addr, MODULE_CLKCTRL_MODULEMODE_MASK,
 169                        MODULE_CLKCTRL_MODULEMODE_SW_DISABLE <<
 170                        MODULE_CLKCTRL_MODULEMODE_SHIFT);
 171        debug("Disable clock module - %p\n", clkctrl_addr);
 172        if (wait_for_disable)
 173                wait_for_clk_disable(clkctrl_addr);
 174}
 175
 176static inline void enable_clock_domain(u32 *const clkctrl_reg, u32 enable_mode)
 177{
 178        clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
 179                        enable_mode << CD_CLKCTRL_CLKTRCTRL_SHIFT);
 180        debug("Enable clock domain - %p\n", clkctrl_reg);
 181}
 182
 183static inline void disable_clock_domain(u32 *const clkctrl_reg)
 184{
 185        clrsetbits_le32(clkctrl_reg, CD_CLKCTRL_CLKTRCTRL_MASK,
 186                        CD_CLKCTRL_CLKTRCTRL_SW_SLEEP <<
 187                        CD_CLKCTRL_CLKTRCTRL_SHIFT);
 188        debug("Disable clock domain - %p\n", clkctrl_reg);
 189}
 190
 191void do_enable_clocks(u32 *const *clk_domains,
 192                      u32 *const *clk_modules_explicit_en, u8 wait_for_enable)
 193{
 194        u32 i, max = 100;
 195
 196        /* Put the clock domains in SW_WKUP mode */
 197        for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++) {
 198                enable_clock_domain(clk_domains[i],
 199                                    CD_CLKCTRL_CLKTRCTRL_SW_WKUP);
 200        }
 201
 202        /* Clock modules that need to be put in SW_EXPLICIT_EN mode */
 203        for (i = 0; (i < max) && clk_modules_explicit_en &&
 204             clk_modules_explicit_en[i]; i++) {
 205                enable_clock_module(clk_modules_explicit_en[i],
 206                                    MODULE_CLKCTRL_MODULEMODE_SW_EXPLICIT_EN,
 207                                    wait_for_enable);
 208        };
 209}
 210
 211void do_disable_clocks(u32 *const *clk_domains,
 212                        u32 *const *clk_modules_disable,
 213                        u8 wait_for_disable)
 214{
 215        u32 i, max = 100;
 216
 217
 218        /* Clock modules that need to be put in SW_DISABLE */
 219        for (i = 0; (i < max) && clk_modules_disable && clk_modules_disable[i];
 220             i++)
 221                disable_clock_module(clk_modules_disable[i],
 222                                     wait_for_disable);
 223
 224        /* Put the clock domains in SW_SLEEP mode */
 225        for (i = 0; (i < max) && clk_domains && clk_domains[i]; i++)
 226                disable_clock_domain(clk_domains[i]);
 227}
 228
 229/*
 230 * Before scaling up the clocks we need to have the PMIC scale up the
 231 * voltages first.  This will be dependent on which PMIC is in use
 232 * and in some cases we may not be scaling things up at all and thus not
 233 * need to do anything here.
 234 */
 235__weak void scale_vcores(void)
 236{
 237}
 238
 239void setup_early_clocks(void)
 240{
 241        setup_clocks_for_console();
 242        enable_basic_clocks();
 243        timer_init();
 244}
 245
 246void prcm_init(void)
 247{
 248        scale_vcores();
 249        setup_dplls();
 250}
 251
 252void rtc_only_prcm_init(void)
 253{
 254        const struct dpll_params *params;
 255
 256        rtc_only_enable_basic_clocks();
 257
 258        params = get_dpll_ddr_params();
 259        do_setup_dpll(&dpll_ddr_regs, params);
 260}
 261