mirror of
				git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
				synced 2025-10-31 08:44:41 +00:00 
			
		
		
		
	 c942fddf87
			
		
	
	
		c942fddf87
		
	
	
	
	
		
			
			Based on 3 normalized pattern(s): this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details this program is free software you can redistribute it and or modify it under the terms of the gnu general public license as published by the free software foundation either version 2 of the license or at your option any later version [author] [graeme] [gregory] [gg]@[slimlogic] [co] [uk] [author] [kishon] [vijay] [abraham] [i] [kishon]@[ti] [com] [based] [on] [twl6030]_[usb] [c] [author] [hema] [hk] [hemahk]@[ti] [com] this program is distributed in the hope that it will be useful but without any warranty without even the implied warranty of merchantability or fitness for a particular purpose see the gnu general public license for more details extracted by the scancode license scanner the SPDX license identifier GPL-2.0-or-later has been chosen to replace the boilerplate/reference in 1105 file(s). Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Allison Randal <allison@lohutok.net> Reviewed-by: Richard Fontana <rfontana@redhat.com> Reviewed-by: Kate Stewart <kstewart@linuxfoundation.org> Cc: linux-spdx@vger.kernel.org Link: https://lkml.kernel.org/r/20190527070033.202006027@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
		
			
				
	
	
		
			138 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
	
		
			3.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0-or-later
 | |
| /*
 | |
|  * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
 | |
|  * Author: Lin Huang <hl@rock-chips.com>
 | |
|  */
 | |
| 
 | |
| #include <linux/arm-smccc.h>
 | |
| #include <linux/clk.h>
 | |
| #include <linux/clk-provider.h>
 | |
| #include <linux/io.h>
 | |
| #include <linux/slab.h>
 | |
| #include <soc/rockchip/rockchip_sip.h>
 | |
| #include "clk.h"
 | |
| 
 | |
| struct rockchip_ddrclk {
 | |
| 	struct clk_hw	hw;
 | |
| 	void __iomem	*reg_base;
 | |
| 	int		mux_offset;
 | |
| 	int		mux_shift;
 | |
| 	int		mux_width;
 | |
| 	int		div_shift;
 | |
| 	int		div_width;
 | |
| 	int		ddr_flag;
 | |
| 	spinlock_t	*lock;
 | |
| };
 | |
| 
 | |
| #define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw)
 | |
| 
 | |
| static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate,
 | |
| 					unsigned long prate)
 | |
| {
 | |
| 	struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
 | |
| 	unsigned long flags;
 | |
| 	struct arm_smccc_res res;
 | |
| 
 | |
| 	spin_lock_irqsave(ddrclk->lock, flags);
 | |
| 	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, drate, 0,
 | |
| 		      ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE,
 | |
| 		      0, 0, 0, 0, &res);
 | |
| 	spin_unlock_irqrestore(ddrclk->lock, flags);
 | |
| 
 | |
| 	return res.a0;
 | |
| }
 | |
| 
 | |
| static unsigned long
 | |
| rockchip_ddrclk_sip_recalc_rate(struct clk_hw *hw,
 | |
| 				unsigned long parent_rate)
 | |
| {
 | |
| 	struct arm_smccc_res res;
 | |
| 
 | |
| 	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
 | |
| 		      ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE,
 | |
| 		      0, 0, 0, 0, &res);
 | |
| 
 | |
| 	return res.a0;
 | |
| }
 | |
| 
 | |
| static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw,
 | |
| 					   unsigned long rate,
 | |
| 					   unsigned long *prate)
 | |
| {
 | |
| 	struct arm_smccc_res res;
 | |
| 
 | |
| 	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, rate, 0,
 | |
| 		      ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE,
 | |
| 		      0, 0, 0, 0, &res);
 | |
| 
 | |
| 	return res.a0;
 | |
| }
 | |
| 
 | |
| static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw)
 | |
| {
 | |
| 	struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
 | |
| 	u32 val;
 | |
| 
 | |
| 	val = readl(ddrclk->reg_base +
 | |
| 			ddrclk->mux_offset) >> ddrclk->mux_shift;
 | |
| 	val &= GENMASK(ddrclk->mux_width - 1, 0);
 | |
| 
 | |
| 	return val;
 | |
| }
 | |
| 
 | |
| static const struct clk_ops rockchip_ddrclk_sip_ops = {
 | |
| 	.recalc_rate = rockchip_ddrclk_sip_recalc_rate,
 | |
| 	.set_rate = rockchip_ddrclk_sip_set_rate,
 | |
| 	.round_rate = rockchip_ddrclk_sip_round_rate,
 | |
| 	.get_parent = rockchip_ddrclk_get_parent,
 | |
| };
 | |
| 
 | |
| struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
 | |
| 					 const char *const *parent_names,
 | |
| 					 u8 num_parents, int mux_offset,
 | |
| 					 int mux_shift, int mux_width,
 | |
| 					 int div_shift, int div_width,
 | |
| 					 int ddr_flag, void __iomem *reg_base,
 | |
| 					 spinlock_t *lock)
 | |
| {
 | |
| 	struct rockchip_ddrclk *ddrclk;
 | |
| 	struct clk_init_data init;
 | |
| 	struct clk *clk;
 | |
| 
 | |
| 	ddrclk = kzalloc(sizeof(*ddrclk), GFP_KERNEL);
 | |
| 	if (!ddrclk)
 | |
| 		return ERR_PTR(-ENOMEM);
 | |
| 
 | |
| 	init.name = name;
 | |
| 	init.parent_names = parent_names;
 | |
| 	init.num_parents = num_parents;
 | |
| 
 | |
| 	init.flags = flags;
 | |
| 	init.flags |= CLK_SET_RATE_NO_REPARENT;
 | |
| 
 | |
| 	switch (ddr_flag) {
 | |
| 	case ROCKCHIP_DDRCLK_SIP:
 | |
| 		init.ops = &rockchip_ddrclk_sip_ops;
 | |
| 		break;
 | |
| 	default:
 | |
| 		pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag);
 | |
| 		kfree(ddrclk);
 | |
| 		return ERR_PTR(-EINVAL);
 | |
| 	}
 | |
| 
 | |
| 	ddrclk->reg_base = reg_base;
 | |
| 	ddrclk->lock = lock;
 | |
| 	ddrclk->hw.init = &init;
 | |
| 	ddrclk->mux_offset = mux_offset;
 | |
| 	ddrclk->mux_shift = mux_shift;
 | |
| 	ddrclk->mux_width = mux_width;
 | |
| 	ddrclk->div_shift = div_shift;
 | |
| 	ddrclk->div_width = div_width;
 | |
| 	ddrclk->ddr_flag = ddr_flag;
 | |
| 
 | |
| 	clk = clk_register(NULL, &ddrclk->hw);
 | |
| 	if (IS_ERR(clk))
 | |
| 		kfree(ddrclk);
 | |
| 
 | |
| 	return clk;
 | |
| }
 |