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

ccu_sdm.c (4707B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C) 2017 Chen-Yu Tsai <wens@csie.org>
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/io.h>
      8#include <linux/spinlock.h>
      9
     10#include "ccu_sdm.h"
     11
     12bool ccu_sdm_helper_is_enabled(struct ccu_common *common,
     13			       struct ccu_sdm_internal *sdm)
     14{
     15	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
     16		return false;
     17
     18	if (sdm->enable && !(readl(common->base + common->reg) & sdm->enable))
     19		return false;
     20
     21	return !!(readl(common->base + sdm->tuning_reg) & sdm->tuning_enable);
     22}
     23EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_is_enabled, SUNXI_CCU);
     24
     25void ccu_sdm_helper_enable(struct ccu_common *common,
     26			   struct ccu_sdm_internal *sdm,
     27			   unsigned long rate)
     28{
     29	unsigned long flags;
     30	unsigned int i;
     31	u32 reg;
     32
     33	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
     34		return;
     35
     36	/* Set the pattern */
     37	for (i = 0; i < sdm->table_size; i++)
     38		if (sdm->table[i].rate == rate)
     39			writel(sdm->table[i].pattern,
     40			       common->base + sdm->tuning_reg);
     41
     42	/* Make sure SDM is enabled */
     43	spin_lock_irqsave(common->lock, flags);
     44	reg = readl(common->base + sdm->tuning_reg);
     45	writel(reg | sdm->tuning_enable, common->base + sdm->tuning_reg);
     46	spin_unlock_irqrestore(common->lock, flags);
     47
     48	spin_lock_irqsave(common->lock, flags);
     49	reg = readl(common->base + common->reg);
     50	writel(reg | sdm->enable, common->base + common->reg);
     51	spin_unlock_irqrestore(common->lock, flags);
     52}
     53EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_enable, SUNXI_CCU);
     54
     55void ccu_sdm_helper_disable(struct ccu_common *common,
     56			    struct ccu_sdm_internal *sdm)
     57{
     58	unsigned long flags;
     59	u32 reg;
     60
     61	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
     62		return;
     63
     64	spin_lock_irqsave(common->lock, flags);
     65	reg = readl(common->base + common->reg);
     66	writel(reg & ~sdm->enable, common->base + common->reg);
     67	spin_unlock_irqrestore(common->lock, flags);
     68
     69	spin_lock_irqsave(common->lock, flags);
     70	reg = readl(common->base + sdm->tuning_reg);
     71	writel(reg & ~sdm->tuning_enable, common->base + sdm->tuning_reg);
     72	spin_unlock_irqrestore(common->lock, flags);
     73}
     74EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_disable, SUNXI_CCU);
     75
     76/*
     77 * Sigma delta modulation provides a way to do fractional-N frequency
     78 * synthesis, in essence allowing the PLL to output any frequency
     79 * within its operational range. On earlier SoCs such as the A10/A20,
     80 * some PLLs support this. On later SoCs, all PLLs support this.
     81 *
     82 * The datasheets do not explain what the "wave top" and "wave bottom"
     83 * parameters mean or do, nor how to calculate the effective output
     84 * frequency. The only examples (and real world usage) are for the audio
     85 * PLL to generate 24.576 and 22.5792 MHz clock rates used by the audio
     86 * peripherals. The author lacks the underlying domain knowledge to
     87 * pursue this.
     88 *
     89 * The goal and function of the following code is to support the two
     90 * clock rates used by the audio subsystem, allowing for proper audio
     91 * playback and capture without any pitch or speed changes.
     92 */
     93bool ccu_sdm_helper_has_rate(struct ccu_common *common,
     94			     struct ccu_sdm_internal *sdm,
     95			     unsigned long rate)
     96{
     97	unsigned int i;
     98
     99	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
    100		return false;
    101
    102	for (i = 0; i < sdm->table_size; i++)
    103		if (sdm->table[i].rate == rate)
    104			return true;
    105
    106	return false;
    107}
    108EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_has_rate, SUNXI_CCU);
    109
    110unsigned long ccu_sdm_helper_read_rate(struct ccu_common *common,
    111				       struct ccu_sdm_internal *sdm,
    112				       u32 m, u32 n)
    113{
    114	unsigned int i;
    115	u32 reg;
    116
    117	pr_debug("%s: Read sigma-delta modulation setting\n",
    118		 clk_hw_get_name(&common->hw));
    119
    120	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
    121		return 0;
    122
    123	pr_debug("%s: clock is sigma-delta modulated\n",
    124		 clk_hw_get_name(&common->hw));
    125
    126	reg = readl(common->base + sdm->tuning_reg);
    127
    128	pr_debug("%s: pattern reg is 0x%x",
    129		 clk_hw_get_name(&common->hw), reg);
    130
    131	for (i = 0; i < sdm->table_size; i++)
    132		if (sdm->table[i].pattern == reg &&
    133		    sdm->table[i].m == m && sdm->table[i].n == n)
    134			return sdm->table[i].rate;
    135
    136	/* We can't calculate the effective clock rate, so just fail. */
    137	return 0;
    138}
    139EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_read_rate, SUNXI_CCU);
    140
    141int ccu_sdm_helper_get_factors(struct ccu_common *common,
    142			       struct ccu_sdm_internal *sdm,
    143			       unsigned long rate,
    144			       unsigned long *m, unsigned long *n)
    145{
    146	unsigned int i;
    147
    148	if (!(common->features & CCU_FEATURE_SIGMA_DELTA_MOD))
    149		return -EINVAL;
    150
    151	for (i = 0; i < sdm->table_size; i++)
    152		if (sdm->table[i].rate == rate) {
    153			*m = sdm->table[i].m;
    154			*n = sdm->table[i].n;
    155			return 0;
    156		}
    157
    158	/* nothing found */
    159	return -EINVAL;
    160}
    161EXPORT_SYMBOL_NS_GPL(ccu_sdm_helper_get_factors, SUNXI_CCU);