1/* 2 * linux/drivers/media/video/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 "regs-mfc.h" 19#include "s5p_mfc_cmd.h" 20#include "s5p_mfc_common.h" 21#include "s5p_mfc_debug.h" 22#include "s5p_mfc_intr.h" 23#include "s5p_mfc_pm.h" 24 25static void *s5p_mfc_bitproc_buf; 26static size_t s5p_mfc_bitproc_phys; 27static unsigned char *s5p_mfc_bitproc_virt; 28 29/* Allocate and load firmware */ 30int s5p_mfc_alloc_and_load_firmware(struct s5p_mfc_dev *dev) 31{ 32 struct firmware *fw_blob; 33 size_t bank2_base_phys; 34 void *b_base; 35 int err; 36 37 /* Firmare has to be present as a separate file or compiled 38 * into kernel. */ 39 mfc_debug_enter(); 40 err = request_firmware((const struct firmware **)&fw_blob, 41 "s5p-mfc.fw", dev->v4l2_dev.dev); 42 if (err != 0) { 43 mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); 44 return -EINVAL; 45 } 46 dev->fw_size = ALIGN(fw_blob->size, FIRMWARE_ALIGN); 47 if (s5p_mfc_bitproc_buf) { 48 mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n"); 49 release_firmware(fw_blob); 50 return -ENOMEM; 51 } 52 s5p_mfc_bitproc_buf = vb2_dma_contig_memops.alloc( 53 dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], dev->fw_size); 54 if (IS_ERR(s5p_mfc_bitproc_buf)) { 55 s5p_mfc_bitproc_buf = 0; 56 mfc_err("Allocating bitprocessor buffer failed\n"); 57 release_firmware(fw_blob); 58 return -ENOMEM; 59 } 60 s5p_mfc_bitproc_phys = s5p_mfc_mem_cookie( 61 dev->alloc_ctx[MFC_BANK1_ALLOC_CTX], s5p_mfc_bitproc_buf); 62 if (s5p_mfc_bitproc_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { 63 mfc_err("The base memory for bank 1 is not aligned to 128KB\n"); 64 vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); 65 s5p_mfc_bitproc_phys = 0; 66 s5p_mfc_bitproc_buf = 0; 67 release_firmware(fw_blob); 68 return -EIO; 69 } 70 s5p_mfc_bitproc_virt = vb2_dma_contig_memops.vaddr(s5p_mfc_bitproc_buf); 71 if (!s5p_mfc_bitproc_virt) { 72 mfc_err("Bitprocessor memory remap failed\n"); 73 vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); 74 s5p_mfc_bitproc_phys = 0; 75 s5p_mfc_bitproc_buf = 0; 76 release_firmware(fw_blob); 77 return -EIO; 78 } 79 dev->bank1 = s5p_mfc_bitproc_phys; 80 b_base = vb2_dma_contig_memops.alloc( 81 dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], 1 << MFC_BANK2_ALIGN_ORDER); 82 if (IS_ERR(b_base)) { 83 vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); 84 s5p_mfc_bitproc_phys = 0; 85 s5p_mfc_bitproc_buf = 0; 86 mfc_err("Allocating bank2 base failed\n"); 87 release_firmware(fw_blob); 88 return -ENOMEM; 89 } 90 bank2_base_phys = s5p_mfc_mem_cookie( 91 dev->alloc_ctx[MFC_BANK2_ALLOC_CTX], b_base); 92 vb2_dma_contig_memops.put(b_base); 93 if (bank2_base_phys & ((1 << MFC_BASE_ALIGN_ORDER) - 1)) { 94 mfc_err("The base memory for bank 2 is not aligned to 128KB\n"); 95 vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); 96 s5p_mfc_bitproc_phys = 0; 97 s5p_mfc_bitproc_buf = 0; 98 release_firmware(fw_blob); 99 return -EIO; 100 } 101 dev->bank2 = bank2_base_phys; 102 memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); 103 wmb(); 104 release_firmware(fw_blob); 105 mfc_debug_leave(); 106 return 0; 107} 108 109/* Reload firmware to MFC */ 110int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev) 111{ 112 struct firmware *fw_blob; 113 int err; 114 115 /* Firmare has to be present as a separate file or compiled 116 * into kernel. */ 117 mfc_debug_enter(); 118 err = request_firmware((const struct firmware **)&fw_blob, 119 "s5p-mfc.fw", dev->v4l2_dev.dev); 120 if (err != 0) { 121 mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n"); 122 return -EINVAL; 123 } 124 if (fw_blob->size > dev->fw_size) { 125 mfc_err("MFC firmware is too big to be loaded\n"); 126 release_firmware(fw_blob); 127 return -ENOMEM; 128 } 129 if (s5p_mfc_bitproc_buf == 0 || s5p_mfc_bitproc_phys == 0) { 130 mfc_err("MFC firmware is not allocated or was not mapped correctly\n"); 131 release_firmware(fw_blob); 132 return -EINVAL; 133 } 134 memcpy(s5p_mfc_bitproc_virt, fw_blob->data, fw_blob->size); 135 wmb(); 136 release_firmware(fw_blob); 137 mfc_debug_leave(); 138 return 0; 139} 140 141/* Release firmware memory */ 142int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev) 143{ 144 /* Before calling this function one has to make sure 145 * that MFC is no longer processing */ 146 if (!s5p_mfc_bitproc_buf) 147 return -EINVAL; 148 vb2_dma_contig_memops.put(s5p_mfc_bitproc_buf); 149 s5p_mfc_bitproc_virt = 0; 150 s5p_mfc_bitproc_phys = 0; 151 s5p_mfc_bitproc_buf = 0; 152 return 0; 153} 154 155/* Reset the device */ 156int s5p_mfc_reset(struct s5p_mfc_dev *dev) 157{ 158 unsigned int mc_status; 159 unsigned long timeout; 160 161 mfc_debug_enter(); 162 /* Stop procedure */ 163 /* reset RISC */ 164 mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET); 165 /* All reset except for MC */ 166 mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET); 167 mdelay(10); 168 169 timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); 170 /* Check MC status */ 171 do { 172 if (time_after(jiffies, timeout)) { 173 mfc_err("Timeout while resetting MFC\n"); 174 return -EIO; 175 } 176 177 mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS); 178 179 } while (mc_status & 0x3); 180 181 mfc_write(dev, 0x0, S5P_FIMV_SW_RESET); 182 mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET); 183 mfc_debug_leave(); 184 return 0; 185} 186 187static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev) 188{ 189 mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A); 190 mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B); 191 mfc_debug(2, "Bank1: %08x, Bank2: %08x\n", dev->bank1, dev->bank2); 192} 193 194static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev) 195{ 196 mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID); 197 mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID); 198 mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD); 199 mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD); 200} 201 202/* Initialize hardware */ 203int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) 204{ 205 unsigned int ver; 206 int ret; 207 208 mfc_debug_enter(); 209 if (!s5p_mfc_bitproc_buf) 210 return -EINVAL; 211 212 /* 0. MFC reset */ 213 mfc_debug(2, "MFC reset..\n"); 214 s5p_mfc_clock_on(); 215 ret = s5p_mfc_reset(dev); 216 if (ret) { 217 mfc_err("Failed to reset MFC - timeout\n"); 218 return ret; 219 } 220 mfc_debug(2, "Done MFC reset..\n"); 221 /* 1. Set DRAM base Addr */ 222 s5p_mfc_init_memctrl(dev); 223 /* 2. Initialize registers of channel I/F */ 224 s5p_mfc_clear_cmds(dev); 225 /* 3. Release reset signal to the RISC */ 226 s5p_mfc_clean_dev_int_flags(dev); 227 mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); 228 mfc_debug(2, "Will now wait for completion of firmware transfer\n"); 229 if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_FW_STATUS_RET)) { 230 mfc_err("Failed to load firmware\n"); 231 s5p_mfc_reset(dev); 232 s5p_mfc_clock_off(); 233 return -EIO; 234 } 235 s5p_mfc_clean_dev_int_flags(dev); 236 /* 4. Initialize firmware */ 237 ret = s5p_mfc_sys_init_cmd(dev); 238 if (ret) { 239 mfc_err("Failed to send command to MFC - timeout\n"); 240 s5p_mfc_reset(dev); 241 s5p_mfc_clock_off(); 242 return ret; 243 } 244 mfc_debug(2, "Ok, now will write a command to init the system\n"); 245 if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SYS_INIT_RET)) { 246 mfc_err("Failed to load firmware\n"); 247 s5p_mfc_reset(dev); 248 s5p_mfc_clock_off(); 249 return -EIO; 250 } 251 dev->int_cond = 0; 252 if (dev->int_err != 0 || dev->int_type != 253 S5P_FIMV_R2H_CMD_SYS_INIT_RET) { 254 /* Failure. */ 255 mfc_err("Failed to init firmware - error: %d int: %d\n", 256 dev->int_err, dev->int_type); 257 s5p_mfc_reset(dev); 258 s5p_mfc_clock_off(); 259 return -EIO; 260 } 261 ver = mfc_read(dev, S5P_FIMV_FW_VERSION); 262 mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", 263 (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); 264 s5p_mfc_clock_off(); 265 mfc_debug_leave(); 266 return 0; 267} 268 269 270int s5p_mfc_sleep(struct s5p_mfc_dev *dev) 271{ 272 int ret; 273 274 mfc_debug_enter(); 275 s5p_mfc_clock_on(); 276 s5p_mfc_clean_dev_int_flags(dev); 277 ret = s5p_mfc_sleep_cmd(dev); 278 if (ret) { 279 mfc_err("Failed to send command to MFC - timeout\n"); 280 return ret; 281 } 282 if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_SLEEP_RET)) { 283 mfc_err("Failed to sleep\n"); 284 return -EIO; 285 } 286 s5p_mfc_clock_off(); 287 dev->int_cond = 0; 288 if (dev->int_err != 0 || dev->int_type != 289 S5P_FIMV_R2H_CMD_SLEEP_RET) { 290 /* Failure. */ 291 mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err, 292 dev->int_type); 293 return -EIO; 294 } 295 mfc_debug_leave(); 296 return ret; 297} 298 299int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) 300{ 301 int ret; 302 303 mfc_debug_enter(); 304 /* 0. MFC reset */ 305 mfc_debug(2, "MFC reset..\n"); 306 s5p_mfc_clock_on(); 307 ret = s5p_mfc_reset(dev); 308 if (ret) { 309 mfc_err("Failed to reset MFC - timeout\n"); 310 return ret; 311 } 312 mfc_debug(2, "Done MFC reset..\n"); 313 /* 1. Set DRAM base Addr */ 314 s5p_mfc_init_memctrl(dev); 315 /* 2. Initialize registers of channel I/F */ 316 s5p_mfc_clear_cmds(dev); 317 s5p_mfc_clean_dev_int_flags(dev); 318 /* 3. Initialize firmware */ 319 ret = s5p_mfc_wakeup_cmd(dev); 320 if (ret) { 321 mfc_err("Failed to send command to MFC - timeout\n"); 322 return ret; 323 } 324 /* 4. Release reset signal to the RISC */ 325 mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET); 326 mfc_debug(2, "Ok, now will write a command to wakeup the system\n"); 327 if (s5p_mfc_wait_for_done_dev(dev, S5P_FIMV_R2H_CMD_WAKEUP_RET)) { 328 mfc_err("Failed to load firmware\n"); 329 return -EIO; 330 } 331 s5p_mfc_clock_off(); 332 dev->int_cond = 0; 333 if (dev->int_err != 0 || dev->int_type != 334 S5P_FIMV_R2H_CMD_WAKEUP_RET) { 335 /* Failure. */ 336 mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err, 337 dev->int_type); 338 return -EIO; 339 } 340 mfc_debug_leave(); 341 return 0; 342} 343 344