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-utmi.c (6244B)


      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#include <soc/at91/atmel-sfr.h>
     13
     14#include "pmc.h"
     15
     16/*
     17 * The purpose of this clock is to generate a 480 MHz signal. A different
     18 * rate can't be configured.
     19 */
     20#define UTMI_RATE	480000000
     21
     22struct clk_utmi {
     23	struct clk_hw hw;
     24	struct regmap *regmap_pmc;
     25	struct regmap *regmap_sfr;
     26	struct at91_clk_pms pms;
     27};
     28
     29#define to_clk_utmi(hw) container_of(hw, struct clk_utmi, hw)
     30
     31static inline bool clk_utmi_ready(struct regmap *regmap)
     32{
     33	unsigned int status;
     34
     35	regmap_read(regmap, AT91_PMC_SR, &status);
     36
     37	return status & AT91_PMC_LOCKU;
     38}
     39
     40static int clk_utmi_prepare(struct clk_hw *hw)
     41{
     42	struct clk_hw *hw_parent;
     43	struct clk_utmi *utmi = to_clk_utmi(hw);
     44	unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
     45			    AT91_PMC_BIASEN;
     46	unsigned int utmi_ref_clk_freq;
     47	unsigned long parent_rate;
     48
     49	/*
     50	 * If mainck rate is different from 12 MHz, we have to configure the
     51	 * FREQ field of the SFR_UTMICKTRIM register to generate properly
     52	 * the utmi clock.
     53	 */
     54	hw_parent = clk_hw_get_parent(hw);
     55	parent_rate = clk_hw_get_rate(hw_parent);
     56
     57	switch (parent_rate) {
     58	case 12000000:
     59		utmi_ref_clk_freq = 0;
     60		break;
     61	case 16000000:
     62		utmi_ref_clk_freq = 1;
     63		break;
     64	case 24000000:
     65		utmi_ref_clk_freq = 2;
     66		break;
     67	/*
     68	 * Not supported on SAMA5D2 but it's not an issue since MAINCK
     69	 * maximum value is 24 MHz.
     70	 */
     71	case 48000000:
     72		utmi_ref_clk_freq = 3;
     73		break;
     74	default:
     75		pr_err("UTMICK: unsupported mainck rate\n");
     76		return -EINVAL;
     77	}
     78
     79	if (utmi->regmap_sfr) {
     80		regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
     81				   AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
     82	} else if (utmi_ref_clk_freq) {
     83		pr_err("UTMICK: sfr node required\n");
     84		return -EINVAL;
     85	}
     86
     87	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR, uckr, uckr);
     88
     89	while (!clk_utmi_ready(utmi->regmap_pmc))
     90		cpu_relax();
     91
     92	return 0;
     93}
     94
     95static int clk_utmi_is_prepared(struct clk_hw *hw)
     96{
     97	struct clk_utmi *utmi = to_clk_utmi(hw);
     98
     99	return clk_utmi_ready(utmi->regmap_pmc);
    100}
    101
    102static void clk_utmi_unprepare(struct clk_hw *hw)
    103{
    104	struct clk_utmi *utmi = to_clk_utmi(hw);
    105
    106	regmap_update_bits(utmi->regmap_pmc, AT91_CKGR_UCKR,
    107			   AT91_PMC_UPLLEN, 0);
    108}
    109
    110static unsigned long clk_utmi_recalc_rate(struct clk_hw *hw,
    111					  unsigned long parent_rate)
    112{
    113	/* UTMI clk rate is fixed. */
    114	return UTMI_RATE;
    115}
    116
    117static int clk_utmi_save_context(struct clk_hw *hw)
    118{
    119	struct clk_utmi *utmi = to_clk_utmi(hw);
    120
    121	utmi->pms.status = clk_utmi_is_prepared(hw);
    122
    123	return 0;
    124}
    125
    126static void clk_utmi_restore_context(struct clk_hw *hw)
    127{
    128	struct clk_utmi *utmi = to_clk_utmi(hw);
    129
    130	if (utmi->pms.status)
    131		clk_utmi_prepare(hw);
    132}
    133
    134static const struct clk_ops utmi_ops = {
    135	.prepare = clk_utmi_prepare,
    136	.unprepare = clk_utmi_unprepare,
    137	.is_prepared = clk_utmi_is_prepared,
    138	.recalc_rate = clk_utmi_recalc_rate,
    139	.save_context = clk_utmi_save_context,
    140	.restore_context = clk_utmi_restore_context,
    141};
    142
    143static struct clk_hw * __init
    144at91_clk_register_utmi_internal(struct regmap *regmap_pmc,
    145				struct regmap *regmap_sfr,
    146				const char *name, const char *parent_name,
    147				const struct clk_ops *ops, unsigned long flags)
    148{
    149	struct clk_utmi *utmi;
    150	struct clk_hw *hw;
    151	struct clk_init_data init;
    152	int ret;
    153
    154	utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
    155	if (!utmi)
    156		return ERR_PTR(-ENOMEM);
    157
    158	init.name = name;
    159	init.ops = ops;
    160	init.parent_names = parent_name ? &parent_name : NULL;
    161	init.num_parents = parent_name ? 1 : 0;
    162	init.flags = flags;
    163
    164	utmi->hw.init = &init;
    165	utmi->regmap_pmc = regmap_pmc;
    166	utmi->regmap_sfr = regmap_sfr;
    167
    168	hw = &utmi->hw;
    169	ret = clk_hw_register(NULL, &utmi->hw);
    170	if (ret) {
    171		kfree(utmi);
    172		hw = ERR_PTR(ret);
    173	}
    174
    175	return hw;
    176}
    177
    178struct clk_hw * __init
    179at91_clk_register_utmi(struct regmap *regmap_pmc, struct regmap *regmap_sfr,
    180		       const char *name, const char *parent_name)
    181{
    182	return at91_clk_register_utmi_internal(regmap_pmc, regmap_sfr, name,
    183			parent_name, &utmi_ops, CLK_SET_RATE_GATE);
    184}
    185
    186static int clk_utmi_sama7g5_prepare(struct clk_hw *hw)
    187{
    188	struct clk_utmi *utmi = to_clk_utmi(hw);
    189	struct clk_hw *hw_parent;
    190	unsigned long parent_rate;
    191	unsigned int val;
    192
    193	hw_parent = clk_hw_get_parent(hw);
    194	parent_rate = clk_hw_get_rate(hw_parent);
    195
    196	switch (parent_rate) {
    197	case 16000000:
    198		val = 0;
    199		break;
    200	case 20000000:
    201		val = 2;
    202		break;
    203	case 24000000:
    204		val = 3;
    205		break;
    206	case 32000000:
    207		val = 5;
    208		break;
    209	default:
    210		pr_err("UTMICK: unsupported main_xtal rate\n");
    211		return -EINVAL;
    212	}
    213
    214	regmap_write(utmi->regmap_pmc, AT91_PMC_XTALF, val);
    215
    216	return 0;
    217
    218}
    219
    220static int clk_utmi_sama7g5_is_prepared(struct clk_hw *hw)
    221{
    222	struct clk_utmi *utmi = to_clk_utmi(hw);
    223	struct clk_hw *hw_parent;
    224	unsigned long parent_rate;
    225	unsigned int val;
    226
    227	hw_parent = clk_hw_get_parent(hw);
    228	parent_rate = clk_hw_get_rate(hw_parent);
    229
    230	regmap_read(utmi->regmap_pmc, AT91_PMC_XTALF, &val);
    231	switch (val & 0x7) {
    232	case 0:
    233		if (parent_rate == 16000000)
    234			return 1;
    235		break;
    236	case 2:
    237		if (parent_rate == 20000000)
    238			return 1;
    239		break;
    240	case 3:
    241		if (parent_rate == 24000000)
    242			return 1;
    243		break;
    244	case 5:
    245		if (parent_rate == 32000000)
    246			return 1;
    247		break;
    248	default:
    249		break;
    250	}
    251
    252	return 0;
    253}
    254
    255static int clk_utmi_sama7g5_save_context(struct clk_hw *hw)
    256{
    257	struct clk_utmi *utmi = to_clk_utmi(hw);
    258
    259	utmi->pms.status = clk_utmi_sama7g5_is_prepared(hw);
    260
    261	return 0;
    262}
    263
    264static void clk_utmi_sama7g5_restore_context(struct clk_hw *hw)
    265{
    266	struct clk_utmi *utmi = to_clk_utmi(hw);
    267
    268	if (utmi->pms.status)
    269		clk_utmi_sama7g5_prepare(hw);
    270}
    271
    272static const struct clk_ops sama7g5_utmi_ops = {
    273	.prepare = clk_utmi_sama7g5_prepare,
    274	.is_prepared = clk_utmi_sama7g5_is_prepared,
    275	.recalc_rate = clk_utmi_recalc_rate,
    276	.save_context = clk_utmi_sama7g5_save_context,
    277	.restore_context = clk_utmi_sama7g5_restore_context,
    278};
    279
    280struct clk_hw * __init
    281at91_clk_sama7g5_register_utmi(struct regmap *regmap_pmc, const char *name,
    282			       const char *parent_name)
    283{
    284	return at91_clk_register_utmi_internal(regmap_pmc, NULL, name,
    285			parent_name, &sama7g5_utmi_ops, 0);
    286}