cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clk-ddr.c (3360B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (c) 2016 Rockchip Electronics Co. Ltd.
      4 * Author: Lin Huang <hl@rock-chips.com>
      5 */
      6
      7#include <linux/arm-smccc.h>
      8#include <linux/clk.h>
      9#include <linux/clk-provider.h>
     10#include <linux/io.h>
     11#include <linux/slab.h>
     12#include <soc/rockchip/rockchip_sip.h>
     13#include "clk.h"
     14
     15struct rockchip_ddrclk {
     16	struct clk_hw	hw;
     17	void __iomem	*reg_base;
     18	int		mux_offset;
     19	int		mux_shift;
     20	int		mux_width;
     21	int		div_shift;
     22	int		div_width;
     23	int		ddr_flag;
     24	spinlock_t	*lock;
     25};
     26
     27#define to_rockchip_ddrclk_hw(hw) container_of(hw, struct rockchip_ddrclk, hw)
     28
     29static int rockchip_ddrclk_sip_set_rate(struct clk_hw *hw, unsigned long drate,
     30					unsigned long prate)
     31{
     32	struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
     33	unsigned long flags;
     34	struct arm_smccc_res res;
     35
     36	spin_lock_irqsave(ddrclk->lock, flags);
     37	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, drate, 0,
     38		      ROCKCHIP_SIP_CONFIG_DRAM_SET_RATE,
     39		      0, 0, 0, 0, &res);
     40	spin_unlock_irqrestore(ddrclk->lock, flags);
     41
     42	return res.a0;
     43}
     44
     45static unsigned long
     46rockchip_ddrclk_sip_recalc_rate(struct clk_hw *hw,
     47				unsigned long parent_rate)
     48{
     49	struct arm_smccc_res res;
     50
     51	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
     52		      ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE,
     53		      0, 0, 0, 0, &res);
     54
     55	return res.a0;
     56}
     57
     58static long rockchip_ddrclk_sip_round_rate(struct clk_hw *hw,
     59					   unsigned long rate,
     60					   unsigned long *prate)
     61{
     62	struct arm_smccc_res res;
     63
     64	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, rate, 0,
     65		      ROCKCHIP_SIP_CONFIG_DRAM_ROUND_RATE,
     66		      0, 0, 0, 0, &res);
     67
     68	return res.a0;
     69}
     70
     71static u8 rockchip_ddrclk_get_parent(struct clk_hw *hw)
     72{
     73	struct rockchip_ddrclk *ddrclk = to_rockchip_ddrclk_hw(hw);
     74	u32 val;
     75
     76	val = readl(ddrclk->reg_base +
     77			ddrclk->mux_offset) >> ddrclk->mux_shift;
     78	val &= GENMASK(ddrclk->mux_width - 1, 0);
     79
     80	return val;
     81}
     82
     83static const struct clk_ops rockchip_ddrclk_sip_ops = {
     84	.recalc_rate = rockchip_ddrclk_sip_recalc_rate,
     85	.set_rate = rockchip_ddrclk_sip_set_rate,
     86	.round_rate = rockchip_ddrclk_sip_round_rate,
     87	.get_parent = rockchip_ddrclk_get_parent,
     88};
     89
     90struct clk *rockchip_clk_register_ddrclk(const char *name, int flags,
     91					 const char *const *parent_names,
     92					 u8 num_parents, int mux_offset,
     93					 int mux_shift, int mux_width,
     94					 int div_shift, int div_width,
     95					 int ddr_flag, void __iomem *reg_base,
     96					 spinlock_t *lock)
     97{
     98	struct rockchip_ddrclk *ddrclk;
     99	struct clk_init_data init;
    100	struct clk *clk;
    101
    102	ddrclk = kzalloc(sizeof(*ddrclk), GFP_KERNEL);
    103	if (!ddrclk)
    104		return ERR_PTR(-ENOMEM);
    105
    106	init.name = name;
    107	init.parent_names = parent_names;
    108	init.num_parents = num_parents;
    109
    110	init.flags = flags;
    111	init.flags |= CLK_SET_RATE_NO_REPARENT;
    112
    113	switch (ddr_flag) {
    114	case ROCKCHIP_DDRCLK_SIP:
    115		init.ops = &rockchip_ddrclk_sip_ops;
    116		break;
    117	default:
    118		pr_err("%s: unsupported ddrclk type %d\n", __func__, ddr_flag);
    119		kfree(ddrclk);
    120		return ERR_PTR(-EINVAL);
    121	}
    122
    123	ddrclk->reg_base = reg_base;
    124	ddrclk->lock = lock;
    125	ddrclk->hw.init = &init;
    126	ddrclk->mux_offset = mux_offset;
    127	ddrclk->mux_shift = mux_shift;
    128	ddrclk->mux_width = mux_width;
    129	ddrclk->div_shift = div_shift;
    130	ddrclk->div_width = div_width;
    131	ddrclk->ddr_flag = ddr_flag;
    132
    133	clk = clk_register(NULL, &ddrclk->hw);
    134	if (IS_ERR(clk))
    135		kfree(ddrclk);
    136
    137	return clk;
    138}
    139EXPORT_SYMBOL_GPL(rockchip_clk_register_ddrclk);