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-bpmp.c (15714B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Copyright (C) 2016-2020 NVIDIA Corporation
      4 */
      5
      6#include <linux/clk-provider.h>
      7#include <linux/device.h>
      8#include <linux/seq_buf.h>
      9#include <linux/slab.h>
     10
     11#include <soc/tegra/bpmp.h>
     12#include <soc/tegra/bpmp-abi.h>
     13
     14#define TEGRA_BPMP_DUMP_CLOCK_INFO	0
     15
     16#define TEGRA_BPMP_CLK_HAS_MUX		BIT(0)
     17#define TEGRA_BPMP_CLK_HAS_SET_RATE	BIT(1)
     18#define TEGRA_BPMP_CLK_IS_ROOT		BIT(2)
     19
     20struct tegra_bpmp_clk_info {
     21	unsigned int id;
     22	char name[MRQ_CLK_NAME_MAXLEN];
     23	unsigned int parents[MRQ_CLK_MAX_PARENTS];
     24	unsigned int num_parents;
     25	unsigned long flags;
     26};
     27
     28struct tegra_bpmp_clk {
     29	struct clk_hw hw;
     30
     31	struct tegra_bpmp *bpmp;
     32	unsigned int id;
     33
     34	unsigned int num_parents;
     35	unsigned int *parents;
     36};
     37
     38static inline struct tegra_bpmp_clk *to_tegra_bpmp_clk(struct clk_hw *hw)
     39{
     40	return container_of(hw, struct tegra_bpmp_clk, hw);
     41}
     42
     43struct tegra_bpmp_clk_message {
     44	unsigned int cmd;
     45	unsigned int id;
     46
     47	struct {
     48		const void *data;
     49		size_t size;
     50	} tx;
     51
     52	struct {
     53		void *data;
     54		size_t size;
     55		int ret;
     56	} rx;
     57};
     58
     59static int tegra_bpmp_clk_transfer(struct tegra_bpmp *bpmp,
     60				   const struct tegra_bpmp_clk_message *clk)
     61{
     62	struct mrq_clk_request request;
     63	struct tegra_bpmp_message msg;
     64	void *req = &request;
     65	int err;
     66
     67	memset(&request, 0, sizeof(request));
     68	request.cmd_and_id = (clk->cmd << 24) | clk->id;
     69
     70	/*
     71	 * The mrq_clk_request structure has an anonymous union at offset 4
     72	 * that contains all possible sub-command structures. Copy the data
     73	 * to that union. Ideally we'd be able to refer to it by name, but
     74	 * doing so would require changing the ABI header and increase the
     75	 * maintenance burden.
     76	 */
     77	memcpy(req + 4, clk->tx.data, clk->tx.size);
     78
     79	memset(&msg, 0, sizeof(msg));
     80	msg.mrq = MRQ_CLK;
     81	msg.tx.data = &request;
     82	msg.tx.size = sizeof(request);
     83	msg.rx.data = clk->rx.data;
     84	msg.rx.size = clk->rx.size;
     85
     86	err = tegra_bpmp_transfer(bpmp, &msg);
     87	if (err < 0)
     88		return err;
     89	else if (msg.rx.ret < 0)
     90		return -EINVAL;
     91
     92	return 0;
     93}
     94
     95static int tegra_bpmp_clk_prepare(struct clk_hw *hw)
     96{
     97	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
     98	struct tegra_bpmp_clk_message msg;
     99
    100	memset(&msg, 0, sizeof(msg));
    101	msg.cmd = CMD_CLK_ENABLE;
    102	msg.id = clk->id;
    103
    104	return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    105}
    106
    107static void tegra_bpmp_clk_unprepare(struct clk_hw *hw)
    108{
    109	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    110	struct tegra_bpmp_clk_message msg;
    111	int err;
    112
    113	memset(&msg, 0, sizeof(msg));
    114	msg.cmd = CMD_CLK_DISABLE;
    115	msg.id = clk->id;
    116
    117	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    118	if (err < 0)
    119		dev_err(clk->bpmp->dev, "failed to disable clock %s: %d\n",
    120			clk_hw_get_name(hw), err);
    121}
    122
    123static int tegra_bpmp_clk_is_prepared(struct clk_hw *hw)
    124{
    125	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    126	struct cmd_clk_is_enabled_response response;
    127	struct tegra_bpmp_clk_message msg;
    128	int err;
    129
    130	memset(&msg, 0, sizeof(msg));
    131	msg.cmd = CMD_CLK_IS_ENABLED;
    132	msg.id = clk->id;
    133	msg.rx.data = &response;
    134	msg.rx.size = sizeof(response);
    135
    136	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    137	if (err < 0)
    138		return err;
    139
    140	return response.state;
    141}
    142
    143static unsigned long tegra_bpmp_clk_recalc_rate(struct clk_hw *hw,
    144						unsigned long parent_rate)
    145{
    146	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    147	struct cmd_clk_get_rate_response response;
    148	struct cmd_clk_get_rate_request request;
    149	struct tegra_bpmp_clk_message msg;
    150	int err;
    151
    152	memset(&msg, 0, sizeof(msg));
    153	msg.cmd = CMD_CLK_GET_RATE;
    154	msg.id = clk->id;
    155	msg.tx.data = &request;
    156	msg.tx.size = sizeof(request);
    157	msg.rx.data = &response;
    158	msg.rx.size = sizeof(response);
    159
    160	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    161	if (err < 0)
    162		return err;
    163
    164	return response.rate;
    165}
    166
    167static int tegra_bpmp_clk_determine_rate(struct clk_hw *hw,
    168					 struct clk_rate_request *rate_req)
    169{
    170	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    171	struct cmd_clk_round_rate_response response;
    172	struct cmd_clk_round_rate_request request;
    173	struct tegra_bpmp_clk_message msg;
    174	unsigned long rate;
    175	int err;
    176
    177	rate = min(max(rate_req->rate, rate_req->min_rate), rate_req->max_rate);
    178
    179	memset(&request, 0, sizeof(request));
    180	request.rate = min_t(u64, rate, S64_MAX);
    181
    182	memset(&msg, 0, sizeof(msg));
    183	msg.cmd = CMD_CLK_ROUND_RATE;
    184	msg.id = clk->id;
    185	msg.tx.data = &request;
    186	msg.tx.size = sizeof(request);
    187	msg.rx.data = &response;
    188	msg.rx.size = sizeof(response);
    189
    190	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    191	if (err < 0)
    192		return err;
    193
    194	rate_req->rate = (unsigned long)response.rate;
    195
    196	return 0;
    197}
    198
    199static int tegra_bpmp_clk_set_parent(struct clk_hw *hw, u8 index)
    200{
    201	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    202	struct cmd_clk_set_parent_response response;
    203	struct cmd_clk_set_parent_request request;
    204	struct tegra_bpmp_clk_message msg;
    205	int err;
    206
    207	memset(&request, 0, sizeof(request));
    208	request.parent_id = clk->parents[index];
    209
    210	memset(&msg, 0, sizeof(msg));
    211	msg.cmd = CMD_CLK_SET_PARENT;
    212	msg.id = clk->id;
    213	msg.tx.data = &request;
    214	msg.tx.size = sizeof(request);
    215	msg.rx.data = &response;
    216	msg.rx.size = sizeof(response);
    217
    218	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    219	if (err < 0)
    220		return err;
    221
    222	/* XXX check parent ID in response */
    223
    224	return 0;
    225}
    226
    227static u8 tegra_bpmp_clk_get_parent(struct clk_hw *hw)
    228{
    229	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    230	struct cmd_clk_get_parent_response response;
    231	struct tegra_bpmp_clk_message msg;
    232	unsigned int i;
    233	int err;
    234
    235	memset(&msg, 0, sizeof(msg));
    236	msg.cmd = CMD_CLK_GET_PARENT;
    237	msg.id = clk->id;
    238	msg.rx.data = &response;
    239	msg.rx.size = sizeof(response);
    240
    241	err = tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    242	if (err < 0) {
    243		dev_err(clk->bpmp->dev, "failed to get parent for %s: %d\n",
    244			clk_hw_get_name(hw), err);
    245		return U8_MAX;
    246	}
    247
    248	for (i = 0; i < clk->num_parents; i++)
    249		if (clk->parents[i] == response.parent_id)
    250			return i;
    251
    252	return U8_MAX;
    253}
    254
    255static int tegra_bpmp_clk_set_rate(struct clk_hw *hw, unsigned long rate,
    256				   unsigned long parent_rate)
    257{
    258	struct tegra_bpmp_clk *clk = to_tegra_bpmp_clk(hw);
    259	struct cmd_clk_set_rate_response response;
    260	struct cmd_clk_set_rate_request request;
    261	struct tegra_bpmp_clk_message msg;
    262
    263	memset(&request, 0, sizeof(request));
    264	request.rate = min_t(u64, rate, S64_MAX);
    265
    266	memset(&msg, 0, sizeof(msg));
    267	msg.cmd = CMD_CLK_SET_RATE;
    268	msg.id = clk->id;
    269	msg.tx.data = &request;
    270	msg.tx.size = sizeof(request);
    271	msg.rx.data = &response;
    272	msg.rx.size = sizeof(response);
    273
    274	return tegra_bpmp_clk_transfer(clk->bpmp, &msg);
    275}
    276
    277static const struct clk_ops tegra_bpmp_clk_gate_ops = {
    278	.prepare = tegra_bpmp_clk_prepare,
    279	.unprepare = tegra_bpmp_clk_unprepare,
    280	.is_prepared = tegra_bpmp_clk_is_prepared,
    281	.recalc_rate = tegra_bpmp_clk_recalc_rate,
    282};
    283
    284static const struct clk_ops tegra_bpmp_clk_mux_ops = {
    285	.prepare = tegra_bpmp_clk_prepare,
    286	.unprepare = tegra_bpmp_clk_unprepare,
    287	.is_prepared = tegra_bpmp_clk_is_prepared,
    288	.recalc_rate = tegra_bpmp_clk_recalc_rate,
    289	.set_parent = tegra_bpmp_clk_set_parent,
    290	.get_parent = tegra_bpmp_clk_get_parent,
    291};
    292
    293static const struct clk_ops tegra_bpmp_clk_rate_ops = {
    294	.prepare = tegra_bpmp_clk_prepare,
    295	.unprepare = tegra_bpmp_clk_unprepare,
    296	.is_prepared = tegra_bpmp_clk_is_prepared,
    297	.recalc_rate = tegra_bpmp_clk_recalc_rate,
    298	.determine_rate = tegra_bpmp_clk_determine_rate,
    299	.set_rate = tegra_bpmp_clk_set_rate,
    300};
    301
    302static const struct clk_ops tegra_bpmp_clk_mux_rate_ops = {
    303	.prepare = tegra_bpmp_clk_prepare,
    304	.unprepare = tegra_bpmp_clk_unprepare,
    305	.is_prepared = tegra_bpmp_clk_is_prepared,
    306	.recalc_rate = tegra_bpmp_clk_recalc_rate,
    307	.determine_rate = tegra_bpmp_clk_determine_rate,
    308	.set_parent = tegra_bpmp_clk_set_parent,
    309	.get_parent = tegra_bpmp_clk_get_parent,
    310	.set_rate = tegra_bpmp_clk_set_rate,
    311};
    312
    313static int tegra_bpmp_clk_get_max_id(struct tegra_bpmp *bpmp)
    314{
    315	struct cmd_clk_get_max_clk_id_response response;
    316	struct tegra_bpmp_clk_message msg;
    317	int err;
    318
    319	memset(&msg, 0, sizeof(msg));
    320	msg.cmd = CMD_CLK_GET_MAX_CLK_ID;
    321	msg.rx.data = &response;
    322	msg.rx.size = sizeof(response);
    323
    324	err = tegra_bpmp_clk_transfer(bpmp, &msg);
    325	if (err < 0)
    326		return err;
    327
    328	if (response.max_id > INT_MAX)
    329		return -E2BIG;
    330
    331	return response.max_id;
    332}
    333
    334static int tegra_bpmp_clk_get_info(struct tegra_bpmp *bpmp, unsigned int id,
    335				   struct tegra_bpmp_clk_info *info)
    336{
    337	struct cmd_clk_get_all_info_response response;
    338	struct tegra_bpmp_clk_message msg;
    339	unsigned int i;
    340	int err;
    341
    342	memset(&msg, 0, sizeof(msg));
    343	msg.cmd = CMD_CLK_GET_ALL_INFO;
    344	msg.id = id;
    345	msg.rx.data = &response;
    346	msg.rx.size = sizeof(response);
    347
    348	err = tegra_bpmp_clk_transfer(bpmp, &msg);
    349	if (err < 0)
    350		return err;
    351
    352	strlcpy(info->name, response.name, MRQ_CLK_NAME_MAXLEN);
    353	info->num_parents = response.num_parents;
    354
    355	for (i = 0; i < info->num_parents; i++)
    356		info->parents[i] = response.parents[i];
    357
    358	info->flags = response.flags;
    359
    360	return 0;
    361}
    362
    363static void tegra_bpmp_clk_info_dump(struct tegra_bpmp *bpmp,
    364				     const char *level,
    365				     const struct tegra_bpmp_clk_info *info)
    366{
    367	const char *prefix = "";
    368	struct seq_buf buf;
    369	unsigned int i;
    370	char flags[64];
    371
    372	seq_buf_init(&buf, flags, sizeof(flags));
    373
    374	if (info->flags)
    375		seq_buf_printf(&buf, "(");
    376
    377	if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
    378		seq_buf_printf(&buf, "%smux", prefix);
    379		prefix = ", ";
    380	}
    381
    382	if ((info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE) == 0) {
    383		seq_buf_printf(&buf, "%sfixed", prefix);
    384		prefix = ", ";
    385	}
    386
    387	if (info->flags & TEGRA_BPMP_CLK_IS_ROOT) {
    388		seq_buf_printf(&buf, "%sroot", prefix);
    389		prefix = ", ";
    390	}
    391
    392	if (info->flags)
    393		seq_buf_printf(&buf, ")");
    394
    395	dev_printk(level, bpmp->dev, "%03u: %s\n", info->id, info->name);
    396	dev_printk(level, bpmp->dev, "  flags: %lx %s\n", info->flags, flags);
    397	dev_printk(level, bpmp->dev, "  parents: %u\n", info->num_parents);
    398
    399	for (i = 0; i < info->num_parents; i++)
    400		dev_printk(level, bpmp->dev, "    %03u\n", info->parents[i]);
    401}
    402
    403static int tegra_bpmp_probe_clocks(struct tegra_bpmp *bpmp,
    404				   struct tegra_bpmp_clk_info **clocksp)
    405{
    406	struct tegra_bpmp_clk_info *clocks;
    407	unsigned int max_id, id, count = 0;
    408	unsigned int holes = 0;
    409	int err;
    410
    411	err = tegra_bpmp_clk_get_max_id(bpmp);
    412	if (err < 0)
    413		return err;
    414
    415	max_id = err;
    416
    417	dev_dbg(bpmp->dev, "maximum clock ID: %u\n", max_id);
    418
    419	clocks = kcalloc(max_id + 1, sizeof(*clocks), GFP_KERNEL);
    420	if (!clocks)
    421		return -ENOMEM;
    422
    423	for (id = 0; id <= max_id; id++) {
    424		struct tegra_bpmp_clk_info *info = &clocks[count];
    425
    426		err = tegra_bpmp_clk_get_info(bpmp, id, info);
    427		if (err < 0)
    428			continue;
    429
    430		if (info->num_parents >= U8_MAX) {
    431			dev_err(bpmp->dev,
    432				"clock %u has too many parents (%u, max: %u)\n",
    433				id, info->num_parents, U8_MAX);
    434			continue;
    435		}
    436
    437		/* clock not exposed by BPMP */
    438		if (info->name[0] == '\0') {
    439			holes++;
    440			continue;
    441		}
    442
    443		info->id = id;
    444		count++;
    445
    446		if (TEGRA_BPMP_DUMP_CLOCK_INFO)
    447			tegra_bpmp_clk_info_dump(bpmp, KERN_DEBUG, info);
    448	}
    449
    450	dev_dbg(bpmp->dev, "holes: %u\n", holes);
    451	*clocksp = clocks;
    452
    453	return count;
    454}
    455
    456static unsigned int
    457tegra_bpmp_clk_id_to_index(const struct tegra_bpmp_clk_info *clocks,
    458			   unsigned int num_clocks, unsigned int id)
    459{
    460	unsigned int i;
    461
    462	for (i = 0; i < num_clocks; i++)
    463		if (clocks[i].id == id)
    464			return i;
    465
    466	return UINT_MAX;
    467}
    468
    469static const struct tegra_bpmp_clk_info *
    470tegra_bpmp_clk_find(const struct tegra_bpmp_clk_info *clocks,
    471		    unsigned int num_clocks, unsigned int id)
    472{
    473	unsigned int i;
    474
    475	i = tegra_bpmp_clk_id_to_index(clocks, num_clocks, id);
    476
    477	if (i < num_clocks)
    478		return &clocks[i];
    479
    480	return NULL;
    481}
    482
    483static struct tegra_bpmp_clk *
    484tegra_bpmp_clk_register(struct tegra_bpmp *bpmp,
    485			const struct tegra_bpmp_clk_info *info,
    486			const struct tegra_bpmp_clk_info *clocks,
    487			unsigned int num_clocks)
    488{
    489	struct tegra_bpmp_clk *clk;
    490	struct clk_init_data init;
    491	const char **parents;
    492	unsigned int i;
    493	int err;
    494
    495	clk = devm_kzalloc(bpmp->dev, sizeof(*clk), GFP_KERNEL);
    496	if (!clk)
    497		return ERR_PTR(-ENOMEM);
    498
    499	clk->id = info->id;
    500	clk->bpmp = bpmp;
    501
    502	clk->parents = devm_kcalloc(bpmp->dev, info->num_parents,
    503				    sizeof(*clk->parents), GFP_KERNEL);
    504	if (!clk->parents)
    505		return ERR_PTR(-ENOMEM);
    506
    507	clk->num_parents = info->num_parents;
    508
    509	/* hardware clock initialization */
    510	memset(&init, 0, sizeof(init));
    511	init.name = info->name;
    512	clk->hw.init = &init;
    513
    514	if (info->flags & TEGRA_BPMP_CLK_HAS_MUX) {
    515		if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
    516			init.ops = &tegra_bpmp_clk_mux_rate_ops;
    517		else
    518			init.ops = &tegra_bpmp_clk_mux_ops;
    519	} else {
    520		if (info->flags & TEGRA_BPMP_CLK_HAS_SET_RATE)
    521			init.ops = &tegra_bpmp_clk_rate_ops;
    522		else
    523			init.ops = &tegra_bpmp_clk_gate_ops;
    524	}
    525
    526	init.num_parents = info->num_parents;
    527
    528	parents = kcalloc(info->num_parents, sizeof(*parents), GFP_KERNEL);
    529	if (!parents)
    530		return ERR_PTR(-ENOMEM);
    531
    532	for (i = 0; i < info->num_parents; i++) {
    533		const struct tegra_bpmp_clk_info *parent;
    534
    535		/* keep a private copy of the ID to parent index map */
    536		clk->parents[i] = info->parents[i];
    537
    538		parent = tegra_bpmp_clk_find(clocks, num_clocks,
    539					     info->parents[i]);
    540		if (!parent) {
    541			dev_err(bpmp->dev, "no parent %u found for %u\n",
    542				info->parents[i], info->id);
    543			continue;
    544		}
    545
    546		parents[i] = parent->name;
    547	}
    548
    549	init.parent_names = parents;
    550
    551	err = devm_clk_hw_register(bpmp->dev, &clk->hw);
    552
    553	kfree(parents);
    554
    555	if (err < 0)
    556		return ERR_PTR(err);
    557
    558	return clk;
    559}
    560
    561static void tegra_bpmp_register_clocks_one(struct tegra_bpmp *bpmp,
    562					   struct tegra_bpmp_clk_info *infos,
    563					   unsigned int i,
    564					   unsigned int count)
    565{
    566	unsigned int j;
    567	struct tegra_bpmp_clk_info *info;
    568	struct tegra_bpmp_clk *clk;
    569
    570	if (bpmp->clocks[i]) {
    571		/* already registered */
    572		return;
    573	}
    574
    575	info = &infos[i];
    576	for (j = 0; j < info->num_parents; ++j) {
    577		unsigned int p_id = info->parents[j];
    578		unsigned int p_i = tegra_bpmp_clk_id_to_index(infos, count,
    579							      p_id);
    580		if (p_i < count)
    581			tegra_bpmp_register_clocks_one(bpmp, infos, p_i, count);
    582	}
    583
    584	clk = tegra_bpmp_clk_register(bpmp, info, infos, count);
    585	if (IS_ERR(clk)) {
    586		dev_err(bpmp->dev,
    587			"failed to register clock %u (%s): %ld\n",
    588			info->id, info->name, PTR_ERR(clk));
    589		/* intentionally store the error pointer to
    590		 * bpmp->clocks[i] to avoid re-attempting the
    591		 * registration later
    592		 */
    593	}
    594
    595	bpmp->clocks[i] = clk;
    596}
    597
    598static int tegra_bpmp_register_clocks(struct tegra_bpmp *bpmp,
    599				      struct tegra_bpmp_clk_info *infos,
    600				      unsigned int count)
    601{
    602	unsigned int i;
    603
    604	bpmp->num_clocks = count;
    605
    606	bpmp->clocks = devm_kcalloc(bpmp->dev, count, sizeof(struct tegra_bpmp_clk), GFP_KERNEL);
    607	if (!bpmp->clocks)
    608		return -ENOMEM;
    609
    610	for (i = 0; i < count; i++) {
    611		tegra_bpmp_register_clocks_one(bpmp, infos, i, count);
    612	}
    613
    614	return 0;
    615}
    616
    617static void tegra_bpmp_unregister_clocks(struct tegra_bpmp *bpmp)
    618{
    619	unsigned int i;
    620
    621	for (i = 0; i < bpmp->num_clocks; i++)
    622		clk_hw_unregister(&bpmp->clocks[i]->hw);
    623}
    624
    625static struct clk_hw *tegra_bpmp_clk_of_xlate(struct of_phandle_args *clkspec,
    626					      void *data)
    627{
    628	unsigned int id = clkspec->args[0], i;
    629	struct tegra_bpmp *bpmp = data;
    630
    631	for (i = 0; i < bpmp->num_clocks; i++) {
    632		struct tegra_bpmp_clk *clk = bpmp->clocks[i];
    633
    634		if (!clk)
    635			continue;
    636
    637		if (clk->id == id)
    638			return &clk->hw;
    639	}
    640
    641	return NULL;
    642}
    643
    644int tegra_bpmp_init_clocks(struct tegra_bpmp *bpmp)
    645{
    646	struct tegra_bpmp_clk_info *clocks;
    647	unsigned int count;
    648	int err;
    649
    650	err = tegra_bpmp_probe_clocks(bpmp, &clocks);
    651	if (err < 0)
    652		return err;
    653
    654	count = err;
    655
    656	dev_dbg(bpmp->dev, "%u clocks probed\n", count);
    657
    658	err = tegra_bpmp_register_clocks(bpmp, clocks, count);
    659	if (err < 0)
    660		goto free;
    661
    662	err = of_clk_add_hw_provider(bpmp->dev->of_node,
    663				     tegra_bpmp_clk_of_xlate,
    664				     bpmp);
    665	if (err < 0) {
    666		tegra_bpmp_unregister_clocks(bpmp);
    667		goto free;
    668	}
    669
    670free:
    671	kfree(clocks);
    672	return err;
    673}