18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (c) 2013, 2018, The Linux Foundation. All rights reserved.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/bitops.h>
88c2ecf20Sopenharmony_ci#include <linux/err.h>
98c2ecf20Sopenharmony_ci#include <linux/bug.h>
108c2ecf20Sopenharmony_ci#include <linux/export.h>
118c2ecf20Sopenharmony_ci#include <linux/clk-provider.h>
128c2ecf20Sopenharmony_ci#include <linux/delay.h>
138c2ecf20Sopenharmony_ci#include <linux/rational.h>
148c2ecf20Sopenharmony_ci#include <linux/regmap.h>
158c2ecf20Sopenharmony_ci#include <linux/math64.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <asm/div64.h>
198c2ecf20Sopenharmony_ci
208c2ecf20Sopenharmony_ci#include "clk-rcg.h"
218c2ecf20Sopenharmony_ci#include "common.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define CMD_REG			0x0
248c2ecf20Sopenharmony_ci#define CMD_UPDATE		BIT(0)
258c2ecf20Sopenharmony_ci#define CMD_ROOT_EN		BIT(1)
268c2ecf20Sopenharmony_ci#define CMD_DIRTY_CFG		BIT(4)
278c2ecf20Sopenharmony_ci#define CMD_DIRTY_N		BIT(5)
288c2ecf20Sopenharmony_ci#define CMD_DIRTY_M		BIT(6)
298c2ecf20Sopenharmony_ci#define CMD_DIRTY_D		BIT(7)
308c2ecf20Sopenharmony_ci#define CMD_ROOT_OFF		BIT(31)
318c2ecf20Sopenharmony_ci
328c2ecf20Sopenharmony_ci#define CFG_REG			0x4
338c2ecf20Sopenharmony_ci#define CFG_SRC_DIV_SHIFT	0
348c2ecf20Sopenharmony_ci#define CFG_SRC_SEL_SHIFT	8
358c2ecf20Sopenharmony_ci#define CFG_SRC_SEL_MASK	(0x7 << CFG_SRC_SEL_SHIFT)
368c2ecf20Sopenharmony_ci#define CFG_MODE_SHIFT		12
378c2ecf20Sopenharmony_ci#define CFG_MODE_MASK		(0x3 << CFG_MODE_SHIFT)
388c2ecf20Sopenharmony_ci#define CFG_MODE_DUAL_EDGE	(0x2 << CFG_MODE_SHIFT)
398c2ecf20Sopenharmony_ci#define CFG_HW_CLK_CTRL_MASK	BIT(20)
408c2ecf20Sopenharmony_ci
418c2ecf20Sopenharmony_ci#define M_REG			0x8
428c2ecf20Sopenharmony_ci#define N_REG			0xc
438c2ecf20Sopenharmony_ci#define D_REG			0x10
448c2ecf20Sopenharmony_ci
458c2ecf20Sopenharmony_ci#define RCG_CFG_OFFSET(rcg)	((rcg)->cmd_rcgr + (rcg)->cfg_off + CFG_REG)
468c2ecf20Sopenharmony_ci#define RCG_M_OFFSET(rcg)	((rcg)->cmd_rcgr + (rcg)->cfg_off + M_REG)
478c2ecf20Sopenharmony_ci#define RCG_N_OFFSET(rcg)	((rcg)->cmd_rcgr + (rcg)->cfg_off + N_REG)
488c2ecf20Sopenharmony_ci#define RCG_D_OFFSET(rcg)	((rcg)->cmd_rcgr + (rcg)->cfg_off + D_REG)
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci/* Dynamic Frequency Scaling */
518c2ecf20Sopenharmony_ci#define MAX_PERF_LEVEL		8
528c2ecf20Sopenharmony_ci#define SE_CMD_DFSR_OFFSET	0x14
538c2ecf20Sopenharmony_ci#define SE_CMD_DFS_EN		BIT(0)
548c2ecf20Sopenharmony_ci#define SE_PERF_DFSR(level)	(0x1c + 0x4 * (level))
558c2ecf20Sopenharmony_ci#define SE_PERF_M_DFSR(level)	(0x5c + 0x4 * (level))
568c2ecf20Sopenharmony_ci#define SE_PERF_N_DFSR(level)	(0x9c + 0x4 * (level))
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_cienum freq_policy {
598c2ecf20Sopenharmony_ci	FLOOR,
608c2ecf20Sopenharmony_ci	CEIL,
618c2ecf20Sopenharmony_ci};
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic int clk_rcg2_is_enabled(struct clk_hw *hw)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
668c2ecf20Sopenharmony_ci	u32 cmd;
678c2ecf20Sopenharmony_ci	int ret;
688c2ecf20Sopenharmony_ci
698c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
708c2ecf20Sopenharmony_ci	if (ret)
718c2ecf20Sopenharmony_ci		return ret;
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	return (cmd & CMD_ROOT_OFF) == 0;
748c2ecf20Sopenharmony_ci}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_cistatic u8 clk_rcg2_get_parent(struct clk_hw *hw)
778c2ecf20Sopenharmony_ci{
788c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
798c2ecf20Sopenharmony_ci	int num_parents = clk_hw_get_num_parents(hw);
808c2ecf20Sopenharmony_ci	u32 cfg;
818c2ecf20Sopenharmony_ci	int i, ret;
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci	ret = regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
848c2ecf20Sopenharmony_ci	if (ret)
858c2ecf20Sopenharmony_ci		goto err;
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	cfg &= CFG_SRC_SEL_MASK;
888c2ecf20Sopenharmony_ci	cfg >>= CFG_SRC_SEL_SHIFT;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++)
918c2ecf20Sopenharmony_ci		if (cfg == rcg->parent_map[i].cfg)
928c2ecf20Sopenharmony_ci			return i;
938c2ecf20Sopenharmony_ci
948c2ecf20Sopenharmony_cierr:
958c2ecf20Sopenharmony_ci	pr_debug("%s: Clock %s has invalid parent, using default.\n",
968c2ecf20Sopenharmony_ci		 __func__, clk_hw_get_name(hw));
978c2ecf20Sopenharmony_ci	return 0;
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int update_config(struct clk_rcg2 *rcg)
1018c2ecf20Sopenharmony_ci{
1028c2ecf20Sopenharmony_ci	int count, ret;
1038c2ecf20Sopenharmony_ci	u32 cmd;
1048c2ecf20Sopenharmony_ci	struct clk_hw *hw = &rcg->clkr.hw;
1058c2ecf20Sopenharmony_ci	const char *name = clk_hw_get_name(hw);
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
1088c2ecf20Sopenharmony_ci				 CMD_UPDATE, CMD_UPDATE);
1098c2ecf20Sopenharmony_ci	if (ret)
1108c2ecf20Sopenharmony_ci		return ret;
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ci	/* Wait for update to take effect */
1138c2ecf20Sopenharmony_ci	for (count = 500; count > 0; count--) {
1148c2ecf20Sopenharmony_ci		ret = regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG, &cmd);
1158c2ecf20Sopenharmony_ci		if (ret)
1168c2ecf20Sopenharmony_ci			return ret;
1178c2ecf20Sopenharmony_ci		if (!(cmd & CMD_UPDATE))
1188c2ecf20Sopenharmony_ci			return 0;
1198c2ecf20Sopenharmony_ci		udelay(1);
1208c2ecf20Sopenharmony_ci	}
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	WARN(1, "%s: rcg didn't update its configuration.", name);
1238c2ecf20Sopenharmony_ci	return -EBUSY;
1248c2ecf20Sopenharmony_ci}
1258c2ecf20Sopenharmony_ci
1268c2ecf20Sopenharmony_cistatic int clk_rcg2_set_parent(struct clk_hw *hw, u8 index)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1298c2ecf20Sopenharmony_ci	int ret;
1308c2ecf20Sopenharmony_ci	u32 cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	ret = regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg),
1338c2ecf20Sopenharmony_ci				 CFG_SRC_SEL_MASK, cfg);
1348c2ecf20Sopenharmony_ci	if (ret)
1358c2ecf20Sopenharmony_ci		return ret;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	return update_config(rcg);
1388c2ecf20Sopenharmony_ci}
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci/*
1418c2ecf20Sopenharmony_ci * Calculate m/n:d rate
1428c2ecf20Sopenharmony_ci *
1438c2ecf20Sopenharmony_ci *          parent_rate     m
1448c2ecf20Sopenharmony_ci *   rate = ----------- x  ---
1458c2ecf20Sopenharmony_ci *            hid_div       n
1468c2ecf20Sopenharmony_ci */
1478c2ecf20Sopenharmony_cistatic unsigned long
1488c2ecf20Sopenharmony_cicalc_rate(unsigned long rate, u32 m, u32 n, u32 mode, u32 hid_div)
1498c2ecf20Sopenharmony_ci{
1508c2ecf20Sopenharmony_ci	if (hid_div)
1518c2ecf20Sopenharmony_ci		rate = mult_frac(rate, 2, hid_div + 1);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (mode)
1548c2ecf20Sopenharmony_ci		rate = mult_frac(rate, m, n);
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return rate;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic unsigned long
1608c2ecf20Sopenharmony_ciclk_rcg2_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
1618c2ecf20Sopenharmony_ci{
1628c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1638c2ecf20Sopenharmony_ci	u32 cfg, hid_div, m = 0, n = 0, mode = 0, mask;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg), &cfg);
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_ci	if (rcg->mnd_width) {
1688c2ecf20Sopenharmony_ci		mask = BIT(rcg->mnd_width) - 1;
1698c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, RCG_M_OFFSET(rcg), &m);
1708c2ecf20Sopenharmony_ci		m &= mask;
1718c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, RCG_N_OFFSET(rcg), &n);
1728c2ecf20Sopenharmony_ci		n =  ~n;
1738c2ecf20Sopenharmony_ci		n &= mask;
1748c2ecf20Sopenharmony_ci		n += m;
1758c2ecf20Sopenharmony_ci		mode = cfg & CFG_MODE_MASK;
1768c2ecf20Sopenharmony_ci		mode >>= CFG_MODE_SHIFT;
1778c2ecf20Sopenharmony_ci	}
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	mask = BIT(rcg->hid_width) - 1;
1808c2ecf20Sopenharmony_ci	hid_div = cfg >> CFG_SRC_DIV_SHIFT;
1818c2ecf20Sopenharmony_ci	hid_div &= mask;
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci	return calc_rate(parent_rate, m, n, mode, hid_div);
1848c2ecf20Sopenharmony_ci}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_cistatic int _freq_tbl_determine_rate(struct clk_hw *hw, const struct freq_tbl *f,
1878c2ecf20Sopenharmony_ci				    struct clk_rate_request *req,
1888c2ecf20Sopenharmony_ci				    enum freq_policy policy)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	unsigned long clk_flags, rate = req->rate;
1918c2ecf20Sopenharmony_ci	struct clk_hw *p;
1928c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
1938c2ecf20Sopenharmony_ci	int index;
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci	switch (policy) {
1968c2ecf20Sopenharmony_ci	case FLOOR:
1978c2ecf20Sopenharmony_ci		f = qcom_find_freq_floor(f, rate);
1988c2ecf20Sopenharmony_ci		break;
1998c2ecf20Sopenharmony_ci	case CEIL:
2008c2ecf20Sopenharmony_ci		f = qcom_find_freq(f, rate);
2018c2ecf20Sopenharmony_ci		break;
2028c2ecf20Sopenharmony_ci	default:
2038c2ecf20Sopenharmony_ci		return -EINVAL;
2048c2ecf20Sopenharmony_ci	}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci	if (!f)
2078c2ecf20Sopenharmony_ci		return -EINVAL;
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci	index = qcom_find_src_index(hw, rcg->parent_map, f->src);
2108c2ecf20Sopenharmony_ci	if (index < 0)
2118c2ecf20Sopenharmony_ci		return index;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	clk_flags = clk_hw_get_flags(hw);
2148c2ecf20Sopenharmony_ci	p = clk_hw_get_parent_by_index(hw, index);
2158c2ecf20Sopenharmony_ci	if (!p)
2168c2ecf20Sopenharmony_ci		return -EINVAL;
2178c2ecf20Sopenharmony_ci
2188c2ecf20Sopenharmony_ci	if (clk_flags & CLK_SET_RATE_PARENT) {
2198c2ecf20Sopenharmony_ci		rate = f->freq;
2208c2ecf20Sopenharmony_ci		if (f->pre_div) {
2218c2ecf20Sopenharmony_ci			if (!rate)
2228c2ecf20Sopenharmony_ci				rate = req->rate;
2238c2ecf20Sopenharmony_ci			rate /= 2;
2248c2ecf20Sopenharmony_ci			rate *= f->pre_div + 1;
2258c2ecf20Sopenharmony_ci		}
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci		if (f->n) {
2288c2ecf20Sopenharmony_ci			u64 tmp = rate;
2298c2ecf20Sopenharmony_ci			tmp = tmp * f->n;
2308c2ecf20Sopenharmony_ci			do_div(tmp, f->m);
2318c2ecf20Sopenharmony_ci			rate = tmp;
2328c2ecf20Sopenharmony_ci		}
2338c2ecf20Sopenharmony_ci	} else {
2348c2ecf20Sopenharmony_ci		rate =  clk_hw_get_rate(p);
2358c2ecf20Sopenharmony_ci	}
2368c2ecf20Sopenharmony_ci	req->best_parent_hw = p;
2378c2ecf20Sopenharmony_ci	req->best_parent_rate = rate;
2388c2ecf20Sopenharmony_ci	req->rate = f->freq;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	return 0;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_cistatic int clk_rcg2_determine_rate(struct clk_hw *hw,
2448c2ecf20Sopenharmony_ci				   struct clk_rate_request *req)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, CEIL);
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_cistatic int clk_rcg2_determine_floor_rate(struct clk_hw *hw,
2528c2ecf20Sopenharmony_ci					 struct clk_rate_request *req)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	return _freq_tbl_determine_rate(hw, rcg->freq_tbl, req, FLOOR);
2578c2ecf20Sopenharmony_ci}
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_cistatic int __clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
2608c2ecf20Sopenharmony_ci{
2618c2ecf20Sopenharmony_ci	u32 cfg, mask, d_val, not2d_val, n_minus_m;
2628c2ecf20Sopenharmony_ci	struct clk_hw *hw = &rcg->clkr.hw;
2638c2ecf20Sopenharmony_ci	int ret, index = qcom_find_src_index(hw, rcg->parent_map, f->src);
2648c2ecf20Sopenharmony_ci
2658c2ecf20Sopenharmony_ci	if (index < 0)
2668c2ecf20Sopenharmony_ci		return index;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	if (rcg->mnd_width && f->n) {
2698c2ecf20Sopenharmony_ci		mask = BIT(rcg->mnd_width) - 1;
2708c2ecf20Sopenharmony_ci		ret = regmap_update_bits(rcg->clkr.regmap,
2718c2ecf20Sopenharmony_ci				RCG_M_OFFSET(rcg), mask, f->m);
2728c2ecf20Sopenharmony_ci		if (ret)
2738c2ecf20Sopenharmony_ci			return ret;
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci		ret = regmap_update_bits(rcg->clkr.regmap,
2768c2ecf20Sopenharmony_ci				RCG_N_OFFSET(rcg), mask, ~(f->n - f->m));
2778c2ecf20Sopenharmony_ci		if (ret)
2788c2ecf20Sopenharmony_ci			return ret;
2798c2ecf20Sopenharmony_ci
2808c2ecf20Sopenharmony_ci		/* Calculate 2d value */
2818c2ecf20Sopenharmony_ci		d_val = f->n;
2828c2ecf20Sopenharmony_ci
2838c2ecf20Sopenharmony_ci		n_minus_m = f->n - f->m;
2848c2ecf20Sopenharmony_ci		n_minus_m *= 2;
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci		d_val = clamp_t(u32, d_val, f->m, n_minus_m);
2878c2ecf20Sopenharmony_ci		not2d_val = ~d_val & mask;
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_ci		ret = regmap_update_bits(rcg->clkr.regmap,
2908c2ecf20Sopenharmony_ci				RCG_D_OFFSET(rcg), mask, not2d_val);
2918c2ecf20Sopenharmony_ci		if (ret)
2928c2ecf20Sopenharmony_ci			return ret;
2938c2ecf20Sopenharmony_ci	}
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	mask = BIT(rcg->hid_width) - 1;
2968c2ecf20Sopenharmony_ci	mask |= CFG_SRC_SEL_MASK | CFG_MODE_MASK | CFG_HW_CLK_CTRL_MASK;
2978c2ecf20Sopenharmony_ci	cfg = f->pre_div << CFG_SRC_DIV_SHIFT;
2988c2ecf20Sopenharmony_ci	cfg |= rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
2998c2ecf20Sopenharmony_ci	if (rcg->mnd_width && f->n && (f->m != f->n))
3008c2ecf20Sopenharmony_ci		cfg |= CFG_MODE_DUAL_EDGE;
3018c2ecf20Sopenharmony_ci	return regmap_update_bits(rcg->clkr.regmap, RCG_CFG_OFFSET(rcg),
3028c2ecf20Sopenharmony_ci					mask, cfg);
3038c2ecf20Sopenharmony_ci}
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_cistatic int clk_rcg2_configure(struct clk_rcg2 *rcg, const struct freq_tbl *f)
3068c2ecf20Sopenharmony_ci{
3078c2ecf20Sopenharmony_ci	int ret;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	ret = __clk_rcg2_configure(rcg, f);
3108c2ecf20Sopenharmony_ci	if (ret)
3118c2ecf20Sopenharmony_ci		return ret;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	return update_config(rcg);
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int __clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
3178c2ecf20Sopenharmony_ci			       enum freq_policy policy)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
3208c2ecf20Sopenharmony_ci	const struct freq_tbl *f;
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci	switch (policy) {
3238c2ecf20Sopenharmony_ci	case FLOOR:
3248c2ecf20Sopenharmony_ci		f = qcom_find_freq_floor(rcg->freq_tbl, rate);
3258c2ecf20Sopenharmony_ci		break;
3268c2ecf20Sopenharmony_ci	case CEIL:
3278c2ecf20Sopenharmony_ci		f = qcom_find_freq(rcg->freq_tbl, rate);
3288c2ecf20Sopenharmony_ci		break;
3298c2ecf20Sopenharmony_ci	default:
3308c2ecf20Sopenharmony_ci		return -EINVAL;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	if (!f)
3348c2ecf20Sopenharmony_ci		return -EINVAL;
3358c2ecf20Sopenharmony_ci
3368c2ecf20Sopenharmony_ci	return clk_rcg2_configure(rcg, f);
3378c2ecf20Sopenharmony_ci}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_cistatic int clk_rcg2_set_rate(struct clk_hw *hw, unsigned long rate,
3408c2ecf20Sopenharmony_ci			    unsigned long parent_rate)
3418c2ecf20Sopenharmony_ci{
3428c2ecf20Sopenharmony_ci	return __clk_rcg2_set_rate(hw, rate, CEIL);
3438c2ecf20Sopenharmony_ci}
3448c2ecf20Sopenharmony_ci
3458c2ecf20Sopenharmony_cistatic int clk_rcg2_set_floor_rate(struct clk_hw *hw, unsigned long rate,
3468c2ecf20Sopenharmony_ci				   unsigned long parent_rate)
3478c2ecf20Sopenharmony_ci{
3488c2ecf20Sopenharmony_ci	return __clk_rcg2_set_rate(hw, rate, FLOOR);
3498c2ecf20Sopenharmony_ci}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_cistatic int clk_rcg2_set_rate_and_parent(struct clk_hw *hw,
3528c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
3538c2ecf20Sopenharmony_ci{
3548c2ecf20Sopenharmony_ci	return __clk_rcg2_set_rate(hw, rate, CEIL);
3558c2ecf20Sopenharmony_ci}
3568c2ecf20Sopenharmony_ci
3578c2ecf20Sopenharmony_cistatic int clk_rcg2_set_floor_rate_and_parent(struct clk_hw *hw,
3588c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
3598c2ecf20Sopenharmony_ci{
3608c2ecf20Sopenharmony_ci	return __clk_rcg2_set_rate(hw, rate, FLOOR);
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg2_ops = {
3648c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
3658c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
3668c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
3678c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
3688c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg2_determine_rate,
3698c2ecf20Sopenharmony_ci	.set_rate = clk_rcg2_set_rate,
3708c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg2_set_rate_and_parent,
3718c2ecf20Sopenharmony_ci};
3728c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg2_ops);
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg2_floor_ops = {
3758c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
3768c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
3778c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
3788c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
3798c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg2_determine_floor_rate,
3808c2ecf20Sopenharmony_ci	.set_rate = clk_rcg2_set_floor_rate,
3818c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg2_set_floor_rate_and_parent,
3828c2ecf20Sopenharmony_ci};
3838c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg2_floor_ops);
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_cistruct frac_entry {
3868c2ecf20Sopenharmony_ci	int num;
3878c2ecf20Sopenharmony_ci	int den;
3888c2ecf20Sopenharmony_ci};
3898c2ecf20Sopenharmony_ci
3908c2ecf20Sopenharmony_cistatic const struct frac_entry frac_table_675m[] = {	/* link rate of 270M */
3918c2ecf20Sopenharmony_ci	{ 52, 295 },	/* 119 M */
3928c2ecf20Sopenharmony_ci	{ 11, 57 },	/* 130.25 M */
3938c2ecf20Sopenharmony_ci	{ 63, 307 },	/* 138.50 M */
3948c2ecf20Sopenharmony_ci	{ 11, 50 },	/* 148.50 M */
3958c2ecf20Sopenharmony_ci	{ 47, 206 },	/* 154 M */
3968c2ecf20Sopenharmony_ci	{ 31, 100 },	/* 205.25 M */
3978c2ecf20Sopenharmony_ci	{ 107, 269 },	/* 268.50 M */
3988c2ecf20Sopenharmony_ci	{ },
3998c2ecf20Sopenharmony_ci};
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_cistatic struct frac_entry frac_table_810m[] = { /* Link rate of 162M */
4028c2ecf20Sopenharmony_ci	{ 31, 211 },	/* 119 M */
4038c2ecf20Sopenharmony_ci	{ 32, 199 },	/* 130.25 M */
4048c2ecf20Sopenharmony_ci	{ 63, 307 },	/* 138.50 M */
4058c2ecf20Sopenharmony_ci	{ 11, 60 },	/* 148.50 M */
4068c2ecf20Sopenharmony_ci	{ 50, 263 },	/* 154 M */
4078c2ecf20Sopenharmony_ci	{ 31, 120 },	/* 205.25 M */
4088c2ecf20Sopenharmony_ci	{ 119, 359 },	/* 268.50 M */
4098c2ecf20Sopenharmony_ci	{ },
4108c2ecf20Sopenharmony_ci};
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_cistatic int clk_edp_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
4138c2ecf20Sopenharmony_ci			      unsigned long parent_rate)
4148c2ecf20Sopenharmony_ci{
4158c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
4168c2ecf20Sopenharmony_ci	struct freq_tbl f = *rcg->freq_tbl;
4178c2ecf20Sopenharmony_ci	const struct frac_entry *frac;
4188c2ecf20Sopenharmony_ci	int delta = 100000;
4198c2ecf20Sopenharmony_ci	s64 src_rate = parent_rate;
4208c2ecf20Sopenharmony_ci	s64 request;
4218c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
4228c2ecf20Sopenharmony_ci	u32 hid_div;
4238c2ecf20Sopenharmony_ci
4248c2ecf20Sopenharmony_ci	if (src_rate == 810000000)
4258c2ecf20Sopenharmony_ci		frac = frac_table_810m;
4268c2ecf20Sopenharmony_ci	else
4278c2ecf20Sopenharmony_ci		frac = frac_table_675m;
4288c2ecf20Sopenharmony_ci
4298c2ecf20Sopenharmony_ci	for (; frac->num; frac++) {
4308c2ecf20Sopenharmony_ci		request = rate;
4318c2ecf20Sopenharmony_ci		request *= frac->den;
4328c2ecf20Sopenharmony_ci		request = div_s64(request, frac->num);
4338c2ecf20Sopenharmony_ci		if ((src_rate < (request - delta)) ||
4348c2ecf20Sopenharmony_ci		    (src_rate > (request + delta)))
4358c2ecf20Sopenharmony_ci			continue;
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
4388c2ecf20Sopenharmony_ci				&hid_div);
4398c2ecf20Sopenharmony_ci		f.pre_div = hid_div;
4408c2ecf20Sopenharmony_ci		f.pre_div >>= CFG_SRC_DIV_SHIFT;
4418c2ecf20Sopenharmony_ci		f.pre_div &= mask;
4428c2ecf20Sopenharmony_ci		f.m = frac->num;
4438c2ecf20Sopenharmony_ci		f.n = frac->den;
4448c2ecf20Sopenharmony_ci
4458c2ecf20Sopenharmony_ci		return clk_rcg2_configure(rcg, &f);
4468c2ecf20Sopenharmony_ci	}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_ci	return -EINVAL;
4498c2ecf20Sopenharmony_ci}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_cistatic int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
4528c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	/* Parent index is set statically in frequency table */
4558c2ecf20Sopenharmony_ci	return clk_edp_pixel_set_rate(hw, rate, parent_rate);
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int clk_edp_pixel_determine_rate(struct clk_hw *hw,
4598c2ecf20Sopenharmony_ci					struct clk_rate_request *req)
4608c2ecf20Sopenharmony_ci{
4618c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
4628c2ecf20Sopenharmony_ci	const struct freq_tbl *f = rcg->freq_tbl;
4638c2ecf20Sopenharmony_ci	const struct frac_entry *frac;
4648c2ecf20Sopenharmony_ci	int delta = 100000;
4658c2ecf20Sopenharmony_ci	s64 request;
4668c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
4678c2ecf20Sopenharmony_ci	u32 hid_div;
4688c2ecf20Sopenharmony_ci	int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	/* Force the correct parent */
4718c2ecf20Sopenharmony_ci	req->best_parent_hw = clk_hw_get_parent_by_index(hw, index);
4728c2ecf20Sopenharmony_ci	req->best_parent_rate = clk_hw_get_rate(req->best_parent_hw);
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	if (req->best_parent_rate == 810000000)
4758c2ecf20Sopenharmony_ci		frac = frac_table_810m;
4768c2ecf20Sopenharmony_ci	else
4778c2ecf20Sopenharmony_ci		frac = frac_table_675m;
4788c2ecf20Sopenharmony_ci
4798c2ecf20Sopenharmony_ci	for (; frac->num; frac++) {
4808c2ecf20Sopenharmony_ci		request = req->rate;
4818c2ecf20Sopenharmony_ci		request *= frac->den;
4828c2ecf20Sopenharmony_ci		request = div_s64(request, frac->num);
4838c2ecf20Sopenharmony_ci		if ((req->best_parent_rate < (request - delta)) ||
4848c2ecf20Sopenharmony_ci		    (req->best_parent_rate > (request + delta)))
4858c2ecf20Sopenharmony_ci			continue;
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
4888c2ecf20Sopenharmony_ci				&hid_div);
4898c2ecf20Sopenharmony_ci		hid_div >>= CFG_SRC_DIV_SHIFT;
4908c2ecf20Sopenharmony_ci		hid_div &= mask;
4918c2ecf20Sopenharmony_ci
4928c2ecf20Sopenharmony_ci		req->rate = calc_rate(req->best_parent_rate,
4938c2ecf20Sopenharmony_ci				      frac->num, frac->den,
4948c2ecf20Sopenharmony_ci				      !!frac->den, hid_div);
4958c2ecf20Sopenharmony_ci		return 0;
4968c2ecf20Sopenharmony_ci	}
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	return -EINVAL;
4998c2ecf20Sopenharmony_ci}
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ciconst struct clk_ops clk_edp_pixel_ops = {
5028c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
5038c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
5048c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
5058c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
5068c2ecf20Sopenharmony_ci	.set_rate = clk_edp_pixel_set_rate,
5078c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_edp_pixel_set_rate_and_parent,
5088c2ecf20Sopenharmony_ci	.determine_rate = clk_edp_pixel_determine_rate,
5098c2ecf20Sopenharmony_ci};
5108c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
5118c2ecf20Sopenharmony_ci
5128c2ecf20Sopenharmony_cistatic int clk_byte_determine_rate(struct clk_hw *hw,
5138c2ecf20Sopenharmony_ci				   struct clk_rate_request *req)
5148c2ecf20Sopenharmony_ci{
5158c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
5168c2ecf20Sopenharmony_ci	const struct freq_tbl *f = rcg->freq_tbl;
5178c2ecf20Sopenharmony_ci	int index = qcom_find_src_index(hw, rcg->parent_map, f->src);
5188c2ecf20Sopenharmony_ci	unsigned long parent_rate, div;
5198c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
5208c2ecf20Sopenharmony_ci	struct clk_hw *p;
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_ci	if (req->rate == 0)
5238c2ecf20Sopenharmony_ci		return -EINVAL;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	req->best_parent_hw = p = clk_hw_get_parent_by_index(hw, index);
5268c2ecf20Sopenharmony_ci	req->best_parent_rate = parent_rate = clk_hw_round_rate(p, req->rate);
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_ci	div = DIV_ROUND_UP((2 * parent_rate), req->rate) - 1;
5298c2ecf20Sopenharmony_ci	div = min_t(u32, div, mask);
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_ci	req->rate = calc_rate(parent_rate, 0, 0, 0, div);
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	return 0;
5348c2ecf20Sopenharmony_ci}
5358c2ecf20Sopenharmony_ci
5368c2ecf20Sopenharmony_cistatic int clk_byte_set_rate(struct clk_hw *hw, unsigned long rate,
5378c2ecf20Sopenharmony_ci			 unsigned long parent_rate)
5388c2ecf20Sopenharmony_ci{
5398c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
5408c2ecf20Sopenharmony_ci	struct freq_tbl f = *rcg->freq_tbl;
5418c2ecf20Sopenharmony_ci	unsigned long div;
5428c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
5458c2ecf20Sopenharmony_ci	div = min_t(u32, div, mask);
5468c2ecf20Sopenharmony_ci
5478c2ecf20Sopenharmony_ci	f.pre_div = div;
5488c2ecf20Sopenharmony_ci
5498c2ecf20Sopenharmony_ci	return clk_rcg2_configure(rcg, &f);
5508c2ecf20Sopenharmony_ci}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_cistatic int clk_byte_set_rate_and_parent(struct clk_hw *hw,
5538c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
5548c2ecf20Sopenharmony_ci{
5558c2ecf20Sopenharmony_ci	/* Parent index is set statically in frequency table */
5568c2ecf20Sopenharmony_ci	return clk_byte_set_rate(hw, rate, parent_rate);
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ciconst struct clk_ops clk_byte_ops = {
5608c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
5618c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
5628c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
5638c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
5648c2ecf20Sopenharmony_ci	.set_rate = clk_byte_set_rate,
5658c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_byte_set_rate_and_parent,
5668c2ecf20Sopenharmony_ci	.determine_rate = clk_byte_determine_rate,
5678c2ecf20Sopenharmony_ci};
5688c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_byte_ops);
5698c2ecf20Sopenharmony_ci
5708c2ecf20Sopenharmony_cistatic int clk_byte2_determine_rate(struct clk_hw *hw,
5718c2ecf20Sopenharmony_ci				    struct clk_rate_request *req)
5728c2ecf20Sopenharmony_ci{
5738c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
5748c2ecf20Sopenharmony_ci	unsigned long parent_rate, div;
5758c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
5768c2ecf20Sopenharmony_ci	struct clk_hw *p;
5778c2ecf20Sopenharmony_ci	unsigned long rate = req->rate;
5788c2ecf20Sopenharmony_ci
5798c2ecf20Sopenharmony_ci	if (rate == 0)
5808c2ecf20Sopenharmony_ci		return -EINVAL;
5818c2ecf20Sopenharmony_ci
5828c2ecf20Sopenharmony_ci	p = req->best_parent_hw;
5838c2ecf20Sopenharmony_ci	req->best_parent_rate = parent_rate = clk_hw_round_rate(p, rate);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
5868c2ecf20Sopenharmony_ci	div = min_t(u32, div, mask);
5878c2ecf20Sopenharmony_ci
5888c2ecf20Sopenharmony_ci	req->rate = calc_rate(parent_rate, 0, 0, 0, div);
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	return 0;
5918c2ecf20Sopenharmony_ci}
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_cistatic int clk_byte2_set_rate(struct clk_hw *hw, unsigned long rate,
5948c2ecf20Sopenharmony_ci			 unsigned long parent_rate)
5958c2ecf20Sopenharmony_ci{
5968c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
5978c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
5988c2ecf20Sopenharmony_ci	unsigned long div;
5998c2ecf20Sopenharmony_ci	int i, num_parents = clk_hw_get_num_parents(hw);
6008c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
6018c2ecf20Sopenharmony_ci	u32 cfg;
6028c2ecf20Sopenharmony_ci
6038c2ecf20Sopenharmony_ci	div = DIV_ROUND_UP((2 * parent_rate), rate) - 1;
6048c2ecf20Sopenharmony_ci	div = min_t(u32, div, mask);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	f.pre_div = div;
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
6098c2ecf20Sopenharmony_ci	cfg &= CFG_SRC_SEL_MASK;
6108c2ecf20Sopenharmony_ci	cfg >>= CFG_SRC_SEL_SHIFT;
6118c2ecf20Sopenharmony_ci
6128c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++) {
6138c2ecf20Sopenharmony_ci		if (cfg == rcg->parent_map[i].cfg) {
6148c2ecf20Sopenharmony_ci			f.src = rcg->parent_map[i].src;
6158c2ecf20Sopenharmony_ci			return clk_rcg2_configure(rcg, &f);
6168c2ecf20Sopenharmony_ci		}
6178c2ecf20Sopenharmony_ci	}
6188c2ecf20Sopenharmony_ci
6198c2ecf20Sopenharmony_ci	return -EINVAL;
6208c2ecf20Sopenharmony_ci}
6218c2ecf20Sopenharmony_ci
6228c2ecf20Sopenharmony_cistatic int clk_byte2_set_rate_and_parent(struct clk_hw *hw,
6238c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
6248c2ecf20Sopenharmony_ci{
6258c2ecf20Sopenharmony_ci	/* Read the hardware to determine parent during set_rate */
6268c2ecf20Sopenharmony_ci	return clk_byte2_set_rate(hw, rate, parent_rate);
6278c2ecf20Sopenharmony_ci}
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_ciconst struct clk_ops clk_byte2_ops = {
6308c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
6318c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
6328c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
6338c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
6348c2ecf20Sopenharmony_ci	.set_rate = clk_byte2_set_rate,
6358c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_byte2_set_rate_and_parent,
6368c2ecf20Sopenharmony_ci	.determine_rate = clk_byte2_determine_rate,
6378c2ecf20Sopenharmony_ci};
6388c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_byte2_ops);
6398c2ecf20Sopenharmony_ci
6408c2ecf20Sopenharmony_cistatic const struct frac_entry frac_table_pixel[] = {
6418c2ecf20Sopenharmony_ci	{ 3, 8 },
6428c2ecf20Sopenharmony_ci	{ 2, 9 },
6438c2ecf20Sopenharmony_ci	{ 4, 9 },
6448c2ecf20Sopenharmony_ci	{ 1, 1 },
6458c2ecf20Sopenharmony_ci	{ 2, 3 },
6468c2ecf20Sopenharmony_ci	{ }
6478c2ecf20Sopenharmony_ci};
6488c2ecf20Sopenharmony_ci
6498c2ecf20Sopenharmony_cistatic int clk_pixel_determine_rate(struct clk_hw *hw,
6508c2ecf20Sopenharmony_ci				    struct clk_rate_request *req)
6518c2ecf20Sopenharmony_ci{
6528c2ecf20Sopenharmony_ci	unsigned long request, src_rate;
6538c2ecf20Sopenharmony_ci	int delta = 100000;
6548c2ecf20Sopenharmony_ci	const struct frac_entry *frac = frac_table_pixel;
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci	for (; frac->num; frac++) {
6578c2ecf20Sopenharmony_ci		request = (req->rate * frac->den) / frac->num;
6588c2ecf20Sopenharmony_ci
6598c2ecf20Sopenharmony_ci		src_rate = clk_hw_round_rate(req->best_parent_hw, request);
6608c2ecf20Sopenharmony_ci		if ((src_rate < (request - delta)) ||
6618c2ecf20Sopenharmony_ci			(src_rate > (request + delta)))
6628c2ecf20Sopenharmony_ci			continue;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci		req->best_parent_rate = src_rate;
6658c2ecf20Sopenharmony_ci		req->rate = (src_rate * frac->num) / frac->den;
6668c2ecf20Sopenharmony_ci		return 0;
6678c2ecf20Sopenharmony_ci	}
6688c2ecf20Sopenharmony_ci
6698c2ecf20Sopenharmony_ci	return -EINVAL;
6708c2ecf20Sopenharmony_ci}
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_cistatic int clk_pixel_set_rate(struct clk_hw *hw, unsigned long rate,
6738c2ecf20Sopenharmony_ci		unsigned long parent_rate)
6748c2ecf20Sopenharmony_ci{
6758c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
6768c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
6778c2ecf20Sopenharmony_ci	const struct frac_entry *frac = frac_table_pixel;
6788c2ecf20Sopenharmony_ci	unsigned long request;
6798c2ecf20Sopenharmony_ci	int delta = 100000;
6808c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
6818c2ecf20Sopenharmony_ci	u32 hid_div, cfg;
6828c2ecf20Sopenharmony_ci	int i, num_parents = clk_hw_get_num_parents(hw);
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
6858c2ecf20Sopenharmony_ci	cfg &= CFG_SRC_SEL_MASK;
6868c2ecf20Sopenharmony_ci	cfg >>= CFG_SRC_SEL_SHIFT;
6878c2ecf20Sopenharmony_ci
6888c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++)
6898c2ecf20Sopenharmony_ci		if (cfg == rcg->parent_map[i].cfg) {
6908c2ecf20Sopenharmony_ci			f.src = rcg->parent_map[i].src;
6918c2ecf20Sopenharmony_ci			break;
6928c2ecf20Sopenharmony_ci		}
6938c2ecf20Sopenharmony_ci
6948c2ecf20Sopenharmony_ci	for (; frac->num; frac++) {
6958c2ecf20Sopenharmony_ci		request = (rate * frac->den) / frac->num;
6968c2ecf20Sopenharmony_ci
6978c2ecf20Sopenharmony_ci		if ((parent_rate < (request - delta)) ||
6988c2ecf20Sopenharmony_ci			(parent_rate > (request + delta)))
6998c2ecf20Sopenharmony_ci			continue;
7008c2ecf20Sopenharmony_ci
7018c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
7028c2ecf20Sopenharmony_ci				&hid_div);
7038c2ecf20Sopenharmony_ci		f.pre_div = hid_div;
7048c2ecf20Sopenharmony_ci		f.pre_div >>= CFG_SRC_DIV_SHIFT;
7058c2ecf20Sopenharmony_ci		f.pre_div &= mask;
7068c2ecf20Sopenharmony_ci		f.m = frac->num;
7078c2ecf20Sopenharmony_ci		f.n = frac->den;
7088c2ecf20Sopenharmony_ci
7098c2ecf20Sopenharmony_ci		return clk_rcg2_configure(rcg, &f);
7108c2ecf20Sopenharmony_ci	}
7118c2ecf20Sopenharmony_ci	return -EINVAL;
7128c2ecf20Sopenharmony_ci}
7138c2ecf20Sopenharmony_ci
7148c2ecf20Sopenharmony_cistatic int clk_pixel_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
7158c2ecf20Sopenharmony_ci		unsigned long parent_rate, u8 index)
7168c2ecf20Sopenharmony_ci{
7178c2ecf20Sopenharmony_ci	return clk_pixel_set_rate(hw, rate, parent_rate);
7188c2ecf20Sopenharmony_ci}
7198c2ecf20Sopenharmony_ci
7208c2ecf20Sopenharmony_ciconst struct clk_ops clk_pixel_ops = {
7218c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
7228c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
7238c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
7248c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
7258c2ecf20Sopenharmony_ci	.set_rate = clk_pixel_set_rate,
7268c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_pixel_set_rate_and_parent,
7278c2ecf20Sopenharmony_ci	.determine_rate = clk_pixel_determine_rate,
7288c2ecf20Sopenharmony_ci};
7298c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_pixel_ops);
7308c2ecf20Sopenharmony_ci
7318c2ecf20Sopenharmony_cistatic int clk_gfx3d_determine_rate(struct clk_hw *hw,
7328c2ecf20Sopenharmony_ci				    struct clk_rate_request *req)
7338c2ecf20Sopenharmony_ci{
7348c2ecf20Sopenharmony_ci	struct clk_rate_request parent_req = { };
7358c2ecf20Sopenharmony_ci	struct clk_hw *p2, *p8, *p9, *xo;
7368c2ecf20Sopenharmony_ci	unsigned long p9_rate;
7378c2ecf20Sopenharmony_ci	int ret;
7388c2ecf20Sopenharmony_ci
7398c2ecf20Sopenharmony_ci	xo = clk_hw_get_parent_by_index(hw, 0);
7408c2ecf20Sopenharmony_ci	if (req->rate == clk_hw_get_rate(xo)) {
7418c2ecf20Sopenharmony_ci		req->best_parent_hw = xo;
7428c2ecf20Sopenharmony_ci		return 0;
7438c2ecf20Sopenharmony_ci	}
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	p9 = clk_hw_get_parent_by_index(hw, 2);
7468c2ecf20Sopenharmony_ci	p2 = clk_hw_get_parent_by_index(hw, 3);
7478c2ecf20Sopenharmony_ci	p8 = clk_hw_get_parent_by_index(hw, 4);
7488c2ecf20Sopenharmony_ci
7498c2ecf20Sopenharmony_ci	/* PLL9 is a fixed rate PLL */
7508c2ecf20Sopenharmony_ci	p9_rate = clk_hw_get_rate(p9);
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	parent_req.rate = req->rate = min(req->rate, p9_rate);
7538c2ecf20Sopenharmony_ci	if (req->rate == p9_rate) {
7548c2ecf20Sopenharmony_ci		req->rate = req->best_parent_rate = p9_rate;
7558c2ecf20Sopenharmony_ci		req->best_parent_hw = p9;
7568c2ecf20Sopenharmony_ci		return 0;
7578c2ecf20Sopenharmony_ci	}
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (req->best_parent_hw == p9) {
7608c2ecf20Sopenharmony_ci		/* Are we going back to a previously used rate? */
7618c2ecf20Sopenharmony_ci		if (clk_hw_get_rate(p8) == req->rate)
7628c2ecf20Sopenharmony_ci			req->best_parent_hw = p8;
7638c2ecf20Sopenharmony_ci		else
7648c2ecf20Sopenharmony_ci			req->best_parent_hw = p2;
7658c2ecf20Sopenharmony_ci	} else if (req->best_parent_hw == p8) {
7668c2ecf20Sopenharmony_ci		req->best_parent_hw = p2;
7678c2ecf20Sopenharmony_ci	} else {
7688c2ecf20Sopenharmony_ci		req->best_parent_hw = p8;
7698c2ecf20Sopenharmony_ci	}
7708c2ecf20Sopenharmony_ci
7718c2ecf20Sopenharmony_ci	ret = __clk_determine_rate(req->best_parent_hw, &parent_req);
7728c2ecf20Sopenharmony_ci	if (ret)
7738c2ecf20Sopenharmony_ci		return ret;
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_ci	req->rate = req->best_parent_rate = parent_req.rate;
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_ci	return 0;
7788c2ecf20Sopenharmony_ci}
7798c2ecf20Sopenharmony_ci
7808c2ecf20Sopenharmony_cistatic int clk_gfx3d_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
7818c2ecf20Sopenharmony_ci		unsigned long parent_rate, u8 index)
7828c2ecf20Sopenharmony_ci{
7838c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
7848c2ecf20Sopenharmony_ci	u32 cfg;
7858c2ecf20Sopenharmony_ci	int ret;
7868c2ecf20Sopenharmony_ci
7878c2ecf20Sopenharmony_ci	/* Just mux it, we don't use the division or m/n hardware */
7888c2ecf20Sopenharmony_ci	cfg = rcg->parent_map[index].cfg << CFG_SRC_SEL_SHIFT;
7898c2ecf20Sopenharmony_ci	ret = regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
7908c2ecf20Sopenharmony_ci	if (ret)
7918c2ecf20Sopenharmony_ci		return ret;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return update_config(rcg);
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic int clk_gfx3d_set_rate(struct clk_hw *hw, unsigned long rate,
7978c2ecf20Sopenharmony_ci			      unsigned long parent_rate)
7988c2ecf20Sopenharmony_ci{
7998c2ecf20Sopenharmony_ci	/*
8008c2ecf20Sopenharmony_ci	 * We should never get here; clk_gfx3d_determine_rate() should always
8018c2ecf20Sopenharmony_ci	 * make us use a different parent than what we're currently using, so
8028c2ecf20Sopenharmony_ci	 * clk_gfx3d_set_rate_and_parent() should always be called.
8038c2ecf20Sopenharmony_ci	 */
8048c2ecf20Sopenharmony_ci	return 0;
8058c2ecf20Sopenharmony_ci}
8068c2ecf20Sopenharmony_ci
8078c2ecf20Sopenharmony_ciconst struct clk_ops clk_gfx3d_ops = {
8088c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
8098c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
8108c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
8118c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
8128c2ecf20Sopenharmony_ci	.set_rate = clk_gfx3d_set_rate,
8138c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_gfx3d_set_rate_and_parent,
8148c2ecf20Sopenharmony_ci	.determine_rate = clk_gfx3d_determine_rate,
8158c2ecf20Sopenharmony_ci};
8168c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_gfx3d_ops);
8178c2ecf20Sopenharmony_ci
8188c2ecf20Sopenharmony_cistatic int clk_rcg2_set_force_enable(struct clk_hw *hw)
8198c2ecf20Sopenharmony_ci{
8208c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
8218c2ecf20Sopenharmony_ci	const char *name = clk_hw_get_name(hw);
8228c2ecf20Sopenharmony_ci	int ret, count;
8238c2ecf20Sopenharmony_ci
8248c2ecf20Sopenharmony_ci	ret = regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
8258c2ecf20Sopenharmony_ci				 CMD_ROOT_EN, CMD_ROOT_EN);
8268c2ecf20Sopenharmony_ci	if (ret)
8278c2ecf20Sopenharmony_ci		return ret;
8288c2ecf20Sopenharmony_ci
8298c2ecf20Sopenharmony_ci	/* wait for RCG to turn ON */
8308c2ecf20Sopenharmony_ci	for (count = 500; count > 0; count--) {
8318c2ecf20Sopenharmony_ci		if (clk_rcg2_is_enabled(hw))
8328c2ecf20Sopenharmony_ci			return 0;
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci		udelay(1);
8358c2ecf20Sopenharmony_ci	}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	pr_err("%s: RCG did not turn on\n", name);
8388c2ecf20Sopenharmony_ci	return -ETIMEDOUT;
8398c2ecf20Sopenharmony_ci}
8408c2ecf20Sopenharmony_ci
8418c2ecf20Sopenharmony_cistatic int clk_rcg2_clear_force_enable(struct clk_hw *hw)
8428c2ecf20Sopenharmony_ci{
8438c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
8448c2ecf20Sopenharmony_ci
8458c2ecf20Sopenharmony_ci	return regmap_update_bits(rcg->clkr.regmap, rcg->cmd_rcgr + CMD_REG,
8468c2ecf20Sopenharmony_ci					CMD_ROOT_EN, 0);
8478c2ecf20Sopenharmony_ci}
8488c2ecf20Sopenharmony_ci
8498c2ecf20Sopenharmony_cistatic int
8508c2ecf20Sopenharmony_ciclk_rcg2_shared_force_enable_clear(struct clk_hw *hw, const struct freq_tbl *f)
8518c2ecf20Sopenharmony_ci{
8528c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
8538c2ecf20Sopenharmony_ci	int ret;
8548c2ecf20Sopenharmony_ci
8558c2ecf20Sopenharmony_ci	ret = clk_rcg2_set_force_enable(hw);
8568c2ecf20Sopenharmony_ci	if (ret)
8578c2ecf20Sopenharmony_ci		return ret;
8588c2ecf20Sopenharmony_ci
8598c2ecf20Sopenharmony_ci	ret = clk_rcg2_configure(rcg, f);
8608c2ecf20Sopenharmony_ci	if (ret)
8618c2ecf20Sopenharmony_ci		return ret;
8628c2ecf20Sopenharmony_ci
8638c2ecf20Sopenharmony_ci	return clk_rcg2_clear_force_enable(hw);
8648c2ecf20Sopenharmony_ci}
8658c2ecf20Sopenharmony_ci
8668c2ecf20Sopenharmony_cistatic int clk_rcg2_shared_set_rate(struct clk_hw *hw, unsigned long rate,
8678c2ecf20Sopenharmony_ci				    unsigned long parent_rate)
8688c2ecf20Sopenharmony_ci{
8698c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
8708c2ecf20Sopenharmony_ci	const struct freq_tbl *f;
8718c2ecf20Sopenharmony_ci
8728c2ecf20Sopenharmony_ci	f = qcom_find_freq(rcg->freq_tbl, rate);
8738c2ecf20Sopenharmony_ci	if (!f)
8748c2ecf20Sopenharmony_ci		return -EINVAL;
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci	/*
8778c2ecf20Sopenharmony_ci	 * In case clock is disabled, update the CFG, M, N and D registers
8788c2ecf20Sopenharmony_ci	 * and don't hit the update bit of CMD register.
8798c2ecf20Sopenharmony_ci	 */
8808c2ecf20Sopenharmony_ci	if (!__clk_is_enabled(hw->clk))
8818c2ecf20Sopenharmony_ci		return __clk_rcg2_configure(rcg, f);
8828c2ecf20Sopenharmony_ci
8838c2ecf20Sopenharmony_ci	return clk_rcg2_shared_force_enable_clear(hw, f);
8848c2ecf20Sopenharmony_ci}
8858c2ecf20Sopenharmony_ci
8868c2ecf20Sopenharmony_cistatic int clk_rcg2_shared_set_rate_and_parent(struct clk_hw *hw,
8878c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
8888c2ecf20Sopenharmony_ci{
8898c2ecf20Sopenharmony_ci	return clk_rcg2_shared_set_rate(hw, rate, parent_rate);
8908c2ecf20Sopenharmony_ci}
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_cistatic int clk_rcg2_shared_enable(struct clk_hw *hw)
8938c2ecf20Sopenharmony_ci{
8948c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
8958c2ecf20Sopenharmony_ci	int ret;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	/*
8988c2ecf20Sopenharmony_ci	 * Set the update bit because required configuration has already
8998c2ecf20Sopenharmony_ci	 * been written in clk_rcg2_shared_set_rate()
9008c2ecf20Sopenharmony_ci	 */
9018c2ecf20Sopenharmony_ci	ret = clk_rcg2_set_force_enable(hw);
9028c2ecf20Sopenharmony_ci	if (ret)
9038c2ecf20Sopenharmony_ci		return ret;
9048c2ecf20Sopenharmony_ci
9058c2ecf20Sopenharmony_ci	ret = update_config(rcg);
9068c2ecf20Sopenharmony_ci	if (ret)
9078c2ecf20Sopenharmony_ci		return ret;
9088c2ecf20Sopenharmony_ci
9098c2ecf20Sopenharmony_ci	return clk_rcg2_clear_force_enable(hw);
9108c2ecf20Sopenharmony_ci}
9118c2ecf20Sopenharmony_ci
9128c2ecf20Sopenharmony_cistatic void clk_rcg2_shared_disable(struct clk_hw *hw)
9138c2ecf20Sopenharmony_ci{
9148c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
9158c2ecf20Sopenharmony_ci	u32 cfg;
9168c2ecf20Sopenharmony_ci
9178c2ecf20Sopenharmony_ci	/*
9188c2ecf20Sopenharmony_ci	 * Store current configuration as switching to safe source would clear
9198c2ecf20Sopenharmony_ci	 * the SRC and DIV of CFG register
9208c2ecf20Sopenharmony_ci	 */
9218c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
9228c2ecf20Sopenharmony_ci
9238c2ecf20Sopenharmony_ci	/*
9248c2ecf20Sopenharmony_ci	 * Park the RCG at a safe configuration - sourced off of safe source.
9258c2ecf20Sopenharmony_ci	 * Force enable and disable the RCG while configuring it to safeguard
9268c2ecf20Sopenharmony_ci	 * against any update signal coming from the downstream clock.
9278c2ecf20Sopenharmony_ci	 * The current parent is still prepared and enabled at this point, and
9288c2ecf20Sopenharmony_ci	 * the safe source is always on while application processor subsystem
9298c2ecf20Sopenharmony_ci	 * is online. Therefore, the RCG can safely switch its parent.
9308c2ecf20Sopenharmony_ci	 */
9318c2ecf20Sopenharmony_ci	clk_rcg2_set_force_enable(hw);
9328c2ecf20Sopenharmony_ci
9338c2ecf20Sopenharmony_ci	regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG,
9348c2ecf20Sopenharmony_ci		     rcg->safe_src_index << CFG_SRC_SEL_SHIFT);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	update_config(rcg);
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci	clk_rcg2_clear_force_enable(hw);
9398c2ecf20Sopenharmony_ci
9408c2ecf20Sopenharmony_ci	/* Write back the stored configuration corresponding to current rate */
9418c2ecf20Sopenharmony_ci	regmap_write(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, cfg);
9428c2ecf20Sopenharmony_ci}
9438c2ecf20Sopenharmony_ci
9448c2ecf20Sopenharmony_ciconst struct clk_ops clk_rcg2_shared_ops = {
9458c2ecf20Sopenharmony_ci	.enable = clk_rcg2_shared_enable,
9468c2ecf20Sopenharmony_ci	.disable = clk_rcg2_shared_disable,
9478c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
9488c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
9498c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
9508c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg2_determine_rate,
9518c2ecf20Sopenharmony_ci	.set_rate = clk_rcg2_shared_set_rate,
9528c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg2_shared_set_rate_and_parent,
9538c2ecf20Sopenharmony_ci};
9548c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_rcg2_shared_ops);
9558c2ecf20Sopenharmony_ci
9568c2ecf20Sopenharmony_ci/* Common APIs to be used for DFS based RCGR */
9578c2ecf20Sopenharmony_cistatic void clk_rcg2_dfs_populate_freq(struct clk_hw *hw, unsigned int l,
9588c2ecf20Sopenharmony_ci				       struct freq_tbl *f)
9598c2ecf20Sopenharmony_ci{
9608c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
9618c2ecf20Sopenharmony_ci	struct clk_hw *p;
9628c2ecf20Sopenharmony_ci	unsigned long prate = 0;
9638c2ecf20Sopenharmony_ci	u32 val, mask, cfg, mode, src;
9648c2ecf20Sopenharmony_ci	int i, num_parents;
9658c2ecf20Sopenharmony_ci
9668c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(l), &cfg);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	mask = BIT(rcg->hid_width) - 1;
9698c2ecf20Sopenharmony_ci	f->pre_div = 1;
9708c2ecf20Sopenharmony_ci	if (cfg & mask)
9718c2ecf20Sopenharmony_ci		f->pre_div = cfg & mask;
9728c2ecf20Sopenharmony_ci
9738c2ecf20Sopenharmony_ci	src = cfg & CFG_SRC_SEL_MASK;
9748c2ecf20Sopenharmony_ci	src >>= CFG_SRC_SEL_SHIFT;
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci	num_parents = clk_hw_get_num_parents(hw);
9778c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++) {
9788c2ecf20Sopenharmony_ci		if (src == rcg->parent_map[i].cfg) {
9798c2ecf20Sopenharmony_ci			f->src = rcg->parent_map[i].src;
9808c2ecf20Sopenharmony_ci			p = clk_hw_get_parent_by_index(&rcg->clkr.hw, i);
9818c2ecf20Sopenharmony_ci			prate = clk_hw_get_rate(p);
9828c2ecf20Sopenharmony_ci		}
9838c2ecf20Sopenharmony_ci	}
9848c2ecf20Sopenharmony_ci
9858c2ecf20Sopenharmony_ci	mode = cfg & CFG_MODE_MASK;
9868c2ecf20Sopenharmony_ci	mode >>= CFG_MODE_SHIFT;
9878c2ecf20Sopenharmony_ci	if (mode) {
9888c2ecf20Sopenharmony_ci		mask = BIT(rcg->mnd_width) - 1;
9898c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_M_DFSR(l),
9908c2ecf20Sopenharmony_ci			    &val);
9918c2ecf20Sopenharmony_ci		val &= mask;
9928c2ecf20Sopenharmony_ci		f->m = val;
9938c2ecf20Sopenharmony_ci
9948c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_N_DFSR(l),
9958c2ecf20Sopenharmony_ci			    &val);
9968c2ecf20Sopenharmony_ci		val = ~val;
9978c2ecf20Sopenharmony_ci		val &= mask;
9988c2ecf20Sopenharmony_ci		val += f->m;
9998c2ecf20Sopenharmony_ci		f->n = val;
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci	f->freq = calc_rate(prate, f->m, f->n, mode, f->pre_div);
10038c2ecf20Sopenharmony_ci}
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_cistatic int clk_rcg2_dfs_populate_freq_table(struct clk_rcg2 *rcg)
10068c2ecf20Sopenharmony_ci{
10078c2ecf20Sopenharmony_ci	struct freq_tbl *freq_tbl;
10088c2ecf20Sopenharmony_ci	int i;
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	/* Allocate space for 1 extra since table is NULL terminated */
10118c2ecf20Sopenharmony_ci	freq_tbl = kcalloc(MAX_PERF_LEVEL + 1, sizeof(*freq_tbl), GFP_KERNEL);
10128c2ecf20Sopenharmony_ci	if (!freq_tbl)
10138c2ecf20Sopenharmony_ci		return -ENOMEM;
10148c2ecf20Sopenharmony_ci	rcg->freq_tbl = freq_tbl;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_PERF_LEVEL; i++)
10178c2ecf20Sopenharmony_ci		clk_rcg2_dfs_populate_freq(&rcg->clkr.hw, i, freq_tbl + i);
10188c2ecf20Sopenharmony_ci
10198c2ecf20Sopenharmony_ci	return 0;
10208c2ecf20Sopenharmony_ci}
10218c2ecf20Sopenharmony_ci
10228c2ecf20Sopenharmony_cistatic int clk_rcg2_dfs_determine_rate(struct clk_hw *hw,
10238c2ecf20Sopenharmony_ci				   struct clk_rate_request *req)
10248c2ecf20Sopenharmony_ci{
10258c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
10268c2ecf20Sopenharmony_ci	int ret;
10278c2ecf20Sopenharmony_ci
10288c2ecf20Sopenharmony_ci	if (!rcg->freq_tbl) {
10298c2ecf20Sopenharmony_ci		ret = clk_rcg2_dfs_populate_freq_table(rcg);
10308c2ecf20Sopenharmony_ci		if (ret) {
10318c2ecf20Sopenharmony_ci			pr_err("Failed to update DFS tables for %s\n",
10328c2ecf20Sopenharmony_ci					clk_hw_get_name(hw));
10338c2ecf20Sopenharmony_ci			return ret;
10348c2ecf20Sopenharmony_ci		}
10358c2ecf20Sopenharmony_ci	}
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci	return clk_rcg2_determine_rate(hw, req);
10388c2ecf20Sopenharmony_ci}
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_cistatic unsigned long
10418c2ecf20Sopenharmony_ciclk_rcg2_dfs_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
10428c2ecf20Sopenharmony_ci{
10438c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
10448c2ecf20Sopenharmony_ci	u32 level, mask, cfg, m = 0, n = 0, mode, pre_div;
10458c2ecf20Sopenharmony_ci
10468c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap,
10478c2ecf20Sopenharmony_ci		    rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &level);
10488c2ecf20Sopenharmony_ci	level &= GENMASK(4, 1);
10498c2ecf20Sopenharmony_ci	level >>= 1;
10508c2ecf20Sopenharmony_ci
10518c2ecf20Sopenharmony_ci	if (rcg->freq_tbl)
10528c2ecf20Sopenharmony_ci		return rcg->freq_tbl[level].freq;
10538c2ecf20Sopenharmony_ci
10548c2ecf20Sopenharmony_ci	/*
10558c2ecf20Sopenharmony_ci	 * Assume that parent_rate is actually the parent because
10568c2ecf20Sopenharmony_ci	 * we can't do any better at figuring it out when the table
10578c2ecf20Sopenharmony_ci	 * hasn't been populated yet. We only populate the table
10588c2ecf20Sopenharmony_ci	 * in determine_rate because we can't guarantee the parents
10598c2ecf20Sopenharmony_ci	 * will be registered with the framework until then.
10608c2ecf20Sopenharmony_ci	 */
10618c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + SE_PERF_DFSR(level),
10628c2ecf20Sopenharmony_ci		    &cfg);
10638c2ecf20Sopenharmony_ci
10648c2ecf20Sopenharmony_ci	mask = BIT(rcg->hid_width) - 1;
10658c2ecf20Sopenharmony_ci	pre_div = 1;
10668c2ecf20Sopenharmony_ci	if (cfg & mask)
10678c2ecf20Sopenharmony_ci		pre_div = cfg & mask;
10688c2ecf20Sopenharmony_ci
10698c2ecf20Sopenharmony_ci	mode = cfg & CFG_MODE_MASK;
10708c2ecf20Sopenharmony_ci	mode >>= CFG_MODE_SHIFT;
10718c2ecf20Sopenharmony_ci	if (mode) {
10728c2ecf20Sopenharmony_ci		mask = BIT(rcg->mnd_width) - 1;
10738c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap,
10748c2ecf20Sopenharmony_ci			    rcg->cmd_rcgr + SE_PERF_M_DFSR(level), &m);
10758c2ecf20Sopenharmony_ci		m &= mask;
10768c2ecf20Sopenharmony_ci
10778c2ecf20Sopenharmony_ci		regmap_read(rcg->clkr.regmap,
10788c2ecf20Sopenharmony_ci			    rcg->cmd_rcgr + SE_PERF_N_DFSR(level), &n);
10798c2ecf20Sopenharmony_ci		n = ~n;
10808c2ecf20Sopenharmony_ci		n &= mask;
10818c2ecf20Sopenharmony_ci		n += m;
10828c2ecf20Sopenharmony_ci	}
10838c2ecf20Sopenharmony_ci
10848c2ecf20Sopenharmony_ci	return calc_rate(parent_rate, m, n, mode, pre_div);
10858c2ecf20Sopenharmony_ci}
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_cistatic const struct clk_ops clk_rcg2_dfs_ops = {
10888c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
10898c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
10908c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg2_dfs_determine_rate,
10918c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_dfs_recalc_rate,
10928c2ecf20Sopenharmony_ci};
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_cistatic int clk_rcg2_enable_dfs(const struct clk_rcg_dfs_data *data,
10958c2ecf20Sopenharmony_ci			       struct regmap *regmap)
10968c2ecf20Sopenharmony_ci{
10978c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = data->rcg;
10988c2ecf20Sopenharmony_ci	struct clk_init_data *init = data->init;
10998c2ecf20Sopenharmony_ci	u32 val;
11008c2ecf20Sopenharmony_ci	int ret;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	ret = regmap_read(regmap, rcg->cmd_rcgr + SE_CMD_DFSR_OFFSET, &val);
11038c2ecf20Sopenharmony_ci	if (ret)
11048c2ecf20Sopenharmony_ci		return -EINVAL;
11058c2ecf20Sopenharmony_ci
11068c2ecf20Sopenharmony_ci	if (!(val & SE_CMD_DFS_EN))
11078c2ecf20Sopenharmony_ci		return 0;
11088c2ecf20Sopenharmony_ci
11098c2ecf20Sopenharmony_ci	/*
11108c2ecf20Sopenharmony_ci	 * Rate changes with consumer writing a register in
11118c2ecf20Sopenharmony_ci	 * their own I/O region
11128c2ecf20Sopenharmony_ci	 */
11138c2ecf20Sopenharmony_ci	init->flags |= CLK_GET_RATE_NOCACHE;
11148c2ecf20Sopenharmony_ci	init->ops = &clk_rcg2_dfs_ops;
11158c2ecf20Sopenharmony_ci
11168c2ecf20Sopenharmony_ci	rcg->freq_tbl = NULL;
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_ci	return 0;
11198c2ecf20Sopenharmony_ci}
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ciint qcom_cc_register_rcg_dfs(struct regmap *regmap,
11228c2ecf20Sopenharmony_ci			     const struct clk_rcg_dfs_data *rcgs, size_t len)
11238c2ecf20Sopenharmony_ci{
11248c2ecf20Sopenharmony_ci	int i, ret;
11258c2ecf20Sopenharmony_ci
11268c2ecf20Sopenharmony_ci	for (i = 0; i < len; i++) {
11278c2ecf20Sopenharmony_ci		ret = clk_rcg2_enable_dfs(&rcgs[i], regmap);
11288c2ecf20Sopenharmony_ci		if (ret)
11298c2ecf20Sopenharmony_ci			return ret;
11308c2ecf20Sopenharmony_ci	}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_ci	return 0;
11338c2ecf20Sopenharmony_ci}
11348c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(qcom_cc_register_rcg_dfs);
11358c2ecf20Sopenharmony_ci
11368c2ecf20Sopenharmony_cistatic int clk_rcg2_dp_set_rate(struct clk_hw *hw, unsigned long rate,
11378c2ecf20Sopenharmony_ci			unsigned long parent_rate)
11388c2ecf20Sopenharmony_ci{
11398c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
11408c2ecf20Sopenharmony_ci	struct freq_tbl f = { 0 };
11418c2ecf20Sopenharmony_ci	u32 mask = BIT(rcg->hid_width) - 1;
11428c2ecf20Sopenharmony_ci	u32 hid_div, cfg;
11438c2ecf20Sopenharmony_ci	int i, num_parents = clk_hw_get_num_parents(hw);
11448c2ecf20Sopenharmony_ci	unsigned long num, den;
11458c2ecf20Sopenharmony_ci
11468c2ecf20Sopenharmony_ci	rational_best_approximation(parent_rate, rate,
11478c2ecf20Sopenharmony_ci			GENMASK(rcg->mnd_width - 1, 0),
11488c2ecf20Sopenharmony_ci			GENMASK(rcg->mnd_width - 1, 0), &den, &num);
11498c2ecf20Sopenharmony_ci
11508c2ecf20Sopenharmony_ci	if (!num || !den)
11518c2ecf20Sopenharmony_ci		return -EINVAL;
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_ci	regmap_read(rcg->clkr.regmap, rcg->cmd_rcgr + CFG_REG, &cfg);
11548c2ecf20Sopenharmony_ci	hid_div = cfg;
11558c2ecf20Sopenharmony_ci	cfg &= CFG_SRC_SEL_MASK;
11568c2ecf20Sopenharmony_ci	cfg >>= CFG_SRC_SEL_SHIFT;
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_ci	for (i = 0; i < num_parents; i++) {
11598c2ecf20Sopenharmony_ci		if (cfg == rcg->parent_map[i].cfg) {
11608c2ecf20Sopenharmony_ci			f.src = rcg->parent_map[i].src;
11618c2ecf20Sopenharmony_ci			break;
11628c2ecf20Sopenharmony_ci		}
11638c2ecf20Sopenharmony_ci	}
11648c2ecf20Sopenharmony_ci
11658c2ecf20Sopenharmony_ci	f.pre_div = hid_div;
11668c2ecf20Sopenharmony_ci	f.pre_div >>= CFG_SRC_DIV_SHIFT;
11678c2ecf20Sopenharmony_ci	f.pre_div &= mask;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	if (num != den) {
11708c2ecf20Sopenharmony_ci		f.m = num;
11718c2ecf20Sopenharmony_ci		f.n = den;
11728c2ecf20Sopenharmony_ci	} else {
11738c2ecf20Sopenharmony_ci		f.m = 0;
11748c2ecf20Sopenharmony_ci		f.n = 0;
11758c2ecf20Sopenharmony_ci	}
11768c2ecf20Sopenharmony_ci
11778c2ecf20Sopenharmony_ci	return clk_rcg2_configure(rcg, &f);
11788c2ecf20Sopenharmony_ci}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_cistatic int clk_rcg2_dp_set_rate_and_parent(struct clk_hw *hw,
11818c2ecf20Sopenharmony_ci		unsigned long rate, unsigned long parent_rate, u8 index)
11828c2ecf20Sopenharmony_ci{
11838c2ecf20Sopenharmony_ci	return clk_rcg2_dp_set_rate(hw, rate, parent_rate);
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic int clk_rcg2_dp_determine_rate(struct clk_hw *hw,
11878c2ecf20Sopenharmony_ci				struct clk_rate_request *req)
11888c2ecf20Sopenharmony_ci{
11898c2ecf20Sopenharmony_ci	struct clk_rcg2 *rcg = to_clk_rcg2(hw);
11908c2ecf20Sopenharmony_ci	unsigned long num, den;
11918c2ecf20Sopenharmony_ci	u64 tmp;
11928c2ecf20Sopenharmony_ci
11938c2ecf20Sopenharmony_ci	/* Parent rate is a fixed phy link rate */
11948c2ecf20Sopenharmony_ci	rational_best_approximation(req->best_parent_rate, req->rate,
11958c2ecf20Sopenharmony_ci			GENMASK(rcg->mnd_width - 1, 0),
11968c2ecf20Sopenharmony_ci			GENMASK(rcg->mnd_width - 1, 0), &den, &num);
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_ci	if (!num || !den)
11998c2ecf20Sopenharmony_ci		return -EINVAL;
12008c2ecf20Sopenharmony_ci
12018c2ecf20Sopenharmony_ci	tmp = req->best_parent_rate * num;
12028c2ecf20Sopenharmony_ci	do_div(tmp, den);
12038c2ecf20Sopenharmony_ci	req->rate = tmp;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	return 0;
12068c2ecf20Sopenharmony_ci}
12078c2ecf20Sopenharmony_ci
12088c2ecf20Sopenharmony_ciconst struct clk_ops clk_dp_ops = {
12098c2ecf20Sopenharmony_ci	.is_enabled = clk_rcg2_is_enabled,
12108c2ecf20Sopenharmony_ci	.get_parent = clk_rcg2_get_parent,
12118c2ecf20Sopenharmony_ci	.set_parent = clk_rcg2_set_parent,
12128c2ecf20Sopenharmony_ci	.recalc_rate = clk_rcg2_recalc_rate,
12138c2ecf20Sopenharmony_ci	.set_rate = clk_rcg2_dp_set_rate,
12148c2ecf20Sopenharmony_ci	.set_rate_and_parent = clk_rcg2_dp_set_rate_and_parent,
12158c2ecf20Sopenharmony_ci	.determine_rate = clk_rcg2_dp_determine_rate,
12168c2ecf20Sopenharmony_ci};
12178c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(clk_dp_ops);
1218