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