Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 1 | /* |
Mauro Carvalho Chehab | 2c3fb08 | 2012-08-14 17:31:16 -0300 | [diff] [blame] | 2 | * linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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> |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 18 | #include "s5p_mfc_cmd.h" |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 19 | #include "s5p_mfc_common.h" |
| 20 | #include "s5p_mfc_debug.h" |
| 21 | #include "s5p_mfc_intr.h" |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 22 | #include "s5p_mfc_opr.h" |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 23 | #include "s5p_mfc_pm.h" |
Mauro Carvalho Chehab | b171e3d | 2014-08-26 10:58:23 -0300 | [diff] [blame] | 24 | #include "s5p_mfc_ctrl.h" |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 25 | |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 26 | /* Allocate memory for firmware */ |
| 27 | int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev) |
| 28 | { |
| 29 | void *bank2_virt; |
| 30 | dma_addr_t bank2_dma_addr; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 31 | |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 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 | |
Maurizio Lombardi | 69b9fe2 | 2014-06-27 06:28:31 -0300 | [diff] [blame] | 42 | if (!dev->fw_virt_addr) { |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 43 | mfc_err("Allocating bitprocessor buffer failed\n"); |
| 44 | return -ENOMEM; |
| 45 | } |
| 46 | |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 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 | |
Maurizio Lombardi | 69b9fe2 | 2014-06-27 06:28:31 -0300 | [diff] [blame] | 51 | if (!bank2_virt) { |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 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. |
Jonathan McCrohan | 39c1cb2 | 2013-10-20 21:34:01 -0300 | [diff] [blame] | 70 | * Firmware will always occupy the beginning of this area so it is |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 71 | * impossible having a video frame buffer with zero address. */ |
| 72 | dev->bank2 = dev->bank1; |
| 73 | } |
| 74 | return 0; |
| 75 | } |
| 76 | |
| 77 | /* Load firmware */ |
| 78 | int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev) |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 79 | { |
| 80 | struct firmware *fw_blob; |
Arun Kumar K | 77ba6b7 | 2014-05-21 06:29:30 -0300 | [diff] [blame] | 81 | int i, err = -EINVAL; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 82 | |
| 83 | /* Firmare has to be present as a separate file or compiled |
| 84 | * into kernel. */ |
| 85 | mfc_debug_enter(); |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 86 | |
Arun Kumar K | 77ba6b7 | 2014-05-21 06:29:30 -0300 | [diff] [blame] | 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 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 | } |
Arun Kumar K | 8f532a7 | 2012-10-03 22:19:09 -0300 | [diff] [blame] | 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 | } |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 107 | if (!dev->fw_virt_addr) { |
| 108 | mfc_err("MFC firmware is not allocated\n"); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 109 | release_firmware(fw_blob); |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 110 | return -EINVAL; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 111 | } |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 112 | memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 113 | wmb(); |
| 114 | release_firmware(fw_blob); |
| 115 | mfc_debug_leave(); |
| 116 | return 0; |
| 117 | } |
| 118 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 119 | /* Release firmware memory */ |
| 120 | int 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 */ |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 124 | if (!dev->fw_virt_addr) |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 125 | return -EINVAL; |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 126 | dma_free_coherent(dev->mem_dev_l, dev->fw_size, dev->fw_virt_addr, |
| 127 | dev->bank1); |
| 128 | dev->fw_virt_addr = NULL; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 129 | return 0; |
| 130 | } |
| 131 | |
Mauro Carvalho Chehab | 5932f74 | 2014-10-28 15:48:50 -0200 | [diff] [blame] | 132 | static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev) |
Kiran AVND | 09accda | 2014-10-21 08:07:00 -0300 | [diff] [blame] | 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 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 151 | /* Reset the device */ |
| 152 | int s5p_mfc_reset(struct s5p_mfc_dev *dev) |
| 153 | { |
| 154 | unsigned int mc_status; |
| 155 | unsigned long timeout; |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 156 | int i; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 157 | |
| 158 | mfc_debug_enter(); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 159 | |
Arun Kumar K | 722b979 | 2013-07-09 01:24:36 -0300 | [diff] [blame] | 160 | if (IS_MFCV6_PLUS(dev)) { |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 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); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 165 | |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 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)); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 168 | |
Kiran AVND | 09accda | 2014-10-21 08:07:00 -0300 | [diff] [blame] | 169 | /* check bus reset control before reset */ |
| 170 | if (dev->risc_on) |
| 171 | if (s5p_mfc_bus_reset(dev)) |
| 172 | return -EIO; |
Kiran AVND | d7dce6a | 2014-10-21 08:06:59 -0300 | [diff] [blame] | 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 | */ |
Kiran AVND | 09accda | 2014-10-21 08:07:00 -0300 | [diff] [blame] | 177 | if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev))) |
Kiran AVND | d7dce6a | 2014-10-21 08:06:59 -0300 | [diff] [blame] | 178 | mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6); |
| 179 | |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 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 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 206 | mfc_debug_leave(); |
| 207 | return 0; |
| 208 | } |
| 209 | |
| 210 | static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) |
| 211 | { |
Arun Kumar K | 722b979 | 2013-07-09 01:24:36 -0300 | [diff] [blame] | 212 | if (IS_MFCV6_PLUS(dev)) { |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 213 | mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6); |
Mauro Carvalho Chehab | 03ce781 | 2014-09-24 19:07:36 -0300 | [diff] [blame] | 214 | mfc_debug(2, "Base Address : %pad\n", &dev->bank1); |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 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); |
Mauro Carvalho Chehab | 03ce781 | 2014-09-24 19:07:36 -0300 | [diff] [blame] | 218 | mfc_debug(2, "Bank1: %pad, Bank2: %pad\n", |
| 219 | &dev->bank1, &dev->bank2); |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 220 | } |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 221 | } |
| 222 | |
| 223 | static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) |
| 224 | { |
Arun Kumar K | 722b979 | 2013-07-09 01:24:36 -0300 | [diff] [blame] | 225 | if (IS_MFCV6_PLUS(dev)) { |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 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 | } |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 234 | } |
| 235 | |
| 236 | /* Initialize hardware */ |
| 237 | int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) |
| 238 | { |
| 239 | unsigned int ver; |
| 240 | int ret; |
| 241 | |
| 242 | mfc_debug_enter(); |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 243 | if (!dev->fw_virt_addr) { |
| 244 | mfc_err("Firmware memory is not allocated.\n"); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 245 | return -EINVAL; |
Kamil Debski | 2e731e4 | 2013-01-03 11:02:07 -0300 | [diff] [blame] | 246 | } |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 247 | |
| 248 | /* 0. MFC reset */ |
| 249 | mfc_debug(2, "MFC reset..\n"); |
| 250 | s5p_mfc_clock_on(); |
Kiran AVND | d7dce6a | 2014-10-21 08:06:59 -0300 | [diff] [blame] | 251 | dev->risc_on = 0; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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); |
Kiran AVND | d7dce6a | 2014-10-21 08:06:59 -0300 | [diff] [blame] | 264 | if (IS_MFCV6_PLUS(dev)) { |
| 265 | dev->risc_on = 1; |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 266 | mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6); |
Kiran AVND | d7dce6a | 2014-10-21 08:06:59 -0300 | [diff] [blame] | 267 | } |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 268 | else |
| 269 | mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 270 | mfc_debug(2, "Will now wait for completion of firmware transfer\n"); |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 271 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 */ |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 279 | ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 | } |
Zhaowei Yuan | e47ccb1 | 2014-08-13 23:11:47 -0300 | [diff] [blame] | 286 | mfc_debug(2, "Ok, now will wait for completion of hardware init\n"); |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 287 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { |
Zhaowei Yuan | e47ccb1 | 2014-08-13 23:11:47 -0300 | [diff] [blame] | 288 | mfc_err("Failed to init hardware\n"); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 != |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 295 | S5P_MFC_R2H_CMD_SYS_INIT_RET) { |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 | } |
Arun Kumar K | 722b979 | 2013-07-09 01:24:36 -0300 | [diff] [blame] | 303 | if (IS_MFCV6_PLUS(dev)) |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 304 | ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6); |
| 305 | else |
| 306 | ver = mfc_read(dev, S5P_FIMV_FW_VERSION); |
| 307 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 | |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 316 | /* Deinitialize hardware */ |
| 317 | void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) |
| 318 | { |
| 319 | s5p_mfc_clock_on(); |
| 320 | |
| 321 | s5p_mfc_reset(dev); |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 322 | s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 323 | |
| 324 | s5p_mfc_clock_off(); |
| 325 | } |
| 326 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 327 | int 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); |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 334 | ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 335 | if (ret) { |
| 336 | mfc_err("Failed to send command to MFC - timeout\n"); |
| 337 | return ret; |
| 338 | } |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 339 | if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) { |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 != |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 346 | S5P_MFC_R2H_CMD_SLEEP_RET) { |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 | |
Arun Mankuzhi | 773e635 | 2014-10-21 08:07:02 -0300 | [diff] [blame] | 356 | static 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 | |
| 382 | static 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 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 408 | int 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(); |
Kiran AVND | d7dce6a | 2014-10-21 08:06:59 -0300 | [diff] [blame] | 416 | dev->risc_on = 0; |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 417 | ret = s5p_mfc_reset(dev); |
| 418 | if (ret) { |
| 419 | mfc_err("Failed to reset MFC - timeout\n"); |
Arun Mankuzhi | 773e635 | 2014-10-21 08:07:02 -0300 | [diff] [blame] | 420 | s5p_mfc_clock_off(); |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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); |
Arun Mankuzhi | 773e635 | 2014-10-21 08:07:02 -0300 | [diff] [blame] | 429 | /* 3. Send MFC wakeup command and wait for completion*/ |
| 430 | if (IS_MFCV8(dev)) |
| 431 | ret = s5p_mfc_v8_wait_wakeup(dev); |
Jeongtae Park | f96f3cf | 2012-10-03 22:19:11 -0300 | [diff] [blame] | 432 | else |
Arun Mankuzhi | 773e635 | 2014-10-21 08:07:02 -0300 | [diff] [blame] | 433 | ret = s5p_mfc_wait_wakeup(dev); |
| 434 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 435 | s5p_mfc_clock_off(); |
Arun Mankuzhi | 773e635 | 2014-10-21 08:07:02 -0300 | [diff] [blame] | 436 | if (ret) |
| 437 | return ret; |
| 438 | |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 439 | dev->int_cond = 0; |
| 440 | if (dev->int_err != 0 || dev->int_type != |
Arun Kumar K | 43a1ea1 | 2012-10-03 22:19:08 -0300 | [diff] [blame] | 441 | S5P_MFC_R2H_CMD_WAKEUP_RET) { |
Kamil Debski | af93574 | 2011-06-21 10:51:26 -0300 | [diff] [blame] | 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 | |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 451 | int 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); |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 471 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 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 | |
| 483 | err_free_desc_buf: |
| 484 | if (ctx->type == MFCINST_DECODER) |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 485 | s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 486 | err_free_inst_buf: |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 487 | s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 488 | err: |
| 489 | return ret; |
| 490 | } |
| 491 | |
| 492 | void 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); |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 496 | s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 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 */ |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 503 | s5p_mfc_hw_call(dev->mfc_ops, release_codec_buffers, ctx); |
| 504 | s5p_mfc_hw_call(dev->mfc_ops, release_instance_buffer, ctx); |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 505 | if (ctx->type == MFCINST_DECODER) |
Andrzej Hajda | fdd1d4b | 2015-12-02 06:22:32 -0200 | [diff] [blame] | 506 | s5p_mfc_hw_call(dev->mfc_ops, release_dec_desc_buffer, ctx); |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 507 | |
Pawel Osciak | 9d87e83 | 2014-05-19 09:33:00 -0300 | [diff] [blame] | 508 | ctx->inst_no = MFC_NO_INSTANCE_SET; |
Pawel Osciak | 818cd91 | 2014-05-19 09:32:59 -0300 | [diff] [blame] | 509 | ctx->state = MFCINST_FREE; |
| 510 | } |