1734f69a7SPaul Walmsley /* 2734f69a7SPaul Walmsley * OMAP2xxx DVFS virtual clock functions 3734f69a7SPaul Walmsley * 4baa689b8SPaul Walmsley * Copyright (C) 2005-2008, 2012 Texas Instruments, Inc. 5734f69a7SPaul Walmsley * Copyright (C) 2004-2010 Nokia Corporation 6734f69a7SPaul Walmsley * 7734f69a7SPaul Walmsley * Contacts: 8734f69a7SPaul Walmsley * Richard Woodruff <r-woodruff2@ti.com> 9734f69a7SPaul Walmsley * Paul Walmsley 10734f69a7SPaul Walmsley * 11734f69a7SPaul Walmsley * Based on earlier work by Tuukka Tikkanen, Tony Lindgren, 12734f69a7SPaul Walmsley * Gordon McNutt and RidgeRun, Inc. 13734f69a7SPaul Walmsley * 14734f69a7SPaul Walmsley * This program is free software; you can redistribute it and/or modify 15734f69a7SPaul Walmsley * it under the terms of the GNU General Public License version 2 as 16734f69a7SPaul Walmsley * published by the Free Software Foundation. 17734f69a7SPaul Walmsley * 18734f69a7SPaul Walmsley * XXX Some of this code should be replaceable by the upcoming OPP layer 19734f69a7SPaul Walmsley * code. However, some notion of "rate set" is probably still necessary 20734f69a7SPaul Walmsley * for OMAP2xxx at least. Rate sets should be generalized so they can be 21734f69a7SPaul Walmsley * used for any OMAP chip, not just OMAP2xxx. In particular, Richard Woodruff 22734f69a7SPaul Walmsley * has in the past expressed a preference to use rate sets for OPP changes, 23734f69a7SPaul Walmsley * rather than dynamically recalculating the clock tree, so if someone wants 24734f69a7SPaul Walmsley * this badly enough to write the code to handle it, we should support it 25734f69a7SPaul Walmsley * as an option. 26734f69a7SPaul Walmsley */ 27734f69a7SPaul Walmsley #undef DEBUG 28734f69a7SPaul Walmsley 29734f69a7SPaul Walmsley #include <linux/kernel.h> 30734f69a7SPaul Walmsley #include <linux/errno.h> 31734f69a7SPaul Walmsley #include <linux/clk.h> 32734f69a7SPaul Walmsley #include <linux/io.h> 33734f69a7SPaul Walmsley #include <linux/cpufreq.h> 345a0e3ad6STejun Heo #include <linux/slab.h> 35734f69a7SPaul Walmsley 36dbc04161STony Lindgren #include "soc.h" 37734f69a7SPaul Walmsley #include "clock.h" 38734f69a7SPaul Walmsley #include "clock2xxx.h" 39734f69a7SPaul Walmsley #include "opp2xxx.h" 40d9a16f9aSPaul Walmsley #include "cm2xxx.h" 41734f69a7SPaul Walmsley #include "cm-regbits-24xx.h" 423e6ece13SPaul Walmsley #include "sdrc.h" 43bf027ca1STony Lindgren #include "sram.h" 44734f69a7SPaul Walmsley 45734f69a7SPaul Walmsley const struct prcm_config *curr_prcm_set; 46734f69a7SPaul Walmsley const struct prcm_config *rate_table; 47734f69a7SPaul Walmsley 48baa689b8SPaul Walmsley /* 49baa689b8SPaul Walmsley * sys_ck_rate: the rate of the external high-frequency clock 50baa689b8SPaul Walmsley * oscillator on the board. Set by the SoC-specific clock init code. 51baa689b8SPaul Walmsley * Once set during a boot, will not change. 52baa689b8SPaul Walmsley */ 53baa689b8SPaul Walmsley static unsigned long sys_ck_rate; 54baa689b8SPaul Walmsley 55734f69a7SPaul Walmsley /** 56734f69a7SPaul Walmsley * omap2_table_mpu_recalc - just return the MPU speed 57734f69a7SPaul Walmsley * @clk: virt_prcm_set struct clk 58734f69a7SPaul Walmsley * 59734f69a7SPaul Walmsley * Set virt_prcm_set's rate to the mpu_speed field of the current PRCM set. 60734f69a7SPaul Walmsley */ 61ed1ebc49SRajendra Nayak unsigned long omap2_table_mpu_recalc(struct clk_hw *clk, 62ed1ebc49SRajendra Nayak unsigned long parent_rate) 63734f69a7SPaul Walmsley { 64734f69a7SPaul Walmsley return curr_prcm_set->mpu_speed; 65734f69a7SPaul Walmsley } 66734f69a7SPaul Walmsley 67734f69a7SPaul Walmsley /* 68734f69a7SPaul Walmsley * Look for a rate equal or less than the target rate given a configuration set. 69734f69a7SPaul Walmsley * 70734f69a7SPaul Walmsley * What's not entirely clear is "which" field represents the key field. 71734f69a7SPaul Walmsley * Some might argue L3-DDR, others ARM, others IVA. This code is simple and 72734f69a7SPaul Walmsley * just uses the ARM rates. 73734f69a7SPaul Walmsley */ 74ed1ebc49SRajendra Nayak long omap2_round_to_table_rate(struct clk_hw *hw, unsigned long rate, 75ed1ebc49SRajendra Nayak unsigned long *parent_rate) 76734f69a7SPaul Walmsley { 77734f69a7SPaul Walmsley const struct prcm_config *ptr; 78baa689b8SPaul Walmsley long highest_rate; 79734f69a7SPaul Walmsley 80734f69a7SPaul Walmsley highest_rate = -EINVAL; 81734f69a7SPaul Walmsley 82734f69a7SPaul Walmsley for (ptr = rate_table; ptr->mpu_speed; ptr++) { 83734f69a7SPaul Walmsley if (!(ptr->flags & cpu_mask)) 84734f69a7SPaul Walmsley continue; 85baa689b8SPaul Walmsley if (ptr->xtal_speed != sys_ck_rate) 86734f69a7SPaul Walmsley continue; 87734f69a7SPaul Walmsley 88734f69a7SPaul Walmsley highest_rate = ptr->mpu_speed; 89734f69a7SPaul Walmsley 90734f69a7SPaul Walmsley /* Can check only after xtal frequency check */ 91734f69a7SPaul Walmsley if (ptr->mpu_speed <= rate) 92734f69a7SPaul Walmsley break; 93734f69a7SPaul Walmsley } 94734f69a7SPaul Walmsley return highest_rate; 95734f69a7SPaul Walmsley } 96734f69a7SPaul Walmsley 97734f69a7SPaul Walmsley /* Sets basic clocks based on the specified rate */ 98ed1ebc49SRajendra Nayak int omap2_select_table_rate(struct clk_hw *hw, unsigned long rate, 99ed1ebc49SRajendra Nayak unsigned long parent_rate) 100734f69a7SPaul Walmsley { 101*cd6e9db2STero Kristo u32 cur_rate, done_rate, bypass = 0; 102734f69a7SPaul Walmsley const struct prcm_config *prcm; 103734f69a7SPaul Walmsley unsigned long found_speed = 0; 104734f69a7SPaul Walmsley unsigned long flags; 105734f69a7SPaul Walmsley 106734f69a7SPaul Walmsley for (prcm = rate_table; prcm->mpu_speed; prcm++) { 107734f69a7SPaul Walmsley if (!(prcm->flags & cpu_mask)) 108734f69a7SPaul Walmsley continue; 109734f69a7SPaul Walmsley 110baa689b8SPaul Walmsley if (prcm->xtal_speed != sys_ck_rate) 111734f69a7SPaul Walmsley continue; 112734f69a7SPaul Walmsley 113734f69a7SPaul Walmsley if (prcm->mpu_speed <= rate) { 114734f69a7SPaul Walmsley found_speed = prcm->mpu_speed; 115734f69a7SPaul Walmsley break; 116734f69a7SPaul Walmsley } 117734f69a7SPaul Walmsley } 118734f69a7SPaul Walmsley 119734f69a7SPaul Walmsley if (!found_speed) { 120734f69a7SPaul Walmsley printk(KERN_INFO "Could not set MPU rate to %luMHz\n", 121734f69a7SPaul Walmsley rate / 1000000); 122734f69a7SPaul Walmsley return -EINVAL; 123734f69a7SPaul Walmsley } 124734f69a7SPaul Walmsley 125734f69a7SPaul Walmsley curr_prcm_set = prcm; 1265f039377SPaul Walmsley cur_rate = omap2xxx_clk_get_core_rate(); 127734f69a7SPaul Walmsley 128734f69a7SPaul Walmsley if (prcm->dpll_speed == cur_rate / 2) { 129734f69a7SPaul Walmsley omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL, 1); 130734f69a7SPaul Walmsley } else if (prcm->dpll_speed == cur_rate * 2) { 131734f69a7SPaul Walmsley omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); 132734f69a7SPaul Walmsley } else if (prcm->dpll_speed != cur_rate) { 133734f69a7SPaul Walmsley local_irq_save(flags); 134734f69a7SPaul Walmsley 135734f69a7SPaul Walmsley if (prcm->dpll_speed == prcm->xtal_speed) 136734f69a7SPaul Walmsley bypass = 1; 137734f69a7SPaul Walmsley 138734f69a7SPaul Walmsley if ((prcm->cm_clksel2_pll & OMAP24XX_CORE_CLK_SRC_MASK) == 139734f69a7SPaul Walmsley CORE_CLK_SRC_DPLL_X2) 140734f69a7SPaul Walmsley done_rate = CORE_CLK_SRC_DPLL_X2; 141734f69a7SPaul Walmsley else 142734f69a7SPaul Walmsley done_rate = CORE_CLK_SRC_DPLL; 143734f69a7SPaul Walmsley 144*cd6e9db2STero Kristo omap2xxx_cm_set_mod_dividers(prcm->cm_clksel_mpu, 145*cd6e9db2STero Kristo prcm->cm_clksel_dsp, 146*cd6e9db2STero Kristo prcm->cm_clksel_gfx, 147*cd6e9db2STero Kristo prcm->cm_clksel1_core, 148*cd6e9db2STero Kristo prcm->cm_clksel_mdm); 149734f69a7SPaul Walmsley 150734f69a7SPaul Walmsley /* x2 to enter omap2xxx_sdrc_init_params() */ 151734f69a7SPaul Walmsley omap2xxx_sdrc_reprogram(CORE_CLK_SRC_DPLL_X2, 1); 152734f69a7SPaul Walmsley 153734f69a7SPaul Walmsley omap2_set_prcm(prcm->cm_clksel1_pll, prcm->base_sdrc_rfr, 154734f69a7SPaul Walmsley bypass); 155734f69a7SPaul Walmsley 156734f69a7SPaul Walmsley omap2xxx_sdrc_init_params(omap2xxx_sdrc_dll_is_unlocked()); 157734f69a7SPaul Walmsley omap2xxx_sdrc_reprogram(done_rate, 0); 158734f69a7SPaul Walmsley 159734f69a7SPaul Walmsley local_irq_restore(flags); 160734f69a7SPaul Walmsley } 161734f69a7SPaul Walmsley 162734f69a7SPaul Walmsley return 0; 163734f69a7SPaul Walmsley } 164baa689b8SPaul Walmsley 165baa689b8SPaul Walmsley /** 166baa689b8SPaul Walmsley * omap2xxx_clkt_vps_check_bootloader_rate - determine which of the rate 167baa689b8SPaul Walmsley * table sets matches the current CORE DPLL hardware rate 168baa689b8SPaul Walmsley * 169baa689b8SPaul Walmsley * Check the MPU rate set by bootloader. Sets the 'curr_prcm_set' 170baa689b8SPaul Walmsley * global to point to the active rate set when found; otherwise, sets 171baa689b8SPaul Walmsley * it to NULL. No return value; 172baa689b8SPaul Walmsley */ 173baa689b8SPaul Walmsley void omap2xxx_clkt_vps_check_bootloader_rates(void) 174baa689b8SPaul Walmsley { 175baa689b8SPaul Walmsley const struct prcm_config *prcm = NULL; 176baa689b8SPaul Walmsley unsigned long rate; 177baa689b8SPaul Walmsley 178baa689b8SPaul Walmsley rate = omap2xxx_clk_get_core_rate(); 179baa689b8SPaul Walmsley for (prcm = rate_table; prcm->mpu_speed; prcm++) { 180baa689b8SPaul Walmsley if (!(prcm->flags & cpu_mask)) 181baa689b8SPaul Walmsley continue; 182baa689b8SPaul Walmsley if (prcm->xtal_speed != sys_ck_rate) 183baa689b8SPaul Walmsley continue; 184baa689b8SPaul Walmsley if (prcm->dpll_speed <= rate) 185baa689b8SPaul Walmsley break; 186baa689b8SPaul Walmsley } 187baa689b8SPaul Walmsley curr_prcm_set = prcm; 188baa689b8SPaul Walmsley } 189baa689b8SPaul Walmsley 190baa689b8SPaul Walmsley /** 191baa689b8SPaul Walmsley * omap2xxx_clkt_vps_late_init - store a copy of the sys_ck rate 192baa689b8SPaul Walmsley * 193baa689b8SPaul Walmsley * Store a copy of the sys_ck rate for later use by the OMAP2xxx DVFS 194baa689b8SPaul Walmsley * code. (The sys_ck rate does not -- or rather, must not -- change 195baa689b8SPaul Walmsley * during kernel runtime.) Must be called after we have a valid 196baa689b8SPaul Walmsley * sys_ck rate, but before the virt_prcm_set clock rate is 197baa689b8SPaul Walmsley * recalculated. No return value. 198baa689b8SPaul Walmsley */ 199baa689b8SPaul Walmsley void omap2xxx_clkt_vps_late_init(void) 200baa689b8SPaul Walmsley { 201baa689b8SPaul Walmsley struct clk *c; 202baa689b8SPaul Walmsley 203baa689b8SPaul Walmsley c = clk_get(NULL, "sys_ck"); 204baa689b8SPaul Walmsley if (IS_ERR(c)) { 205baa689b8SPaul Walmsley WARN(1, "could not locate sys_ck\n"); 206baa689b8SPaul Walmsley } else { 207baa689b8SPaul Walmsley sys_ck_rate = clk_get_rate(c); 208baa689b8SPaul Walmsley clk_put(c); 209baa689b8SPaul Walmsley } 210baa689b8SPaul Walmsley } 211