1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Copyright (C) 2023 Intel Corporation. All rights reserved.
4 * Intel Visual Sensing Controller ACE Linux driver
5 */
6
7/*
8 * To set ownership of camera sensor, there is specific command, which
9 * is sent via MEI protocol. That's a two-step scheme where the firmware
10 * first acks receipt of the command and later responses the command was
11 * executed. The command sending function uses "completion" as the
12 * synchronization mechanism. The notification for command is received
13 * via a mei callback which wakes up the caller. There can be only one
14 * outstanding command at a time.
15 *
16 * The power line of camera sensor is directly connected to IVSC instead
17 * of host, when camera sensor ownership is switched to host, sensor is
18 * already powered up by firmware.
19 */
20
21#include <linux/acpi.h>
22#include <linux/completion.h>
23#include <linux/delay.h>
24#include <linux/kernel.h>
25#include <linux/mei_cl_bus.h>
26#include <linux/module.h>
27#include <linux/mutex.h>
28#include <linux/pm_runtime.h>
29#include <linux/slab.h>
30#include <linux/uuid.h>
31#include <linux/workqueue.h>
32
33#define	MEI_ACE_DRIVER_NAME	"ivsc_ace"
34
35/* indicating driver message */
36#define	ACE_DRV_MSG		1
37/* indicating set command */
38#define	ACE_CMD_SET		4
39/* command timeout determined experimentally */
40#define	ACE_CMD_TIMEOUT		(5 * HZ)
41/* indicating the first command block */
42#define	ACE_CMD_INIT_BLOCK	1
43/* indicating the last command block */
44#define	ACE_CMD_FINAL_BLOCK	1
45/* size of camera status notification content */
46#define	ACE_CAMERA_STATUS_SIZE	5
47
48/* UUID used to get firmware id */
49#define ACE_GET_FW_ID_UUID UUID_LE(0x6167DCFB, 0x72F1, 0x4584, 0xBF, \
50				   0xE3, 0x84, 0x17, 0x71, 0xAA, 0x79, 0x0B)
51
52/* UUID used to get csi device */
53#define MEI_CSI_UUID UUID_LE(0x92335FCF, 0x3203, 0x4472, \
54			     0xAF, 0x93, 0x7b, 0x44, 0x53, 0xAC, 0x29, 0xDA)
55
56/* identify firmware event type */
57enum ace_event_type {
58	/* firmware ready */
59	ACE_FW_READY = 0x8,
60
61	/* command response */
62	ACE_CMD_RESPONSE = 0x10,
63};
64
65/* identify camera sensor ownership */
66enum ace_camera_owner {
67	ACE_CAMERA_IVSC,
68	ACE_CAMERA_HOST,
69};
70
71/* identify the command id supported by firmware IPC */
72enum ace_cmd_id {
73	/* used to switch camera sensor to host */
74	ACE_SWITCH_CAMERA_TO_HOST = 0x13,
75
76	/* used to switch camera sensor to IVSC */
77	ACE_SWITCH_CAMERA_TO_IVSC = 0x14,
78
79	/* used to get firmware id */
80	ACE_GET_FW_ID = 0x1A,
81};
82
83/* ACE command header structure */
84struct ace_cmd_hdr {
85	u32 firmware_id : 16;
86	u32 instance_id : 8;
87	u32 type : 5;
88	u32 rsp : 1;
89	u32 msg_tgt : 1;
90	u32 _hw_rsvd_1 : 1;
91	u32 param_size : 20;
92	u32 cmd_id : 8;
93	u32 final_block : 1;
94	u32 init_block : 1;
95	u32 _hw_rsvd_2 : 2;
96} __packed;
97
98/* ACE command parameter structure */
99union ace_cmd_param {
100	uuid_le uuid;
101	u32 param;
102};
103
104/* ACE command structure */
105struct ace_cmd {
106	struct ace_cmd_hdr hdr;
107	union ace_cmd_param param;
108} __packed;
109
110/* ACE notification header */
111union ace_notif_hdr {
112	struct _confirm {
113		u32 status : 24;
114		u32 type : 5;
115		u32 rsp : 1;
116		u32 msg_tgt : 1;
117		u32 _hw_rsvd_1 : 1;
118		u32 param_size : 20;
119		u32 cmd_id : 8;
120		u32 final_block : 1;
121		u32 init_block : 1;
122		u32 _hw_rsvd_2 : 2;
123	} __packed ack;
124
125	struct _event {
126		u32 rsvd1 : 16;
127		u32 event_type : 8;
128		u32 type : 5;
129		u32 ack : 1;
130		u32 msg_tgt : 1;
131		u32 _hw_rsvd_1 : 1;
132		u32 rsvd2 : 30;
133		u32 _hw_rsvd_2 : 2;
134	} __packed event;
135
136	struct _response {
137		u32 event_id : 16;
138		u32 notif_type : 8;
139		u32 type : 5;
140		u32 rsp : 1;
141		u32 msg_tgt : 1;
142		u32 _hw_rsvd_1 : 1;
143		u32 event_data_size : 16;
144		u32 request_target : 1;
145		u32 request_type : 5;
146		u32 cmd_id : 8;
147		u32 _hw_rsvd_2 : 2;
148	} __packed response;
149};
150
151/* ACE notification content */
152union ace_notif_cont {
153	u16 firmware_id;
154	u8 state_notif;
155	u8 camera_status[ACE_CAMERA_STATUS_SIZE];
156};
157
158/* ACE notification structure */
159struct ace_notif {
160	union ace_notif_hdr hdr;
161	union ace_notif_cont cont;
162} __packed;
163
164struct mei_ace {
165	struct mei_cl_device *cldev;
166
167	/* command ack */
168	struct ace_notif cmd_ack;
169	/* command response */
170	struct ace_notif cmd_response;
171	/* used to wait for command ack and response */
172	struct completion cmd_completion;
173	/* lock used to prevent multiple call to send command */
174	struct mutex lock;
175
176	/* used to construct command */
177	u16 firmware_id;
178
179	struct device *csi_dev;
180
181	/* runtime PM link from ace to csi */
182	struct device_link *csi_link;
183
184	struct work_struct work;
185};
186
187static inline void init_cmd_hdr(struct ace_cmd_hdr *hdr)
188{
189	memset(hdr, 0, sizeof(struct ace_cmd_hdr));
190
191	hdr->type = ACE_CMD_SET;
192	hdr->msg_tgt = ACE_DRV_MSG;
193	hdr->init_block = ACE_CMD_INIT_BLOCK;
194	hdr->final_block = ACE_CMD_FINAL_BLOCK;
195}
196
197static int construct_command(struct mei_ace *ace, struct ace_cmd *cmd,
198			     enum ace_cmd_id cmd_id)
199{
200	union ace_cmd_param *param = &cmd->param;
201	struct ace_cmd_hdr *hdr = &cmd->hdr;
202
203	init_cmd_hdr(hdr);
204
205	hdr->cmd_id = cmd_id;
206	switch (cmd_id) {
207	case ACE_GET_FW_ID:
208		param->uuid = ACE_GET_FW_ID_UUID;
209		hdr->param_size = sizeof(param->uuid);
210		break;
211	case ACE_SWITCH_CAMERA_TO_IVSC:
212		param->param = 0;
213		hdr->firmware_id = ace->firmware_id;
214		hdr->param_size = sizeof(param->param);
215		break;
216	case ACE_SWITCH_CAMERA_TO_HOST:
217		hdr->firmware_id = ace->firmware_id;
218		break;
219	default:
220		return -EINVAL;
221	}
222
223	return hdr->param_size + sizeof(cmd->hdr);
224}
225
226/* send command to firmware */
227static int mei_ace_send(struct mei_ace *ace, struct ace_cmd *cmd,
228			size_t len, bool only_ack)
229{
230	union ace_notif_hdr *resp_hdr = &ace->cmd_response.hdr;
231	union ace_notif_hdr *ack_hdr = &ace->cmd_ack.hdr;
232	struct ace_cmd_hdr *cmd_hdr = &cmd->hdr;
233	int ret;
234
235	mutex_lock(&ace->lock);
236
237	reinit_completion(&ace->cmd_completion);
238
239	ret = mei_cldev_send(ace->cldev, (u8 *)cmd, len);
240	if (ret < 0)
241		goto out;
242
243	ret = wait_for_completion_killable_timeout(&ace->cmd_completion,
244						   ACE_CMD_TIMEOUT);
245	if (ret < 0) {
246		goto out;
247	} else if (!ret) {
248		ret = -ETIMEDOUT;
249		goto out;
250	}
251
252	if (ack_hdr->ack.cmd_id != cmd_hdr->cmd_id) {
253		ret = -EINVAL;
254		goto out;
255	}
256
257	/* command ack status */
258	ret = ack_hdr->ack.status;
259	if (ret) {
260		ret = -EIO;
261		goto out;
262	}
263
264	if (only_ack)
265		goto out;
266
267	ret = wait_for_completion_killable_timeout(&ace->cmd_completion,
268						   ACE_CMD_TIMEOUT);
269	if (ret < 0) {
270		goto out;
271	} else if (!ret) {
272		ret = -ETIMEDOUT;
273		goto out;
274	} else {
275		ret = 0;
276	}
277
278	if (resp_hdr->response.cmd_id != cmd_hdr->cmd_id)
279		ret = -EINVAL;
280
281out:
282	mutex_unlock(&ace->lock);
283
284	return ret;
285}
286
287static int ace_set_camera_owner(struct mei_ace *ace,
288				enum ace_camera_owner owner)
289{
290	enum ace_cmd_id cmd_id;
291	struct ace_cmd cmd;
292	int cmd_size;
293	int ret;
294
295	if (owner == ACE_CAMERA_IVSC)
296		cmd_id = ACE_SWITCH_CAMERA_TO_IVSC;
297	else
298		cmd_id = ACE_SWITCH_CAMERA_TO_HOST;
299
300	cmd_size = construct_command(ace, &cmd, cmd_id);
301	if (cmd_size >= 0)
302		ret = mei_ace_send(ace, &cmd, cmd_size, false);
303	else
304		ret = cmd_size;
305
306	return ret;
307}
308
309/* the first command downloaded to firmware */
310static inline int ace_get_firmware_id(struct mei_ace *ace)
311{
312	struct ace_cmd cmd;
313	int cmd_size;
314	int ret;
315
316	cmd_size = construct_command(ace, &cmd, ACE_GET_FW_ID);
317	if (cmd_size >= 0)
318		ret = mei_ace_send(ace, &cmd, cmd_size, true);
319	else
320		ret = cmd_size;
321
322	return ret;
323}
324
325static void handle_command_response(struct mei_ace *ace,
326				    struct ace_notif *resp, int len)
327{
328	union ace_notif_hdr *hdr = &resp->hdr;
329
330	switch (hdr->response.cmd_id) {
331	case ACE_SWITCH_CAMERA_TO_IVSC:
332	case ACE_SWITCH_CAMERA_TO_HOST:
333		memcpy(&ace->cmd_response, resp, len);
334		complete(&ace->cmd_completion);
335		break;
336	case ACE_GET_FW_ID:
337		break;
338	default:
339		break;
340	}
341}
342
343static void handle_command_ack(struct mei_ace *ace,
344			       struct ace_notif *ack, int len)
345{
346	union ace_notif_hdr *hdr = &ack->hdr;
347
348	switch (hdr->ack.cmd_id) {
349	case ACE_GET_FW_ID:
350		ace->firmware_id = ack->cont.firmware_id;
351		fallthrough;
352	case ACE_SWITCH_CAMERA_TO_IVSC:
353	case ACE_SWITCH_CAMERA_TO_HOST:
354		memcpy(&ace->cmd_ack, ack, len);
355		complete(&ace->cmd_completion);
356		break;
357	default:
358		break;
359	}
360}
361
362/* callback for receive */
363static void mei_ace_rx(struct mei_cl_device *cldev)
364{
365	struct mei_ace *ace = mei_cldev_get_drvdata(cldev);
366	struct ace_notif event;
367	union ace_notif_hdr *hdr = &event.hdr;
368	int ret;
369
370	ret = mei_cldev_recv(cldev, (u8 *)&event, sizeof(event));
371	if (ret < 0) {
372		dev_err(&cldev->dev, "recv error: %d\n", ret);
373		return;
374	}
375
376	if (hdr->event.ack) {
377		handle_command_ack(ace, &event, ret);
378		return;
379	}
380
381	switch (hdr->event.event_type) {
382	case ACE_CMD_RESPONSE:
383		handle_command_response(ace, &event, ret);
384		break;
385	case ACE_FW_READY:
386		/*
387		 * firmware ready notification sent to driver
388		 * after HECI client connected with firmware.
389		 */
390		dev_dbg(&cldev->dev, "firmware ready\n");
391		break;
392	default:
393		break;
394	}
395}
396
397static int mei_ace_setup_dev_link(struct mei_ace *ace)
398{
399	struct device *dev = &ace->cldev->dev;
400	uuid_le uuid = MEI_CSI_UUID;
401	struct device *csi_dev;
402	char name[64];
403	int ret;
404
405	snprintf(name, sizeof(name), "%s-%pUl", dev_name(dev->parent), &uuid);
406
407	csi_dev = device_find_child_by_name(dev->parent, name);
408	if (!csi_dev) {
409		ret = -EPROBE_DEFER;
410		goto err;
411	}
412
413	/* setup link between mei_ace and mei_csi */
414	ace->csi_link = device_link_add(csi_dev, dev, DL_FLAG_PM_RUNTIME |
415					DL_FLAG_RPM_ACTIVE | DL_FLAG_STATELESS);
416	if (!ace->csi_link) {
417		ret = -EINVAL;
418		dev_err(dev, "failed to link to %s\n", dev_name(csi_dev));
419		goto err_put;
420	}
421
422	ace->csi_dev = csi_dev;
423
424	return 0;
425
426err_put:
427	put_device(csi_dev);
428
429err:
430	return ret;
431}
432
433/* switch camera to host before probe sensor device */
434static void mei_ace_post_probe_work(struct work_struct *work)
435{
436	struct acpi_device *adev;
437	struct mei_ace *ace;
438	struct device *dev;
439	int ret;
440
441	ace = container_of(work, struct mei_ace, work);
442	dev = &ace->cldev->dev;
443
444	ret = ace_set_camera_owner(ace, ACE_CAMERA_HOST);
445	if (ret) {
446		dev_err(dev, "switch camera to host failed: %d\n", ret);
447		return;
448	}
449
450	adev = ACPI_COMPANION(dev->parent);
451	if (!adev)
452		return;
453
454	acpi_dev_clear_dependencies(adev);
455}
456
457static int mei_ace_probe(struct mei_cl_device *cldev,
458			 const struct mei_cl_device_id *id)
459{
460	struct device *dev = &cldev->dev;
461	struct mei_ace *ace;
462	int ret;
463
464	ace = devm_kzalloc(dev, sizeof(struct mei_ace), GFP_KERNEL);
465	if (!ace)
466		return -ENOMEM;
467
468	ace->cldev = cldev;
469	mutex_init(&ace->lock);
470	init_completion(&ace->cmd_completion);
471	INIT_WORK(&ace->work, mei_ace_post_probe_work);
472
473	mei_cldev_set_drvdata(cldev, ace);
474
475	ret = mei_cldev_enable(cldev);
476	if (ret < 0) {
477		dev_err(dev, "mei_cldev_enable failed: %d\n", ret);
478		goto destroy_mutex;
479	}
480
481	ret = mei_cldev_register_rx_cb(cldev, mei_ace_rx);
482	if (ret) {
483		dev_err(dev, "event cb registration failed: %d\n", ret);
484		goto err_disable;
485	}
486
487	ret = ace_get_firmware_id(ace);
488	if (ret) {
489		dev_err(dev, "get firmware id failed: %d\n", ret);
490		goto err_disable;
491	}
492
493	pm_runtime_set_active(dev);
494	pm_runtime_enable(dev);
495
496	ret = mei_ace_setup_dev_link(ace);
497	if (ret)
498		goto disable_pm;
499
500	schedule_work(&ace->work);
501
502	return 0;
503
504disable_pm:
505	pm_runtime_disable(dev);
506	pm_runtime_set_suspended(dev);
507
508err_disable:
509	mei_cldev_disable(cldev);
510
511destroy_mutex:
512	mutex_destroy(&ace->lock);
513
514	return ret;
515}
516
517static void mei_ace_remove(struct mei_cl_device *cldev)
518{
519	struct mei_ace *ace = mei_cldev_get_drvdata(cldev);
520
521	cancel_work_sync(&ace->work);
522
523	device_link_del(ace->csi_link);
524	put_device(ace->csi_dev);
525
526	pm_runtime_disable(&cldev->dev);
527	pm_runtime_set_suspended(&cldev->dev);
528
529	ace_set_camera_owner(ace, ACE_CAMERA_IVSC);
530
531	mutex_destroy(&ace->lock);
532}
533
534static int __maybe_unused mei_ace_runtime_suspend(struct device *dev)
535{
536	struct mei_ace *ace = dev_get_drvdata(dev);
537
538	return ace_set_camera_owner(ace, ACE_CAMERA_IVSC);
539}
540
541static int __maybe_unused mei_ace_runtime_resume(struct device *dev)
542{
543	struct mei_ace *ace = dev_get_drvdata(dev);
544
545	return ace_set_camera_owner(ace, ACE_CAMERA_HOST);
546}
547
548static const struct dev_pm_ops mei_ace_pm_ops = {
549	SET_RUNTIME_PM_OPS(mei_ace_runtime_suspend,
550			   mei_ace_runtime_resume, NULL)
551};
552
553#define MEI_ACE_UUID UUID_LE(0x5DB76CF6, 0x0A68, 0x4ED6, \
554			     0x9B, 0x78, 0x03, 0x61, 0x63, 0x5E, 0x24, 0x47)
555
556static const struct mei_cl_device_id mei_ace_tbl[] = {
557	{ MEI_ACE_DRIVER_NAME, MEI_ACE_UUID, MEI_CL_VERSION_ANY },
558	{ /* sentinel */ }
559};
560MODULE_DEVICE_TABLE(mei, mei_ace_tbl);
561
562static struct mei_cl_driver mei_ace_driver = {
563	.id_table = mei_ace_tbl,
564	.name = MEI_ACE_DRIVER_NAME,
565
566	.probe = mei_ace_probe,
567	.remove = mei_ace_remove,
568
569	.driver = {
570		.pm = &mei_ace_pm_ops,
571	},
572};
573
574module_mei_cl_driver(mei_ace_driver);
575
576MODULE_AUTHOR("Wentong Wu <wentong.wu@intel.com>");
577MODULE_AUTHOR("Zhifeng Wang <zhifeng.wang@intel.com>");
578MODULE_DESCRIPTION("Device driver for IVSC ACE");
579MODULE_LICENSE("GPL");
580