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-gate.c (2925B)


      1/*
      2 * mmp gate clock operation source file
      3 *
      4 * Copyright (C) 2014 Marvell
      5 * Chao Xie <chao.xie@marvell.com>
      6 *
      7 * This file is licensed under the terms of the GNU General Public
      8 * License version 2. This program is licensed "as is" without any
      9 * warranty of any kind, whether express or implied.
     10 */
     11
     12#include <linux/clk-provider.h>
     13#include <linux/slab.h>
     14#include <linux/io.h>
     15#include <linux/err.h>
     16#include <linux/delay.h>
     17
     18#include "clk.h"
     19
     20/*
     21 * Some clocks will have mutiple bits to enable the clocks, and
     22 * the bits to disable the clock is not same as enabling bits.
     23 */
     24
     25#define to_clk_mmp_gate(hw)	container_of(hw, struct mmp_clk_gate, hw)
     26
     27static int mmp_clk_gate_enable(struct clk_hw *hw)
     28{
     29	struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
     30	unsigned long flags = 0;
     31	unsigned long rate;
     32	u32 tmp;
     33
     34	if (gate->lock)
     35		spin_lock_irqsave(gate->lock, flags);
     36
     37	tmp = readl(gate->reg);
     38	tmp &= ~gate->mask;
     39	tmp |= gate->val_enable;
     40	writel(tmp, gate->reg);
     41
     42	if (gate->lock)
     43		spin_unlock_irqrestore(gate->lock, flags);
     44
     45	if (gate->flags & MMP_CLK_GATE_NEED_DELAY) {
     46		rate = clk_hw_get_rate(hw);
     47		/* Need delay 2 cycles. */
     48		udelay(2000000/rate);
     49	}
     50
     51	return 0;
     52}
     53
     54static void mmp_clk_gate_disable(struct clk_hw *hw)
     55{
     56	struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
     57	unsigned long flags = 0;
     58	u32 tmp;
     59
     60	if (gate->lock)
     61		spin_lock_irqsave(gate->lock, flags);
     62
     63	tmp = readl(gate->reg);
     64	tmp &= ~gate->mask;
     65	tmp |= gate->val_disable;
     66	writel(tmp, gate->reg);
     67
     68	if (gate->lock)
     69		spin_unlock_irqrestore(gate->lock, flags);
     70}
     71
     72static int mmp_clk_gate_is_enabled(struct clk_hw *hw)
     73{
     74	struct mmp_clk_gate *gate = to_clk_mmp_gate(hw);
     75	unsigned long flags = 0;
     76	u32 tmp;
     77
     78	if (gate->lock)
     79		spin_lock_irqsave(gate->lock, flags);
     80
     81	tmp = readl(gate->reg);
     82
     83	if (gate->lock)
     84		spin_unlock_irqrestore(gate->lock, flags);
     85
     86	return (tmp & gate->mask) == gate->val_enable;
     87}
     88
     89const struct clk_ops mmp_clk_gate_ops = {
     90	.enable = mmp_clk_gate_enable,
     91	.disable = mmp_clk_gate_disable,
     92	.is_enabled = mmp_clk_gate_is_enabled,
     93};
     94
     95struct clk *mmp_clk_register_gate(struct device *dev, const char *name,
     96		const char *parent_name, unsigned long flags,
     97		void __iomem *reg, u32 mask, u32 val_enable, u32 val_disable,
     98		unsigned int gate_flags, spinlock_t *lock)
     99{
    100	struct mmp_clk_gate *gate;
    101	struct clk *clk;
    102	struct clk_init_data init;
    103
    104	/* allocate the gate */
    105	gate = kzalloc(sizeof(*gate), GFP_KERNEL);
    106	if (!gate)
    107		return ERR_PTR(-ENOMEM);
    108
    109	init.name = name;
    110	init.ops = &mmp_clk_gate_ops;
    111	init.flags = flags;
    112	init.parent_names = (parent_name ? &parent_name : NULL);
    113	init.num_parents = (parent_name ? 1 : 0);
    114
    115	/* struct clk_gate assignments */
    116	gate->reg = reg;
    117	gate->mask = mask;
    118	gate->val_enable = val_enable;
    119	gate->val_disable = val_disable;
    120	gate->flags = gate_flags;
    121	gate->lock = lock;
    122	gate->hw.init = &init;
    123
    124	clk = clk_register(dev, &gate->hw);
    125
    126	if (IS_ERR(clk))
    127		kfree(gate);
    128
    129	return clk;
    130}