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