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

ccu_div.c (3504B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2016 Maxime Ripard
      4 * Maxime Ripard <maxime.ripard@free-electrons.com>
      5 */
      6
      7#include <linux/clk-provider.h>
      8#include <linux/io.h>
      9
     10#include "ccu_gate.h"
     11#include "ccu_div.h"
     12
     13static unsigned long ccu_div_round_rate(struct ccu_mux_internal *mux,
     14					struct clk_hw *parent,
     15					unsigned long *parent_rate,
     16					unsigned long rate,
     17					void *data)
     18{
     19	struct ccu_div *cd = data;
     20
     21	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
     22		rate *= cd->fixed_post_div;
     23
     24	rate = divider_round_rate_parent(&cd->common.hw, parent,
     25					 rate, parent_rate,
     26					 cd->div.table, cd->div.width,
     27					 cd->div.flags);
     28
     29	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
     30		rate /= cd->fixed_post_div;
     31
     32	return rate;
     33}
     34
     35static void ccu_div_disable(struct clk_hw *hw)
     36{
     37	struct ccu_div *cd = hw_to_ccu_div(hw);
     38
     39	return ccu_gate_helper_disable(&cd->common, cd->enable);
     40}
     41
     42static int ccu_div_enable(struct clk_hw *hw)
     43{
     44	struct ccu_div *cd = hw_to_ccu_div(hw);
     45
     46	return ccu_gate_helper_enable(&cd->common, cd->enable);
     47}
     48
     49static int ccu_div_is_enabled(struct clk_hw *hw)
     50{
     51	struct ccu_div *cd = hw_to_ccu_div(hw);
     52
     53	return ccu_gate_helper_is_enabled(&cd->common, cd->enable);
     54}
     55
     56static unsigned long ccu_div_recalc_rate(struct clk_hw *hw,
     57					unsigned long parent_rate)
     58{
     59	struct ccu_div *cd = hw_to_ccu_div(hw);
     60	unsigned long val;
     61	u32 reg;
     62
     63	reg = readl(cd->common.base + cd->common.reg);
     64	val = reg >> cd->div.shift;
     65	val &= (1 << cd->div.width) - 1;
     66
     67	parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
     68						  parent_rate);
     69
     70	val = divider_recalc_rate(hw, parent_rate, val, cd->div.table,
     71				  cd->div.flags, cd->div.width);
     72
     73	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
     74		val /= cd->fixed_post_div;
     75
     76	return val;
     77}
     78
     79static int ccu_div_determine_rate(struct clk_hw *hw,
     80				struct clk_rate_request *req)
     81{
     82	struct ccu_div *cd = hw_to_ccu_div(hw);
     83
     84	return ccu_mux_helper_determine_rate(&cd->common, &cd->mux,
     85					     req, ccu_div_round_rate, cd);
     86}
     87
     88static int ccu_div_set_rate(struct clk_hw *hw, unsigned long rate,
     89			   unsigned long parent_rate)
     90{
     91	struct ccu_div *cd = hw_to_ccu_div(hw);
     92	unsigned long flags;
     93	unsigned long val;
     94	u32 reg;
     95
     96	parent_rate = ccu_mux_helper_apply_prediv(&cd->common, &cd->mux, -1,
     97						  parent_rate);
     98
     99	if (cd->common.features & CCU_FEATURE_FIXED_POSTDIV)
    100		rate *= cd->fixed_post_div;
    101
    102	val = divider_get_val(rate, parent_rate, cd->div.table, cd->div.width,
    103			      cd->div.flags);
    104
    105	spin_lock_irqsave(cd->common.lock, flags);
    106
    107	reg = readl(cd->common.base + cd->common.reg);
    108	reg &= ~GENMASK(cd->div.width + cd->div.shift - 1, cd->div.shift);
    109
    110	writel(reg | (val << cd->div.shift),
    111	       cd->common.base + cd->common.reg);
    112
    113	spin_unlock_irqrestore(cd->common.lock, flags);
    114
    115	return 0;
    116}
    117
    118static u8 ccu_div_get_parent(struct clk_hw *hw)
    119{
    120	struct ccu_div *cd = hw_to_ccu_div(hw);
    121
    122	return ccu_mux_helper_get_parent(&cd->common, &cd->mux);
    123}
    124
    125static int ccu_div_set_parent(struct clk_hw *hw, u8 index)
    126{
    127	struct ccu_div *cd = hw_to_ccu_div(hw);
    128
    129	return ccu_mux_helper_set_parent(&cd->common, &cd->mux, index);
    130}
    131
    132const struct clk_ops ccu_div_ops = {
    133	.disable	= ccu_div_disable,
    134	.enable		= ccu_div_enable,
    135	.is_enabled	= ccu_div_is_enabled,
    136
    137	.get_parent	= ccu_div_get_parent,
    138	.set_parent	= ccu_div_set_parent,
    139
    140	.determine_rate	= ccu_div_determine_rate,
    141	.recalc_rate	= ccu_div_recalc_rate,
    142	.set_rate	= ccu_div_set_rate,
    143};
    144EXPORT_SYMBOL_NS_GPL(ccu_div_ops, SUNXI_CCU);