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-hi6220-stub.c (6455B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Hi6220 stub clock driver
      4 *
      5 * Copyright (c) 2015 Hisilicon Limited.
      6 * Copyright (c) 2015 Linaro Limited.
      7 *
      8 * Author: Leo Yan <leo.yan@linaro.org>
      9 */
     10
     11#include <linux/clk-provider.h>
     12#include <linux/err.h>
     13#include <linux/kernel.h>
     14#include <linux/mfd/syscon.h>
     15#include <linux/mailbox_client.h>
     16#include <linux/of.h>
     17#include <linux/of_device.h>
     18#include <linux/regmap.h>
     19
     20/* Stub clocks id */
     21#define HI6220_STUB_ACPU0		0
     22#define HI6220_STUB_ACPU1		1
     23#define HI6220_STUB_GPU			2
     24#define HI6220_STUB_DDR			5
     25
     26/* Mailbox message */
     27#define HI6220_MBOX_MSG_LEN		8
     28
     29#define HI6220_MBOX_FREQ		0xA
     30#define HI6220_MBOX_CMD_SET		0x3
     31#define HI6220_MBOX_OBJ_AP		0x0
     32
     33/* CPU dynamic frequency scaling */
     34#define ACPU_DFS_FREQ_MAX		0x1724
     35#define ACPU_DFS_CUR_FREQ		0x17CC
     36#define ACPU_DFS_FLAG			0x1B30
     37#define ACPU_DFS_FREQ_REQ		0x1B34
     38#define ACPU_DFS_FREQ_LMT		0x1B38
     39#define ACPU_DFS_LOCK_FLAG		0xAEAEAEAE
     40
     41#define to_stub_clk(hw) container_of(hw, struct hi6220_stub_clk, hw)
     42
     43struct hi6220_stub_clk {
     44	u32 id;
     45
     46	struct device *dev;
     47	struct clk_hw hw;
     48
     49	struct regmap *dfs_map;
     50	struct mbox_client cl;
     51	struct mbox_chan *mbox;
     52};
     53
     54struct hi6220_mbox_msg {
     55	unsigned char type;
     56	unsigned char cmd;
     57	unsigned char obj;
     58	unsigned char src;
     59	unsigned char para[4];
     60};
     61
     62union hi6220_mbox_data {
     63	unsigned int data[HI6220_MBOX_MSG_LEN];
     64	struct hi6220_mbox_msg msg;
     65};
     66
     67static unsigned int hi6220_acpu_get_freq(struct hi6220_stub_clk *stub_clk)
     68{
     69	unsigned int freq;
     70
     71	regmap_read(stub_clk->dfs_map, ACPU_DFS_CUR_FREQ, &freq);
     72	return freq;
     73}
     74
     75static int hi6220_acpu_set_freq(struct hi6220_stub_clk *stub_clk,
     76				unsigned int freq)
     77{
     78	union hi6220_mbox_data data;
     79
     80	/* set the frequency in sram */
     81	regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, freq);
     82
     83	/* compound mailbox message */
     84	data.msg.type = HI6220_MBOX_FREQ;
     85	data.msg.cmd  = HI6220_MBOX_CMD_SET;
     86	data.msg.obj  = HI6220_MBOX_OBJ_AP;
     87	data.msg.src  = HI6220_MBOX_OBJ_AP;
     88
     89	mbox_send_message(stub_clk->mbox, &data);
     90	return 0;
     91}
     92
     93static int hi6220_acpu_round_freq(struct hi6220_stub_clk *stub_clk,
     94				  unsigned int freq)
     95{
     96	unsigned int limit_flag, limit_freq = UINT_MAX;
     97	unsigned int max_freq;
     98
     99	/* check the constrained frequency */
    100	regmap_read(stub_clk->dfs_map, ACPU_DFS_FLAG, &limit_flag);
    101	if (limit_flag == ACPU_DFS_LOCK_FLAG)
    102		regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, &limit_freq);
    103
    104	/* check the supported maximum frequency */
    105	regmap_read(stub_clk->dfs_map, ACPU_DFS_FREQ_MAX, &max_freq);
    106
    107	/* calculate the real maximum frequency */
    108	max_freq = min(max_freq, limit_freq);
    109
    110	if (WARN_ON(freq > max_freq))
    111		freq = max_freq;
    112
    113	return freq;
    114}
    115
    116static unsigned long hi6220_stub_clk_recalc_rate(struct clk_hw *hw,
    117		unsigned long parent_rate)
    118{
    119	u32 rate = 0;
    120	struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
    121
    122	switch (stub_clk->id) {
    123	case HI6220_STUB_ACPU0:
    124		rate = hi6220_acpu_get_freq(stub_clk);
    125
    126		/* convert from kHz to Hz */
    127		rate *= 1000;
    128		break;
    129
    130	default:
    131		dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
    132			__func__, stub_clk->id);
    133		break;
    134	}
    135
    136	return rate;
    137}
    138
    139static int hi6220_stub_clk_set_rate(struct clk_hw *hw, unsigned long rate,
    140		unsigned long parent_rate)
    141{
    142	struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
    143	unsigned long new_rate = rate / 1000;  /* kHz */
    144	int ret = 0;
    145
    146	switch (stub_clk->id) {
    147	case HI6220_STUB_ACPU0:
    148		ret = hi6220_acpu_set_freq(stub_clk, new_rate);
    149		if (ret < 0)
    150			return ret;
    151
    152		break;
    153
    154	default:
    155		dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
    156			__func__, stub_clk->id);
    157		break;
    158	}
    159
    160	pr_debug("%s: set rate=%ldkHz\n", __func__, new_rate);
    161	return ret;
    162}
    163
    164static long hi6220_stub_clk_round_rate(struct clk_hw *hw, unsigned long rate,
    165		unsigned long *parent_rate)
    166{
    167	struct hi6220_stub_clk *stub_clk = to_stub_clk(hw);
    168	unsigned long new_rate = rate / 1000;  /* kHz */
    169
    170	switch (stub_clk->id) {
    171	case HI6220_STUB_ACPU0:
    172		new_rate = hi6220_acpu_round_freq(stub_clk, new_rate);
    173
    174		/* convert from kHz to Hz */
    175		new_rate *= 1000;
    176		break;
    177
    178	default:
    179		dev_err(stub_clk->dev, "%s: un-supported clock id %d\n",
    180			__func__, stub_clk->id);
    181		break;
    182	}
    183
    184	return new_rate;
    185}
    186
    187static const struct clk_ops hi6220_stub_clk_ops = {
    188	.recalc_rate	= hi6220_stub_clk_recalc_rate,
    189	.round_rate	= hi6220_stub_clk_round_rate,
    190	.set_rate	= hi6220_stub_clk_set_rate,
    191};
    192
    193static int hi6220_stub_clk_probe(struct platform_device *pdev)
    194{
    195	struct device *dev = &pdev->dev;
    196	struct clk_init_data init;
    197	struct hi6220_stub_clk *stub_clk;
    198	struct clk *clk;
    199	struct device_node *np = pdev->dev.of_node;
    200	int ret;
    201
    202	stub_clk = devm_kzalloc(dev, sizeof(*stub_clk), GFP_KERNEL);
    203	if (!stub_clk)
    204		return -ENOMEM;
    205
    206	stub_clk->dfs_map = syscon_regmap_lookup_by_phandle(np,
    207				"hisilicon,hi6220-clk-sram");
    208	if (IS_ERR(stub_clk->dfs_map)) {
    209		dev_err(dev, "failed to get sram regmap\n");
    210		return PTR_ERR(stub_clk->dfs_map);
    211	}
    212
    213	stub_clk->hw.init = &init;
    214	stub_clk->dev = dev;
    215	stub_clk->id = HI6220_STUB_ACPU0;
    216
    217	/* Use mailbox client with blocking mode */
    218	stub_clk->cl.dev = dev;
    219	stub_clk->cl.tx_done = NULL;
    220	stub_clk->cl.tx_block = true;
    221	stub_clk->cl.tx_tout = 500;
    222	stub_clk->cl.knows_txdone = false;
    223
    224	/* Allocate mailbox channel */
    225	stub_clk->mbox = mbox_request_channel(&stub_clk->cl, 0);
    226	if (IS_ERR(stub_clk->mbox)) {
    227		dev_err(dev, "failed get mailbox channel\n");
    228		return PTR_ERR(stub_clk->mbox);
    229	}
    230
    231	init.name = "acpu0";
    232	init.ops = &hi6220_stub_clk_ops;
    233	init.num_parents = 0;
    234	init.flags = 0;
    235
    236	clk = devm_clk_register(dev, &stub_clk->hw);
    237	if (IS_ERR(clk))
    238		return PTR_ERR(clk);
    239
    240	ret = of_clk_add_provider(np, of_clk_src_simple_get, clk);
    241	if (ret) {
    242		dev_err(dev, "failed to register OF clock provider\n");
    243		return ret;
    244	}
    245
    246	/* initialize buffer to zero */
    247	regmap_write(stub_clk->dfs_map, ACPU_DFS_FLAG, 0x0);
    248	regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_REQ, 0x0);
    249	regmap_write(stub_clk->dfs_map, ACPU_DFS_FREQ_LMT, 0x0);
    250
    251	dev_dbg(dev, "Registered clock '%s'\n", init.name);
    252	return 0;
    253}
    254
    255static const struct of_device_id hi6220_stub_clk_of_match[] = {
    256	{ .compatible = "hisilicon,hi6220-stub-clk", },
    257	{}
    258};
    259
    260static struct platform_driver hi6220_stub_clk_driver = {
    261	.driver	= {
    262		.name = "hi6220-stub-clk",
    263		.of_match_table = hi6220_stub_clk_of_match,
    264	},
    265	.probe = hi6220_stub_clk_probe,
    266};
    267
    268static int __init hi6220_stub_clk_init(void)
    269{
    270	return platform_driver_register(&hi6220_stub_clk_driver);
    271}
    272subsys_initcall(hi6220_stub_clk_init);