Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * OMAP2xxx DVFS virtual clock functions
0004  *
0005  * Copyright (C) 2005-2008, 2012 Texas Instruments, Inc.
0006  * Copyright (C) 2004-2010 Nokia Corporation
0007  *
0008  * Contacts:
0009  * Richard Woodruff <r-woodruff2@ti.com>
0010  * Paul Walmsley
0011  *
0012  * Based on earlier work by Tuukka Tikkanen, Tony Lindgren,
0013  * Gordon McNutt and RidgeRun, Inc.
0014  *
0015  * XXX Some of this code should be replaceable by the upcoming OPP layer
0016  * code.  However, some notion of "rate set" is probably still necessary
0017  * for OMAP2xxx at least.  Rate sets should be generalized so they can be
0018  * used for any OMAP chip, not just OMAP2xxx.  In particular, Richard Woodruff
0019  * has in the past expressed a preference to use rate sets for OPP changes,
0020  * rather than dynamically recalculating the clock tree, so if someone wants
0021  * this badly enough to write the code to handle it, we should support it
0022  * as an option.
0023  */
0024 #undef DEBUG
0025 
0026 #include <linux/kernel.h>
0027 #include <linux/errno.h>
0028 #include <linux/clk.h>
0029 #include <linux/io.h>
0030 #include <linux/cpufreq.h>
0031 #include <linux/slab.h>
0032 
0033 #include "soc.h"
0034 #include "clock.h"
0035 #include "clock2xxx.h"
0036 #include "opp2xxx.h"
0037 #include "cm2xxx.h"
0038 #include "cm-regbits-24xx.h"
0039 #include "sdrc.h"
0040 #include "sram.h"
0041 
0042 const struct prcm_config *curr_prcm_set;
0043 const struct prcm_config *rate_table;
0044 
0045 /*
0046  * sys_ck_rate: the rate of the external high-frequency clock
0047  * oscillator on the board.  Set by the SoC-specific clock init code.
0048  * Once set during a boot, will not change.
0049  */
0050 static unsigned long sys_ck_rate;
0051 
0052 /**
0053  * omap2_table_mpu_recalc - just return the MPU speed
0054  * @clk: virt_prcm_set struct clk
0055  *
0056  * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set.
0057  */
0058 unsigned long omap2_table_mpu_recalc(struct clk_hw *clk,
0059                      unsigned long parent_rate)
0060 {
0061     return curr_prcm_set->mpu_speed;
0062 }
0063 
0064 /*
0065  * Look for a rate equal or less than the target rate given a configuration set.
0066  *
0067  * What's not entirely clear is "which" field represents the key field.
0068  * Some might argue L3-DDR, others ARM, others IVA. This code is simple and
0069  * just uses the ARM rates.
0070  */
0071 long omap2_round_to_table_rate(struct clk_hw *hw, unsigned long rate,
0072                    unsigned long *parent_rate)
0073 {
0074     const struct prcm_config *ptr;
0075     long highest_rate;
0076 
0077     highest_rate = -EINVAL;
0078 
0079     for (ptr = rate_table; ptr->mpu_speed; ptr++) {
0080         if (!(ptr->flags & cpu_mask))
0081             continue;
0082         if (ptr->xtal_speed != sys_ck_rate)
0083             continue;
0084 
0085         highest_rate = ptr->mpu_speed;
0086 
0087         /* Can check only after xtal frequency check */
0088         if (ptr->mpu_speed <= rate)
0089             break;
0090     }
0091     return highest_rate;
0092 }
0093 
0094 /* Sets basic clocks based on the specified rate */
0095 int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate,
0096                 unsigned long parent_rate)
0097 {
0098     u32 cur_rate, done_rate, bypass = 0;
0099     const struct prcm_config *prcm;
0100     unsigned long found_speed = 0;
0101     unsigned long flags;
0102 
0103     for (prcm = rate_table; prcm->mpu_speed; prcm++) {
0104         if (!(prcm->flags & cpu_mask))
0105             continue;
0106 
0107         if (prcm->xtal_speed != sys_ck_rate)
0108             continue;
0109 
0110         if (prcm->mpu_speed <= rate) {
0111             found_speed = prcm->mpu_speed;
0112             break;
0113         }
0114     }
0115 
0116     if (!found_speed) {
0117         printk(KERN_INFO "Could not set MPU rate to %luMHz\n",
0118                rate / 1000000);
0119         return -EINVAL;
0120     }
0121 
0122     curr_prcm_set = prcm;
0123     cur_rate = omap2xxx_clk_get_core_rate();
0124 
0125     if (prcm->dpll_speed == cur_rate / 2) {
0126         omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1);
0127     } else if (prcm->dpll_speed == cur_rate * 2) {
0128         omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0129     } else if (prcm->dpll_speed != cur_rate) {
0130         local_irq_save(flags);
0131 
0132         if (prcm->dpll_speed == prcm->xtal_speed)
0133             bypass = 1;
0134 
0135         if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) ==
0136             CORE_CLK_SRC_DPLL_X2)
0137             done_rate = CORE_CLK_SRC_DPLL_X2;
0138         else
0139             done_rate = CORE_CLK_SRC_DPLL;
0140 
0141         omap2xxx_cm_set_mod_dividers(prcm->cm_clksel_mpu,
0142                          prcm->cm_clksel_dsp,
0143                          prcm->cm_clksel_gfx,
0144                          prcm->cm_clksel1_core,
0145                          prcm->cm_clksel_mdm);
0146 
0147         /* x2 to enter omap2xxx_sdrc_init_params() */
0148         omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1);
0149 
0150         omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr,
0151                    bypass);
0152 
0153         omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked());
0154         omap2xxx_sdrc_reprogram(done_rate, 0);
0155 
0156         local_irq_restore(flags);
0157     }
0158 
0159     return 0;
0160 }
0161 
0162 /**
0163  * omap2xxx_clkt_vps_check_bootloader_rate - determine which of the rate
0164  * table sets matches the current CORE DPLL hardware rate
0165  *
0166  * Check the MPU rate set by bootloader.  Sets the 'curr_prcm_set'
0167  * global to point to the active rate set when found; otherwise, sets
0168  * it to NULL.  No return value;
0169  */
0170 void omap2xxx_clkt_vps_check_bootloader_rates(void)
0171 {
0172     const struct prcm_config *prcm = NULL;
0173     unsigned long rate;
0174 
0175     rate = omap2xxx_clk_get_core_rate();
0176     for (prcm = rate_table; prcm->mpu_speed; prcm++) {
0177         if (!(prcm->flags & cpu_mask))
0178             continue;
0179         if (prcm->xtal_speed != sys_ck_rate)
0180             continue;
0181         if (prcm->dpll_speed <= rate)
0182             break;
0183     }
0184     curr_prcm_set = prcm;
0185 }
0186 
0187 /**
0188  * omap2xxx_clkt_vps_late_init - store a copy of the sys_ck rate
0189  *
0190  * Store a copy of the sys_ck rate for later use by the OMAP2xxx DVFS
0191  * code.  (The sys_ck rate does not -- or rather, must not -- change
0192  * during kernel runtime.)  Must be called after we have a valid
0193  * sys_ck rate, but before the virt_prcm_set clock rate is
0194  * recalculated.  No return value.
0195  */
0196 void omap2xxx_clkt_vps_late_init(void)
0197 {
0198     struct clk *c;
0199 
0200     c = clk_get(NULL, "sys_ck");
0201     if (IS_ERR(c)) {
0202         WARN(1, "could not locate sys_ck\n");
0203     } else {
0204         sys_ck_rate = clk_get_rate(c);
0205         clk_put(c);
0206     }
0207 }
0208 
0209 #ifdef CONFIG_OF
0210 #include <linux/clk-provider.h>
0211 #include <linux/clkdev.h>
0212 
0213 static const struct clk_ops virt_prcm_set_ops = {
0214     .recalc_rate    = &omap2_table_mpu_recalc,
0215     .set_rate   = &omap2_select_table_rate,
0216     .round_rate = &omap2_round_to_table_rate,
0217 };
0218 
0219 /**
0220  * omap2xxx_clkt_vps_init - initialize virt_prcm_set clock
0221  *
0222  * Does a manual init for the virtual prcm DVFS clock for OMAP2. This
0223  * function is called only from omap2 DT clock init, as the virtual
0224  * node is not modelled in the DT clock data.
0225  */
0226 void omap2xxx_clkt_vps_init(void)
0227 {
0228     struct clk_init_data init = { NULL };
0229     struct clk_hw_omap *hw = NULL;
0230     struct clk *clk;
0231     const char *parent_name = "mpu_ck";
0232 
0233     omap2xxx_clkt_vps_late_init();
0234     omap2xxx_clkt_vps_check_bootloader_rates();
0235 
0236     hw = kzalloc(sizeof(*hw), GFP_KERNEL);
0237     if (!hw)
0238         return;
0239     init.name = "virt_prcm_set";
0240     init.ops = &virt_prcm_set_ops;
0241     init.parent_names = &parent_name;
0242     init.num_parents = 1;
0243 
0244     hw->hw.init = &init;
0245 
0246     clk = clk_register(NULL, &hw->hw);
0247     if (IS_ERR(clk)) {
0248         printk(KERN_ERR "Failed to register clock\n");
0249         kfree(hw);
0250         return;
0251     }
0252 
0253     clkdev_create(clk, "cpufreq_ck", NULL);
0254 }
0255 #endif