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-scmi.c (6685B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * System Control and Power Interface (SCMI) Protocol based clock driver
      4 *
      5 * Copyright (C) 2018-2022 ARM Ltd.
      6 */
      7
      8#include <linux/clk-provider.h>
      9#include <linux/device.h>
     10#include <linux/err.h>
     11#include <linux/of.h>
     12#include <linux/module.h>
     13#include <linux/scmi_protocol.h>
     14#include <asm/div64.h>
     15
     16static const struct scmi_clk_proto_ops *scmi_proto_clk_ops;
     17
     18struct scmi_clk {
     19	u32 id;
     20	struct clk_hw hw;
     21	const struct scmi_clock_info *info;
     22	const struct scmi_protocol_handle *ph;
     23};
     24
     25#define to_scmi_clk(clk) container_of(clk, struct scmi_clk, hw)
     26
     27static unsigned long scmi_clk_recalc_rate(struct clk_hw *hw,
     28					  unsigned long parent_rate)
     29{
     30	int ret;
     31	u64 rate;
     32	struct scmi_clk *clk = to_scmi_clk(hw);
     33
     34	ret = scmi_proto_clk_ops->rate_get(clk->ph, clk->id, &rate);
     35	if (ret)
     36		return 0;
     37	return rate;
     38}
     39
     40static long scmi_clk_round_rate(struct clk_hw *hw, unsigned long rate,
     41				unsigned long *parent_rate)
     42{
     43	u64 fmin, fmax, ftmp;
     44	struct scmi_clk *clk = to_scmi_clk(hw);
     45
     46	/*
     47	 * We can't figure out what rate it will be, so just return the
     48	 * rate back to the caller. scmi_clk_recalc_rate() will be called
     49	 * after the rate is set and we'll know what rate the clock is
     50	 * running at then.
     51	 */
     52	if (clk->info->rate_discrete)
     53		return rate;
     54
     55	fmin = clk->info->range.min_rate;
     56	fmax = clk->info->range.max_rate;
     57	if (rate <= fmin)
     58		return fmin;
     59	else if (rate >= fmax)
     60		return fmax;
     61
     62	ftmp = rate - fmin;
     63	ftmp += clk->info->range.step_size - 1; /* to round up */
     64	do_div(ftmp, clk->info->range.step_size);
     65
     66	return ftmp * clk->info->range.step_size + fmin;
     67}
     68
     69static int scmi_clk_set_rate(struct clk_hw *hw, unsigned long rate,
     70			     unsigned long parent_rate)
     71{
     72	struct scmi_clk *clk = to_scmi_clk(hw);
     73
     74	return scmi_proto_clk_ops->rate_set(clk->ph, clk->id, rate);
     75}
     76
     77static int scmi_clk_enable(struct clk_hw *hw)
     78{
     79	struct scmi_clk *clk = to_scmi_clk(hw);
     80
     81	return scmi_proto_clk_ops->enable(clk->ph, clk->id);
     82}
     83
     84static void scmi_clk_disable(struct clk_hw *hw)
     85{
     86	struct scmi_clk *clk = to_scmi_clk(hw);
     87
     88	scmi_proto_clk_ops->disable(clk->ph, clk->id);
     89}
     90
     91static int scmi_clk_atomic_enable(struct clk_hw *hw)
     92{
     93	struct scmi_clk *clk = to_scmi_clk(hw);
     94
     95	return scmi_proto_clk_ops->enable_atomic(clk->ph, clk->id);
     96}
     97
     98static void scmi_clk_atomic_disable(struct clk_hw *hw)
     99{
    100	struct scmi_clk *clk = to_scmi_clk(hw);
    101
    102	scmi_proto_clk_ops->disable_atomic(clk->ph, clk->id);
    103}
    104
    105/*
    106 * We can provide enable/disable atomic callbacks only if the underlying SCMI
    107 * transport for an SCMI instance is configured to handle SCMI commands in an
    108 * atomic manner.
    109 *
    110 * When no SCMI atomic transport support is available we instead provide only
    111 * the prepare/unprepare API, as allowed by the clock framework when atomic
    112 * calls are not available.
    113 *
    114 * Two distinct sets of clk_ops are provided since we could have multiple SCMI
    115 * instances with different underlying transport quality, so they cannot be
    116 * shared.
    117 */
    118static const struct clk_ops scmi_clk_ops = {
    119	.recalc_rate = scmi_clk_recalc_rate,
    120	.round_rate = scmi_clk_round_rate,
    121	.set_rate = scmi_clk_set_rate,
    122	.prepare = scmi_clk_enable,
    123	.unprepare = scmi_clk_disable,
    124};
    125
    126static const struct clk_ops scmi_atomic_clk_ops = {
    127	.recalc_rate = scmi_clk_recalc_rate,
    128	.round_rate = scmi_clk_round_rate,
    129	.set_rate = scmi_clk_set_rate,
    130	.enable = scmi_clk_atomic_enable,
    131	.disable = scmi_clk_atomic_disable,
    132};
    133
    134static int scmi_clk_ops_init(struct device *dev, struct scmi_clk *sclk,
    135			     const struct clk_ops *scmi_ops)
    136{
    137	int ret;
    138	unsigned long min_rate, max_rate;
    139
    140	struct clk_init_data init = {
    141		.flags = CLK_GET_RATE_NOCACHE,
    142		.num_parents = 0,
    143		.ops = scmi_ops,
    144		.name = sclk->info->name,
    145	};
    146
    147	sclk->hw.init = &init;
    148	ret = devm_clk_hw_register(dev, &sclk->hw);
    149	if (ret)
    150		return ret;
    151
    152	if (sclk->info->rate_discrete) {
    153		int num_rates = sclk->info->list.num_rates;
    154
    155		if (num_rates <= 0)
    156			return -EINVAL;
    157
    158		min_rate = sclk->info->list.rates[0];
    159		max_rate = sclk->info->list.rates[num_rates - 1];
    160	} else {
    161		min_rate = sclk->info->range.min_rate;
    162		max_rate = sclk->info->range.max_rate;
    163	}
    164
    165	clk_hw_set_rate_range(&sclk->hw, min_rate, max_rate);
    166	return ret;
    167}
    168
    169static int scmi_clocks_probe(struct scmi_device *sdev)
    170{
    171	int idx, count, err;
    172	unsigned int atomic_threshold;
    173	bool is_atomic;
    174	struct clk_hw **hws;
    175	struct clk_hw_onecell_data *clk_data;
    176	struct device *dev = &sdev->dev;
    177	struct device_node *np = dev->of_node;
    178	const struct scmi_handle *handle = sdev->handle;
    179	struct scmi_protocol_handle *ph;
    180
    181	if (!handle)
    182		return -ENODEV;
    183
    184	scmi_proto_clk_ops =
    185		handle->devm_protocol_get(sdev, SCMI_PROTOCOL_CLOCK, &ph);
    186	if (IS_ERR(scmi_proto_clk_ops))
    187		return PTR_ERR(scmi_proto_clk_ops);
    188
    189	count = scmi_proto_clk_ops->count_get(ph);
    190	if (count < 0) {
    191		dev_err(dev, "%pOFn: invalid clock output count\n", np);
    192		return -EINVAL;
    193	}
    194
    195	clk_data = devm_kzalloc(dev, struct_size(clk_data, hws, count),
    196				GFP_KERNEL);
    197	if (!clk_data)
    198		return -ENOMEM;
    199
    200	clk_data->num = count;
    201	hws = clk_data->hws;
    202
    203	is_atomic = handle->is_transport_atomic(handle, &atomic_threshold);
    204
    205	for (idx = 0; idx < count; idx++) {
    206		struct scmi_clk *sclk;
    207		const struct clk_ops *scmi_ops;
    208
    209		sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
    210		if (!sclk)
    211			return -ENOMEM;
    212
    213		sclk->info = scmi_proto_clk_ops->info_get(ph, idx);
    214		if (!sclk->info) {
    215			dev_dbg(dev, "invalid clock info for idx %d\n", idx);
    216			continue;
    217		}
    218
    219		sclk->id = idx;
    220		sclk->ph = ph;
    221
    222		/*
    223		 * Note that when transport is atomic but SCMI protocol did not
    224		 * specify (or support) an enable_latency associated with a
    225		 * clock, we default to use atomic operations mode.
    226		 */
    227		if (is_atomic &&
    228		    sclk->info->enable_latency <= atomic_threshold)
    229			scmi_ops = &scmi_atomic_clk_ops;
    230		else
    231			scmi_ops = &scmi_clk_ops;
    232
    233		err = scmi_clk_ops_init(dev, sclk, scmi_ops);
    234		if (err) {
    235			dev_err(dev, "failed to register clock %d\n", idx);
    236			devm_kfree(dev, sclk);
    237			hws[idx] = NULL;
    238		} else {
    239			dev_dbg(dev, "Registered clock:%s%s\n",
    240				sclk->info->name,
    241				scmi_ops == &scmi_atomic_clk_ops ?
    242				" (atomic ops)" : "");
    243			hws[idx] = &sclk->hw;
    244		}
    245	}
    246
    247	return devm_of_clk_add_hw_provider(dev, of_clk_hw_onecell_get,
    248					   clk_data);
    249}
    250
    251static const struct scmi_device_id scmi_id_table[] = {
    252	{ SCMI_PROTOCOL_CLOCK, "clocks" },
    253	{ },
    254};
    255MODULE_DEVICE_TABLE(scmi, scmi_id_table);
    256
    257static struct scmi_driver scmi_clocks_driver = {
    258	.name = "scmi-clocks",
    259	.probe = scmi_clocks_probe,
    260	.id_table = scmi_id_table,
    261};
    262module_scmi_driver(scmi_clocks_driver);
    263
    264MODULE_AUTHOR("Sudeep Holla <sudeep.holla@arm.com>");
    265MODULE_DESCRIPTION("ARM SCMI clock driver");
    266MODULE_LICENSE("GPL v2");