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-apbc.c (3412B)


      1/*
      2 * mmp APB clock operation source file
      3 *
      4 * Copyright (C) 2012 Marvell
      5 * Chao Xie <xiechao.mail@gmail.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/kernel.h>
     13#include <linux/io.h>
     14#include <linux/err.h>
     15#include <linux/delay.h>
     16#include <linux/slab.h>
     17
     18#include "clk.h"
     19
     20/* Common APB clock register bit definitions */
     21#define APBC_APBCLK	(1 << 0)  /* APB Bus Clock Enable */
     22#define APBC_FNCLK	(1 << 1)  /* Functional Clock Enable */
     23#define APBC_RST	(1 << 2)  /* Reset Generation */
     24#define APBC_POWER	(1 << 7)  /* Reset Generation */
     25
     26#define to_clk_apbc(hw) container_of(hw, struct clk_apbc, hw)
     27struct clk_apbc {
     28	struct clk_hw		hw;
     29	void __iomem		*base;
     30	unsigned int		delay;
     31	unsigned int		flags;
     32	spinlock_t		*lock;
     33};
     34
     35static int clk_apbc_prepare(struct clk_hw *hw)
     36{
     37	struct clk_apbc *apbc = to_clk_apbc(hw);
     38	unsigned int data;
     39	unsigned long flags = 0;
     40
     41	/*
     42	 * It may share same register as MUX clock,
     43	 * and it will impact FNCLK enable. Spinlock is needed
     44	 */
     45	if (apbc->lock)
     46		spin_lock_irqsave(apbc->lock, flags);
     47
     48	data = readl_relaxed(apbc->base);
     49	if (apbc->flags & APBC_POWER_CTRL)
     50		data |= APBC_POWER;
     51	data |= APBC_FNCLK;
     52	writel_relaxed(data, apbc->base);
     53
     54	if (apbc->lock)
     55		spin_unlock_irqrestore(apbc->lock, flags);
     56
     57	udelay(apbc->delay);
     58
     59	if (apbc->lock)
     60		spin_lock_irqsave(apbc->lock, flags);
     61
     62	data = readl_relaxed(apbc->base);
     63	data |= APBC_APBCLK;
     64	writel_relaxed(data, apbc->base);
     65
     66	if (apbc->lock)
     67		spin_unlock_irqrestore(apbc->lock, flags);
     68
     69	udelay(apbc->delay);
     70
     71	if (!(apbc->flags & APBC_NO_BUS_CTRL)) {
     72		if (apbc->lock)
     73			spin_lock_irqsave(apbc->lock, flags);
     74
     75		data = readl_relaxed(apbc->base);
     76		data &= ~APBC_RST;
     77		writel_relaxed(data, apbc->base);
     78
     79		if (apbc->lock)
     80			spin_unlock_irqrestore(apbc->lock, flags);
     81	}
     82
     83	return 0;
     84}
     85
     86static void clk_apbc_unprepare(struct clk_hw *hw)
     87{
     88	struct clk_apbc *apbc = to_clk_apbc(hw);
     89	unsigned long data;
     90	unsigned long flags = 0;
     91
     92	if (apbc->lock)
     93		spin_lock_irqsave(apbc->lock, flags);
     94
     95	data = readl_relaxed(apbc->base);
     96	if (apbc->flags & APBC_POWER_CTRL)
     97		data &= ~APBC_POWER;
     98	data &= ~APBC_FNCLK;
     99	writel_relaxed(data, apbc->base);
    100
    101	if (apbc->lock)
    102		spin_unlock_irqrestore(apbc->lock, flags);
    103
    104	udelay(10);
    105
    106	if (apbc->lock)
    107		spin_lock_irqsave(apbc->lock, flags);
    108
    109	data = readl_relaxed(apbc->base);
    110	data &= ~APBC_APBCLK;
    111	writel_relaxed(data, apbc->base);
    112
    113	if (apbc->lock)
    114		spin_unlock_irqrestore(apbc->lock, flags);
    115}
    116
    117static const struct clk_ops clk_apbc_ops = {
    118	.prepare = clk_apbc_prepare,
    119	.unprepare = clk_apbc_unprepare,
    120};
    121
    122struct clk *mmp_clk_register_apbc(const char *name, const char *parent_name,
    123		void __iomem *base, unsigned int delay,
    124		unsigned int apbc_flags, spinlock_t *lock)
    125{
    126	struct clk_apbc *apbc;
    127	struct clk *clk;
    128	struct clk_init_data init;
    129
    130	apbc = kzalloc(sizeof(*apbc), GFP_KERNEL);
    131	if (!apbc)
    132		return NULL;
    133
    134	init.name = name;
    135	init.ops = &clk_apbc_ops;
    136	init.flags = CLK_SET_RATE_PARENT;
    137	init.parent_names = (parent_name ? &parent_name : NULL);
    138	init.num_parents = (parent_name ? 1 : 0);
    139
    140	apbc->base = base;
    141	apbc->delay = delay;
    142	apbc->flags = apbc_flags;
    143	apbc->lock = lock;
    144	apbc->hw.init = &init;
    145
    146	clk = clk_register(NULL, &apbc->hw);
    147	if (IS_ERR(clk))
    148		kfree(apbc);
    149
    150	return clk;
    151}