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