| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved.
- */
- #include <linux/kernel.h>
- #include <linux/bitops.h>
- #include <linux/err.h>
- #include <linux/bug.h>
- #include <linux/export.h>
- #include <linux/clk.h>
- #include <linux/clk-provider.h>
- #include <linux/delay.h>
- #include <linux/rational.h>
- #include <linux/regmap.h>
- #include <linux/math64.h>
- #include <linux/gcd.h>
- #include <linux/minmax.h>
- #include <linux/slab.h>
- #include <asm/div64.h>
- #include "clk-rcg.h"
- #include "common.h"
- #define CMD_REG 0x0
- #define CMD_UPDATE BIT(0)
- #define CMD_ROOT_EN BIT(1)
- #define CMD_DIRTY_CFG BIT(4)
- #define CMD_DIRTY_N BIT(5)
- #define CMD_DIRTY_M BIT(6)
- #define CMD_DIRTY_D BIT(7)
- #define CMD_ROOT_OFF BIT(31)
- #define CFG_REG 0x4
- #define CFG_SRC_DIV_SHIFT 0
- #define CFG_SRC_DIV_LENGTH 8
- #define CFG_SRC_SEL_SHIFT 8
- #define CFG_SRC_SEL_MASK (0x7 << CFG_SRC_SEL_SHIFT)
- #define CFG_MODE_SHIFT 12
- #define CFG_MODE_MASK (0x3 << CFG_MODE_SHIFT)
- #define CFG_MODE_DUAL_EDGE (0x2 << CFG_MODE_SHIFT)
- #define CFG_HW_CLK_CTRL_MASK BIT(20)
- #define M_REG 0x8
- #define N_REG 0xc
- #define D_REG 0x10
- #define RCG_CFG_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + CFG_REG)
- #define RCG_M_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + M_REG)
- #define RCG_N_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + N_REG)
- #define RCG_D_OFFSET(rcg) ((rcg)->cmd_rcgr + (rcg)->cfg_off + D_REG)
- /* Dynamic Frequency Scaling */
- #define MAX_PERF_LEVEL 8
- #define SE_CMD_DFSR_OFFSET 0x14
- #define SE_CMD_DFS_EN BIT(0)
- #define SE_PERF_DFSR(level) (0x1c + 0x4 * (level))
- #define SE_PERF_M_DFSR(level) (0x5c + 0x4 * (level))
- #define SE_PERF_N_DFSR(level) (0x9c + 0x4 * (level))
- enum freq_policy {
- FLOOR,
- CEIL,
- };
- static int clk_rcg2_is_enabled(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 cmd;
- int ret;
- ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
- if (ret)
- return ret;
- return (cmd & CMD_ROOT_OFF) == 0;
- }
- static u8 __clk_rcg2_get_parent(struct clk_hw *hw, u32 cfg)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int num_parents = clk_hw_get_num_parents(hw);
- int i;
- cfg &= CFG_SRC_SEL_MASK;
- cfg >>= CFG_SRC_SEL_SHIFT;
- for (i = 0; i < num_parents; i++)
- if (cfg == rcg->parent_map[i].cfg)
- return i;
- pr_debug("%s: Clock %s has invalid parent, using default.\n",
- __func__, clk_hw_get_name(hw));
- return 0;
- }
- static u8 clk_rcg2_get_parent(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 cfg;
- int ret;
- ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
- if (ret) {
- pr_debug("%s: Unable to read CFG register for %s\n",
- __func__, clk_hw_get_name(hw));
- return 0;
- }
- return __clk_rcg2_get_parent(hw, cfg);
- }
- static int update_config(struct clk_rcg2 *rcg)
- {
- int count, ret;
- u32 cmd;
- struct clk_hw *hw = &rcg->clkr.hw;
- const char *name = clk_hw_get_name(hw);
- ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
- CMD_UPDATE, CMD_UPDATE);
- if (ret)
- return ret;
- /* Wait for update to take effect */
- for (count = 500; count > 0; count--) {
- ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
- if (ret)
- return ret;
- if (!(cmd & CMD_UPDATE))
- return 0;
- udelay(1);
- }
- WARN(1, "%s: rcg didn't update its configuration.", name);
- return -EBUSY;
- }
- static int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int ret;
- u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
- ret = regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg),
- CFG_SRC_SEL_MASK, cfg);
- if (ret)
- return ret;
- return update_config(rcg);
- }
- /**
- * convert_to_reg_val() - Convert divisor values to hardware values.
- *
- * @f: Frequency table with pure m/n/pre_div parameters.
- */
- static void convert_to_reg_val(struct freq_tbl *f)
- {
- f->pre_div *= 2;
- f->pre_div -= 1;
- }
- /**
- * calc_rate() - Calculate rate based on m/n:d values
- *
- * @rate: Parent rate.
- * @m: Multiplier.
- * @n: Divisor.
- * @mode: Use zero to ignore m/n calculation.
- * @hid_div: Pre divisor register value. Pre divisor value
- * relates to hid_div as pre_div = (hid_div + 1) / 2.
- *
- * Return calculated rate according to formula:
- *
- * parent_rate m
- * rate = ----------- x ---
- * pre_div n
- */
- static unsigned long
- calc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
- {
- if (hid_div)
- rate = mult_frac(rate, 2, hid_div + 1);
- if (mode)
- rate = mult_frac(rate, m, n);
- return rate;
- }
- static unsigned long
- __clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate, u32 cfg)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 hid_div, m = 0, n = 0, mode = 0, mask;
- if (rcg->mnd_width) {
- mask = BIT(rcg->mnd_width) - 1;
- regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m);
- m &= mask;
- regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &n);
- n = ~n;
- n &= mask;
- n += m;
- mode = cfg & CFG_MODE_MASK;
- mode >>= CFG_MODE_SHIFT;
- }
- mask = BIT(rcg->hid_width) - 1;
- hid_div = cfg >> CFG_SRC_DIV_SHIFT;
- hid_div &= mask;
- return calc_rate(parent_rate, m, n, mode, hid_div);
- }
- static unsigned long
- clk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 cfg;
- regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
- return __clk_rcg2_recalc_rate(hw, parent_rate, cfg);
- }
- static int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
- struct clk_rate_request *req,
- enum freq_policy policy)
- {
- unsigned long clk_flags, rate = req->rate;
- struct clk_hw *p;
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int index;
- switch (policy) {
- case FLOOR:
- f = qcom_find_freq_floor(f, rate);
- break;
- case CEIL:
- f = qcom_find_freq(f, rate);
- break;
- default:
- return -EINVAL;
- }
- if (!f)
- return -EINVAL;
- index = qcom_find_src_index(hw, rcg->parent_map, f->src);
- if (index < 0)
- return index;
- clk_flags = clk_hw_get_flags(hw);
- p = clk_hw_get_parent_by_index(hw, index);
- if (!p)
- return -EINVAL;
- if (clk_flags & CLK_SET_RATE_PARENT) {
- rate = f->freq;
- if (f->pre_div) {
- if (!rate)
- rate = req->rate;
- rate /= 2;
- rate *= f->pre_div + 1;
- }
- if (f->n) {
- u64 tmp = rate;
- tmp = tmp * f->n;
- do_div(tmp, f->m);
- rate = tmp;
- }
- } else {
- rate = clk_hw_get_rate(p);
- }
- req->best_parent_hw = p;
- req->best_parent_rate = rate;
- req->rate = f->freq;
- return 0;
- }
- static const struct freq_conf *
- __clk_rcg2_select_conf(struct clk_hw *hw, const struct freq_multi_tbl *f,
- unsigned long req_rate)
- {
- unsigned long rate_diff, best_rate_diff = ULONG_MAX;
- const struct freq_conf *conf, *best_conf = NULL;
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const char *name = clk_hw_get_name(hw);
- unsigned long parent_rate, rate;
- struct clk_hw *p;
- int index, i;
- /* Exit early if only one config is defined */
- if (f->num_confs == 1) {
- best_conf = f->confs;
- goto exit;
- }
- /* Search in each provided config the one that is near the wanted rate */
- for (i = 0, conf = f->confs; i < f->num_confs; i++, conf++) {
- index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
- if (index < 0)
- continue;
- p = clk_hw_get_parent_by_index(hw, index);
- if (!p)
- continue;
- parent_rate = clk_hw_get_rate(p);
- rate = calc_rate(parent_rate, conf->n, conf->m, conf->n, conf->pre_div);
- if (rate == req_rate) {
- best_conf = conf;
- goto exit;
- }
- rate_diff = abs_diff(req_rate, rate);
- if (rate_diff < best_rate_diff) {
- best_rate_diff = rate_diff;
- best_conf = conf;
- }
- }
- /*
- * Very unlikely. Warn if we couldn't find a correct config
- * due to parent not found in every config.
- */
- if (unlikely(!best_conf)) {
- WARN(1, "%s: can't find a configuration for rate %lu\n",
- name, req_rate);
- return ERR_PTR(-EINVAL);
- }
- exit:
- return best_conf;
- }
- static int _freq_tbl_fm_determine_rate(struct clk_hw *hw, const struct freq_multi_tbl *f,
- struct clk_rate_request *req)
- {
- unsigned long clk_flags, rate = req->rate;
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_conf *conf;
- struct clk_hw *p;
- int index;
- f = qcom_find_freq_multi(f, rate);
- if (!f || !f->confs)
- return -EINVAL;
- conf = __clk_rcg2_select_conf(hw, f, rate);
- if (IS_ERR(conf))
- return PTR_ERR(conf);
- index = qcom_find_src_index(hw, rcg->parent_map, conf->src);
- if (index < 0)
- return index;
- clk_flags = clk_hw_get_flags(hw);
- p = clk_hw_get_parent_by_index(hw, index);
- if (!p)
- return -EINVAL;
- if (clk_flags & CLK_SET_RATE_PARENT) {
- rate = f->freq;
- if (conf->pre_div) {
- if (!rate)
- rate = req->rate;
- rate /= 2;
- rate *= conf->pre_div + 1;
- }
- if (conf->n) {
- u64 tmp = rate;
- tmp = tmp * conf->n;
- do_div(tmp, conf->m);
- rate = tmp;
- }
- } else {
- rate = clk_hw_get_rate(p);
- }
- req->best_parent_hw = p;
- req->best_parent_rate = rate;
- req->rate = f->freq;
- return 0;
- }
- static int clk_rcg2_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, CEIL);
- }
- static int clk_rcg2_determine_floor_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, FLOOR);
- }
- static int clk_rcg2_fm_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- return _freq_tbl_fm_determine_rate(hw, rcg->freq_multi_tbl, req);
- }
- /**
- * clk_rcg2_split_div() - Split multiplier that doesn't fit in n neither in pre_div.
- *
- * @multiplier: Multiplier to split between n and pre_div.
- * @pre_div: Pointer to pre divisor value.
- * @n: Pointer to n divisor value.
- * @pre_div_max: Pre divisor maximum value.
- */
- static inline void clk_rcg2_split_div(int multiplier, unsigned int *pre_div,
- u16 *n, unsigned int pre_div_max)
- {
- *n = mult_frac(multiplier * *n, *pre_div, pre_div_max);
- *pre_div = pre_div_max;
- }
- static void clk_rcg2_calc_mnd(u64 parent_rate, u64 rate, struct freq_tbl *f,
- unsigned int mnd_max, unsigned int pre_div_max)
- {
- int i = 2;
- unsigned int pre_div = 1;
- unsigned long rates_gcd, scaled_parent_rate;
- u16 m, n = 1, n_candidate = 1, n_max;
- rates_gcd = gcd(parent_rate, rate);
- m = div64_u64(rate, rates_gcd);
- scaled_parent_rate = div64_u64(parent_rate, rates_gcd);
- while (scaled_parent_rate > (mnd_max + m) * pre_div_max) {
- // we're exceeding divisor's range, trying lower scale.
- if (m > 1) {
- m--;
- scaled_parent_rate = mult_frac(scaled_parent_rate, m, (m + 1));
- } else {
- // cannot lower scale, just set max divisor values.
- f->n = mnd_max + m;
- f->pre_div = pre_div_max;
- f->m = m;
- return;
- }
- }
- n_max = m + mnd_max;
- while (scaled_parent_rate > 1) {
- while (scaled_parent_rate % i == 0) {
- n_candidate *= i;
- if (n_candidate < n_max)
- n = n_candidate;
- else if (pre_div * i < pre_div_max)
- pre_div *= i;
- else
- clk_rcg2_split_div(i, &pre_div, &n, pre_div_max);
- scaled_parent_rate /= i;
- }
- i++;
- }
- f->m = m;
- f->n = n;
- f->pre_div = pre_div > 1 ? pre_div : 0;
- }
- static int clk_rcg2_determine_gp_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct freq_tbl f_tbl = {}, *f = &f_tbl;
- int mnd_max = BIT(rcg->mnd_width) - 1;
- int hid_max = BIT(rcg->hid_width) - 1;
- struct clk_hw *parent;
- u64 parent_rate;
- parent = clk_hw_get_parent(hw);
- parent_rate = clk_get_rate(parent->clk);
- if (!parent_rate)
- return -EINVAL;
- clk_rcg2_calc_mnd(parent_rate, req->rate, f, mnd_max, hid_max / 2);
- convert_to_reg_val(f);
- req->rate = calc_rate(parent_rate, f->m, f->n, f->n, f->pre_div);
- return 0;
- }
- static int __clk_rcg2_configure_parent(struct clk_rcg2 *rcg, u8 src, u32 *_cfg)
- {
- struct clk_hw *hw = &rcg->clkr.hw;
- int index = qcom_find_src_index(hw, rcg->parent_map, src);
- if (index < 0)
- return index;
- *_cfg &= ~CFG_SRC_SEL_MASK;
- *_cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
- return 0;
- }
- static int __clk_rcg2_configure_mnd(struct clk_rcg2 *rcg, const struct freq_tbl *f,
- u32 *_cfg)
- {
- u32 cfg, mask, d_val, not2d_val, n_minus_m;
- int ret;
- if (rcg->mnd_width && f->n) {
- mask = BIT(rcg->mnd_width) - 1;
- ret = regmap_update_bits(rcg->clkr.regmap,
- RCG_M_OFFSET(rcg), mask, f->m);
- if (ret)
- return ret;
- ret = regmap_update_bits(rcg->clkr.regmap,
- RCG_N_OFFSET(rcg), mask, ~(f->n - f->m));
- if (ret)
- return ret;
- /* Calculate 2d value */
- d_val = f->n;
- n_minus_m = f->n - f->m;
- n_minus_m *= 2;
- d_val = clamp_t(u32, d_val, f->m, n_minus_m);
- not2d_val = ~d_val & mask;
- ret = regmap_update_bits(rcg->clkr.regmap,
- RCG_D_OFFSET(rcg), mask, not2d_val);
- if (ret)
- return ret;
- }
- mask = BIT(rcg->hid_width) - 1;
- mask |= CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK;
- cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
- if (rcg->mnd_width && f->n && (f->m != f->n))
- cfg |= CFG_MODE_DUAL_EDGE;
- if (rcg->hw_clk_ctrl)
- cfg |= CFG_HW_CLK_CTRL_MASK;
- *_cfg &= ~mask;
- *_cfg |= cfg;
- return 0;
- }
- static int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f,
- u32 *_cfg)
- {
- int ret;
- ret = __clk_rcg2_configure_parent(rcg, f->src, _cfg);
- if (ret)
- return ret;
- ret = __clk_rcg2_configure_mnd(rcg, f, _cfg);
- if (ret)
- return ret;
- return 0;
- }
- static int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
- {
- u32 cfg;
- int ret;
- ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
- if (ret)
- return ret;
- ret = __clk_rcg2_configure(rcg, f, &cfg);
- if (ret)
- return ret;
- ret = regmap_write(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), cfg);
- if (ret)
- return ret;
- return update_config(rcg);
- }
- static int clk_rcg2_configure_gp(struct clk_rcg2 *rcg, const struct freq_tbl *f)
- {
- u32 cfg;
- int ret;
- ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
- if (ret)
- return ret;
- ret = __clk_rcg2_configure_mnd(rcg, f, &cfg);
- if (ret)
- return ret;
- ret = regmap_write(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), cfg);
- if (ret)
- return ret;
- return update_config(rcg);
- }
- static int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
- enum freq_policy policy)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_tbl *f;
- switch (policy) {
- case FLOOR:
- f = qcom_find_freq_floor(rcg->freq_tbl, rate);
- break;
- case CEIL:
- f = qcom_find_freq(rcg->freq_tbl, rate);
- break;
- default:
- return -EINVAL;
- }
- if (!f)
- return -EINVAL;
- return clk_rcg2_configure(rcg, f);
- }
- static int __clk_rcg2_fm_set_rate(struct clk_hw *hw, unsigned long rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_multi_tbl *f;
- const struct freq_conf *conf;
- struct freq_tbl f_tbl = {};
- f = qcom_find_freq_multi(rcg->freq_multi_tbl, rate);
- if (!f || !f->confs)
- return -EINVAL;
- conf = __clk_rcg2_select_conf(hw, f, rate);
- if (IS_ERR(conf))
- return PTR_ERR(conf);
- f_tbl.freq = f->freq;
- f_tbl.src = conf->src;
- f_tbl.pre_div = conf->pre_div;
- f_tbl.m = conf->m;
- f_tbl.n = conf->n;
- return clk_rcg2_configure(rcg, &f_tbl);
- }
- static int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- return __clk_rcg2_set_rate(hw, rate, CEIL);
- }
- static int clk_rcg2_set_gp_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int mnd_max = BIT(rcg->mnd_width) - 1;
- int hid_max = BIT(rcg->hid_width) - 1;
- struct freq_tbl f_tbl = {}, *f = &f_tbl;
- int ret;
- clk_rcg2_calc_mnd(parent_rate, rate, f, mnd_max, hid_max / 2);
- convert_to_reg_val(f);
- ret = clk_rcg2_configure_gp(rcg, f);
- return ret;
- }
- static int clk_rcg2_set_floor_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- return __clk_rcg2_set_rate(hw, rate, FLOOR);
- }
- static int clk_rcg2_fm_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- return __clk_rcg2_fm_set_rate(hw, rate);
- }
- static int clk_rcg2_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- return __clk_rcg2_set_rate(hw, rate, CEIL);
- }
- static int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- return __clk_rcg2_set_rate(hw, rate, FLOOR);
- }
- static int clk_rcg2_fm_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- return __clk_rcg2_fm_set_rate(hw, rate);
- }
- static int clk_rcg2_get_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 notn_m, n, m, d, not2d, mask;
- if (!rcg->mnd_width) {
- /* 50 % duty-cycle for Non-MND RCGs */
- duty->num = 1;
- duty->den = 2;
- return 0;
- }
- regmap_read(rcg->clkr.regmap, RCG_D_OFFSET(rcg), ¬2d);
- regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m);
- regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), ¬n_m);
- if (!not2d && !m && !notn_m) {
- /* 50 % duty-cycle always */
- duty->num = 1;
- duty->den = 2;
- return 0;
- }
- mask = BIT(rcg->mnd_width) - 1;
- d = ~(not2d) & mask;
- d = DIV_ROUND_CLOSEST(d, 2);
- n = (~(notn_m) + m) & mask;
- duty->num = d;
- duty->den = n;
- return 0;
- }
- static int clk_rcg2_set_duty_cycle(struct clk_hw *hw, struct clk_duty *duty)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 notn_m, n, m, d, not2d, mask, cfg;
- int ret;
- /* Duty-cycle cannot be modified for non-MND RCGs */
- if (!rcg->mnd_width)
- return -EINVAL;
- mask = BIT(rcg->mnd_width) - 1;
- regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), ¬n_m);
- regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m);
- regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
- /* Duty-cycle cannot be modified if MND divider is in bypass mode. */
- if (!(cfg & CFG_MODE_MASK))
- return -EINVAL;
- n = (~(notn_m) + m) & mask;
- /* Calculate 2d value */
- d = DIV_ROUND_CLOSEST(n * duty->num * 2, duty->den);
- /*
- * Check bit widths of 2d. If D is too big reduce duty cycle.
- * Also make sure it is never zero.
- */
- d = clamp_val(d, 1, mask);
- if ((d / 2) > (n - m))
- d = (n - m) * 2;
- else if ((d / 2) < (m / 2))
- d = m;
- not2d = ~d & mask;
- ret = regmap_update_bits(rcg->clkr.regmap, RCG_D_OFFSET(rcg), mask,
- not2d);
- if (ret)
- return ret;
- return update_config(rcg);
- }
- const struct clk_ops clk_rcg2_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .determine_rate = clk_rcg2_determine_rate,
- .set_rate = clk_rcg2_set_rate,
- .set_rate_and_parent = clk_rcg2_set_rate_and_parent,
- .get_duty_cycle = clk_rcg2_get_duty_cycle,
- .set_duty_cycle = clk_rcg2_set_duty_cycle,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_ops);
- const struct clk_ops clk_rcg2_gp_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .determine_rate = clk_rcg2_determine_gp_rate,
- .set_rate = clk_rcg2_set_gp_rate,
- .get_duty_cycle = clk_rcg2_get_duty_cycle,
- .set_duty_cycle = clk_rcg2_set_duty_cycle,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_gp_ops);
- const struct clk_ops clk_rcg2_floor_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .determine_rate = clk_rcg2_determine_floor_rate,
- .set_rate = clk_rcg2_set_floor_rate,
- .set_rate_and_parent = clk_rcg2_set_floor_rate_and_parent,
- .get_duty_cycle = clk_rcg2_get_duty_cycle,
- .set_duty_cycle = clk_rcg2_set_duty_cycle,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
- const struct clk_ops clk_rcg2_fm_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .determine_rate = clk_rcg2_fm_determine_rate,
- .set_rate = clk_rcg2_fm_set_rate,
- .set_rate_and_parent = clk_rcg2_fm_set_rate_and_parent,
- .get_duty_cycle = clk_rcg2_get_duty_cycle,
- .set_duty_cycle = clk_rcg2_set_duty_cycle,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_fm_ops);
- const struct clk_ops clk_rcg2_mux_closest_ops = {
- .determine_rate = __clk_mux_determine_rate_closest,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_mux_closest_ops);
- struct frac_entry {
- int num;
- int den;
- };
- static const struct frac_entry frac_table_675m[] = { /* link rate of 270M */
- { 52, 295 }, /* 119 M */
- { 11, 57 }, /* 130.25 M */
- { 63, 307 }, /* 138.50 M */
- { 11, 50 }, /* 148.50 M */
- { 47, 206 }, /* 154 M */
- { 31, 100 }, /* 205.25 M */
- { 107, 269 }, /* 268.50 M */
- { },
- };
- static struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
- { 31, 211 }, /* 119 M */
- { 32, 199 }, /* 130.25 M */
- { 63, 307 }, /* 138.50 M */
- { 11, 60 }, /* 148.50 M */
- { 50, 263 }, /* 154 M */
- { 31, 120 }, /* 205.25 M */
- { 119, 359 }, /* 268.50 M */
- { },
- };
- static int clk_edp_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct freq_tbl f = *rcg->freq_tbl;
- const struct frac_entry *frac;
- int delta = 100000;
- s64 src_rate = parent_rate;
- s64 request;
- u32 mask = BIT(rcg->hid_width) - 1;
- u32 hid_div;
- if (src_rate == 810000000)
- frac = frac_table_810m;
- else
- frac = frac_table_675m;
- for (; frac->num; frac++) {
- request = rate;
- request *= frac->den;
- request = div_s64(request, frac->num);
- if ((src_rate < (request - delta)) ||
- (src_rate > (request + delta)))
- continue;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
- &hid_div);
- f.pre_div = hid_div;
- f.pre_div >>= CFG_SRC_DIV_SHIFT;
- f.pre_div &= mask;
- f.m = frac->num;
- f.n = frac->den;
- return clk_rcg2_configure(rcg, &f);
- }
- return -EINVAL;
- }
- static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- /* Parent index is set statically in frequency table */
- return clk_edp_pixel_set_rate(hw, rate, parent_rate);
- }
- static int clk_edp_pixel_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_tbl *f = rcg->freq_tbl;
- const struct frac_entry *frac;
- int delta = 100000;
- s64 request;
- u32 mask = BIT(rcg->hid_width) - 1;
- u32 hid_div;
- int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
- /* Force the correct parent */
- req->best_parent_hw = clk_hw_get_parent_by_index(hw, index);
- req->best_parent_rate = clk_hw_get_rate(req->best_parent_hw);
- if (req->best_parent_rate == 810000000)
- frac = frac_table_810m;
- else
- frac = frac_table_675m;
- for (; frac->num; frac++) {
- request = req->rate;
- request *= frac->den;
- request = div_s64(request, frac->num);
- if ((req->best_parent_rate < (request - delta)) ||
- (req->best_parent_rate > (request + delta)))
- continue;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
- &hid_div);
- hid_div >>= CFG_SRC_DIV_SHIFT;
- hid_div &= mask;
- req->rate = calc_rate(req->best_parent_rate,
- frac->num, frac->den,
- !!frac->den, hid_div);
- return 0;
- }
- return -EINVAL;
- }
- const struct clk_ops clk_edp_pixel_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .set_rate = clk_edp_pixel_set_rate,
- .set_rate_and_parent = clk_edp_pixel_set_rate_and_parent,
- .determine_rate = clk_edp_pixel_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
- static int clk_byte_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_tbl *f = rcg->freq_tbl;
- int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
- unsigned long parent_rate, div;
- u32 mask = BIT(rcg->hid_width) - 1;
- struct clk_hw *p;
- if (req->rate == 0)
- return -EINVAL;
- req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
- req->best_parent_rate = parent_rate = clk_hw_round_rate(p, req->rate);
- div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1;
- div = min_t(u32, div, mask);
- req->rate = calc_rate(parent_rate, 0, 0, 0, div);
- return 0;
- }
- static int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct freq_tbl f = *rcg->freq_tbl;
- unsigned long div;
- u32 mask = BIT(rcg->hid_width) - 1;
- div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
- div = min_t(u32, div, mask);
- f.pre_div = div;
- return clk_rcg2_configure(rcg, &f);
- }
- static int clk_byte_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- /* Parent index is set statically in frequency table */
- return clk_byte_set_rate(hw, rate, parent_rate);
- }
- const struct clk_ops clk_byte_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .set_rate = clk_byte_set_rate,
- .set_rate_and_parent = clk_byte_set_rate_and_parent,
- .determine_rate = clk_byte_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_byte_ops);
- static int clk_byte2_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- unsigned long parent_rate, div;
- u32 mask = BIT(rcg->hid_width) - 1;
- struct clk_hw *p;
- unsigned long rate = req->rate;
- if (rate == 0)
- return -EINVAL;
- p = req->best_parent_hw;
- req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate);
- div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
- div = min_t(u32, div, mask);
- req->rate = calc_rate(parent_rate, 0, 0, 0, div);
- return 0;
- }
- static int clk_byte2_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct freq_tbl f = { 0 };
- unsigned long div;
- int i, num_parents = clk_hw_get_num_parents(hw);
- u32 mask = BIT(rcg->hid_width) - 1;
- u32 cfg;
- div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
- div = min_t(u32, div, mask);
- f.pre_div = div;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
- cfg &= CFG_SRC_SEL_MASK;
- cfg >>= CFG_SRC_SEL_SHIFT;
- for (i = 0; i < num_parents; i++) {
- if (cfg == rcg->parent_map[i].cfg) {
- f.src = rcg->parent_map[i].src;
- return clk_rcg2_configure(rcg, &f);
- }
- }
- return -EINVAL;
- }
- static int clk_byte2_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- /* Read the hardware to determine parent during set_rate */
- return clk_byte2_set_rate(hw, rate, parent_rate);
- }
- const struct clk_ops clk_byte2_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .set_rate = clk_byte2_set_rate,
- .set_rate_and_parent = clk_byte2_set_rate_and_parent,
- .determine_rate = clk_byte2_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_byte2_ops);
- static const struct frac_entry frac_table_pixel[] = {
- { 3, 8 },
- { 2, 9 },
- { 4, 9 },
- { 1, 1 },
- { 2, 3 },
- { }
- };
- static int clk_pixel_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- unsigned long request, src_rate;
- int delta = 100000;
- const struct frac_entry *frac = frac_table_pixel;
- for (; frac->num; frac++) {
- request = (req->rate * frac->den) / frac->num;
- src_rate = clk_hw_round_rate(req->best_parent_hw, request);
- if ((src_rate < (request - delta)) ||
- (src_rate > (request + delta)))
- continue;
- req->best_parent_rate = src_rate;
- req->rate = (src_rate * frac->num) / frac->den;
- return 0;
- }
- return -EINVAL;
- }
- static int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct freq_tbl f = { 0 };
- const struct frac_entry *frac = frac_table_pixel;
- unsigned long request;
- int delta = 100000;
- u32 mask = BIT(rcg->hid_width) - 1;
- u32 hid_div, cfg;
- int i, num_parents = clk_hw_get_num_parents(hw);
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
- cfg &= CFG_SRC_SEL_MASK;
- cfg >>= CFG_SRC_SEL_SHIFT;
- for (i = 0; i < num_parents; i++)
- if (cfg == rcg->parent_map[i].cfg) {
- f.src = rcg->parent_map[i].src;
- break;
- }
- for (; frac->num; frac++) {
- request = (rate * frac->den) / frac->num;
- if ((parent_rate < (request - delta)) ||
- (parent_rate > (request + delta)))
- continue;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
- &hid_div);
- f.pre_div = hid_div;
- f.pre_div >>= CFG_SRC_DIV_SHIFT;
- f.pre_div &= mask;
- f.m = frac->num;
- f.n = frac->den;
- return clk_rcg2_configure(rcg, &f);
- }
- return -EINVAL;
- }
- static int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate, u8 index)
- {
- return clk_pixel_set_rate(hw, rate, parent_rate);
- }
- const struct clk_ops clk_pixel_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .set_rate = clk_pixel_set_rate,
- .set_rate_and_parent = clk_pixel_set_rate_and_parent,
- .determine_rate = clk_pixel_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_pixel_ops);
- static int clk_gfx3d_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rate_request parent_req = { .min_rate = 0, .max_rate = ULONG_MAX };
- struct clk_rcg2_gfx3d *cgfx = to_clk_rcg2_gfx3d(hw);
- struct clk_hw *xo, *p0, *p1, *p2;
- unsigned long p0_rate;
- u8 mux_div = cgfx->div;
- int ret;
- p0 = cgfx->hws[0];
- p1 = cgfx->hws[1];
- p2 = cgfx->hws[2];
- /*
- * This function does ping-pong the RCG between PLLs: if we don't
- * have at least one fixed PLL and two variable ones,
- * then it's not going to work correctly.
- */
- if (WARN_ON(!p0 || !p1 || !p2))
- return -EINVAL;
- xo = clk_hw_get_parent_by_index(hw, 0);
- if (req->rate == clk_hw_get_rate(xo)) {
- req->best_parent_hw = xo;
- return 0;
- }
- if (mux_div == 0)
- mux_div = 1;
- parent_req.rate = req->rate * mux_div;
- /* This has to be a fixed rate PLL */
- p0_rate = clk_hw_get_rate(p0);
- if (parent_req.rate == p0_rate) {
- req->rate = req->best_parent_rate = p0_rate;
- req->best_parent_hw = p0;
- return 0;
- }
- if (req->best_parent_hw == p0) {
- /* Are we going back to a previously used rate? */
- if (clk_hw_get_rate(p2) == parent_req.rate)
- req->best_parent_hw = p2;
- else
- req->best_parent_hw = p1;
- } else if (req->best_parent_hw == p2) {
- req->best_parent_hw = p1;
- } else {
- req->best_parent_hw = p2;
- }
- clk_hw_get_rate_range(req->best_parent_hw,
- &parent_req.min_rate, &parent_req.max_rate);
- if (req->min_rate > parent_req.min_rate)
- parent_req.min_rate = req->min_rate;
- if (req->max_rate < parent_req.max_rate)
- parent_req.max_rate = req->max_rate;
- parent_req.best_parent_hw = req->best_parent_hw;
- ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
- if (ret)
- return ret;
- req->rate = req->best_parent_rate = parent_req.rate;
- req->rate /= mux_div;
- return 0;
- }
- static int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate, u8 index)
- {
- struct clk_rcg2_gfx3d *cgfx = to_clk_rcg2_gfx3d(hw);
- struct clk_rcg2 *rcg = &cgfx->rcg;
- u32 cfg;
- int ret;
- cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
- /* On some targets, the GFX3D RCG may need to divide PLL frequency */
- if (cgfx->div > 1)
- cfg |= ((2 * cgfx->div) - 1) << CFG_SRC_DIV_SHIFT;
- ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
- if (ret)
- return ret;
- return update_config(rcg);
- }
- static int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- /*
- * We should never get here; clk_gfx3d_determine_rate() should always
- * make us use a different parent than what we're currently using, so
- * clk_gfx3d_set_rate_and_parent() should always be called.
- */
- return 0;
- }
- const struct clk_ops clk_gfx3d_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .set_rate = clk_gfx3d_set_rate,
- .set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
- .determine_rate = clk_gfx3d_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_gfx3d_ops);
- static int clk_rcg2_set_force_enable(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const char *name = clk_hw_get_name(hw);
- int ret, count;
- ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
- CMD_ROOT_EN, CMD_ROOT_EN);
- if (ret)
- return ret;
- /* wait for RCG to turn ON */
- for (count = 500; count > 0; count--) {
- if (clk_rcg2_is_enabled(hw))
- return 0;
- udelay(1);
- }
- pr_err("%s: RCG did not turn on\n", name);
- return -ETIMEDOUT;
- }
- static int clk_rcg2_clear_force_enable(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
- CMD_ROOT_EN, 0);
- }
- static int
- clk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int ret;
- ret = clk_rcg2_set_force_enable(hw);
- if (ret)
- return ret;
- ret = clk_rcg2_configure(rcg, f);
- if (ret)
- return ret;
- return clk_rcg2_clear_force_enable(hw);
- }
- static int __clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate,
- enum freq_policy policy)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- const struct freq_tbl *f;
- switch (policy) {
- case FLOOR:
- f = qcom_find_freq_floor(rcg->freq_tbl, rate);
- break;
- case CEIL:
- f = qcom_find_freq(rcg->freq_tbl, rate);
- break;
- default:
- return -EINVAL;
- }
- /*
- * In case clock is disabled, update the M, N and D registers, cache
- * the CFG value in parked_cfg and don't hit the update bit of CMD
- * register.
- */
- if (!clk_hw_is_enabled(hw))
- return __clk_rcg2_configure(rcg, f, &rcg->parked_cfg);
- return clk_rcg2_shared_force_enable_clear(hw, f);
- }
- static int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, CEIL);
- }
- static int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, CEIL);
- }
- static int clk_rcg2_shared_set_floor_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, FLOOR);
- }
- static int clk_rcg2_shared_set_floor_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- return __clk_rcg2_shared_set_rate(hw, rate, parent_rate, FLOOR);
- }
- static int clk_rcg2_shared_enable(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int ret;
- /*
- * Set the update bit because required configuration has already
- * been written in clk_rcg2_shared_set_rate()
- */
- ret = clk_rcg2_set_force_enable(hw);
- if (ret)
- return ret;
- /* Write back the stored configuration corresponding to current rate */
- ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, rcg->parked_cfg);
- if (ret)
- return ret;
- ret = update_config(rcg);
- if (ret)
- return ret;
- return clk_rcg2_clear_force_enable(hw);
- }
- static void clk_rcg2_shared_disable(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- /*
- * Store current configuration as switching to safe source would clear
- * the SRC and DIV of CFG register
- */
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &rcg->parked_cfg);
- /*
- * Park the RCG at a safe configuration - sourced off of safe source.
- * Force enable and disable the RCG while configuring it to safeguard
- * against any update signal coming from the downstream clock.
- * The current parent is still prepared and enabled at this point, and
- * the safe source is always on while application processor subsystem
- * is online. Therefore, the RCG can safely switch its parent.
- */
- clk_rcg2_set_force_enable(hw);
- regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
- rcg->safe_src_index << CFG_SRC_SEL_SHIFT);
- update_config(rcg);
- clk_rcg2_clear_force_enable(hw);
- }
- static u8 clk_rcg2_shared_get_parent(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- /* If the shared rcg is parked use the cached cfg instead */
- if (!clk_hw_is_enabled(hw))
- return __clk_rcg2_get_parent(hw, rcg->parked_cfg);
- return clk_rcg2_get_parent(hw);
- }
- static int clk_rcg2_shared_set_parent(struct clk_hw *hw, u8 index)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- /* If the shared rcg is parked only update the cached cfg */
- if (!clk_hw_is_enabled(hw)) {
- rcg->parked_cfg &= ~CFG_SRC_SEL_MASK;
- rcg->parked_cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
- return 0;
- }
- return clk_rcg2_set_parent(hw, index);
- }
- static unsigned long
- clk_rcg2_shared_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- /* If the shared rcg is parked use the cached cfg instead */
- if (!clk_hw_is_enabled(hw))
- return __clk_rcg2_recalc_rate(hw, parent_rate, rcg->parked_cfg);
- return clk_rcg2_recalc_rate(hw, parent_rate);
- }
- static int clk_rcg2_shared_init(struct clk_hw *hw)
- {
- /*
- * This does a few things:
- *
- * 1. Sets rcg->parked_cfg to reflect the value at probe so that the
- * proper parent is reported from clk_rcg2_shared_get_parent().
- *
- * 2. Clears the force enable bit of the RCG because we rely on child
- * clks (branches) to turn the RCG on/off with a hardware feedback
- * mechanism and only set the force enable bit in the RCG when we
- * want to make sure the clk stays on for parent switches or
- * parking.
- *
- * 3. Parks shared RCGs on the safe source at registration because we
- * can't be certain that the parent clk will stay on during boot,
- * especially if the parent is shared. If this RCG is enabled at
- * boot, and the parent is turned off, the RCG will get stuck on. A
- * GDSC can wedge if is turned on and the RCG is stuck on because
- * the GDSC's controller will hang waiting for the clk status to
- * toggle on when it never does.
- *
- * The safest option here is to "park" the RCG at init so that the clk
- * can never get stuck on or off. This ensures the GDSC can't get
- * wedged.
- */
- clk_rcg2_shared_disable(hw);
- return 0;
- }
- const struct clk_ops clk_rcg2_shared_ops = {
- .init = clk_rcg2_shared_init,
- .enable = clk_rcg2_shared_enable,
- .disable = clk_rcg2_shared_disable,
- .get_parent = clk_rcg2_shared_get_parent,
- .set_parent = clk_rcg2_shared_set_parent,
- .recalc_rate = clk_rcg2_shared_recalc_rate,
- .determine_rate = clk_rcg2_determine_rate,
- .set_rate = clk_rcg2_shared_set_rate,
- .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
- const struct clk_ops clk_rcg2_shared_floor_ops = {
- .enable = clk_rcg2_shared_enable,
- .disable = clk_rcg2_shared_disable,
- .get_parent = clk_rcg2_shared_get_parent,
- .set_parent = clk_rcg2_shared_set_parent,
- .recalc_rate = clk_rcg2_shared_recalc_rate,
- .determine_rate = clk_rcg2_determine_floor_rate,
- .set_rate = clk_rcg2_shared_set_floor_rate,
- .set_rate_and_parent = clk_rcg2_shared_set_floor_rate_and_parent,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_shared_floor_ops);
- static int clk_rcg2_shared_no_init_park(struct clk_hw *hw)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- /*
- * Read the config register so that the parent is properly mapped at
- * registration time.
- */
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &rcg->parked_cfg);
- return 0;
- }
- /*
- * Like clk_rcg2_shared_ops but skip the init so that the clk frequency is left
- * unchanged at registration time.
- */
- const struct clk_ops clk_rcg2_shared_no_init_park_ops = {
- .init = clk_rcg2_shared_no_init_park,
- .enable = clk_rcg2_shared_enable,
- .disable = clk_rcg2_shared_disable,
- .get_parent = clk_rcg2_shared_get_parent,
- .set_parent = clk_rcg2_shared_set_parent,
- .recalc_rate = clk_rcg2_shared_recalc_rate,
- .determine_rate = clk_rcg2_determine_rate,
- .set_rate = clk_rcg2_shared_set_rate,
- .set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,
- };
- EXPORT_SYMBOL_GPL(clk_rcg2_shared_no_init_park_ops);
- /* Common APIs to be used for DFS based RCGR */
- static void clk_rcg2_dfs_populate_freq(struct clk_hw *hw, unsigned int l,
- struct freq_tbl *f)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct clk_hw *p;
- unsigned long prate = 0;
- u32 val, mask, cfg, mode, src;
- int i, num_parents;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(l), &cfg);
- mask = BIT(rcg->hid_width) - 1;
- f->pre_div = 1;
- if (cfg & mask)
- f->pre_div = cfg & mask;
- src = cfg & CFG_SRC_SEL_MASK;
- src >>= CFG_SRC_SEL_SHIFT;
- num_parents = clk_hw_get_num_parents(hw);
- for (i = 0; i < num_parents; i++) {
- if (src == rcg->parent_map[i].cfg) {
- f->src = rcg->parent_map[i].src;
- p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i);
- prate = clk_hw_get_rate(p);
- }
- }
- mode = cfg & CFG_MODE_MASK;
- mode >>= CFG_MODE_SHIFT;
- if (mode) {
- mask = BIT(rcg->mnd_width) - 1;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_M_DFSR(l),
- &val);
- val &= mask;
- f->m = val;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_N_DFSR(l),
- &val);
- val = ~val;
- val &= mask;
- val += f->m;
- f->n = val;
- }
- f->freq = calc_rate(prate, f->m, f->n, mode, f->pre_div);
- }
- static int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg)
- {
- struct freq_tbl *freq_tbl;
- int i;
- /* Allocate space for 1 extra since table is NULL terminated */
- freq_tbl = kzalloc_objs(*freq_tbl, MAX_PERF_LEVEL + 1);
- if (!freq_tbl)
- return -ENOMEM;
- rcg->freq_tbl = freq_tbl;
- for (i = 0; i < MAX_PERF_LEVEL; i++)
- clk_rcg2_dfs_populate_freq(&rcg->clkr.hw, i, freq_tbl + i);
- return 0;
- }
- static int clk_rcg2_dfs_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- int ret;
- if (!rcg->freq_tbl) {
- ret = clk_rcg2_dfs_populate_freq_table(rcg);
- if (ret) {
- pr_err("Failed to update DFS tables for %s\n",
- clk_hw_get_name(hw));
- return ret;
- }
- }
- return clk_rcg2_determine_rate(hw, req);
- }
- static unsigned long
- clk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- u32 level, mask, cfg, m = 0, n = 0, mode, pre_div;
- regmap_read(rcg->clkr.regmap,
- rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
- level &= GENMASK(4, 1);
- level >>= 1;
- if (rcg->freq_tbl)
- return rcg->freq_tbl[level].freq;
- /*
- * Assume that parent_rate is actually the parent because
- * we can't do any better at figuring it out when the table
- * hasn't been populated yet. We only populate the table
- * in determine_rate because we can't guarantee the parents
- * will be registered with the framework until then.
- */
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(level),
- &cfg);
- mask = BIT(rcg->hid_width) - 1;
- pre_div = 1;
- if (cfg & mask)
- pre_div = cfg & mask;
- mode = cfg & CFG_MODE_MASK;
- mode >>= CFG_MODE_SHIFT;
- if (mode) {
- mask = BIT(rcg->mnd_width) - 1;
- regmap_read(rcg->clkr.regmap,
- rcg->cmd_rcgr + SE_PERF_M_DFSR(level), &m);
- m &= mask;
- regmap_read(rcg->clkr.regmap,
- rcg->cmd_rcgr + SE_PERF_N_DFSR(level), &n);
- n = ~n;
- n &= mask;
- n += m;
- }
- return calc_rate(parent_rate, m, n, mode, pre_div);
- }
- static const struct clk_ops clk_rcg2_dfs_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .determine_rate = clk_rcg2_dfs_determine_rate,
- .recalc_rate = clk_rcg2_dfs_recalc_rate,
- };
- static int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
- struct regmap *regmap)
- {
- struct clk_rcg2 *rcg = data->rcg;
- struct clk_init_data *init = data->init;
- u32 val;
- int ret;
- ret = regmap_read(regmap, rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &val);
- if (ret)
- return -EINVAL;
- if (!(val & SE_CMD_DFS_EN))
- return 0;
- /*
- * Rate changes with consumer writing a register in
- * their own I/O region
- */
- init->flags |= CLK_GET_RATE_NOCACHE;
- init->ops = &clk_rcg2_dfs_ops;
- rcg->freq_tbl = NULL;
- return 0;
- }
- int qcom_cc_register_rcg_dfs(struct regmap *regmap,
- const struct clk_rcg_dfs_data *rcgs, size_t len)
- {
- int i, ret;
- for (i = 0; i < len; i++) {
- ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
- if (ret)
- return ret;
- }
- return 0;
- }
- EXPORT_SYMBOL_GPL(qcom_cc_register_rcg_dfs);
- static int clk_rcg2_dp_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- struct freq_tbl f = { 0 };
- u32 mask = BIT(rcg->hid_width) - 1;
- u32 hid_div, cfg;
- int i, num_parents = clk_hw_get_num_parents(hw);
- unsigned long num, den;
- rational_best_approximation(parent_rate, rate,
- GENMASK(rcg->mnd_width - 1, 0),
- GENMASK(rcg->mnd_width - 1, 0), &den, &num);
- if (!num || !den)
- return -EINVAL;
- regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
- hid_div = cfg;
- cfg &= CFG_SRC_SEL_MASK;
- cfg >>= CFG_SRC_SEL_SHIFT;
- for (i = 0; i < num_parents; i++) {
- if (cfg == rcg->parent_map[i].cfg) {
- f.src = rcg->parent_map[i].src;
- break;
- }
- }
- f.pre_div = hid_div;
- f.pre_div >>= CFG_SRC_DIV_SHIFT;
- f.pre_div &= mask;
- if (num != den) {
- f.m = num;
- f.n = den;
- } else {
- f.m = 0;
- f.n = 0;
- }
- return clk_rcg2_configure(rcg, &f);
- }
- static int clk_rcg2_dp_set_rate_and_parent(struct clk_hw *hw,
- unsigned long rate, unsigned long parent_rate, u8 index)
- {
- return clk_rcg2_dp_set_rate(hw, rate, parent_rate);
- }
- static int clk_rcg2_dp_determine_rate(struct clk_hw *hw,
- struct clk_rate_request *req)
- {
- struct clk_rcg2 *rcg = to_clk_rcg2(hw);
- unsigned long num, den;
- u64 tmp;
- /* Parent rate is a fixed phy link rate */
- rational_best_approximation(req->best_parent_rate, req->rate,
- GENMASK(rcg->mnd_width - 1, 0),
- GENMASK(rcg->mnd_width - 1, 0), &den, &num);
- if (!num || !den)
- return -EINVAL;
- tmp = req->best_parent_rate * num;
- do_div(tmp, den);
- req->rate = tmp;
- return 0;
- }
- const struct clk_ops clk_dp_ops = {
- .is_enabled = clk_rcg2_is_enabled,
- .get_parent = clk_rcg2_get_parent,
- .set_parent = clk_rcg2_set_parent,
- .recalc_rate = clk_rcg2_recalc_rate,
- .set_rate = clk_rcg2_dp_set_rate,
- .set_rate_and_parent = clk_rcg2_dp_set_rate_and_parent,
- .determine_rate = clk_rcg2_dp_determine_rate,
- };
- EXPORT_SYMBOL_GPL(clk_dp_ops);
|