···11+NVIDIA Tegra124 DFLL FCPU clocksource22+33+This binding uses the common clock binding:44+Documentation/devicetree/bindings/clock/clock-bindings.txt55+66+The DFLL IP block on Tegra is a root clocksource designed for clocking77+the fast CPU cluster. It consists of a free-running voltage controlled88+oscillator connected to the CPU voltage rail (VDD_CPU), and a closed loop99+control module that will automatically adjust the VDD_CPU voltage by1010+communicating with an off-chip PMIC either via an I2C bus or via PWM signals.1111+Currently only the I2C mode is supported by these bindings.1212+1313+Required properties:1414+- compatible : should be "nvidia,tegra124-dfll"1515+- reg : Defines the following set of registers, in the order listed:1616+ - registers for the DFLL control logic.1717+ - registers for the I2C output logic.1818+ - registers for the integrated I2C master controller.1919+ - look-up table RAM for voltage register values.2020+- interrupts: Should contain the DFLL block interrupt.2121+- clocks: Must contain an entry for each entry in clock-names.2222+ See clock-bindings.txt for details.2323+- clock-names: Must include the following entries:2424+ - soc: Clock source for the DFLL control logic.2525+ - ref: The closed loop reference clock2626+ - i2c: Clock source for the integrated I2C master.2727+- resets: Must contain an entry for each entry in reset-names.2828+ See ../reset/reset.txt for details.2929+- reset-names: Must include the following entries:3030+ - dvco: Reset control for the DFLL DVCO.3131+- #clock-cells: Must be 0.3232+- clock-output-names: Name of the clock output.3333+- vdd-cpu-supply: Regulator for the CPU voltage rail that the DFLL3434+ hardware will start controlling. The regulator will be queried for3535+ the I2C register, control values and supported voltages.3636+3737+Required properties for the control loop parameters:3838+- nvidia,sample-rate: Sample rate of the DFLL control loop.3939+- nvidia,droop-ctrl: See the register CL_DVFS_DROOP_CTRL in the TRM.4040+- nvidia,force-mode: See the field DFLL_PARAMS_FORCE_MODE in the TRM.4141+- nvidia,cf: Numeric value, see the field DFLL_PARAMS_CF_PARAM in the TRM.4242+- nvidia,ci: Numeric value, see the field DFLL_PARAMS_CI_PARAM in the TRM.4343+- nvidia,cg: Numeric value, see the field DFLL_PARAMS_CG_PARAM in the TRM.4444+4545+Optional properties for the control loop parameters:4646+- nvidia,cg-scale: Boolean value, see the field DFLL_PARAMS_CG_SCALE in the TRM.4747+4848+Required properties for I2C mode:4949+- nvidia,i2c-fs-rate: I2C transfer rate, if using full speed mode.5050+5151+Example:5252+5353+clock@0,70110000 {5454+ compatible = "nvidia,tegra124-dfll";5555+ reg = <0 0x70110000 0 0x100>, /* DFLL control */5656+ <0 0x70110000 0 0x100>, /* I2C output control */5757+ <0 0x70110100 0 0x100>, /* Integrated I2C controller */5858+ <0 0x70110200 0 0x100>; /* Look-up table RAM */5959+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;6060+ clocks = <&tegra_car TEGRA124_CLK_DFLL_SOC>,6161+ <&tegra_car TEGRA124_CLK_DFLL_REF>,6262+ <&tegra_car TEGRA124_CLK_I2C5>;6363+ clock-names = "soc", "ref", "i2c";6464+ resets = <&tegra_car TEGRA124_RST_DFLL_DVCO>;6565+ reset-names = "dvco";6666+ #clock-cells = <0>;6767+ clock-output-names = "dfllCPU_out";6868+ vdd-cpu-supply = <&vdd_cpu>;6969+ status = "okay";7070+7171+ nvidia,sample-rate = <12500>;7272+ nvidia,droop-ctrl = <0x00000f00>;7373+ nvidia,force-mode = <1>;7474+ nvidia,cf = <10>;7575+ nvidia,ci = <0>;7676+ nvidia,cg = <2>;7777+7878+ nvidia,i2c-fs-rate = <400000>;7979+};
+1
arch/arm/mach-tegra/Kconfig
···88 select HAVE_ARM_SCU if SMP99 select HAVE_ARM_TWD if SMP1010 select PINCTRL1111+ select PM_OPP1112 select ARCH_HAS_RESET_CONTROLLER1213 select RESET_CONTROLLER1314 select SOC_BUS
···11+/*22+ * clk-dfll.c - Tegra DFLL clock source common code33+ *44+ * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.55+ *66+ * Aleksandr Frid <afrid@nvidia.com>77+ * Paul Walmsley <pwalmsley@nvidia.com>88+ *99+ * This program is free software; you can redistribute it and/or modify1010+ * it under the terms of the GNU General Public License version 2 as1111+ * published by the Free Software Foundation.1212+ *1313+ * This program is distributed in the hope that it will be useful, but WITHOUT1414+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1515+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1616+ * more details.1717+ *1818+ * This library is for the DVCO and DFLL IP blocks on the Tegra1241919+ * SoC. These IP blocks together are also known at NVIDIA as2020+ * "CL-DVFS". To try to avoid confusion, this code refers to them2121+ * collectively as the "DFLL."2222+ *2323+ * The DFLL is a root clocksource which tolerates some amount of2424+ * supply voltage noise. Tegra124 uses it to clock the fast CPU2525+ * complex when the target CPU speed is above a particular rate. The2626+ * DFLL can be operated in either open-loop mode or closed-loop mode.2727+ * In open-loop mode, the DFLL generates an output clock appropriate2828+ * to the supply voltage. In closed-loop mode, when configured with a2929+ * target frequency, the DFLL minimizes supply voltage while3030+ * delivering an average frequency equal to the target.3131+ *3232+ * Devices clocked by the DFLL must be able to tolerate frequency3333+ * variation. In the case of the CPU, it's important to note that the3434+ * CPU cycle time will vary. This has implications for3535+ * performance-measurement code and any code that relies on the CPU3636+ * cycle time to delay for a certain length of time.3737+ *3838+ */3939+4040+#include <linux/clk.h>4141+#include <linux/clk-provider.h>4242+#include <linux/debugfs.h>4343+#include <linux/device.h>4444+#include <linux/err.h>4545+#include <linux/i2c.h>4646+#include <linux/io.h>4747+#include <linux/kernel.h>4848+#include <linux/module.h>4949+#include <linux/of.h>5050+#include <linux/pm_opp.h>5151+#include <linux/pm_runtime.h>5252+#include <linux/regmap.h>5353+#include <linux/regulator/consumer.h>5454+#include <linux/reset.h>5555+#include <linux/seq_file.h>5656+5757+#include "clk-dfll.h"5858+5959+/*6060+ * DFLL control registers - access via dfll_{readl,writel}6161+ */6262+6363+/* DFLL_CTRL: DFLL control register */6464+#define DFLL_CTRL 0x006565+#define DFLL_CTRL_MODE_MASK 0x036666+6767+/* DFLL_CONFIG: DFLL sample rate control */6868+#define DFLL_CONFIG 0x046969+#define DFLL_CONFIG_DIV_MASK 0xff7070+#define DFLL_CONFIG_DIV_PRESCALE 327171+7272+/* DFLL_PARAMS: tuning coefficients for closed loop integrator */7373+#define DFLL_PARAMS 0x087474+#define DFLL_PARAMS_CG_SCALE (0x1 << 24)7575+#define DFLL_PARAMS_FORCE_MODE_SHIFT 227676+#define DFLL_PARAMS_FORCE_MODE_MASK (0x3 << DFLL_PARAMS_FORCE_MODE_SHIFT)7777+#define DFLL_PARAMS_CF_PARAM_SHIFT 167878+#define DFLL_PARAMS_CF_PARAM_MASK (0x3f << DFLL_PARAMS_CF_PARAM_SHIFT)7979+#define DFLL_PARAMS_CI_PARAM_SHIFT 88080+#define DFLL_PARAMS_CI_PARAM_MASK (0x7 << DFLL_PARAMS_CI_PARAM_SHIFT)8181+#define DFLL_PARAMS_CG_PARAM_SHIFT 08282+#define DFLL_PARAMS_CG_PARAM_MASK (0xff << DFLL_PARAMS_CG_PARAM_SHIFT)8383+8484+/* DFLL_TUNE0: delay line configuration register 0 */8585+#define DFLL_TUNE0 0x0c8686+8787+/* DFLL_TUNE1: delay line configuration register 1 */8888+#define DFLL_TUNE1 0x108989+9090+/* DFLL_FREQ_REQ: target DFLL frequency control */9191+#define DFLL_FREQ_REQ 0x149292+#define DFLL_FREQ_REQ_FORCE_ENABLE (0x1 << 28)9393+#define DFLL_FREQ_REQ_FORCE_SHIFT 169494+#define DFLL_FREQ_REQ_FORCE_MASK (0xfff << DFLL_FREQ_REQ_FORCE_SHIFT)9595+#define FORCE_MAX 20479696+#define FORCE_MIN -20489797+#define DFLL_FREQ_REQ_SCALE_SHIFT 89898+#define DFLL_FREQ_REQ_SCALE_MASK (0xff << DFLL_FREQ_REQ_SCALE_SHIFT)9999+#define DFLL_FREQ_REQ_SCALE_MAX 256100100+#define DFLL_FREQ_REQ_FREQ_VALID (0x1 << 7)101101+#define DFLL_FREQ_REQ_MULT_SHIFT 0102102+#define DFLL_FREQ_REG_MULT_MASK (0x7f << DFLL_FREQ_REQ_MULT_SHIFT)103103+#define FREQ_MAX 127104104+105105+/* DFLL_DROOP_CTRL: droop prevention control */106106+#define DFLL_DROOP_CTRL 0x1c107107+108108+/* DFLL_OUTPUT_CFG: closed loop mode control registers */109109+/* NOTE: access via dfll_i2c_{readl,writel} */110110+#define DFLL_OUTPUT_CFG 0x20111111+#define DFLL_OUTPUT_CFG_I2C_ENABLE (0x1 << 30)112112+#define OUT_MASK 0x3f113113+#define DFLL_OUTPUT_CFG_SAFE_SHIFT 24114114+#define DFLL_OUTPUT_CFG_SAFE_MASK \115115+ (OUT_MASK << DFLL_OUTPUT_CFG_SAFE_SHIFT)116116+#define DFLL_OUTPUT_CFG_MAX_SHIFT 16117117+#define DFLL_OUTPUT_CFG_MAX_MASK \118118+ (OUT_MASK << DFLL_OUTPUT_CFG_MAX_SHIFT)119119+#define DFLL_OUTPUT_CFG_MIN_SHIFT 8120120+#define DFLL_OUTPUT_CFG_MIN_MASK \121121+ (OUT_MASK << DFLL_OUTPUT_CFG_MIN_SHIFT)122122+#define DFLL_OUTPUT_CFG_PWM_DELTA (0x1 << 7)123123+#define DFLL_OUTPUT_CFG_PWM_ENABLE (0x1 << 6)124124+#define DFLL_OUTPUT_CFG_PWM_DIV_SHIFT 0125125+#define DFLL_OUTPUT_CFG_PWM_DIV_MASK \126126+ (OUT_MASK << DFLL_OUTPUT_CFG_PWM_DIV_SHIFT)127127+128128+/* DFLL_OUTPUT_FORCE: closed loop mode voltage forcing control */129129+#define DFLL_OUTPUT_FORCE 0x24130130+#define DFLL_OUTPUT_FORCE_ENABLE (0x1 << 6)131131+#define DFLL_OUTPUT_FORCE_VALUE_SHIFT 0132132+#define DFLL_OUTPUT_FORCE_VALUE_MASK \133133+ (OUT_MASK << DFLL_OUTPUT_FORCE_VALUE_SHIFT)134134+135135+/* DFLL_MONITOR_CTRL: internal monitor data source control */136136+#define DFLL_MONITOR_CTRL 0x28137137+#define DFLL_MONITOR_CTRL_FREQ 6138138+139139+/* DFLL_MONITOR_DATA: internal monitor data output */140140+#define DFLL_MONITOR_DATA 0x2c141141+#define DFLL_MONITOR_DATA_NEW_MASK (0x1 << 16)142142+#define DFLL_MONITOR_DATA_VAL_SHIFT 0143143+#define DFLL_MONITOR_DATA_VAL_MASK (0xFFFF << DFLL_MONITOR_DATA_VAL_SHIFT)144144+145145+/*146146+ * I2C output control registers - access via dfll_i2c_{readl,writel}147147+ */148148+149149+/* DFLL_I2C_CFG: I2C controller configuration register */150150+#define DFLL_I2C_CFG 0x40151151+#define DFLL_I2C_CFG_ARB_ENABLE (0x1 << 20)152152+#define DFLL_I2C_CFG_HS_CODE_SHIFT 16153153+#define DFLL_I2C_CFG_HS_CODE_MASK (0x7 << DFLL_I2C_CFG_HS_CODE_SHIFT)154154+#define DFLL_I2C_CFG_PACKET_ENABLE (0x1 << 15)155155+#define DFLL_I2C_CFG_SIZE_SHIFT 12156156+#define DFLL_I2C_CFG_SIZE_MASK (0x7 << DFLL_I2C_CFG_SIZE_SHIFT)157157+#define DFLL_I2C_CFG_SLAVE_ADDR_10 (0x1 << 10)158158+#define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT 1159159+#define DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT 0160160+161161+/* DFLL_I2C_VDD_REG_ADDR: PMIC I2C address for closed loop mode */162162+#define DFLL_I2C_VDD_REG_ADDR 0x44163163+164164+/* DFLL_I2C_STS: I2C controller status */165165+#define DFLL_I2C_STS 0x48166166+#define DFLL_I2C_STS_I2C_LAST_SHIFT 1167167+#define DFLL_I2C_STS_I2C_REQ_PENDING 0x1168168+169169+/* DFLL_INTR_STS: DFLL interrupt status register */170170+#define DFLL_INTR_STS 0x5c171171+172172+/* DFLL_INTR_EN: DFLL interrupt enable register */173173+#define DFLL_INTR_EN 0x60174174+#define DFLL_INTR_MIN_MASK 0x1175175+#define DFLL_INTR_MAX_MASK 0x2176176+177177+/*178178+ * Integrated I2C controller registers - relative to td->i2c_controller_base179179+ */180180+181181+/* DFLL_I2C_CLK_DIVISOR: I2C controller clock divisor */182182+#define DFLL_I2C_CLK_DIVISOR 0x6c183183+#define DFLL_I2C_CLK_DIVISOR_MASK 0xffff184184+#define DFLL_I2C_CLK_DIVISOR_FS_SHIFT 16185185+#define DFLL_I2C_CLK_DIVISOR_HS_SHIFT 0186186+#define DFLL_I2C_CLK_DIVISOR_PREDIV 8187187+#define DFLL_I2C_CLK_DIVISOR_HSMODE_PREDIV 12188188+189189+/*190190+ * Other constants191191+ */192192+193193+/* MAX_DFLL_VOLTAGES: number of LUT entries in the DFLL IP block */194194+#define MAX_DFLL_VOLTAGES 33195195+196196+/*197197+ * REF_CLK_CYC_PER_DVCO_SAMPLE: the number of ref_clk cycles that the hardware198198+ * integrates the DVCO counter over - used for debug rate monitoring and199199+ * droop control200200+ */201201+#define REF_CLK_CYC_PER_DVCO_SAMPLE 4202202+203203+/*204204+ * REF_CLOCK_RATE: the DFLL reference clock rate currently supported by this205205+ * driver, in Hz206206+ */207207+#define REF_CLOCK_RATE 51000000UL208208+209209+#define DVCO_RATE_TO_MULT(rate, ref_rate) ((rate) / ((ref_rate) / 2))210210+#define MULT_TO_DVCO_RATE(mult, ref_rate) ((mult) * ((ref_rate) / 2))211211+212212+/**213213+ * enum dfll_ctrl_mode - DFLL hardware operating mode214214+ * @DFLL_UNINITIALIZED: (uninitialized state - not in hardware bitfield)215215+ * @DFLL_DISABLED: DFLL not generating an output clock216216+ * @DFLL_OPEN_LOOP: DVCO running, but DFLL not adjusting voltage217217+ * @DFLL_CLOSED_LOOP: DVCO running, and DFLL adjusting voltage to match218218+ * the requested rate219219+ *220220+ * The integer corresponding to the last two states, minus one, is221221+ * written to the DFLL hardware to change operating modes.222222+ */223223+enum dfll_ctrl_mode {224224+ DFLL_UNINITIALIZED = 0,225225+ DFLL_DISABLED = 1,226226+ DFLL_OPEN_LOOP = 2,227227+ DFLL_CLOSED_LOOP = 3,228228+};229229+230230+/**231231+ * enum dfll_tune_range - voltage range that the driver believes it's in232232+ * @DFLL_TUNE_UNINITIALIZED: DFLL tuning not yet programmed233233+ * @DFLL_TUNE_LOW: DFLL in the low-voltage range (or open-loop mode)234234+ *235235+ * Some DFLL tuning parameters may need to change depending on the236236+ * DVCO's voltage; these states represent the ranges that the driver237237+ * supports. These are software states; these values are never238238+ * written into registers.239239+ */240240+enum dfll_tune_range {241241+ DFLL_TUNE_UNINITIALIZED = 0,242242+ DFLL_TUNE_LOW = 1,243243+};244244+245245+/**246246+ * struct dfll_rate_req - target DFLL rate request data247247+ * @rate: target frequency, after the postscaling248248+ * @dvco_target_rate: target frequency, after the postscaling249249+ * @lut_index: LUT index at which voltage the dvco_target_rate will be reached250250+ * @mult_bits: value to program to the MULT bits of the DFLL_FREQ_REQ register251251+ * @scale_bits: value to program to the SCALE bits of the DFLL_FREQ_REQ register252252+ */253253+struct dfll_rate_req {254254+ unsigned long rate;255255+ unsigned long dvco_target_rate;256256+ int lut_index;257257+ u8 mult_bits;258258+ u8 scale_bits;259259+};260260+261261+struct tegra_dfll {262262+ struct device *dev;263263+ struct tegra_dfll_soc_data *soc;264264+265265+ void __iomem *base;266266+ void __iomem *i2c_base;267267+ void __iomem *i2c_controller_base;268268+ void __iomem *lut_base;269269+270270+ struct regulator *vdd_reg;271271+ struct clk *soc_clk;272272+ struct clk *ref_clk;273273+ struct clk *i2c_clk;274274+ struct clk *dfll_clk;275275+ struct reset_control *dvco_rst;276276+ unsigned long ref_rate;277277+ unsigned long i2c_clk_rate;278278+ unsigned long dvco_rate_min;279279+280280+ enum dfll_ctrl_mode mode;281281+ enum dfll_tune_range tune_range;282282+ struct dentry *debugfs_dir;283283+ struct clk_hw dfll_clk_hw;284284+ const char *output_clock_name;285285+ struct dfll_rate_req last_req;286286+ unsigned long last_unrounded_rate;287287+288288+ /* Parameters from DT */289289+ u32 droop_ctrl;290290+ u32 sample_rate;291291+ u32 force_mode;292292+ u32 cf;293293+ u32 ci;294294+ u32 cg;295295+ bool cg_scale;296296+297297+ /* I2C interface parameters */298298+ u32 i2c_fs_rate;299299+ u32 i2c_reg;300300+ u32 i2c_slave_addr;301301+302302+ /* i2c_lut array entries are regulator framework selectors */303303+ unsigned i2c_lut[MAX_DFLL_VOLTAGES];304304+ int i2c_lut_size;305305+ u8 lut_min, lut_max, lut_safe;306306+};307307+308308+#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw)309309+310310+/* mode_name: map numeric DFLL modes to names for friendly console messages */311311+static const char * const mode_name[] = {312312+ [DFLL_UNINITIALIZED] = "uninitialized",313313+ [DFLL_DISABLED] = "disabled",314314+ [DFLL_OPEN_LOOP] = "open_loop",315315+ [DFLL_CLOSED_LOOP] = "closed_loop",316316+};317317+318318+/*319319+ * Register accessors320320+ */321321+322322+static inline u32 dfll_readl(struct tegra_dfll *td, u32 offs)323323+{324324+ return __raw_readl(td->base + offs);325325+}326326+327327+static inline void dfll_writel(struct tegra_dfll *td, u32 val, u32 offs)328328+{329329+ WARN_ON(offs >= DFLL_I2C_CFG);330330+ __raw_writel(val, td->base + offs);331331+}332332+333333+static inline void dfll_wmb(struct tegra_dfll *td)334334+{335335+ dfll_readl(td, DFLL_CTRL);336336+}337337+338338+/* I2C output control registers - for addresses above DFLL_I2C_CFG */339339+340340+static inline u32 dfll_i2c_readl(struct tegra_dfll *td, u32 offs)341341+{342342+ return __raw_readl(td->i2c_base + offs);343343+}344344+345345+static inline void dfll_i2c_writel(struct tegra_dfll *td, u32 val, u32 offs)346346+{347347+ __raw_writel(val, td->i2c_base + offs);348348+}349349+350350+static inline void dfll_i2c_wmb(struct tegra_dfll *td)351351+{352352+ dfll_i2c_readl(td, DFLL_I2C_CFG);353353+}354354+355355+/**356356+ * dfll_is_running - is the DFLL currently generating a clock?357357+ * @td: DFLL instance358358+ *359359+ * If the DFLL is currently generating an output clock signal, return360360+ * true; otherwise return false.361361+ */362362+static bool dfll_is_running(struct tegra_dfll *td)363363+{364364+ return td->mode >= DFLL_OPEN_LOOP;365365+}366366+367367+/*368368+ * Runtime PM suspend/resume callbacks369369+ */370370+371371+/**372372+ * tegra_dfll_runtime_resume - enable all clocks needed by the DFLL373373+ * @dev: DFLL device *374374+ *375375+ * Enable all clocks needed by the DFLL. Assumes that clk_prepare()376376+ * has already been called on all the clocks.377377+ *378378+ * XXX Should also handle context restore when returning from off.379379+ */380380+int tegra_dfll_runtime_resume(struct device *dev)381381+{382382+ struct tegra_dfll *td = dev_get_drvdata(dev);383383+ int ret;384384+385385+ ret = clk_enable(td->ref_clk);386386+ if (ret) {387387+ dev_err(dev, "could not enable ref clock: %d\n", ret);388388+ return ret;389389+ }390390+391391+ ret = clk_enable(td->soc_clk);392392+ if (ret) {393393+ dev_err(dev, "could not enable register clock: %d\n", ret);394394+ clk_disable(td->ref_clk);395395+ return ret;396396+ }397397+398398+ ret = clk_enable(td->i2c_clk);399399+ if (ret) {400400+ dev_err(dev, "could not enable i2c clock: %d\n", ret);401401+ clk_disable(td->soc_clk);402402+ clk_disable(td->ref_clk);403403+ return ret;404404+ }405405+406406+ return 0;407407+}408408+EXPORT_SYMBOL(tegra_dfll_runtime_resume);409409+410410+/**411411+ * tegra_dfll_runtime_suspend - disable all clocks needed by the DFLL412412+ * @dev: DFLL device *413413+ *414414+ * Disable all clocks needed by the DFLL. Assumes that other code415415+ * will later call clk_unprepare().416416+ */417417+int tegra_dfll_runtime_suspend(struct device *dev)418418+{419419+ struct tegra_dfll *td = dev_get_drvdata(dev);420420+421421+ clk_disable(td->ref_clk);422422+ clk_disable(td->soc_clk);423423+ clk_disable(td->i2c_clk);424424+425425+ return 0;426426+}427427+EXPORT_SYMBOL(tegra_dfll_runtime_suspend);428428+429429+/*430430+ * DFLL tuning operations (per-voltage-range tuning settings)431431+ */432432+433433+/**434434+ * dfll_tune_low - tune to DFLL and CPU settings valid for any voltage435435+ * @td: DFLL instance436436+ *437437+ * Tune the DFLL oscillator parameters and the CPU clock shaper for438438+ * the low-voltage range. These settings are valid for any voltage,439439+ * but may not be optimal.440440+ */441441+static void dfll_tune_low(struct tegra_dfll *td)442442+{443443+ td->tune_range = DFLL_TUNE_LOW;444444+445445+ dfll_writel(td, td->soc->tune0_low, DFLL_TUNE0);446446+ dfll_writel(td, td->soc->tune1, DFLL_TUNE1);447447+ dfll_wmb(td);448448+449449+ if (td->soc->set_clock_trimmers_low)450450+ td->soc->set_clock_trimmers_low();451451+}452452+453453+/*454454+ * Output clock scaler helpers455455+ */456456+457457+/**458458+ * dfll_scale_dvco_rate - calculate scaled rate from the DVCO rate459459+ * @scale_bits: clock scaler value (bits in the DFLL_FREQ_REQ_SCALE field)460460+ * @dvco_rate: the DVCO rate461461+ *462462+ * Apply the same scaling formula that the DFLL hardware uses to scale463463+ * the DVCO rate.464464+ */465465+static unsigned long dfll_scale_dvco_rate(int scale_bits,466466+ unsigned long dvco_rate)467467+{468468+ return (u64)dvco_rate * (scale_bits + 1) / DFLL_FREQ_REQ_SCALE_MAX;469469+}470470+471471+/*472472+ * Monitor control473473+ */474474+475475+/**476476+ * dfll_calc_monitored_rate - convert DFLL_MONITOR_DATA_VAL rate into real freq477477+ * @monitor_data: value read from the DFLL_MONITOR_DATA_VAL bitfield478478+ * @ref_rate: DFLL reference clock rate479479+ *480480+ * Convert @monitor_data from DFLL_MONITOR_DATA_VAL units into cycles481481+ * per second. Returns the converted value.482482+ */483483+static u64 dfll_calc_monitored_rate(u32 monitor_data,484484+ unsigned long ref_rate)485485+{486486+ return monitor_data * (ref_rate / REF_CLK_CYC_PER_DVCO_SAMPLE);487487+}488488+489489+/**490490+ * dfll_read_monitor_rate - return the DFLL's output rate from internal monitor491491+ * @td: DFLL instance492492+ *493493+ * If the DFLL is enabled, return the last rate reported by the DFLL's494494+ * internal monitoring hardware. This works in both open-loop and495495+ * closed-loop mode, and takes the output scaler setting into account.496496+ * Assumes that the monitor was programmed to monitor frequency before497497+ * the sample period started. If the driver believes that the DFLL is498498+ * currently uninitialized or disabled, it will return 0, since499499+ * otherwise the DFLL monitor data register will return the last500500+ * measured rate from when the DFLL was active.501501+ */502502+static u64 dfll_read_monitor_rate(struct tegra_dfll *td)503503+{504504+ u32 v, s;505505+ u64 pre_scaler_rate, post_scaler_rate;506506+507507+ if (!dfll_is_running(td))508508+ return 0;509509+510510+ v = dfll_readl(td, DFLL_MONITOR_DATA);511511+ v = (v & DFLL_MONITOR_DATA_VAL_MASK) >> DFLL_MONITOR_DATA_VAL_SHIFT;512512+ pre_scaler_rate = dfll_calc_monitored_rate(v, td->ref_rate);513513+514514+ s = dfll_readl(td, DFLL_FREQ_REQ);515515+ s = (s & DFLL_FREQ_REQ_SCALE_MASK) >> DFLL_FREQ_REQ_SCALE_SHIFT;516516+ post_scaler_rate = dfll_scale_dvco_rate(s, pre_scaler_rate);517517+518518+ return post_scaler_rate;519519+}520520+521521+/*522522+ * DFLL mode switching523523+ */524524+525525+/**526526+ * dfll_set_mode - change the DFLL control mode527527+ * @td: DFLL instance528528+ * @mode: DFLL control mode (see enum dfll_ctrl_mode)529529+ *530530+ * Change the DFLL's operating mode between disabled, open-loop mode,531531+ * and closed-loop mode, or vice versa.532532+ */533533+static void dfll_set_mode(struct tegra_dfll *td,534534+ enum dfll_ctrl_mode mode)535535+{536536+ td->mode = mode;537537+ dfll_writel(td, mode - 1, DFLL_CTRL);538538+ dfll_wmb(td);539539+}540540+541541+/*542542+ * DFLL-to-I2C controller interface543543+ */544544+545545+/**546546+ * dfll_i2c_set_output_enabled - enable/disable I2C PMIC voltage requests547547+ * @td: DFLL instance548548+ * @enable: whether to enable or disable the I2C voltage requests549549+ *550550+ * Set the master enable control for I2C control value updates. If disabled,551551+ * then I2C control messages are inhibited, regardless of the DFLL mode.552552+ */553553+static int dfll_i2c_set_output_enabled(struct tegra_dfll *td, bool enable)554554+{555555+ u32 val;556556+557557+ val = dfll_i2c_readl(td, DFLL_OUTPUT_CFG);558558+559559+ if (enable)560560+ val |= DFLL_OUTPUT_CFG_I2C_ENABLE;561561+ else562562+ val &= ~DFLL_OUTPUT_CFG_I2C_ENABLE;563563+564564+ dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG);565565+ dfll_i2c_wmb(td);566566+567567+ return 0;568568+}569569+570570+/**571571+ * dfll_load_lut - load the voltage lookup table572572+ * @td: struct tegra_dfll *573573+ *574574+ * Load the voltage-to-PMIC register value lookup table into the DFLL575575+ * IP block memory. Look-up tables can be loaded at any time.576576+ */577577+static void dfll_load_i2c_lut(struct tegra_dfll *td)578578+{579579+ int i, lut_index;580580+ u32 val;581581+582582+ for (i = 0; i < MAX_DFLL_VOLTAGES; i++) {583583+ if (i < td->lut_min)584584+ lut_index = td->lut_min;585585+ else if (i > td->lut_max)586586+ lut_index = td->lut_max;587587+ else588588+ lut_index = i;589589+590590+ val = regulator_list_hardware_vsel(td->vdd_reg,591591+ td->i2c_lut[lut_index]);592592+ __raw_writel(val, td->lut_base + i * 4);593593+ }594594+595595+ dfll_i2c_wmb(td);596596+}597597+598598+/**599599+ * dfll_init_i2c_if - set up the DFLL's DFLL-I2C interface600600+ * @td: DFLL instance601601+ *602602+ * During DFLL driver initialization, program the DFLL-I2C interface603603+ * with the PMU slave address, vdd register offset, and transfer mode.604604+ * This data is used by the DFLL to automatically construct I2C605605+ * voltage-set commands, which are then passed to the DFLL's internal606606+ * I2C controller.607607+ */608608+static void dfll_init_i2c_if(struct tegra_dfll *td)609609+{610610+ u32 val;611611+612612+ if (td->i2c_slave_addr > 0x7f) {613613+ val = td->i2c_slave_addr << DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_10BIT;614614+ val |= DFLL_I2C_CFG_SLAVE_ADDR_10;615615+ } else {616616+ val = td->i2c_slave_addr << DFLL_I2C_CFG_SLAVE_ADDR_SHIFT_7BIT;617617+ }618618+ val |= DFLL_I2C_CFG_SIZE_MASK;619619+ val |= DFLL_I2C_CFG_ARB_ENABLE;620620+ dfll_i2c_writel(td, val, DFLL_I2C_CFG);621621+622622+ dfll_i2c_writel(td, td->i2c_reg, DFLL_I2C_VDD_REG_ADDR);623623+624624+ val = DIV_ROUND_UP(td->i2c_clk_rate, td->i2c_fs_rate * 8);625625+ BUG_ON(!val || (val > DFLL_I2C_CLK_DIVISOR_MASK));626626+ val = (val - 1) << DFLL_I2C_CLK_DIVISOR_FS_SHIFT;627627+628628+ /* default hs divisor just in case */629629+ val |= 1 << DFLL_I2C_CLK_DIVISOR_HS_SHIFT;630630+ __raw_writel(val, td->i2c_controller_base + DFLL_I2C_CLK_DIVISOR);631631+ dfll_i2c_wmb(td);632632+}633633+634634+/**635635+ * dfll_init_out_if - prepare DFLL-to-PMIC interface636636+ * @td: DFLL instance637637+ *638638+ * During DFLL driver initialization or resume from context loss,639639+ * disable the I2C command output to the PMIC, set safe voltage and640640+ * output limits, and disable and clear limit interrupts.641641+ */642642+static void dfll_init_out_if(struct tegra_dfll *td)643643+{644644+ u32 val;645645+646646+ td->lut_min = 0;647647+ td->lut_max = td->i2c_lut_size - 1;648648+ td->lut_safe = td->lut_min + 1;649649+650650+ dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG);651651+ val = (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) |652652+ (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) |653653+ (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT);654654+ dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG);655655+ dfll_i2c_wmb(td);656656+657657+ dfll_writel(td, 0, DFLL_OUTPUT_FORCE);658658+ dfll_i2c_writel(td, 0, DFLL_INTR_EN);659659+ dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK,660660+ DFLL_INTR_STS);661661+662662+ dfll_load_i2c_lut(td);663663+ dfll_init_i2c_if(td);664664+}665665+666666+/*667667+ * Set/get the DFLL's targeted output clock rate668668+ */669669+670670+/**671671+ * find_lut_index_for_rate - determine I2C LUT index for given DFLL rate672672+ * @td: DFLL instance673673+ * @rate: clock rate674674+ *675675+ * Determines the index of a I2C LUT entry for a voltage that approximately676676+ * produces the given DFLL clock rate. This is used when forcing a value677677+ * to the integrator during rate changes. Returns -ENOENT if a suitable678678+ * LUT index is not found.679679+ */680680+static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)681681+{682682+ struct dev_pm_opp *opp;683683+ int i, uv;684684+685685+ opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);686686+ if (IS_ERR(opp))687687+ return PTR_ERR(opp);688688+ uv = dev_pm_opp_get_voltage(opp);689689+690690+ for (i = 0; i < td->i2c_lut_size; i++) {691691+ if (regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) == uv)692692+ return i;693693+ }694694+695695+ return -ENOENT;696696+}697697+698698+/**699699+ * dfll_calculate_rate_request - calculate DFLL parameters for a given rate700700+ * @td: DFLL instance701701+ * @req: DFLL-rate-request structure702702+ * @rate: the desired DFLL rate703703+ *704704+ * Populate the DFLL-rate-request record @req fields with the scale_bits705705+ * and mult_bits fields, based on the target input rate. Returns 0 upon706706+ * success, or -EINVAL if the requested rate in req->rate is too high707707+ * or low for the DFLL to generate.708708+ */709709+static int dfll_calculate_rate_request(struct tegra_dfll *td,710710+ struct dfll_rate_req *req,711711+ unsigned long rate)712712+{713713+ u32 val;714714+715715+ /*716716+ * If requested rate is below the minimum DVCO rate, active the scaler.717717+ * In the future the DVCO minimum voltage should be selected based on718718+ * chip temperature and the actual minimum rate should be calibrated719719+ * at runtime.720720+ */721721+ req->scale_bits = DFLL_FREQ_REQ_SCALE_MAX - 1;722722+ if (rate < td->dvco_rate_min) {723723+ int scale;724724+725725+ scale = DIV_ROUND_CLOSEST(rate / 1000 * DFLL_FREQ_REQ_SCALE_MAX,726726+ td->dvco_rate_min / 1000);727727+ if (!scale) {728728+ dev_err(td->dev, "%s: Rate %lu is too low\n",729729+ __func__, rate);730730+ return -EINVAL;731731+ }732732+ req->scale_bits = scale - 1;733733+ rate = td->dvco_rate_min;734734+ }735735+736736+ /* Convert requested rate into frequency request and scale settings */737737+ val = DVCO_RATE_TO_MULT(rate, td->ref_rate);738738+ if (val > FREQ_MAX) {739739+ dev_err(td->dev, "%s: Rate %lu is above dfll range\n",740740+ __func__, rate);741741+ return -EINVAL;742742+ }743743+ req->mult_bits = val;744744+ req->dvco_target_rate = MULT_TO_DVCO_RATE(req->mult_bits, td->ref_rate);745745+ req->rate = dfll_scale_dvco_rate(req->scale_bits,746746+ req->dvco_target_rate);747747+ req->lut_index = find_lut_index_for_rate(td, req->dvco_target_rate);748748+ if (req->lut_index < 0)749749+ return req->lut_index;750750+751751+ return 0;752752+}753753+754754+/**755755+ * dfll_set_frequency_request - start the frequency change operation756756+ * @td: DFLL instance757757+ * @req: rate request structure758758+ *759759+ * Tell the DFLL to try to change its output frequency to the760760+ * frequency represented by @req. DFLL must be in closed-loop mode.761761+ */762762+static void dfll_set_frequency_request(struct tegra_dfll *td,763763+ struct dfll_rate_req *req)764764+{765765+ u32 val = 0;766766+ int force_val;767767+ int coef = 128; /* FIXME: td->cg_scale? */;768768+769769+ force_val = (req->lut_index - td->lut_safe) * coef / td->cg;770770+ force_val = clamp(force_val, FORCE_MIN, FORCE_MAX);771771+772772+ val |= req->mult_bits << DFLL_FREQ_REQ_MULT_SHIFT;773773+ val |= req->scale_bits << DFLL_FREQ_REQ_SCALE_SHIFT;774774+ val |= ((u32)force_val << DFLL_FREQ_REQ_FORCE_SHIFT) &775775+ DFLL_FREQ_REQ_FORCE_MASK;776776+ val |= DFLL_FREQ_REQ_FREQ_VALID | DFLL_FREQ_REQ_FORCE_ENABLE;777777+778778+ dfll_writel(td, val, DFLL_FREQ_REQ);779779+ dfll_wmb(td);780780+}781781+782782+/**783783+ * tegra_dfll_request_rate - set the next rate for the DFLL to tune to784784+ * @td: DFLL instance785785+ * @rate: clock rate to target786786+ *787787+ * Convert the requested clock rate @rate into the DFLL control logic788788+ * settings. In closed-loop mode, update new settings immediately to789789+ * adjust DFLL output rate accordingly. Otherwise, just save them790790+ * until the next switch to closed loop. Returns 0 upon success,791791+ * -EPERM if the DFLL driver has not yet been initialized, or -EINVAL792792+ * if @rate is outside the DFLL's tunable range.793793+ */794794+static int dfll_request_rate(struct tegra_dfll *td, unsigned long rate)795795+{796796+ int ret;797797+ struct dfll_rate_req req;798798+799799+ if (td->mode == DFLL_UNINITIALIZED) {800800+ dev_err(td->dev, "%s: Cannot set DFLL rate in %s mode\n",801801+ __func__, mode_name[td->mode]);802802+ return -EPERM;803803+ }804804+805805+ ret = dfll_calculate_rate_request(td, &req, rate);806806+ if (ret)807807+ return ret;808808+809809+ td->last_unrounded_rate = rate;810810+ td->last_req = req;811811+812812+ if (td->mode == DFLL_CLOSED_LOOP)813813+ dfll_set_frequency_request(td, &td->last_req);814814+815815+ return 0;816816+}817817+818818+/*819819+ * DFLL enable/disable & open-loop <-> closed-loop transitions820820+ */821821+822822+/**823823+ * dfll_disable - switch from open-loop mode to disabled mode824824+ * @td: DFLL instance825825+ *826826+ * Switch from OPEN_LOOP state to DISABLED state. Returns 0 upon success827827+ * or -EPERM if the DFLL is not currently in open-loop mode.828828+ */829829+static int dfll_disable(struct tegra_dfll *td)830830+{831831+ if (td->mode != DFLL_OPEN_LOOP) {832832+ dev_err(td->dev, "cannot disable DFLL in %s mode\n",833833+ mode_name[td->mode]);834834+ return -EINVAL;835835+ }836836+837837+ dfll_set_mode(td, DFLL_DISABLED);838838+ pm_runtime_put_sync(td->dev);839839+840840+ return 0;841841+}842842+843843+/**844844+ * dfll_enable - switch a disabled DFLL to open-loop mode845845+ * @td: DFLL instance846846+ *847847+ * Switch from DISABLED state to OPEN_LOOP state. Returns 0 upon success848848+ * or -EPERM if the DFLL is not currently disabled.849849+ */850850+static int dfll_enable(struct tegra_dfll *td)851851+{852852+ if (td->mode != DFLL_DISABLED) {853853+ dev_err(td->dev, "cannot enable DFLL in %s mode\n",854854+ mode_name[td->mode]);855855+ return -EPERM;856856+ }857857+858858+ pm_runtime_get_sync(td->dev);859859+ dfll_set_mode(td, DFLL_OPEN_LOOP);860860+861861+ return 0;862862+}863863+864864+/**865865+ * dfll_set_open_loop_config - prepare to switch to open-loop mode866866+ * @td: DFLL instance867867+ *868868+ * Prepare to switch the DFLL to open-loop mode. This switches the869869+ * DFLL to the low-voltage tuning range, ensures that I2C output870870+ * forcing is disabled, and disables the output clock rate scaler.871871+ * The DFLL's low-voltage tuning range parameters must be872872+ * characterized to keep the downstream device stable at any DVCO873873+ * input voltage. No return value.874874+ */875875+static void dfll_set_open_loop_config(struct tegra_dfll *td)876876+{877877+ u32 val;878878+879879+ /* always tune low (safe) in open loop */880880+ if (td->tune_range != DFLL_TUNE_LOW)881881+ dfll_tune_low(td);882882+883883+ val = dfll_readl(td, DFLL_FREQ_REQ);884884+ val |= DFLL_FREQ_REQ_SCALE_MASK;885885+ val &= ~DFLL_FREQ_REQ_FORCE_ENABLE;886886+ dfll_writel(td, val, DFLL_FREQ_REQ);887887+ dfll_wmb(td);888888+}889889+890890+/**891891+ * tegra_dfll_lock - switch from open-loop to closed-loop mode892892+ * @td: DFLL instance893893+ *894894+ * Switch from OPEN_LOOP state to CLOSED_LOOP state. Returns 0 upon success,895895+ * -EINVAL if the DFLL's target rate hasn't been set yet, or -EPERM if the896896+ * DFLL is not currently in open-loop mode.897897+ */898898+static int dfll_lock(struct tegra_dfll *td)899899+{900900+ struct dfll_rate_req *req = &td->last_req;901901+902902+ switch (td->mode) {903903+ case DFLL_CLOSED_LOOP:904904+ return 0;905905+906906+ case DFLL_OPEN_LOOP:907907+ if (req->rate == 0) {908908+ dev_err(td->dev, "%s: Cannot lock DFLL at rate 0\n",909909+ __func__);910910+ return -EINVAL;911911+ }912912+913913+ dfll_i2c_set_output_enabled(td, true);914914+ dfll_set_mode(td, DFLL_CLOSED_LOOP);915915+ dfll_set_frequency_request(td, req);916916+ return 0;917917+918918+ default:919919+ BUG_ON(td->mode > DFLL_CLOSED_LOOP);920920+ dev_err(td->dev, "%s: Cannot lock DFLL in %s mode\n",921921+ __func__, mode_name[td->mode]);922922+ return -EPERM;923923+ }924924+}925925+926926+/**927927+ * tegra_dfll_unlock - switch from closed-loop to open-loop mode928928+ * @td: DFLL instance929929+ *930930+ * Switch from CLOSED_LOOP state to OPEN_LOOP state. Returns 0 upon success,931931+ * or -EPERM if the DFLL is not currently in open-loop mode.932932+ */933933+static int dfll_unlock(struct tegra_dfll *td)934934+{935935+ switch (td->mode) {936936+ case DFLL_CLOSED_LOOP:937937+ dfll_set_open_loop_config(td);938938+ dfll_set_mode(td, DFLL_OPEN_LOOP);939939+ dfll_i2c_set_output_enabled(td, false);940940+ return 0;941941+942942+ case DFLL_OPEN_LOOP:943943+ return 0;944944+945945+ default:946946+ BUG_ON(td->mode > DFLL_CLOSED_LOOP);947947+ dev_err(td->dev, "%s: Cannot unlock DFLL in %s mode\n",948948+ __func__, mode_name[td->mode]);949949+ return -EPERM;950950+ }951951+}952952+953953+/*954954+ * Clock framework integration955955+ *956956+ * When the DFLL is being controlled by the CCF, always enter closed loop957957+ * mode when the clk is enabled. This requires that a DFLL rate request958958+ * has been set beforehand, which implies that a clk_set_rate() call is959959+ * always required before a clk_enable().960960+ */961961+962962+static int dfll_clk_is_enabled(struct clk_hw *hw)963963+{964964+ struct tegra_dfll *td = clk_hw_to_dfll(hw);965965+966966+ return dfll_is_running(td);967967+}968968+969969+static int dfll_clk_enable(struct clk_hw *hw)970970+{971971+ struct tegra_dfll *td = clk_hw_to_dfll(hw);972972+ int ret;973973+974974+ ret = dfll_enable(td);975975+ if (ret)976976+ return ret;977977+978978+ ret = dfll_lock(td);979979+ if (ret)980980+ dfll_disable(td);981981+982982+ return ret;983983+}984984+985985+static void dfll_clk_disable(struct clk_hw *hw)986986+{987987+ struct tegra_dfll *td = clk_hw_to_dfll(hw);988988+ int ret;989989+990990+ ret = dfll_unlock(td);991991+ if (!ret)992992+ dfll_disable(td);993993+}994994+995995+static unsigned long dfll_clk_recalc_rate(struct clk_hw *hw,996996+ unsigned long parent_rate)997997+{998998+ struct tegra_dfll *td = clk_hw_to_dfll(hw);999999+10001000+ return td->last_unrounded_rate;10011001+}10021002+10031003+static long dfll_clk_round_rate(struct clk_hw *hw,10041004+ unsigned long rate,10051005+ unsigned long *parent_rate)10061006+{10071007+ struct tegra_dfll *td = clk_hw_to_dfll(hw);10081008+ struct dfll_rate_req req;10091009+ int ret;10101010+10111011+ ret = dfll_calculate_rate_request(td, &req, rate);10121012+ if (ret)10131013+ return ret;10141014+10151015+ /*10161016+ * Don't return the rounded rate, since it doesn't really matter as10171017+ * the output rate will be voltage controlled anyway, and cpufreq10181018+ * freaks out if any rounding happens.10191019+ */10201020+ return rate;10211021+}10221022+10231023+static int dfll_clk_set_rate(struct clk_hw *hw, unsigned long rate,10241024+ unsigned long parent_rate)10251025+{10261026+ struct tegra_dfll *td = clk_hw_to_dfll(hw);10271027+10281028+ return dfll_request_rate(td, rate);10291029+}10301030+10311031+static const struct clk_ops dfll_clk_ops = {10321032+ .is_enabled = dfll_clk_is_enabled,10331033+ .enable = dfll_clk_enable,10341034+ .disable = dfll_clk_disable,10351035+ .recalc_rate = dfll_clk_recalc_rate,10361036+ .round_rate = dfll_clk_round_rate,10371037+ .set_rate = dfll_clk_set_rate,10381038+};10391039+10401040+static struct clk_init_data dfll_clk_init_data = {10411041+ .flags = CLK_IS_ROOT,10421042+ .ops = &dfll_clk_ops,10431043+ .num_parents = 0,10441044+};10451045+10461046+/**10471047+ * dfll_register_clk - register the DFLL output clock with the clock framework10481048+ * @td: DFLL instance10491049+ *10501050+ * Register the DFLL's output clock with the Linux clock framework and register10511051+ * the DFLL driver as an OF clock provider. Returns 0 upon success or -EINVAL10521052+ * or -ENOMEM upon failure.10531053+ */10541054+static int dfll_register_clk(struct tegra_dfll *td)10551055+{10561056+ int ret;10571057+10581058+ dfll_clk_init_data.name = td->output_clock_name;10591059+ td->dfll_clk_hw.init = &dfll_clk_init_data;10601060+10611061+ td->dfll_clk = clk_register(td->dev, &td->dfll_clk_hw);10621062+ if (IS_ERR(td->dfll_clk)) {10631063+ dev_err(td->dev, "DFLL clock registration error\n");10641064+ return -EINVAL;10651065+ }10661066+10671067+ ret = of_clk_add_provider(td->dev->of_node, of_clk_src_simple_get,10681068+ td->dfll_clk);10691069+ if (ret) {10701070+ dev_err(td->dev, "of_clk_add_provider() failed\n");10711071+10721072+ clk_unregister(td->dfll_clk);10731073+ return ret;10741074+ }10751075+10761076+ return 0;10771077+}10781078+10791079+/**10801080+ * dfll_unregister_clk - unregister the DFLL output clock10811081+ * @td: DFLL instance10821082+ *10831083+ * Unregister the DFLL's output clock from the Linux clock framework10841084+ * and from clkdev. No return value.10851085+ */10861086+static void dfll_unregister_clk(struct tegra_dfll *td)10871087+{10881088+ of_clk_del_provider(td->dev->of_node);10891089+ clk_unregister(td->dfll_clk);10901090+ td->dfll_clk = NULL;10911091+}10921092+10931093+/*10941094+ * Debugfs interface10951095+ */10961096+10971097+#ifdef CONFIG_DEBUG_FS10981098+10991099+static int attr_enable_get(void *data, u64 *val)11001100+{11011101+ struct tegra_dfll *td = data;11021102+11031103+ *val = dfll_is_running(td);11041104+11051105+ return 0;11061106+}11071107+static int attr_enable_set(void *data, u64 val)11081108+{11091109+ struct tegra_dfll *td = data;11101110+11111111+ return val ? dfll_enable(td) : dfll_disable(td);11121112+}11131113+DEFINE_SIMPLE_ATTRIBUTE(enable_fops, attr_enable_get, attr_enable_set,11141114+ "%llu\n");11151115+11161116+static int attr_lock_get(void *data, u64 *val)11171117+{11181118+ struct tegra_dfll *td = data;11191119+11201120+ *val = (td->mode == DFLL_CLOSED_LOOP);11211121+11221122+ return 0;11231123+}11241124+static int attr_lock_set(void *data, u64 val)11251125+{11261126+ struct tegra_dfll *td = data;11271127+11281128+ return val ? dfll_lock(td) : dfll_unlock(td);11291129+}11301130+DEFINE_SIMPLE_ATTRIBUTE(lock_fops, attr_lock_get, attr_lock_set,11311131+ "%llu\n");11321132+11331133+static int attr_rate_get(void *data, u64 *val)11341134+{11351135+ struct tegra_dfll *td = data;11361136+11371137+ *val = dfll_read_monitor_rate(td);11381138+11391139+ return 0;11401140+}11411141+11421142+static int attr_rate_set(void *data, u64 val)11431143+{11441144+ struct tegra_dfll *td = data;11451145+11461146+ return dfll_request_rate(td, val);11471147+}11481148+DEFINE_SIMPLE_ATTRIBUTE(rate_fops, attr_rate_get, attr_rate_set, "%llu\n");11491149+11501150+static int attr_registers_show(struct seq_file *s, void *data)11511151+{11521152+ u32 val, offs;11531153+ struct tegra_dfll *td = s->private;11541154+11551155+ seq_puts(s, "CONTROL REGISTERS:\n");11561156+ for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) {11571157+ if (offs == DFLL_OUTPUT_CFG)11581158+ val = dfll_i2c_readl(td, offs);11591159+ else11601160+ val = dfll_readl(td, offs);11611161+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs, val);11621162+ }11631163+11641164+ seq_puts(s, "\nI2C and INTR REGISTERS:\n");11651165+ for (offs = DFLL_I2C_CFG; offs <= DFLL_I2C_STS; offs += 4)11661166+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,11671167+ dfll_i2c_readl(td, offs));11681168+ for (offs = DFLL_INTR_STS; offs <= DFLL_INTR_EN; offs += 4)11691169+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,11701170+ dfll_i2c_readl(td, offs));11711171+11721172+ seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n");11731173+ offs = DFLL_I2C_CLK_DIVISOR;11741174+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,11751175+ __raw_readl(td->i2c_controller_base + offs));11761176+11771177+ seq_puts(s, "\nLUT:\n");11781178+ for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4)11791179+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,11801180+ __raw_readl(td->lut_base + offs));11811181+11821182+ return 0;11831183+}11841184+11851185+static int attr_registers_open(struct inode *inode, struct file *file)11861186+{11871187+ return single_open(file, attr_registers_show, inode->i_private);11881188+}11891189+11901190+static const struct file_operations attr_registers_fops = {11911191+ .open = attr_registers_open,11921192+ .read = seq_read,11931193+ .llseek = seq_lseek,11941194+ .release = single_release,11951195+};11961196+11971197+static int dfll_debug_init(struct tegra_dfll *td)11981198+{11991199+ int ret;12001200+12011201+ if (!td || (td->mode == DFLL_UNINITIALIZED))12021202+ return 0;12031203+12041204+ td->debugfs_dir = debugfs_create_dir("tegra_dfll_fcpu", NULL);12051205+ if (!td->debugfs_dir)12061206+ return -ENOMEM;12071207+12081208+ ret = -ENOMEM;12091209+12101210+ if (!debugfs_create_file("enable", S_IRUGO | S_IWUSR,12111211+ td->debugfs_dir, td, &enable_fops))12121212+ goto err_out;12131213+12141214+ if (!debugfs_create_file("lock", S_IRUGO,12151215+ td->debugfs_dir, td, &lock_fops))12161216+ goto err_out;12171217+12181218+ if (!debugfs_create_file("rate", S_IRUGO,12191219+ td->debugfs_dir, td, &rate_fops))12201220+ goto err_out;12211221+12221222+ if (!debugfs_create_file("registers", S_IRUGO,12231223+ td->debugfs_dir, td, &attr_registers_fops))12241224+ goto err_out;12251225+12261226+ return 0;12271227+12281228+err_out:12291229+ debugfs_remove_recursive(td->debugfs_dir);12301230+ return ret;12311231+}12321232+12331233+#endif /* CONFIG_DEBUG_FS */12341234+12351235+/*12361236+ * DFLL initialization12371237+ */12381238+12391239+/**12401240+ * dfll_set_default_params - program non-output related DFLL parameters12411241+ * @td: DFLL instance12421242+ *12431243+ * During DFLL driver initialization or resume from context loss,12441244+ * program parameters for the closed loop integrator, DVCO tuning,12451245+ * voltage droop control and monitor control.12461246+ */12471247+static void dfll_set_default_params(struct tegra_dfll *td)12481248+{12491249+ u32 val;12501250+12511251+ val = DIV_ROUND_UP(td->ref_rate, td->sample_rate * 32);12521252+ BUG_ON(val > DFLL_CONFIG_DIV_MASK);12531253+ dfll_writel(td, val, DFLL_CONFIG);12541254+12551255+ val = (td->force_mode << DFLL_PARAMS_FORCE_MODE_SHIFT) |12561256+ (td->cf << DFLL_PARAMS_CF_PARAM_SHIFT) |12571257+ (td->ci << DFLL_PARAMS_CI_PARAM_SHIFT) |12581258+ (td->cg << DFLL_PARAMS_CG_PARAM_SHIFT) |12591259+ (td->cg_scale ? DFLL_PARAMS_CG_SCALE : 0);12601260+ dfll_writel(td, val, DFLL_PARAMS);12611261+12621262+ dfll_tune_low(td);12631263+ dfll_writel(td, td->droop_ctrl, DFLL_DROOP_CTRL);12641264+ dfll_writel(td, DFLL_MONITOR_CTRL_FREQ, DFLL_MONITOR_CTRL);12651265+}12661266+12671267+/**12681268+ * dfll_init_clks - clk_get() the DFLL source clocks12691269+ * @td: DFLL instance12701270+ *12711271+ * Call clk_get() on the DFLL source clocks and save the pointers for later12721272+ * use. Returns 0 upon success or error (see devm_clk_get) if one or more12731273+ * of the clocks couldn't be looked up.12741274+ */12751275+static int dfll_init_clks(struct tegra_dfll *td)12761276+{12771277+ td->ref_clk = devm_clk_get(td->dev, "ref");12781278+ if (IS_ERR(td->ref_clk)) {12791279+ dev_err(td->dev, "missing ref clock\n");12801280+ return PTR_ERR(td->ref_clk);12811281+ }12821282+12831283+ td->soc_clk = devm_clk_get(td->dev, "soc");12841284+ if (IS_ERR(td->soc_clk)) {12851285+ dev_err(td->dev, "missing soc clock\n");12861286+ return PTR_ERR(td->soc_clk);12871287+ }12881288+12891289+ td->i2c_clk = devm_clk_get(td->dev, "i2c");12901290+ if (IS_ERR(td->i2c_clk)) {12911291+ dev_err(td->dev, "missing i2c clock\n");12921292+ return PTR_ERR(td->i2c_clk);12931293+ }12941294+ td->i2c_clk_rate = clk_get_rate(td->i2c_clk);12951295+12961296+ return 0;12971297+}12981298+12991299+/**13001300+ * dfll_init - Prepare the DFLL IP block for use13011301+ * @td: DFLL instance13021302+ *13031303+ * Do everything necessary to prepare the DFLL IP block for use. The13041304+ * DFLL will be left in DISABLED state. Called by dfll_probe().13051305+ * Returns 0 upon success, or passes along the error from whatever13061306+ * function returned it.13071307+ */13081308+static int dfll_init(struct tegra_dfll *td)13091309+{13101310+ int ret;13111311+13121312+ td->ref_rate = clk_get_rate(td->ref_clk);13131313+ if (td->ref_rate != REF_CLOCK_RATE) {13141314+ dev_err(td->dev, "unexpected ref clk rate %lu, expecting %lu",13151315+ td->ref_rate, REF_CLOCK_RATE);13161316+ return -EINVAL;13171317+ }13181318+13191319+ reset_control_deassert(td->dvco_rst);13201320+13211321+ ret = clk_prepare(td->ref_clk);13221322+ if (ret) {13231323+ dev_err(td->dev, "failed to prepare ref_clk\n");13241324+ return ret;13251325+ }13261326+13271327+ ret = clk_prepare(td->soc_clk);13281328+ if (ret) {13291329+ dev_err(td->dev, "failed to prepare soc_clk\n");13301330+ goto di_err1;13311331+ }13321332+13331333+ ret = clk_prepare(td->i2c_clk);13341334+ if (ret) {13351335+ dev_err(td->dev, "failed to prepare i2c_clk\n");13361336+ goto di_err2;13371337+ }13381338+13391339+ td->last_unrounded_rate = 0;13401340+13411341+ pm_runtime_enable(td->dev);13421342+ pm_runtime_get_sync(td->dev);13431343+13441344+ dfll_set_mode(td, DFLL_DISABLED);13451345+ dfll_set_default_params(td);13461346+13471347+ if (td->soc->init_clock_trimmers)13481348+ td->soc->init_clock_trimmers();13491349+13501350+ dfll_set_open_loop_config(td);13511351+13521352+ dfll_init_out_if(td);13531353+13541354+ pm_runtime_put_sync(td->dev);13551355+13561356+ return 0;13571357+13581358+di_err2:13591359+ clk_unprepare(td->soc_clk);13601360+di_err1:13611361+ clk_unprepare(td->ref_clk);13621362+13631363+ reset_control_assert(td->dvco_rst);13641364+13651365+ return ret;13661366+}13671367+13681368+/*13691369+ * DT data fetch13701370+ */13711371+13721372+/*13731373+ * Find a PMIC voltage register-to-voltage mapping for the given voltage.13741374+ * An exact voltage match is required.13751375+ */13761376+static int find_vdd_map_entry_exact(struct tegra_dfll *td, int uV)13771377+{13781378+ int i, n_voltages, reg_uV;13791379+13801380+ n_voltages = regulator_count_voltages(td->vdd_reg);13811381+ for (i = 0; i < n_voltages; i++) {13821382+ reg_uV = regulator_list_voltage(td->vdd_reg, i);13831383+ if (reg_uV < 0)13841384+ break;13851385+13861386+ if (uV == reg_uV)13871387+ return i;13881388+ }13891389+13901390+ dev_err(td->dev, "no voltage map entry for %d uV\n", uV);13911391+ return -EINVAL;13921392+}13931393+13941394+/*13951395+ * Find a PMIC voltage register-to-voltage mapping for the given voltage,13961396+ * rounding up to the closest supported voltage.13971397+ * */13981398+static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV)13991399+{14001400+ int i, n_voltages, reg_uV;14011401+14021402+ n_voltages = regulator_count_voltages(td->vdd_reg);14031403+ for (i = 0; i < n_voltages; i++) {14041404+ reg_uV = regulator_list_voltage(td->vdd_reg, i);14051405+ if (reg_uV < 0)14061406+ break;14071407+14081408+ if (uV <= reg_uV)14091409+ return i;14101410+ }14111411+14121412+ dev_err(td->dev, "no voltage map entry rounding to %d uV\n", uV);14131413+ return -EINVAL;14141414+}14151415+14161416+/**14171417+ * dfll_build_i2c_lut - build the I2C voltage register lookup table14181418+ * @td: DFLL instance14191419+ *14201420+ * The DFLL hardware has 33 bytes of look-up table RAM that must be filled with14211421+ * PMIC voltage register values that span the entire DFLL operating range.14221422+ * This function builds the look-up table based on the OPP table provided by14231423+ * the soc-specific platform driver (td->soc->opp_dev) and the PMIC14241424+ * register-to-voltage mapping queried from the regulator framework.14251425+ *14261426+ * On success, fills in td->i2c_lut and returns 0, or -err on failure.14271427+ */14281428+static int dfll_build_i2c_lut(struct tegra_dfll *td)14291429+{14301430+ int ret = -EINVAL;14311431+ int j, v, v_max, v_opp;14321432+ int selector;14331433+ unsigned long rate;14341434+ struct dev_pm_opp *opp;14351435+14361436+ rcu_read_lock();14371437+14381438+ rate = ULONG_MAX;14391439+ opp = dev_pm_opp_find_freq_floor(td->soc->dev, &rate);14401440+ if (IS_ERR(opp)) {14411441+ dev_err(td->dev, "couldn't get vmax opp, empty opp table?\n");14421442+ goto out;14431443+ }14441444+ v_max = dev_pm_opp_get_voltage(opp);14451445+14461446+ v = td->soc->min_millivolts * 1000;14471447+ td->i2c_lut[0] = find_vdd_map_entry_exact(td, v);14481448+ if (td->i2c_lut[0] < 0)14491449+ goto out;14501450+14511451+ for (j = 1, rate = 0; ; rate++) {14521452+ opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);14531453+ if (IS_ERR(opp))14541454+ break;14551455+ v_opp = dev_pm_opp_get_voltage(opp);14561456+14571457+ if (v_opp <= td->soc->min_millivolts * 1000)14581458+ td->dvco_rate_min = dev_pm_opp_get_freq(opp);14591459+14601460+ for (;;) {14611461+ v += max(1, (v_max - v) / (MAX_DFLL_VOLTAGES - j));14621462+ if (v >= v_opp)14631463+ break;14641464+14651465+ selector = find_vdd_map_entry_min(td, v);14661466+ if (selector < 0)14671467+ goto out;14681468+ if (selector != td->i2c_lut[j - 1])14691469+ td->i2c_lut[j++] = selector;14701470+ }14711471+14721472+ v = (j == MAX_DFLL_VOLTAGES - 1) ? v_max : v_opp;14731473+ selector = find_vdd_map_entry_exact(td, v);14741474+ if (selector < 0)14751475+ goto out;14761476+ if (selector != td->i2c_lut[j - 1])14771477+ td->i2c_lut[j++] = selector;14781478+14791479+ if (v >= v_max)14801480+ break;14811481+ }14821482+ td->i2c_lut_size = j;14831483+14841484+ if (!td->dvco_rate_min)14851485+ dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n",14861486+ td->soc->min_millivolts);14871487+ else14881488+ ret = 0;14891489+14901490+out:14911491+ rcu_read_unlock();14921492+14931493+ return ret;14941494+}14951495+14961496+/**14971497+ * read_dt_param - helper function for reading required parameters from the DT14981498+ * @td: DFLL instance14991499+ * @param: DT property name15001500+ * @dest: output pointer for the value read15011501+ *15021502+ * Read a required numeric parameter from the DFLL device node, or complain15031503+ * if the property doesn't exist. Returns a boolean indicating success for15041504+ * easy chaining of multiple calls to this function.15051505+ */15061506+static bool read_dt_param(struct tegra_dfll *td, const char *param, u32 *dest)15071507+{15081508+ int err = of_property_read_u32(td->dev->of_node, param, dest);15091509+15101510+ if (err < 0) {15111511+ dev_err(td->dev, "failed to read DT parameter %s: %d\n",15121512+ param, err);15131513+ return false;15141514+ }15151515+15161516+ return true;15171517+}15181518+15191519+/**15201520+ * dfll_fetch_i2c_params - query PMIC I2C params from DT & regulator subsystem15211521+ * @td: DFLL instance15221522+ *15231523+ * Read all the parameters required for operation in I2C mode. The parameters15241524+ * can originate from the device tree or the regulator subsystem.15251525+ * Returns 0 on success or -err on failure.15261526+ */15271527+static int dfll_fetch_i2c_params(struct tegra_dfll *td)15281528+{15291529+ struct regmap *regmap;15301530+ struct device *i2c_dev;15311531+ struct i2c_client *i2c_client;15321532+ int vsel_reg, vsel_mask;15331533+ int ret;15341534+15351535+ if (!read_dt_param(td, "nvidia,i2c-fs-rate", &td->i2c_fs_rate))15361536+ return -EINVAL;15371537+15381538+ regmap = regulator_get_regmap(td->vdd_reg);15391539+ i2c_dev = regmap_get_device(regmap);15401540+ i2c_client = to_i2c_client(i2c_dev);15411541+15421542+ td->i2c_slave_addr = i2c_client->addr;15431543+15441544+ ret = regulator_get_hardware_vsel_register(td->vdd_reg,15451545+ &vsel_reg,15461546+ &vsel_mask);15471547+ if (ret < 0) {15481548+ dev_err(td->dev,15491549+ "regulator unsuitable for DFLL I2C operation\n");15501550+ return -EINVAL;15511551+ }15521552+ td->i2c_reg = vsel_reg;15531553+15541554+ ret = dfll_build_i2c_lut(td);15551555+ if (ret) {15561556+ dev_err(td->dev, "couldn't build I2C LUT\n");15571557+ return ret;15581558+ }15591559+15601560+ return 0;15611561+}15621562+15631563+/**15641564+ * dfll_fetch_common_params - read DFLL parameters from the device tree15651565+ * @td: DFLL instance15661566+ *15671567+ * Read all the DT parameters that are common to both I2C and PWM operation.15681568+ * Returns 0 on success or -EINVAL on any failure.15691569+ */15701570+static int dfll_fetch_common_params(struct tegra_dfll *td)15711571+{15721572+ bool ok = true;15731573+15741574+ ok &= read_dt_param(td, "nvidia,droop-ctrl", &td->droop_ctrl);15751575+ ok &= read_dt_param(td, "nvidia,sample-rate", &td->sample_rate);15761576+ ok &= read_dt_param(td, "nvidia,force-mode", &td->force_mode);15771577+ ok &= read_dt_param(td, "nvidia,cf", &td->cf);15781578+ ok &= read_dt_param(td, "nvidia,ci", &td->ci);15791579+ ok &= read_dt_param(td, "nvidia,cg", &td->cg);15801580+ td->cg_scale = of_property_read_bool(td->dev->of_node,15811581+ "nvidia,cg-scale");15821582+15831583+ if (of_property_read_string(td->dev->of_node, "clock-output-names",15841584+ &td->output_clock_name)) {15851585+ dev_err(td->dev, "missing clock-output-names property\n");15861586+ ok = false;15871587+ }15881588+15891589+ return ok ? 0 : -EINVAL;15901590+}15911591+15921592+/*15931593+ * API exported to per-SoC platform drivers15941594+ */15951595+15961596+/**15971597+ * tegra_dfll_register - probe a Tegra DFLL device15981598+ * @pdev: DFLL platform_device *15991599+ * @soc: Per-SoC integration and characterization data for this DFLL instance16001600+ *16011601+ * Probe and initialize a DFLL device instance. Intended to be called16021602+ * by a SoC-specific shim driver that passes in per-SoC integration16031603+ * and configuration data via @soc. Returns 0 on success or -err on failure.16041604+ */16051605+int tegra_dfll_register(struct platform_device *pdev,16061606+ struct tegra_dfll_soc_data *soc)16071607+{16081608+ struct resource *mem;16091609+ struct tegra_dfll *td;16101610+ int ret;16111611+16121612+ if (!soc) {16131613+ dev_err(&pdev->dev, "no tegra_dfll_soc_data provided\n");16141614+ return -EINVAL;16151615+ }16161616+16171617+ td = devm_kzalloc(&pdev->dev, sizeof(*td), GFP_KERNEL);16181618+ if (!td)16191619+ return -ENOMEM;16201620+ td->dev = &pdev->dev;16211621+ platform_set_drvdata(pdev, td);16221622+16231623+ td->soc = soc;16241624+16251625+ td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");16261626+ if (IS_ERR(td->vdd_reg)) {16271627+ dev_err(td->dev, "couldn't get vdd_cpu regulator\n");16281628+ return PTR_ERR(td->vdd_reg);16291629+ }16301630+16311631+ td->dvco_rst = devm_reset_control_get(td->dev, "dvco");16321632+ if (IS_ERR(td->dvco_rst)) {16331633+ dev_err(td->dev, "couldn't get dvco reset\n");16341634+ return PTR_ERR(td->dvco_rst);16351635+ }16361636+16371637+ ret = dfll_fetch_common_params(td);16381638+ if (ret) {16391639+ dev_err(td->dev, "couldn't parse device tree parameters\n");16401640+ return ret;16411641+ }16421642+16431643+ ret = dfll_fetch_i2c_params(td);16441644+ if (ret)16451645+ return ret;16461646+16471647+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);16481648+ if (!mem) {16491649+ dev_err(td->dev, "no control register resource\n");16501650+ return -ENODEV;16511651+ }16521652+16531653+ td->base = devm_ioremap(td->dev, mem->start, resource_size(mem));16541654+ if (!td->base) {16551655+ dev_err(td->dev, "couldn't ioremap DFLL control registers\n");16561656+ return -ENODEV;16571657+ }16581658+16591659+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);16601660+ if (!mem) {16611661+ dev_err(td->dev, "no i2c_base resource\n");16621662+ return -ENODEV;16631663+ }16641664+16651665+ td->i2c_base = devm_ioremap(td->dev, mem->start, resource_size(mem));16661666+ if (!td->i2c_base) {16671667+ dev_err(td->dev, "couldn't ioremap i2c_base resource\n");16681668+ return -ENODEV;16691669+ }16701670+16711671+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 2);16721672+ if (!mem) {16731673+ dev_err(td->dev, "no i2c_controller_base resource\n");16741674+ return -ENODEV;16751675+ }16761676+16771677+ td->i2c_controller_base = devm_ioremap(td->dev, mem->start,16781678+ resource_size(mem));16791679+ if (!td->i2c_controller_base) {16801680+ dev_err(td->dev,16811681+ "couldn't ioremap i2c_controller_base resource\n");16821682+ return -ENODEV;16831683+ }16841684+16851685+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 3);16861686+ if (!mem) {16871687+ dev_err(td->dev, "no lut_base resource\n");16881688+ return -ENODEV;16891689+ }16901690+16911691+ td->lut_base = devm_ioremap(td->dev, mem->start, resource_size(mem));16921692+ if (!td->lut_base) {16931693+ dev_err(td->dev,16941694+ "couldn't ioremap lut_base resource\n");16951695+ return -ENODEV;16961696+ }16971697+16981698+ ret = dfll_init_clks(td);16991699+ if (ret) {17001700+ dev_err(&pdev->dev, "DFLL clock init error\n");17011701+ return ret;17021702+ }17031703+17041704+ /* Enable the clocks and set the device up */17051705+ ret = dfll_init(td);17061706+ if (ret)17071707+ return ret;17081708+17091709+ ret = dfll_register_clk(td);17101710+ if (ret) {17111711+ dev_err(&pdev->dev, "DFLL clk registration failed\n");17121712+ return ret;17131713+ }17141714+17151715+#ifdef CONFIG_DEBUG_FS17161716+ dfll_debug_init(td);17171717+#endif17181718+17191719+ return 0;17201720+}17211721+EXPORT_SYMBOL(tegra_dfll_register);17221722+17231723+/**17241724+ * tegra_dfll_unregister - release all of the DFLL driver resources for a device17251725+ * @pdev: DFLL platform_device *17261726+ *17271727+ * Unbind this driver from the DFLL hardware device represented by17281728+ * @pdev. The DFLL must be disabled for this to succeed. Returns 017291729+ * upon success or -EBUSY if the DFLL is still active.17301730+ */17311731+int tegra_dfll_unregister(struct platform_device *pdev)17321732+{17331733+ struct tegra_dfll *td = platform_get_drvdata(pdev);17341734+17351735+ /* Try to prevent removal while the DFLL is active */17361736+ if (td->mode != DFLL_DISABLED) {17371737+ dev_err(&pdev->dev,17381738+ "must disable DFLL before removing driver\n");17391739+ return -EBUSY;17401740+ }17411741+17421742+ debugfs_remove_recursive(td->debugfs_dir);17431743+17441744+ dfll_unregister_clk(td);17451745+ pm_runtime_disable(&pdev->dev);17461746+17471747+ clk_unprepare(td->ref_clk);17481748+ clk_unprepare(td->soc_clk);17491749+ clk_unprepare(td->i2c_clk);17501750+17511751+ reset_control_assert(td->dvco_rst);17521752+17531753+ return 0;17541754+}17551755+EXPORT_SYMBOL(tegra_dfll_unregister);
+54
drivers/clk/tegra/clk-dfll.h
···11+/*22+ * clk-dfll.h - prototypes and macros for the Tegra DFLL clocksource driver33+ * Copyright (C) 2013 NVIDIA Corporation. All rights reserved.44+ *55+ * Aleksandr Frid <afrid@nvidia.com>66+ * Paul Walmsley <pwalmsley@nvidia.com>77+ *88+ * This program is free software; you can redistribute it and/or modify99+ * it under the terms of the GNU General Public License version 2 as1010+ * published by the Free Software Foundation.1111+ *1212+ * This program is distributed in the hope that it will be useful, but WITHOUT1313+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1414+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1515+ * more details.1616+ */1717+1818+#ifndef __DRIVERS_CLK_TEGRA_CLK_DFLL_H1919+#define __DRIVERS_CLK_TEGRA_CLK_DFLL_H2020+2121+#include <linux/platform_device.h>2222+#include <linux/reset.h>2323+#include <linux/types.h>2424+2525+/**2626+ * struct tegra_dfll_soc_data - SoC-specific hooks/integration for the DFLL driver2727+ * @opp_dev: struct device * that holds the OPP table for the DFLL2828+ * @min_millivolts: minimum voltage (in mV) that the DFLL can operate2929+ * @tune0_low: DFLL tuning register 0 (low voltage range)3030+ * @tune0_high: DFLL tuning register 0 (high voltage range)3131+ * @tune1: DFLL tuning register 13232+ * @assert_dvco_reset: fn ptr to place the DVCO in reset3333+ * @deassert_dvco_reset: fn ptr to release the DVCO reset3434+ * @set_clock_trimmers_high: fn ptr to tune clock trimmers for high voltage3535+ * @set_clock_trimmers_low: fn ptr to tune clock trimmers for low voltage3636+ */3737+struct tegra_dfll_soc_data {3838+ struct device *dev;3939+ unsigned int min_millivolts;4040+ u32 tune0_low;4141+ u32 tune0_high;4242+ u32 tune1;4343+ void (*init_clock_trimmers)(void);4444+ void (*set_clock_trimmers_high)(void);4545+ void (*set_clock_trimmers_low)(void);4646+};4747+4848+int tegra_dfll_register(struct platform_device *pdev,4949+ struct tegra_dfll_soc_data *soc);5050+int tegra_dfll_unregister(struct platform_device *pdev);5151+int tegra_dfll_runtime_suspend(struct device *dev);5252+int tegra_dfll_runtime_resume(struct device *dev);5353+5454+#endif /* __DRIVERS_CLK_TEGRA_CLK_DFLL_H */
···11+/*22+ * Tegra124 DFLL FCPU clock source driver33+ *44+ * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.55+ *66+ * Aleksandr Frid <afrid@nvidia.com>77+ * Paul Walmsley <pwalmsley@nvidia.com>88+ *99+ * This program is free software; you can redistribute it and/or modify1010+ * it under the terms of the GNU General Public License version 2 as1111+ * published by the Free Software Foundation.1212+ *1313+ * This program is distributed in the hope that it will be useful, but WITHOUT1414+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1515+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1616+ * more details.1717+ *1818+ */1919+2020+#include <linux/cpu.h>2121+#include <linux/err.h>2222+#include <linux/kernel.h>2323+#include <linux/module.h>2424+#include <linux/platform_device.h>2525+#include <soc/tegra/fuse.h>2626+2727+#include "clk.h"2828+#include "clk-dfll.h"2929+#include "cvb.h"3030+3131+/* Maximum CPU frequency, indexed by CPU speedo id */3232+static const unsigned long cpu_max_freq_table[] = {3333+ [0] = 2014500000UL,3434+ [1] = 2320500000UL,3535+ [2] = 2116500000UL,3636+ [3] = 2524500000UL,3737+};3838+3939+static const struct cvb_table tegra124_cpu_cvb_tables[] = {4040+ {4141+ .speedo_id = -1,4242+ .process_id = -1,4343+ .min_millivolts = 900,4444+ .max_millivolts = 1260,4545+ .alignment = {4646+ .step_uv = 10000, /* 10mV */4747+ },4848+ .speedo_scale = 100,4949+ .voltage_scale = 1000,5050+ .cvb_table = {5151+ {204000000UL, {1112619, -29295, 402} },5252+ {306000000UL, {1150460, -30585, 402} },5353+ {408000000UL, {1190122, -31865, 402} },5454+ {510000000UL, {1231606, -33155, 402} },5555+ {612000000UL, {1274912, -34435, 402} },5656+ {714000000UL, {1320040, -35725, 402} },5757+ {816000000UL, {1366990, -37005, 402} },5858+ {918000000UL, {1415762, -38295, 402} },5959+ {1020000000UL, {1466355, -39575, 402} },6060+ {1122000000UL, {1518771, -40865, 402} },6161+ {1224000000UL, {1573009, -42145, 402} },6262+ {1326000000UL, {1629068, -43435, 402} },6363+ {1428000000UL, {1686950, -44715, 402} },6464+ {1530000000UL, {1746653, -46005, 402} },6565+ {1632000000UL, {1808179, -47285, 402} },6666+ {1734000000UL, {1871526, -48575, 402} },6767+ {1836000000UL, {1936696, -49855, 402} },6868+ {1938000000UL, {2003687, -51145, 402} },6969+ {2014500000UL, {2054787, -52095, 402} },7070+ {2116500000UL, {2124957, -53385, 402} },7171+ {2218500000UL, {2196950, -54665, 402} },7272+ {2320500000UL, {2270765, -55955, 402} },7373+ {2422500000UL, {2346401, -57235, 402} },7474+ {2524500000UL, {2437299, -58535, 402} },7575+ {0, { 0, 0, 0} },7676+ },7777+ .cpu_dfll_data = {7878+ .tune0_low = 0x005020ff,7979+ .tune0_high = 0x005040ff,8080+ .tune1 = 0x00000060,8181+ }8282+ },8383+};8484+8585+static int tegra124_dfll_fcpu_probe(struct platform_device *pdev)8686+{8787+ int process_id, speedo_id, speedo_value;8888+ struct tegra_dfll_soc_data *soc;8989+ const struct cvb_table *cvb;9090+9191+ process_id = tegra_sku_info.cpu_process_id;9292+ speedo_id = tegra_sku_info.cpu_speedo_id;9393+ speedo_value = tegra_sku_info.cpu_speedo_value;9494+9595+ if (speedo_id >= ARRAY_SIZE(cpu_max_freq_table)) {9696+ dev_err(&pdev->dev, "unknown max CPU freq for speedo_id=%d\n",9797+ speedo_id);9898+ return -ENODEV;9999+ }100100+101101+ soc = devm_kzalloc(&pdev->dev, sizeof(*soc), GFP_KERNEL);102102+ if (!soc)103103+ return -ENOMEM;104104+105105+ soc->dev = get_cpu_device(0);106106+ if (!soc->dev) {107107+ dev_err(&pdev->dev, "no CPU0 device\n");108108+ return -ENODEV;109109+ }110110+111111+ cvb = tegra_cvb_build_opp_table(tegra124_cpu_cvb_tables,112112+ ARRAY_SIZE(tegra124_cpu_cvb_tables),113113+ process_id, speedo_id, speedo_value,114114+ cpu_max_freq_table[speedo_id],115115+ soc->dev);116116+ if (IS_ERR(cvb)) {117117+ dev_err(&pdev->dev, "couldn't build OPP table: %ld\n",118118+ PTR_ERR(cvb));119119+ return PTR_ERR(cvb);120120+ }121121+122122+ soc->min_millivolts = cvb->min_millivolts;123123+ soc->tune0_low = cvb->cpu_dfll_data.tune0_low;124124+ soc->tune0_high = cvb->cpu_dfll_data.tune0_high;125125+ soc->tune1 = cvb->cpu_dfll_data.tune1;126126+127127+ return tegra_dfll_register(pdev, soc);128128+}129129+130130+static const struct of_device_id tegra124_dfll_fcpu_of_match[] = {131131+ { .compatible = "nvidia,tegra124-dfll", },132132+ { },133133+};134134+MODULE_DEVICE_TABLE(of, tegra124_dfll_fcpu_of_match);135135+136136+static const struct dev_pm_ops tegra124_dfll_pm_ops = {137137+ SET_RUNTIME_PM_OPS(tegra_dfll_runtime_suspend,138138+ tegra_dfll_runtime_resume, NULL)139139+};140140+141141+static struct platform_driver tegra124_dfll_fcpu_driver = {142142+ .probe = tegra124_dfll_fcpu_probe,143143+ .remove = tegra_dfll_unregister,144144+ .driver = {145145+ .name = "tegra124-dfll",146146+ .of_match_table = tegra124_dfll_fcpu_of_match,147147+ .pm = &tegra124_dfll_pm_ops,148148+ },149149+};150150+151151+static int __init tegra124_dfll_fcpu_init(void)152152+{153153+ return platform_driver_register(&tegra124_dfll_fcpu_driver);154154+}155155+module_init(tegra124_dfll_fcpu_init);156156+157157+static void __exit tegra124_dfll_fcpu_exit(void)158158+{159159+ platform_driver_unregister(&tegra124_dfll_fcpu_driver);160160+}161161+module_exit(tegra124_dfll_fcpu_exit);162162+163163+MODULE_DESCRIPTION("Tegra124 DFLL clock source driver");164164+MODULE_LICENSE("GPL v2");165165+MODULE_AUTHOR("Aleksandr Frid <afrid@nvidia.com>");166166+MODULE_AUTHOR("Paul Walmsley <pwalmsley@nvidia.com>");
+82
drivers/clk/tegra/clk-tegra124.c
···2323#include <linux/export.h>2424#include <linux/clk/tegra.h>2525#include <dt-bindings/clock/tegra124-car.h>2626+#include <dt-bindings/reset/tegra124-car.h>26272728#include "clk.h"2829#include "clk-id.h"···38373938#define CLK_SOURCE_CSITE 0x1d44039#define CLK_SOURCE_EMC 0x19c4040+4141+#define RST_DFLL_DVCO 0x2f44242+#define DVFS_DFLL_RESET_SHIFT 041434244#define PLLC_BASE 0x804345#define PLLC_OUT 0x84···9793#define PMC_PLLM_WB0_OVERRIDE 0x1dc9894#define PMC_PLLM_WB0_OVERRIDE_2 0x2b099959696+#define CCLKG_BURST_POLICY 0x3689797+10098#define UTMIP_PLL_CFG2 0x48810199#define UTMIP_PLL_CFG2_STABLE_COUNT(x) (((x) & 0xffff) << 6)102100#define UTMIP_PLL_CFG2_ACTIVE_DLY_COUNT(x) (((x) & 0x3f) << 18)···131125#ifdef CONFIG_PM_SLEEP132126static struct cpu_clk_suspend_context {133127 u32 clk_csite_src;128128+ u32 cclkg_burst;129129+ u32 cclkg_divider;134130} tegra124_cpu_clk_sctx;135131#endif136132···13261318 tegra124_cpu_clk_sctx.clk_csite_src =13271319 readl(clk_base + CLK_SOURCE_CSITE);13281320 writel(3 << 30, clk_base + CLK_SOURCE_CSITE);13211321+13221322+ tegra124_cpu_clk_sctx.cclkg_burst =13231323+ readl(clk_base + CCLKG_BURST_POLICY);13241324+ tegra124_cpu_clk_sctx.cclkg_divider =13251325+ readl(clk_base + CCLKG_BURST_POLICY + 4);13291326}1330132713311328static void tegra124_cpu_clock_resume(void)13321329{13331330 writel(tegra124_cpu_clk_sctx.clk_csite_src,13341331 clk_base + CLK_SOURCE_CSITE);13321332+13331333+ writel(tegra124_cpu_clk_sctx.cclkg_burst,13341334+ clk_base + CCLKG_BURST_POLICY);13351335+ writel(tegra124_cpu_clk_sctx.cclkg_divider,13361336+ clk_base + CCLKG_BURST_POLICY + 4);13351337}13361338#endif13371339···14321414}1433141514341416/**14171417+ * tegra124_car_barrier - wait for pending writes to the CAR to complete14181418+ *14191419+ * Wait for any outstanding writes to the CAR MMIO space from this CPU14201420+ * to complete before continuing execution. No return value.14211421+ */14221422+static void tegra124_car_barrier(void)14231423+{14241424+ readl_relaxed(clk_base + RST_DFLL_DVCO);14251425+}14261426+14271427+/**14281428+ * tegra124_clock_assert_dfll_dvco_reset - assert the DFLL's DVCO reset14291429+ *14301430+ * Assert the reset line of the DFLL's DVCO. No return value.14311431+ */14321432+void tegra124_clock_assert_dfll_dvco_reset(void)14331433+{14341434+ u32 v;14351435+14361436+ v = readl_relaxed(clk_base + RST_DFLL_DVCO);14371437+ v |= (1 << DVFS_DFLL_RESET_SHIFT);14381438+ writel_relaxed(v, clk_base + RST_DFLL_DVCO);14391439+ tegra124_car_barrier();14401440+}14411441+14421442+/**14431443+ * tegra124_clock_deassert_dfll_dvco_reset - deassert the DFLL's DVCO reset14441444+ *14451445+ * Deassert the reset line of the DFLL's DVCO, allowing the DVCO to14461446+ * operate. No return value.14471447+ */14481448+void tegra124_clock_deassert_dfll_dvco_reset(void)14491449+{14501450+ u32 v;14511451+14521452+ v = readl_relaxed(clk_base + RST_DFLL_DVCO);14531453+ v &= ~(1 << DVFS_DFLL_RESET_SHIFT);14541454+ writel_relaxed(v, clk_base + RST_DFLL_DVCO);14551455+ tegra124_car_barrier();14561456+}14571457+14581458+int tegra124_reset_assert(unsigned long id)14591459+{14601460+ if (id == TEGRA124_RST_DFLL_DVCO)14611461+ tegra124_clock_assert_dfll_dvco_reset();14621462+ else14631463+ return -EINVAL;14641464+14651465+ return 0;14661466+}14671467+14681468+int tegra124_reset_deassert(unsigned long id)14691469+{14701470+ if (id == TEGRA124_RST_DFLL_DVCO)14711471+ tegra124_clock_deassert_dfll_dvco_reset();14721472+ else14731473+ return -EINVAL;14741474+14751475+ return 0;14761476+}14771477+14781478+/**14351479 * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs14361480 *14371481 * Program an initial clock rate and enable or disable clocks needed···15781498{15791499 tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks,15801500 &pll_x_params);15011501+ tegra_init_special_resets(1, tegra124_reset_assert,15021502+ tegra124_reset_deassert);15811503 tegra_add_of_provider(np);1582150415831505 clks[TEGRA124_CLK_EMC] = tegra_clk_register_emc(clk_base, np,
+31-8
drivers/clk/tegra/clk.c
···5050#define RST_DEVICES_L 0x0045151#define RST_DEVICES_H 0x0085252#define RST_DEVICES_U 0x00C5353-#define RST_DFLL_DVCO 0x2F45453#define RST_DEVICES_V 0x3585554#define RST_DEVICES_W 0x35C5655#define RST_DEVICES_X 0x28C···7879static struct clk **clks;7980static int clk_num;8081static struct clk_onecell_data clk_data;8282+8383+/* Handlers for SoC-specific reset lines */8484+static int (*special_reset_assert)(unsigned long);8585+static int (*special_reset_deassert)(unsigned long);8686+static unsigned int num_special_reset;81878288static struct tegra_clk_periph_regs periph_regs[] = {8389 [0] = {···157153 */158154 tegra_read_chipid();159155160160- writel_relaxed(BIT(id % 32),161161- clk_base + periph_regs[id / 32].rst_set_reg);156156+ if (id < periph_banks * 32) {157157+ writel_relaxed(BIT(id % 32),158158+ clk_base + periph_regs[id / 32].rst_set_reg);159159+ return 0;160160+ } else if (id < periph_banks * 32 + num_special_reset) {161161+ return special_reset_assert(id);162162+ }162163163163- return 0;164164+ return -EINVAL;164165}165166166167static int tegra_clk_rst_deassert(struct reset_controller_dev *rcdev,167168 unsigned long id)168169{169169- writel_relaxed(BIT(id % 32),170170- clk_base + periph_regs[id / 32].rst_clr_reg);170170+ if (id < periph_banks * 32) {171171+ writel_relaxed(BIT(id % 32),172172+ clk_base + periph_regs[id / 32].rst_clr_reg);173173+ return 0;174174+ } else if (id < periph_banks * 32 + num_special_reset) {175175+ return special_reset_deassert(id);176176+ }171177172172- return 0;178178+ return -EINVAL;173179}174180175181struct tegra_clk_periph_regs *get_reg_bank(int clkid)···301287 of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);302288303289 rst_ctlr.of_node = np;304304- rst_ctlr.nr_resets = periph_banks * 32;290290+ rst_ctlr.nr_resets = periph_banks * 32 + num_special_reset;305291 reset_controller_register(&rst_ctlr);292292+}293293+294294+void __init tegra_init_special_resets(unsigned int num,295295+ int (*assert)(unsigned long),296296+ int (*deassert)(unsigned long))297297+{298298+ num_special_reset = num;299299+ special_reset_assert = assert;300300+ special_reset_deassert = deassert;306301}307302308303void __init tegra_register_devclks(struct tegra_devclk *dev_clks, int num)
+3
drivers/clk/tegra/clk.h
···591591 char *con_id;592592};593593594594+void tegra_init_special_resets(unsigned int num, int (*assert)(unsigned long),595595+ int (*deassert)(unsigned long));596596+594597void tegra_init_from_table(struct tegra_clk_init_table *tbl,595598 struct clk *clks[], int clk_max);596599
+140
drivers/clk/tegra/cvb.c
···11+/*22+ * Utility functions for parsing Tegra CVB voltage tables33+ *44+ * Copyright (C) 2012-2014 NVIDIA Corporation. All rights reserved.55+ *66+ * This program is free software; you can redistribute it and/or modify77+ * it under the terms of the GNU General Public License version 2 as88+ * published by the Free Software Foundation.99+ *1010+ * This program is distributed in the hope that it will be useful, but WITHOUT1111+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1212+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1313+ * more details.1414+ *1515+ */1616+#include <linux/err.h>1717+#include <linux/kernel.h>1818+#include <linux/pm_opp.h>1919+2020+#include "cvb.h"2121+2222+/* cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) */2323+static inline int get_cvb_voltage(int speedo, int s_scale,2424+ const struct cvb_coefficients *cvb)2525+{2626+ int mv;2727+2828+ /* apply only speedo scale: output mv = cvb_mv * v_scale */2929+ mv = DIV_ROUND_CLOSEST(cvb->c2 * speedo, s_scale);3030+ mv = DIV_ROUND_CLOSEST((mv + cvb->c1) * speedo, s_scale) + cvb->c0;3131+ return mv;3232+}3333+3434+static int round_cvb_voltage(int mv, int v_scale,3535+ const struct rail_alignment *align)3636+{3737+ /* combined: apply voltage scale and round to cvb alignment step */3838+ int uv;3939+ int step = (align->step_uv ? : 1000) * v_scale;4040+ int offset = align->offset_uv * v_scale;4141+4242+ uv = max(mv * 1000, offset) - offset;4343+ uv = DIV_ROUND_UP(uv, step) * align->step_uv + align->offset_uv;4444+ return uv / 1000;4545+}4646+4747+enum {4848+ DOWN,4949+ UP5050+};5151+5252+static int round_voltage(int mv, const struct rail_alignment *align, int up)5353+{5454+ if (align->step_uv) {5555+ int uv;5656+5757+ uv = max(mv * 1000, align->offset_uv) - align->offset_uv;5858+ uv = (uv + (up ? align->step_uv - 1 : 0)) / align->step_uv;5959+ return (uv * align->step_uv + align->offset_uv) / 1000;6060+ }6161+ return mv;6262+}6363+6464+static int build_opp_table(const struct cvb_table *d,6565+ int speedo_value,6666+ unsigned long max_freq,6767+ struct device *opp_dev)6868+{6969+ int i, ret, dfll_mv, min_mv, max_mv;7070+ const struct cvb_table_freq_entry *table = NULL;7171+ const struct rail_alignment *align = &d->alignment;7272+7373+ min_mv = round_voltage(d->min_millivolts, align, UP);7474+ max_mv = round_voltage(d->max_millivolts, align, DOWN);7575+7676+ for (i = 0; i < MAX_DVFS_FREQS; i++) {7777+ table = &d->cvb_table[i];7878+ if (!table->freq || (table->freq > max_freq))7979+ break;8080+8181+ /*8282+ * FIXME after clk_round_rate/clk_determine_rate prototypes8383+ * have been updated8484+ */8585+ if (table->freq & (1<<31))8686+ continue;8787+8888+ dfll_mv = get_cvb_voltage(8989+ speedo_value, d->speedo_scale, &table->coefficients);9090+ dfll_mv = round_cvb_voltage(dfll_mv, d->voltage_scale, align);9191+ dfll_mv = clamp(dfll_mv, min_mv, max_mv);9292+9393+ ret = dev_pm_opp_add(opp_dev, table->freq, dfll_mv * 1000);9494+ if (ret)9595+ return ret;9696+ }9797+9898+ return 0;9999+}100100+101101+/**102102+ * tegra_cvb_build_opp_table - build OPP table from Tegra CVB tables103103+ * @cvb_tables: array of CVB tables104104+ * @sz: size of the previously mentioned array105105+ * @process_id: process id of the HW module106106+ * @speedo_id: speedo id of the HW module107107+ * @speedo_value: speedo value of the HW module108108+ * @max_rate: highest safe clock rate109109+ * @opp_dev: the struct device * for which the OPP table is built110110+ *111111+ * On Tegra, a CVB table encodes the relationship between operating voltage112112+ * and safe maximal frequency for a given module (e.g. GPU or CPU). This113113+ * function calculates the optimal voltage-frequency operating points114114+ * for the given arguments and exports them via the OPP library for the115115+ * given @opp_dev. Returns a pointer to the struct cvb_table that matched116116+ * or an ERR_PTR on failure.117117+ */118118+const struct cvb_table *tegra_cvb_build_opp_table(119119+ const struct cvb_table *cvb_tables,120120+ size_t sz, int process_id,121121+ int speedo_id, int speedo_value,122122+ unsigned long max_rate,123123+ struct device *opp_dev)124124+{125125+ int i, ret;126126+127127+ for (i = 0; i < sz; i++) {128128+ const struct cvb_table *d = &cvb_tables[i];129129+130130+ if (d->speedo_id != -1 && d->speedo_id != speedo_id)131131+ continue;132132+ if (d->process_id != -1 && d->process_id != process_id)133133+ continue;134134+135135+ ret = build_opp_table(d, speedo_value, max_rate, opp_dev);136136+ return ret ? ERR_PTR(ret) : d;137137+ }138138+139139+ return ERR_PTR(-EINVAL);140140+}
+67
drivers/clk/tegra/cvb.h
···11+/*22+ * Utility functions for parsing Tegra CVB voltage tables33+ *44+ * This program is free software; you can redistribute it and/or modify55+ * it under the terms of the GNU General Public License version 2 as66+ * published by the Free Software Foundation.77+ *88+ * This program is distributed in the hope that it will be useful, but WITHOUT99+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or1010+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for1111+ * more details.1212+ *1313+ */1414+1515+#ifndef __DRIVERS_CLK_TEGRA_CVB_H1616+#define __DRIVERS_CLK_TEGRA_CVB_H1717+1818+#include <linux/types.h>1919+2020+struct device;2121+2222+#define MAX_DVFS_FREQS 402323+2424+struct rail_alignment {2525+ int offset_uv;2626+ int step_uv;2727+};2828+2929+struct cvb_coefficients {3030+ int c0;3131+ int c1;3232+ int c2;3333+};3434+3535+struct cvb_table_freq_entry {3636+ unsigned long freq;3737+ struct cvb_coefficients coefficients;3838+};3939+4040+struct cvb_cpu_dfll_data {4141+ u32 tune0_low;4242+ u32 tune0_high;4343+ u32 tune1;4444+};4545+4646+struct cvb_table {4747+ int speedo_id;4848+ int process_id;4949+5050+ int min_millivolts;5151+ int max_millivolts;5252+ struct rail_alignment alignment;5353+5454+ int speedo_scale;5555+ int voltage_scale;5656+ struct cvb_table_freq_entry cvb_table[MAX_DVFS_FREQS];5757+ struct cvb_cpu_dfll_data cpu_dfll_data;5858+};5959+6060+const struct cvb_table *tegra_cvb_build_opp_table(6161+ const struct cvb_table *cvb_tables,6262+ size_t sz, int process_id,6363+ int speedo_id, int speedo_value,6464+ unsigned long max_rate,6565+ struct device *opp_dev);6666+6767+#endif