linux/drivers/media/video/s5p-mfc/s5p_mfc_ctrl.c
<<
>>
Prefs
   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
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.