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-system.c (2804B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/clkdev.h>
      8#include <linux/clk/at91_pmc.h>
      9#include <linux/of.h>
     10#include <linux/mfd/syscon.h>
     11#include <linux/regmap.h>
     12
     13#include "pmc.h"
     14
     15#define SYSTEM_MAX_ID		31
     16
     17#define SYSTEM_MAX_NAME_SZ	32
     18
     19#define to_clk_system(hw) container_of(hw, struct clk_system, hw)
     20struct clk_system {
     21	struct clk_hw hw;
     22	struct regmap *regmap;
     23	struct at91_clk_pms pms;
     24	u8 id;
     25};
     26
     27static inline int is_pck(int id)
     28{
     29	return (id >= 8) && (id <= 15);
     30}
     31
     32static inline bool clk_system_ready(struct regmap *regmap, int id)
     33{
     34	unsigned int status;
     35
     36	regmap_read(regmap, AT91_PMC_SR, &status);
     37
     38	return !!(status & (1 << id));
     39}
     40
     41static int clk_system_prepare(struct clk_hw *hw)
     42{
     43	struct clk_system *sys = to_clk_system(hw);
     44
     45	regmap_write(sys->regmap, AT91_PMC_SCER, 1 << sys->id);
     46
     47	if (!is_pck(sys->id))
     48		return 0;
     49
     50	while (!clk_system_ready(sys->regmap, sys->id))
     51		cpu_relax();
     52
     53	return 0;
     54}
     55
     56static void clk_system_unprepare(struct clk_hw *hw)
     57{
     58	struct clk_system *sys = to_clk_system(hw);
     59
     60	regmap_write(sys->regmap, AT91_PMC_SCDR, 1 << sys->id);
     61}
     62
     63static int clk_system_is_prepared(struct clk_hw *hw)
     64{
     65	struct clk_system *sys = to_clk_system(hw);
     66	unsigned int status;
     67
     68	regmap_read(sys->regmap, AT91_PMC_SCSR, &status);
     69
     70	if (!(status & (1 << sys->id)))
     71		return 0;
     72
     73	if (!is_pck(sys->id))
     74		return 1;
     75
     76	regmap_read(sys->regmap, AT91_PMC_SR, &status);
     77
     78	return !!(status & (1 << sys->id));
     79}
     80
     81static int clk_system_save_context(struct clk_hw *hw)
     82{
     83	struct clk_system *sys = to_clk_system(hw);
     84
     85	sys->pms.status = clk_system_is_prepared(hw);
     86
     87	return 0;
     88}
     89
     90static void clk_system_restore_context(struct clk_hw *hw)
     91{
     92	struct clk_system *sys = to_clk_system(hw);
     93
     94	if (sys->pms.status)
     95		clk_system_prepare(&sys->hw);
     96}
     97
     98static const struct clk_ops system_ops = {
     99	.prepare = clk_system_prepare,
    100	.unprepare = clk_system_unprepare,
    101	.is_prepared = clk_system_is_prepared,
    102	.save_context = clk_system_save_context,
    103	.restore_context = clk_system_restore_context,
    104};
    105
    106struct clk_hw * __init
    107at91_clk_register_system(struct regmap *regmap, const char *name,
    108			 const char *parent_name, u8 id)
    109{
    110	struct clk_system *sys;
    111	struct clk_hw *hw;
    112	struct clk_init_data init;
    113	int ret;
    114
    115	if (!parent_name || id > SYSTEM_MAX_ID)
    116		return ERR_PTR(-EINVAL);
    117
    118	sys = kzalloc(sizeof(*sys), GFP_KERNEL);
    119	if (!sys)
    120		return ERR_PTR(-ENOMEM);
    121
    122	init.name = name;
    123	init.ops = &system_ops;
    124	init.parent_names = &parent_name;
    125	init.num_parents = 1;
    126	init.flags = CLK_SET_RATE_PARENT;
    127
    128	sys->id = id;
    129	sys->hw.init = &init;
    130	sys->regmap = regmap;
    131
    132	hw = &sys->hw;
    133	ret = clk_hw_register(NULL, &sys->hw);
    134	if (ret) {
    135		kfree(sys);
    136		hw = ERR_PTR(ret);
    137	}
    138
    139	return hw;
    140}