1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (c) 2022 MediaTek Inc.
4 * Author: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
5 */
6
7 #include <linux/mailbox_controller.h>
8 #include <linux/platform_device.h>
9 #include "mtk-mdp3-cmdq.h"
10 #include "mtk-mdp3-comp.h"
11 #include "mtk-mdp3-core.h"
12 #include "mtk-mdp3-m2m.h"
13
14 #define MDP_PATH_MAX_COMPS IMG_MAX_COMPONENTS
15
16 struct mdp_path {
17 struct mdp_dev *mdp_dev;
18 struct mdp_comp_ctx comps[MDP_PATH_MAX_COMPS];
19 u32 num_comps;
20 const struct img_config *config;
21 const struct img_ipi_frameparam *param;
22 const struct v4l2_rect *composes[IMG_MAX_HW_OUTPUTS];
23 struct v4l2_rect bounds[IMG_MAX_HW_OUTPUTS];
24 };
25
26 #define has_op(ctx, op) \
27 ((ctx)->comp->ops && (ctx)->comp->ops->op)
28 #define call_op(ctx, op, ...) \
29 (has_op(ctx, op) ? (ctx)->comp->ops->op(ctx, ##__VA_ARGS__) : 0)
30
is_output_disabled(const struct img_compparam * param,u32 count)31 static bool is_output_disabled(const struct img_compparam *param, u32 count)
32 {
33 return (count < param->num_subfrms) ?
34 (param->frame.output_disable ||
35 param->subfrms[count].tile_disable) :
36 true;
37 }
38
mdp_path_subfrm_require(const struct mdp_path * path,struct mdp_cmdq_cmd * cmd,s32 * mutex_id,u32 count)39 static int mdp_path_subfrm_require(const struct mdp_path *path,
40 struct mdp_cmdq_cmd *cmd,
41 s32 *mutex_id, u32 count)
42 {
43 const struct img_config *config = path->config;
44 const struct mdp_comp_ctx *ctx;
45 const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data;
46 struct device *dev = &path->mdp_dev->pdev->dev;
47 struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
48 int id, index;
49
50 /* Decide which mutex to use based on the current pipeline */
51 switch (path->comps[0].comp->id) {
52 case MDP_COMP_RDMA0:
53 *mutex_id = MDP_PIPE_RDMA0;
54 break;
55 case MDP_COMP_ISP_IMGI:
56 *mutex_id = MDP_PIPE_IMGI;
57 break;
58 case MDP_COMP_WPEI:
59 *mutex_id = MDP_PIPE_WPEI;
60 break;
61 case MDP_COMP_WPEI2:
62 *mutex_id = MDP_PIPE_WPEI2;
63 break;
64 default:
65 dev_err(dev, "Unknown pipeline and no mutex is assigned");
66 return -EINVAL;
67 }
68
69 /* Set mutex mod */
70 for (index = 0; index < config->num_components; index++) {
71 ctx = &path->comps[index];
72 if (is_output_disabled(ctx->param, count))
73 continue;
74 id = ctx->comp->id;
75 mtk_mutex_write_mod(mutex[*mutex_id],
76 data->mdp_mutex_table_idx[id], false);
77 }
78
79 mtk_mutex_write_sof(mutex[*mutex_id],
80 MUTEX_SOF_IDX_SINGLE_MODE);
81
82 return 0;
83 }
84
mdp_path_subfrm_run(const struct mdp_path * path,struct mdp_cmdq_cmd * cmd,s32 * mutex_id,u32 count)85 static int mdp_path_subfrm_run(const struct mdp_path *path,
86 struct mdp_cmdq_cmd *cmd,
87 s32 *mutex_id, u32 count)
88 {
89 const struct img_config *config = path->config;
90 const struct mdp_comp_ctx *ctx;
91 struct device *dev = &path->mdp_dev->pdev->dev;
92 struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex;
93 int index;
94 s32 event;
95
96 if (-1 == *mutex_id) {
97 dev_err(dev, "Incorrect mutex id");
98 return -EINVAL;
99 }
100
101 /* Wait WROT SRAM shared to DISP RDMA */
102 /* Clear SOF event for each engine */
103 for (index = 0; index < config->num_components; index++) {
104 ctx = &path->comps[index];
105 if (is_output_disabled(ctx->param, count))
106 continue;
107 event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
108 if (event != MDP_GCE_NO_EVENT)
109 MM_REG_CLEAR(cmd, event);
110 }
111
112 /* Enable the mutex */
113 mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt);
114
115 /* Wait SOF events and clear mutex modules (optional) */
116 for (index = 0; index < config->num_components; index++) {
117 ctx = &path->comps[index];
118 if (is_output_disabled(ctx->param, count))
119 continue;
120 event = ctx->comp->gce_event[MDP_GCE_EVENT_SOF];
121 if (event != MDP_GCE_NO_EVENT)
122 MM_REG_WAIT(cmd, event);
123 }
124
125 return 0;
126 }
127
mdp_path_ctx_init(struct mdp_dev * mdp,struct mdp_path * path)128 static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path)
129 {
130 const struct img_config *config = path->config;
131 int index, ret;
132
133 if (config->num_components < 1)
134 return -EINVAL;
135
136 for (index = 0; index < config->num_components; index++) {
137 ret = mdp_comp_ctx_config(mdp, &path->comps[index],
138 &config->components[index],
139 path->param);
140 if (ret)
141 return ret;
142 }
143
144 return 0;
145 }
146
mdp_path_config_subfrm(struct mdp_cmdq_cmd * cmd,struct mdp_path * path,u32 count)147 static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd,
148 struct mdp_path *path, u32 count)
149 {
150 const struct img_config *config = path->config;
151 const struct img_mmsys_ctrl *ctrl = &config->ctrls[count];
152 const struct img_mux *set;
153 struct mdp_comp_ctx *ctx;
154 s32 mutex_id;
155 int index, ret;
156
157 /* Acquire components */
158 ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count);
159 if (ret)
160 return ret;
161 /* Enable mux settings */
162 for (index = 0; index < ctrl->num_sets; index++) {
163 set = &ctrl->sets[index];
164 cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
165 set->value, 0xFFFFFFFF);
166 }
167 /* Config sub-frame information */
168 for (index = (config->num_components - 1); index >= 0; index--) {
169 ctx = &path->comps[index];
170 if (is_output_disabled(ctx->param, count))
171 continue;
172 ret = call_op(ctx, config_subfrm, cmd, count);
173 if (ret)
174 return ret;
175 }
176 /* Run components */
177 ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count);
178 if (ret)
179 return ret;
180 /* Wait components done */
181 for (index = 0; index < config->num_components; index++) {
182 ctx = &path->comps[index];
183 if (is_output_disabled(ctx->param, count))
184 continue;
185 ret = call_op(ctx, wait_comp_event, cmd);
186 if (ret)
187 return ret;
188 }
189 /* Advance to the next sub-frame */
190 for (index = 0; index < config->num_components; index++) {
191 ctx = &path->comps[index];
192 ret = call_op(ctx, advance_subfrm, cmd, count);
193 if (ret)
194 return ret;
195 }
196 /* Disable mux settings */
197 for (index = 0; index < ctrl->num_sets; index++) {
198 set = &ctrl->sets[index];
199 cmdq_pkt_write_mask(&cmd->pkt, set->subsys_id, set->reg,
200 0, 0xFFFFFFFF);
201 }
202
203 return 0;
204 }
205
mdp_path_config(struct mdp_dev * mdp,struct mdp_cmdq_cmd * cmd,struct mdp_path * path)206 static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd,
207 struct mdp_path *path)
208 {
209 const struct img_config *config = path->config;
210 struct mdp_comp_ctx *ctx;
211 int index, count, ret;
212
213 /* Config path frame */
214 /* Reset components */
215 for (index = 0; index < config->num_components; index++) {
216 ctx = &path->comps[index];
217 ret = call_op(ctx, init_comp, cmd);
218 if (ret)
219 return ret;
220 }
221 /* Config frame mode */
222 for (index = 0; index < config->num_components; index++) {
223 const struct v4l2_rect *compose =
224 path->composes[ctx->param->outputs[0]];
225
226 ctx = &path->comps[index];
227 ret = call_op(ctx, config_frame, cmd, compose);
228 if (ret)
229 return ret;
230 }
231
232 /* Config path sub-frames */
233 for (count = 0; count < config->num_subfrms; count++) {
234 ret = mdp_path_config_subfrm(cmd, path, count);
235 if (ret)
236 return ret;
237 }
238 /* Post processing information */
239 for (index = 0; index < config->num_components; index++) {
240 ctx = &path->comps[index];
241 ret = call_op(ctx, post_process, cmd);
242 if (ret)
243 return ret;
244 }
245 return 0;
246 }
247
mdp_cmdq_pkt_create(struct cmdq_client * client,struct cmdq_pkt * pkt,size_t size)248 static int mdp_cmdq_pkt_create(struct cmdq_client *client, struct cmdq_pkt *pkt,
249 size_t size)
250 {
251 struct device *dev;
252 dma_addr_t dma_addr;
253
254 pkt->va_base = kzalloc(size, GFP_KERNEL);
255 if (!pkt->va_base)
256 return -ENOMEM;
257
258 pkt->buf_size = size;
259 pkt->cl = (void *)client;
260
261 dev = client->chan->mbox->dev;
262 dma_addr = dma_map_single(dev, pkt->va_base, pkt->buf_size,
263 DMA_TO_DEVICE);
264 if (dma_mapping_error(dev, dma_addr)) {
265 dev_err(dev, "dma map failed, size=%u\n", (u32)(u64)size);
266 kfree(pkt->va_base);
267 return -ENOMEM;
268 }
269
270 pkt->pa_base = dma_addr;
271
272 return 0;
273 }
274
mdp_cmdq_pkt_destroy(struct cmdq_pkt * pkt)275 static void mdp_cmdq_pkt_destroy(struct cmdq_pkt *pkt)
276 {
277 struct cmdq_client *client = (struct cmdq_client *)pkt->cl;
278
279 dma_unmap_single(client->chan->mbox->dev, pkt->pa_base, pkt->buf_size,
280 DMA_TO_DEVICE);
281 kfree(pkt->va_base);
282 pkt->va_base = NULL;
283 }
284
mdp_auto_release_work(struct work_struct * work)285 static void mdp_auto_release_work(struct work_struct *work)
286 {
287 struct mdp_cmdq_cmd *cmd;
288 struct mdp_dev *mdp;
289
290 cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work);
291 mdp = cmd->mdp;
292
293 mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
294 mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
295 cmd->num_comps);
296
297 atomic_dec(&mdp->job_count);
298 wake_up(&mdp->callback_wq);
299
300 mdp_cmdq_pkt_destroy(&cmd->pkt);
301 kfree(cmd->comps);
302 cmd->comps = NULL;
303 kfree(cmd);
304 cmd = NULL;
305 }
306
mdp_handle_cmdq_callback(struct mbox_client * cl,void * mssg)307 static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg)
308 {
309 struct mdp_cmdq_cmd *cmd;
310 struct cmdq_cb_data *data;
311 struct mdp_dev *mdp;
312 struct device *dev;
313
314 if (!mssg) {
315 pr_info("%s:no callback data\n", __func__);
316 return;
317 }
318
319 data = (struct cmdq_cb_data *)mssg;
320 cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt);
321 mdp = cmd->mdp;
322 dev = &mdp->pdev->dev;
323
324 if (cmd->mdp_ctx)
325 mdp_m2m_job_finish(cmd->mdp_ctx);
326
327 if (cmd->user_cmdq_cb) {
328 struct cmdq_cb_data user_cb_data;
329
330 user_cb_data.sta = data->sta;
331 user_cb_data.pkt = data->pkt;
332 cmd->user_cmdq_cb(user_cb_data);
333 }
334
335 INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work);
336 if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) {
337 dev_err(dev, "%s:queue_work fail!\n", __func__);
338 mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
339 mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
340 cmd->num_comps);
341
342 atomic_dec(&mdp->job_count);
343 wake_up(&mdp->callback_wq);
344
345 mdp_cmdq_pkt_destroy(&cmd->pkt);
346 kfree(cmd->comps);
347 cmd->comps = NULL;
348 kfree(cmd);
349 cmd = NULL;
350 }
351 }
352
mdp_cmdq_send(struct mdp_dev * mdp,struct mdp_cmdq_param * param)353 int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param)
354 {
355 struct mdp_path *path = NULL;
356 struct mdp_cmdq_cmd *cmd = NULL;
357 struct mdp_comp *comps = NULL;
358 struct device *dev = &mdp->pdev->dev;
359 int i, ret;
360
361 atomic_inc(&mdp->job_count);
362 if (atomic_read(&mdp->suspended)) {
363 atomic_dec(&mdp->job_count);
364 return -ECANCELED;
365 }
366
367 cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
368 if (!cmd) {
369 ret = -ENOMEM;
370 goto err_cancel_job;
371 }
372
373 ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K);
374 if (ret)
375 goto err_free_cmd;
376
377 comps = kcalloc(param->config->num_components, sizeof(*comps),
378 GFP_KERNEL);
379 if (!comps) {
380 ret = -ENOMEM;
381 goto err_destroy_pkt;
382 }
383
384 path = kzalloc(sizeof(*path), GFP_KERNEL);
385 if (!path) {
386 ret = -ENOMEM;
387 goto err_free_comps;
388 }
389
390 ret = mtk_mutex_prepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
391 if (ret) {
392 dev_err(dev, "Fail to enable mutex clk\n");
393 goto err_free_path;
394 }
395
396 path->mdp_dev = mdp;
397 path->config = param->config;
398 path->param = param->param;
399 for (i = 0; i < param->param->num_outputs; i++) {
400 path->bounds[i].left = 0;
401 path->bounds[i].top = 0;
402 path->bounds[i].width =
403 param->param->outputs[i].buffer.format.width;
404 path->bounds[i].height =
405 param->param->outputs[i].buffer.format.height;
406 path->composes[i] = param->composes[i] ?
407 param->composes[i] : &path->bounds[i];
408 }
409
410 ret = mdp_path_ctx_init(mdp, path);
411 if (ret) {
412 dev_err(dev, "mdp_path_ctx_init error\n");
413 goto err_free_path;
414 }
415
416 ret = mdp_path_config(mdp, cmd, path);
417 if (ret) {
418 dev_err(dev, "mdp_path_config error\n");
419 goto err_free_path;
420 }
421 cmdq_pkt_finalize(&cmd->pkt);
422
423 for (i = 0; i < param->config->num_components; i++)
424 memcpy(&comps[i], path->comps[i].comp,
425 sizeof(struct mdp_comp));
426
427 mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback;
428 cmd->mdp = mdp;
429 cmd->user_cmdq_cb = param->cmdq_cb;
430 cmd->user_cb_data = param->cb_data;
431 cmd->comps = comps;
432 cmd->num_comps = param->config->num_components;
433 cmd->mdp_ctx = param->mdp_ctx;
434
435 ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps);
436 if (ret)
437 goto err_free_path;
438
439 dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev,
440 cmd->pkt.pa_base, cmd->pkt.cmd_buf_size,
441 DMA_TO_DEVICE);
442 ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt);
443 if (ret < 0) {
444 dev_err(dev, "mbox send message fail %d!\n", ret);
445 goto err_clock_off;
446 }
447 mbox_client_txdone(mdp->cmdq_clt->chan, 0);
448
449 kfree(path);
450 return 0;
451
452 err_clock_off:
453 mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps,
454 cmd->num_comps);
455 err_free_path:
456 mtk_mutex_unprepare(mdp->mdp_mutex[MDP_PIPE_RDMA0]);
457 kfree(path);
458 err_free_comps:
459 kfree(comps);
460 err_destroy_pkt:
461 mdp_cmdq_pkt_destroy(&cmd->pkt);
462 err_free_cmd:
463 kfree(cmd);
464 err_cancel_job:
465 atomic_dec(&mdp->job_count);
466
467 return ret;
468 }
469 EXPORT_SYMBOL_GPL(mdp_cmdq_send);
470