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-branch.c (3720B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2013, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/kernel.h>
      7#include <linux/bitops.h>
      8#include <linux/err.h>
      9#include <linux/delay.h>
     10#include <linux/export.h>
     11#include <linux/clk-provider.h>
     12#include <linux/regmap.h>
     13
     14#include "clk-branch.h"
     15
     16static bool clk_branch_in_hwcg_mode(const struct clk_branch *br)
     17{
     18	u32 val;
     19
     20	if (!br->hwcg_reg)
     21		return false;
     22
     23	regmap_read(br->clkr.regmap, br->hwcg_reg, &val);
     24
     25	return !!(val & BIT(br->hwcg_bit));
     26}
     27
     28static bool clk_branch_check_halt(const struct clk_branch *br, bool enabling)
     29{
     30	bool invert = (br->halt_check == BRANCH_HALT_ENABLE);
     31	u32 val;
     32
     33	regmap_read(br->clkr.regmap, br->halt_reg, &val);
     34
     35	val &= BIT(br->halt_bit);
     36	if (invert)
     37		val = !val;
     38
     39	return !!val == !enabling;
     40}
     41
     42#define BRANCH_CLK_OFF			BIT(31)
     43#define BRANCH_NOC_FSM_STATUS_SHIFT	28
     44#define BRANCH_NOC_FSM_STATUS_MASK	0x7
     45#define BRANCH_NOC_FSM_STATUS_ON	(0x2 << BRANCH_NOC_FSM_STATUS_SHIFT)
     46
     47static bool clk_branch2_check_halt(const struct clk_branch *br, bool enabling)
     48{
     49	u32 val;
     50	u32 mask;
     51
     52	mask = BRANCH_NOC_FSM_STATUS_MASK << BRANCH_NOC_FSM_STATUS_SHIFT;
     53	mask |= BRANCH_CLK_OFF;
     54
     55	regmap_read(br->clkr.regmap, br->halt_reg, &val);
     56
     57	if (enabling) {
     58		val &= mask;
     59		return (val & BRANCH_CLK_OFF) == 0 ||
     60			val == BRANCH_NOC_FSM_STATUS_ON;
     61	} else {
     62		return val & BRANCH_CLK_OFF;
     63	}
     64}
     65
     66static int clk_branch_wait(const struct clk_branch *br, bool enabling,
     67		bool (check_halt)(const struct clk_branch *, bool))
     68{
     69	bool voted = br->halt_check & BRANCH_VOTED;
     70	const char *name = clk_hw_get_name(&br->clkr.hw);
     71
     72	/*
     73	 * Skip checking halt bit if we're explicitly ignoring the bit or the
     74	 * clock is in hardware gated mode
     75	 */
     76	if (br->halt_check == BRANCH_HALT_SKIP || clk_branch_in_hwcg_mode(br))
     77		return 0;
     78
     79	if (br->halt_check == BRANCH_HALT_DELAY || (!enabling && voted)) {
     80		udelay(10);
     81	} else if (br->halt_check == BRANCH_HALT_ENABLE ||
     82		   br->halt_check == BRANCH_HALT ||
     83		   (enabling && voted)) {
     84		int count = 200;
     85
     86		while (count-- > 0) {
     87			if (check_halt(br, enabling))
     88				return 0;
     89			udelay(1);
     90		}
     91		WARN(1, "%s status stuck at 'o%s'", name,
     92				enabling ? "ff" : "n");
     93		return -EBUSY;
     94	}
     95	return 0;
     96}
     97
     98static int clk_branch_toggle(struct clk_hw *hw, bool en,
     99		bool (check_halt)(const struct clk_branch *, bool))
    100{
    101	struct clk_branch *br = to_clk_branch(hw);
    102	int ret;
    103
    104	if (en) {
    105		ret = clk_enable_regmap(hw);
    106		if (ret)
    107			return ret;
    108	} else {
    109		clk_disable_regmap(hw);
    110	}
    111
    112	return clk_branch_wait(br, en, check_halt);
    113}
    114
    115static int clk_branch_enable(struct clk_hw *hw)
    116{
    117	return clk_branch_toggle(hw, true, clk_branch_check_halt);
    118}
    119
    120static void clk_branch_disable(struct clk_hw *hw)
    121{
    122	clk_branch_toggle(hw, false, clk_branch_check_halt);
    123}
    124
    125const struct clk_ops clk_branch_ops = {
    126	.enable = clk_branch_enable,
    127	.disable = clk_branch_disable,
    128	.is_enabled = clk_is_enabled_regmap,
    129};
    130EXPORT_SYMBOL_GPL(clk_branch_ops);
    131
    132static int clk_branch2_enable(struct clk_hw *hw)
    133{
    134	return clk_branch_toggle(hw, true, clk_branch2_check_halt);
    135}
    136
    137static void clk_branch2_disable(struct clk_hw *hw)
    138{
    139	clk_branch_toggle(hw, false, clk_branch2_check_halt);
    140}
    141
    142const struct clk_ops clk_branch2_ops = {
    143	.enable = clk_branch2_enable,
    144	.disable = clk_branch2_disable,
    145	.is_enabled = clk_is_enabled_regmap,
    146};
    147EXPORT_SYMBOL_GPL(clk_branch2_ops);
    148
    149const struct clk_ops clk_branch2_aon_ops = {
    150	.enable = clk_branch2_enable,
    151	.is_enabled = clk_is_enabled_regmap,
    152};
    153EXPORT_SYMBOL_GPL(clk_branch2_aon_ops);
    154
    155const struct clk_ops clk_branch_simple_ops = {
    156	.enable = clk_enable_regmap,
    157	.disable = clk_disable_regmap,
    158	.is_enabled = clk_is_enabled_regmap,
    159};
    160EXPORT_SYMBOL_GPL(clk_branch_simple_ops);