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

clkc.c (5018B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Toshiba Visconti clock controller
      4 *
      5 * Copyright (c) 2021 TOSHIBA CORPORATION
      6 * Copyright (c) 2021 Toshiba Electronic Devices & Storage Corporation
      7 *
      8 * Nobuhiro Iwamatsu <nobuhiro1.iwamatsu@toshiba.co.jp>
      9 */
     10
     11#include <linux/clk-provider.h>
     12#include <linux/delay.h>
     13#include <linux/device.h>
     14#include <linux/io.h>
     15#include <linux/of.h>
     16#include <linux/of_address.h>
     17#include <linux/regmap.h>
     18#include <linux/slab.h>
     19#include <linux/string.h>
     20
     21#include "clkc.h"
     22
     23static inline struct visconti_clk_gate *to_visconti_clk_gate(struct clk_hw *hw)
     24{
     25	return container_of(hw, struct visconti_clk_gate, hw);
     26}
     27
     28static int visconti_gate_clk_is_enabled(struct clk_hw *hw)
     29{
     30	struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
     31	u32 clk = BIT(gate->ck_idx);
     32	u32 val;
     33
     34	regmap_read(gate->regmap, gate->ckon_offset, &val);
     35	return (val & clk) ? 1 : 0;
     36}
     37
     38static void visconti_gate_clk_disable(struct clk_hw *hw)
     39{
     40	struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
     41	u32 clk = BIT(gate->ck_idx);
     42	unsigned long flags;
     43
     44	spin_lock_irqsave(gate->lock, flags);
     45
     46	if (!visconti_gate_clk_is_enabled(hw)) {
     47		spin_unlock_irqrestore(gate->lock, flags);
     48		return;
     49	}
     50
     51	regmap_update_bits(gate->regmap, gate->ckoff_offset, clk, clk);
     52	spin_unlock_irqrestore(gate->lock, flags);
     53}
     54
     55static int visconti_gate_clk_enable(struct clk_hw *hw)
     56{
     57	struct visconti_clk_gate *gate = to_visconti_clk_gate(hw);
     58	u32 clk = BIT(gate->ck_idx);
     59	unsigned long flags;
     60
     61	spin_lock_irqsave(gate->lock, flags);
     62	regmap_update_bits(gate->regmap, gate->ckon_offset, clk, clk);
     63	spin_unlock_irqrestore(gate->lock, flags);
     64
     65	return 0;
     66}
     67
     68static const struct clk_ops visconti_clk_gate_ops = {
     69	.enable = visconti_gate_clk_enable,
     70	.disable = visconti_gate_clk_disable,
     71	.is_enabled = visconti_gate_clk_is_enabled,
     72};
     73
     74static struct clk_hw *visconti_clk_register_gate(struct device *dev,
     75						 const char *name,
     76						 const char *parent_name,
     77						 struct regmap *regmap,
     78						 const struct visconti_clk_gate_table *clks,
     79						 u32	rson_offset,
     80						 u32	rsoff_offset,
     81						 u8	rs_idx,
     82						 spinlock_t *lock)
     83{
     84	struct visconti_clk_gate *gate;
     85	struct clk_parent_data *pdata;
     86	struct clk_init_data init;
     87	struct clk_hw *hw;
     88	int ret;
     89
     90	pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
     91	if (!pdata)
     92		return ERR_PTR(-ENOMEM);
     93
     94	pdata->name = pdata->fw_name = parent_name;
     95
     96	gate = devm_kzalloc(dev, sizeof(*gate), GFP_KERNEL);
     97	if (!gate)
     98		return ERR_PTR(-ENOMEM);
     99
    100	init.name = name;
    101	init.ops = &visconti_clk_gate_ops;
    102	init.flags = clks->flags;
    103	init.parent_data = pdata;
    104	init.num_parents = 1;
    105
    106	gate->regmap = regmap;
    107	gate->ckon_offset = clks->ckon_offset;
    108	gate->ckoff_offset = clks->ckoff_offset;
    109	gate->ck_idx = clks->ck_idx;
    110	gate->rson_offset = rson_offset;
    111	gate->rsoff_offset = rsoff_offset;
    112	gate->rs_idx = rs_idx;
    113	gate->lock = lock;
    114	gate->hw.init = &init;
    115
    116	hw = &gate->hw;
    117	ret = devm_clk_hw_register(dev, hw);
    118	if (ret)
    119		hw = ERR_PTR(ret);
    120
    121	return hw;
    122}
    123
    124int visconti_clk_register_gates(struct visconti_clk_provider *ctx,
    125				const struct visconti_clk_gate_table *clks,
    126				int num_gate,
    127				const struct visconti_reset_data *reset,
    128				spinlock_t *lock)
    129{
    130	struct device *dev = ctx->dev;
    131	int i;
    132
    133	for (i = 0; i < num_gate; i++) {
    134		const char *parent_div_name = clks[i].parent_data[0].name;
    135		struct clk_parent_data *pdata;
    136		u32 rson_offset, rsoff_offset;
    137		struct clk_hw *gate_clk;
    138		struct clk_hw *div_clk;
    139		char *dev_name;
    140		u8 rs_idx;
    141
    142		pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
    143		if (!pdata)
    144			return -ENOMEM;
    145
    146		dev_name = devm_kasprintf(dev, GFP_KERNEL, "%s_div", clks[i].name);
    147		if (!dev_name)
    148			return -ENOMEM;
    149
    150		if (clks[i].rs_id != NO_RESET) {
    151			rson_offset = reset[clks[i].rs_id].rson_offset;
    152			rsoff_offset = reset[clks[i].rs_id].rsoff_offset;
    153			rs_idx = reset[clks[i].rs_id].rs_idx;
    154		} else {
    155			rson_offset = rsoff_offset = rs_idx = -1;
    156		}
    157
    158		div_clk = devm_clk_hw_register_fixed_factor(dev,
    159							    dev_name,
    160							    parent_div_name,
    161							    0, 1,
    162							    clks[i].div);
    163		if (IS_ERR(div_clk))
    164			return PTR_ERR(div_clk);
    165
    166		gate_clk = visconti_clk_register_gate(dev,
    167						      clks[i].name,
    168						      dev_name,
    169						      ctx->regmap,
    170						      &clks[i],
    171						      rson_offset,
    172						      rsoff_offset,
    173						      rs_idx,
    174						      lock);
    175		if (IS_ERR(gate_clk)) {
    176			dev_err(dev, "%s: failed to register clock %s\n",
    177				__func__, clks[i].name);
    178			return PTR_ERR(gate_clk);
    179		}
    180
    181		ctx->clk_data.hws[clks[i].id] = gate_clk;
    182	}
    183
    184	return 0;
    185}
    186
    187struct visconti_clk_provider *visconti_init_clk(struct device *dev,
    188						struct regmap *regmap,
    189						unsigned long nr_clks)
    190{
    191	struct visconti_clk_provider *ctx;
    192	int i;
    193
    194	ctx = devm_kzalloc(dev, struct_size(ctx, clk_data.hws, nr_clks), GFP_KERNEL);
    195	if (!ctx)
    196		return ERR_PTR(-ENOMEM);
    197
    198	for (i = 0; i < nr_clks; ++i)
    199		ctx->clk_data.hws[i] = ERR_PTR(-ENOENT);
    200	ctx->clk_data.num = nr_clks;
    201
    202	ctx->dev = dev;
    203	ctx->regmap = regmap;
    204
    205	return ctx;
    206}