]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blame - drivers/media/pci/intel/ipu6/ipu6-ppg.c
UBUNTU: SAUCE: IPU driver release WW48
[mirror_ubuntu-jammy-kernel.git] / drivers / media / pci / intel / ipu6 / ipu6-ppg.c
CommitLineData
f2efa4ee
WY
1// SPDX-License-Identifier: GPL-2.0
2// Copyright (C) 2020 Intel Corporation
3
4#include <linux/module.h>
5#include <linux/pm_runtime.h>
6
7#include <asm/cacheflush.h>
8
9#include "ipu6-ppg.h"
10
11static bool enable_suspend_resume;
12module_param(enable_suspend_resume, bool, 0664);
13MODULE_PARM_DESC(enable_suspend_resume, "enable fw ppg suspend/resume api");
14
15static struct ipu_psys_kcmd *
16ipu_psys_ppg_get_kcmd(struct ipu_psys_ppg *kppg, enum ipu_psys_cmd_state state)
17{
18 struct ipu_psys_kcmd *kcmd;
19
20 if (list_empty(&kppg->kcmds_new_list))
21 return NULL;
22
23 list_for_each_entry(kcmd, &kppg->kcmds_new_list, list) {
24 if (kcmd->state == state)
25 return kcmd;
26 }
27
28 return NULL;
29}
30
31struct ipu_psys_kcmd *ipu_psys_ppg_get_stop_kcmd(struct ipu_psys_ppg *kppg)
32{
33 struct ipu_psys_kcmd *kcmd;
34
af60d6fc
WY
35 WARN(!mutex_is_locked(&kppg->mutex), "ppg locking error");
36
f2efa4ee
WY
37 if (list_empty(&kppg->kcmds_processing_list))
38 return NULL;
39
40 list_for_each_entry(kcmd, &kppg->kcmds_processing_list, list) {
41 if (kcmd->state == KCMD_STATE_PPG_STOP)
42 return kcmd;
43 }
44
45 return NULL;
46}
47
48static struct ipu_psys_buffer_set *
49__get_buf_set(struct ipu_psys_fh *fh, size_t buf_set_size)
50{
51 struct ipu_psys_buffer_set *kbuf_set;
52 struct ipu_psys_scheduler *sched = &fh->sched;
53
54 mutex_lock(&sched->bs_mutex);
55 list_for_each_entry(kbuf_set, &sched->buf_sets, list) {
56 if (!kbuf_set->buf_set_size &&
57 kbuf_set->size >= buf_set_size) {
58 kbuf_set->buf_set_size = buf_set_size;
59 mutex_unlock(&sched->bs_mutex);
60 return kbuf_set;
61 }
62 }
63
64 mutex_unlock(&sched->bs_mutex);
65 /* no suitable buffer available, allocate new one */
66 kbuf_set = kzalloc(sizeof(*kbuf_set), GFP_KERNEL);
67 if (!kbuf_set)
68 return NULL;
69
70 kbuf_set->kaddr = dma_alloc_attrs(&fh->psys->adev->dev,
71 buf_set_size, &kbuf_set->dma_addr,
72 GFP_KERNEL, 0);
73 if (!kbuf_set->kaddr) {
74 kfree(kbuf_set);
75 return NULL;
76 }
77
78 kbuf_set->buf_set_size = buf_set_size;
79 kbuf_set->size = buf_set_size;
80 mutex_lock(&sched->bs_mutex);
81 list_add(&kbuf_set->list, &sched->buf_sets);
82 mutex_unlock(&sched->bs_mutex);
83
84 return kbuf_set;
85}
86
87static struct ipu_psys_buffer_set *
88ipu_psys_create_buffer_set(struct ipu_psys_kcmd *kcmd,
89 struct ipu_psys_ppg *kppg)
90{
91 struct ipu_psys_fh *fh = kcmd->fh;
92 struct ipu_psys *psys = fh->psys;
93 struct ipu_psys_buffer_set *kbuf_set;
94 size_t buf_set_size;
95 u32 *keb;
96
97 buf_set_size = ipu_fw_psys_ppg_get_buffer_set_size(kcmd);
98
99 kbuf_set = __get_buf_set(fh, buf_set_size);
100 if (!kbuf_set)
101 goto error;
102
103 kbuf_set->buf_set = ipu_fw_psys_ppg_create_buffer_set(kcmd,
104 kbuf_set->kaddr,
105 0);
106
107 ipu_fw_psys_ppg_buffer_set_vaddress(kbuf_set->buf_set,
108 kbuf_set->dma_addr);
109 keb = kcmd->kernel_enable_bitmap;
110 ipu_fw_psys_ppg_buffer_set_set_kernel_enable_bitmap(kbuf_set->buf_set,
111 keb);
112
113 return kbuf_set;
114error:
115 dev_err(&psys->adev->dev, "failed to create buffer set\n");
116 return NULL;
117}
118
119int ipu_psys_ppg_get_bufset(struct ipu_psys_kcmd *kcmd,
120 struct ipu_psys_ppg *kppg)
121{
122 struct ipu_psys *psys = kppg->fh->psys;
123 struct ipu_psys_buffer_set *kbuf_set;
124 size_t buf_set_size;
125 unsigned int i;
126 int ret;
127
128 buf_set_size = ipu_fw_psys_ppg_get_buffer_set_size(kcmd);
129
130 kbuf_set = ipu_psys_create_buffer_set(kcmd, kppg);
131 if (!kbuf_set) {
132 ret = -EINVAL;
133 goto error;
134 }
135 kcmd->kbuf_set = kbuf_set;
136 kbuf_set->kcmd = kcmd;
137
138 for (i = 0; i < kcmd->nbuffers; i++) {
139 struct ipu_fw_psys_terminal *terminal;
140 u32 buffer;
141
142 terminal = ipu_fw_psys_pg_get_terminal(kcmd, i);
143 if (!terminal)
144 continue;
145
146 buffer = (u32)kcmd->kbufs[i]->dma_addr +
147 kcmd->buffers[i].data_offset;
148
149 ret = ipu_fw_psys_ppg_set_buffer_set(kcmd, terminal, i, buffer);
150 if (ret) {
151 dev_err(&psys->adev->dev, "Unable to set bufset\n");
152 goto error;
153 }
154 }
155
156 return 0;
157
158error:
159 dev_err(&psys->adev->dev, "failed to get buffer set\n");
160 return ret;
161}
162
163void ipu_psys_ppg_complete(struct ipu_psys *psys, struct ipu_psys_ppg *kppg)
164{
165 u8 queue_id;
166 int old_ppg_state;
167
168 if (!psys || !kppg)
169 return;
170
171 mutex_lock(&kppg->mutex);
172 old_ppg_state = kppg->state;
173 if (kppg->state == PPG_STATE_STOPPING) {
174 unsigned long flags;
175 struct ipu_psys_kcmd tmp_kcmd = {
176 .kpg = kppg->kpg,
177 };
178
179 kppg->state = PPG_STATE_STOPPED;
180 ipu_psys_free_resources(&kppg->kpg->resource_alloc,
181 &psys->resource_pool_running);
182 queue_id = ipu_fw_psys_ppg_get_base_queue_id(&tmp_kcmd);
183 ipu_psys_free_cmd_queue_resource(&psys->resource_pool_running,
184 queue_id);
185 spin_lock_irqsave(&psys->pgs_lock, flags);
186 kppg->kpg->pg_size = 0;
187 spin_unlock_irqrestore(&psys->pgs_lock, flags);
188 pm_runtime_put(&psys->adev->dev);
189 } else {
190 if (kppg->state == PPG_STATE_SUSPENDING) {
191 kppg->state = PPG_STATE_SUSPENDED;
192 ipu_psys_free_resources(&kppg->kpg->resource_alloc,
193 &psys->resource_pool_running);
194 } else if (kppg->state == PPG_STATE_STARTED ||
195 kppg->state == PPG_STATE_RESUMED) {
196 kppg->state = PPG_STATE_RUNNING;
197 }
198
199 /* Kick l-scheduler thread for FW callback,
200 * also for checking if need to enter power gating
201 */
202 atomic_set(&psys->wakeup_count, 1);
203 wake_up_interruptible(&psys->sched_cmd_wq);
204 }
205 if (old_ppg_state != kppg->state)
206 dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
207 __func__, kppg, old_ppg_state, kppg->state);
208
209 mutex_unlock(&kppg->mutex);
210}
211
212int ipu_psys_ppg_start(struct ipu_psys_ppg *kppg)
213{
214 struct ipu_psys *psys = kppg->fh->psys;
215 struct ipu_psys_kcmd *kcmd = ipu_psys_ppg_get_kcmd(kppg,
216 KCMD_STATE_PPG_START);
217 unsigned int i;
218 int ret;
219
220 if (!kcmd) {
221 dev_err(&psys->adev->dev, "failed to find start kcmd!\n");
222 return -EINVAL;
223 }
224
225 dev_dbg(&psys->adev->dev, "start ppg id %d, addr 0x%p\n",
226 ipu_fw_psys_pg_get_id(kcmd), kppg);
227
228 kppg->state = PPG_STATE_STARTING;
229 for (i = 0; i < kcmd->nbuffers; i++) {
230 struct ipu_fw_psys_terminal *terminal;
231
232 terminal = ipu_fw_psys_pg_get_terminal(kcmd, i);
233 if (!terminal)
234 continue;
235
236 ret = ipu_fw_psys_terminal_set(terminal, i, kcmd, 0,
237 kcmd->buffers[i].len);
238 if (ret) {
239 dev_err(&psys->adev->dev, "Unable to set terminal\n");
af60d6fc 240 return ret;
f2efa4ee
WY
241 }
242 }
243
244 ret = ipu_fw_psys_pg_submit(kcmd);
245 if (ret) {
246 dev_err(&psys->adev->dev, "failed to submit kcmd!\n");
af60d6fc 247 return ret;
f2efa4ee
WY
248 }
249
250 ret = ipu_psys_allocate_resources(&psys->adev->dev,
251 kcmd->kpg->pg,
252 kcmd->pg_manifest,
253 &kcmd->kpg->resource_alloc,
254 &psys->resource_pool_running);
255 if (ret) {
256 dev_err(&psys->adev->dev, "alloc resources failed!\n");
257 return ret;
258 }
259
260 ret = pm_runtime_get_sync(&psys->adev->dev);
261 if (ret < 0) {
262 dev_err(&psys->adev->dev, "failed to power on psys\n");
af60d6fc 263 goto error;
f2efa4ee
WY
264 }
265
266 ret = ipu_psys_kcmd_start(psys, kcmd);
267 if (ret) {
af60d6fc
WY
268 ipu_psys_kcmd_complete(kppg, kcmd, -EIO);
269 goto error;
f2efa4ee
WY
270 }
271
272 dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
273 __func__, kppg, kppg->state, PPG_STATE_STARTED);
274 kppg->state = PPG_STATE_STARTED;
af60d6fc 275 ipu_psys_kcmd_complete(kppg, kcmd, 0);
f2efa4ee
WY
276
277 return 0;
278
279error:
af60d6fc
WY
280 pm_runtime_put_noidle(&psys->adev->dev);
281 ipu_psys_reset_process_cell(&psys->adev->dev,
282 kcmd->kpg->pg,
283 kcmd->pg_manifest,
284 kcmd->kpg->pg->process_count);
285 ipu_psys_free_resources(&kppg->kpg->resource_alloc,
286 &psys->resource_pool_running);
287
f2efa4ee
WY
288 dev_err(&psys->adev->dev, "failed to start ppg\n");
289 return ret;
290}
291
292int ipu_psys_ppg_resume(struct ipu_psys_ppg *kppg)
293{
294 struct ipu_psys *psys = kppg->fh->psys;
295 struct ipu_psys_kcmd tmp_kcmd = {
296 .kpg = kppg->kpg,
297 .fh = kppg->fh,
298 };
299 int ret;
300
301 dev_dbg(&psys->adev->dev, "resume ppg id %d, addr 0x%p\n",
302 ipu_fw_psys_pg_get_id(&tmp_kcmd), kppg);
303
304 kppg->state = PPG_STATE_RESUMING;
305 if (enable_suspend_resume) {
306 ret = ipu_psys_allocate_resources(&psys->adev->dev,
307 kppg->kpg->pg,
308 kppg->manifest,
309 &kppg->kpg->resource_alloc,
310 &psys->resource_pool_running);
311 if (ret) {
312 dev_err(&psys->adev->dev, "failed to allocate res\n");
313 return -EIO;
314 }
315
316 ret = ipu_fw_psys_ppg_resume(&tmp_kcmd);
317 if (ret) {
318 dev_err(&psys->adev->dev, "failed to resume ppg\n");
af60d6fc 319 goto error;
f2efa4ee
WY
320 }
321 } else {
322 kppg->kpg->pg->state = IPU_FW_PSYS_PROCESS_GROUP_READY;
323 ret = ipu_fw_psys_pg_submit(&tmp_kcmd);
324 if (ret) {
325 dev_err(&psys->adev->dev, "failed to submit kcmd!\n");
326 return ret;
327 }
328
329 ret = ipu_psys_allocate_resources(&psys->adev->dev,
330 kppg->kpg->pg,
331 kppg->manifest,
332 &kppg->kpg->resource_alloc,
333 &psys->resource_pool_running);
334 if (ret) {
335 dev_err(&psys->adev->dev, "failed to allocate res\n");
336 return ret;
337 }
338
339 ret = ipu_psys_kcmd_start(psys, &tmp_kcmd);
340 if (ret) {
341 dev_err(&psys->adev->dev, "failed to start kcmd!\n");
af60d6fc 342 goto error;
f2efa4ee
WY
343 }
344 }
345 dev_dbg(&psys->adev->dev, "s_change:%s: %p %d -> %d\n",
346 __func__, kppg, kppg->state, PPG_STATE_RESUMED);
347 kppg->state = PPG_STATE_RESUMED;
348
af60d6fc
WY
349 return 0;
350
351error:
352 ipu_psys_reset_process_cell(&psys->adev->dev,
353 kppg->kpg->pg,
354 kppg->manifest,
355 kppg->kpg->pg->process_count);
356 ipu_psys_free_resources(&kppg->kpg->resource_alloc,
357 &psys->resource_pool_running);
358
f2efa4ee
WY
359 return ret;
360}
361
362int ipu_psys_ppg_stop(struct ipu_psys_ppg *kppg)
363{
364 struct ipu_psys_kcmd *kcmd = ipu_psys_ppg_get_kcmd(kppg,
365 KCMD_STATE_PPG_STOP);
366 struct ipu_psys *psys = kppg->fh->psys;
367 struct ipu_psys_kcmd kcmd_temp;
368 int ppg_id, ret = 0;
369
370 if (kcmd) {
371 list_move_tail(&kcmd->list, &kppg->kcmds_processing_list);
372 } else {
373 dev_dbg(&psys->adev->dev, "Exceptional stop happened!\n");
374 kcmd_temp.kpg = kppg->kpg;
375 kcmd_temp.fh = kppg->fh;
376 kcmd = &kcmd_temp;
377 /* delete kppg in stop list to avoid this ppg resuming */
378 ipu_psys_scheduler_remove_kppg(kppg, SCHED_STOP_LIST);
379 }
380
381 ppg_id = ipu_fw_psys_pg_get_id(kcmd);
382 dev_dbg(&psys->adev->dev, "stop ppg(%d, addr 0x%p)\n", ppg_id, kppg);
383
384 if (kppg->state & PPG_STATE_SUSPENDED) {
385 if (enable_suspend_resume) {
386 dev_dbg(&psys->adev->dev, "need resume before stop!\n");
387 kcmd_temp.kpg = kppg->kpg;
388 kcmd_temp.fh = kppg->fh;
389 ret = ipu_fw_psys_ppg_resume(&kcmd_temp);
390 if (ret)
391 dev_err(&psys->adev->dev,
392 "ppg(%d) failed to resume\n", ppg_id);
393 } else if (kcmd != &kcmd_temp) {
394 unsigned long flags;
395
396 ipu_psys_free_cmd_queue_resource(
397 &psys->resource_pool_running,
398 ipu_fw_psys_ppg_get_base_queue_id(kcmd));
af60d6fc 399 ipu_psys_kcmd_complete(kppg, kcmd, 0);
f2efa4ee
WY
400 spin_lock_irqsave(&psys->pgs_lock, flags);
401 kppg->kpg->pg_size = 0;
402 spin_unlock_irqrestore(&psys->pgs_lock, flags);
403 dev_dbg(&psys->adev->dev,
404 "s_change:%s %p %d -> %d\n", __func__,
405 kppg, kppg->state, PPG_STATE_STOPPED);
406 pm_runtime_put(&psys->adev->dev);
407 kppg->state = PPG_STATE_STOPPED;
408 return 0;
409 }
410 }
411 dev_dbg(&psys->adev->dev, "s_change:%s %p %d -> %d\n",
412 __func__, kppg, kppg->state, PPG_STATE_STOPPING);
413 kppg->state = PPG_STATE_STOPPING;
414 ret = ipu_fw_psys_pg_abort(kcmd);
415 if (ret)
416 dev_err(&psys->adev->dev, "ppg(%d) failed to abort\n", ppg_id);
417
418 return ret;
419}
420
421int ipu_psys_ppg_suspend(struct ipu_psys_ppg *kppg)
422{
423 struct ipu_psys *psys = kppg->fh->psys;
424 struct ipu_psys_kcmd tmp_kcmd = {
425 .kpg = kppg->kpg,
426 .fh = kppg->fh,
427 };
428 int ppg_id = ipu_fw_psys_pg_get_id(&tmp_kcmd);
429 int ret = 0;
430
431 dev_dbg(&psys->adev->dev, "suspend ppg(%d, addr 0x%p)\n", ppg_id, kppg);
432
433 dev_dbg(&psys->adev->dev, "s_change:%s %p %d -> %d\n",
434 __func__, kppg, kppg->state, PPG_STATE_SUSPENDING);
435 kppg->state = PPG_STATE_SUSPENDING;
436 if (enable_suspend_resume)
437 ret = ipu_fw_psys_ppg_suspend(&tmp_kcmd);
438 else
439 ret = ipu_fw_psys_pg_abort(&tmp_kcmd);
440 if (ret)
441 dev_err(&psys->adev->dev, "failed to %s ppg(%d)\n",
442 enable_suspend_resume ? "suspend" : "stop", ret);
443
444 return ret;
445}
446
447static bool ipu_psys_ppg_is_bufset_existing(struct ipu_psys_ppg *kppg)
448{
449 return !list_empty(&kppg->kcmds_new_list);
450}
451
452/*
453 * ipu_psys_ppg_enqueue_bufsets - enqueue buffer sets to firmware
454 * Sometimes, if the ppg is at suspended state, this function will return true
455 * to reschedule and let the resume command scheduled before the buffer sets
456 * enqueuing.
457 */
458bool ipu_psys_ppg_enqueue_bufsets(struct ipu_psys_ppg *kppg)
459{
460 struct ipu_psys_kcmd *kcmd, *kcmd0;
461 struct ipu_psys *psys = kppg->fh->psys;
462 bool need_resume = false;
463
464 mutex_lock(&kppg->mutex);
465
466 if (kppg->state & (PPG_STATE_STARTED | PPG_STATE_RESUMED |
467 PPG_STATE_RUNNING)) {
468 if (ipu_psys_ppg_is_bufset_existing(kppg)) {
469 list_for_each_entry_safe(kcmd, kcmd0,
470 &kppg->kcmds_new_list, list) {
471 int ret;
472
473 if (kcmd->state != KCMD_STATE_PPG_ENQUEUE) {
474 need_resume = true;
475 break;
476 }
477
478 ret = ipu_fw_psys_ppg_enqueue_bufs(kcmd);
479 if (ret) {
480 dev_err(&psys->adev->dev,
481 "kppg 0x%p fail to qbufset %d",
482 kppg, ret);
483 break;
484 }
485 list_move_tail(&kcmd->list,
486 &kppg->kcmds_processing_list);
487 dev_dbg(&psys->adev->dev,
488 "kppg %d %p queue kcmd 0x%p fh 0x%p\n",
489 ipu_fw_psys_pg_get_id(kcmd),
490 kppg, kcmd, kcmd->fh);
491 }
492 }
493 }
494
495 mutex_unlock(&kppg->mutex);
496 return need_resume;
497}
498
499void ipu_psys_enter_power_gating(struct ipu_psys *psys)
500{
501 struct ipu_psys_scheduler *sched;
502 struct ipu_psys_ppg *kppg;
503 struct ipu_psys_fh *fh;
504 int ret = 0;
505
506 list_for_each_entry(fh, &psys->fhs, list) {
507 mutex_lock(&fh->mutex);
508 sched = &fh->sched;
509 if (list_empty(&sched->ppgs)) {
510 mutex_unlock(&fh->mutex);
511 continue;
512 }
513
514 list_for_each_entry(kppg, &sched->ppgs, list) {
515 mutex_lock(&kppg->mutex);
516 /* kppg has already power down */
517 if (kppg->state == PPG_STATE_STOPPED) {
518 mutex_unlock(&kppg->mutex);
519 continue;
520 }
521
522 ret = pm_runtime_put_autosuspend(&psys->adev->dev);
523 if (ret < 0) {
524 dev_err(&psys->adev->dev,
525 "failed to power gating off\n");
526 pm_runtime_get_sync(&psys->adev->dev);
527
528 }
529 mutex_unlock(&kppg->mutex);
530 }
531 mutex_unlock(&fh->mutex);
532 }
533}
534
535void ipu_psys_exit_power_gating(struct ipu_psys *psys)
536{
537 struct ipu_psys_scheduler *sched;
538 struct ipu_psys_ppg *kppg;
539 struct ipu_psys_fh *fh;
540 int ret = 0;
541
542 list_for_each_entry(fh, &psys->fhs, list) {
543 mutex_lock(&fh->mutex);
544 sched = &fh->sched;
545 if (list_empty(&sched->ppgs)) {
546 mutex_unlock(&fh->mutex);
547 continue;
548 }
549
550 list_for_each_entry(kppg, &sched->ppgs, list) {
551 mutex_lock(&kppg->mutex);
552 /* kppg is not started and power up */
553 if (kppg->state == PPG_STATE_START ||
554 kppg->state == PPG_STATE_STARTING) {
555 mutex_unlock(&kppg->mutex);
556 continue;
557 }
558
559 ret = pm_runtime_get_sync(&psys->adev->dev);
560 if (ret < 0) {
561 dev_err(&psys->adev->dev,
562 "failed to power gating\n");
563 pm_runtime_put_noidle(&psys->adev->dev);
564 }
565 mutex_unlock(&kppg->mutex);
566 }
567 mutex_unlock(&fh->mutex);
568 }
569}