linux/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
<<
>>
Prefs
   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
  25/* Allocate memory for firmware */
  26int s5p_mfc_alloc_firmware(struct s5p_mfc_dev *dev)
  27{
  28        void *bank2_virt;
  29        dma_addr_t bank2_dma_addr;
  30
  31        dev->fw_size = dev->variant->buf_size->fw;
  32
  33        if (dev->fw_virt_addr) {
  34                mfc_err("Attempting to allocate firmware when it seems that it is already loaded\n");
  35                return -ENOMEM;
  36        }
  37
  38        dev->fw_virt_addr = dma_alloc_coherent(dev->mem_dev_l, dev->fw_size,
  39                                        &dev->bank1, GFP_KERNEL);
  40
  41        if (IS_ERR_OR_NULL(dev->fw_virt_addr)) {
  42                dev->fw_virt_addr = NULL;
  43                mfc_err("Allocating bitprocessor buffer failed\n");
  44                return -ENOMEM;
  45        }
  46
  47        dev->bank1 = dev->bank1;
  48
  49        if (HAS_PORTNUM(dev) && IS_TWOPORT(dev)) {
  50                bank2_virt = dma_alloc_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER,
  51                                        &bank2_dma_addr, GFP_KERNEL);
  52
  53                if (IS_ERR(dev->fw_virt_addr)) {
  54                        mfc_err("Allocating bank2 base failed\n");
  55                        dma_free_coherent(dev->mem_dev_l, dev->fw_size,
  56                                dev->fw_virt_addr, dev->bank1);
  57                        dev->fw_virt_addr = NULL;
  58                        return -ENOMEM;
  59                }
  60
  61                /* Valid buffers passed to MFC encoder with LAST_FRAME command
  62                 * should not have address of bank2 - MFC will treat it as a null frame.
  63                 * To avoid such situation we set bank2 address below the pool address.
  64                 */
  65                dev->bank2 = bank2_dma_addr - (1 << MFC_BASE_ALIGN_ORDER);
  66
  67                dma_free_coherent(dev->mem_dev_r, 1 << MFC_BASE_ALIGN_ORDER,
  68                        bank2_virt, bank2_dma_addr);
  69
  70        } else {
  71                /* In this case bank2 can point to the same address as bank1.
  72                 * Firmware will always occupy the beggining of this area so it is
  73                 * impossible having a video frame buffer with zero address. */
  74                dev->bank2 = dev->bank1;
  75        }
  76        return 0;
  77}
  78
  79/* Load firmware */
  80int s5p_mfc_load_firmware(struct s5p_mfc_dev *dev)
  81{
  82        struct firmware *fw_blob;
  83        int err;
  84
  85        /* Firmare has to be present as a separate file or compiled
  86         * into kernel. */
  87        mfc_debug_enter();
  88
  89        err = request_firmware((const struct firmware **)&fw_blob,
  90                                     dev->variant->fw_name, dev->v4l2_dev.dev);
  91        if (err != 0) {
  92                mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
  93                return -EINVAL;
  94        }
  95        if (fw_blob->size > dev->fw_size) {
  96                mfc_err("MFC firmware is too big to be loaded\n");
  97                release_firmware(fw_blob);
  98                return -ENOMEM;
  99        }
 100        if (!dev->fw_virt_addr) {
 101                mfc_err("MFC firmware is not allocated\n");
 102                release_firmware(fw_blob);
 103                return -EINVAL;
 104        }
 105        memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size);
 106        wmb();
 107        release_firmware(fw_blob);
 108        mfc_debug_leave();
 109        return 0;
 110}
 111
 112/* Reload firmware to MFC */
 113int s5p_mfc_reload_firmware(struct s5p_mfc_dev *dev)
 114{
 115        struct firmware *fw_blob;
 116        int err;
 117
 118        /* Firmare has to be present as a separate file or compiled
 119         * into kernel. */
 120        mfc_debug_enter();
 121
 122        err = request_firmware((const struct firmware **)&fw_blob,
 123                                     dev->variant->fw_name, dev->v4l2_dev.dev);
 124        if (err != 0) {
 125                mfc_err("Firmware is not present in the /lib/firmware directory nor compiled in kernel\n");
 126                return -EINVAL;
 127        }
 128        if (fw_blob->size > dev->fw_size) {
 129                mfc_err("MFC firmware is too big to be loaded\n");
 130                release_firmware(fw_blob);
 131                return -ENOMEM;
 132        }
 133        if (!dev->fw_virt_addr) {
 134                mfc_err("MFC firmware is not allocated\n");
 135                release_firmware(fw_blob);
 136                return -EINVAL;
 137        }
 138        memcpy(dev->fw_virt_addr, fw_blob->data, fw_blob->size);
 139        wmb();
 140        release_firmware(fw_blob);
 141        mfc_debug_leave();
 142        return 0;
 143}
 144
 145/* Release firmware memory */
 146int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
 147{
 148        /* Before calling this function one has to make sure
 149         * that MFC is no longer processing */
 150        if (!dev->fw_virt_addr)
 151                return -EINVAL;
 152        dma_free_coherent(dev->mem_dev_l, dev->fw_size, dev->fw_virt_addr,
 153                                                dev->bank1);
 154        dev->fw_virt_addr = NULL;
 155        return 0;
 156}
 157
 158/* Reset the device */
 159int s5p_mfc_reset(struct s5p_mfc_dev *dev)
 160{
 161        unsigned int mc_status;
 162        unsigned long timeout;
 163        int i;
 164
 165        mfc_debug_enter();
 166
 167        if (IS_MFCV6(dev)) {
 168                /* Reset IP */
 169                /*  except RISC, reset */
 170                mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6);
 171                /*  reset release */
 172                mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6);
 173
 174                /* Zero Initialization of MFC registers */
 175                mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
 176                mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6);
 177                mfc_write(dev, 0, S5P_FIMV_FW_VERSION_V6);
 178
 179                for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++)
 180                        mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
 181
 182                /* Reset */
 183                mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6);
 184                mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6);
 185                mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6);
 186        } else {
 187                /* Stop procedure */
 188                /*  reset RISC */
 189                mfc_write(dev, 0x3f6, S5P_FIMV_SW_RESET);
 190                /*  All reset except for MC */
 191                mfc_write(dev, 0x3e2, S5P_FIMV_SW_RESET);
 192                mdelay(10);
 193
 194                timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
 195                /* Check MC status */
 196                do {
 197                        if (time_after(jiffies, timeout)) {
 198                                mfc_err("Timeout while resetting MFC\n");
 199                                return -EIO;
 200                        }
 201
 202                        mc_status = mfc_read(dev, S5P_FIMV_MC_STATUS);
 203
 204                } while (mc_status & 0x3);
 205
 206                mfc_write(dev, 0x0, S5P_FIMV_SW_RESET);
 207                mfc_write(dev, 0x3fe, S5P_FIMV_SW_RESET);
 208        }
 209
 210        mfc_debug_leave();
 211        return 0;
 212}
 213
 214static inline void s5p_mfc_init_memctrl(struct s5p_mfc_dev *dev)
 215{
 216        if (IS_MFCV6(dev)) {
 217                mfc_write(dev, dev->bank1, S5P_FIMV_RISC_BASE_ADDRESS_V6);
 218                mfc_debug(2, "Base Address : %08x\n", dev->bank1);
 219        } else {
 220                mfc_write(dev, dev->bank1, S5P_FIMV_MC_DRAMBASE_ADR_A);
 221                mfc_write(dev, dev->bank2, S5P_FIMV_MC_DRAMBASE_ADR_B);
 222                mfc_debug(2, "Bank1: %08x, Bank2: %08x\n",
 223                                dev->bank1, dev->bank2);
 224        }
 225}
 226
 227static inline void s5p_mfc_clear_cmds(struct s5p_mfc_dev *dev)
 228{
 229        if (IS_MFCV6(dev)) {
 230                /* Zero initialization should be done before RESET.
 231                 * Nothing to do here. */
 232        } else {
 233                mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH0_INST_ID);
 234                mfc_write(dev, 0xffffffff, S5P_FIMV_SI_CH1_INST_ID);
 235                mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD);
 236                mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD);
 237        }
 238}
 239
 240/* Initialize hardware */
 241int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
 242{
 243        unsigned int ver;
 244        int ret;
 245
 246        mfc_debug_enter();
 247        if (!dev->fw_virt_addr) {
 248                mfc_err("Firmware memory is not allocated.\n");
 249                return -EINVAL;
 250        }
 251
 252        /* 0. MFC reset */
 253        mfc_debug(2, "MFC reset..\n");
 254        s5p_mfc_clock_on();
 255        ret = s5p_mfc_reset(dev);
 256        if (ret) {
 257                mfc_err("Failed to reset MFC - timeout\n");
 258                return ret;
 259        }
 260        mfc_debug(2, "Done MFC reset..\n");
 261        /* 1. Set DRAM base Addr */
 262        s5p_mfc_init_memctrl(dev);
 263        /* 2. Initialize registers of channel I/F */
 264        s5p_mfc_clear_cmds(dev);
 265        /* 3. Release reset signal to the RISC */
 266        s5p_mfc_clean_dev_int_flags(dev);
 267        if (IS_MFCV6(dev))
 268                mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
 269        else
 270                mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
 271        mfc_debug(2, "Will now wait for completion of firmware transfer\n");
 272        if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
 273                mfc_err("Failed to load firmware\n");
 274                s5p_mfc_reset(dev);
 275                s5p_mfc_clock_off();
 276                return -EIO;
 277        }
 278        s5p_mfc_clean_dev_int_flags(dev);
 279        /* 4. Initialize firmware */
 280        ret = s5p_mfc_hw_call(dev->mfc_cmds, sys_init_cmd, dev);
 281        if (ret) {
 282                mfc_err("Failed to send command to MFC - timeout\n");
 283                s5p_mfc_reset(dev);
 284                s5p_mfc_clock_off();
 285                return ret;
 286        }
 287        mfc_debug(2, "Ok, now will write a command to init the system\n");
 288        if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) {
 289                mfc_err("Failed to load firmware\n");
 290                s5p_mfc_reset(dev);
 291                s5p_mfc_clock_off();
 292                return -EIO;
 293        }
 294        dev->int_cond = 0;
 295        if (dev->int_err != 0 || dev->int_type !=
 296                                        S5P_MFC_R2H_CMD_SYS_INIT_RET) {
 297                /* Failure. */
 298                mfc_err("Failed to init firmware - error: %d int: %d\n",
 299                                                dev->int_err, dev->int_type);
 300                s5p_mfc_reset(dev);
 301                s5p_mfc_clock_off();
 302                return -EIO;
 303        }
 304        if (IS_MFCV6(dev))
 305                ver = mfc_read(dev, S5P_FIMV_FW_VERSION_V6);
 306        else
 307                ver = mfc_read(dev, S5P_FIMV_FW_VERSION);
 308
 309        mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n",
 310                (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF);
 311        s5p_mfc_clock_off();
 312        mfc_debug_leave();
 313        return 0;
 314}
 315
 316
 317/* Deinitialize hardware */
 318void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev)
 319{
 320        s5p_mfc_clock_on();
 321
 322        s5p_mfc_reset(dev);
 323        s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev);
 324
 325        s5p_mfc_clock_off();
 326}
 327
 328int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
 329{
 330        int ret;
 331
 332        mfc_debug_enter();
 333        s5p_mfc_clock_on();
 334        s5p_mfc_clean_dev_int_flags(dev);
 335        ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev);
 336        if (ret) {
 337                mfc_err("Failed to send command to MFC - timeout\n");
 338                return ret;
 339        }
 340        if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SLEEP_RET)) {
 341                mfc_err("Failed to sleep\n");
 342                return -EIO;
 343        }
 344        s5p_mfc_clock_off();
 345        dev->int_cond = 0;
 346        if (dev->int_err != 0 || dev->int_type !=
 347                                                S5P_MFC_R2H_CMD_SLEEP_RET) {
 348                /* Failure. */
 349                mfc_err("Failed to sleep - error: %d int: %d\n", dev->int_err,
 350                                                                dev->int_type);
 351                return -EIO;
 352        }
 353        mfc_debug_leave();
 354        return ret;
 355}
 356
 357int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
 358{
 359        int ret;
 360
 361        mfc_debug_enter();
 362        /* 0. MFC reset */
 363        mfc_debug(2, "MFC reset..\n");
 364        s5p_mfc_clock_on();
 365        ret = s5p_mfc_reset(dev);
 366        if (ret) {
 367                mfc_err("Failed to reset MFC - timeout\n");
 368                return ret;
 369        }
 370        mfc_debug(2, "Done MFC reset..\n");
 371        /* 1. Set DRAM base Addr */
 372        s5p_mfc_init_memctrl(dev);
 373        /* 2. Initialize registers of channel I/F */
 374        s5p_mfc_clear_cmds(dev);
 375        s5p_mfc_clean_dev_int_flags(dev);
 376        /* 3. Initialize firmware */
 377        ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
 378        if (ret) {
 379                mfc_err("Failed to send command to MFC - timeout\n");
 380                return ret;
 381        }
 382        /* 4. Release reset signal to the RISC */
 383        if (IS_MFCV6(dev))
 384                mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
 385        else
 386                mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
 387        mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
 388        if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
 389                mfc_err("Failed to load firmware\n");
 390                return -EIO;
 391        }
 392        s5p_mfc_clock_off();
 393        dev->int_cond = 0;
 394        if (dev->int_err != 0 || dev->int_type !=
 395                                                S5P_MFC_R2H_CMD_WAKEUP_RET) {
 396                /* Failure. */
 397                mfc_err("Failed to wakeup - error: %d int: %d\n", dev->int_err,
 398                                                                dev->int_type);
 399                return -EIO;
 400        }
 401        mfc_debug_leave();
 402        return 0;
 403}
 404
 405