brintos

brintos / linux-shallow public Read only

0
0
Text · 26.9 KiB · 2ed2279 Raw
1118 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * System Control and Management Interface (SCMI) Clock Protocol4 *5 * Copyright (C) 2018-2022 ARM Ltd.6 */7 8#include <linux/module.h>9#include <linux/limits.h>10#include <linux/sort.h>11 12#include "protocols.h"13#include "notify.h"14 15/* Updated only after ALL the mandatory features for that version are merged */16#define SCMI_PROTOCOL_SUPPORTED_VERSION		0x3000017 18enum scmi_clock_protocol_cmd {19	CLOCK_ATTRIBUTES = 0x3,20	CLOCK_DESCRIBE_RATES = 0x4,21	CLOCK_RATE_SET = 0x5,22	CLOCK_RATE_GET = 0x6,23	CLOCK_CONFIG_SET = 0x7,24	CLOCK_NAME_GET = 0x8,25	CLOCK_RATE_NOTIFY = 0x9,26	CLOCK_RATE_CHANGE_REQUESTED_NOTIFY = 0xA,27	CLOCK_CONFIG_GET = 0xB,28	CLOCK_POSSIBLE_PARENTS_GET = 0xC,29	CLOCK_PARENT_SET = 0xD,30	CLOCK_PARENT_GET = 0xE,31	CLOCK_GET_PERMISSIONS = 0xF,32};33 34#define CLOCK_STATE_CONTROL_ALLOWED	BIT(31)35#define CLOCK_PARENT_CONTROL_ALLOWED	BIT(30)36#define CLOCK_RATE_CONTROL_ALLOWED	BIT(29)37 38enum clk_state {39	CLK_STATE_DISABLE,40	CLK_STATE_ENABLE,41	CLK_STATE_RESERVED,42	CLK_STATE_UNCHANGED,43};44 45struct scmi_msg_resp_clock_protocol_attributes {46	__le16 num_clocks;47	u8 max_async_req;48	u8 reserved;49};50 51struct scmi_msg_resp_clock_attributes {52	__le32 attributes;53#define SUPPORTS_RATE_CHANGED_NOTIF(x)		((x) & BIT(31))54#define SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(x)	((x) & BIT(30))55#define SUPPORTS_EXTENDED_NAMES(x)		((x) & BIT(29))56#define SUPPORTS_PARENT_CLOCK(x)		((x) & BIT(28))57#define SUPPORTS_EXTENDED_CONFIG(x)		((x) & BIT(27))58#define SUPPORTS_GET_PERMISSIONS(x)		((x) & BIT(1))59	u8 name[SCMI_SHORT_NAME_MAX_SIZE];60	__le32 clock_enable_latency;61};62 63struct scmi_msg_clock_possible_parents {64	__le32 id;65	__le32 skip_parents;66};67 68struct scmi_msg_resp_clock_possible_parents {69	__le32 num_parent_flags;70#define NUM_PARENTS_RETURNED(x)		((x) & 0xff)71#define NUM_PARENTS_REMAINING(x)	((x) >> 24)72	__le32 possible_parents[];73};74 75struct scmi_msg_clock_set_parent {76	__le32 id;77	__le32 parent_id;78};79 80struct scmi_msg_clock_config_set {81	__le32 id;82	__le32 attributes;83};84 85/* Valid only from SCMI clock v2.1 */86struct scmi_msg_clock_config_set_v2 {87	__le32 id;88	__le32 attributes;89#define NULL_OEM_TYPE			090#define REGMASK_OEM_TYPE_SET		GENMASK(23, 16)91#define REGMASK_CLK_STATE		GENMASK(1, 0)92	__le32 oem_config_val;93};94 95struct scmi_msg_clock_config_get {96	__le32 id;97	__le32 flags;98#define REGMASK_OEM_TYPE_GET		GENMASK(7, 0)99};100 101struct scmi_msg_resp_clock_config_get {102	__le32 attributes;103	__le32 config;104#define IS_CLK_ENABLED(x)		le32_get_bits((x), BIT(0))105	__le32 oem_config_val;106};107 108struct scmi_msg_clock_describe_rates {109	__le32 id;110	__le32 rate_index;111};112 113struct scmi_msg_resp_clock_describe_rates {114	__le32 num_rates_flags;115#define NUM_RETURNED(x)		((x) & 0xfff)116#define RATE_DISCRETE(x)	!((x) & BIT(12))117#define NUM_REMAINING(x)	((x) >> 16)118	struct {119		__le32 value_low;120		__le32 value_high;121	} rate[];122#define RATE_TO_U64(X)		\123({				\124	typeof(X) x = (X);	\125	le32_to_cpu((x).value_low) | (u64)le32_to_cpu((x).value_high) << 32; \126})127};128 129struct scmi_clock_set_rate {130	__le32 flags;131#define CLOCK_SET_ASYNC		BIT(0)132#define CLOCK_SET_IGNORE_RESP	BIT(1)133#define CLOCK_SET_ROUND_UP	BIT(2)134#define CLOCK_SET_ROUND_AUTO	BIT(3)135	__le32 id;136	__le32 value_low;137	__le32 value_high;138};139 140struct scmi_msg_resp_set_rate_complete {141	__le32 id;142	__le32 rate_low;143	__le32 rate_high;144};145 146struct scmi_msg_clock_rate_notify {147	__le32 clk_id;148	__le32 notify_enable;149};150 151struct scmi_clock_rate_notify_payld {152	__le32 agent_id;153	__le32 clock_id;154	__le32 rate_low;155	__le32 rate_high;156};157 158struct clock_info {159	u32 version;160	int num_clocks;161	int max_async_req;162	bool notify_rate_changed_cmd;163	bool notify_rate_change_requested_cmd;164	atomic_t cur_async_req;165	struct scmi_clock_info *clk;166	int (*clock_config_set)(const struct scmi_protocol_handle *ph,167				u32 clk_id, enum clk_state state,168				enum scmi_clock_oem_config oem_type,169				u32 oem_val, bool atomic);170	int (*clock_config_get)(const struct scmi_protocol_handle *ph,171				u32 clk_id, enum scmi_clock_oem_config oem_type,172				u32 *attributes, bool *enabled, u32 *oem_val,173				bool atomic);174};175 176static enum scmi_clock_protocol_cmd evt_2_cmd[] = {177	CLOCK_RATE_NOTIFY,178	CLOCK_RATE_CHANGE_REQUESTED_NOTIFY,179};180 181static inline struct scmi_clock_info *182scmi_clock_domain_lookup(struct clock_info *ci, u32 clk_id)183{184	if (clk_id >= ci->num_clocks)185		return ERR_PTR(-EINVAL);186 187	return ci->clk + clk_id;188}189 190static int191scmi_clock_protocol_attributes_get(const struct scmi_protocol_handle *ph,192				   struct clock_info *ci)193{194	int ret;195	struct scmi_xfer *t;196	struct scmi_msg_resp_clock_protocol_attributes *attr;197 198	ret = ph->xops->xfer_get_init(ph, PROTOCOL_ATTRIBUTES,199				      0, sizeof(*attr), &t);200	if (ret)201		return ret;202 203	attr = t->rx.buf;204 205	ret = ph->xops->do_xfer(ph, t);206	if (!ret) {207		ci->num_clocks = le16_to_cpu(attr->num_clocks);208		ci->max_async_req = attr->max_async_req;209	}210 211	ph->xops->xfer_put(ph, t);212 213	if (!ret) {214		if (!ph->hops->protocol_msg_check(ph, CLOCK_RATE_NOTIFY, NULL))215			ci->notify_rate_changed_cmd = true;216 217		if (!ph->hops->protocol_msg_check(ph,218						  CLOCK_RATE_CHANGE_REQUESTED_NOTIFY,219						  NULL))220			ci->notify_rate_change_requested_cmd = true;221	}222 223	return ret;224}225 226struct scmi_clk_ipriv {227	struct device *dev;228	u32 clk_id;229	struct scmi_clock_info *clk;230};231 232static void iter_clk_possible_parents_prepare_message(void *message, unsigned int desc_index,233						      const void *priv)234{235	struct scmi_msg_clock_possible_parents *msg = message;236	const struct scmi_clk_ipriv *p = priv;237 238	msg->id = cpu_to_le32(p->clk_id);239	/* Set the number of OPPs to be skipped/already read */240	msg->skip_parents = cpu_to_le32(desc_index);241}242 243static int iter_clk_possible_parents_update_state(struct scmi_iterator_state *st,244						  const void *response, void *priv)245{246	const struct scmi_msg_resp_clock_possible_parents *r = response;247	struct scmi_clk_ipriv *p = priv;248	struct device *dev = ((struct scmi_clk_ipriv *)p)->dev;249	u32 flags;250 251	flags = le32_to_cpu(r->num_parent_flags);252	st->num_returned = NUM_PARENTS_RETURNED(flags);253	st->num_remaining = NUM_PARENTS_REMAINING(flags);254 255	/*256	 * num parents is not declared previously anywhere so we257	 * assume it's returned+remaining on first call.258	 */259	if (!st->max_resources) {260		p->clk->num_parents = st->num_returned + st->num_remaining;261		p->clk->parents = devm_kcalloc(dev, p->clk->num_parents,262					       sizeof(*p->clk->parents),263					       GFP_KERNEL);264		if (!p->clk->parents) {265			p->clk->num_parents = 0;266			return -ENOMEM;267		}268		st->max_resources = st->num_returned + st->num_remaining;269	}270 271	return 0;272}273 274static int iter_clk_possible_parents_process_response(const struct scmi_protocol_handle *ph,275						      const void *response,276						      struct scmi_iterator_state *st,277						      void *priv)278{279	const struct scmi_msg_resp_clock_possible_parents *r = response;280	struct scmi_clk_ipriv *p = priv;281 282	u32 *parent = &p->clk->parents[st->desc_index + st->loop_idx];283 284	*parent = le32_to_cpu(r->possible_parents[st->loop_idx]);285 286	return 0;287}288 289static int scmi_clock_possible_parents(const struct scmi_protocol_handle *ph, u32 clk_id,290				       struct scmi_clock_info *clk)291{292	struct scmi_iterator_ops ops = {293		.prepare_message = iter_clk_possible_parents_prepare_message,294		.update_state = iter_clk_possible_parents_update_state,295		.process_response = iter_clk_possible_parents_process_response,296	};297 298	struct scmi_clk_ipriv ppriv = {299		.clk_id = clk_id,300		.clk = clk,301		.dev = ph->dev,302	};303	void *iter;304	int ret;305 306	iter = ph->hops->iter_response_init(ph, &ops, 0,307					    CLOCK_POSSIBLE_PARENTS_GET,308					    sizeof(struct scmi_msg_clock_possible_parents),309					    &ppriv);310	if (IS_ERR(iter))311		return PTR_ERR(iter);312 313	ret = ph->hops->iter_response_run(iter);314 315	return ret;316}317 318static int319scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,320			   struct scmi_clock_info *clk)321{322	struct scmi_xfer *t;323	u32 perm;324	int ret;325 326	ret = ph->xops->xfer_get_init(ph, CLOCK_GET_PERMISSIONS,327				      sizeof(clk_id), sizeof(perm), &t);328	if (ret)329		return ret;330 331	put_unaligned_le32(clk_id, t->tx.buf);332 333	ret = ph->xops->do_xfer(ph, t);334	if (!ret) {335		perm = get_unaligned_le32(t->rx.buf);336 337		clk->state_ctrl_forbidden = !(perm & CLOCK_STATE_CONTROL_ALLOWED);338		clk->rate_ctrl_forbidden = !(perm & CLOCK_RATE_CONTROL_ALLOWED);339		clk->parent_ctrl_forbidden = !(perm & CLOCK_PARENT_CONTROL_ALLOWED);340	}341 342	ph->xops->xfer_put(ph, t);343 344	return ret;345}346 347static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,348				     u32 clk_id, struct clock_info *cinfo,349				     u32 version)350{351	int ret;352	u32 attributes;353	struct scmi_xfer *t;354	struct scmi_msg_resp_clock_attributes *attr;355	struct scmi_clock_info *clk = cinfo->clk + clk_id;356 357	ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES,358				      sizeof(clk_id), sizeof(*attr), &t);359	if (ret)360		return ret;361 362	put_unaligned_le32(clk_id, t->tx.buf);363	attr = t->rx.buf;364 365	ret = ph->xops->do_xfer(ph, t);366	if (!ret) {367		u32 latency = 0;368 369		attributes = le32_to_cpu(attr->attributes);370		strscpy(clk->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);371		/* clock_enable_latency field is present only since SCMI v3.1 */372		if (PROTOCOL_REV_MAJOR(version) >= 0x2)373			latency = le32_to_cpu(attr->clock_enable_latency);374		clk->enable_latency = latency ? : U32_MAX;375	}376 377	ph->xops->xfer_put(ph, t);378 379	/*380	 * If supported overwrite short name with the extended one;381	 * on error just carry on and use already provided short name.382	 */383	if (!ret && PROTOCOL_REV_MAJOR(version) >= 0x2) {384		if (SUPPORTS_EXTENDED_NAMES(attributes))385			ph->hops->extended_name_get(ph, CLOCK_NAME_GET, clk_id,386						    NULL, clk->name,387						    SCMI_MAX_STR_SIZE);388 389		if (cinfo->notify_rate_changed_cmd &&390		    SUPPORTS_RATE_CHANGED_NOTIF(attributes))391			clk->rate_changed_notifications = true;392		if (cinfo->notify_rate_change_requested_cmd &&393		    SUPPORTS_RATE_CHANGE_REQUESTED_NOTIF(attributes))394			clk->rate_change_requested_notifications = true;395		if (PROTOCOL_REV_MAJOR(version) >= 0x3) {396			if (SUPPORTS_PARENT_CLOCK(attributes))397				scmi_clock_possible_parents(ph, clk_id, clk);398			if (SUPPORTS_GET_PERMISSIONS(attributes))399				scmi_clock_get_permissions(ph, clk_id, clk);400			if (SUPPORTS_EXTENDED_CONFIG(attributes))401				clk->extended_config = true;402		}403	}404 405	return ret;406}407 408static int rate_cmp_func(const void *_r1, const void *_r2)409{410	const u64 *r1 = _r1, *r2 = _r2;411 412	if (*r1 < *r2)413		return -1;414	else if (*r1 == *r2)415		return 0;416	else417		return 1;418}419 420static void iter_clk_describe_prepare_message(void *message,421					      const unsigned int desc_index,422					      const void *priv)423{424	struct scmi_msg_clock_describe_rates *msg = message;425	const struct scmi_clk_ipriv *p = priv;426 427	msg->id = cpu_to_le32(p->clk_id);428	/* Set the number of rates to be skipped/already read */429	msg->rate_index = cpu_to_le32(desc_index);430}431 432static int433iter_clk_describe_update_state(struct scmi_iterator_state *st,434			       const void *response, void *priv)435{436	u32 flags;437	struct scmi_clk_ipriv *p = priv;438	const struct scmi_msg_resp_clock_describe_rates *r = response;439 440	flags = le32_to_cpu(r->num_rates_flags);441	st->num_remaining = NUM_REMAINING(flags);442	st->num_returned = NUM_RETURNED(flags);443	p->clk->rate_discrete = RATE_DISCRETE(flags);444 445	/* Warn about out of spec replies ... */446	if (!p->clk->rate_discrete &&447	    (st->num_returned != 3 || st->num_remaining != 0)) {448		dev_warn(p->dev,449			 "Out-of-spec CLOCK_DESCRIBE_RATES reply for %s - returned:%d remaining:%d rx_len:%zd\n",450			 p->clk->name, st->num_returned, st->num_remaining,451			 st->rx_len);452 453		/*454		 * A known quirk: a triplet is returned but num_returned != 3455		 * Check for a safe payload size and fix.456		 */457		if (st->num_returned != 3 && st->num_remaining == 0 &&458		    st->rx_len == sizeof(*r) + sizeof(__le32) * 2 * 3) {459			st->num_returned = 3;460			st->num_remaining = 0;461		} else {462			dev_err(p->dev,463				"Cannot fix out-of-spec reply !\n");464			return -EPROTO;465		}466	}467 468	return 0;469}470 471static int472iter_clk_describe_process_response(const struct scmi_protocol_handle *ph,473				   const void *response,474				   struct scmi_iterator_state *st, void *priv)475{476	int ret = 0;477	struct scmi_clk_ipriv *p = priv;478	const struct scmi_msg_resp_clock_describe_rates *r = response;479 480	if (!p->clk->rate_discrete) {481		switch (st->desc_index + st->loop_idx) {482		case 0:483			p->clk->range.min_rate = RATE_TO_U64(r->rate[0]);484			break;485		case 1:486			p->clk->range.max_rate = RATE_TO_U64(r->rate[1]);487			break;488		case 2:489			p->clk->range.step_size = RATE_TO_U64(r->rate[2]);490			break;491		default:492			ret = -EINVAL;493			break;494		}495	} else {496		u64 *rate = &p->clk->list.rates[st->desc_index + st->loop_idx];497 498		*rate = RATE_TO_U64(r->rate[st->loop_idx]);499		p->clk->list.num_rates++;500	}501 502	return ret;503}504 505static int506scmi_clock_describe_rates_get(const struct scmi_protocol_handle *ph, u32 clk_id,507			      struct scmi_clock_info *clk)508{509	int ret;510	void *iter;511	struct scmi_iterator_ops ops = {512		.prepare_message = iter_clk_describe_prepare_message,513		.update_state = iter_clk_describe_update_state,514		.process_response = iter_clk_describe_process_response,515	};516	struct scmi_clk_ipriv cpriv = {517		.clk_id = clk_id,518		.clk = clk,519		.dev = ph->dev,520	};521 522	iter = ph->hops->iter_response_init(ph, &ops, SCMI_MAX_NUM_RATES,523					    CLOCK_DESCRIBE_RATES,524					    sizeof(struct scmi_msg_clock_describe_rates),525					    &cpriv);526	if (IS_ERR(iter))527		return PTR_ERR(iter);528 529	ret = ph->hops->iter_response_run(iter);530	if (ret)531		return ret;532 533	if (!clk->rate_discrete) {534		dev_dbg(ph->dev, "Min %llu Max %llu Step %llu Hz\n",535			clk->range.min_rate, clk->range.max_rate,536			clk->range.step_size);537	} else if (clk->list.num_rates) {538		sort(clk->list.rates, clk->list.num_rates,539		     sizeof(clk->list.rates[0]), rate_cmp_func, NULL);540	}541 542	return ret;543}544 545static int546scmi_clock_rate_get(const struct scmi_protocol_handle *ph,547		    u32 clk_id, u64 *value)548{549	int ret;550	struct scmi_xfer *t;551 552	ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_GET,553				      sizeof(__le32), sizeof(u64), &t);554	if (ret)555		return ret;556 557	put_unaligned_le32(clk_id, t->tx.buf);558 559	ret = ph->xops->do_xfer(ph, t);560	if (!ret)561		*value = get_unaligned_le64(t->rx.buf);562 563	ph->xops->xfer_put(ph, t);564	return ret;565}566 567static int scmi_clock_rate_set(const struct scmi_protocol_handle *ph,568			       u32 clk_id, u64 rate)569{570	int ret;571	u32 flags = 0;572	struct scmi_xfer *t;573	struct scmi_clock_set_rate *cfg;574	struct clock_info *ci = ph->get_priv(ph);575	struct scmi_clock_info *clk;576 577	clk = scmi_clock_domain_lookup(ci, clk_id);578	if (IS_ERR(clk))579		return PTR_ERR(clk);580 581	if (clk->rate_ctrl_forbidden)582		return -EACCES;583 584	ret = ph->xops->xfer_get_init(ph, CLOCK_RATE_SET, sizeof(*cfg), 0, &t);585	if (ret)586		return ret;587 588	if (ci->max_async_req &&589	    atomic_inc_return(&ci->cur_async_req) < ci->max_async_req)590		flags |= CLOCK_SET_ASYNC;591 592	cfg = t->tx.buf;593	cfg->flags = cpu_to_le32(flags);594	cfg->id = cpu_to_le32(clk_id);595	cfg->value_low = cpu_to_le32(rate & 0xffffffff);596	cfg->value_high = cpu_to_le32(rate >> 32);597 598	if (flags & CLOCK_SET_ASYNC) {599		ret = ph->xops->do_xfer_with_response(ph, t);600		if (!ret) {601			struct scmi_msg_resp_set_rate_complete *resp;602 603			resp = t->rx.buf;604			if (le32_to_cpu(resp->id) == clk_id)605				dev_dbg(ph->dev,606					"Clk ID %d set async to %llu\n", clk_id,607					get_unaligned_le64(&resp->rate_low));608			else609				ret = -EPROTO;610		}611	} else {612		ret = ph->xops->do_xfer(ph, t);613	}614 615	if (ci->max_async_req)616		atomic_dec(&ci->cur_async_req);617 618	ph->xops->xfer_put(ph, t);619	return ret;620}621 622static int623scmi_clock_config_set(const struct scmi_protocol_handle *ph, u32 clk_id,624		      enum clk_state state,625		      enum scmi_clock_oem_config __unused0, u32 __unused1,626		      bool atomic)627{628	int ret;629	struct scmi_xfer *t;630	struct scmi_msg_clock_config_set *cfg;631 632	if (state >= CLK_STATE_RESERVED)633		return -EINVAL;634 635	ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_SET,636				      sizeof(*cfg), 0, &t);637	if (ret)638		return ret;639 640	t->hdr.poll_completion = atomic;641 642	cfg = t->tx.buf;643	cfg->id = cpu_to_le32(clk_id);644	cfg->attributes = cpu_to_le32(state);645 646	ret = ph->xops->do_xfer(ph, t);647 648	ph->xops->xfer_put(ph, t);649	return ret;650}651 652static int653scmi_clock_set_parent(const struct scmi_protocol_handle *ph, u32 clk_id,654		      u32 parent_id)655{656	int ret;657	struct scmi_xfer *t;658	struct scmi_msg_clock_set_parent *cfg;659	struct clock_info *ci = ph->get_priv(ph);660	struct scmi_clock_info *clk;661 662	clk = scmi_clock_domain_lookup(ci, clk_id);663	if (IS_ERR(clk))664		return PTR_ERR(clk);665 666	if (parent_id >= clk->num_parents)667		return -EINVAL;668 669	if (clk->parent_ctrl_forbidden)670		return -EACCES;671 672	ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_SET,673				      sizeof(*cfg), 0, &t);674	if (ret)675		return ret;676 677	t->hdr.poll_completion = false;678 679	cfg = t->tx.buf;680	cfg->id = cpu_to_le32(clk_id);681	cfg->parent_id = cpu_to_le32(clk->parents[parent_id]);682 683	ret = ph->xops->do_xfer(ph, t);684 685	ph->xops->xfer_put(ph, t);686 687	return ret;688}689 690static int691scmi_clock_get_parent(const struct scmi_protocol_handle *ph, u32 clk_id,692		      u32 *parent_id)693{694	int ret;695	struct scmi_xfer *t;696 697	ret = ph->xops->xfer_get_init(ph, CLOCK_PARENT_GET,698				      sizeof(__le32), sizeof(u32), &t);699	if (ret)700		return ret;701 702	put_unaligned_le32(clk_id, t->tx.buf);703 704	ret = ph->xops->do_xfer(ph, t);705	if (!ret)706		*parent_id = get_unaligned_le32(t->rx.buf);707 708	ph->xops->xfer_put(ph, t);709	return ret;710}711 712/* For SCMI clock v3.0 and onwards */713static int714scmi_clock_config_set_v2(const struct scmi_protocol_handle *ph, u32 clk_id,715			 enum clk_state state,716			 enum scmi_clock_oem_config oem_type, u32 oem_val,717			 bool atomic)718{719	int ret;720	u32 attrs;721	struct scmi_xfer *t;722	struct scmi_msg_clock_config_set_v2 *cfg;723 724	if (state == CLK_STATE_RESERVED ||725	    (!oem_type && state == CLK_STATE_UNCHANGED))726		return -EINVAL;727 728	ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_SET,729				      sizeof(*cfg), 0, &t);730	if (ret)731		return ret;732 733	t->hdr.poll_completion = atomic;734 735	attrs = FIELD_PREP(REGMASK_OEM_TYPE_SET, oem_type) |736		 FIELD_PREP(REGMASK_CLK_STATE, state);737 738	cfg = t->tx.buf;739	cfg->id = cpu_to_le32(clk_id);740	cfg->attributes = cpu_to_le32(attrs);741	/* Clear in any case */742	cfg->oem_config_val = cpu_to_le32(0);743	if (oem_type)744		cfg->oem_config_val = cpu_to_le32(oem_val);745 746	ret = ph->xops->do_xfer(ph, t);747 748	ph->xops->xfer_put(ph, t);749	return ret;750}751 752static int scmi_clock_enable(const struct scmi_protocol_handle *ph, u32 clk_id,753			     bool atomic)754{755	struct clock_info *ci = ph->get_priv(ph);756	struct scmi_clock_info *clk;757 758	clk = scmi_clock_domain_lookup(ci, clk_id);759	if (IS_ERR(clk))760		return PTR_ERR(clk);761 762	if (clk->state_ctrl_forbidden)763		return -EACCES;764 765	return ci->clock_config_set(ph, clk_id, CLK_STATE_ENABLE,766				    NULL_OEM_TYPE, 0, atomic);767}768 769static int scmi_clock_disable(const struct scmi_protocol_handle *ph, u32 clk_id,770			      bool atomic)771{772	struct clock_info *ci = ph->get_priv(ph);773	struct scmi_clock_info *clk;774 775	clk = scmi_clock_domain_lookup(ci, clk_id);776	if (IS_ERR(clk))777		return PTR_ERR(clk);778 779	if (clk->state_ctrl_forbidden)780		return -EACCES;781 782	return ci->clock_config_set(ph, clk_id, CLK_STATE_DISABLE,783				    NULL_OEM_TYPE, 0, atomic);784}785 786/* For SCMI clock v3.0 and onwards */787static int788scmi_clock_config_get_v2(const struct scmi_protocol_handle *ph, u32 clk_id,789			 enum scmi_clock_oem_config oem_type, u32 *attributes,790			 bool *enabled, u32 *oem_val, bool atomic)791{792	int ret;793	u32 flags;794	struct scmi_xfer *t;795	struct scmi_msg_clock_config_get *cfg;796 797	ret = ph->xops->xfer_get_init(ph, CLOCK_CONFIG_GET,798				      sizeof(*cfg), 0, &t);799	if (ret)800		return ret;801 802	t->hdr.poll_completion = atomic;803 804	flags = FIELD_PREP(REGMASK_OEM_TYPE_GET, oem_type);805 806	cfg = t->tx.buf;807	cfg->id = cpu_to_le32(clk_id);808	cfg->flags = cpu_to_le32(flags);809 810	ret = ph->xops->do_xfer(ph, t);811	if (!ret) {812		struct scmi_msg_resp_clock_config_get *resp = t->rx.buf;813 814		if (attributes)815			*attributes = le32_to_cpu(resp->attributes);816 817		if (enabled)818			*enabled = IS_CLK_ENABLED(resp->config);819 820		if (oem_val && oem_type)821			*oem_val = le32_to_cpu(resp->oem_config_val);822	}823 824	ph->xops->xfer_put(ph, t);825 826	return ret;827}828 829static int830scmi_clock_config_get(const struct scmi_protocol_handle *ph, u32 clk_id,831		      enum scmi_clock_oem_config oem_type, u32 *attributes,832		      bool *enabled, u32 *oem_val, bool atomic)833{834	int ret;835	struct scmi_xfer *t;836	struct scmi_msg_resp_clock_attributes *resp;837 838	if (!enabled)839		return -EINVAL;840 841	ret = ph->xops->xfer_get_init(ph, CLOCK_ATTRIBUTES,842				      sizeof(clk_id), sizeof(*resp), &t);843	if (ret)844		return ret;845 846	t->hdr.poll_completion = atomic;847	put_unaligned_le32(clk_id, t->tx.buf);848	resp = t->rx.buf;849 850	ret = ph->xops->do_xfer(ph, t);851	if (!ret)852		*enabled = IS_CLK_ENABLED(resp->attributes);853 854	ph->xops->xfer_put(ph, t);855 856	return ret;857}858 859static int scmi_clock_state_get(const struct scmi_protocol_handle *ph,860				u32 clk_id, bool *enabled, bool atomic)861{862	struct clock_info *ci = ph->get_priv(ph);863 864	return ci->clock_config_get(ph, clk_id, NULL_OEM_TYPE, NULL,865				    enabled, NULL, atomic);866}867 868static int scmi_clock_config_oem_set(const struct scmi_protocol_handle *ph,869				     u32 clk_id,870				     enum scmi_clock_oem_config oem_type,871				     u32 oem_val, bool atomic)872{873	struct clock_info *ci = ph->get_priv(ph);874	struct scmi_clock_info *clk;875 876	clk = scmi_clock_domain_lookup(ci, clk_id);877	if (IS_ERR(clk))878		return PTR_ERR(clk);879 880	if (!clk->extended_config)881		return -EOPNOTSUPP;882 883	return ci->clock_config_set(ph, clk_id, CLK_STATE_UNCHANGED,884				    oem_type, oem_val, atomic);885}886 887static int scmi_clock_config_oem_get(const struct scmi_protocol_handle *ph,888				     u32 clk_id,889				     enum scmi_clock_oem_config oem_type,890				     u32 *oem_val, u32 *attributes, bool atomic)891{892	struct clock_info *ci = ph->get_priv(ph);893	struct scmi_clock_info *clk;894 895	clk = scmi_clock_domain_lookup(ci, clk_id);896	if (IS_ERR(clk))897		return PTR_ERR(clk);898 899	if (!clk->extended_config)900		return -EOPNOTSUPP;901 902	return ci->clock_config_get(ph, clk_id, oem_type, attributes,903				    NULL, oem_val, atomic);904}905 906static int scmi_clock_count_get(const struct scmi_protocol_handle *ph)907{908	struct clock_info *ci = ph->get_priv(ph);909 910	return ci->num_clocks;911}912 913static const struct scmi_clock_info *914scmi_clock_info_get(const struct scmi_protocol_handle *ph, u32 clk_id)915{916	struct scmi_clock_info *clk;917	struct clock_info *ci = ph->get_priv(ph);918 919	clk = scmi_clock_domain_lookup(ci, clk_id);920	if (IS_ERR(clk))921		return NULL;922 923	if (!clk->name[0])924		return NULL;925 926	return clk;927}928 929static const struct scmi_clk_proto_ops clk_proto_ops = {930	.count_get = scmi_clock_count_get,931	.info_get = scmi_clock_info_get,932	.rate_get = scmi_clock_rate_get,933	.rate_set = scmi_clock_rate_set,934	.enable = scmi_clock_enable,935	.disable = scmi_clock_disable,936	.state_get = scmi_clock_state_get,937	.config_oem_get = scmi_clock_config_oem_get,938	.config_oem_set = scmi_clock_config_oem_set,939	.parent_set = scmi_clock_set_parent,940	.parent_get = scmi_clock_get_parent,941};942 943static bool scmi_clk_notify_supported(const struct scmi_protocol_handle *ph,944				      u8 evt_id, u32 src_id)945{946	bool supported;947	struct scmi_clock_info *clk;948	struct clock_info *ci = ph->get_priv(ph);949 950	if (evt_id >= ARRAY_SIZE(evt_2_cmd))951		return false;952 953	clk = scmi_clock_domain_lookup(ci, src_id);954	if (IS_ERR(clk))955		return false;956 957	if (evt_id == SCMI_EVENT_CLOCK_RATE_CHANGED)958		supported = clk->rate_changed_notifications;959	else960		supported = clk->rate_change_requested_notifications;961 962	return supported;963}964 965static int scmi_clk_rate_notify(const struct scmi_protocol_handle *ph,966				u32 clk_id, int message_id, bool enable)967{968	int ret;969	struct scmi_xfer *t;970	struct scmi_msg_clock_rate_notify *notify;971 972	ret = ph->xops->xfer_get_init(ph, message_id, sizeof(*notify), 0, &t);973	if (ret)974		return ret;975 976	notify = t->tx.buf;977	notify->clk_id = cpu_to_le32(clk_id);978	notify->notify_enable = enable ? cpu_to_le32(BIT(0)) : 0;979 980	ret = ph->xops->do_xfer(ph, t);981 982	ph->xops->xfer_put(ph, t);983	return ret;984}985 986static int scmi_clk_set_notify_enabled(const struct scmi_protocol_handle *ph,987				       u8 evt_id, u32 src_id, bool enable)988{989	int ret, cmd_id;990 991	if (evt_id >= ARRAY_SIZE(evt_2_cmd))992		return -EINVAL;993 994	cmd_id = evt_2_cmd[evt_id];995	ret = scmi_clk_rate_notify(ph, src_id, cmd_id, enable);996	if (ret)997		pr_debug("FAIL_ENABLED - evt[%X] dom[%d] - ret:%d\n",998			 evt_id, src_id, ret);999 1000	return ret;1001}1002 1003static void *scmi_clk_fill_custom_report(const struct scmi_protocol_handle *ph,1004					 u8 evt_id, ktime_t timestamp,1005					 const void *payld, size_t payld_sz,1006					 void *report, u32 *src_id)1007{1008	const struct scmi_clock_rate_notify_payld *p = payld;1009	struct scmi_clock_rate_notif_report *r = report;1010 1011	if (sizeof(*p) != payld_sz ||1012	    (evt_id != SCMI_EVENT_CLOCK_RATE_CHANGED &&1013	     evt_id != SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED))1014		return NULL;1015 1016	r->timestamp = timestamp;1017	r->agent_id = le32_to_cpu(p->agent_id);1018	r->clock_id = le32_to_cpu(p->clock_id);1019	r->rate = get_unaligned_le64(&p->rate_low);1020	*src_id = r->clock_id;1021 1022	return r;1023}1024 1025static int scmi_clk_get_num_sources(const struct scmi_protocol_handle *ph)1026{1027	struct clock_info *ci = ph->get_priv(ph);1028 1029	if (!ci)1030		return -EINVAL;1031 1032	return ci->num_clocks;1033}1034 1035static const struct scmi_event clk_events[] = {1036	{1037		.id = SCMI_EVENT_CLOCK_RATE_CHANGED,1038		.max_payld_sz = sizeof(struct scmi_clock_rate_notify_payld),1039		.max_report_sz = sizeof(struct scmi_clock_rate_notif_report),1040	},1041	{1042		.id = SCMI_EVENT_CLOCK_RATE_CHANGE_REQUESTED,1043		.max_payld_sz = sizeof(struct scmi_clock_rate_notify_payld),1044		.max_report_sz = sizeof(struct scmi_clock_rate_notif_report),1045	},1046};1047 1048static const struct scmi_event_ops clk_event_ops = {1049	.is_notify_supported = scmi_clk_notify_supported,1050	.get_num_sources = scmi_clk_get_num_sources,1051	.set_notify_enabled = scmi_clk_set_notify_enabled,1052	.fill_custom_report = scmi_clk_fill_custom_report,1053};1054 1055static const struct scmi_protocol_events clk_protocol_events = {1056	.queue_sz = SCMI_PROTO_QUEUE_SZ,1057	.ops = &clk_event_ops,1058	.evts = clk_events,1059	.num_events = ARRAY_SIZE(clk_events),1060};1061 1062static int scmi_clock_protocol_init(const struct scmi_protocol_handle *ph)1063{1064	u32 version;1065	int clkid, ret;1066	struct clock_info *cinfo;1067 1068	ret = ph->xops->version_get(ph, &version);1069	if (ret)1070		return ret;1071 1072	dev_dbg(ph->dev, "Clock Version %d.%d\n",1073		PROTOCOL_REV_MAJOR(version), PROTOCOL_REV_MINOR(version));1074 1075	cinfo = devm_kzalloc(ph->dev, sizeof(*cinfo), GFP_KERNEL);1076	if (!cinfo)1077		return -ENOMEM;1078 1079	ret = scmi_clock_protocol_attributes_get(ph, cinfo);1080	if (ret)1081		return ret;1082 1083	cinfo->clk = devm_kcalloc(ph->dev, cinfo->num_clocks,1084				  sizeof(*cinfo->clk), GFP_KERNEL);1085	if (!cinfo->clk)1086		return -ENOMEM;1087 1088	for (clkid = 0; clkid < cinfo->num_clocks; clkid++) {1089		struct scmi_clock_info *clk = cinfo->clk + clkid;1090 1091		ret = scmi_clock_attributes_get(ph, clkid, cinfo, version);1092		if (!ret)1093			scmi_clock_describe_rates_get(ph, clkid, clk);1094	}1095 1096	if (PROTOCOL_REV_MAJOR(version) >= 0x3) {1097		cinfo->clock_config_set = scmi_clock_config_set_v2;1098		cinfo->clock_config_get = scmi_clock_config_get_v2;1099	} else {1100		cinfo->clock_config_set = scmi_clock_config_set;1101		cinfo->clock_config_get = scmi_clock_config_get;1102	}1103 1104	cinfo->version = version;1105	return ph->set_priv(ph, cinfo, version);1106}1107 1108static const struct scmi_protocol scmi_clock = {1109	.id = SCMI_PROTOCOL_CLOCK,1110	.owner = THIS_MODULE,1111	.instance_init = &scmi_clock_protocol_init,1112	.ops = &clk_proto_ops,1113	.events = &clk_protocol_events,1114	.supported_version = SCMI_PROTOCOL_SUPPORTED_VERSION,1115};1116 1117DEFINE_SCMI_PROTOCOL_REGISTER_UNREGISTER(clock, scmi_clock)1118