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

osm-l3.c (10061B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
      4 */
      5
      6#include <linux/bitfield.h>
      7#include <linux/clk.h>
      8#include <linux/interconnect-provider.h>
      9#include <linux/io.h>
     10#include <linux/kernel.h>
     11#include <linux/module.h>
     12#include <linux/of_device.h>
     13#include <linux/platform_device.h>
     14
     15#include <dt-bindings/interconnect/qcom,osm-l3.h>
     16
     17#include "sc7180.h"
     18#include "sc7280.h"
     19#include "sc8180x.h"
     20#include "sdm845.h"
     21#include "sm8150.h"
     22#include "sm8250.h"
     23
     24#define LUT_MAX_ENTRIES			40U
     25#define LUT_SRC				GENMASK(31, 30)
     26#define LUT_L_VAL			GENMASK(7, 0)
     27#define CLK_HW_DIV			2
     28
     29/* OSM Register offsets */
     30#define REG_ENABLE			0x0
     31#define OSM_LUT_ROW_SIZE		32
     32#define OSM_REG_FREQ_LUT		0x110
     33#define OSM_REG_PERF_STATE		0x920
     34
     35/* EPSS Register offsets */
     36#define EPSS_LUT_ROW_SIZE		4
     37#define EPSS_REG_FREQ_LUT		0x100
     38#define EPSS_REG_PERF_STATE		0x320
     39
     40#define OSM_L3_MAX_LINKS		1
     41
     42#define to_osm_l3_provider(_provider) \
     43	container_of(_provider, struct qcom_osm_l3_icc_provider, provider)
     44
     45struct qcom_osm_l3_icc_provider {
     46	void __iomem *base;
     47	unsigned int max_state;
     48	unsigned int reg_perf_state;
     49	unsigned long lut_tables[LUT_MAX_ENTRIES];
     50	struct icc_provider provider;
     51};
     52
     53/**
     54 * struct qcom_osm_l3_node - Qualcomm specific interconnect nodes
     55 * @name: the node name used in debugfs
     56 * @links: an array of nodes where we can go next while traversing
     57 * @id: a unique node identifier
     58 * @num_links: the total number of @links
     59 * @buswidth: width of the interconnect between a node and the bus
     60 */
     61struct qcom_osm_l3_node {
     62	const char *name;
     63	u16 links[OSM_L3_MAX_LINKS];
     64	u16 id;
     65	u16 num_links;
     66	u16 buswidth;
     67};
     68
     69struct qcom_osm_l3_desc {
     70	const struct qcom_osm_l3_node * const *nodes;
     71	size_t num_nodes;
     72	unsigned int lut_row_size;
     73	unsigned int reg_freq_lut;
     74	unsigned int reg_perf_state;
     75};
     76
     77#define DEFINE_QNODE(_name, _id, _buswidth, ...)			\
     78	static const struct qcom_osm_l3_node _name = {			\
     79		.name = #_name,						\
     80		.id = _id,						\
     81		.buswidth = _buswidth,					\
     82		.num_links = ARRAY_SIZE(((int[]){ __VA_ARGS__ })),	\
     83		.links = { __VA_ARGS__ },				\
     84	}
     85
     86DEFINE_QNODE(sdm845_osm_apps_l3, SDM845_MASTER_OSM_L3_APPS, 16, SDM845_SLAVE_OSM_L3);
     87DEFINE_QNODE(sdm845_osm_l3, SDM845_SLAVE_OSM_L3, 16);
     88
     89static const struct qcom_osm_l3_node * const sdm845_osm_l3_nodes[] = {
     90	[MASTER_OSM_L3_APPS] = &sdm845_osm_apps_l3,
     91	[SLAVE_OSM_L3] = &sdm845_osm_l3,
     92};
     93
     94static const struct qcom_osm_l3_desc sdm845_icc_osm_l3 = {
     95	.nodes = sdm845_osm_l3_nodes,
     96	.num_nodes = ARRAY_SIZE(sdm845_osm_l3_nodes),
     97	.lut_row_size = OSM_LUT_ROW_SIZE,
     98	.reg_freq_lut = OSM_REG_FREQ_LUT,
     99	.reg_perf_state = OSM_REG_PERF_STATE,
    100};
    101
    102DEFINE_QNODE(sc7180_osm_apps_l3, SC7180_MASTER_OSM_L3_APPS, 16, SC7180_SLAVE_OSM_L3);
    103DEFINE_QNODE(sc7180_osm_l3, SC7180_SLAVE_OSM_L3, 16);
    104
    105static const struct qcom_osm_l3_node * const sc7180_osm_l3_nodes[] = {
    106	[MASTER_OSM_L3_APPS] = &sc7180_osm_apps_l3,
    107	[SLAVE_OSM_L3] = &sc7180_osm_l3,
    108};
    109
    110static const struct qcom_osm_l3_desc sc7180_icc_osm_l3 = {
    111	.nodes = sc7180_osm_l3_nodes,
    112	.num_nodes = ARRAY_SIZE(sc7180_osm_l3_nodes),
    113	.lut_row_size = OSM_LUT_ROW_SIZE,
    114	.reg_freq_lut = OSM_REG_FREQ_LUT,
    115	.reg_perf_state = OSM_REG_PERF_STATE,
    116};
    117
    118DEFINE_QNODE(sc7280_epss_apps_l3, SC7280_MASTER_EPSS_L3_APPS, 32, SC7280_SLAVE_EPSS_L3);
    119DEFINE_QNODE(sc7280_epss_l3, SC7280_SLAVE_EPSS_L3, 32);
    120
    121static const struct qcom_osm_l3_node * const sc7280_epss_l3_nodes[] = {
    122	[MASTER_EPSS_L3_APPS] = &sc7280_epss_apps_l3,
    123	[SLAVE_EPSS_L3_SHARED] = &sc7280_epss_l3,
    124};
    125
    126static const struct qcom_osm_l3_desc sc7280_icc_epss_l3 = {
    127	.nodes = sc7280_epss_l3_nodes,
    128	.num_nodes = ARRAY_SIZE(sc7280_epss_l3_nodes),
    129	.lut_row_size = EPSS_LUT_ROW_SIZE,
    130	.reg_freq_lut = EPSS_REG_FREQ_LUT,
    131	.reg_perf_state = EPSS_REG_PERF_STATE,
    132};
    133
    134DEFINE_QNODE(sc8180x_osm_apps_l3, SC8180X_MASTER_OSM_L3_APPS, 32, SC8180X_SLAVE_OSM_L3);
    135DEFINE_QNODE(sc8180x_osm_l3, SC8180X_SLAVE_OSM_L3, 32);
    136
    137static const struct qcom_osm_l3_node * const sc8180x_osm_l3_nodes[] = {
    138	[MASTER_OSM_L3_APPS] = &sc8180x_osm_apps_l3,
    139	[SLAVE_OSM_L3] = &sc8180x_osm_l3,
    140};
    141
    142static const struct qcom_osm_l3_desc sc8180x_icc_osm_l3 = {
    143	.nodes = sc8180x_osm_l3_nodes,
    144	.num_nodes = ARRAY_SIZE(sc8180x_osm_l3_nodes),
    145	.lut_row_size = OSM_LUT_ROW_SIZE,
    146	.reg_freq_lut = OSM_REG_FREQ_LUT,
    147	.reg_perf_state = OSM_REG_PERF_STATE,
    148};
    149
    150DEFINE_QNODE(sm8150_osm_apps_l3, SM8150_MASTER_OSM_L3_APPS, 32, SM8150_SLAVE_OSM_L3);
    151DEFINE_QNODE(sm8150_osm_l3, SM8150_SLAVE_OSM_L3, 32);
    152
    153static const struct qcom_osm_l3_node * const sm8150_osm_l3_nodes[] = {
    154	[MASTER_OSM_L3_APPS] = &sm8150_osm_apps_l3,
    155	[SLAVE_OSM_L3] = &sm8150_osm_l3,
    156};
    157
    158static const struct qcom_osm_l3_desc sm8150_icc_osm_l3 = {
    159	.nodes = sm8150_osm_l3_nodes,
    160	.num_nodes = ARRAY_SIZE(sm8150_osm_l3_nodes),
    161	.lut_row_size = OSM_LUT_ROW_SIZE,
    162	.reg_freq_lut = OSM_REG_FREQ_LUT,
    163	.reg_perf_state = OSM_REG_PERF_STATE,
    164};
    165
    166DEFINE_QNODE(sm8250_epss_apps_l3, SM8250_MASTER_EPSS_L3_APPS, 32, SM8250_SLAVE_EPSS_L3);
    167DEFINE_QNODE(sm8250_epss_l3, SM8250_SLAVE_EPSS_L3, 32);
    168
    169static const struct qcom_osm_l3_node * const sm8250_epss_l3_nodes[] = {
    170	[MASTER_EPSS_L3_APPS] = &sm8250_epss_apps_l3,
    171	[SLAVE_EPSS_L3_SHARED] = &sm8250_epss_l3,
    172};
    173
    174static const struct qcom_osm_l3_desc sm8250_icc_epss_l3 = {
    175	.nodes = sm8250_epss_l3_nodes,
    176	.num_nodes = ARRAY_SIZE(sm8250_epss_l3_nodes),
    177	.lut_row_size = EPSS_LUT_ROW_SIZE,
    178	.reg_freq_lut = EPSS_REG_FREQ_LUT,
    179	.reg_perf_state = EPSS_REG_PERF_STATE,
    180};
    181
    182static int qcom_osm_l3_set(struct icc_node *src, struct icc_node *dst)
    183{
    184	struct qcom_osm_l3_icc_provider *qp;
    185	struct icc_provider *provider;
    186	const struct qcom_osm_l3_node *qn;
    187	struct icc_node *n;
    188	unsigned int index;
    189	u32 agg_peak = 0;
    190	u32 agg_avg = 0;
    191	u64 rate;
    192
    193	qn = src->data;
    194	provider = src->provider;
    195	qp = to_osm_l3_provider(provider);
    196
    197	list_for_each_entry(n, &provider->nodes, node_list)
    198		provider->aggregate(n, 0, n->avg_bw, n->peak_bw,
    199				    &agg_avg, &agg_peak);
    200
    201	rate = max(agg_avg, agg_peak);
    202	rate = icc_units_to_bps(rate);
    203	do_div(rate, qn->buswidth);
    204
    205	for (index = 0; index < qp->max_state - 1; index++) {
    206		if (qp->lut_tables[index] >= rate)
    207			break;
    208	}
    209
    210	writel_relaxed(index, qp->base + qp->reg_perf_state);
    211
    212	return 0;
    213}
    214
    215static int qcom_osm_l3_remove(struct platform_device *pdev)
    216{
    217	struct qcom_osm_l3_icc_provider *qp = platform_get_drvdata(pdev);
    218
    219	icc_nodes_remove(&qp->provider);
    220	return icc_provider_del(&qp->provider);
    221}
    222
    223static int qcom_osm_l3_probe(struct platform_device *pdev)
    224{
    225	u32 info, src, lval, i, prev_freq = 0, freq;
    226	static unsigned long hw_rate, xo_rate;
    227	struct qcom_osm_l3_icc_provider *qp;
    228	const struct qcom_osm_l3_desc *desc;
    229	struct icc_onecell_data *data;
    230	struct icc_provider *provider;
    231	const struct qcom_osm_l3_node * const *qnodes;
    232	struct icc_node *node;
    233	size_t num_nodes;
    234	struct clk *clk;
    235	int ret;
    236
    237	clk = clk_get(&pdev->dev, "xo");
    238	if (IS_ERR(clk))
    239		return PTR_ERR(clk);
    240
    241	xo_rate = clk_get_rate(clk);
    242	clk_put(clk);
    243
    244	clk = clk_get(&pdev->dev, "alternate");
    245	if (IS_ERR(clk))
    246		return PTR_ERR(clk);
    247
    248	hw_rate = clk_get_rate(clk) / CLK_HW_DIV;
    249	clk_put(clk);
    250
    251	qp = devm_kzalloc(&pdev->dev, sizeof(*qp), GFP_KERNEL);
    252	if (!qp)
    253		return -ENOMEM;
    254
    255	qp->base = devm_platform_ioremap_resource(pdev, 0);
    256	if (IS_ERR(qp->base))
    257		return PTR_ERR(qp->base);
    258
    259	/* HW should be in enabled state to proceed */
    260	if (!(readl_relaxed(qp->base + REG_ENABLE) & 0x1)) {
    261		dev_err(&pdev->dev, "error hardware not enabled\n");
    262		return -ENODEV;
    263	}
    264
    265	desc = device_get_match_data(&pdev->dev);
    266	if (!desc)
    267		return -EINVAL;
    268
    269	qp->reg_perf_state = desc->reg_perf_state;
    270
    271	for (i = 0; i < LUT_MAX_ENTRIES; i++) {
    272		info = readl_relaxed(qp->base + desc->reg_freq_lut +
    273				     i * desc->lut_row_size);
    274		src = FIELD_GET(LUT_SRC, info);
    275		lval = FIELD_GET(LUT_L_VAL, info);
    276		if (src)
    277			freq = xo_rate * lval;
    278		else
    279			freq = hw_rate;
    280
    281		/* Two of the same frequencies signify end of table */
    282		if (i > 0 && prev_freq == freq)
    283			break;
    284
    285		dev_dbg(&pdev->dev, "index=%d freq=%d\n", i, freq);
    286
    287		qp->lut_tables[i] = freq;
    288		prev_freq = freq;
    289	}
    290	qp->max_state = i;
    291
    292	qnodes = desc->nodes;
    293	num_nodes = desc->num_nodes;
    294
    295	data = devm_kcalloc(&pdev->dev, num_nodes, sizeof(*node), GFP_KERNEL);
    296	if (!data)
    297		return -ENOMEM;
    298
    299	provider = &qp->provider;
    300	provider->dev = &pdev->dev;
    301	provider->set = qcom_osm_l3_set;
    302	provider->aggregate = icc_std_aggregate;
    303	provider->xlate = of_icc_xlate_onecell;
    304	INIT_LIST_HEAD(&provider->nodes);
    305	provider->data = data;
    306
    307	ret = icc_provider_add(provider);
    308	if (ret) {
    309		dev_err(&pdev->dev, "error adding interconnect provider\n");
    310		return ret;
    311	}
    312
    313	for (i = 0; i < num_nodes; i++) {
    314		size_t j;
    315
    316		node = icc_node_create(qnodes[i]->id);
    317		if (IS_ERR(node)) {
    318			ret = PTR_ERR(node);
    319			goto err;
    320		}
    321
    322		node->name = qnodes[i]->name;
    323		/* Cast away const and add it back in qcom_osm_l3_set() */
    324		node->data = (void *)qnodes[i];
    325		icc_node_add(node, provider);
    326
    327		for (j = 0; j < qnodes[i]->num_links; j++)
    328			icc_link_create(node, qnodes[i]->links[j]);
    329
    330		data->nodes[i] = node;
    331	}
    332	data->num_nodes = num_nodes;
    333
    334	platform_set_drvdata(pdev, qp);
    335
    336	return 0;
    337err:
    338	icc_nodes_remove(provider);
    339	icc_provider_del(provider);
    340
    341	return ret;
    342}
    343
    344static const struct of_device_id osm_l3_of_match[] = {
    345	{ .compatible = "qcom,sc7180-osm-l3", .data = &sc7180_icc_osm_l3 },
    346	{ .compatible = "qcom,sc7280-epss-l3", .data = &sc7280_icc_epss_l3 },
    347	{ .compatible = "qcom,sdm845-osm-l3", .data = &sdm845_icc_osm_l3 },
    348	{ .compatible = "qcom,sm8150-osm-l3", .data = &sm8150_icc_osm_l3 },
    349	{ .compatible = "qcom,sc8180x-osm-l3", .data = &sc8180x_icc_osm_l3 },
    350	{ .compatible = "qcom,sm8250-epss-l3", .data = &sm8250_icc_epss_l3 },
    351	{ }
    352};
    353MODULE_DEVICE_TABLE(of, osm_l3_of_match);
    354
    355static struct platform_driver osm_l3_driver = {
    356	.probe = qcom_osm_l3_probe,
    357	.remove = qcom_osm_l3_remove,
    358	.driver = {
    359		.name = "osm-l3",
    360		.of_match_table = osm_l3_of_match,
    361		.sync_state = icc_sync_state,
    362	},
    363};
    364module_platform_driver(osm_l3_driver);
    365
    366MODULE_DESCRIPTION("Qualcomm OSM L3 interconnect driver");
    367MODULE_LICENSE("GPL v2");