File Index
Files and directories
Sign in
FILE

thead,th1520-aon.c

File preview with syntax highlighting.

linux-6.19.14/drivers/firmware/thead,th1520-aon.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/*
  3 * Copyright (C) 2021 Alibaba Group Holding Limited.
  4 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
  5 * Author: Michal Wilczynski <m.wilczynski@samsung.com>
  6 */
  7
  8#include <linux/device.h>
  9#include <linux/firmware/thead/thead,th1520-aon.h>
 10#include <linux/mailbox_client.h>
 11#include <linux/mailbox_controller.h>
 12#include <linux/slab.h>
 13
 14#define MAX_RX_TIMEOUT (msecs_to_jiffies(3000))
 15#define MAX_TX_TIMEOUT 500
 16
 17struct th1520_aon_chan {
 18	struct mbox_chan *ch;
 19	struct th1520_aon_rpc_ack_common ack_msg;
 20	struct mbox_client cl;
 21	struct completion done;
 22
 23	/* make sure only one RPC is performed at a time */
 24	struct mutex transaction_lock;
 25};
 26
 27struct th1520_aon_msg_req_set_resource_power_mode {
 28	struct th1520_aon_rpc_msg_hdr hdr;
 29	u16 resource;
 30	u16 mode;
 31	u16 reserved[10];
 32} __packed __aligned(1);
 33
 34/*
 35 * This type is used to indicate error response for most functions.
 36 */
 37enum th1520_aon_error_codes {
 38	LIGHT_AON_ERR_NONE = 0, /* Success */
 39	LIGHT_AON_ERR_VERSION = 1, /* Incompatible API version */
 40	LIGHT_AON_ERR_CONFIG = 2, /* Configuration error */
 41	LIGHT_AON_ERR_PARM = 3, /* Bad parameter */
 42	LIGHT_AON_ERR_NOACCESS = 4, /* Permission error (no access) */
 43	LIGHT_AON_ERR_LOCKED = 5, /* Permission error (locked) */
 44	LIGHT_AON_ERR_UNAVAILABLE = 6, /* Unavailable (out of resources) */
 45	LIGHT_AON_ERR_NOTFOUND = 7, /* Not found */
 46	LIGHT_AON_ERR_NOPOWER = 8, /* No power */
 47	LIGHT_AON_ERR_IPC = 9, /* Generic IPC error */
 48	LIGHT_AON_ERR_BUSY = 10, /* Resource is currently busy/active */
 49	LIGHT_AON_ERR_FAIL = 11, /* General I/O failure */
 50	LIGHT_AON_ERR_LAST
 51};
 52
 53static int th1520_aon_linux_errmap[LIGHT_AON_ERR_LAST] = {
 54	0, /* LIGHT_AON_ERR_NONE */
 55	-EINVAL, /* LIGHT_AON_ERR_VERSION */
 56	-EINVAL, /* LIGHT_AON_ERR_CONFIG */
 57	-EINVAL, /* LIGHT_AON_ERR_PARM */
 58	-EACCES, /* LIGHT_AON_ERR_NOACCESS */
 59	-EACCES, /* LIGHT_AON_ERR_LOCKED */
 60	-ERANGE, /* LIGHT_AON_ERR_UNAVAILABLE */
 61	-EEXIST, /* LIGHT_AON_ERR_NOTFOUND */
 62	-EPERM, /* LIGHT_AON_ERR_NOPOWER */
 63	-EPIPE, /* LIGHT_AON_ERR_IPC */
 64	-EBUSY, /* LIGHT_AON_ERR_BUSY */
 65	-EIO, /* LIGHT_AON_ERR_FAIL */
 66};
 67
 68static inline int th1520_aon_to_linux_errno(int errno)
 69{
 70	if (errno >= LIGHT_AON_ERR_NONE && errno < LIGHT_AON_ERR_LAST)
 71		return th1520_aon_linux_errmap[errno];
 72
 73	return -EIO;
 74}
 75
 76static void th1520_aon_rx_callback(struct mbox_client *c, void *rx_msg)
 77{
 78	struct th1520_aon_chan *aon_chan =
 79		container_of(c, struct th1520_aon_chan, cl);
 80	struct th1520_aon_rpc_msg_hdr *hdr =
 81		(struct th1520_aon_rpc_msg_hdr *)rx_msg;
 82	u8 recv_size = sizeof(struct th1520_aon_rpc_msg_hdr) + hdr->size;
 83
 84	if (recv_size != sizeof(struct th1520_aon_rpc_ack_common)) {
 85		dev_err(c->dev, "Invalid ack size, not completing\n");
 86		return;
 87	}
 88
 89	memcpy(&aon_chan->ack_msg, rx_msg, recv_size);
 90	complete(&aon_chan->done);
 91}
 92
 93/**
 94 * th1520_aon_call_rpc() - Send an RPC request to the TH1520 AON subsystem
 95 * @aon_chan: Pointer to the AON channel structure
 96 * @msg: Pointer to the message (RPC payload) that will be sent
 97 *
 98 * This function sends an RPC message to the TH1520 AON subsystem via mailbox.
 99 * It takes the provided @msg buffer, formats it with version and service flags,
100 * then blocks until the RPC completes or times out. The completion is signaled
101 * by the `aon_chan->done` completion, which is waited upon for a duration
102 * defined by `MAX_RX_TIMEOUT`.
103 *
104 * Return:
105 * * 0 on success
106 * * -ETIMEDOUT if the RPC call times out
107 * * A negative error code if the mailbox send fails or if AON responds with
108 *   a non-zero error code (converted via th1520_aon_to_linux_errno()).
109 */
110int th1520_aon_call_rpc(struct th1520_aon_chan *aon_chan, void *msg)
111{
112	struct th1520_aon_rpc_msg_hdr *hdr = msg;
113	int ret;
114
115	mutex_lock(&aon_chan->transaction_lock);
116	reinit_completion(&aon_chan->done);
117
118	RPC_SET_VER(hdr, TH1520_AON_RPC_VERSION);
119	RPC_SET_SVC_ID(hdr, hdr->svc);
120	RPC_SET_SVC_FLAG_MSG_TYPE(hdr, RPC_SVC_MSG_TYPE_DATA);
121	RPC_SET_SVC_FLAG_ACK_TYPE(hdr, RPC_SVC_MSG_NEED_ACK);
122
123	ret = mbox_send_message(aon_chan->ch, msg);
124	if (ret < 0) {
125		dev_err(aon_chan->cl.dev, "RPC send msg failed: %d\n", ret);
126		goto out;
127	}
128
129	if (!wait_for_completion_timeout(&aon_chan->done, MAX_RX_TIMEOUT)) {
130		dev_err(aon_chan->cl.dev, "RPC send msg timeout\n");
131		mutex_unlock(&aon_chan->transaction_lock);
132		return -ETIMEDOUT;
133	}
134
135	ret = aon_chan->ack_msg.err_code;
136
137out:
138	mutex_unlock(&aon_chan->transaction_lock);
139
140	return th1520_aon_to_linux_errno(ret);
141}
142EXPORT_SYMBOL_GPL(th1520_aon_call_rpc);
143
144/**
145 * th1520_aon_power_update() - Change power state of a resource via TH1520 AON
146 * @aon_chan: Pointer to the AON channel structure
147 * @rsrc: Resource ID whose power state needs to be updated
148 * @power_on: Boolean indicating whether the resource should be powered on (true)
149 *            or powered off (false)
150 *
151 * This function requests the TH1520 AON subsystem to set the power mode of the
152 * given resource (@rsrc) to either on or off. It constructs the message in
153 * `struct th1520_aon_msg_req_set_resource_power_mode` and then invokes
154 * th1520_aon_call_rpc() to make the request. If the AON call fails, an error
155 * message is logged along with the specific return code.
156 *
157 * Return:
158 * * 0 on success
159 * * A negative error code in case of failures (propagated from
160 *   th1520_aon_call_rpc()).
161 */
162int th1520_aon_power_update(struct th1520_aon_chan *aon_chan, u16 rsrc,
163			    bool power_on)
164{
165	struct th1520_aon_msg_req_set_resource_power_mode msg = {};
166	struct th1520_aon_rpc_msg_hdr *hdr = &msg.hdr;
167	int ret;
168
169	hdr->svc = TH1520_AON_RPC_SVC_PM;
170	hdr->func = TH1520_AON_PM_FUNC_SET_RESOURCE_POWER_MODE;
171	hdr->size = TH1520_AON_RPC_MSG_NUM;
172
173	msg.resource = cpu_to_be16(rsrc);
174	msg.mode = cpu_to_be16(power_on ? TH1520_AON_PM_PW_MODE_ON :
175					  TH1520_AON_PM_PW_MODE_OFF);
176
177	ret = th1520_aon_call_rpc(aon_chan, &msg);
178	if (ret)
179		dev_err(aon_chan->cl.dev, "failed to power %s resource %d ret %d\n",
180			power_on ? "up" : "off", rsrc, ret);
181
182	return ret;
183}
184EXPORT_SYMBOL_GPL(th1520_aon_power_update);
185
186/**
187 * th1520_aon_init() - Initialize TH1520 AON firmware protocol interface
188 * @dev: Device pointer for the AON subsystem
189 *
190 * This function initializes the TH1520 AON firmware protocol interface by:
191 * - Allocating and initializing the AON channel structure
192 * - Setting up the mailbox client
193 * - Requesting the AON mailbox channel
194 * - Initializing synchronization primitives
195 *
196 * Return:
197 * * Valid pointer to th1520_aon_chan structure on success
198 * * ERR_PTR(-ENOMEM) if memory allocation fails
199 * * ERR_PTR() with other negative error codes from mailbox operations
200 */
201struct th1520_aon_chan *th1520_aon_init(struct device *dev)
202{
203	struct th1520_aon_chan *aon_chan;
204	struct mbox_client *cl;
205	int ret;
206
207	aon_chan = kzalloc(sizeof(*aon_chan), GFP_KERNEL);
208	if (!aon_chan)
209		return ERR_PTR(-ENOMEM);
210
211	cl = &aon_chan->cl;
212	cl->dev = dev;
213	cl->tx_block = true;
214	cl->tx_tout = MAX_TX_TIMEOUT;
215	cl->rx_callback = th1520_aon_rx_callback;
216
217	aon_chan->ch = mbox_request_channel_byname(cl, "aon");
218	if (IS_ERR(aon_chan->ch)) {
219		dev_err(dev, "Failed to request aon mbox chan\n");
220		ret = PTR_ERR(aon_chan->ch);
221		kfree(aon_chan);
222		return ERR_PTR(ret);
223	}
224
225	mutex_init(&aon_chan->transaction_lock);
226	init_completion(&aon_chan->done);
227
228	return aon_chan;
229}
230EXPORT_SYMBOL_GPL(th1520_aon_init);
231
232/**
233 * th1520_aon_deinit() - Clean up TH1520 AON firmware protocol interface
234 * @aon_chan: Pointer to the AON channel structure to clean up
235 *
236 * This function cleans up resources allocated by th1520_aon_init():
237 * - Frees the mailbox channel
238 * - Frees the AON channel
239 */
240void th1520_aon_deinit(struct th1520_aon_chan *aon_chan)
241{
242	mbox_free_channel(aon_chan->ch);
243	kfree(aon_chan);
244}
245EXPORT_SYMBOL_GPL(th1520_aon_deinit);
246
247MODULE_AUTHOR("Michal Wilczynski <m.wilczynski@samsung.com>");
248MODULE_DESCRIPTION("T-HEAD TH1520 Always-On firmware protocol library");
249MODULE_LICENSE("GPL");
~/ Read-only file preview.