xref: /linux/drivers/media/platform/amphion/vpu_rpc.c (revision a1c613ae4c322ddd58d5a8539dbfba2a0380a8c0)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright 2020-2021 NXP
4  */
5 
6 #include <linux/init.h>
7 #include <linux/interconnect.h>
8 #include <linux/ioctl.h>
9 #include <linux/list.h>
10 #include <linux/kernel.h>
11 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/firmware/imx/ipc.h>
14 #include <linux/firmware/imx/svc/misc.h>
15 #include "vpu.h"
16 #include "vpu_rpc.h"
17 #include "vpu_imx8q.h"
18 #include "vpu_windsor.h"
19 #include "vpu_malone.h"
20 
vpu_iface_check_memory_region(struct vpu_core * core,dma_addr_t addr,u32 size)21 int vpu_iface_check_memory_region(struct vpu_core *core, dma_addr_t addr, u32 size)
22 {
23 	struct vpu_iface_ops *ops = vpu_core_get_iface(core);
24 
25 	if (!ops || !ops->check_memory_region)
26 		return VPU_CORE_MEMORY_INVALID;
27 
28 	return ops->check_memory_region(core->fw.phys, addr, size);
29 }
30 
vpu_rpc_check_buffer_space(struct vpu_rpc_buffer_desc * desc,bool write)31 static u32 vpu_rpc_check_buffer_space(struct vpu_rpc_buffer_desc *desc, bool write)
32 {
33 	u32 ptr1;
34 	u32 ptr2;
35 	u32 size;
36 
37 	size = desc->end - desc->start;
38 	if (write) {
39 		ptr1 = desc->wptr;
40 		ptr2 = desc->rptr;
41 	} else {
42 		ptr1 = desc->rptr;
43 		ptr2 = desc->wptr;
44 	}
45 
46 	if (ptr1 == ptr2) {
47 		if (!write)
48 			return 0;
49 		else
50 			return size;
51 	}
52 
53 	return (ptr2 + size - ptr1) % size;
54 }
55 
vpu_rpc_send_cmd_buf(struct vpu_shared_addr * shared,struct vpu_rpc_event * cmd)56 static int vpu_rpc_send_cmd_buf(struct vpu_shared_addr *shared, struct vpu_rpc_event *cmd)
57 {
58 	struct vpu_rpc_buffer_desc *desc;
59 	u32 space = 0;
60 	u32 *data;
61 	u32 wptr;
62 	u32 i;
63 
64 	if (cmd->hdr.num > 0xff || cmd->hdr.num >= ARRAY_SIZE(cmd->data))
65 		return -EINVAL;
66 	desc = shared->cmd_desc;
67 	space = vpu_rpc_check_buffer_space(desc, true);
68 	if (space < (((cmd->hdr.num + 1) << 2) + 16))
69 		return -EINVAL;
70 	wptr = desc->wptr;
71 	data = (u32 *)(shared->cmd_mem_vir + desc->wptr - desc->start);
72 	*data = 0;
73 	*data |= ((cmd->hdr.index & 0xff) << 24);
74 	*data |= ((cmd->hdr.num & 0xff) << 16);
75 	*data |= (cmd->hdr.id & 0x3fff);
76 	wptr += 4;
77 	data++;
78 	if (wptr >= desc->end) {
79 		wptr = desc->start;
80 		data = shared->cmd_mem_vir;
81 	}
82 
83 	for (i = 0; i < cmd->hdr.num; i++) {
84 		*data = cmd->data[i];
85 		wptr += 4;
86 		data++;
87 		if (wptr >= desc->end) {
88 			wptr = desc->start;
89 			data = shared->cmd_mem_vir;
90 		}
91 	}
92 
93 	/*update wptr after data is written*/
94 	mb();
95 	desc->wptr = wptr;
96 
97 	return 0;
98 }
99 
vpu_rpc_check_msg(struct vpu_shared_addr * shared)100 static bool vpu_rpc_check_msg(struct vpu_shared_addr *shared)
101 {
102 	struct vpu_rpc_buffer_desc *desc;
103 	u32 space = 0;
104 	u32 msgword;
105 	u32 msgnum;
106 
107 	desc = shared->msg_desc;
108 	space = vpu_rpc_check_buffer_space(desc, 0);
109 	space = (space >> 2);
110 
111 	if (space) {
112 		msgword = *(u32 *)(shared->msg_mem_vir + desc->rptr - desc->start);
113 		msgnum = (msgword & 0xff0000) >> 16;
114 		if (msgnum <= space)
115 			return true;
116 	}
117 
118 	return false;
119 }
120 
vpu_rpc_receive_msg_buf(struct vpu_shared_addr * shared,struct vpu_rpc_event * msg)121 static int vpu_rpc_receive_msg_buf(struct vpu_shared_addr *shared, struct vpu_rpc_event *msg)
122 {
123 	struct vpu_rpc_buffer_desc *desc;
124 	u32 *data;
125 	u32 msgword;
126 	u32 rptr;
127 	u32 i;
128 
129 	if (!vpu_rpc_check_msg(shared))
130 		return -EINVAL;
131 
132 	desc = shared->msg_desc;
133 	data = (u32 *)(shared->msg_mem_vir + desc->rptr - desc->start);
134 	rptr = desc->rptr;
135 	msgword = *data;
136 	data++;
137 	rptr += 4;
138 	if (rptr >= desc->end) {
139 		rptr = desc->start;
140 		data = shared->msg_mem_vir;
141 	}
142 
143 	msg->hdr.index = (msgword >> 24) & 0xff;
144 	msg->hdr.num = (msgword >> 16) & 0xff;
145 	msg->hdr.id = msgword & 0x3fff;
146 
147 	if (msg->hdr.num > ARRAY_SIZE(msg->data))
148 		return -EINVAL;
149 
150 	for (i = 0; i < msg->hdr.num; i++) {
151 		msg->data[i] = *data;
152 		data++;
153 		rptr += 4;
154 		if (rptr >= desc->end) {
155 			rptr = desc->start;
156 			data = shared->msg_mem_vir;
157 		}
158 	}
159 
160 	/*update rptr after data is read*/
161 	mb();
162 	desc->rptr = rptr;
163 
164 	return 0;
165 }
166 
167 static struct vpu_iface_ops imx8q_rpc_ops[] = {
168 	[VPU_CORE_TYPE_ENC] = {
169 		.check_codec = vpu_imx8q_check_codec,
170 		.check_fmt = vpu_imx8q_check_fmt,
171 		.boot_core = vpu_imx8q_boot_core,
172 		.get_power_state = vpu_imx8q_get_power_state,
173 		.on_firmware_loaded = vpu_imx8q_on_firmware_loaded,
174 		.get_data_size = vpu_windsor_get_data_size,
175 		.check_memory_region = vpu_imx8q_check_memory_region,
176 		.init_rpc = vpu_windsor_init_rpc,
177 		.set_log_buf = vpu_windsor_set_log_buf,
178 		.set_system_cfg = vpu_windsor_set_system_cfg,
179 		.get_version = vpu_windsor_get_version,
180 		.send_cmd_buf = vpu_rpc_send_cmd_buf,
181 		.receive_msg_buf = vpu_rpc_receive_msg_buf,
182 		.pack_cmd = vpu_windsor_pack_cmd,
183 		.convert_msg_id = vpu_windsor_convert_msg_id,
184 		.unpack_msg_data = vpu_windsor_unpack_msg_data,
185 		.config_memory_resource = vpu_windsor_config_memory_resource,
186 		.get_stream_buffer_size = vpu_windsor_get_stream_buffer_size,
187 		.config_stream_buffer = vpu_windsor_config_stream_buffer,
188 		.get_stream_buffer_desc = vpu_windsor_get_stream_buffer_desc,
189 		.update_stream_buffer = vpu_windsor_update_stream_buffer,
190 		.set_encode_params = vpu_windsor_set_encode_params,
191 		.input_frame = vpu_windsor_input_frame,
192 		.get_max_instance_count = vpu_windsor_get_max_instance_count,
193 	},
194 	[VPU_CORE_TYPE_DEC] = {
195 		.check_codec = vpu_imx8q_check_codec,
196 		.check_fmt = vpu_malone_check_fmt,
197 		.boot_core = vpu_imx8q_boot_core,
198 		.get_power_state = vpu_imx8q_get_power_state,
199 		.on_firmware_loaded = vpu_imx8q_on_firmware_loaded,
200 		.get_data_size = vpu_malone_get_data_size,
201 		.check_memory_region = vpu_imx8q_check_memory_region,
202 		.init_rpc = vpu_malone_init_rpc,
203 		.set_log_buf = vpu_malone_set_log_buf,
204 		.set_system_cfg = vpu_malone_set_system_cfg,
205 		.get_version = vpu_malone_get_version,
206 		.send_cmd_buf = vpu_rpc_send_cmd_buf,
207 		.receive_msg_buf = vpu_rpc_receive_msg_buf,
208 		.get_stream_buffer_size = vpu_malone_get_stream_buffer_size,
209 		.config_stream_buffer = vpu_malone_config_stream_buffer,
210 		.set_decode_params = vpu_malone_set_decode_params,
211 		.pack_cmd = vpu_malone_pack_cmd,
212 		.convert_msg_id = vpu_malone_convert_msg_id,
213 		.unpack_msg_data = vpu_malone_unpack_msg_data,
214 		.get_stream_buffer_desc = vpu_malone_get_stream_buffer_desc,
215 		.update_stream_buffer = vpu_malone_update_stream_buffer,
216 		.add_scode = vpu_malone_add_scode,
217 		.input_frame = vpu_malone_input_frame,
218 		.pre_send_cmd = vpu_malone_pre_cmd,
219 		.post_send_cmd = vpu_malone_post_cmd,
220 		.init_instance = vpu_malone_init_instance,
221 		.get_max_instance_count = vpu_malone_get_max_instance_count,
222 	},
223 };
224 
vpu_get_iface(struct vpu_dev * vpu,enum vpu_core_type type)225 static struct vpu_iface_ops *vpu_get_iface(struct vpu_dev *vpu, enum vpu_core_type type)
226 {
227 	struct vpu_iface_ops *rpc_ops = NULL;
228 	u32 size = 0;
229 
230 	switch (vpu->res->plat_type) {
231 	case IMX8QXP:
232 	case IMX8QM:
233 		rpc_ops = imx8q_rpc_ops;
234 		size = ARRAY_SIZE(imx8q_rpc_ops);
235 		break;
236 	default:
237 		return NULL;
238 	}
239 
240 	if (type >= size)
241 		return NULL;
242 
243 	return &rpc_ops[type];
244 }
245 
vpu_core_get_iface(struct vpu_core * core)246 struct vpu_iface_ops *vpu_core_get_iface(struct vpu_core *core)
247 {
248 	return vpu_get_iface(core->vpu, core->type);
249 }
250 
vpu_inst_get_iface(struct vpu_inst * inst)251 struct vpu_iface_ops *vpu_inst_get_iface(struct vpu_inst *inst)
252 {
253 	if (inst->core)
254 		return vpu_core_get_iface(inst->core);
255 
256 	return vpu_get_iface(inst->vpu, inst->type);
257 }
258