143ecec16SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0-or-later
243ecec16SMauro Carvalho Chehab /*
343ecec16SMauro Carvalho Chehab * linux/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c
443ecec16SMauro Carvalho Chehab *
543ecec16SMauro Carvalho Chehab * Copyright (c) 2010 Samsung Electronics Co., Ltd.
643ecec16SMauro Carvalho Chehab * http://www.samsung.com/
743ecec16SMauro Carvalho Chehab */
843ecec16SMauro Carvalho Chehab
943ecec16SMauro Carvalho Chehab #include <linux/delay.h>
1043ecec16SMauro Carvalho Chehab #include <linux/err.h>
1143ecec16SMauro Carvalho Chehab #include <linux/firmware.h>
1243ecec16SMauro Carvalho Chehab #include <linux/jiffies.h>
1343ecec16SMauro Carvalho Chehab #include <linux/sched.h>
1443ecec16SMauro Carvalho Chehab #include "s5p_mfc_cmd.h"
1543ecec16SMauro Carvalho Chehab #include "s5p_mfc_common.h"
1643ecec16SMauro Carvalho Chehab #include "s5p_mfc_debug.h"
1743ecec16SMauro Carvalho Chehab #include "s5p_mfc_intr.h"
1843ecec16SMauro Carvalho Chehab #include "s5p_mfc_opr.h"
1943ecec16SMauro Carvalho Chehab #include "s5p_mfc_pm.h"
2043ecec16SMauro Carvalho Chehab #include "s5p_mfc_ctrl.h"
2143ecec16SMauro Carvalho Chehab
2243ecec16SMauro Carvalho Chehab /* Allocate memory for firmware */
s5p_mfc_alloc_firmware(struct s5p_mfc_dev * dev)2343ecec16SMauro Carvalho Chehab int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
2443ecec16SMauro Carvalho Chehab {
2543ecec16SMauro Carvalho Chehab struct s5p_mfc_priv_buf *fw_buf = &dev->fw_buf;
2643ecec16SMauro Carvalho Chehab int err;
2743ecec16SMauro Carvalho Chehab
2843ecec16SMauro Carvalho Chehab fw_buf->size = dev->variant->buf_size->fw;
2943ecec16SMauro Carvalho Chehab
3043ecec16SMauro Carvalho Chehab if (fw_buf->virt) {
3143ecec16SMauro Carvalho Chehab mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
3243ecec16SMauro Carvalho Chehab return -ENOMEM;
3343ecec16SMauro Carvalho Chehab }
3443ecec16SMauro Carvalho Chehab
3543ecec16SMauro Carvalho Chehab err = s5p_mfc_alloc_priv_buf(dev, BANK_L_CTX, &dev->fw_buf);
3643ecec16SMauro Carvalho Chehab if (err) {
3743ecec16SMauro Carvalho Chehab mfc_err("Allocating bitprocessor buffer failed\n");
3843ecec16SMauro Carvalho Chehab return err;
3943ecec16SMauro Carvalho Chehab }
4043ecec16SMauro Carvalho Chehab
4143ecec16SMauro Carvalho Chehab return 0;
4243ecec16SMauro Carvalho Chehab }
4343ecec16SMauro Carvalho Chehab
4443ecec16SMauro Carvalho Chehab /* Load firmware */
s5p_mfc_load_firmware(struct s5p_mfc_dev * dev)4543ecec16SMauro Carvalho Chehab int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
4643ecec16SMauro Carvalho Chehab {
4743ecec16SMauro Carvalho Chehab struct firmware *fw_blob;
4843ecec16SMauro Carvalho Chehab int i, err = -EINVAL;
4943ecec16SMauro Carvalho Chehab
5043ecec16SMauro Carvalho Chehab /* Firmware has to be present as a separate file or compiled
5143ecec16SMauro Carvalho Chehab * into kernel. */
5243ecec16SMauro Carvalho Chehab mfc_debug_enter();
5343ecec16SMauro Carvalho Chehab
5443ecec16SMauro Carvalho Chehab if (dev->fw_get_done)
5543ecec16SMauro Carvalho Chehab return 0;
5643ecec16SMauro Carvalho Chehab
5743ecec16SMauro Carvalho Chehab for (i = MFC_FW_MAX_VERSIONS - 1; i >= 0; i--) {
5843ecec16SMauro Carvalho Chehab if (!dev->variant->fw_name[i])
5943ecec16SMauro Carvalho Chehab continue;
6043ecec16SMauro Carvalho Chehab err = request_firmware((const struct firmware **)&fw_blob,
6143ecec16SMauro Carvalho Chehab dev->variant->fw_name[i], &dev->plat_dev->dev);
6243ecec16SMauro Carvalho Chehab if (!err) {
6343ecec16SMauro Carvalho Chehab dev->fw_ver = (enum s5p_mfc_fw_ver) i;
6443ecec16SMauro Carvalho Chehab break;
6543ecec16SMauro Carvalho Chehab }
6643ecec16SMauro Carvalho Chehab }
6743ecec16SMauro Carvalho Chehab
6843ecec16SMauro Carvalho Chehab if (err != 0) {
6943ecec16SMauro Carvalho Chehab mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
7043ecec16SMauro Carvalho Chehab return -EINVAL;
7143ecec16SMauro Carvalho Chehab }
7243ecec16SMauro Carvalho Chehab if (fw_blob->size > dev->fw_buf.size) {
7343ecec16SMauro Carvalho Chehab mfc_err("MFC firmware is too big to be loaded\n");
7443ecec16SMauro Carvalho Chehab release_firmware(fw_blob);
7543ecec16SMauro Carvalho Chehab return -ENOMEM;
7643ecec16SMauro Carvalho Chehab }
7743ecec16SMauro Carvalho Chehab memcpy(dev->fw_buf.virt, fw_blob->data, fw_blob->size);
7843ecec16SMauro Carvalho Chehab wmb();
7943ecec16SMauro Carvalho Chehab dev->fw_get_done = true;
8043ecec16SMauro Carvalho Chehab release_firmware(fw_blob);
8143ecec16SMauro Carvalho Chehab mfc_debug_leave();
8243ecec16SMauro Carvalho Chehab return 0;
8343ecec16SMauro Carvalho Chehab }
8443ecec16SMauro Carvalho Chehab
8543ecec16SMauro Carvalho Chehab /* Release firmware memory */
s5p_mfc_release_firmware(struct s5p_mfc_dev * dev)8643ecec16SMauro Carvalho Chehab int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
8743ecec16SMauro Carvalho Chehab {
8843ecec16SMauro Carvalho Chehab /* Before calling this function one has to make sure
8943ecec16SMauro Carvalho Chehab * that MFC is no longer processing */
9043ecec16SMauro Carvalho Chehab s5p_mfc_release_priv_buf(dev, &dev->fw_buf);
9143ecec16SMauro Carvalho Chehab dev->fw_get_done = false;
9243ecec16SMauro Carvalho Chehab return 0;
9343ecec16SMauro Carvalho Chehab }
9443ecec16SMauro Carvalho Chehab
s5p_mfc_bus_reset(struct s5p_mfc_dev * dev)9543ecec16SMauro Carvalho Chehab static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev)
9643ecec16SMauro Carvalho Chehab {
9743ecec16SMauro Carvalho Chehab unsigned int status;
9843ecec16SMauro Carvalho Chehab unsigned long timeout;
9943ecec16SMauro Carvalho Chehab
10043ecec16SMauro Carvalho Chehab /* Reset */
10143ecec16SMauro Carvalho Chehab mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
10243ecec16SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
10343ecec16SMauro Carvalho Chehab /* Check bus status */
10443ecec16SMauro Carvalho Chehab do {
10543ecec16SMauro Carvalho Chehab if (time_after(jiffies, timeout)) {
10643ecec16SMauro Carvalho Chehab mfc_err("Timeout while resetting MFC.\n");
10743ecec16SMauro Carvalho Chehab return -EIO;
10843ecec16SMauro Carvalho Chehab }
10943ecec16SMauro Carvalho Chehab status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL);
11043ecec16SMauro Carvalho Chehab } while ((status & 0x2) == 0);
11143ecec16SMauro Carvalho Chehab return 0;
11243ecec16SMauro Carvalho Chehab }
11343ecec16SMauro Carvalho Chehab
11443ecec16SMauro Carvalho Chehab /* Reset the device */
s5p_mfc_reset(struct s5p_mfc_dev * dev)11543ecec16SMauro Carvalho Chehab int s5p_mfc_reset(struct s5p_mfc_dev *dev)
11643ecec16SMauro Carvalho Chehab {
11743ecec16SMauro Carvalho Chehab unsigned int mc_status;
11843ecec16SMauro Carvalho Chehab unsigned long timeout;
11943ecec16SMauro Carvalho Chehab int i;
12043ecec16SMauro Carvalho Chehab
12143ecec16SMauro Carvalho Chehab mfc_debug_enter();
12243ecec16SMauro Carvalho Chehab
12343ecec16SMauro Carvalho Chehab if (IS_MFCV6_PLUS(dev)) {
12443ecec16SMauro Carvalho Chehab /* Zero Initialization of MFC registers */
12543ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
12643ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6);
12743ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6);
12843ecec16SMauro Carvalho Chehab
12943ecec16SMauro Carvalho Chehab for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++)
13043ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
13143ecec16SMauro Carvalho Chehab
13243ecec16SMauro Carvalho Chehab /* check bus reset control before reset */
13343ecec16SMauro Carvalho Chehab if (dev->risc_on)
13443ecec16SMauro Carvalho Chehab if (s5p_mfc_bus_reset(dev))
13543ecec16SMauro Carvalho Chehab return -EIO;
13643ecec16SMauro Carvalho Chehab /* Reset
13743ecec16SMauro Carvalho Chehab * set RISC_ON to 0 during power_on & wake_up.
13843ecec16SMauro Carvalho Chehab * V6 needs RISC_ON set to 0 during reset also.
13943ecec16SMauro Carvalho Chehab */
14043ecec16SMauro Carvalho Chehab if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev)))
14143ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6);
14243ecec16SMauro Carvalho Chehab
14343ecec16SMauro Carvalho Chehab mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6);
14443ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6);
14543ecec16SMauro Carvalho Chehab } else {
14643ecec16SMauro Carvalho Chehab /* Stop procedure */
14743ecec16SMauro Carvalho Chehab /* reset RISC */
14843ecec16SMauro Carvalho Chehab mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
14943ecec16SMauro Carvalho Chehab /* All reset except for MC */
15043ecec16SMauro Carvalho Chehab mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
15143ecec16SMauro Carvalho Chehab mdelay(10);
15243ecec16SMauro Carvalho Chehab
15343ecec16SMauro Carvalho Chehab timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
15443ecec16SMauro Carvalho Chehab /* Check MC status */
15543ecec16SMauro Carvalho Chehab do {
15643ecec16SMauro Carvalho Chehab if (time_after(jiffies, timeout)) {
15743ecec16SMauro Carvalho Chehab mfc_err("Timeout while resetting MFC\n");
15843ecec16SMauro Carvalho Chehab return -EIO;
15943ecec16SMauro Carvalho Chehab }
16043ecec16SMauro Carvalho Chehab
16143ecec16SMauro Carvalho Chehab mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
16243ecec16SMauro Carvalho Chehab
16343ecec16SMauro Carvalho Chehab } while (mc_status & 0x3);
16443ecec16SMauro Carvalho Chehab
16543ecec16SMauro Carvalho Chehab mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
16643ecec16SMauro Carvalho Chehab mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
16743ecec16SMauro Carvalho Chehab }
16843ecec16SMauro Carvalho Chehab
16943ecec16SMauro Carvalho Chehab mfc_debug_leave();
17043ecec16SMauro Carvalho Chehab return 0;
17143ecec16SMauro Carvalho Chehab }
17243ecec16SMauro Carvalho Chehab
s5p_mfc_init_memctrl(struct s5p_mfc_dev * dev)17343ecec16SMauro Carvalho Chehab static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
17443ecec16SMauro Carvalho Chehab {
17543ecec16SMauro Carvalho Chehab if (IS_MFCV6_PLUS(dev)) {
17643ecec16SMauro Carvalho Chehab mfc_write(dev, dev->dma_base[BANK_L_CTX],
17743ecec16SMauro Carvalho Chehab S5P_FIMV_RISC_BASE_ADDRESS_V6);
17843ecec16SMauro Carvalho Chehab mfc_debug(2, "Base Address : %pad\n",
17943ecec16SMauro Carvalho Chehab &dev->dma_base[BANK_L_CTX]);
18043ecec16SMauro Carvalho Chehab } else {
18143ecec16SMauro Carvalho Chehab mfc_write(dev, dev->dma_base[BANK_L_CTX],
18243ecec16SMauro Carvalho Chehab S5P_FIMV_MC_DRAMBASE_ADR_A);
18343ecec16SMauro Carvalho Chehab mfc_write(dev, dev->dma_base[BANK_R_CTX],
18443ecec16SMauro Carvalho Chehab S5P_FIMV_MC_DRAMBASE_ADR_B);
18543ecec16SMauro Carvalho Chehab mfc_debug(2, "Bank1: %pad, Bank2: %pad\n",
18643ecec16SMauro Carvalho Chehab &dev->dma_base[BANK_L_CTX],
18743ecec16SMauro Carvalho Chehab &dev->dma_base[BANK_R_CTX]);
18843ecec16SMauro Carvalho Chehab }
18943ecec16SMauro Carvalho Chehab }
19043ecec16SMauro Carvalho Chehab
s5p_mfc_clear_cmds(struct s5p_mfc_dev * dev)19143ecec16SMauro Carvalho Chehab static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
19243ecec16SMauro Carvalho Chehab {
19343ecec16SMauro Carvalho Chehab if (IS_MFCV6_PLUS(dev)) {
19443ecec16SMauro Carvalho Chehab /* Zero initialization should be done before RESET.
19543ecec16SMauro Carvalho Chehab * Nothing to do here. */
19643ecec16SMauro Carvalho Chehab } else {
19743ecec16SMauro Carvalho Chehab mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
19843ecec16SMauro Carvalho Chehab mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
19943ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
20043ecec16SMauro Carvalho Chehab mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
20143ecec16SMauro Carvalho Chehab }
20243ecec16SMauro Carvalho Chehab }
20343ecec16SMauro Carvalho Chehab
20443ecec16SMauro Carvalho Chehab /* Initialize hardware */
s5p_mfc_init_hw(struct s5p_mfc_dev * dev)20543ecec16SMauro Carvalho Chehab int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
20643ecec16SMauro Carvalho Chehab {
20743ecec16SMauro Carvalho Chehab unsigned int ver;
20843ecec16SMauro Carvalho Chehab int ret;
20943ecec16SMauro Carvalho Chehab
21043ecec16SMauro Carvalho Chehab mfc_debug_enter();
21143ecec16SMauro Carvalho Chehab if (!dev->fw_buf.virt) {
21243ecec16SMauro Carvalho Chehab mfc_err("Firmware memory is not allocated.\n");
21343ecec16SMauro Carvalho Chehab return -EINVAL;
21443ecec16SMauro Carvalho Chehab }
21543ecec16SMauro Carvalho Chehab
21643ecec16SMauro Carvalho Chehab /* 0. MFC reset */
21743ecec16SMauro Carvalho Chehab mfc_debug(2, "MFC reset..\n");
21843ecec16SMauro Carvalho Chehab s5p_mfc_clock_on();
21943ecec16SMauro Carvalho Chehab dev->risc_on = 0;
22043ecec16SMauro Carvalho Chehab ret = s5p_mfc_reset(dev);
22143ecec16SMauro Carvalho Chehab if (ret) {
22243ecec16SMauro Carvalho Chehab mfc_err("Failed to reset MFC - timeout\n");
22343ecec16SMauro Carvalho Chehab return ret;
22443ecec16SMauro Carvalho Chehab }
22543ecec16SMauro Carvalho Chehab mfc_debug(2, "Done MFC reset..\n");
22643ecec16SMauro Carvalho Chehab /* 1. Set DRAM base Addr */
22743ecec16SMauro Carvalho Chehab s5p_mfc_init_memctrl(dev);
22843ecec16SMauro Carvalho Chehab /* 2. Initialize registers of channel I/F */
22943ecec16SMauro Carvalho Chehab s5p_mfc_clear_cmds(dev);
23043ecec16SMauro Carvalho Chehab /* 3. Release reset signal to the RISC */
23143ecec16SMauro Carvalho Chehab s5p_mfc_clean_dev_int_flags(dev);
23243ecec16SMauro Carvalho Chehab if (IS_MFCV6_PLUS(dev)) {
23343ecec16SMauro Carvalho Chehab dev->risc_on = 1;
23443ecec16SMauro Carvalho Chehab mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
23543ecec16SMauro Carvalho Chehab }
23643ecec16SMauro Carvalho Chehab else
23743ecec16SMauro Carvalho Chehab mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
23843ecec16SMauro Carvalho Chehab
23943ecec16SMauro Carvalho Chehab if (IS_MFCV10(dev))
24043ecec16SMauro Carvalho Chehab mfc_write(dev, 0x0, S5P_FIMV_MFC_CLOCK_OFF_V10);
24143ecec16SMauro Carvalho Chehab
24243ecec16SMauro Carvalho Chehab mfc_debug(2, "Will now wait for completion of firmware transfer\n");
24343ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
24443ecec16SMauro Carvalho Chehab mfc_err("Failed to load firmware\n");
24543ecec16SMauro Carvalho Chehab s5p_mfc_reset(dev);
24643ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
24743ecec16SMauro Carvalho Chehab return -EIO;
24843ecec16SMauro Carvalho Chehab }
24943ecec16SMauro Carvalho Chehab s5p_mfc_clean_dev_int_flags(dev);
25043ecec16SMauro Carvalho Chehab /* 4. Initialize firmware */
25143ecec16SMauro Carvalho Chehab ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev);
25243ecec16SMauro Carvalho Chehab if (ret) {
25343ecec16SMauro Carvalho Chehab mfc_err("Failed to send command to MFC - timeout\n");
25443ecec16SMauro Carvalho Chehab s5p_mfc_reset(dev);
25543ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
25643ecec16SMauro Carvalho Chehab return ret;
25743ecec16SMauro Carvalho Chehab }
25843ecec16SMauro Carvalho Chehab mfc_debug(2, "Ok, now will wait for completion of hardware init\n");
25943ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
26043ecec16SMauro Carvalho Chehab mfc_err("Failed to init hardware\n");
26143ecec16SMauro Carvalho Chehab s5p_mfc_reset(dev);
26243ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
26343ecec16SMauro Carvalho Chehab return -EIO;
26443ecec16SMauro Carvalho Chehab }
26543ecec16SMauro Carvalho Chehab dev->int_cond = 0;
26643ecec16SMauro Carvalho Chehab if (dev->int_err != 0 || dev->int_type !=
26743ecec16SMauro Carvalho Chehab S5P_MFC_R2H_CMD_SYS_INIT_RET) {
26843ecec16SMauro Carvalho Chehab /* Failure. */
26943ecec16SMauro Carvalho Chehab mfc_err("Failed to init firmware - error: %d int: %d\n",
27043ecec16SMauro Carvalho Chehab dev->int_err, dev->int_type);
27143ecec16SMauro Carvalho Chehab s5p_mfc_reset(dev);
27243ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
27343ecec16SMauro Carvalho Chehab return -EIO;
27443ecec16SMauro Carvalho Chehab }
27543ecec16SMauro Carvalho Chehab if (IS_MFCV6_PLUS(dev))
27643ecec16SMauro Carvalho Chehab ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6);
27743ecec16SMauro Carvalho Chehab else
27843ecec16SMauro Carvalho Chehab ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
27943ecec16SMauro Carvalho Chehab
28043ecec16SMauro Carvalho Chehab mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
28143ecec16SMauro Carvalho Chehab (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
28243ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
28343ecec16SMauro Carvalho Chehab mfc_debug_leave();
28443ecec16SMauro Carvalho Chehab return 0;
28543ecec16SMauro Carvalho Chehab }
28643ecec16SMauro Carvalho Chehab
28743ecec16SMauro Carvalho Chehab
28843ecec16SMauro Carvalho Chehab /* Deinitialize hardware */
s5p_mfc_deinit_hw(struct s5p_mfc_dev * dev)28943ecec16SMauro Carvalho Chehab void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
29043ecec16SMauro Carvalho Chehab {
29143ecec16SMauro Carvalho Chehab s5p_mfc_clock_on();
29243ecec16SMauro Carvalho Chehab
29343ecec16SMauro Carvalho Chehab s5p_mfc_reset(dev);
29443ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
29543ecec16SMauro Carvalho Chehab
29643ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
29743ecec16SMauro Carvalho Chehab }
29843ecec16SMauro Carvalho Chehab
s5p_mfc_sleep(struct s5p_mfc_dev * dev)29943ecec16SMauro Carvalho Chehab int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
30043ecec16SMauro Carvalho Chehab {
30143ecec16SMauro Carvalho Chehab int ret;
30243ecec16SMauro Carvalho Chehab
30343ecec16SMauro Carvalho Chehab mfc_debug_enter();
30443ecec16SMauro Carvalho Chehab s5p_mfc_clock_on();
30543ecec16SMauro Carvalho Chehab s5p_mfc_clean_dev_int_flags(dev);
30643ecec16SMauro Carvalho Chehab ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev);
30743ecec16SMauro Carvalho Chehab if (ret) {
30843ecec16SMauro Carvalho Chehab mfc_err("Failed to send command to MFC - timeout\n");
30943ecec16SMauro Carvalho Chehab return ret;
31043ecec16SMauro Carvalho Chehab }
31143ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) {
31243ecec16SMauro Carvalho Chehab mfc_err("Failed to sleep\n");
31343ecec16SMauro Carvalho Chehab return -EIO;
31443ecec16SMauro Carvalho Chehab }
31543ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
31643ecec16SMauro Carvalho Chehab dev->int_cond = 0;
31743ecec16SMauro Carvalho Chehab if (dev->int_err != 0 || dev->int_type !=
31843ecec16SMauro Carvalho Chehab S5P_MFC_R2H_CMD_SLEEP_RET) {
31943ecec16SMauro Carvalho Chehab /* Failure. */
32043ecec16SMauro Carvalho Chehab mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
32143ecec16SMauro Carvalho Chehab dev->int_type);
32243ecec16SMauro Carvalho Chehab return -EIO;
32343ecec16SMauro Carvalho Chehab }
32443ecec16SMauro Carvalho Chehab mfc_debug_leave();
32543ecec16SMauro Carvalho Chehab return ret;
32643ecec16SMauro Carvalho Chehab }
32743ecec16SMauro Carvalho Chehab
s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev * dev)32843ecec16SMauro Carvalho Chehab static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev)
32943ecec16SMauro Carvalho Chehab {
33043ecec16SMauro Carvalho Chehab int ret;
33143ecec16SMauro Carvalho Chehab
33243ecec16SMauro Carvalho Chehab /* Release reset signal to the RISC */
33343ecec16SMauro Carvalho Chehab dev->risc_on = 1;
33443ecec16SMauro Carvalho Chehab mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
33543ecec16SMauro Carvalho Chehab
33643ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
33743ecec16SMauro Carvalho Chehab mfc_err("Failed to reset MFCV8\n");
33843ecec16SMauro Carvalho Chehab return -EIO;
33943ecec16SMauro Carvalho Chehab }
34043ecec16SMauro Carvalho Chehab mfc_debug(2, "Write command to wakeup MFCV8\n");
34143ecec16SMauro Carvalho Chehab ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
34243ecec16SMauro Carvalho Chehab if (ret) {
34343ecec16SMauro Carvalho Chehab mfc_err("Failed to send command to MFCV8 - timeout\n");
34443ecec16SMauro Carvalho Chehab return ret;
34543ecec16SMauro Carvalho Chehab }
34643ecec16SMauro Carvalho Chehab
34743ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
34843ecec16SMauro Carvalho Chehab mfc_err("Failed to wakeup MFC\n");
34943ecec16SMauro Carvalho Chehab return -EIO;
35043ecec16SMauro Carvalho Chehab }
35143ecec16SMauro Carvalho Chehab return ret;
35243ecec16SMauro Carvalho Chehab }
35343ecec16SMauro Carvalho Chehab
s5p_mfc_wait_wakeup(struct s5p_mfc_dev * dev)35443ecec16SMauro Carvalho Chehab static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev)
35543ecec16SMauro Carvalho Chehab {
35643ecec16SMauro Carvalho Chehab int ret;
35743ecec16SMauro Carvalho Chehab
35843ecec16SMauro Carvalho Chehab /* Send MFC wakeup command */
35943ecec16SMauro Carvalho Chehab ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
36043ecec16SMauro Carvalho Chehab if (ret) {
36143ecec16SMauro Carvalho Chehab mfc_err("Failed to send command to MFC - timeout\n");
36243ecec16SMauro Carvalho Chehab return ret;
36343ecec16SMauro Carvalho Chehab }
36443ecec16SMauro Carvalho Chehab
36543ecec16SMauro Carvalho Chehab /* Release reset signal to the RISC */
36643ecec16SMauro Carvalho Chehab if (IS_MFCV6_PLUS(dev)) {
36743ecec16SMauro Carvalho Chehab dev->risc_on = 1;
36843ecec16SMauro Carvalho Chehab mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
36943ecec16SMauro Carvalho Chehab } else {
37043ecec16SMauro Carvalho Chehab mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
37143ecec16SMauro Carvalho Chehab }
37243ecec16SMauro Carvalho Chehab
37343ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
37443ecec16SMauro Carvalho Chehab mfc_err("Failed to wakeup MFC\n");
37543ecec16SMauro Carvalho Chehab return -EIO;
37643ecec16SMauro Carvalho Chehab }
37743ecec16SMauro Carvalho Chehab return ret;
37843ecec16SMauro Carvalho Chehab }
37943ecec16SMauro Carvalho Chehab
s5p_mfc_wakeup(struct s5p_mfc_dev * dev)38043ecec16SMauro Carvalho Chehab int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
38143ecec16SMauro Carvalho Chehab {
38243ecec16SMauro Carvalho Chehab int ret;
38343ecec16SMauro Carvalho Chehab
38443ecec16SMauro Carvalho Chehab mfc_debug_enter();
38543ecec16SMauro Carvalho Chehab /* 0. MFC reset */
38643ecec16SMauro Carvalho Chehab mfc_debug(2, "MFC reset..\n");
38743ecec16SMauro Carvalho Chehab s5p_mfc_clock_on();
38843ecec16SMauro Carvalho Chehab dev->risc_on = 0;
38943ecec16SMauro Carvalho Chehab ret = s5p_mfc_reset(dev);
39043ecec16SMauro Carvalho Chehab if (ret) {
39143ecec16SMauro Carvalho Chehab mfc_err("Failed to reset MFC - timeout\n");
39243ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
39343ecec16SMauro Carvalho Chehab return ret;
39443ecec16SMauro Carvalho Chehab }
39543ecec16SMauro Carvalho Chehab mfc_debug(2, "Done MFC reset..\n");
39643ecec16SMauro Carvalho Chehab /* 1. Set DRAM base Addr */
39743ecec16SMauro Carvalho Chehab s5p_mfc_init_memctrl(dev);
39843ecec16SMauro Carvalho Chehab /* 2. Initialize registers of channel I/F */
39943ecec16SMauro Carvalho Chehab s5p_mfc_clear_cmds(dev);
40043ecec16SMauro Carvalho Chehab s5p_mfc_clean_dev_int_flags(dev);
40143ecec16SMauro Carvalho Chehab /* 3. Send MFC wakeup command and wait for completion*/
40243ecec16SMauro Carvalho Chehab if (IS_MFCV8_PLUS(dev))
40343ecec16SMauro Carvalho Chehab ret = s5p_mfc_v8_wait_wakeup(dev);
40443ecec16SMauro Carvalho Chehab else
40543ecec16SMauro Carvalho Chehab ret = s5p_mfc_wait_wakeup(dev);
40643ecec16SMauro Carvalho Chehab
40743ecec16SMauro Carvalho Chehab s5p_mfc_clock_off();
40843ecec16SMauro Carvalho Chehab if (ret)
40943ecec16SMauro Carvalho Chehab return ret;
41043ecec16SMauro Carvalho Chehab
41143ecec16SMauro Carvalho Chehab dev->int_cond = 0;
41243ecec16SMauro Carvalho Chehab if (dev->int_err != 0 || dev->int_type !=
41343ecec16SMauro Carvalho Chehab S5P_MFC_R2H_CMD_WAKEUP_RET) {
41443ecec16SMauro Carvalho Chehab /* Failure. */
41543ecec16SMauro Carvalho Chehab mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
41643ecec16SMauro Carvalho Chehab dev->int_type);
41743ecec16SMauro Carvalho Chehab return -EIO;
41843ecec16SMauro Carvalho Chehab }
41943ecec16SMauro Carvalho Chehab mfc_debug_leave();
42043ecec16SMauro Carvalho Chehab return 0;
42143ecec16SMauro Carvalho Chehab }
42243ecec16SMauro Carvalho Chehab
s5p_mfc_open_mfc_inst(struct s5p_mfc_dev * dev,struct s5p_mfc_ctx * ctx)42343ecec16SMauro Carvalho Chehab int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
42443ecec16SMauro Carvalho Chehab {
42543ecec16SMauro Carvalho Chehab int ret = 0;
42643ecec16SMauro Carvalho Chehab
42743ecec16SMauro Carvalho Chehab ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_instance_buffer, ctx);
42843ecec16SMauro Carvalho Chehab if (ret) {
42943ecec16SMauro Carvalho Chehab mfc_err("Failed allocating instance buffer\n");
43043ecec16SMauro Carvalho Chehab goto err;
43143ecec16SMauro Carvalho Chehab }
43243ecec16SMauro Carvalho Chehab
43343ecec16SMauro Carvalho Chehab if (ctx->type == MFCINST_DECODER) {
43443ecec16SMauro Carvalho Chehab ret = s5p_mfc_hw_call(dev->mfc_ops,
43543ecec16SMauro Carvalho Chehab alloc_dec_temp_buffers, ctx);
43643ecec16SMauro Carvalho Chehab if (ret) {
43743ecec16SMauro Carvalho Chehab mfc_err("Failed allocating temporary buffers\n");
43843ecec16SMauro Carvalho Chehab goto err_free_inst_buf;
43943ecec16SMauro Carvalho Chehab }
44043ecec16SMauro Carvalho Chehab }
44143ecec16SMauro Carvalho Chehab
44243ecec16SMauro Carvalho Chehab set_work_bit_irqsave(ctx);
44343ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
44443ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_ctx(ctx,
44543ecec16SMauro Carvalho Chehab S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
44643ecec16SMauro Carvalho Chehab /* Error or timeout */
44743ecec16SMauro Carvalho Chehab mfc_err("Error getting instance from hardware\n");
44843ecec16SMauro Carvalho Chehab ret = -EIO;
44943ecec16SMauro Carvalho Chehab goto err_free_desc_buf;
45043ecec16SMauro Carvalho Chehab }
45143ecec16SMauro Carvalho Chehab
45243ecec16SMauro Carvalho Chehab mfc_debug(2, "Got instance number: %d\n", ctx->inst_no);
45343ecec16SMauro Carvalho Chehab return ret;
45443ecec16SMauro Carvalho Chehab
45543ecec16SMauro Carvalho Chehab err_free_desc_buf:
45643ecec16SMauro Carvalho Chehab if (ctx->type == MFCINST_DECODER)
45743ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
45843ecec16SMauro Carvalho Chehab err_free_inst_buf:
45943ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
46043ecec16SMauro Carvalho Chehab err:
46143ecec16SMauro Carvalho Chehab return ret;
46243ecec16SMauro Carvalho Chehab }
46343ecec16SMauro Carvalho Chehab
s5p_mfc_close_mfc_inst(struct s5p_mfc_dev * dev,struct s5p_mfc_ctx * ctx)46443ecec16SMauro Carvalho Chehab void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
46543ecec16SMauro Carvalho Chehab {
46643ecec16SMauro Carvalho Chehab ctx->state = MFCINST_RETURN_INST;
46743ecec16SMauro Carvalho Chehab set_work_bit_irqsave(ctx);
46843ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, try_run, dev);
46943ecec16SMauro Carvalho Chehab /* Wait until instance is returned or timeout occurred */
47043ecec16SMauro Carvalho Chehab if (s5p_mfc_wait_for_done_ctx(ctx,
471*d3f3c2feSSmitha T Murthy S5P_MFC_R2H_CMD_CLOSE_INSTANCE_RET, 0)){
472*d3f3c2feSSmitha T Murthy clear_work_bit_irqsave(ctx);
47343ecec16SMauro Carvalho Chehab mfc_err("Err returning instance\n");
474*d3f3c2feSSmitha T Murthy }
47543ecec16SMauro Carvalho Chehab
47643ecec16SMauro Carvalho Chehab /* Free resources */
47743ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx);
47843ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx);
47943ecec16SMauro Carvalho Chehab if (ctx->type == MFCINST_DECODER)
48043ecec16SMauro Carvalho Chehab s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx);
48143ecec16SMauro Carvalho Chehab
48243ecec16SMauro Carvalho Chehab ctx->inst_no = MFC_NO_INSTANCE_SET;
48343ecec16SMauro Carvalho Chehab ctx->state = MFCINST_FREE;
48443ecec16SMauro Carvalho Chehab }
485