• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT)
2 /*
3  * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4  *
5  * author:
6  *	Alpha Lin, alpha.lin@rock-chips.com
7  *	Randy Li, randy.li@rock-chips.com
8  *	Ding Wei, leo.ding@rock-chips.com
9  *
10  */
11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
12 
13 #include <linux/completion.h>
14 #include <linux/delay.h>
15 #include <linux/module.h>
16 #include <linux/of_platform.h>
17 #include <linux/proc_fs.h>
18 #include <linux/seq_file.h>
19 #include <linux/slab.h>
20 #include <linux/nospec.h>
21 #include <linux/mfd/syscon.h>
22 
23 #include "mpp_debug.h"
24 #include "mpp_common.h"
25 #include "mpp_iommu.h"
26 
27 #define MPP_CLASS_NAME		"mpp_class"
28 #define MPP_SERVICE_NAME	"mpp_service"
29 
30 #define HAS_RKVDEC	IS_ENABLED(CONFIG_ROCKCHIP_MPP_RKVDEC)
31 #define HAS_RKVENC	IS_ENABLED(CONFIG_ROCKCHIP_MPP_RKVENC)
32 #define HAS_VDPU1	IS_ENABLED(CONFIG_ROCKCHIP_MPP_VDPU1)
33 #define HAS_VEPU1	IS_ENABLED(CONFIG_ROCKCHIP_MPP_VEPU1)
34 #define HAS_VDPU2	IS_ENABLED(CONFIG_ROCKCHIP_MPP_VDPU2)
35 #define HAS_VEPU2	IS_ENABLED(CONFIG_ROCKCHIP_MPP_VEPU2)
36 #define HAS_VEPU22	IS_ENABLED(CONFIG_ROCKCHIP_MPP_VEPU22)
37 #define HAS_IEP2	IS_ENABLED(CONFIG_ROCKCHIP_MPP_IEP2)
38 #define HAS_JPGDEC	IS_ENABLED(CONFIG_ROCKCHIP_MPP_JPGDEC)
39 #define HAS_RKVDEC2	IS_ENABLED(CONFIG_ROCKCHIP_MPP_RKVDEC2)
40 #define HAS_RKVENC2	IS_ENABLED(CONFIG_ROCKCHIP_MPP_RKVENC2)
41 #define HAS_AV1DEC	IS_ENABLED(CONFIG_ROCKCHIP_MPP_AV1DEC)
42 
43 #define MPP_REGISTER_DRIVER(srv, flag, X, x) {\
44 	if (flag)\
45 		mpp_add_driver(srv, MPP_DRIVER_##X, &rockchip_##x##_driver, "grf_"#x);\
46 	}
47 
48 unsigned int mpp_dev_debug;
49 module_param(mpp_dev_debug, uint, 0644);
50 MODULE_PARM_DESC(mpp_dev_debug, "bit switch for mpp debug information");
51 
52 static const char mpp_version[] = MPP_VERSION;
53 
mpp_init_grf(struct device_node * np,struct mpp_grf_info * grf_info,const char * grf_name)54 static int mpp_init_grf(struct device_node *np,
55 			struct mpp_grf_info *grf_info,
56 			const char *grf_name)
57 {
58 	int ret;
59 	int index;
60 	u32 grf_offset = 0;
61 	u32 grf_value = 0;
62 	struct regmap *grf;
63 
64 	grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
65 	if (IS_ERR_OR_NULL(grf))
66 		return -EINVAL;
67 
68 	ret = of_property_read_u32(np, "rockchip,grf-offset", &grf_offset);
69 	if (ret)
70 		return -ENODATA;
71 
72 	index = of_property_match_string(np, "rockchip,grf-names", grf_name);
73 	if (index < 0)
74 		return -ENODATA;
75 
76 	ret = of_property_read_u32_index(np, "rockchip,grf-values",
77 					 index, &grf_value);
78 	if (ret)
79 		return -ENODATA;
80 
81 	grf_info->grf = grf;
82 	grf_info->offset = grf_offset;
83 	grf_info->val = grf_value;
84 
85 	mpp_set_grf(grf_info);
86 
87 	return 0;
88 }
89 
mpp_add_driver(struct mpp_service * srv,enum MPP_DRIVER_TYPE type,struct platform_driver * driver,const char * grf_name)90 static int mpp_add_driver(struct mpp_service *srv,
91 			  enum MPP_DRIVER_TYPE type,
92 			  struct platform_driver *driver,
93 			  const char *grf_name)
94 {
95 	int ret;
96 
97 	mpp_init_grf(srv->dev->of_node,
98 		     &srv->grf_infos[type],
99 		     grf_name);
100 
101 	if (type == MPP_DRIVER_AV1DEC)
102 		ret = av1dec_driver_register(driver);
103 	else
104 		ret = platform_driver_register(driver);
105 	if (ret)
106 		return ret;
107 
108 	srv->sub_drivers[type] = driver;
109 
110 	return 0;
111 }
112 
mpp_remove_driver(struct mpp_service * srv,int i)113 static int mpp_remove_driver(struct mpp_service *srv, int i)
114 {
115 	if (srv && srv->sub_drivers[i]) {
116 		mpp_set_grf(&srv->grf_infos[i]);
117 		platform_driver_unregister(srv->sub_drivers[i]);
118 		srv->sub_drivers[i] = NULL;
119 	}
120 
121 	return 0;
122 }
123 
mpp_register_service(struct mpp_service * srv,const char * service_name)124 static int mpp_register_service(struct mpp_service *srv,
125 				const char *service_name)
126 {
127 	int ret;
128 	struct device *dev = srv->dev;
129 
130 	/* create a device */
131 	ret = alloc_chrdev_region(&srv->dev_id, 0, 1, service_name);
132 	if (ret) {
133 		dev_err(dev, "alloc dev_t failed\n");
134 		return ret;
135 	}
136 
137 	cdev_init(&srv->mpp_cdev, &rockchip_mpp_fops);
138 	srv->mpp_cdev.owner = THIS_MODULE;
139 	srv->mpp_cdev.ops = &rockchip_mpp_fops;
140 
141 	ret = cdev_add(&srv->mpp_cdev, srv->dev_id, 1);
142 	if (ret) {
143 		unregister_chrdev_region(srv->dev_id, 1);
144 		dev_err(dev, "add device failed\n");
145 		return ret;
146 	}
147 
148 	srv->child_dev = device_create(srv->cls, dev, srv->dev_id,
149 				       NULL, "%s", service_name);
150 
151 	return 0;
152 }
153 
mpp_remove_service(struct mpp_service * srv)154 static int mpp_remove_service(struct mpp_service *srv)
155 {
156 	device_destroy(srv->cls, srv->dev_id);
157 	cdev_del(&srv->mpp_cdev);
158 	unregister_chrdev_region(srv->dev_id, 1);
159 
160 	return 0;
161 }
162 
163 #ifdef CONFIG_ROCKCHIP_MPP_PROC_FS
mpp_procfs_remove(struct mpp_service * srv)164 static int mpp_procfs_remove(struct mpp_service *srv)
165 {
166 	if (srv->procfs) {
167 		proc_remove(srv->procfs);
168 		srv->procfs = NULL;
169 	}
170 
171 	return 0;
172 }
173 
mpp_show_version(struct seq_file * seq,void * offset)174 static int mpp_show_version(struct seq_file *seq, void *offset)
175 {
176 	seq_printf(seq, "%s\n", mpp_version);
177 
178 	return 0;
179 }
180 
mpp_show_session_summary(struct seq_file * seq,void * offset)181 static int mpp_show_session_summary(struct seq_file *seq, void *offset)
182 {
183 	struct mpp_session *session = NULL, *n;
184 	struct mpp_service *srv = seq->private;
185 
186 	mutex_lock(&srv->session_lock);
187 	list_for_each_entry_safe(session, n,
188 				 &srv->session_list,
189 				 service_link) {
190 		struct  mpp_dev *mpp;
191 
192 		if (!session->priv)
193 			continue;
194 
195 		if (!session->mpp)
196 			continue;
197 		mpp = session->mpp;
198 
199 		if (mpp->dev_ops->dump_session)
200 			mpp->dev_ops->dump_session(session, seq);
201 	}
202 	mutex_unlock(&srv->session_lock);
203 
204 	return 0;
205 }
206 
mpp_show_support_cmd(struct seq_file * file,void * v)207 static int mpp_show_support_cmd(struct seq_file *file, void *v)
208 {
209 	seq_puts(file, "------------- SUPPORT CMD -------------\n");
210 	seq_printf(file, "QUERY_HW_SUPPORT:     0x%08x\n", MPP_CMD_QUERY_HW_SUPPORT);
211 	seq_printf(file, "QUERY_HW_ID:          0x%08x\n", MPP_CMD_QUERY_HW_ID);
212 	seq_printf(file, "QUERY_CMD_SUPPORT:    0x%08x\n", MPP_CMD_QUERY_CMD_SUPPORT);
213 	seq_printf(file, "QUERY_BUTT:           0x%08x\n", MPP_CMD_QUERY_BUTT);
214 	seq_puts(file, "----\n");
215 	seq_printf(file, "INIT_CLIENT_TYPE:     0x%08x\n", MPP_CMD_INIT_CLIENT_TYPE);
216 	seq_printf(file, "INIT_TRANS_TABLE:     0x%08x\n", MPP_CMD_INIT_TRANS_TABLE);
217 	seq_printf(file, "INIT_BUTT:            0x%08x\n", MPP_CMD_INIT_BUTT);
218 	seq_puts(file, "----\n");
219 	seq_printf(file, "SET_REG_WRITE:        0x%08x\n", MPP_CMD_SET_REG_WRITE);
220 	seq_printf(file, "SET_REG_READ:         0x%08x\n", MPP_CMD_SET_REG_READ);
221 	seq_printf(file, "SET_REG_ADDR_OFFSET:  0x%08x\n", MPP_CMD_SET_REG_ADDR_OFFSET);
222 	seq_printf(file, "SEND_BUTT:            0x%08x\n", MPP_CMD_SEND_BUTT);
223 	seq_puts(file, "----\n");
224 	seq_printf(file, "POLL_HW_FINISH:       0x%08x\n", MPP_CMD_POLL_HW_FINISH);
225 	seq_printf(file, "POLL_BUTT:            0x%08x\n", MPP_CMD_POLL_BUTT);
226 	seq_puts(file, "----\n");
227 	seq_printf(file, "RESET_SESSION:        0x%08x\n", MPP_CMD_RESET_SESSION);
228 	seq_printf(file, "TRANS_FD_TO_IOVA:     0x%08x\n", MPP_CMD_TRANS_FD_TO_IOVA);
229 	seq_printf(file, "RELEASE_FD:           0x%08x\n", MPP_CMD_RELEASE_FD);
230 	seq_printf(file, "SEND_CODEC_INFO:      0x%08x\n", MPP_CMD_SEND_CODEC_INFO);
231 	seq_printf(file, "CONTROL_BUTT:         0x%08x\n", MPP_CMD_CONTROL_BUTT);
232 
233 	return 0;
234 }
235 
mpp_show_support_device(struct seq_file * file,void * v)236 static int mpp_show_support_device(struct seq_file *file, void *v)
237 {
238 	u32 i;
239 	struct mpp_service *srv = file->private;
240 
241 	seq_puts(file, "---- SUPPORT DEVICES ----\n");
242 	for (i = 0; i < MPP_DEVICE_BUTT; i++) {
243 		struct mpp_dev *mpp;
244 		struct mpp_hw_info *hw_info;
245 
246 		if (test_bit(i, &srv->hw_support)) {
247 			mpp = srv->sub_devices[array_index_nospec(i, MPP_DEVICE_BUTT)];
248 			if (!mpp)
249 				continue;
250 
251 			seq_printf(file, "DEVICE[%2d]:%-10s", i, mpp_device_name[i]);
252 			hw_info = mpp->var->hw_info;
253 			if (hw_info->hw_id)
254 				seq_printf(file, "HW_ID:0x%08x", hw_info->hw_id);
255 			seq_puts(file, "\n");
256 		}
257 	}
258 
259 	return 0;
260 }
261 
mpp_procfs_init(struct mpp_service * srv)262 static int mpp_procfs_init(struct mpp_service *srv)
263 {
264 	srv->procfs = proc_mkdir(MPP_SERVICE_NAME, NULL);
265 	if (IS_ERR_OR_NULL(srv->procfs)) {
266 		mpp_err("failed on mkdir /proc/%s\n", MPP_SERVICE_NAME);
267 		srv->procfs = NULL;
268 		return -EIO;
269 	}
270 	/* show version */
271 	proc_create_single("version", 0444, srv->procfs, mpp_show_version);
272 	/* for show session info */
273 	proc_create_single_data("sessions-summary", 0444,
274 				srv->procfs, mpp_show_session_summary, srv);
275 	/* show support dev cmd */
276 	proc_create_single("supports-cmd", 0444, srv->procfs, mpp_show_support_cmd);
277 	/* show support devices */
278 	proc_create_single_data("supports-device", 0444,
279 				srv->procfs, mpp_show_support_device, srv);
280 
281 	return 0;
282 }
283 #else
mpp_procfs_remove(struct mpp_service * srv)284 static inline int mpp_procfs_remove(struct mpp_service *srv)
285 {
286 	return 0;
287 }
288 
mpp_procfs_init(struct mpp_service * srv)289 static inline int mpp_procfs_init(struct mpp_service *srv)
290 {
291 	return 0;
292 }
293 #endif
294 
mpp_service_probe(struct platform_device * pdev)295 static int mpp_service_probe(struct platform_device *pdev)
296 {
297 	int ret, i;
298 	struct mpp_service *srv = NULL;
299 	struct mpp_taskqueue *queue;
300 	struct device *dev = &pdev->dev;
301 	struct device_node *np = dev->of_node;
302 
303 	dev_info(dev, "%s\n", mpp_version);
304 	dev_info(dev, "probe start\n");
305 	srv = devm_kzalloc(dev, sizeof(*srv), GFP_KERNEL);
306 	if (!srv)
307 		return -ENOMEM;
308 
309 	srv->dev = dev;
310 	atomic_set(&srv->shutdown_request, 0);
311 	platform_set_drvdata(pdev, srv);
312 
313 	srv->cls = class_create(THIS_MODULE, MPP_CLASS_NAME);
314 	if (PTR_ERR_OR_ZERO(srv->cls))
315 		return PTR_ERR(srv->cls);
316 
317 	of_property_read_u32(np, "rockchip,taskqueue-count",
318 			     &srv->taskqueue_cnt);
319 	if (srv->taskqueue_cnt > MPP_DEVICE_BUTT) {
320 		dev_err(dev, "rockchip,taskqueue-count %d must less than %d\n",
321 			srv->taskqueue_cnt, MPP_DEVICE_BUTT);
322 		return -EINVAL;
323 	}
324 
325 	for (i = 0; i < srv->taskqueue_cnt; i++) {
326 		queue = mpp_taskqueue_init(dev);
327 		if (!queue)
328 			continue;
329 
330 		kthread_init_worker(&queue->worker);
331 		queue->kworker_task = kthread_run(kthread_worker_fn, &queue->worker,
332 						  "queue_work%d", i);
333 		srv->task_queues[i] = queue;
334 	}
335 
336 	of_property_read_u32(np, "rockchip,resetgroup-count",
337 			     &srv->reset_group_cnt);
338 	if (srv->reset_group_cnt > MPP_DEVICE_BUTT) {
339 		dev_err(dev, "rockchip,resetgroup-count %d must less than %d\n",
340 			srv->reset_group_cnt, MPP_DEVICE_BUTT);
341 		return -EINVAL;
342 	}
343 
344 	if (srv->reset_group_cnt) {
345 		u32 i = 0;
346 		struct mpp_reset_group *group;
347 
348 		for (i = 0; i < srv->reset_group_cnt; i++) {
349 			group = devm_kzalloc(dev, sizeof(*group), GFP_KERNEL);
350 			if (!group)
351 				continue;
352 
353 			init_rwsem(&group->rw_sem);
354 			srv->reset_groups[i] = group;
355 		}
356 	}
357 
358 	ret = mpp_register_service(srv, MPP_SERVICE_NAME);
359 	if (ret) {
360 		dev_err(dev, "register %s device\n", MPP_SERVICE_NAME);
361 		goto fail_register;
362 	}
363 	mutex_init(&srv->session_lock);
364 	INIT_LIST_HEAD(&srv->session_list);
365 	mpp_procfs_init(srv);
366 
367 	/* register sub drivers */
368 	MPP_REGISTER_DRIVER(srv, HAS_RKVDEC, RKVDEC, rkvdec);
369 	MPP_REGISTER_DRIVER(srv, HAS_RKVENC, RKVENC, rkvenc);
370 	MPP_REGISTER_DRIVER(srv, HAS_VDPU1, VDPU1, vdpu1);
371 	MPP_REGISTER_DRIVER(srv, HAS_VEPU1, VEPU1, vepu1);
372 	MPP_REGISTER_DRIVER(srv, HAS_VDPU2, VDPU2, vdpu2);
373 	MPP_REGISTER_DRIVER(srv, HAS_VEPU2, VEPU2, vepu2);
374 	MPP_REGISTER_DRIVER(srv, HAS_VEPU22, VEPU22, vepu22);
375 	MPP_REGISTER_DRIVER(srv, HAS_IEP2, IEP2, iep2);
376 	MPP_REGISTER_DRIVER(srv, HAS_JPGDEC, JPGDEC, jpgdec);
377 	MPP_REGISTER_DRIVER(srv, HAS_RKVDEC2, RKVDEC2, rkvdec2);
378 	MPP_REGISTER_DRIVER(srv, HAS_RKVENC2, RKVENC2, rkvenc2);
379 	MPP_REGISTER_DRIVER(srv, HAS_AV1DEC, AV1DEC, av1dec);
380 
381 	dev_info(dev, "probe success\n");
382 
383 	return 0;
384 
385 fail_register:
386 	class_destroy(srv->cls);
387 
388 	return ret;
389 }
390 
mpp_service_remove(struct platform_device * pdev)391 static int mpp_service_remove(struct platform_device *pdev)
392 {
393 	struct mpp_taskqueue *queue;
394 	struct device *dev = &pdev->dev;
395 	struct mpp_service *srv = platform_get_drvdata(pdev);
396 	int i;
397 
398 	dev_info(dev, "remove device\n");
399 
400 	for (i = 0; i < srv->taskqueue_cnt; i++) {
401 		queue = srv->task_queues[i];
402 		if (queue && queue->kworker_task) {
403 			kthread_flush_worker(&queue->worker);
404 			kthread_stop(queue->kworker_task);
405 			queue->kworker_task = NULL;
406 		}
407 	}
408 
409 	/* remove sub drivers */
410 	for (i = 0; i < MPP_DRIVER_BUTT; i++)
411 		mpp_remove_driver(srv, i);
412 
413 	mpp_remove_service(srv);
414 	class_destroy(srv->cls);
415 	mpp_procfs_remove(srv);
416 
417 	return 0;
418 }
419 
420 static const struct of_device_id mpp_dt_ids[] = {
421 	{
422 		.compatible = "rockchip,mpp-service",
423 	},
424 	{ },
425 };
426 
427 static struct platform_driver mpp_service_driver = {
428 	.probe = mpp_service_probe,
429 	.remove = mpp_service_remove,
430 	.driver = {
431 		.name = "mpp_service",
432 		.of_match_table = of_match_ptr(mpp_dt_ids),
433 	},
434 };
435 
436 module_platform_driver(mpp_service_driver);
437 
438 MODULE_LICENSE("Dual MIT/GPL");
439 MODULE_VERSION(MPP_VERSION);
440 MODULE_AUTHOR("Ding Wei leo.ding@rock-chips.com");
441 MODULE_DESCRIPTION("Rockchip mpp service driver");
442