1/* 2 * linux/drivers/media/platform/s5p-mfc/s5p_mfc_cmd_v5.c 3 * 4 * Copyright (C) 2011 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 "regs-mfc.h" 14#include "s5p_mfc_cmd.h" 15#include "s5p_mfc_common.h" 16#include "s5p_mfc_debug.h" 17#include "s5p_mfc_cmd_v5.h" 18 19/* This function is used to send a command to the MFC */ 20static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, 21 struct s5p_mfc_cmd_args *args) 22{ 23 int cur_cmd; 24 unsigned long timeout; 25 26 timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT); 27 /* wait until host to risc command register becomes 'H2R_CMD_EMPTY' */ 28 do { 29 if (time_after(jiffies, timeout)) { 30 mfc_err("Timeout while waiting for hardware\n"); 31 return -EIO; 32 } 33 cur_cmd = mfc_read(dev, S5P_FIMV_HOST2RISC_CMD); 34 } while (cur_cmd != S5P_FIMV_H2R_CMD_EMPTY); 35 mfc_write(dev, args->arg[0], S5P_FIMV_HOST2RISC_ARG1); 36 mfc_write(dev, args->arg[1], S5P_FIMV_HOST2RISC_ARG2); 37 mfc_write(dev, args->arg[2], S5P_FIMV_HOST2RISC_ARG3); 38 mfc_write(dev, args->arg[3], S5P_FIMV_HOST2RISC_ARG4); 39 /* Issue the command */ 40 mfc_write(dev, cmd, S5P_FIMV_HOST2RISC_CMD); 41 return 0; 42} 43 44/* Initialize the MFC */ 45static int s5p_mfc_sys_init_cmd_v5(struct s5p_mfc_dev *dev) 46{ 47 struct s5p_mfc_cmd_args h2r_args; 48 49 memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); 50 h2r_args.arg[0] = dev->fw_size; 51 return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SYS_INIT, 52 &h2r_args); 53} 54 55/* Suspend the MFC hardware */ 56static int s5p_mfc_sleep_cmd_v5(struct s5p_mfc_dev *dev) 57{ 58 struct s5p_mfc_cmd_args h2r_args; 59 60 memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); 61 return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_SLEEP, &h2r_args); 62} 63 64/* Wake up the MFC hardware */ 65static int s5p_mfc_wakeup_cmd_v5(struct s5p_mfc_dev *dev) 66{ 67 struct s5p_mfc_cmd_args h2r_args; 68 69 memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); 70 return s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_WAKEUP, 71 &h2r_args); 72} 73 74 75static int s5p_mfc_open_inst_cmd_v5(struct s5p_mfc_ctx *ctx) 76{ 77 struct s5p_mfc_dev *dev = ctx->dev; 78 struct s5p_mfc_cmd_args h2r_args; 79 int ret; 80 81 /* Preparing decoding - getting instance number */ 82 mfc_debug(2, "Getting instance number (codec: %d)\n", ctx->codec_mode); 83 dev->curr_ctx = ctx->num; 84 memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); 85 switch (ctx->codec_mode) { 86 case S5P_MFC_CODEC_H264_DEC: 87 h2r_args.arg[0] = S5P_FIMV_CODEC_H264_DEC; 88 break; 89 case S5P_MFC_CODEC_VC1_DEC: 90 h2r_args.arg[0] = S5P_FIMV_CODEC_VC1_DEC; 91 break; 92 case S5P_MFC_CODEC_MPEG4_DEC: 93 h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_DEC; 94 break; 95 case S5P_MFC_CODEC_MPEG2_DEC: 96 h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG2_DEC; 97 break; 98 case S5P_MFC_CODEC_H263_DEC: 99 h2r_args.arg[0] = S5P_FIMV_CODEC_H263_DEC; 100 break; 101 case S5P_MFC_CODEC_VC1RCV_DEC: 102 h2r_args.arg[0] = S5P_FIMV_CODEC_VC1RCV_DEC; 103 break; 104 case S5P_MFC_CODEC_H264_ENC: 105 h2r_args.arg[0] = S5P_FIMV_CODEC_H264_ENC; 106 break; 107 case S5P_MFC_CODEC_MPEG4_ENC: 108 h2r_args.arg[0] = S5P_FIMV_CODEC_MPEG4_ENC; 109 break; 110 case S5P_MFC_CODEC_H263_ENC: 111 h2r_args.arg[0] = S5P_FIMV_CODEC_H263_ENC; 112 break; 113 default: 114 h2r_args.arg[0] = S5P_FIMV_CODEC_NONE; 115 } 116 h2r_args.arg[1] = 0; /* no crc & no pixelcache */ 117 h2r_args.arg[2] = ctx->ctx.ofs; 118 h2r_args.arg[3] = ctx->ctx.size; 119 ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_OPEN_INSTANCE, 120 &h2r_args); 121 if (ret) { 122 mfc_err("Failed to create a new instance\n"); 123 ctx->state = MFCINST_ERROR; 124 } 125 return ret; 126} 127 128static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) 129{ 130 struct s5p_mfc_dev *dev = ctx->dev; 131 struct s5p_mfc_cmd_args h2r_args; 132 int ret; 133 134 if (ctx->state == MFCINST_FREE) { 135 mfc_err("Instance already returned\n"); 136 ctx->state = MFCINST_ERROR; 137 return -EINVAL; 138 } 139 /* Closing decoding instance */ 140 mfc_debug(2, "Returning instance number %d\n", ctx->inst_no); 141 dev->curr_ctx = ctx->num; 142 memset(&h2r_args, 0, sizeof(struct s5p_mfc_cmd_args)); 143 h2r_args.arg[0] = ctx->inst_no; 144 ret = s5p_mfc_cmd_host2risc_v5(dev, S5P_FIMV_H2R_CMD_CLOSE_INSTANCE, 145 &h2r_args); 146 if (ret) { 147 mfc_err("Failed to return an instance\n"); 148 ctx->state = MFCINST_ERROR; 149 return -EINVAL; 150 } 151 return 0; 152} 153 154/* Initialize cmd function pointers for MFC v5 */ 155static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { 156 .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, 157 .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, 158 .sleep_cmd = s5p_mfc_sleep_cmd_v5, 159 .wakeup_cmd = s5p_mfc_wakeup_cmd_v5, 160 .open_inst_cmd = s5p_mfc_open_inst_cmd_v5, 161 .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, 162}; 163 164struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) 165{ 166 return &s5p_mfc_cmds_v5; 167} 168