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-inverter.c (2309B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright 2015 Heiko Stuebner <heiko@sntech.de>
      4 */
      5
      6#include <linux/slab.h>
      7#include <linux/clk-provider.h>
      8#include <linux/io.h>
      9#include <linux/spinlock.h>
     10#include <linux/kernel.h>
     11#include "clk.h"
     12
     13struct rockchip_inv_clock {
     14	struct clk_hw	hw;
     15	void __iomem	*reg;
     16	int		shift;
     17	int		flags;
     18	spinlock_t	*lock;
     19};
     20
     21#define to_inv_clock(_hw) container_of(_hw, struct rockchip_inv_clock, hw)
     22
     23#define INVERTER_MASK 0x1
     24
     25static int rockchip_inv_get_phase(struct clk_hw *hw)
     26{
     27	struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
     28	u32 val;
     29
     30	val = readl(inv_clock->reg) >> inv_clock->shift;
     31	val &= INVERTER_MASK;
     32	return val ? 180 : 0;
     33}
     34
     35static int rockchip_inv_set_phase(struct clk_hw *hw, int degrees)
     36{
     37	struct rockchip_inv_clock *inv_clock = to_inv_clock(hw);
     38	u32 val;
     39
     40	if (degrees % 180 == 0) {
     41		val = !!degrees;
     42	} else {
     43		pr_err("%s: unsupported phase %d for %s\n",
     44		       __func__, degrees, clk_hw_get_name(hw));
     45		return -EINVAL;
     46	}
     47
     48	if (inv_clock->flags & ROCKCHIP_INVERTER_HIWORD_MASK) {
     49		writel(HIWORD_UPDATE(val, INVERTER_MASK, inv_clock->shift),
     50		       inv_clock->reg);
     51	} else {
     52		unsigned long flags;
     53		u32 reg;
     54
     55		spin_lock_irqsave(inv_clock->lock, flags);
     56
     57		reg = readl(inv_clock->reg);
     58		reg &= ~BIT(inv_clock->shift);
     59		reg |= val;
     60		writel(reg, inv_clock->reg);
     61
     62		spin_unlock_irqrestore(inv_clock->lock, flags);
     63	}
     64
     65	return 0;
     66}
     67
     68static const struct clk_ops rockchip_inv_clk_ops = {
     69	.get_phase	= rockchip_inv_get_phase,
     70	.set_phase	= rockchip_inv_set_phase,
     71};
     72
     73struct clk *rockchip_clk_register_inverter(const char *name,
     74				const char *const *parent_names, u8 num_parents,
     75				void __iomem *reg, int shift, int flags,
     76				spinlock_t *lock)
     77{
     78	struct clk_init_data init;
     79	struct rockchip_inv_clock *inv_clock;
     80	struct clk *clk;
     81
     82	inv_clock = kmalloc(sizeof(*inv_clock), GFP_KERNEL);
     83	if (!inv_clock)
     84		return ERR_PTR(-ENOMEM);
     85
     86	init.name = name;
     87	init.num_parents = num_parents;
     88	init.flags = CLK_SET_RATE_PARENT;
     89	init.parent_names = parent_names;
     90	init.ops = &rockchip_inv_clk_ops;
     91
     92	inv_clock->hw.init = &init;
     93	inv_clock->reg = reg;
     94	inv_clock->shift = shift;
     95	inv_clock->flags = flags;
     96	inv_clock->lock = lock;
     97
     98	clk = clk_register(NULL, &inv_clock->hw);
     99	if (IS_ERR(clk))
    100		kfree(inv_clock);
    101
    102	return clk;
    103}