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