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-composite-7ulp.c (4351B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * Copyright (C) 2016 Freescale Semiconductor, Inc.
      4 * Copyright 2017~2018 NXP
      5 *
      6 */
      7
      8#include <linux/bits.h>
      9#include <linux/clk-provider.h>
     10#include <linux/err.h>
     11#include <linux/io.h>
     12#include <linux/slab.h>
     13
     14#include "../clk-fractional-divider.h"
     15#include "clk.h"
     16
     17#define PCG_PCS_SHIFT	24
     18#define PCG_PCS_MASK	0x7
     19#define PCG_CGC_SHIFT	30
     20#define PCG_FRAC_SHIFT	3
     21#define PCG_FRAC_WIDTH	1
     22#define PCG_FRAC_MASK	BIT(3)
     23#define PCG_PCD_SHIFT	0
     24#define PCG_PCD_WIDTH	3
     25#define PCG_PCD_MASK	0x7
     26
     27#define SW_RST		BIT(28)
     28
     29static int pcc_gate_enable(struct clk_hw *hw)
     30{
     31	struct clk_gate *gate = to_clk_gate(hw);
     32	unsigned long flags;
     33	u32 val;
     34	int ret;
     35
     36	ret = clk_gate_ops.enable(hw);
     37	if (ret)
     38		return ret;
     39
     40	spin_lock_irqsave(gate->lock, flags);
     41	/*
     42	 * release the sw reset for peripherals associated with
     43	 * with this pcc clock.
     44	 */
     45	val = readl(gate->reg);
     46	val |= SW_RST;
     47	writel(val, gate->reg);
     48
     49	spin_unlock_irqrestore(gate->lock, flags);
     50
     51	return 0;
     52}
     53
     54static void pcc_gate_disable(struct clk_hw *hw)
     55{
     56	clk_gate_ops.disable(hw);
     57}
     58
     59static int pcc_gate_is_enabled(struct clk_hw *hw)
     60{
     61	return clk_gate_ops.is_enabled(hw);
     62}
     63
     64static const struct clk_ops pcc_gate_ops = {
     65	.enable = pcc_gate_enable,
     66	.disable = pcc_gate_disable,
     67	.is_enabled = pcc_gate_is_enabled,
     68};
     69
     70static struct clk_hw *imx_ulp_clk_hw_composite(const char *name,
     71				     const char * const *parent_names,
     72				     int num_parents, bool mux_present,
     73				     bool rate_present, bool gate_present,
     74				     void __iomem *reg, bool has_swrst)
     75{
     76	struct clk_hw *mux_hw = NULL, *fd_hw = NULL, *gate_hw = NULL;
     77	struct clk_fractional_divider *fd = NULL;
     78	struct clk_gate *gate = NULL;
     79	struct clk_mux *mux = NULL;
     80	struct clk_hw *hw;
     81	u32 val;
     82
     83	if (mux_present) {
     84		mux = kzalloc(sizeof(*mux), GFP_KERNEL);
     85		if (!mux)
     86			return ERR_PTR(-ENOMEM);
     87		mux_hw = &mux->hw;
     88		mux->reg = reg;
     89		mux->shift = PCG_PCS_SHIFT;
     90		mux->mask = PCG_PCS_MASK;
     91		if (has_swrst)
     92			mux->lock = &imx_ccm_lock;
     93	}
     94
     95	if (rate_present) {
     96		fd = kzalloc(sizeof(*fd), GFP_KERNEL);
     97		if (!fd) {
     98			kfree(mux);
     99			return ERR_PTR(-ENOMEM);
    100		}
    101		fd_hw = &fd->hw;
    102		fd->reg = reg;
    103		fd->mshift = PCG_FRAC_SHIFT;
    104		fd->mwidth = PCG_FRAC_WIDTH;
    105		fd->mmask  = PCG_FRAC_MASK;
    106		fd->nshift = PCG_PCD_SHIFT;
    107		fd->nwidth = PCG_PCD_WIDTH;
    108		fd->nmask = PCG_PCD_MASK;
    109		fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
    110		if (has_swrst)
    111			fd->lock = &imx_ccm_lock;
    112	}
    113
    114	if (gate_present) {
    115		gate = kzalloc(sizeof(*gate), GFP_KERNEL);
    116		if (!gate) {
    117			kfree(mux);
    118			kfree(fd);
    119			return ERR_PTR(-ENOMEM);
    120		}
    121		gate_hw = &gate->hw;
    122		gate->reg = reg;
    123		gate->bit_idx = PCG_CGC_SHIFT;
    124		if (has_swrst)
    125			gate->lock = &imx_ccm_lock;
    126		/*
    127		 * make sure clock is gated during clock tree initialization,
    128		 * the HW ONLY allow clock parent/rate changed with clock gated,
    129		 * during clock tree initialization, clocks could be enabled
    130		 * by bootloader, so the HW status will mismatch with clock tree
    131		 * prepare count, then clock core driver will allow parent/rate
    132		 * change since the prepare count is zero, but HW actually
    133		 * prevent the parent/rate change due to the clock is enabled.
    134		 */
    135		val = readl_relaxed(reg);
    136		val &= ~(1 << PCG_CGC_SHIFT);
    137		writel_relaxed(val, reg);
    138	}
    139
    140	hw = clk_hw_register_composite(NULL, name, parent_names, num_parents,
    141				       mux_hw, &clk_mux_ops, fd_hw,
    142				       &clk_fractional_divider_ops, gate_hw,
    143				       has_swrst ? &pcc_gate_ops : &clk_gate_ops, CLK_SET_RATE_GATE |
    144				       CLK_SET_PARENT_GATE | CLK_SET_RATE_NO_REPARENT);
    145	if (IS_ERR(hw)) {
    146		kfree(mux);
    147		kfree(fd);
    148		kfree(gate);
    149	}
    150
    151	return hw;
    152}
    153
    154struct clk_hw *imx7ulp_clk_hw_composite(const char *name, const char * const *parent_names,
    155				int num_parents, bool mux_present, bool rate_present,
    156				bool gate_present, void __iomem *reg)
    157{
    158	return imx_ulp_clk_hw_composite(name, parent_names, num_parents, mux_present, rate_present,
    159					gate_present, reg, false);
    160}
    161
    162struct clk_hw *imx8ulp_clk_hw_composite(const char *name, const char * const *parent_names,
    163				int num_parents, bool mux_present, bool rate_present,
    164				bool gate_present, void __iomem *reg, bool has_swrst)
    165{
    166	return imx_ulp_clk_hw_composite(name, parent_names, num_parents, mux_present, rate_present,
    167					gate_present, reg, has_swrst);
    168}
    169EXPORT_SYMBOL_GPL(imx8ulp_clk_hw_composite);