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

rcar-cpg-lib.c (4451B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * R-Car Gen3 Clock Pulse Generator Library
      4 *
      5 * Copyright (C) 2015-2018 Glider bvba
      6 * Copyright (C) 2019 Renesas Electronics Corp.
      7 *
      8 * Based on clk-rcar-gen3.c
      9 *
     10 * Copyright (C) 2015 Renesas Electronics Corp.
     11 */
     12
     13#include <linux/clk.h>
     14#include <linux/clk-provider.h>
     15#include <linux/device.h>
     16#include <linux/err.h>
     17#include <linux/init.h>
     18#include <linux/io.h>
     19#include <linux/pm.h>
     20#include <linux/slab.h>
     21#include <linux/sys_soc.h>
     22
     23#include "rcar-cpg-lib.h"
     24
     25spinlock_t cpg_lock;
     26
     27void cpg_reg_modify(void __iomem *reg, u32 clear, u32 set)
     28{
     29	unsigned long flags;
     30	u32 val;
     31
     32	spin_lock_irqsave(&cpg_lock, flags);
     33	val = readl(reg);
     34	val &= ~clear;
     35	val |= set;
     36	writel(val, reg);
     37	spin_unlock_irqrestore(&cpg_lock, flags);
     38};
     39
     40static int cpg_simple_notifier_call(struct notifier_block *nb,
     41				    unsigned long action, void *data)
     42{
     43	struct cpg_simple_notifier *csn =
     44		container_of(nb, struct cpg_simple_notifier, nb);
     45
     46	switch (action) {
     47	case PM_EVENT_SUSPEND:
     48		csn->saved = readl(csn->reg);
     49		return NOTIFY_OK;
     50
     51	case PM_EVENT_RESUME:
     52		writel(csn->saved, csn->reg);
     53		return NOTIFY_OK;
     54	}
     55	return NOTIFY_DONE;
     56}
     57
     58void cpg_simple_notifier_register(struct raw_notifier_head *notifiers,
     59				  struct cpg_simple_notifier *csn)
     60{
     61	csn->nb.notifier_call = cpg_simple_notifier_call;
     62	raw_notifier_chain_register(notifiers, &csn->nb);
     63}
     64
     65/*
     66 * SDn Clock
     67 */
     68
     69#define SDnSRCFC_SHIFT 2
     70#define STPnHCK	BIT(9 - SDnSRCFC_SHIFT)
     71
     72static const struct clk_div_table cpg_sdh_div_table[] = {
     73	{ 0, 1 }, { 1, 2 }, { STPnHCK | 2, 4 }, { STPnHCK | 3, 8 },
     74	{ STPnHCK | 4, 16 }, { 0, 0 },
     75};
     76
     77struct clk * __init cpg_sdh_clk_register(const char *name,
     78	void __iomem *sdnckcr, const char *parent_name,
     79	struct raw_notifier_head *notifiers)
     80{
     81	struct cpg_simple_notifier *csn;
     82	struct clk *clk;
     83
     84	csn = kzalloc(sizeof(*csn), GFP_KERNEL);
     85	if (!csn)
     86		return ERR_PTR(-ENOMEM);
     87
     88	csn->reg = sdnckcr;
     89
     90	clk = clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr,
     91					 SDnSRCFC_SHIFT, 8, 0, cpg_sdh_div_table,
     92					 &cpg_lock);
     93	if (IS_ERR(clk)) {
     94		kfree(csn);
     95		return clk;
     96	}
     97
     98	cpg_simple_notifier_register(notifiers, csn);
     99	return clk;
    100}
    101
    102static const struct clk_div_table cpg_sd_div_table[] = {
    103	{ 0, 2 }, { 1, 4 }, { 0, 0 },
    104};
    105
    106struct clk * __init cpg_sd_clk_register(const char *name,
    107	void __iomem *sdnckcr, const char *parent_name)
    108{
    109	return clk_register_divider_table(NULL, name, parent_name, 0, sdnckcr,
    110					  0, 2, 0, cpg_sd_div_table, &cpg_lock);
    111}
    112
    113struct rpc_clock {
    114	struct clk_divider div;
    115	struct clk_gate gate;
    116	/*
    117	 * One notifier covers both RPC and RPCD2 clocks as they are both
    118	 * controlled by the same RPCCKCR register...
    119	 */
    120	struct cpg_simple_notifier csn;
    121};
    122
    123static const struct clk_div_table cpg_rpc_div_table[] = {
    124	{ 1, 2 }, { 3, 4 }, { 5, 6 }, { 7, 8 }, { 0, 0 },
    125};
    126
    127struct clk * __init cpg_rpc_clk_register(const char *name,
    128	void __iomem *rpcckcr, const char *parent_name,
    129	struct raw_notifier_head *notifiers)
    130{
    131	struct rpc_clock *rpc;
    132	struct clk *clk;
    133
    134	rpc = kzalloc(sizeof(*rpc), GFP_KERNEL);
    135	if (!rpc)
    136		return ERR_PTR(-ENOMEM);
    137
    138	rpc->div.reg = rpcckcr;
    139	rpc->div.width = 3;
    140	rpc->div.table = cpg_rpc_div_table;
    141	rpc->div.lock = &cpg_lock;
    142
    143	rpc->gate.reg = rpcckcr;
    144	rpc->gate.bit_idx = 8;
    145	rpc->gate.flags = CLK_GATE_SET_TO_DISABLE;
    146	rpc->gate.lock = &cpg_lock;
    147
    148	rpc->csn.reg = rpcckcr;
    149
    150	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
    151				     &rpc->div.hw,  &clk_divider_ops,
    152				     &rpc->gate.hw, &clk_gate_ops,
    153				     CLK_SET_RATE_PARENT);
    154	if (IS_ERR(clk)) {
    155		kfree(rpc);
    156		return clk;
    157	}
    158
    159	cpg_simple_notifier_register(notifiers, &rpc->csn);
    160	return clk;
    161}
    162
    163struct rpcd2_clock {
    164	struct clk_fixed_factor fixed;
    165	struct clk_gate gate;
    166};
    167
    168struct clk * __init cpg_rpcd2_clk_register(const char *name,
    169					   void __iomem *rpcckcr,
    170					   const char *parent_name)
    171{
    172	struct rpcd2_clock *rpcd2;
    173	struct clk *clk;
    174
    175	rpcd2 = kzalloc(sizeof(*rpcd2), GFP_KERNEL);
    176	if (!rpcd2)
    177		return ERR_PTR(-ENOMEM);
    178
    179	rpcd2->fixed.mult = 1;
    180	rpcd2->fixed.div = 2;
    181
    182	rpcd2->gate.reg = rpcckcr;
    183	rpcd2->gate.bit_idx = 9;
    184	rpcd2->gate.flags = CLK_GATE_SET_TO_DISABLE;
    185	rpcd2->gate.lock = &cpg_lock;
    186
    187	clk = clk_register_composite(NULL, name, &parent_name, 1, NULL, NULL,
    188				     &rpcd2->fixed.hw, &clk_fixed_factor_ops,
    189				     &rpcd2->gate.hw, &clk_gate_ops,
    190				     CLK_SET_RATE_PARENT);
    191	if (IS_ERR(clk))
    192		kfree(rpcd2);
    193
    194	return clk;
    195}
    196