1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
4 *
5 * Copyright (c) 2010 Samsung Electronics Co., Ltd.
6 *		http://www.samsung.com/
7 */
8
9#include <linux/delay.h>
10#include <linux/err.h>
11#include <linux/firmware.h>
12#include <linux/jiffies.h>
13#include <linux/sched.h>
14#include "s5p_mfc_cmd.h"
15#include "s5p_mfc_common.h"
16#include "s5p_mfc_debug.h"
17#include "s5p_mfc_intr.h"
18#include "s5p_mfc_opr.h"
19#include "s5p_mfc_pm.h"
20#include "s5p_mfc_ctrl.h"
21
22/* Allocate memory for firmware */
23int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
24{
25	struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf;
26	int err;
27
28	fw_buf->size = dev->variant->buf_size->fw;
29
30	if (fw_buf->virt) {
31		mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
32		return -ENOMEM;
33	}
34
35	err = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->fw_buf);
36	if (err) {
37		mfc_err("Allocating bitprocessor buffer failed\n");
38		return err;
39	}
40
41	return 0;
42}
43
44/* Load firmware */
45int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
46{
47	struct firmware *fw_blob;
48	int i, err = -EINVAL;
49
50	/* Firmware has to be present as a separate file or compiled
51	 * into kernel. */
52	mfc_debug_enter();
53
54	/* In case of MFC v12, RET_SYS_INIT response from hardware fails due to
55	 * incorrect firmware transfer and therefore it is not able to initialize
56	 * the hardware. This causes failed response for SYS_INIT command when
57	 * MFC runs for second time. So, load the MFC v12 firmware for each run.
58	 */
59	if (!IS_MFCV12(dev))
60		if (dev->fw_get_done)
61			return 0;
62
63	for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) {
64		if (!dev->variant->fw_name[i])
65			continue;
66		err = request_firmware((const struct firmware **)&fw_blob,
67				dev->variant->fw_name[i], &dev->plat_dev->dev);
68		if (!err) {
69			dev->fw_ver = (enum s5p_mfc_fw_ver) i;
70			break;
71		}
72	}
73
74	if (err != 0) {
75		mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
76		return -EINVAL;
77	}
78	if (fw_blob->size > dev->fw_buf.size) {
79		mfc_err("MFC firmware is too big to be loaded\n");
80		release_firmware(fw_blob);
81		return -ENOMEM;
82	}
83	memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->size);
84	wmb();
85	dev->fw_get_done = true;
86	release_firmware(fw_blob);
87	mfc_debug_leave();
88	return 0;
89}
90
91/* Release firmware memory */
92int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
93{
94	/* Before calling this function one has to make sure
95	 * that MFC is no longer processing */
96	s5p_mfc_release_priv_buf(dev, &dev->fw_buf);
97	dev->fw_get_done = false;
98	return 0;
99}
100
101static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev)
102{
103	unsigned int status;
104	unsigned long timeout;
105
106	/* Reset */
107	mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
108	timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
109	/* Check bus status */
110	do {
111		if (time_after(jiffies, timeout)) {
112			mfc_err("Timeout while resetting MFC.\n");
113			return -EIO;
114		}
115		status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL);
116	} while ((status & 0x2) == 0);
117	return 0;
118}
119
120/* Reset the device */
121int s5p_mfc_reset(struct s5p_mfc_dev *dev)
122{
123	unsigned int mc_status;
124	unsigned long timeout;
125	int i;
126
127	mfc_debug_enter();
128
129	if (IS_MFCV6_PLUS(dev)) {
130		/* Zero Initialization of MFC registers */
131		mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
132		mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6);
133		mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6);
134
135		for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++)
136			mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
137
138		/* check bus reset control before reset */
139		if (dev->risc_on && !IS_MFCV12(dev))
140			if (s5p_mfc_bus_reset(dev))
141				return -EIO;
142		/* Reset
143		 * set RISC_ON to 0 during power_on & wake_up.
144		 * V6 needs RISC_ON set to 0 during reset also.
145		 */
146		if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev)))
147			mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6);
148
149		mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6);
150		mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6);
151	} else {
152		/* Stop procedure */
153		/*  reset RISC */
154		mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
155		/*  All reset except for MC */
156		mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
157		mdelay(10);
158
159		timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
160		/* Check MC status */
161		do {
162			if (time_after(jiffies, timeout)) {
163				mfc_err("Timeout while resetting MFC\n");
164				return -EIO;
165			}
166
167			mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
168
169		} while (mc_status & 0x3);
170
171		mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
172		mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
173	}
174
175	mfc_debug_leave();
176	return 0;
177}
178
179static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
180{
181	if (IS_MFCV6_PLUS(dev)) {
182		mfc_write(dev, dev->dma_base[BANK_L_CTX],
183			  S5P_FIMV_RISC_BASE_ADDRESS_V6);
184		mfc_debug(2, "Base Address : %pad\n",
185			  &dev->dma_base[BANK_L_CTX]);
186	} else {
187		mfc_write(dev, dev->dma_base[BANK_L_CTX],
188			  S5P_FIMV_MC_DRAMBASE_ADR_A);
189		mfc_write(dev, dev->dma_base[BANK_R_CTX],
190			  S5P_FIMV_MC_DRAMBASE_ADR_B);
191		mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
192			  &dev->dma_base[BANK_L_CTX],
193			  &dev->dma_base[BANK_R_CTX]);
194	}
195}
196
197static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
198{
199	if (IS_MFCV6_PLUS(dev)) {
200		/* Zero initialization should be done before RESET.
201		 * Nothing to do here. */
202	} else {
203		mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
204		mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
205		mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
206		mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
207	}
208}
209
210/* Initialize hardware */
211int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
212{
213	unsigned int ver;
214	int ret;
215
216	mfc_debug_enter();
217	if (!dev->fw_buf.virt) {
218		mfc_err("Firmware memory is not allocated.\n");
219		return -EINVAL;
220	}
221
222	/* 0. MFC reset */
223	mfc_debug(2, "MFC reset..\n");
224	s5p_mfc_clock_on(dev);
225	dev->risc_on = 0;
226	ret = s5p_mfc_reset(dev);
227	if (ret) {
228		mfc_err("Failed to reset MFC - timeout\n");
229		return ret;
230	}
231	mfc_debug(2, "Done MFC reset..\n");
232	/* 1. Set DRAM base Addr */
233	s5p_mfc_init_memctrl(dev);
234	/* 2. Initialize registers of channel I/F */
235	s5p_mfc_clear_cmds(dev);
236	/* 3. Release reset signal to the RISC */
237	s5p_mfc_clean_dev_int_flags(dev);
238	if (IS_MFCV6_PLUS(dev)) {
239		dev->risc_on = 1;
240		mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
241	}
242	else
243		mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
244
245	if (IS_MFCV10_PLUS(dev))
246		mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10);
247
248	mfc_debug(2, "Will now wait for completion of firmware transfer\n");
249	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
250		mfc_err("Failed to load firmware\n");
251		s5p_mfc_reset(dev);
252		s5p_mfc_clock_off(dev);
253		return -EIO;
254	}
255	s5p_mfc_clean_dev_int_flags(dev);
256	/* 4. Initialize firmware */
257	ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev);
258	if (ret) {
259		mfc_err("Failed to send command to MFC - timeout\n");
260		s5p_mfc_reset(dev);
261		s5p_mfc_clock_off(dev);
262		return ret;
263	}
264	mfc_debug(2, "Ok, now will wait for completion of hardware init\n");
265	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
266		mfc_err("Failed to init hardware\n");
267		s5p_mfc_reset(dev);
268		s5p_mfc_clock_off(dev);
269		return -EIO;
270	}
271	dev->int_cond = 0;
272	if (dev->int_err != 0 || dev->int_type !=
273					S5P_MFC_R2H_CMD_SYS_INIT_RET) {
274		/* Failure. */
275		mfc_err("Failed to init firmware - error: %d int: %d\n",
276						dev->int_err, dev->int_type);
277		s5p_mfc_reset(dev);
278		s5p_mfc_clock_off(dev);
279		return -EIO;
280	}
281	if (IS_MFCV6_PLUS(dev))
282		ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6);
283	else
284		ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
285
286	mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
287		(ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
288	s5p_mfc_clock_off(dev);
289	mfc_debug_leave();
290	return 0;
291}
292
293
294/* Deinitialize hardware */
295void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
296{
297	s5p_mfc_clock_on(dev);
298
299	s5p_mfc_reset(dev);
300	s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
301
302	s5p_mfc_clock_off(dev);
303}
304
305int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
306{
307	int ret;
308
309	mfc_debug_enter();
310	s5p_mfc_clock_on(dev);
311	s5p_mfc_clean_dev_int_flags(dev);
312	ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev);
313	if (ret) {
314		mfc_err("Failed to send command to MFC - timeout\n");
315		return ret;
316	}
317	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) {
318		mfc_err("Failed to sleep\n");
319		return -EIO;
320	}
321	s5p_mfc_clock_off(dev);
322	dev->int_cond = 0;
323	if (dev->int_err != 0 || dev->int_type !=
324						S5P_MFC_R2H_CMD_SLEEP_RET) {
325		/* Failure. */
326		mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
327								dev->int_type);
328		return -EIO;
329	}
330	mfc_debug_leave();
331	return ret;
332}
333
334static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev)
335{
336	int ret;
337
338	/* Release reset signal to the RISC */
339	dev->risc_on = 1;
340	mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
341
342	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
343		mfc_err("Failed to reset MFCV8\n");
344		return -EIO;
345	}
346	mfc_debug(2, "Write command to wakeup MFCV8\n");
347	ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
348	if (ret) {
349		mfc_err("Failed to send command to MFCV8 - timeout\n");
350		return ret;
351	}
352
353	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
354		mfc_err("Failed to wakeup MFC\n");
355		return -EIO;
356	}
357	return ret;
358}
359
360static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev)
361{
362	int ret;
363
364	/* Send MFC wakeup command */
365	ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
366	if (ret) {
367		mfc_err("Failed to send command to MFC - timeout\n");
368		return ret;
369	}
370
371	/* Release reset signal to the RISC */
372	if (IS_MFCV6_PLUS(dev)) {
373		dev->risc_on = 1;
374		mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
375	} else {
376		mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
377	}
378
379	if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
380		mfc_err("Failed to wakeup MFC\n");
381		return -EIO;
382	}
383	return ret;
384}
385
386int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
387{
388	int ret;
389
390	mfc_debug_enter();
391	/* 0. MFC reset */
392	mfc_debug(2, "MFC reset..\n");
393	s5p_mfc_clock_on(dev);
394	dev->risc_on = 0;
395	ret = s5p_mfc_reset(dev);
396	if (ret) {
397		mfc_err("Failed to reset MFC - timeout\n");
398		s5p_mfc_clock_off(dev);
399		return ret;
400	}
401	mfc_debug(2, "Done MFC reset..\n");
402	/* 1. Set DRAM base Addr */
403	s5p_mfc_init_memctrl(dev);
404	/* 2. Initialize registers of channel I/F */
405	s5p_mfc_clear_cmds(dev);
406	s5p_mfc_clean_dev_int_flags(dev);
407	/* 3. Send MFC wakeup command and wait for completion*/
408	if (IS_MFCV8_PLUS(dev))
409		ret = s5p_mfc_v8_wait_wakeup(dev);
410	else
411		ret = s5p_mfc_wait_wakeup(dev);
412
413	s5p_mfc_clock_off(dev);
414	if (ret)
415		return ret;
416
417	dev->int_cond = 0;
418	if (dev->int_err != 0 || dev->int_type !=
419						S5P_MFC_R2H_CMD_WAKEUP_RET) {
420		/* Failure. */
421		mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
422								dev->int_type);
423		return -EIO;
424	}
425	mfc_debug_leave();
426	return 0;
427}
428
429int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
430{
431	int ret = 0;
432
433	ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx);
434	if (ret) {
435		mfc_err("Failed allocating instance buffer\n");
436		goto err;
437	}
438
439	if (ctx->type == MFCINST_DECODER) {
440		ret = s5p_mfc_hw_call(dev->mfc_ops,
441					alloc_dec_temp_buffers, ctx);
442		if (ret) {
443			mfc_err("Failed allocating temporary buffers\n");
444			goto err_free_inst_buf;
445		}
446	}
447
448	set_work_bit_irqsave(ctx);
449	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
450	if (s5p_mfc_wait_for_done_ctx(ctx,
451		S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
452		/* Error or timeout */
453		mfc_err("Error getting instance from hardware\n");
454		ret = -EIO;
455		goto err_free_desc_buf;
456	}
457
458	mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
459	return ret;
460
461err_free_desc_buf:
462	if (ctx->type == MFCINST_DECODER)
463		s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
464err_free_inst_buf:
465	s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
466err:
467	return ret;
468}
469
470void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
471{
472	ctx->state = MFCINST_RETURN_INST;
473	set_work_bit_irqsave(ctx);
474	s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
475	/* Wait until instance is returned or timeout occurred */
476	if (s5p_mfc_wait_for_done_ctx(ctx,
477				S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)){
478		clear_work_bit_irqsave(ctx);
479		mfc_err("Err returning instance\n");
480	}
481
482	/* Free resources */
483	s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
484	s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
485	if (ctx->type == MFCINST_DECODER)
486		s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
487
488	ctx->inst_no = MFC_NO_INSTANCE_SET;
489	ctx->state = MFCINST_FREE;
490}
491