1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
259245ce0STero Kristo /*
359245ce0STero Kristo * OMAP4-specific DPLL control functions
459245ce0STero Kristo *
559245ce0STero Kristo * Copyright (C) 2011 Texas Instruments, Inc.
659245ce0STero Kristo * Rajendra Nayak
759245ce0STero Kristo */
859245ce0STero Kristo
959245ce0STero Kristo #include <linux/kernel.h>
1059245ce0STero Kristo #include <linux/errno.h>
1159245ce0STero Kristo #include <linux/clk.h>
1259245ce0STero Kristo #include <linux/io.h>
1359245ce0STero Kristo #include <linux/bitops.h>
1459245ce0STero Kristo #include <linux/clk/ti.h>
1559245ce0STero Kristo
1659245ce0STero Kristo #include "clock.h"
1759245ce0STero Kristo
1859245ce0STero Kristo /*
1959245ce0STero Kristo * Maximum DPLL input frequency (FINT) and output frequency (FOUT) that
2059245ce0STero Kristo * can supported when using the DPLL low-power mode. Frequencies are
2159245ce0STero Kristo * defined in OMAP4430/60 Public TRM section 3.6.3.3.2 "Enable Control,
2259245ce0STero Kristo * Status, and Low-Power Operation Mode".
2359245ce0STero Kristo */
2459245ce0STero Kristo #define OMAP4_DPLL_LP_FINT_MAX 1000000
2559245ce0STero Kristo #define OMAP4_DPLL_LP_FOUT_MAX 100000000
2659245ce0STero Kristo
2759245ce0STero Kristo /*
2859245ce0STero Kristo * Bitfield declarations
2959245ce0STero Kristo */
3059245ce0STero Kristo #define OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK BIT(8)
3159245ce0STero Kristo #define OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK BIT(10)
3259245ce0STero Kristo #define OMAP4430_DPLL_REGM4XEN_MASK BIT(11)
3359245ce0STero Kristo
3459245ce0STero Kristo /* Static rate multiplier for OMAP4 REGM4XEN clocks */
3559245ce0STero Kristo #define OMAP4430_REGM4XEN_MULT 4
3659245ce0STero Kristo
omap4_dpllmx_allow_gatectrl(struct clk_hw_omap * clk)3759245ce0STero Kristo static void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
3859245ce0STero Kristo {
3959245ce0STero Kristo u32 v;
4059245ce0STero Kristo u32 mask;
4159245ce0STero Kristo
426c0afb50STero Kristo if (!clk)
4359245ce0STero Kristo return;
4459245ce0STero Kristo
4559245ce0STero Kristo mask = clk->flags & CLOCK_CLKOUTX2 ?
4659245ce0STero Kristo OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
4759245ce0STero Kristo OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
4859245ce0STero Kristo
496c0afb50STero Kristo v = ti_clk_ll_ops->clk_readl(&clk->clksel_reg);
5059245ce0STero Kristo /* Clear the bit to allow gatectrl */
5159245ce0STero Kristo v &= ~mask;
526c0afb50STero Kristo ti_clk_ll_ops->clk_writel(v, &clk->clksel_reg);
5359245ce0STero Kristo }
5459245ce0STero Kristo
omap4_dpllmx_deny_gatectrl(struct clk_hw_omap * clk)5559245ce0STero Kristo static void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
5659245ce0STero Kristo {
5759245ce0STero Kristo u32 v;
5859245ce0STero Kristo u32 mask;
5959245ce0STero Kristo
606c0afb50STero Kristo if (!clk)
6159245ce0STero Kristo return;
6259245ce0STero Kristo
6359245ce0STero Kristo mask = clk->flags & CLOCK_CLKOUTX2 ?
6459245ce0STero Kristo OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
6559245ce0STero Kristo OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
6659245ce0STero Kristo
676c0afb50STero Kristo v = ti_clk_ll_ops->clk_readl(&clk->clksel_reg);
6859245ce0STero Kristo /* Set the bit to deny gatectrl */
6959245ce0STero Kristo v |= mask;
706c0afb50STero Kristo ti_clk_ll_ops->clk_writel(v, &clk->clksel_reg);
7159245ce0STero Kristo }
7259245ce0STero Kristo
7359245ce0STero Kristo const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
7459245ce0STero Kristo .allow_idle = omap4_dpllmx_allow_gatectrl,
7559245ce0STero Kristo .deny_idle = omap4_dpllmx_deny_gatectrl,
7659245ce0STero Kristo };
7759245ce0STero Kristo
7859245ce0STero Kristo /**
7959245ce0STero Kristo * omap4_dpll_lpmode_recalc - compute DPLL low-power setting
8059245ce0STero Kristo * @dd: pointer to the dpll data structure
8159245ce0STero Kristo *
8259245ce0STero Kristo * Calculates if low-power mode can be enabled based upon the last
8359245ce0STero Kristo * multiplier and divider values calculated. If low-power mode can be
8459245ce0STero Kristo * enabled, then the bit to enable low-power mode is stored in the
8559245ce0STero Kristo * last_rounded_lpmode variable. This implementation is based upon the
8659245ce0STero Kristo * criteria for enabling low-power mode as described in the OMAP4430/60
8759245ce0STero Kristo * Public TRM section 3.6.3.3.2 "Enable Control, Status, and Low-Power
8859245ce0STero Kristo * Operation Mode".
8959245ce0STero Kristo */
omap4_dpll_lpmode_recalc(struct dpll_data * dd)9059245ce0STero Kristo static void omap4_dpll_lpmode_recalc(struct dpll_data *dd)
9159245ce0STero Kristo {
9259245ce0STero Kristo long fint, fout;
9359245ce0STero Kristo
94b6f51284STero Kristo fint = clk_hw_get_rate(dd->clk_ref) / (dd->last_rounded_n + 1);
9559245ce0STero Kristo fout = fint * dd->last_rounded_m;
9659245ce0STero Kristo
9759245ce0STero Kristo if ((fint < OMAP4_DPLL_LP_FINT_MAX) && (fout < OMAP4_DPLL_LP_FOUT_MAX))
9859245ce0STero Kristo dd->last_rounded_lpmode = 1;
9959245ce0STero Kristo else
10059245ce0STero Kristo dd->last_rounded_lpmode = 0;
10159245ce0STero Kristo }
10259245ce0STero Kristo
10359245ce0STero Kristo /**
10459245ce0STero Kristo * omap4_dpll_regm4xen_recalc - compute DPLL rate, considering REGM4XEN bit
105*d8dbf923SLee Jones * @hw: pointer to the clock to compute the rate for
106*d8dbf923SLee Jones * @parent_rate: clock rate of the DPLL parent
10759245ce0STero Kristo *
10859245ce0STero Kristo * Compute the output rate for the OMAP4 DPLL represented by @clk.
10959245ce0STero Kristo * Takes the REGM4XEN bit into consideration, which is needed for the
11059245ce0STero Kristo * OMAP4 ABE DPLL. Returns the DPLL's output rate (before M-dividers)
11159245ce0STero Kristo * upon success, or 0 upon error.
11259245ce0STero Kristo */
omap4_dpll_regm4xen_recalc(struct clk_hw * hw,unsigned long parent_rate)11359245ce0STero Kristo unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
11459245ce0STero Kristo unsigned long parent_rate)
11559245ce0STero Kristo {
11659245ce0STero Kristo struct clk_hw_omap *clk = to_clk_hw_omap(hw);
11759245ce0STero Kristo u32 v;
11859245ce0STero Kristo unsigned long rate;
11959245ce0STero Kristo struct dpll_data *dd;
12059245ce0STero Kristo
12159245ce0STero Kristo if (!clk || !clk->dpll_data)
12259245ce0STero Kristo return 0;
12359245ce0STero Kristo
12459245ce0STero Kristo dd = clk->dpll_data;
12559245ce0STero Kristo
12659245ce0STero Kristo rate = omap2_get_dpll_rate(clk);
12759245ce0STero Kristo
12859245ce0STero Kristo /* regm4xen adds a multiplier of 4 to DPLL calculations */
1296c0afb50STero Kristo v = ti_clk_ll_ops->clk_readl(&dd->control_reg);
13059245ce0STero Kristo if (v & OMAP4430_DPLL_REGM4XEN_MASK)
13159245ce0STero Kristo rate *= OMAP4430_REGM4XEN_MULT;
13259245ce0STero Kristo
13359245ce0STero Kristo return rate;
13459245ce0STero Kristo }
13559245ce0STero Kristo
13659245ce0STero Kristo /**
13759245ce0STero Kristo * omap4_dpll_regm4xen_round_rate - round DPLL rate, considering REGM4XEN bit
138*d8dbf923SLee Jones * @hw: struct hw_clk containing the struct clk * of the DPLL to round a rate for
13959245ce0STero Kristo * @target_rate: the desired rate of the DPLL
140*d8dbf923SLee Jones * @parent_rate: clock rate of the DPLL parent
14159245ce0STero Kristo *
14259245ce0STero Kristo * Compute the rate that would be programmed into the DPLL hardware
14359245ce0STero Kristo * for @clk if set_rate() were to be provided with the rate
14459245ce0STero Kristo * @target_rate. Takes the REGM4XEN bit into consideration, which is
14559245ce0STero Kristo * needed for the OMAP4 ABE DPLL. Returns the rounded rate (before
14659245ce0STero Kristo * M-dividers) upon success, -EINVAL if @clk is null or not a DPLL, or
14759245ce0STero Kristo * ~0 if an error occurred in omap2_dpll_round_rate().
14859245ce0STero Kristo */
omap4_dpll_regm4xen_round_rate(struct clk_hw * hw,unsigned long target_rate,unsigned long * parent_rate)14959245ce0STero Kristo long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
15059245ce0STero Kristo unsigned long target_rate,
15159245ce0STero Kristo unsigned long *parent_rate)
15259245ce0STero Kristo {
15359245ce0STero Kristo struct clk_hw_omap *clk = to_clk_hw_omap(hw);
15459245ce0STero Kristo struct dpll_data *dd;
15559245ce0STero Kristo long r;
15659245ce0STero Kristo
15759245ce0STero Kristo if (!clk || !clk->dpll_data)
15859245ce0STero Kristo return -EINVAL;
15959245ce0STero Kristo
16059245ce0STero Kristo dd = clk->dpll_data;
16159245ce0STero Kristo
16259245ce0STero Kristo dd->last_rounded_m4xen = 0;
16359245ce0STero Kristo
16459245ce0STero Kristo /*
16559245ce0STero Kristo * First try to compute the DPLL configuration for
16659245ce0STero Kristo * target rate without using the 4X multiplier.
16759245ce0STero Kristo */
16859245ce0STero Kristo r = omap2_dpll_round_rate(hw, target_rate, NULL);
16959245ce0STero Kristo if (r != ~0)
17059245ce0STero Kristo goto out;
17159245ce0STero Kristo
17259245ce0STero Kristo /*
17359245ce0STero Kristo * If we did not find a valid DPLL configuration, try again, but
17459245ce0STero Kristo * this time see if using the 4X multiplier can help. Enabling the
17559245ce0STero Kristo * 4X multiplier is equivalent to dividing the target rate by 4.
17659245ce0STero Kristo */
17759245ce0STero Kristo r = omap2_dpll_round_rate(hw, target_rate / OMAP4430_REGM4XEN_MULT,
17859245ce0STero Kristo NULL);
17959245ce0STero Kristo if (r == ~0)
18059245ce0STero Kristo return r;
18159245ce0STero Kristo
18259245ce0STero Kristo dd->last_rounded_rate *= OMAP4430_REGM4XEN_MULT;
18359245ce0STero Kristo dd->last_rounded_m4xen = 1;
18459245ce0STero Kristo
18559245ce0STero Kristo out:
18659245ce0STero Kristo omap4_dpll_lpmode_recalc(dd);
18759245ce0STero Kristo
18859245ce0STero Kristo return dd->last_rounded_rate;
18959245ce0STero Kristo }
19059245ce0STero Kristo
19159245ce0STero Kristo /**
19259245ce0STero Kristo * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
19359245ce0STero Kristo * @hw: pointer to the clock to determine rate for
1944d341056SStephen Boyd * @req: target rate request
19559245ce0STero Kristo *
19659245ce0STero Kristo * Determines which DPLL mode to use for reaching a desired rate.
19759245ce0STero Kristo * Checks whether the DPLL shall be in bypass or locked mode, and if
19859245ce0STero Kristo * locked, calculates the M,N values for the DPLL via round-rate.
1994d341056SStephen Boyd * Returns 0 on success and a negative error value otherwise.
20059245ce0STero Kristo */
omap4_dpll_regm4xen_determine_rate(struct clk_hw * hw,struct clk_rate_request * req)2014d341056SStephen Boyd int omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
2024d341056SStephen Boyd struct clk_rate_request *req)
20359245ce0STero Kristo {
20459245ce0STero Kristo struct clk_hw_omap *clk = to_clk_hw_omap(hw);
20559245ce0STero Kristo struct dpll_data *dd;
20659245ce0STero Kristo
2074d341056SStephen Boyd if (!req->rate)
20859245ce0STero Kristo return -EINVAL;
20959245ce0STero Kristo
21059245ce0STero Kristo dd = clk->dpll_data;
21159245ce0STero Kristo if (!dd)
21259245ce0STero Kristo return -EINVAL;
21359245ce0STero Kristo
214b6f51284STero Kristo if (clk_hw_get_rate(dd->clk_bypass) == req->rate &&
21559245ce0STero Kristo (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
216b6f51284STero Kristo req->best_parent_hw = dd->clk_bypass;
21759245ce0STero Kristo } else {
2184d341056SStephen Boyd req->rate = omap4_dpll_regm4xen_round_rate(hw, req->rate,
2194d341056SStephen Boyd &req->best_parent_rate);
220b6f51284STero Kristo req->best_parent_hw = dd->clk_ref;
22159245ce0STero Kristo }
22259245ce0STero Kristo
2234d341056SStephen Boyd req->best_parent_rate = req->rate;
22459245ce0STero Kristo
2254d341056SStephen Boyd return 0;
22659245ce0STero Kristo }
227