4215 lines
118 KiB
C
4215 lines
118 KiB
C
/**
|
|
* file tng_topaz.c
|
|
* TOPAZ I/O operations and IRQ handling
|
|
*
|
|
*/
|
|
|
|
/**************************************************************************
|
|
*
|
|
* Copyright (c) 2007 Intel Corporation, Hillsboro, OR, USA
|
|
* Copyright (c) Imagination Technologies Limited, UK
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with
|
|
* this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
**************************************************************************/
|
|
|
|
/* include headers */
|
|
/* #define DRM_DEBUG_CODE 2 */
|
|
#include <drm/drmP.h>
|
|
#include <drm/drm.h>
|
|
|
|
#include "psb_drv.h"
|
|
#include "tng_topaz.h"
|
|
#include "psb_powermgmt.h"
|
|
#include "tng_topaz_hw_reg.h"
|
|
/*#include "private_data.h"*/
|
|
|
|
#include <linux/io.h>
|
|
#include <linux/delay.h>
|
|
|
|
#define TOPAZ_MAX_COMMAND_IN_QUEUE 0x1000
|
|
#define MASK_MTX_INT_ENAB 0x4000ff00
|
|
|
|
#define LOOP_COUNT 10000
|
|
|
|
#define MTX_PC (0x05)
|
|
|
|
#define tng__max(a, b) ((a)> (b)) ? (a) : (b)
|
|
#define tng__min(a, b) ((a) < (b)) ? (a) : (b)
|
|
|
|
/*static uint32_t setv_cnt = 0;*/
|
|
|
|
enum MTX_MESSAGE_ID {
|
|
MTX_MESSAGE_ACK, /* !< (no data)\n Null command does nothing\n */
|
|
MTX_MESSAGE_CODED, /* !< (no data)\n Null command does nothing\n */
|
|
} ;
|
|
|
|
/* static function define */
|
|
static int tng_topaz_deliver_command(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
struct ttm_buffer_object *cmd_buffer,
|
|
uint32_t cmd_offset,
|
|
uint32_t cmd_size,
|
|
void **topaz_cmd, uint32_t sequence,
|
|
int copy_cmd);
|
|
|
|
static int tng_topaz_send(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
void *cmd,
|
|
uint32_t cmd_size,
|
|
uint32_t sync_seq);
|
|
|
|
static int tng_topaz_save_command(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
void *cmd,
|
|
uint32_t cmd_size,
|
|
uint32_t sequence);
|
|
|
|
static void tng_topaz_getvideo(
|
|
struct drm_device *dev,
|
|
struct psb_video_ctx *video_ctx);
|
|
|
|
static void tng_topaz_setvideo(
|
|
struct drm_device *dev,
|
|
struct psb_video_ctx *video_ctx);
|
|
|
|
void mtx_start(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
mtx_set_target(dev_priv);
|
|
MTX_WRITE32(MTX_CR_MTX_ENABLE, MASK_MTX_MTX_ENABLE);
|
|
}
|
|
|
|
void mtx_stop(struct drm_psb_private *dev_priv)
|
|
{
|
|
mtx_set_target(dev_priv);
|
|
MTX_WRITE32(MTX_CR_MTX_ENABLE, MASK_MTX_MTX_TOFF);
|
|
}
|
|
|
|
void mtx_kick(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
mtx_set_target(dev_priv);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Kick MTX to start\n");
|
|
MTX_WRITE32(MTX_CR_MTX_KICK, 1);
|
|
}
|
|
|
|
void tng_set_consumer(struct drm_device *dev, uint32_t consumer)
|
|
{
|
|
unsigned int reg_val;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOMTX << 2), ®_val);
|
|
|
|
reg_val = F_INSERT(reg_val, consumer, WB_CONSUMER);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOMTX << 2), reg_val);
|
|
}
|
|
|
|
uint32_t tng_get_consumer(struct drm_device *dev)
|
|
{
|
|
unsigned int reg_val;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOMTX << 2), ®_val);
|
|
|
|
return F_DECODE(reg_val, WB_CONSUMER);
|
|
}
|
|
|
|
void tng_set_producer(struct drm_device *dev, uint32_t producer)
|
|
{
|
|
unsigned int reg_val;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2), ®_val);
|
|
|
|
reg_val = F_INSERT(reg_val, producer, WB_PRODUCER);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2), reg_val);
|
|
}
|
|
|
|
uint32_t tng_get_producer(struct drm_device *dev)
|
|
{
|
|
unsigned int reg_val;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2), ®_val);
|
|
|
|
return F_DECODE(reg_val, WB_PRODUCER);
|
|
}
|
|
|
|
uint32_t tng_wait_for_ctrl(struct drm_device *dev, uint32_t control)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
int32_t ret = 0;
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_ISEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 + (MTX_SCRATCHREG_TOHOST << 2),
|
|
control, 0x80000000, 1);
|
|
if (ret)
|
|
DRM_ERROR("Wait for register timeout");
|
|
|
|
return ret;
|
|
}
|
|
|
|
uint32_t tng_serialize_enter(struct drm_device *dev)
|
|
{
|
|
uint32_t reg_val;
|
|
int32_t ret;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
/*
|
|
* Poll for idle register to tell that both HW
|
|
* and FW are idle (`FW_IDLE_STATUS_IDLE` state)
|
|
*/
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_ISEQUAL,
|
|
MTX_SCRATCHREG_IDLE,
|
|
F_ENCODE(FW_IDLE_STATUS_IDLE, FW_IDLE_REG_STATUS),
|
|
MASK_FW_IDLE_REG_STATUS, 1);
|
|
if (ret)
|
|
DRM_ERROR("Wait for register timeout");
|
|
|
|
MULTICORE_READ32(MTX_SCRATCHREG_IDLE, ®_val);
|
|
|
|
return F_EXTRACT(reg_val, FW_IDLE_REG_RECEIVED_COMMANDS);
|
|
}
|
|
|
|
void tng_serialize_exit(struct drm_device *dev, uint32_t enter_token)
|
|
{
|
|
int32_t ret;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
/*
|
|
* Poll for idle register to tell that both HW
|
|
* and FW are idle (`FW_IDLE_STATUS_IDLE` state)
|
|
*/
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_NOTEQUAL,
|
|
MTX_SCRATCHREG_IDLE,
|
|
F_ENCODE(enter_token, FW_IDLE_REG_RECEIVED_COMMANDS),
|
|
MASK_FW_IDLE_REG_RECEIVED_COMMANDS, 1);
|
|
if (ret)
|
|
DRM_ERROR("Wait for register timeout");
|
|
}
|
|
|
|
static void tng_topaz_Int_clear(
|
|
struct drm_psb_private *dev_priv,
|
|
uint32_t intClearMask)
|
|
{
|
|
unsigned long irq_flags;
|
|
struct tng_topaz_private *topaz_priv;
|
|
|
|
topaz_priv = dev_priv->topaz_private;
|
|
spin_lock_irqsave(&topaz_priv->topaz_lock, irq_flags);
|
|
/* clear interrupt */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_INT_CLEAR,
|
|
intClearMask);
|
|
spin_unlock_irqrestore(&topaz_priv->topaz_lock, irq_flags);
|
|
}
|
|
|
|
struct psb_video_ctx *get_ctx_from_fp(
|
|
struct drm_device *dev, struct file *filp)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct psb_video_ctx *pos;
|
|
unsigned long irq_flags;
|
|
int entrypoint;
|
|
|
|
spin_lock_irqsave(&dev_priv->video_ctx_lock, irq_flags);
|
|
|
|
list_for_each_entry(pos, &dev_priv->video_ctx, head) {
|
|
if (pos->filp == filp) {
|
|
entrypoint = pos->ctx_type & 0xff;
|
|
if (entrypoint == VAEntrypointEncSlice ||
|
|
entrypoint == VAEntrypointEncPicture) {
|
|
spin_unlock_irqrestore(&dev_priv->video_ctx_lock, \
|
|
irq_flags);
|
|
return pos;
|
|
}
|
|
}
|
|
}
|
|
|
|
spin_unlock_irqrestore(&dev_priv->video_ctx_lock, irq_flags);
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t get_ctx_cnt(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct psb_video_ctx *pos, *n;
|
|
int count = 0;
|
|
int entrypoint;
|
|
|
|
list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
|
|
entrypoint = pos->ctx_type & 0xff;
|
|
if (entrypoint == VAEntrypointEncSlice ||
|
|
entrypoint == VAEntrypointEncPicture)
|
|
count++;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
int32_t dispatch_wb_message_polling(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
int32_t sync_seq,
|
|
unsigned char *command)
|
|
{
|
|
struct psb_video_ctx *video_ctx;
|
|
struct tng_topaz_private *topaz_priv;
|
|
struct drm_psb_private *dev_priv;
|
|
struct tng_topaz_cmd_header *cur_cmd_header;
|
|
struct IMG_WRITEBACK_MSG *wb_msg;
|
|
int32_t ret;
|
|
|
|
dev_priv = (struct drm_psb_private *) dev->dev_private;
|
|
if (!dev_priv) {
|
|
DRM_ERROR("Failed to get dev_priv\n");
|
|
return -1;
|
|
}
|
|
|
|
topaz_priv = dev_priv->topaz_private;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
return -1;
|
|
}
|
|
|
|
topaz_priv->consumer = tng_get_consumer(dev);
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
|
|
/* Read and compare consumer and producer */
|
|
if (topaz_priv->producer == topaz_priv->consumer) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: producer = consumer = %d",
|
|
topaz_priv->producer);
|
|
PSB_DEBUG_TOPAZ("polling producer until change\n");
|
|
/* if the same -> poll on Producer change */
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_NOTEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2),
|
|
topaz_priv->consumer, MASK_WB_PRODUCER, 1);
|
|
if (ret) {
|
|
wb_msg = (struct IMG_WRITEBACK_MSG *)
|
|
video_ctx->wb_addr[topaz_priv->consumer];
|
|
DRM_ERROR("Polling timeout, ui32CmdWord = %08x, " \
|
|
"ui32Data = %08x, ui32ExtraData = %08x, " \
|
|
"ui32WritebackVal = %08x, " \
|
|
"ui32CodedBufferConsumed = %08x\n",
|
|
wb_msg->ui32CmdWord, wb_msg->ui32Data,
|
|
wb_msg->ui32ExtraData, wb_msg->ui32WritebackVal,
|
|
wb_msg->ui32CodedBufferConsumed);
|
|
|
|
return ret;
|
|
}
|
|
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
}
|
|
|
|
/* Dispatch new messages */
|
|
do {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Dispatch write back message, " \
|
|
"producer = %d, consumer = %d\n",
|
|
topaz_priv->producer, topaz_priv->consumer);
|
|
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_NOTEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2),
|
|
topaz_priv->consumer, MASK_WB_PRODUCER, 1);
|
|
if (ret) {
|
|
DRM_ERROR("Wait for register timeout");
|
|
return ret;
|
|
}
|
|
|
|
topaz_priv->consumer++;
|
|
if (topaz_priv->consumer == WB_FIFO_SIZE)
|
|
topaz_priv->consumer = 0;
|
|
|
|
tng_set_consumer(dev, topaz_priv->consumer);
|
|
|
|
} while (topaz_priv->consumer != topaz_priv->producer);
|
|
|
|
cur_cmd_header = (struct tng_topaz_cmd_header *)command;
|
|
|
|
if (cur_cmd_header->id != MTX_CMDID_ENCODE_FRAME &&
|
|
cur_cmd_header->id != MTX_CMDID_ISSUEBUFF)
|
|
return 0;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Handle context saving/fence " \
|
|
"handler/dequeue send on ENCODE_FRAME command\n");
|
|
|
|
if (get_ctx_cnt(dev) > 1) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: More than one context, " \
|
|
"save current context\n");
|
|
if (topaz_priv->cur_context->codec != IMG_CODEC_JPEG) {
|
|
ret = tng_topaz_save_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save mtx status");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
*topaz_priv->topaz_sync_addr = sync_seq;
|
|
(topaz_priv->cur_context)->handle_sequence_needed = false;
|
|
psb_fence_handler(dev, LNC_ENGINE_ENCODE);
|
|
|
|
topaz_priv->topaz_busy = 1;
|
|
tng_topaz_dequeue_send(dev);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t dispatch_wb_message_irq(struct drm_device *dev)
|
|
{
|
|
struct tng_topaz_private *topaz_priv;
|
|
struct drm_psb_private *dev_priv;
|
|
/* uint32_t crMultiCoreIntStat;*/
|
|
/* struct psb_video_ctx *video_ctx; */
|
|
/* struct IMG_WRITEBACK_MSG *wb_msg; */
|
|
int32_t ret;
|
|
int32_t count = 0;
|
|
|
|
dev_priv = (struct drm_psb_private *) dev->dev_private;
|
|
if (!dev_priv) {
|
|
DRM_ERROR("Failed to get dev_priv\n");
|
|
return -1;
|
|
}
|
|
|
|
topaz_priv = dev_priv->topaz_private;
|
|
|
|
topaz_priv->consumer = tng_get_consumer(dev);
|
|
|
|
do {
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
count++;
|
|
} while (topaz_priv->producer == topaz_priv->consumer &&
|
|
count < 300000);
|
|
|
|
if (count == 300000) {
|
|
DRM_ERROR("Waiting for IRQ timeout\n");
|
|
return -1;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Producer = %d, Consumer = %d\n",
|
|
topaz_priv->producer, topaz_priv->consumer);
|
|
|
|
do {
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_NOTEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2),
|
|
topaz_priv->consumer, MASK_WB_PRODUCER, 1);
|
|
if (ret)
|
|
return ret;
|
|
|
|
topaz_priv->consumer++;
|
|
if (topaz_priv->consumer == WB_FIFO_SIZE)
|
|
topaz_priv->consumer = 0;
|
|
|
|
/* Indicate buffer used by consmer is available */
|
|
tng_set_consumer(dev, topaz_priv->consumer);
|
|
} while (topaz_priv->consumer != topaz_priv->producer);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int32_t tng_wait_on_sync(
|
|
struct drm_device *dev,
|
|
int32_t sync_seq,
|
|
unsigned long cmd_id)
|
|
{
|
|
struct tng_topaz_private *topaz_priv;
|
|
struct drm_psb_private *dev_priv;
|
|
/* struct IMG_WRITEBACK_MSG *wb_msg; */
|
|
/* struct tng_topaz_cmd_header *cur_cmd_header; */
|
|
int32_t ret;
|
|
int32_t count = 0;
|
|
/* uint32_t crMultiCoreIntStat; */
|
|
|
|
dev_priv = (struct drm_psb_private *) dev->dev_private;
|
|
if (!dev_priv) {
|
|
DRM_ERROR("Failed to get dev_priv\n");
|
|
return -1;
|
|
}
|
|
|
|
topaz_priv = dev_priv->topaz_private;
|
|
|
|
topaz_priv->consumer = tng_get_consumer(dev);
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
while (topaz_priv->producer == topaz_priv->consumer &&
|
|
count < LOOP_COUNT * 1000) {
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
count++;
|
|
}
|
|
|
|
if (count == LOOP_COUNT * 1000) {
|
|
DRM_ERROR("Sync cmd(%s) timeout\n", \
|
|
cmd_to_string(cmd_id & (~MTX_CMDID_PRIORITY)));
|
|
return -1;
|
|
}
|
|
#else
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
|
|
/* Read and compare consumer and producer */
|
|
if (topaz_priv->producer == topaz_priv->consumer) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: producer = consumer = %d, " \
|
|
"polling producer until change\n",
|
|
topaz_priv->producer);
|
|
/* if the same -> poll on Producer change */
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_NOTEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2),
|
|
topaz_priv->consumer, MASK_WB_PRODUCER, 1);
|
|
if (ret) {
|
|
|
|
DRM_ERROR("Polling timeout\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
}
|
|
#endif
|
|
/* Dispatch new messages */
|
|
do {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Dispatch write back message, " \
|
|
"producer = %d, consumer = %d\n",
|
|
topaz_priv->producer, topaz_priv->consumer);
|
|
/*
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_NOTEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOHOST << 2),
|
|
topaz_priv->consumer, MASK_WB_PRODUCER, 1);
|
|
if (ret)
|
|
return ret;
|
|
*/
|
|
|
|
topaz_priv->consumer++;
|
|
if (topaz_priv->consumer == WB_FIFO_SIZE)
|
|
topaz_priv->consumer = 0;
|
|
|
|
/* Indicate buffer used by consmer is available */
|
|
tng_set_consumer(dev, topaz_priv->consumer);
|
|
} while (topaz_priv->consumer != topaz_priv->producer);
|
|
|
|
/* When IRQ enabled, the belowing code will be called in ISR */
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
return 0;
|
|
#endif
|
|
|
|
if (cmd_id != MTX_CMDID_ENCODE_FRAME &&
|
|
cmd_id != MTX_CMDID_ISSUEBUFF)
|
|
return 0;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Handle context saving/fence " \
|
|
"handler/dequeue send on ENCODE_FRAME command\n");
|
|
|
|
if (get_ctx_cnt(dev) > 1) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: More than one context, " \
|
|
"save current context\n");
|
|
if (topaz_priv->cur_context->codec != IMG_CODEC_JPEG) {
|
|
ret = tng_topaz_save_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save mtx status");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
*topaz_priv->topaz_sync_addr = sync_seq;
|
|
(topaz_priv->cur_context)->handle_sequence_needed = false;
|
|
psb_fence_handler(dev, LNC_ENGINE_ENCODE);
|
|
|
|
topaz_priv->topaz_busy = 1;
|
|
tng_topaz_dequeue_send(dev);
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool tng_topaz_interrupt(void *pvData)
|
|
{
|
|
struct drm_device *dev;
|
|
/* struct drm_minor *minor; */
|
|
struct tng_topaz_private *topaz_priv;
|
|
struct drm_psb_private *dev_priv;
|
|
uint32_t crMultiCoreIntStat;
|
|
struct psb_video_ctx *video_ctx;
|
|
struct IMG_WRITEBACK_MSG *wb_msg;
|
|
unsigned long flags;
|
|
|
|
if (pvData == NULL) {
|
|
DRM_ERROR("Invalid params\n");
|
|
return false;
|
|
}
|
|
dev = (struct drm_device *)pvData;
|
|
/*
|
|
minor = (struct drm_minor *)container_of(dev, struct drm_minor, dev);
|
|
file_priv = (struct drm_file *)container_of(minor,
|
|
struct drm_file, minor);
|
|
*/
|
|
/*
|
|
if (!ospm_power_is_hw_on(OSPM_VIDEO_ENC_ISLAND)) {
|
|
DRM_ERROR("ERROR: interrupt arrived but HW is power off\n");
|
|
return false;
|
|
}
|
|
*/
|
|
dev_priv = (struct drm_psb_private *) dev->dev_private;
|
|
if (!dev_priv) {
|
|
DRM_ERROR("Failed to get dev_priv\n");
|
|
return false;
|
|
}
|
|
|
|
topaz_priv = dev_priv->topaz_private;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_INT_STAT,
|
|
&crMultiCoreIntStat);
|
|
|
|
/* if interrupts enabled and fired */
|
|
if ((crMultiCoreIntStat & MASK_TOPAZHP_TOP_CR_INT_STAT_MTX) ==
|
|
MASK_TOPAZHP_TOP_CR_INT_STAT_MTX) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Get MTX interrupt , clear IRQ\n");
|
|
tng_topaz_Int_clear(dev_priv, MASK_TOPAZHP_TOP_CR_INTCLR_MTX);
|
|
} else
|
|
return 0;
|
|
|
|
topaz_priv->consumer = tng_get_consumer(dev);
|
|
topaz_priv->producer = tng_get_producer(dev);
|
|
|
|
/* Encode ctx has already been destroyed by user-space process */
|
|
if (NULL == topaz_priv->irq_context) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: ctx destroyed before ISR.\n");
|
|
return true;
|
|
}
|
|
|
|
video_ctx = topaz_priv->irq_context;
|
|
wb_msg = (struct IMG_WRITEBACK_MSG *)
|
|
video_ctx->wb_addr[(topaz_priv->producer == 0) \
|
|
? 31 \
|
|
: topaz_priv->producer - 1];
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Dispatch write back message:\n");
|
|
PSB_DEBUG_TOPAZ("producer = %d, consumer = %d\n",
|
|
topaz_priv->producer, topaz_priv->consumer);
|
|
|
|
while (topaz_priv->consumer != topaz_priv->producer) {
|
|
topaz_priv->consumer++;
|
|
if (topaz_priv->consumer == WB_FIFO_SIZE)
|
|
topaz_priv->consumer = 0;
|
|
tng_set_consumer(dev, topaz_priv->producer);
|
|
};
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Context %p(%s): \n",
|
|
video_ctx, codec_to_string(video_ctx->codec));
|
|
PSB_DEBUG_TOPAZ("TOPAZ: frame %d, command %s IRQ\n",
|
|
video_ctx->frame_count,
|
|
cmd_to_string(wb_msg->ui32CmdWord));
|
|
|
|
video_ctx->frame_count++;
|
|
#if 0
|
|
if (video_ctx->codec == IMG_CODEC_JPEG) {
|
|
if (wb_msg->ui32CmdWord != MTX_CMDID_NULL) {
|
|
/* The LAST ISSUEBUF cmd means encoding complete */
|
|
if (--topaz_priv->issuebuf_cmd_count) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: JPEG ISSUEBUF cmd " \
|
|
"count left %d, return\n", \
|
|
topaz_priv->issuebuf_cmd_count);
|
|
return true;
|
|
}
|
|
} else {
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
*topaz_priv->topaz_sync_addr = wb_msg->ui32WritebackVal;
|
|
video_ctx->handle_sequence_needed = false;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Set seq %08x, " \
|
|
"dqueue cmd and schedule other work queue in %dms)\n",
|
|
wb_msg->ui32WritebackVal, drm_topaz_pmlatency);
|
|
psb_fence_handler(dev, LNC_ENGINE_ENCODE);
|
|
|
|
/* Launch the task anyway */
|
|
schedule_delayed_work(&topaz_priv->topaz_suspend_work, drm_topaz_pmlatency);
|
|
|
|
return true;
|
|
}
|
|
|
|
static int tng_submit_encode_cmdbuf(struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
struct ttm_buffer_object *cmd_buffer,
|
|
uint32_t cmd_offset, uint32_t cmd_size,
|
|
struct ttm_fence_object *fence)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
int ret = 0;
|
|
void *cmd;
|
|
uint32_t sequence = dev_priv->sequence[LNC_ENGINE_ENCODE];
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *video_ctx = NULL;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: command submit, topaz busy = %d\n",
|
|
topaz_priv->topaz_busy);
|
|
|
|
if (topaz_priv->topaz_fw_loaded == 0) {
|
|
/* #.# load fw to driver */
|
|
PSB_DEBUG_TOPAZ("TOPAZ:load /lib/firmware/topazhp_fw.bin\n");
|
|
if (Is_Secure_Fw())
|
|
ret = tng_securefw(dev, "topaz", "VEC", TNG_IMR6L_MSG_REGADDR);
|
|
else
|
|
ret = tng_rawfw(dev, "topaz");
|
|
if (ret) {
|
|
/* FIXME: find a proper return value */
|
|
DRM_ERROR("TOPAX:load firmware from storage failed\n");
|
|
return -EFAULT;
|
|
}
|
|
topaz_priv->topaz_fw_loaded = 1;
|
|
}
|
|
|
|
/* # if topaz need to reset, reset it */
|
|
if (topaz_priv->topaz_needs_reset) {
|
|
/* #.# reset it */
|
|
PSB_DEBUG_TOPAZ("TOPAZ: needs reset.\n");
|
|
|
|
tng_topaz_reset(dev_priv);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: reset ok.\n");
|
|
|
|
if (Is_Secure_Fw() == 0) {
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (!video_ctx) {
|
|
DRM_ERROR("Failed to get context from fp\n");
|
|
return -1;
|
|
}
|
|
|
|
/* #.# upload firmware */
|
|
ret = tng_topaz_setup_fw(dev, video_ctx, topaz_priv->cur_codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: upload FW to HW failed\n");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!topaz_priv->topaz_busy) {
|
|
/* # direct map topaz command if topaz is free */
|
|
PSB_DEBUG_TOPAZ("TOPAZ:direct send command,sequence %08x\n",
|
|
sequence);
|
|
|
|
ret = tng_topaz_deliver_command(dev, file_priv,
|
|
cmd_buffer, cmd_offset, cmd_size, NULL, sequence, 0);
|
|
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: failed to extract cmd...\n");
|
|
return ret;
|
|
}
|
|
} else {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: queue command of sequence %08x\n",
|
|
sequence);
|
|
cmd = NULL;
|
|
|
|
ret = tng_topaz_deliver_command(dev, file_priv,
|
|
cmd_buffer, cmd_offset, cmd_size, &cmd, sequence, 1);
|
|
if (cmd == NULL || ret) {
|
|
DRM_ERROR("TOPAZ: map command for save fialed\n");
|
|
return ret;
|
|
}
|
|
|
|
ret = tng_topaz_save_command(dev, file_priv,
|
|
cmd, cmd_size, sequence);
|
|
if (ret)
|
|
DRM_ERROR("TOPAZ: save command failed\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int tng_topaz_save_command(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
void *cmd,
|
|
uint32_t cmd_size,
|
|
uint32_t sequence)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_cmd_queue *topaz_cmd;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: queue command,sequence: %08x..\n",
|
|
sequence);
|
|
|
|
topaz_cmd = kzalloc(sizeof(struct tng_topaz_cmd_queue),
|
|
GFP_KERNEL);
|
|
if (!topaz_cmd) {
|
|
DRM_ERROR("TOPAZ: out of memory....\n");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
topaz_cmd->file_priv = file_priv;
|
|
topaz_cmd->cmd = cmd;
|
|
topaz_cmd->cmd_size = cmd_size;
|
|
topaz_cmd->sequence = sequence;
|
|
|
|
/* Avoid race condition with dequeue buffer in kernel task */
|
|
mutex_lock(&topaz_priv->topaz_mutex);
|
|
list_add_tail(&topaz_cmd->head, &topaz_priv->topaz_queue);
|
|
mutex_unlock(&topaz_priv->topaz_mutex);
|
|
|
|
if (!topaz_priv->topaz_busy) {
|
|
/* topaz_priv->topaz_busy = 1; */
|
|
PSB_DEBUG_TOPAZ("TOPAZ: need immediate dequeue...\n");
|
|
ret = tng_topaz_dequeue_send(dev);
|
|
if (ret)
|
|
return -1;
|
|
PSB_DEBUG_TOPAZ("TOPAZ: after dequeue command\n");
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
int tng_cmdbuf_video(struct drm_file *file_priv,
|
|
struct list_head *validate_list,
|
|
uint32_t fence_type,
|
|
struct drm_psb_cmdbuf_arg *arg,
|
|
struct ttm_buffer_object *cmd_buffer,
|
|
struct psb_ttm_fence_rep *fence_arg)
|
|
{
|
|
struct drm_device *dev = file_priv->minor->dev;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct ttm_fence_object *fence = NULL;
|
|
int32_t ret = 0;
|
|
|
|
if (topaz_priv->vec_err == 1) {
|
|
DRM_ERROR("TOPAZ: VEC has error, bypass submit cmd");
|
|
return -1;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ : enter %s cmdsize: %d\n", __func__,
|
|
arg->cmdbuf_size);
|
|
|
|
ret = tng_submit_encode_cmdbuf(dev, file_priv, cmd_buffer,
|
|
arg->cmdbuf_offset, arg->cmdbuf_size, fence);
|
|
if (ret) {
|
|
topaz_priv->vec_err = 1;
|
|
return ret;
|
|
}
|
|
|
|
/* workaround for interrupt issue */
|
|
psb_fence_or_sync(file_priv, LNC_ENGINE_ENCODE,
|
|
fence_type, arg->fence_flags,
|
|
validate_list, fence_arg, &fence);
|
|
PSB_DEBUG_TOPAZ("TOPAZ : current fence 0x%08x\n",
|
|
dev_priv->sequence[LNC_ENGINE_ENCODE]);
|
|
if (fence)
|
|
ttm_fence_object_unref(&fence);
|
|
|
|
spin_lock(&cmd_buffer->bdev->fence_lock);
|
|
if (cmd_buffer->sync_obj != NULL)
|
|
ttm_fence_sync_obj_unref(&cmd_buffer->sync_obj);
|
|
spin_unlock(&cmd_buffer->bdev->fence_lock);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ exit %s\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
#define SHIFT_MTX_CMDWORD_ID (0)
|
|
#define MASK_MTX_CMDWORD_ID (0xff << SHIFT_MTX_CMDWORD_ID)
|
|
#define SHIFT_MTX_CMDWORD_CORE (8)
|
|
#define MASK_MTX_CMDWORD_CORE (0xff << SHIFT_MTX_CMDWORD_CORE)
|
|
#define SHIFT_MTX_CMDWORD_COUNT (16)
|
|
#define MASK_MTX_CMDWORD_COUNT (0xffff << SHIFT_MTX_CMDWORD_COUNT)
|
|
|
|
#define SHIFT_MTX_WBWORD_ID (0)
|
|
#define MASK_MTX_WBWORD_ID (0xff << SHIFT_MTX_WBWORD_ID)
|
|
#define SHIFT_MTX_WBWORD_CORE (8)
|
|
#define MASK_MTX_WBWORD_CORE (0xff << SHIFT_MTX_WBWORD_CORE)
|
|
|
|
#if 0
|
|
static int tng_error_dump_reg(struct drm_psb_private *dev_priv)
|
|
{
|
|
uint32_t reg_val;
|
|
PSB_DEBUG_TOPAZ("MULTICORE Registers:\n");
|
|
MULTICORE_READ32(0x00, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_SRST %08x\n", reg_val);
|
|
MULTICORE_READ32(0x04, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_INT_STAT %08x\n", reg_val);
|
|
MULTICORE_READ32(0x08, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_MTX_INT_ENAB %08x\n", reg_val);
|
|
MULTICORE_READ32(0x0C, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_HOST_INT_ENAB %08x\n", reg_val);
|
|
MULTICORE_READ32(0x10, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_INT_CLEAR %08x\n", reg_val);
|
|
MULTICORE_READ32(0x14, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_MAN_CLK_GATE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x18, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZ_MTX_C_RATIO %08x\n", reg_val);
|
|
MULTICORE_READ32(0x1c, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_STATUS %08x\n", reg_val);
|
|
MULTICORE_READ32(0x1c, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_STATUS %08x\n", reg_val);
|
|
MULTICORE_READ32(0x20, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_MEM_REQ %08x\n", reg_val);
|
|
MULTICORE_READ32(0x24, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_CONTROL0 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x28, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_CONTROL1 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x2c , ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_CONTROL2 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x30, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_DIR_LIST_BASE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x38, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_TILE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x44, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_DEBUG_MSTR %08x\n", reg_val);
|
|
MULTICORE_READ32(0x48, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_DEBUG_SLV %08x\n", reg_val);
|
|
MULTICORE_READ32(0x50, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_CORE_SEL_0 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x54, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_CORE_SEL_1 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x58, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_HW_CFG %08x\n", reg_val);
|
|
MULTICORE_READ32(0x60, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_CMD_FIFO_WRITE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x64, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_CMD_FIFO_WRITE_SPACE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x70, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZ_CMD_FIFO_READ %08x\n", reg_val);
|
|
MULTICORE_READ32(0x74, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZ_CMD_FIFO_READ_AVAILABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x78, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZ_CMD_FIFO_FLUSH %08x\n", reg_val);
|
|
MULTICORE_READ32(0x80, ®_val);
|
|
PSB_DEBUG_TOPAZ("MMU_TILE_EXT %08x\n", reg_val);
|
|
MULTICORE_READ32(0x100, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_1 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x104, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_2 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x108, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_3 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x110, ®_val);
|
|
PSB_DEBUG_TOPAZ("CYCLE_COUNTER %08x\n", reg_val);
|
|
MULTICORE_READ32(0x114, ®_val);
|
|
PSB_DEBUG_TOPAZ("CYCLE_COUNTER_CTRL %08x\n", reg_val);
|
|
MULTICORE_READ32(0x118, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_IDLE_PWR_MAN %08x\n", reg_val);
|
|
MULTICORE_READ32(0x124, ®_val);
|
|
PSB_DEBUG_TOPAZ("DIRECT_BIAS_TABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x128, ®_val);
|
|
PSB_DEBUG_TOPAZ("INTRA_BIAS_TABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x12c, ®_val);
|
|
PSB_DEBUG_TOPAZ("INTER_BIAS_TABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x130, ®_val);
|
|
PSB_DEBUG_TOPAZ("INTRA_SCALE_TABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x134, ®_val);
|
|
PSB_DEBUG_TOPAZ("QPCB_QPCR_OFFSET %08x\n", reg_val);
|
|
MULTICORE_READ32(0x140, ®_val);
|
|
PSB_DEBUG_TOPAZ("INTER_INTRA_SCALE_TABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x144, ®_val);
|
|
PSB_DEBUG_TOPAZ("SKIPPED_CODED_SCALE_TABLE %08x\n", reg_val);
|
|
MULTICORE_READ32(0x148, ®_val);
|
|
PSB_DEBUG_TOPAZ("POLYNOM_ALPHA_COEFF_CORE0 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x14c, ®_val);
|
|
PSB_DEBUG_TOPAZ("POLYNOM_GAMMA_COEFF_CORE0 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x150, ®_val);
|
|
PSB_DEBUG_TOPAZ("POLYNOM_CUTOFF_CORE0 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x154, ®_val);
|
|
PSB_DEBUG_TOPAZ("POLYNOM_ALPHA_COEFF_CORE1 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x158, ®_val);
|
|
PSB_DEBUG_TOPAZ("POLYNOM_GAMMA_COEFF_CORE1 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x15c, ®_val);
|
|
PSB_DEBUG_TOPAZ("POLYNOM_CUTOFF_CORE1 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x300, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_4 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x304, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_5 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x308, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_6 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x30c, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIRMWARE_REG_7 %08x\n", reg_val);
|
|
MULTICORE_READ32(0x3b0, ®_val);
|
|
PSB_DEBUG_TOPAZ("MULTICORE_RSVD0 %08x\n", reg_val);
|
|
|
|
PSB_DEBUG_TOPAZ("TopazHP Core Registers:\n");
|
|
TOPAZCORE_READ32(0, 0x0, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_SRST %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x4, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_INTSTAT %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x8, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_MTX_INTENAB %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0xc, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_HOST_INTENAB %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x10, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_INTCLEAR %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x14, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_INT_COMB_SEL %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x18, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_BUSY %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x24, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_AUTO_CLOCK_GATING %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x28, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_MAN_CLOCK_GATING %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x30, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_RTM %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x34, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_RTM_VALUE %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x38, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_MB_PERFORMANCE_RESULT %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x3c, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_MB_PERFORMANCE_MB_NUMBER %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x188, ®_val);
|
|
PSB_DEBUG_TOPAZ("FIELD_PARITY %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x3d0, ®_val);
|
|
PSB_DEBUG_TOPAZ("WEIGHTED_PRED_CONTROL %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x3d4, ®_val);
|
|
PSB_DEBUG_TOPAZ("WEIGHTED_PRED_COEFFS %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x3e0, ®_val);
|
|
PSB_DEBUG_TOPAZ("WEIGHTED_PRED_INV_WEIGHT %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x3f0, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_RSVD0 %08x\n", reg_val);
|
|
TOPAZCORE_READ32(0, 0x3f4, ®_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZHP_CRC_CLEAR %08x\n", reg_val);
|
|
|
|
|
|
PSB_DEBUG_TOPAZ("MTX Registers:\n");
|
|
MTX_READ32(0x00, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_ENABLE %08x\n", reg_val);
|
|
MTX_READ32(0x08, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_STATUS %08x\n", reg_val);
|
|
MTX_READ32(0x80, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_KICK %08x\n", reg_val);
|
|
MTX_READ32(0x88, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_KICKI %08x\n", reg_val);
|
|
MTX_READ32(0x90, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_FAULT0 %08x\n", reg_val);
|
|
MTX_READ32(0xf8, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_REGISTER_READ_WRITE_DATA %08x\n", reg_val);
|
|
MTX_READ32(0xfc, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_REGISTER_READ_WRITE_REQUEST %08x\n", reg_val);
|
|
MTX_READ32(0x100, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_RAM_ACCESS_DATA_EXCHANGE %08x\n", reg_val);
|
|
MTX_READ32(0x104, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_RAM_ACCESS_DATA_TRANSFER %08x\n", reg_val);
|
|
MTX_READ32(0x108, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_RAM_ACCESS_CONTROL %08x\n", reg_val);
|
|
MTX_READ32(0x10c, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_RAM_ACCESS_STATUS %08x\n", reg_val);
|
|
MTX_READ32(0x200, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_SOFT_RESET %08x\n", reg_val);
|
|
MTX_READ32(0x340, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_SYSC_CDMAC %08x\n", reg_val);
|
|
MTX_READ32(0x344, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_SYSC_CDMAA %08x\n", reg_val);
|
|
MTX_READ32(0x348, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_SYSC_CDMAS0 %08x\n", reg_val);
|
|
MTX_READ32(0x34c, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_SYSC_CDMAS1 %08x\n", reg_val);
|
|
MTX_READ32(0x350, ®_val);
|
|
PSB_DEBUG_TOPAZ("MTX_SYSC_CDMAT %08x\n", reg_val);
|
|
|
|
PSB_DEBUG_TOPAZ("DMA Registers:\n");
|
|
DMAC_READ32(0x00, ®_val);
|
|
PSB_DEBUG_TOPAZ("DMA_Setup_n %08x\n", reg_val);
|
|
DMAC_READ32(0x04, ®_val);
|
|
PSB_DEBUG_TOPAZ("DMA_Count_n %08x\n", reg_val);
|
|
DMAC_READ32(0x08, ®_val);
|
|
PSB_DEBUG_TOPAZ(" DMA_Peripheral_param_n %08x\n", reg_val);
|
|
DMAC_READ32(0x0C, ®_val);
|
|
PSB_DEBUG_TOPAZ("DMA_IRQ_Stat_n %08x\n", reg_val);
|
|
DMAC_READ32(0x10, ®_val);
|
|
PSB_DEBUG_TOPAZ("DMA_2D_Mode_n %08x\n", reg_val);
|
|
DMAC_READ32(0x14, ®_val);
|
|
PSB_DEBUG_TOPAZ("DMA_Peripheral_addr_n %08x\n", reg_val);
|
|
DMAC_READ32(0x18, ®_val);
|
|
PSB_DEBUG_TOPAZ("DMA_Per_hold %08x\n", reg_val);
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int tng_topaz_deliver_command(struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
struct ttm_buffer_object *cmd_buffer,
|
|
uint32_t cmd_offset, uint32_t cmd_size,
|
|
void **topaz_cmd, uint32_t sequence,
|
|
int copy_cmd)
|
|
{
|
|
unsigned long cmd_page_offset = cmd_offset & ~PAGE_MASK;
|
|
struct ttm_bo_kmap_obj cmd_kmap;
|
|
bool is_iomem;
|
|
int ret;
|
|
unsigned char *cmd_start, *tmp;
|
|
|
|
if (cmd_size > (cmd_buffer->num_pages << PAGE_SHIFT)) {
|
|
DRM_ERROR("Command size %d is bigger than " \
|
|
"command buffer size %d", cmd_size,
|
|
(uint32_t)cmd_buffer->num_pages << PAGE_SHIFT);
|
|
return -EINVAL;
|
|
}
|
|
|
|
ret = ttm_bo_kmap(cmd_buffer, cmd_offset >> PAGE_SHIFT, 2,
|
|
&cmd_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: drm_bo_kmap failed: %d\n", ret);
|
|
return ret;
|
|
}
|
|
cmd_start = (unsigned char *) ttm_kmap_obj_virtual(&cmd_kmap,
|
|
&is_iomem) + cmd_page_offset;
|
|
|
|
if (copy_cmd) {
|
|
tmp = kzalloc(cmd_size, GFP_KERNEL);
|
|
if (tmp == NULL) {
|
|
ret = -ENOMEM;
|
|
goto out;
|
|
}
|
|
memcpy(tmp, cmd_start, cmd_size);
|
|
*topaz_cmd = tmp;
|
|
} else {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: directly send the command\n");
|
|
ret = tng_topaz_send(dev, file_priv,
|
|
cmd_start, cmd_size, sequence);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: commit commands failed.\n");
|
|
ret = -EINVAL;
|
|
}
|
|
}
|
|
|
|
out:
|
|
ttm_bo_kunmap(&cmd_kmap);
|
|
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
static int32_t tng_topaz_wait_for_completion(struct drm_psb_private *dev_priv)
|
|
{
|
|
int32_t ret = 0;
|
|
|
|
mtx_set_target(dev_priv);
|
|
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_ISEQUAL,
|
|
REG_OFFSET_TOPAZ_MTX + MTX_CR_MTX_ENABLE,
|
|
MASK_MTX_MTX_TOFF,
|
|
MASK_MTX_MTX_TOFF | MASK_MTX_MTX_ENABLE, 1);
|
|
if (ret)
|
|
DRM_ERROR("TOPAZ: Wait for MTX completion time out\n");
|
|
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
static int32_t tng_restore_bias_table(
|
|
struct drm_device *dev,
|
|
struct psb_video_ctx *video_ctx)
|
|
{
|
|
/* bool is_iomem; */
|
|
uint32_t i;
|
|
uint32_t *p_command;
|
|
uint32_t reg_id;
|
|
uint32_t reg_off;
|
|
uint32_t reg_val;
|
|
uint32_t size;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
int32_t ret = 0;
|
|
|
|
p_command = video_ctx->bias_reg;
|
|
if (p_command == NULL) {
|
|
DRM_ERROR("TOPAZ: Failed to get BIAS reg pointer");
|
|
return -1;
|
|
}
|
|
|
|
size = *p_command++;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Restore BIAS %d registers " \
|
|
"of ctx %p(%s)\n",
|
|
size - 1, video_ctx, \
|
|
codec_to_string(video_ctx->codec));
|
|
for (i = 0; i < size; i++) {
|
|
reg_id = *p_command;
|
|
p_command++;
|
|
reg_off = *p_command;
|
|
p_command++;
|
|
reg_val = *p_command;
|
|
p_command++;
|
|
|
|
switch (reg_id) {
|
|
case TOPAZ_MULTICORE_REG:
|
|
MULTICORE_WRITE32(reg_off, reg_val);
|
|
break;
|
|
case TOPAZ_CORE_REG:
|
|
TOPAZCORE_WRITE32(0, reg_off, reg_val);
|
|
break;
|
|
case TOPAZ_VLC_REG:
|
|
VLC_WRITE32(0, reg_off, reg_val);
|
|
break;
|
|
default:
|
|
DRM_ERROR("Unknown reg space id: %08x\n", reg_id);
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t tng_topaz_restore_mtx_state(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
(struct drm_psb_private *)dev->dev_private;
|
|
uint32_t *mtx_reg_state;
|
|
int i, need_restore = 0;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *pos, *n;
|
|
|
|
/* struct ttm_bo_kmap_obj tmp_kmap; */
|
|
/* bool is_iomem; */
|
|
int32_t ret = 0;
|
|
uint32_t num_pipes;
|
|
struct psb_video_ctx *video_ctx = topaz_priv->cur_context;
|
|
|
|
/*if (!topaz_priv->topaz_mtx_saved)
|
|
return -1;
|
|
*/
|
|
|
|
list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
|
|
if ((pos->ctx_type & 0xff) == VAEntrypointEncSlice ||
|
|
(pos->ctx_type & 0xff) == VAEntrypointEncPicture)
|
|
need_restore = 1;
|
|
}
|
|
|
|
if (0 == need_restore) {
|
|
topaz_priv->topaz_mtx_saved = 0;
|
|
PSB_DEBUG_TOPAZ("topaz: no vec context found. needn't" \
|
|
" to restore mtx registers.\n");
|
|
return ret;
|
|
}
|
|
|
|
if (topaz_priv->topaz_fw_loaded == 0) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: needn't to restore context" \
|
|
" without firmware uploaded\n");
|
|
return ret;
|
|
}
|
|
|
|
/*TopazSC will be reset, no need to restore context.*/
|
|
if (topaz_priv->topaz_needs_reset)
|
|
return ret;
|
|
/*There is no need to restore context for JPEG encoding*/
|
|
/*
|
|
if (TNG_IS_JPEG_ENC(topaz_priv->cur_codec)) {
|
|
if (tng_topaz_setup_fw(dev, 0, topaz_priv->cur_codec))
|
|
DRM_ERROR("TOPAZ: Setup JPEG firmware fails!\n");
|
|
topaz_priv->topaz_mtx_saved = 0;
|
|
return 0;
|
|
}
|
|
*/
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_HW_CFG, &num_pipes);
|
|
num_pipes = num_pipes & MASK_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED;
|
|
|
|
/* Clear registers used for Host-FW communications */
|
|
MULTICORE_WRITE32(MTX_SCRATCHREG_IDLE, 0);
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 + (MTX_SCRATCHREG_BOOTSTATUS << 2), 0);
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 + (MTX_SCRATCHREG_TOHOST << 2), 0);
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 + (MTX_SCRATCHREG_TOMTX << 2), 0);
|
|
|
|
mtx_set_target(dev_priv);
|
|
|
|
/* write the topaz reset bits */
|
|
/*1) Disable MTX by writing one to the MTX_TOFF
|
|
field of the MTX_ENABLE register*/
|
|
MTX_WRITE32(MTX_CR_MTX_ENABLE,
|
|
MASK_MTX_MTX_TOFF);
|
|
|
|
/* 2) Software reset MTX only by writing 0x1
|
|
then 0x0 to the MULTICORE_SRST register */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_SRST, 1);
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_SRST, 0);
|
|
|
|
/* 3) Software reset MTX, cores, and IO by writing 0x7
|
|
then 0x0 to the MULTICORE_SRST register */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_SRST,
|
|
F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_CORE_SOFT_RESET) |
|
|
F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_IO_SOFT_RESET) |
|
|
F_ENCODE(1, TOPAZHP_TOP_CR_IMG_TOPAZ_MTX_SOFT_RESET));
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_SRST, 0);
|
|
|
|
MTX_WRITE32(MTX_CR_MTX_SOFT_RESET, MASK_MTX_MTX_RESET);
|
|
|
|
PSB_UDELAY(6);
|
|
|
|
MTX_WRITE32(MTX_CR_MTX_SOFT_RESET, 0);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Restore status of context %p(%s)\n",
|
|
video_ctx, codec_to_string(video_ctx->codec));
|
|
|
|
/* restore register */
|
|
mtx_reg_state = (uint32_t *)(topaz_priv->topaz_mtx_reg_state[0]);
|
|
if (mtx_reg_state == NULL) {
|
|
DRM_ERROR("TOPAZ: Failed to get MTX register state pointer");
|
|
return -1;
|
|
}
|
|
|
|
/* Restore the MMU Control Registers */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE(0),
|
|
*mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_TILE(0),
|
|
*mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_TILE(1),
|
|
*mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_CONTROL2, *mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_CONTROL1, *mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
/* we do not want to run in secre FW mode so write a place
|
|
* holder to the FIFO that the firmware will know to ignore */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
TOPAZHP_NON_SECURE_FW_MARKER);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_CONTROL0, *mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
/* CARC registers */
|
|
for (i = 0; i < num_pipes; i++) {
|
|
TOPAZCORE_WRITE32(i, INTEL_JMCMP_CF_TOTAL,
|
|
*mtx_reg_state);
|
|
mtx_reg_state++;
|
|
}
|
|
|
|
for (i = 0; i < num_pipes; i++) {
|
|
TOPAZCORE_WRITE32(i, TOPAZHP_CR_TOPAZHP_AUTO_CLOCK_GATING,
|
|
*mtx_reg_state);
|
|
mtx_reg_state++;
|
|
TOPAZCORE_WRITE32(i, TOPAZHP_CR_TOPAZHP_MAN_CLOCK_GATING,
|
|
*mtx_reg_state);
|
|
mtx_reg_state++;
|
|
}
|
|
|
|
ret = mtx_upload_fw(dev, video_ctx->codec, video_ctx);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to upload firmware for codec %s\n",
|
|
codec_to_string(video_ctx->codec));
|
|
/* tng_error_dump_reg(dev_priv); */
|
|
return ret;
|
|
}
|
|
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
|
|
/* Turn on MTX */
|
|
mtx_start(dev);
|
|
|
|
/* Kick the MTX to get things running */
|
|
mtx_kick(dev);
|
|
|
|
/* topaz_priv->topaz_mtx_saved = 0; */
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Restore MTX status return\n");
|
|
|
|
video_ctx->status &= ~MASK_TOPAZ_CONTEXT_SAVED;
|
|
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
psb_irq_preinstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
|
|
psb_irq_postinstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
|
|
|
|
tng_topaz_enableirq(dev);
|
|
#endif
|
|
tng_topaz_setvideo(dev, video_ctx);
|
|
|
|
ret = tng_restore_bias_table(dev, video_ctx);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore BIAS table");
|
|
goto out;
|
|
}
|
|
out:
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
return ret;
|
|
}
|
|
|
|
int32_t tng_topaz_restore_mtx_state_b0(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
(struct drm_psb_private *)dev->dev_private;
|
|
uint32_t *mtx_reg_state;
|
|
int i, need_restore = 0;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *pos, *n;
|
|
|
|
/* struct ttm_bo_kmap_obj tmp_kmap; */
|
|
/* bool is_iomem; */
|
|
int32_t ret = 0;
|
|
uint32_t num_pipes;
|
|
struct psb_video_ctx *video_ctx = topaz_priv->cur_context;
|
|
|
|
/*if (!topaz_priv->topaz_mtx_saved)
|
|
return -1;
|
|
*/
|
|
|
|
list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
|
|
if ((pos->ctx_type & 0xff) == VAEntrypointEncSlice ||
|
|
(pos->ctx_type & 0xff) == VAEntrypointEncPicture)
|
|
need_restore = 1;
|
|
}
|
|
|
|
if (0 == need_restore) {
|
|
topaz_priv->topaz_mtx_saved = 0;
|
|
PSB_DEBUG_TOPAZ("topaz: no vec context found. needn't" \
|
|
" to restore mtx registers.\n");
|
|
return ret;
|
|
}
|
|
|
|
if (topaz_priv->topaz_fw_loaded == 0) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: needn't to restore context" \
|
|
" without firmware uploaded\n");
|
|
return ret;
|
|
}
|
|
|
|
if (topaz_priv->topaz_mtx_reg_state[0] == NULL) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: try to restore context" \
|
|
" without space allocated, return" \
|
|
" directly without restore\n");
|
|
ret = -1;
|
|
return ret;
|
|
}
|
|
|
|
/*TopazSC will be reset, no need to restore context.*/
|
|
if (topaz_priv->topaz_needs_reset)
|
|
return ret;
|
|
/*There is no need to restore context for JPEG encoding*/
|
|
/*
|
|
if (TNG_IS_JPEG_ENC(topaz_priv->cur_codec)) {
|
|
if (tng_topaz_setup_fw(dev, 0, topaz_priv->cur_codec))
|
|
DRM_ERROR("TOPAZ: Setup JPEG firmware fails!\n");
|
|
topaz_priv->topaz_mtx_saved = 0;
|
|
return 0;
|
|
}
|
|
*/
|
|
ret = intel_mid_msgbus_read32(PUNIT_PORT, VEC_SS_PM0);
|
|
PSB_DEBUG_TOPAZ("Read R(0x%08x) V(0x%08x)\n",
|
|
VEC_SS_PM0, ret);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Restore status of context %p(%s)\n",
|
|
video_ctx, codec_to_string(video_ctx->codec));
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_HW_CFG, &num_pipes);
|
|
num_pipes = num_pipes & MASK_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Restore status of pipe (%d)\n",
|
|
num_pipes);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
/* repeat fw_run's steps */
|
|
/* clock gating */
|
|
reg_val = F_ENCODE(1, TOPAZHP_CR_TOPAZHP_VLC_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_DEB_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_IPE0_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_IPE1_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_SPE0_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_SPE1_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_H264COMP4X4_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_H264COMP8X8_AUTO_CLK_GATE)|
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_H264COMP16X16_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_JMCOMP_AUTO_CLK_GATE)|
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_PC_DM_AUTO_CLK_GATE) |
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_PC_DMS_AUTO_CLK_GATE)|
|
|
F_ENCODE(1, TOPAZHP_CR_TOPAZHP_CABAC_AUTO_CLK_GATE);
|
|
|
|
TOPAZCORE_WRITE32(0, TOPAZHP_CR_TOPAZHP_AUTO_CLOCK_GATING, reg_val);
|
|
#endif
|
|
|
|
/* restore register */
|
|
mtx_reg_state = (uint32_t *)(topaz_priv->topaz_mtx_reg_state[0]);
|
|
|
|
/* Restore the MMU Control Registers */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE(0),
|
|
*mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: MMU_DIR_LIST_BASE(0) == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_TILE(0), *mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: CR_MMU_TILE(0) == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_TILE(1), *mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: CR_MMU_TILE(1) == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_CONTROL2, *mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: CR_MMU_CONTROL2 == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_CONTROL1, *mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: CR_MMU_CONTROL1 == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
|
|
/* we do not want to run in secre FW mode so write a place
|
|
* holder to the FIFO that the firmware will know to ignore */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
*mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: CMD_FIFO_WRITE == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
#ifdef MRFLD_B0_DEBUG
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
TOPAZHP_NON_SECURE_FW_MARKER);
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: CMD_FIFO_WRITE == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
|
|
/* MULTICORE_WRITE32(TOPAZHP_TOP_CR_MMU_CONTROL0, *mtx_reg_state); */
|
|
mtx_reg_state++;
|
|
|
|
/* CARC registers */
|
|
for (i = 0; i < num_pipes; i++) {
|
|
TOPAZCORE_WRITE32(i, INTEL_JMCMP_CF_TOTAL, *mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: JMCMP_CF_TOTAL == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
}
|
|
|
|
for (i = 0; i < num_pipes; i++) {
|
|
TOPAZCORE_WRITE32(i, TOPAZHP_CR_TOPAZHP_AUTO_CLOCK_GATING,
|
|
*mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: AUTO_CLOCK_GATING == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
TOPAZCORE_WRITE32(i, TOPAZHP_CR_TOPAZHP_MAN_CLOCK_GATING,
|
|
*mtx_reg_state);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
PSB_DEBUG_TOPAZ("TOPAZ Restore: MAN_CLOCK_GATING == 0x%08x\n",
|
|
*mtx_reg_state);
|
|
#endif
|
|
mtx_reg_state++;
|
|
}
|
|
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CORE_SEL_0, 0);
|
|
/* Turn on MTX */
|
|
mtx_start(dev);
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CORE_SEL_0, 0);
|
|
/* Kick the MTX to get things running */
|
|
mtx_kick(dev);
|
|
ret = tng_topaz_wait_for_register(
|
|
dev_priv, CHECKFUNC_ISEQUAL,
|
|
TOPAZHP_TOP_CR_FIRMWARE_REG_1 + (MTX_SCRATCHREG_BOOTSTATUS<<2),
|
|
TOPAZHP_FW_BOOT_SIGNAL, 0xffffffff, 1);
|
|
if (ret) {
|
|
DRM_ERROR("Restore Firmware failed\n");
|
|
return ret;
|
|
}
|
|
|
|
tng_topaz_mmu_flushcache(dev_priv);
|
|
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
psb_irq_preinstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
|
|
psb_irq_postinstall_islands(dev, OSPM_VIDEO_ENC_ISLAND);
|
|
|
|
tng_topaz_enableirq(dev);
|
|
#endif
|
|
|
|
ret = tng_restore_bias_table(dev, video_ctx);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore BIAS table");
|
|
goto out;
|
|
}
|
|
|
|
tng_topaz_setvideo(dev, video_ctx);
|
|
|
|
video_ctx->status &= ~MASK_TOPAZ_CONTEXT_SAVED;
|
|
/* topaz_priv->topaz_mtx_saved = 0; */
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Restore MTX status return\n");
|
|
out:
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int tng_poll_hw_inactive(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
int32_t ret = 0;
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_ISEQUAL,
|
|
MTX_SCRATCHREG_IDLE,
|
|
F_ENCODE(FW_IDLE_STATUS_IDLE, FW_IDLE_REG_STATUS),
|
|
MASK_FW_IDLE_REG_STATUS, 0);
|
|
if (ret)
|
|
DRM_ERROR("Wait for register timeout");
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int mtx_wait_for_completion(struct drm_psb_private *dev_priv)
|
|
{
|
|
int32_t ret;
|
|
|
|
mtx_set_target(dev_priv);
|
|
|
|
ret = tng_topaz_wait_for_register(dev_priv, CHECKFUNC_ISEQUAL,
|
|
REG_OFFSET_TOPAZ_MTX + MTX_CR_MTX_ENABLE,
|
|
MASK_MTX_MTX_TOFF,
|
|
MASK_MTX_MTX_TOFF | MASK_MTX_MTX_ENABLE, 1);
|
|
if (ret)
|
|
DRM_ERROR("TOPAZ: Wait for MTX completion time out\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
int tng_topaz_save_mtx_state(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
(struct drm_psb_private *)dev->dev_private;
|
|
uint32_t *mtx_reg_state;
|
|
int i, need_save = 0;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *pos, *n;
|
|
/* struct ttm_bo_kmap_obj tmp_kmap; */
|
|
struct psb_video_ctx *video_ctx;
|
|
/* bool is_iomem; */
|
|
uint32_t num_pipes;
|
|
int32_t ret = 0;
|
|
unsigned long irq_flags;
|
|
|
|
PSB_DEBUG_TOPAZ("tng_topaz_save_mtx_state: start\n");
|
|
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
mutex_lock(&topaz_priv->ctx_mutex);
|
|
|
|
/* In case the context has been removed in
|
|
* tng_topaz_remove_ctx()
|
|
*/
|
|
video_ctx = topaz_priv->irq_context;
|
|
if (!video_ctx || !video_ctx->wb_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Context %p has " \
|
|
"been released, bypass saving context\n", \
|
|
video_ctx);
|
|
goto out;
|
|
}
|
|
#else
|
|
if (topaz_priv->cur_context) {
|
|
video_ctx = topaz_priv->cur_context;
|
|
} else {
|
|
DRM_ERROR("Invalid context\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
/* topaz_priv->topaz_mtx_saved = 0; */
|
|
list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
|
|
if ((pos->ctx_type & 0xff) == VAEntrypointEncSlice ||
|
|
(pos->ctx_type & 0xff) == VAEntrypointEncPicture)
|
|
need_save = 1;
|
|
}
|
|
|
|
if (0 == need_save) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: vec context not found. No need" \
|
|
" to save mtx registers.\n");
|
|
goto out;
|
|
}
|
|
|
|
/*TopazSC will be reset, no need to save context.*/
|
|
if (topaz_priv->topaz_needs_reset)
|
|
goto out;
|
|
|
|
if (topaz_priv->topaz_fw_loaded == 0) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: No need to restore context since" \
|
|
" firmware has not been uploaded.\n");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
/*JPEG encoding needn't to save context*/
|
|
if (TNG_IS_JPEG_ENC(topaz_priv->cur_codec)) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Bypass context saving for JPEG\n");
|
|
topaz_priv->topaz_mtx_saved = 1;
|
|
goto out;
|
|
}
|
|
|
|
tng_topaz_mmu_flushcache(dev_priv);
|
|
|
|
tng_topaz_getvideo(dev, video_ctx);
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_HW_CFG, &num_pipes);
|
|
num_pipes = num_pipes & MASK_TOPAZHP_TOP_CR_NUM_CORES_SUPPORTED;
|
|
|
|
mtx_set_target(dev_priv);
|
|
|
|
ret = tng_poll_hw_inactive(dev);
|
|
if (ret)
|
|
goto out;
|
|
|
|
/* Turn off MTX */
|
|
mtx_stop(dev_priv);
|
|
ret = mtx_wait_for_completion(dev_priv);
|
|
if (ret) {
|
|
DRM_ERROR("Mtx wait for completion error");
|
|
goto out;
|
|
}
|
|
|
|
mtx_reg_state = (uint32_t *)(topaz_priv->topaz_mtx_reg_state[0]);
|
|
if (mtx_reg_state == NULL) {
|
|
DRM_ERROR("TOPAZ: Failed to get MTX register state pointer");
|
|
return -1;
|
|
}
|
|
|
|
/* Save the MMU Control Registers */
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MMU_DIR_LIST_BASE(0), mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MMU_TILE(0), mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MMU_TILE(1), mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MMU_CONTROL2, mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MMU_CONTROL1, mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MMU_CONTROL0, mtx_reg_state);
|
|
mtx_reg_state++;
|
|
|
|
/* CARC registers */
|
|
for (i = 0; i < num_pipes; i++) {
|
|
TOPAZCORE_READ32(i, INTEL_JMCMP_CF_TOTAL, mtx_reg_state);
|
|
mtx_reg_state++;
|
|
}
|
|
|
|
for (i = 0; i < num_pipes; i++) {
|
|
TOPAZCORE_READ32(i, TOPAZHP_CR_TOPAZHP_AUTO_CLOCK_GATING,
|
|
mtx_reg_state);
|
|
mtx_reg_state++;
|
|
TOPAZCORE_READ32(i, TOPAZHP_CR_TOPAZHP_MAN_CLOCK_GATING,
|
|
mtx_reg_state);
|
|
mtx_reg_state++;
|
|
}
|
|
|
|
video_ctx->status |= MASK_TOPAZ_CONTEXT_SAVED;
|
|
|
|
out:
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
mutex_unlock(&topaz_priv->ctx_mutex);
|
|
#endif
|
|
/* topaz_priv->topaz_mtx_saved = 1; */
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Save MTX status return\n");
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
return ret;
|
|
}
|
|
|
|
struct file *tng_get_context_fp(
|
|
struct drm_psb_private *dev_priv,
|
|
struct drm_file *file_priv)
|
|
{
|
|
struct file *current_context = NULL;
|
|
struct psb_video_ctx *pos, *n;
|
|
|
|
list_for_each_entry_safe(pos, n, &dev_priv->video_ctx, head) {
|
|
if (pos->filp == file_priv->filp)
|
|
current_context = pos->filp;
|
|
}
|
|
|
|
return current_context;
|
|
}
|
|
|
|
static int tng_save_bias_table(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
const void *cmd)
|
|
{
|
|
/* bool is_iomem; */
|
|
uint32_t *reg_saving_ptr;
|
|
uint32_t size;
|
|
/* struct ttm_bo_kmap_obj tmp_kmap; */
|
|
uint32_t *p_command;
|
|
struct psb_video_ctx *video_ctx;
|
|
int32_t ret = 0;
|
|
|
|
p_command = (uint32_t *)cmd;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
reg_saving_ptr = video_ctx->bias_reg;
|
|
|
|
p_command++;
|
|
/* Register count */
|
|
size = *reg_saving_ptr = *p_command;
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Save BIAS table %d registers " \
|
|
"for context %p\n", size, video_ctx);
|
|
|
|
p_command++;
|
|
reg_saving_ptr++;
|
|
|
|
memcpy(reg_saving_ptr, p_command, size * 3 * 4);
|
|
|
|
/* ttm_bo_kunmap(&tmp_kmap); */
|
|
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
#if 0
|
|
/*
|
|
* Check contxt status and assign ID for new context
|
|
* Return -1 on error
|
|
*/
|
|
static int tng_check_context_status(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint32_t reg_handle,
|
|
uint32_t data_handle,
|
|
uint32_t codec,
|
|
uint32_t *buf_idx)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* If current context issued MTX_CMDID_SHUTDOWN command, mark the ctx_status,
|
|
* clean related reg/data BO, write back BO. Return -1 on the last context.
|
|
*/
|
|
static int32_t tng_release_context(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint32_t cur_codec)
|
|
{
|
|
struct psb_video_ctx *video_ctx;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
return -1;
|
|
}
|
|
|
|
if (cur_codec != IMG_CODEC_JPEG) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Free bias saving memory\n");
|
|
if (video_ctx->bias_reg) {
|
|
kfree(video_ctx->bias_reg);
|
|
video_ctx->bias_reg = NULL;
|
|
}
|
|
|
|
video_ctx->status |= MASK_TOPAZ_FIRMWARE_EXIT;
|
|
} else {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: JPEG bypass unmap " \
|
|
"reg/data saving BO\n");
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
int tng_topaz_kick_null_cmd(struct drm_device *dev,
|
|
uint32_t sync_seq)
|
|
{
|
|
uint32_t cur_free_space;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
#ifdef TOPAZHP_SERIALIZED
|
|
uint32_t serializeToken;
|
|
serializeToken = tng_serialize_enter(dev);
|
|
#endif
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE,
|
|
&cur_free_space);
|
|
|
|
cur_free_space = F_DECODE(cur_free_space,
|
|
TOPAZHP_TOP_CR_CMD_FIFO_SPACE);
|
|
|
|
while (cur_free_space < 4) {
|
|
POLL_TOPAZ_FREE_FIFO_SPACE(4, 100, 10000, &cur_free_space);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ : error ret %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
MULTICORE_READ32(
|
|
TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE,
|
|
&cur_free_space);
|
|
|
|
cur_free_space = F_DECODE(cur_free_space,
|
|
TOPAZHP_TOP_CR_CMD_FIFO_SPACE);
|
|
}
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
MTX_CMDID_NULL | MTX_CMDID_WB_INTERRUPT);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
0);
|
|
|
|
/* Write back address is always 0 */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
0);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
sync_seq);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Write to command FIFO:\n");
|
|
PSB_DEBUG_TOPAZ("%08x, %08x, %08x, %08x\n",
|
|
MTX_CMDID_NULL, 0, 0, 0);
|
|
|
|
/* Notify ISR which context trigger interrupt */
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
topaz_priv->irq_context = topaz_priv->cur_context;
|
|
#endif
|
|
mtx_kick(dev);
|
|
|
|
#ifdef TOPAZHP_SERIALIZED
|
|
tng_serialize_exit(dev, serializeToken);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
int mtx_write_FIFO(
|
|
struct drm_device *dev,
|
|
struct tng_topaz_cmd_header *cmd_header,
|
|
uint32_t param,
|
|
uint32_t param_addr,
|
|
uint32_t sync_seq)
|
|
{
|
|
uint32_t cur_free_space;
|
|
uint32_t wb_val;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
uint32_t cmdword = 0;
|
|
struct psb_video_ctx *video_ctx = NULL;
|
|
|
|
if (topaz_priv->cur_context) {
|
|
video_ctx = topaz_priv->cur_context;
|
|
} else {
|
|
DRM_ERROR("Invalid video context\n");
|
|
return -1;
|
|
}
|
|
|
|
#ifdef TOPAZHP_SERIALIZED
|
|
uint32_t serializeToken;
|
|
serializeToken = tng_serialize_enter(dev);
|
|
#endif
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE,
|
|
&cur_free_space);
|
|
|
|
cur_free_space = F_DECODE(cur_free_space,
|
|
TOPAZHP_TOP_CR_CMD_FIFO_SPACE);
|
|
|
|
while (cur_free_space < 4) {
|
|
POLL_TOPAZ_FREE_FIFO_SPACE(4, 100, 10000, &cur_free_space);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ : error ret %d\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
MULTICORE_READ32(
|
|
TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE,
|
|
&cur_free_space);
|
|
|
|
cur_free_space = F_DECODE(cur_free_space,
|
|
TOPAZHP_TOP_CR_CMD_FIFO_SPACE);
|
|
}
|
|
|
|
cmdword = F_ENCODE(0, MTX_MSG_CORE) | cmd_header->id;
|
|
|
|
if (cmd_header->id & MTX_CMDID_PRIORITY) {
|
|
video_ctx->high_cmd_count++;
|
|
cmdword |= F_ENCODE(1, MTX_MSG_PRIORITY) |
|
|
F_ENCODE(((video_ctx->low_cmd_count - 1) & 0xff) |
|
|
(video_ctx->high_cmd_count << 8), MTX_MSG_COUNT);
|
|
|
|
} else {
|
|
cmdword |= F_ENCODE(video_ctx->low_cmd_count & 0xff, MTX_MSG_COUNT);
|
|
}
|
|
|
|
cmd_header->val = cmdword;
|
|
|
|
/* Trigger interrupt on MTX_CMDID_ENCODE_FRAME cmd */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
cmd_header->val);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
param);
|
|
|
|
/* Write back address is always 0 */
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
param_addr);
|
|
|
|
if (cmd_header->id & MTX_CMDID_PRIORITY) {
|
|
/* prepare Writeback value */
|
|
wb_val = video_ctx->high_cmd_count << 24;
|
|
} else {
|
|
wb_val = video_ctx->low_cmd_count << 16;
|
|
video_ctx->low_cmd_count++;
|
|
}
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE,
|
|
wb_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Write to command FIFO: " \
|
|
"%08x, %08x, %08x, %08x\n",
|
|
cmd_header->val, param, param_addr, wb_val);
|
|
|
|
/* Notify ISR which context trigger interrupt */
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
topaz_priv->irq_context = topaz_priv->cur_context;
|
|
#endif
|
|
mtx_kick(dev);
|
|
|
|
#ifdef TOPAZHP_SERIALIZED
|
|
tng_serialize_exit(dev, serializeToken);
|
|
#endif
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void tng_topaz_getvideo(
|
|
struct drm_device *dev,
|
|
struct psb_video_ctx *video_ctx)
|
|
{
|
|
int ret;
|
|
struct tng_topaz_cmd_header cmd_header;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Issue MTX_CMDID_GETVIDEO command");
|
|
PSB_DEBUG_TOPAZ("TOPAZ: to save context\n");
|
|
cmd_header.id = MTX_CMDID_GETVIDEO;
|
|
|
|
ret = mtx_write_FIFO(dev, &cmd_header,
|
|
video_ctx->enc_ctx_param,
|
|
video_ctx->enc_ctx_addr, 0);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to write command to FIFO");
|
|
goto out;
|
|
}
|
|
|
|
if ((video_ctx->codec == IMG_CODEC_H263_VBR) ||
|
|
(video_ctx->codec == IMG_CODEC_H263_CBR))
|
|
tng_wait_on_sync(dev, 0, cmd_header.id);
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static void tng_topaz_setvideo(
|
|
struct drm_device *dev,
|
|
struct psb_video_ctx *video_ctx)
|
|
{
|
|
int ret;
|
|
struct tng_topaz_cmd_header cmd_header;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Issue MTX_CMDID_SETVIDEO command\n");
|
|
PSB_DEBUG_TOPAZ("TOPAZ: to resotre context\n");
|
|
cmd_header.id = MTX_CMDID_SETVIDEO;
|
|
|
|
ret = mtx_write_FIFO(dev, &cmd_header,
|
|
video_ctx->enc_ctx_param,
|
|
video_ctx->enc_ctx_addr, 0);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to write command to FIFO");
|
|
goto out;
|
|
}
|
|
|
|
if ((video_ctx->codec == IMG_CODEC_H263_VBR) ||
|
|
(video_ctx->codec == IMG_CODEC_H263_CBR))
|
|
tng_wait_on_sync(dev, 0, cmd_header.id);
|
|
out:
|
|
return;
|
|
}
|
|
|
|
static inline void tng_topaz_trace_ctx(
|
|
char *words,
|
|
struct psb_video_ctx *trace_ctx)
|
|
{
|
|
if (words != NULL)
|
|
PSB_DEBUG_TOPAZ("TOPAZ: %s:\n", words);
|
|
#ifdef MRFLD_B0_DEBUG
|
|
if (trace_ctx != NULL)
|
|
PSB_DEBUG_TOPAZ("%08x(%s), status %08x\n",
|
|
trace_ctx, codec_to_string(trace_ctx->codec),
|
|
trace_ctx->status);
|
|
#endif
|
|
return ;
|
|
}
|
|
|
|
int tng_topaz_getvideo_setvideo(
|
|
struct drm_device *dev,
|
|
struct tng_topaz_private *topaz_priv,
|
|
struct psb_video_ctx *old_video_ctx,
|
|
struct psb_video_ctx *new_video_ctx,
|
|
uint32_t codec)
|
|
{
|
|
struct tng_topaz_cmd_header cmd_header;
|
|
int ret = 1;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Issue MTX_CMDID_GETVIDEO command");
|
|
cmd_header.id = MTX_CMDID_GETVIDEO;
|
|
|
|
ret = mtx_write_FIFO(dev, &cmd_header,
|
|
old_video_ctx->enc_ctx_param,
|
|
old_video_ctx->enc_ctx_addr, 0);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to write command to FIFO");
|
|
goto out;
|
|
}
|
|
|
|
/*tng_wait_on_sync(dev, 0, cmd_header.id);*/
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Issue MTX_CMDID_SETVIDEO command\n");
|
|
cmd_header.id = MTX_CMDID_SETVIDEO;
|
|
|
|
ret = mtx_write_FIFO(dev, &cmd_header,
|
|
new_video_ctx->enc_ctx_param,
|
|
new_video_ctx->enc_ctx_addr, 0);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to write command to FIFO");
|
|
goto out;
|
|
}
|
|
|
|
/*tng_wait_on_sync(dev, 0, cmd_header.id);*/
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static int tng_context_switch_secure(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint32_t codec,
|
|
uint32_t is_first_frame)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *video_ctx;
|
|
int32_t ret = 0;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
return -1;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Frame (%d)\n", video_ctx->frame_count);
|
|
|
|
if (TNG_IS_H264_ENC(codec)) {
|
|
codec = IMG_CODEC_H264_ALL_RC;
|
|
PSB_DEBUG_TOPAZ("TOPAZ: use RC_ALL for all H264 Codec\n");
|
|
PSB_DEBUG_TOPAZ("TOPAZ: %s to %s\n", \
|
|
codec_to_string(codec), codec_to_string(video_ctx->codec));
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("Incoming context is %p(%s, %08x)\n", \
|
|
video_ctx, \
|
|
codec_to_string(video_ctx->codec), \
|
|
video_ctx->status);
|
|
|
|
/* Handle JPEG burst mode, save current context only if it's not JPEG */
|
|
if (codec == IMG_CODEC_JPEG) {
|
|
if (topaz_priv->cur_context &&
|
|
topaz_priv->cur_context->codec != IMG_CODEC_JPEG &&
|
|
!(topaz_priv->cur_context->status & MASK_TOPAZ_CONTEXT_SAVED)) {
|
|
|
|
ret = tng_topaz_save_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save mtx status");
|
|
return ret;
|
|
}
|
|
}
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
return ret;
|
|
}
|
|
|
|
/* Continue doing other commands */
|
|
if (is_first_frame) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: First frame of ctx %p(%s, %08x), continue\n",
|
|
video_ctx, codec_to_string(codec), video_ctx->status);
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
return ret;
|
|
}
|
|
|
|
if (drm_topaz_pmpolicy == PSB_PMPOLICY_FORCE_PM) {
|
|
ret = tng_topaz_power_off(dev);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power off");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
if (is_island_on(OSPM_VIDEO_ENC_ISLAND)
|
|
&& (topaz_priv->cur_context != video_ctx)) {
|
|
if (TNG_IS_H264_ENC(topaz_priv->cur_context->codec)
|
|
&& TNG_IS_H264_ENC(video_ctx->codec)) {
|
|
PSB_DEBUG_TOPAZ("ctx switch without power up/off\n");
|
|
ret = tng_topaz_getvideo_setvideo(
|
|
dev, topaz_priv,
|
|
topaz_priv->cur_context,
|
|
video_ctx, codec);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to context switch");
|
|
return ret;
|
|
}
|
|
/* Context switch */
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
} else {
|
|
ret = tng_topaz_power_off(dev);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power off");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!is_island_on(OSPM_VIDEO_ENC_ISLAND)) {
|
|
tng_topaz_power_up(dev, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power up");
|
|
return ret;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("Restore context %p(%s, %08x)", \
|
|
video_ctx, \
|
|
codec_to_string(video_ctx->codec), \
|
|
video_ctx->status);
|
|
|
|
/* Context switch */
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
ret = tng_topaz_restore_mtx_state_b0(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore mtx status");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int tng_context_switch(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint32_t codec,
|
|
uint32_t is_first_frame)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *video_ctx;
|
|
int32_t ret = 0;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
return -1;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Frame (%d)\n", video_ctx->frame_count);
|
|
PSB_DEBUG_TOPAZ("Incoming context is %p(%s, %08x)\n", \
|
|
video_ctx, \
|
|
codec_to_string(video_ctx->codec), \
|
|
video_ctx->status);
|
|
|
|
/* Handle JPEG burst mode, save current context only if it's not JPEG */
|
|
if (codec == IMG_CODEC_JPEG) {
|
|
if (topaz_priv->cur_context &&
|
|
topaz_priv->cur_context->codec != IMG_CODEC_JPEG &&
|
|
!(topaz_priv->cur_context->status & MASK_TOPAZ_CONTEXT_SAVED)) {
|
|
|
|
ret = tng_topaz_save_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save mtx status");
|
|
return ret;
|
|
}
|
|
}
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
return ret;
|
|
}
|
|
|
|
/* Continue doing other commands */
|
|
if (is_first_frame) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: First frame of ctx %p(%s, %08x), continue\n",
|
|
video_ctx, codec_to_string(codec), video_ctx->status);
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
return ret;
|
|
}
|
|
|
|
if (topaz_priv->cur_context == video_ctx) {
|
|
if (drm_topaz_pmpolicy == PSB_PMPOLICY_FORCE_PM) {
|
|
ret = tng_topaz_power_off(dev);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power off");
|
|
return ret;
|
|
}
|
|
}
|
|
if (video_ctx->status & MASK_TOPAZ_CONTEXT_SAVED) {
|
|
PSB_DEBUG_TOPAZ("Same comtext %p(%s, %08x) and already saved\n",
|
|
video_ctx, \
|
|
codec_to_string(video_ctx->codec), \
|
|
video_ctx->status);
|
|
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_topaz_power_up(dev, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power up");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/* Context switch */
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_topaz_restore_mtx_state_b0(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore mtx B0");
|
|
return ret;
|
|
}
|
|
} else {
|
|
ret = tng_topaz_restore_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore mtx");
|
|
return ret;
|
|
}
|
|
}
|
|
} else {
|
|
PSB_DEBUG_TOPAZ("Same context %p(%s, %08x) but not saved, continue\n",
|
|
video_ctx, \
|
|
codec_to_string(video_ctx->codec), \
|
|
video_ctx->status);
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
return ret;
|
|
}
|
|
} else {
|
|
/* Current context already saved */
|
|
if (topaz_priv->cur_context->status & \
|
|
MASK_TOPAZ_CONTEXT_SAVED) {
|
|
PSB_DEBUG_TOPAZ("Different context and current context %p(%s, %08x) already saved, continue\n",
|
|
topaz_priv->cur_context, \
|
|
codec_to_string(topaz_priv->cur_context->codec), \
|
|
topaz_priv->cur_context->status);
|
|
} else {
|
|
/* Save current context */
|
|
PSB_DEBUG_TOPAZ("Different context and current context %p(%s, %08x) not saved, save it first",
|
|
topaz_priv->cur_context, \
|
|
codec_to_string(topaz_priv->cur_context->codec), \
|
|
topaz_priv->cur_context->status);
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_topaz_power_off(dev);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power off");
|
|
return ret;
|
|
}
|
|
} else {
|
|
if (topaz_priv->cur_context->codec != IMG_CODEC_JPEG) {
|
|
ret = tng_topaz_save_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save mtx status");
|
|
return ret;
|
|
}
|
|
} else
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Bypass saving JPEG context\n");
|
|
}
|
|
}
|
|
|
|
if (Is_Secure_Fw()) {
|
|
tng_topaz_power_up(dev, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power up");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("Restore context %p(%s, %08x)", \
|
|
video_ctx, \
|
|
codec_to_string(video_ctx->codec), \
|
|
video_ctx->status);
|
|
|
|
/* Context switch */
|
|
topaz_priv->cur_context = video_ctx;
|
|
topaz_priv->cur_codec = codec;
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_topaz_restore_mtx_state_b0(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore mtx status");
|
|
return ret;
|
|
}
|
|
} else {
|
|
if (topaz_priv->cur_context->codec != IMG_CODEC_JPEG) {
|
|
ret = tng_topaz_restore_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to restore mtx status");
|
|
return ret;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static uint16_t tng__rand(struct psb_video_ctx * video_ctx)
|
|
{
|
|
uint16_t ret = 0;
|
|
video_ctx->pseudo_rand_seed = (uint32_t)((video_ctx->pseudo_rand_seed * 1103515245 + 12345) & 0xffffffff); //Using mask, just in case
|
|
ret = (uint16_t)(video_ctx->pseudo_rand_seed / 65536) % 32768;
|
|
return ret;
|
|
}
|
|
|
|
static int32_t tng_fill_input_control (
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
int8_t slot_num,
|
|
int16_t ir,
|
|
int8_t init_qp,
|
|
int8_t min_qp,
|
|
int32_t buf_size,
|
|
uint32_t pseudo_rand_seed)
|
|
{
|
|
uint16_t default_param;
|
|
uint16_t intra_param;
|
|
bool refresh = false;
|
|
uint32_t cur_index;
|
|
uint32_t mb_x, mb_y;
|
|
uint32_t mb_w, mb_h;
|
|
uint16_t *p_input_buf;
|
|
int8_t qp;
|
|
int8_t max_qp = 31;
|
|
uint16_t mb_param;
|
|
int32_t ret;
|
|
bool is_iomem;
|
|
struct psb_video_ctx *video_ctx;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
return -1;
|
|
}
|
|
video_ctx->pseudo_rand_seed = pseudo_rand_seed;
|
|
|
|
mb_w = video_ctx->frame_w / 16;
|
|
mb_h = video_ctx->frame_h / 16;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Fill input control, cir=%d, initqp=%d, minqp=%d, \
|
|
slot=%d, bufsize=%d, pseudo=%d, mb_w=%d, mb_h=%d\n", \
|
|
ir, init_qp, min_qp, slot_num, buf_size, pseudo_rand_seed, mb_w, mb_h);
|
|
|
|
ret = ttm_bo_reserve(video_ctx->cir_input_ctrl_bo, true, true, false, 0);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: reserver failed.\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = ttm_bo_kmap(video_ctx->cir_input_ctrl_bo, 0,
|
|
video_ctx->cir_input_ctrl_bo->num_pages,
|
|
&video_ctx->cir_input_ctrl_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to map cir input ctrl bo\n");
|
|
ttm_bo_unref(&video_ctx->cir_input_ctrl_bo);
|
|
return -1;
|
|
}
|
|
|
|
video_ctx->cir_input_ctrl_addr = (uint32_t*)(ttm_kmap_obj_virtual(
|
|
&video_ctx->cir_input_ctrl_kmap, &is_iomem) + slot_num * buf_size);
|
|
|
|
if (ir > 0) {
|
|
refresh = true;
|
|
}
|
|
|
|
p_input_buf = (uint16_t *)video_ctx->cir_input_ctrl_addr;
|
|
|
|
cur_index = 0;
|
|
|
|
for(mb_y = 0; mb_y < (uint32_t)(mb_h); mb_y++) {
|
|
for(mb_x = 0; mb_x < mb_w; mb_x++) {
|
|
mb_param = 0;
|
|
|
|
qp = init_qp + ((tng__rand(video_ctx) % 6)-3);
|
|
qp = tng__max(tng__min(qp, max_qp), min_qp);
|
|
|
|
default_param = (qp << 10) | (3 << 7) | (3 << 4);
|
|
intra_param = (qp << 10) | (0 << 7) | (0 << 4);
|
|
|
|
mb_param = default_param;
|
|
if (refresh) {
|
|
if ((int32_t)cur_index > video_ctx->last_cir_index) {
|
|
video_ctx->last_cir_index = cur_index;
|
|
mb_param = intra_param;
|
|
ir--;
|
|
if(ir <= 0)
|
|
refresh = false;
|
|
}
|
|
}
|
|
p_input_buf[cur_index++] = mb_param;
|
|
}
|
|
}
|
|
|
|
if (refresh) {
|
|
video_ctx->last_cir_index = -1;
|
|
while (ir) {
|
|
qp = init_qp + ((tng__rand(video_ctx) % 6) - 3);
|
|
qp = tng__max(tng__min(qp, max_qp), min_qp);
|
|
intra_param = (qp << 10) |(0 << 7) |(0 << 4);
|
|
p_input_buf[++video_ctx->last_cir_index] = intra_param;
|
|
ir--;
|
|
}
|
|
}
|
|
|
|
ttm_bo_unreserve(video_ctx->cir_input_ctrl_bo);
|
|
ttm_bo_kunmap(&video_ctx->cir_input_ctrl_kmap);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t tng_update_air_send (
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint8_t slot_num,
|
|
int16_t skip_count,
|
|
int32_t air_per_frame,
|
|
uint32_t buf_size,
|
|
uint32_t frame_count)
|
|
{
|
|
int32_t ret;
|
|
bool is_iomem;
|
|
uint16_t ui16IntraParam;
|
|
uint32_t ui32CurrentCnt, ui32SentCnt;
|
|
uint32_t ui32MBMaxSize;
|
|
uint16_t *pui16MBParam;
|
|
uint32_t ui32NewScanPos;
|
|
struct psb_video_ctx *video_ctx;
|
|
|
|
ui16IntraParam = (0 << 7) | (0 << 4);
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp\n");
|
|
return -1;
|
|
}
|
|
|
|
if (skip_count >= 0)
|
|
video_ctx->air_info.air_skip_cnt = skip_count;
|
|
else
|
|
video_ctx->air_info.air_skip_cnt = (frame_count & 0x7) + 1; // Pseudorandom skip.
|
|
|
|
if (frame_count < 1) {
|
|
video_ctx->air_info.air_per_frame = air_per_frame;
|
|
return 0;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Update air send, slot_num=%d, skip_count=%d, air_per_frame=%d, buf_size=%d, frame_count=%d\n", \
|
|
slot_num, video_ctx->air_info.air_skip_cnt, video_ctx->air_info.air_per_frame, buf_size, frame_count);
|
|
|
|
ret = ttm_bo_reserve(video_ctx->cir_input_ctrl_bo, true, true, false, 0);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: reserver failed.\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = ttm_bo_kmap(video_ctx->cir_input_ctrl_bo, 0,
|
|
video_ctx->cir_input_ctrl_bo->num_pages,
|
|
&video_ctx->cir_input_ctrl_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to map cir input ctrl bo\n");
|
|
ttm_bo_unref(&video_ctx->cir_input_ctrl_bo);
|
|
return -1;
|
|
}
|
|
|
|
video_ctx->cir_input_ctrl_addr = (uint32_t*)(ttm_kmap_obj_virtual(
|
|
&video_ctx->cir_input_ctrl_kmap, &is_iomem) + slot_num * buf_size);
|
|
|
|
// get the buffer
|
|
pui16MBParam = (uint16_t*) video_ctx->cir_input_ctrl_addr;
|
|
|
|
//fill data
|
|
ui32MBMaxSize = (uint32_t)(video_ctx->frame_w / 16) * (IMG_UINT32)(video_ctx->frame_h / 16);
|
|
|
|
ui32CurrentCnt = 0;
|
|
|
|
ui32NewScanPos = (uint32_t) (video_ctx->air_info.air_scan_pos + video_ctx->air_info.air_skip_cnt) % ui32MBMaxSize;
|
|
ui32CurrentCnt = ui32SentCnt = 0;
|
|
|
|
while (ui32CurrentCnt < ui32MBMaxSize &&
|
|
((video_ctx->air_info.air_per_frame == 0) ||
|
|
ui32SentCnt < (uint32_t) video_ctx->air_info.air_per_frame)) {
|
|
|
|
uint16_t ui16MBParam;
|
|
|
|
if (video_ctx->air_info.air_table[ui32NewScanPos] >= 0) {
|
|
// Mark the entry as 'touched'
|
|
video_ctx->air_info.air_table[ui32NewScanPos] = -1 - video_ctx->air_info.air_table[ui32NewScanPos];
|
|
|
|
if (video_ctx->air_info.air_table[ui32NewScanPos] < -1) {
|
|
ui16MBParam = pui16MBParam[ui32NewScanPos] & (0xFF << 10);
|
|
ui16MBParam |= ui16IntraParam;
|
|
pui16MBParam[ui32NewScanPos] = ui16MBParam;
|
|
video_ctx->air_info.air_table[ui32NewScanPos]++;
|
|
ui32NewScanPos += video_ctx->air_info.air_skip_cnt;
|
|
ui32SentCnt++;
|
|
}
|
|
ui32CurrentCnt++;
|
|
}
|
|
|
|
ui32NewScanPos++;
|
|
ui32NewScanPos = ui32NewScanPos % ui32MBMaxSize;
|
|
if (ui32NewScanPos == video_ctx->air_info.air_scan_pos) {
|
|
/* we have looped around */
|
|
break;
|
|
}
|
|
}
|
|
|
|
video_ctx->air_info.air_scan_pos = ui32NewScanPos;
|
|
|
|
ttm_bo_unreserve(video_ctx->cir_input_ctrl_bo);
|
|
ttm_bo_kunmap(&video_ctx->cir_input_ctrl_kmap);
|
|
return 0;
|
|
}
|
|
|
|
static int32_t tng_air_buf_clear(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv)
|
|
{
|
|
struct psb_video_ctx *video_ctx;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp\n");
|
|
return -1;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Clear AIR buffer\n");
|
|
memset(video_ctx->air_info.air_table, 0, (video_ctx->frame_h * video_ctx->frame_w) >> 8);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t tng_update_air_calc(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint8_t slot_num,
|
|
uint32_t buf_size,
|
|
int32_t sad_threshold,
|
|
uint8_t enable_sel_states_flag)
|
|
{
|
|
int32_t ret;
|
|
bool is_iomem;
|
|
uint8_t *pSADPointer;
|
|
uint8_t *pvSADBuffer;
|
|
uint8_t ui8IsAlreadyIntra;
|
|
uint32_t ui32MBFrameWidth;
|
|
uint32_t ui32MBPictureHeight;
|
|
uint16_t ui16IntraParam;
|
|
uint32_t ui32MBx, ui32MBy;
|
|
uint32_t ui32SADParam;
|
|
uint32_t ui32tSAD_Threshold, ui32tSAD_ThresholdLo, ui32tSAD_ThresholdHi;
|
|
uint32_t ui32MaxMBs, ui32NumMBsOverThreshold, ui32NumMBsOverLo, ui32NumMBsOverHi;
|
|
struct psb_video_ctx *video_ctx;
|
|
IMG_BEST_MULTIPASS_MB_PARAMS *psBestMB_Params;
|
|
IMG_FIRST_STAGE_MB_PARAMS *psFirstMB_Params;
|
|
uint8_t *pFirstPassOutBuf;
|
|
uint8_t *pBestMBDecisionCtrlBuf;
|
|
|
|
ui16IntraParam = (0 << 7) | (0 << 4);
|
|
ui32NumMBsOverThreshold = ui32NumMBsOverLo = ui32NumMBsOverHi = 0;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Update air calc, slot_num=%d, buf_size=%d, sad_threshold=%d, enable_sel_states_flag=%08x\n", \
|
|
slot_num, buf_size, sad_threshold, enable_sel_states_flag);
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Map first pass out params */
|
|
ret = ttm_bo_reserve(video_ctx->bufs_first_pass_out_params_bo, true, true, false, 0);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: reserver failed.\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = ttm_bo_kmap(video_ctx->bufs_first_pass_out_params_bo, 0,
|
|
video_ctx->bufs_first_pass_out_params_bo->num_pages,
|
|
&video_ctx->bufs_first_pass_out_params_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to map first pass out param bo\n");
|
|
ttm_bo_unref(&video_ctx->bufs_first_pass_out_params_bo);
|
|
return -1;
|
|
}
|
|
|
|
video_ctx->bufs_first_pass_out_params_addr = (uint32_t*)(ttm_kmap_obj_virtual(
|
|
&video_ctx->bufs_first_pass_out_params_kmap, &is_iomem) + slot_num * buf_size);
|
|
|
|
pFirstPassOutBuf = (uint8_t *)video_ctx->bufs_first_pass_out_params_addr;
|
|
|
|
/* Map first pass out best multipass params */
|
|
ret = ttm_bo_reserve(video_ctx->bufs_first_pass_out_best_multipass_param_bo, true, true, false, 0);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: reserver failed.\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = ttm_bo_kmap(video_ctx->bufs_first_pass_out_best_multipass_param_bo, 0,
|
|
video_ctx->bufs_first_pass_out_best_multipass_param_bo->num_pages,
|
|
&video_ctx->bufs_first_pass_out_best_multipass_param_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to map first pass out best multipass param bo\n");
|
|
ttm_bo_unref(&video_ctx->bufs_first_pass_out_best_multipass_param_bo);
|
|
return -1;
|
|
}
|
|
video_ctx->bufs_first_pass_out_best_multipass_param_addr = (uint32_t*)(ttm_kmap_obj_virtual(
|
|
&video_ctx->bufs_first_pass_out_best_multipass_param_kmap, &is_iomem) + slot_num * buf_size);
|
|
|
|
pBestMBDecisionCtrlBuf = (uint8_t *)video_ctx->bufs_first_pass_out_best_multipass_param_addr;
|
|
|
|
//fill data
|
|
ui32MBFrameWidth = (video_ctx->frame_w / 16);
|
|
ui32MBPictureHeight = (video_ctx->frame_h / 16);
|
|
|
|
// get the SAD results buffer (either IPE0 and IPE1 results or, preferably, the more accurate Best Multipass SAD results)
|
|
if (pBestMBDecisionCtrlBuf) {
|
|
pvSADBuffer = pBestMBDecisionCtrlBuf;
|
|
|
|
if (enable_sel_states_flag & ESF_MP_BEST_MOTION_VECTOR_STATS)
|
|
{
|
|
// The actual Param structures (which contain SADs) are located after the Multipass Motion Vector entries
|
|
pvSADBuffer += (ui32MBPictureHeight * (ui32MBFrameWidth) * sizeof(IMG_BEST_MULTIPASS_MB_PARAMS_IPMV));
|
|
}
|
|
} else {
|
|
pvSADBuffer = pFirstPassOutBuf;
|
|
}
|
|
|
|
if (video_ctx->air_info.air_per_frame == 0)
|
|
ui32MaxMBs = ui32MBFrameWidth * ui32MBPictureHeight; // Default to ALL MB's in frame
|
|
else if (video_ctx->air_info.air_per_frame < 0)
|
|
video_ctx->air_info.air_per_frame = ui32MaxMBs = ((ui32MBFrameWidth * ui32MBPictureHeight) + 99) / 100; // Default to 1% of MB's in frame (min 1)
|
|
else
|
|
ui32MaxMBs = video_ctx->air_info.air_per_frame;
|
|
|
|
pSADPointer = (uint8_t *)pvSADBuffer;
|
|
|
|
video_ctx->air_info.sad_threshold = sad_threshold;
|
|
if (video_ctx->air_info.sad_threshold >= 0)
|
|
ui32tSAD_Threshold = (uint16_t)video_ctx->air_info.sad_threshold;
|
|
else {
|
|
// Running auto adjust threshold adjust mode
|
|
if (video_ctx->air_info.sad_threshold == -1) {
|
|
// This will occur only the first time
|
|
if (pBestMBDecisionCtrlBuf) {
|
|
psBestMB_Params=(IMG_BEST_MULTIPASS_MB_PARAMS *) pSADPointer; // Auto seed the threshold with the first value
|
|
ui32SADParam = psBestMB_Params->ui32SAD_Inter_MBInfo & IMG_BEST_MULTIPASS_SAD_MASK;
|
|
} else {
|
|
psFirstMB_Params = (IMG_FIRST_STAGE_MB_PARAMS *) pSADPointer; // Auto seed the threshold with the first value
|
|
ui32SADParam = (uint32_t) psFirstMB_Params->ui16Ipe0Sad;
|
|
}
|
|
video_ctx->air_info.sad_threshold = -1 - ui32SADParam; // Negative numbers indicate auto-adjusting threshold
|
|
}
|
|
ui32tSAD_Threshold = (int32_t) - (video_ctx->air_info.sad_threshold + 1);
|
|
}
|
|
|
|
ui32tSAD_ThresholdLo = ui32tSAD_Threshold / 2;
|
|
ui32tSAD_ThresholdHi = ui32tSAD_Threshold + ui32tSAD_ThresholdLo;
|
|
|
|
// This loop could be optimised to a single counter if necessary, retaining for clarity
|
|
for (ui32MBy = 0; ui32MBy < ui32MBPictureHeight; ui32MBy++) {
|
|
for( ui32MBx=0; ui32MBx<ui32MBFrameWidth; ui32MBx++) {
|
|
psBestMB_Params = (IMG_BEST_MULTIPASS_MB_PARAMS *) pSADPointer;
|
|
pSADPointer = (uint8_t *) &(psBestMB_Params[1]);
|
|
//pSADPointer += sizeof(IMG_BEST_MULTIPASS_MB_PARAMS);
|
|
|
|
// Turn all negative table values to positive (reset 'touched' state of a block that may have been set in APP_SendAIRInpCtrlBuf())
|
|
if (video_ctx->air_info.air_table[ui32MBy * ui32MBFrameWidth + ui32MBx] < 0)
|
|
video_ctx->air_info.air_table[ui32MBy * ui32MBFrameWidth + ui32MBx] = -1 - video_ctx->air_info.air_table[ui32MBy * ui32MBFrameWidth + ui32MBx];
|
|
|
|
// This will read the SAD value from the buffer (either IPE0 SAD or the superior Best multipass parameter structure SAD value)
|
|
if (pBestMBDecisionCtrlBuf) {
|
|
psBestMB_Params = (IMG_BEST_MULTIPASS_MB_PARAMS *) pSADPointer;
|
|
ui32SADParam = psBestMB_Params->ui32SAD_Inter_MBInfo & IMG_BEST_MULTIPASS_SAD_MASK;
|
|
if ((psBestMB_Params->ui32SAD_Intra_MBInfo & IMG_BEST_MULTIPASS_MB_TYPE_MASK) >> IMG_BEST_MULTIPASS_MB_TYPE_SHIFT == 1)
|
|
ui8IsAlreadyIntra = 1;
|
|
else
|
|
ui8IsAlreadyIntra = 0;
|
|
|
|
pSADPointer = (uint8_t *) &(psBestMB_Params[1]);
|
|
} else {
|
|
psFirstMB_Params = (IMG_FIRST_STAGE_MB_PARAMS *) pSADPointer;
|
|
ui32SADParam = (uint32_t) psFirstMB_Params->ui16Ipe0Sad;
|
|
ui32SADParam += (uint32_t) psFirstMB_Params->ui16Ipe1Sad;
|
|
ui32SADParam /= 2;
|
|
ui8IsAlreadyIntra = 0; // We don't have the information to determine this
|
|
pSADPointer = (uint8_t *) &(psFirstMB_Params[1]);
|
|
}
|
|
|
|
if (ui32SADParam >= ui32tSAD_ThresholdLo) {
|
|
ui32NumMBsOverLo++;
|
|
|
|
if (ui32SADParam >= ui32tSAD_Threshold) {
|
|
// if (!ui8IsAlreadyIntra) // Don't mark this block if it's just been encoded as an Intra block anyway
|
|
// (results seem better without this condition anyway)
|
|
video_ctx->air_info.air_table[ui32MBy * ui32MBFrameWidth + ui32MBx]++;
|
|
ui32NumMBsOverThreshold++;
|
|
if (ui32SADParam >= ui32tSAD_ThresholdHi)
|
|
ui32NumMBsOverHi++;
|
|
}
|
|
}
|
|
}
|
|
if ((uint64_t)pSADPointer % 64)
|
|
pSADPointer = (uint8_t *) ALIGN_64(((uint64_t) pSADPointer));
|
|
}
|
|
|
|
// Test and process running adaptive threshold case
|
|
if (video_ctx->air_info.sad_threshold < 0) {
|
|
// Adjust our threshold (to indicate it's auto-adjustable store it as a negative value minus 1)
|
|
if (ui32NumMBsOverLo <= ui32MaxMBs)
|
|
video_ctx->air_info.sad_threshold = (int32_t) - ((int32_t)ui32tSAD_ThresholdLo) - 1;
|
|
else {
|
|
if (ui32NumMBsOverHi >= ui32MaxMBs)
|
|
video_ctx->air_info.sad_threshold = (int32_t) - ((int32_t)ui32tSAD_ThresholdHi) - 1;
|
|
else {
|
|
if (ui32MaxMBs < ui32NumMBsOverThreshold) {
|
|
video_ctx->air_info.sad_threshold = ((int32_t)ui32tSAD_ThresholdHi - (int32_t)ui32tSAD_Threshold);
|
|
video_ctx->air_info.sad_threshold *= ((int32_t)ui32MaxMBs - (int32_t)ui32NumMBsOverThreshold);
|
|
video_ctx->air_info.sad_threshold /= ((int32_t)ui32NumMBsOverHi - (int32_t)ui32NumMBsOverThreshold);
|
|
video_ctx->air_info.sad_threshold += ui32tSAD_Threshold;
|
|
} else {
|
|
video_ctx->air_info.sad_threshold = ((int32_t)ui32tSAD_Threshold - (int32_t)ui32tSAD_ThresholdLo);
|
|
video_ctx->air_info.sad_threshold *= ((int32_t)ui32MaxMBs - (int32_t)ui32NumMBsOverLo);
|
|
video_ctx->air_info.sad_threshold /= ((int32_t)ui32NumMBsOverThreshold - (int32_t)ui32NumMBsOverLo);
|
|
video_ctx->air_info.sad_threshold += ui32tSAD_ThresholdLo;
|
|
}
|
|
video_ctx->air_info.sad_threshold = -video_ctx->air_info.sad_threshold - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
ttm_bo_unreserve(video_ctx->bufs_first_pass_out_params_bo);
|
|
ttm_bo_kunmap(&video_ctx->bufs_first_pass_out_params_kmap);
|
|
ttm_bo_unreserve(video_ctx->bufs_first_pass_out_best_multipass_param_bo);
|
|
ttm_bo_kunmap(&video_ctx->bufs_first_pass_out_best_multipass_param_kmap);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int32_t tng_setup_WB_mem(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
const void *command)
|
|
{
|
|
struct ttm_object_file *tfile = BCVideoGetPriv(file_priv)->tfile;
|
|
struct psb_video_ctx *video_ctx;
|
|
uint32_t i = 0;
|
|
const uint32_t len = sizeof(struct IMG_WRITEBACK_MSG);
|
|
int ret;
|
|
bool is_iomem;
|
|
uint32_t wb_handle;
|
|
uint32_t mtx_ctx_handle;
|
|
uint32_t cir_input_ctrl_handle;
|
|
uint32_t bufs_first_pass_out_params_handle;
|
|
uint32_t bufs_first_pass_out_best_multipass_param_handle;
|
|
uint8_t *ptmp = NULL;
|
|
const uint8_t pas_val = (uint8_t) ~0x0;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
return -1;
|
|
}
|
|
|
|
wb_handle = *((uint32_t *)command + 3);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Map write back memory from handle %08x\n",
|
|
wb_handle);
|
|
|
|
video_ctx->wb_bo = ttm_buffer_object_lookup(tfile, wb_handle);
|
|
|
|
if (unlikely(video_ctx->wb_bo == NULL)) {
|
|
DRM_ERROR("TOPAZ: Failed to lookup write back BO\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = ttm_bo_reserve(video_ctx->wb_bo , true, true, false, 0);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: reserver failed.\n");
|
|
return -1;
|
|
}
|
|
|
|
ret = ttm_bo_kmap(video_ctx->wb_bo, 0,
|
|
video_ctx->wb_bo->num_pages,
|
|
&video_ctx->wb_bo_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to map topaz write back BO\n");
|
|
ttm_bo_unref(&video_ctx->wb_bo);
|
|
return -1;
|
|
}
|
|
|
|
video_ctx->wb_addr[0] = (uint32_t *)ttm_kmap_obj_virtual(
|
|
&video_ctx->wb_bo_kmap, &is_iomem);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: memset: val=0x%08x, len=%d\n", \
|
|
pas_val, len);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: memset: wb_addr=%p, i=%d\n", \
|
|
video_ctx->wb_addr[0], i);
|
|
|
|
ptmp = (uint8_t *)(video_ctx->wb_addr[i++]);
|
|
memset(ptmp, pas_val, len);
|
|
while (i < WB_FIFO_SIZE) {
|
|
video_ctx->wb_addr[i] = video_ctx->wb_addr[i-1] + 0x400;
|
|
PSB_DEBUG_TOPAZ("TOPAZ: memset: wb_addr=%p, i=%d\n", \
|
|
video_ctx->wb_addr[i], i);
|
|
ptmp = (uint8_t *)(video_ctx->wb_addr[i++]);
|
|
memset(ptmp, pas_val, len);
|
|
} ;
|
|
|
|
video_ctx->enc_ctx_param = *((uint32_t *)command + 1);
|
|
video_ctx->enc_ctx_addr = *((uint32_t *)command + 2);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: GET/SETVIDEO data: %08x, address: %08x\n", \
|
|
video_ctx->enc_ctx_param, video_ctx->enc_ctx_addr);
|
|
|
|
if (video_ctx->codec == IMG_CODEC_JPEG)
|
|
return 0;
|
|
|
|
mtx_ctx_handle = *((uint32_t *)command + 4);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Map IMG_MTX_VIDEO_CONTEXT buffer from handle %08x\n",
|
|
mtx_ctx_handle);
|
|
|
|
video_ctx->mtx_ctx_bo = ttm_buffer_object_lookup(tfile, mtx_ctx_handle);
|
|
if (unlikely(video_ctx->mtx_ctx_bo == NULL)) {
|
|
DRM_ERROR("TOPAZ: Failed to lookup IMG_MTX_VIDEO_CONTEXT handle\n");
|
|
return -1;
|
|
}
|
|
|
|
/* If this cmd package is dequeued, must reserve it now */
|
|
if (0 == atomic_read(&video_ctx->mtx_ctx_bo->reserved)) {
|
|
PSB_DEBUG_TOPAZ("MTX context not reserved, reserve it now\n");
|
|
ret = ttm_bo_reserve(video_ctx->mtx_ctx_bo, true, true, false, 0);
|
|
if (ret) {
|
|
DRM_ERROR("Reserve MTX context failed.\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
ret = ttm_bo_kmap(video_ctx->mtx_ctx_bo, 0,
|
|
video_ctx->mtx_ctx_bo->num_pages,
|
|
&video_ctx->mtx_ctx_kmap);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to map IMG_MTX_VIDEO_CONTEXT BO\n");
|
|
ttm_bo_unref(&video_ctx->mtx_ctx_bo);
|
|
return -1;
|
|
}
|
|
|
|
video_ctx->setv_addr = (uint32_t)((uint64_t)ttm_kmap_obj_virtual(
|
|
&video_ctx->mtx_ctx_kmap, &is_iomem));
|
|
|
|
cir_input_ctrl_handle = *((uint32_t *)command + 5);
|
|
|
|
video_ctx->cir_input_ctrl_bo = ttm_buffer_object_lookup(tfile, cir_input_ctrl_handle);
|
|
if (unlikely(video_ctx->cir_input_ctrl_bo == NULL)) {
|
|
DRM_ERROR("TOPAZ: Failed to lookup cir input ctrl handle\n");
|
|
return -1;
|
|
}
|
|
|
|
bufs_first_pass_out_params_handle = *((uint32_t *)command + 6);
|
|
|
|
video_ctx->bufs_first_pass_out_params_bo = ttm_buffer_object_lookup(tfile, bufs_first_pass_out_params_handle);
|
|
if (unlikely(video_ctx->bufs_first_pass_out_params_bo == NULL)) {
|
|
DRM_ERROR("TOPAZ: Failed to lookup air first pass out parameter handle\n");
|
|
return -1;
|
|
}
|
|
video_ctx->bufs_first_pass_out_params_addr = NULL;
|
|
|
|
bufs_first_pass_out_best_multipass_param_handle = *((uint32_t *)command + 7);
|
|
|
|
video_ctx->bufs_first_pass_out_best_multipass_param_bo = ttm_buffer_object_lookup(tfile, bufs_first_pass_out_best_multipass_param_handle);
|
|
if (unlikely(video_ctx->bufs_first_pass_out_best_multipass_param_bo == NULL)) {
|
|
DRM_ERROR("TOPAZ: Failed to lookup air first pass out best multipass parameter handle\n");
|
|
return -1;
|
|
}
|
|
video_ctx->bufs_first_pass_out_best_multipass_param_addr = NULL;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int tng_setup_new_context_secure(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint32_t *cmd,
|
|
uint32_t codec)
|
|
{
|
|
struct psb_video_ctx *video_ctx;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
video_ctx->codec = codec;
|
|
if (TNG_IS_H264_ENC(codec)) {
|
|
video_ctx->codec = codec = IMG_CODEC_H264_ALL_RC;
|
|
PSB_DEBUG_TOPAZ("TOPAZ: use RC_ALL for all H264 Codec\n");
|
|
PSB_DEBUG_TOPAZ("TOPAZ: %s to %s\n", \
|
|
codec_to_string(codec), codec_to_string(video_ctx->codec));
|
|
}
|
|
|
|
video_ctx->status = 0;
|
|
video_ctx->frame_count = 0;
|
|
video_ctx->bias_reg = NULL;
|
|
video_ctx->handle_sequence_needed = false;
|
|
video_ctx->high_cmd_count = 0;
|
|
video_ctx->low_cmd_count = 0xa5a5a5a5 % MAX_TOPAZ_CMD_COUNT;
|
|
video_ctx->last_cir_index = -1;
|
|
video_ctx->air_info.air_scan_pos = 0;
|
|
video_ctx->frame_h = (uint16_t)((*((uint32_t *) cmd + 1)) & 0xffff);
|
|
video_ctx->frame_w = (uint16_t)(((*((uint32_t *) cmd + 1))
|
|
& 0xffff0000) >> 16) ;
|
|
|
|
if (codec != IMG_CODEC_JPEG) {
|
|
video_ctx->air_info.air_table = kzalloc((video_ctx->frame_h * video_ctx->frame_w) >> 8, GFP_KERNEL);
|
|
if (!video_ctx->air_info.air_table) {
|
|
DRM_ERROR("TOPAZ: Failed to alloc memory for AIR table\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: new context %p(%s)(cur context = %p)\n",
|
|
video_ctx, codec_to_string(codec), \
|
|
topaz_priv->cur_context);
|
|
|
|
if (Is_Secure_Fw() && drm_topaz_pmpolicy == PSB_PMPOLICY_NOPM) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: new context, force a poweroff to reload firmware anyway\n");
|
|
|
|
drm_topaz_pmpolicy = PSB_PMPOLICY_POWERDOWN; /* off NOPM policy */
|
|
tng_topaz_power_off(dev);
|
|
drm_topaz_pmpolicy = PSB_PMPOLICY_NOPM; /* reset back to NOPM */
|
|
}
|
|
|
|
if (topaz_priv->cur_context &&
|
|
(topaz_priv->cur_context != video_ctx) &&
|
|
is_island_on(OSPM_VIDEO_ENC_ISLAND)) {
|
|
|
|
PSB_DEBUG_TOPAZ("Current context %p(%s, %08x)" \
|
|
" not saved, save it first\n", \
|
|
topaz_priv->cur_context, \
|
|
codec_to_string(topaz_priv->cur_context->codec), \
|
|
topaz_priv->cur_context->status);
|
|
|
|
ret = tng_topaz_power_off(dev);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed");
|
|
DRM_ERROR("to power off");
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
if (video_ctx->codec != IMG_CODEC_JPEG) {
|
|
video_ctx->bias_reg = (uint32_t *)kzalloc(2 * PAGE_SIZE, GFP_KERNEL);
|
|
if (!video_ctx->bias_reg) {
|
|
DRM_ERROR("Failed to kzalloc bias reg, OOM\n");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
} else {
|
|
video_ctx->bias_reg = NULL;
|
|
}
|
|
|
|
ret = tng_topaz_power_up(dev, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: failed power up\n");
|
|
goto out;
|
|
}
|
|
ret = tng_topaz_fw_run(dev, video_ctx, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: upload FW to HW failed\n");
|
|
goto out;
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
static int tng_setup_new_context(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
uint32_t *cmd,
|
|
uint32_t codec)
|
|
{
|
|
struct psb_video_ctx *video_ctx;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Failed to get video contex from filp");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
video_ctx->codec = codec;
|
|
video_ctx->status = 0;
|
|
video_ctx->frame_count = 0;
|
|
video_ctx->bias_reg = NULL;
|
|
video_ctx->handle_sequence_needed = false;
|
|
video_ctx->high_cmd_count = 0;
|
|
video_ctx->low_cmd_count = 0xa5a5a5a5 % MAX_TOPAZ_CMD_COUNT;
|
|
video_ctx->last_cir_index = -1;
|
|
video_ctx->air_info.air_scan_pos = 0;
|
|
video_ctx->frame_h = (uint16_t)((*((uint32_t *) cmd + 1)) & 0xffff);
|
|
video_ctx->frame_w = (uint16_t)(((*((uint32_t *) cmd + 1))
|
|
& 0xffff0000) >> 16) ;
|
|
|
|
if (codec != IMG_CODEC_JPEG) {
|
|
video_ctx->air_info.air_table = (int8_t *)kzalloc((video_ctx->frame_h * video_ctx->frame_w) >> 8, GFP_KERNEL);
|
|
if (!video_ctx->air_info.air_table) {
|
|
DRM_ERROR("TOPAZ: Failed to alloc memory for AIR table\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: new context %p(%s)(cur context = %p)\n",
|
|
video_ctx, codec_to_string(codec), \
|
|
topaz_priv->cur_context);
|
|
|
|
if (Is_Secure_Fw() && drm_topaz_pmpolicy == PSB_PMPOLICY_NOPM) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: new context, force a poweroff to reload firmware anyway\n");
|
|
|
|
drm_topaz_pmpolicy = PSB_PMPOLICY_POWERDOWN; /* off NOPM policy */
|
|
tng_topaz_power_off(dev);
|
|
drm_topaz_pmpolicy = PSB_PMPOLICY_NOPM; /* reset back to NOPM */
|
|
}
|
|
|
|
if (topaz_priv->cur_context &&
|
|
topaz_priv->cur_context != video_ctx) {
|
|
if (topaz_priv->cur_context->status & \
|
|
MASK_TOPAZ_CONTEXT_SAVED) {
|
|
PSB_DEBUG_TOPAZ("Current context %p(%s, %08x)" \
|
|
" already saved, continue\n", \
|
|
topaz_priv->cur_context, \
|
|
codec_to_string(topaz_priv->cur_context->codec), \
|
|
topaz_priv->cur_context->status);
|
|
/* If the previous context not saved */
|
|
} else {
|
|
PSB_DEBUG_TOPAZ("Current context %p(%s, %08x)" \
|
|
" not saved, save it first\n", \
|
|
topaz_priv->cur_context, \
|
|
codec_to_string(topaz_priv->cur_context->codec), \
|
|
topaz_priv->cur_context->status);
|
|
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_topaz_power_off(dev);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed");
|
|
DRM_ERROR("to power off");
|
|
goto out;
|
|
}
|
|
} else {
|
|
ret = tng_topaz_save_mtx_state(dev);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save");
|
|
DRM_ERROR("mtx status");
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (video_ctx->codec != IMG_CODEC_JPEG) {
|
|
video_ctx->bias_reg = (uint32_t *)kzalloc(2 * PAGE_SIZE, GFP_KERNEL);
|
|
if (!video_ctx->bias_reg) {
|
|
DRM_ERROR("Failed to kzalloc bias reg, OOM\n");
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
} else {
|
|
video_ctx->bias_reg = NULL;
|
|
}
|
|
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_topaz_power_up(dev, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: failed power up\n");
|
|
goto out;
|
|
}
|
|
ret = tng_topaz_fw_run(dev, video_ctx, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: upload FW to HW failed\n");
|
|
goto out;
|
|
}
|
|
} else {
|
|
/* Upload the new codec firmware */
|
|
ret = tng_topaz_init_board(dev, video_ctx, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: init board failed\n");
|
|
/* tng_error_dump_reg(dev_priv, 0); */
|
|
goto out;
|
|
}
|
|
|
|
/* Upload the new codec firmware */
|
|
ret = tng_topaz_setup_fw(dev, video_ctx, codec);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: upload FW to HW failed\n");
|
|
/* tng_error_dump_reg(dev_priv, 0); */
|
|
goto out;
|
|
}
|
|
}
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
|
|
static int32_t tng_check_bias_register(uint32_t reg_id, uint32_t reg_off)
|
|
{
|
|
switch (reg_id) {
|
|
case TOPAZ_MULTICORE_REG:
|
|
if (reg_off < REG_MIN_TOPAZ_MULTICORE ||
|
|
reg_off > REG_MAX_TOPAZ_MULTICORE) {
|
|
DRM_ERROR("Invalid MULTICORE register %08x\n",
|
|
reg_off);
|
|
return -1;
|
|
}
|
|
break;
|
|
case TOPAZ_CORE_REG:
|
|
if (reg_off < REG_MIN_TOPAZ_CORE ||
|
|
reg_off > REG_MAX_TOPAZ_CORE) {
|
|
DRM_ERROR("Invalid CORE register %08x\n", reg_off);
|
|
return -1;
|
|
}
|
|
break;
|
|
case TOPAZ_VLC_REG:
|
|
if (reg_off < REG_MIN_TOPAZ_VLC ||
|
|
reg_off > REG_MAX_TOPAZ_VLC) {
|
|
DRM_ERROR("Invalid VLC register %08x\n", reg_off);
|
|
return -1;
|
|
}
|
|
break;
|
|
default:
|
|
DRM_ERROR("Unknown reg space id: %08x\n", reg_id);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int tng_topaz_set_bias(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
const uint32_t *command,
|
|
uint32_t codec,
|
|
uint32_t *cmd_size)
|
|
{
|
|
uint32_t reg_id, reg_off, reg_val, reg_cnt;
|
|
uint32_t *p_command;
|
|
struct drm_psb_private *dev_priv;
|
|
int ret = 0;
|
|
|
|
dev_priv = dev->dev_private;
|
|
p_command = (uint32_t *)command;
|
|
p_command++;
|
|
*cmd_size = *p_command;
|
|
p_command++;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Start to write %d Registers\n", *cmd_size);
|
|
for (reg_cnt = 0; reg_cnt < *cmd_size; reg_cnt++) {
|
|
/* Reg space ID */
|
|
reg_id = *p_command;
|
|
p_command++;
|
|
/* Reg offset */
|
|
reg_off = *p_command;
|
|
p_command++;
|
|
/* Reg value */
|
|
reg_val = *p_command;
|
|
p_command++;
|
|
|
|
ret = tng_check_bias_register(reg_id, reg_off);
|
|
if (ret) {
|
|
DRM_ERROR("Failed in checking BIAS register");
|
|
return ret;
|
|
}
|
|
|
|
switch (reg_id) {
|
|
case TOPAZ_MULTICORE_REG:
|
|
MULTICORE_WRITE32(reg_off, reg_val);
|
|
break;
|
|
case TOPAZ_CORE_REG:
|
|
TOPAZCORE_WRITE32(0, reg_off, reg_val);
|
|
break;
|
|
case TOPAZ_VLC_REG:
|
|
VLC_WRITE32(0, reg_off, reg_val);
|
|
break;
|
|
default:
|
|
DRM_ERROR("Unknown reg space id: (%08x)\n", reg_id);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
p_command = (uint32_t *)command;
|
|
|
|
/* For now, saving BIAS table no matter necessary or not */
|
|
ret = tng_save_bias_table(dev, file_priv, p_command);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to save BIAS table");
|
|
return ret;
|
|
}
|
|
|
|
/* Update Globals */
|
|
if (codec != IMG_CODEC_JPEG) {
|
|
uint32_t ui32ToMtxReg = 0;
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_FIRMWARE_REG_1 +
|
|
(MTX_SCRATCHREG_TOMTX << 2), ui32ToMtxReg);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
/* #define MULTI_STREAM_TEST */
|
|
|
|
int
|
|
tng_topaz_send(
|
|
struct drm_device *dev,
|
|
struct drm_file *file_priv,
|
|
void *cmd,
|
|
uint32_t cmd_size_in,
|
|
uint32_t sync_seq)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
unsigned char *command = (unsigned char *) cmd;
|
|
struct tng_topaz_cmd_header *cur_cmd_header;
|
|
uint32_t cur_cmd_id;
|
|
uint32_t codec = 0;
|
|
int32_t cur_cmd_size = 4;
|
|
int32_t cmd_size = (int32_t)cmd_size_in;
|
|
|
|
/* uint32_t m; */
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
struct psb_video_ctx *video_ctx;
|
|
|
|
if (Is_Secure_Fw() == 0) {
|
|
ret = tng_topaz_power_up(dev, 1);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: Failed to power up");
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
video_ctx = get_ctx_from_fp(dev, file_priv->filp);
|
|
if (!video_ctx) {
|
|
DRM_ERROR("Failed to get context from filp %p\n", file_priv->filp);
|
|
ret = -1;
|
|
goto out;
|
|
}
|
|
|
|
topaz_priv->topaz_busy = 1;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ : send the command in the buffer" \
|
|
" one by one, cmdsize(%d), sequence(%08x)\n",
|
|
cmd_size, sync_seq);
|
|
|
|
if (is_island_on(OSPM_VIDEO_ENC_ISLAND)) {
|
|
/* Must flush here in case of invalid cache data */
|
|
tng_topaz_mmu_flushcache(dev_priv);
|
|
}
|
|
|
|
while (cmd_size > 0) {
|
|
cur_cmd_header = (struct tng_topaz_cmd_header *) command;
|
|
cur_cmd_id = cur_cmd_header->id;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ : cmd is(%s)\n",
|
|
cmd_to_string(cur_cmd_id & (~MTX_CMDID_PRIORITY)));
|
|
PSB_DEBUG_TOPAZ("remaining cmd size is(%d)\n",
|
|
cmd_size);
|
|
|
|
switch (cur_cmd_id) {
|
|
case MTX_CMDID_SW_NEW_CODEC:
|
|
codec = (*((uint32_t *) cmd) & 0xFF00) >> 8;
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_setup_new_context_secure(dev,file_priv,
|
|
(uint32_t *)command, codec);
|
|
|
|
} else {
|
|
ret = tng_setup_new_context(dev, file_priv,
|
|
(uint32_t *)command, codec);
|
|
}
|
|
if (ret) {
|
|
DRM_ERROR("Failed to setup new context");
|
|
return ret;
|
|
}
|
|
cur_cmd_size = 2;
|
|
break;
|
|
case MTX_CMDID_SW_ENTER_LOWPOWER:
|
|
PSB_DEBUG_TOPAZ("TOPAZ : Enter lowpower....\n");
|
|
PSB_DEBUG_TOPAZ("XXX : implement it\n");
|
|
cur_cmd_size = 1;
|
|
break;
|
|
|
|
case MTX_CMDID_SW_LEAVE_LOWPOWER:
|
|
cur_cmd_size = 2;
|
|
if (Is_Secure_Fw()) {
|
|
ret = tng_context_switch_secure(dev, file_priv,
|
|
*((uint32_t *)command + 1),
|
|
((*((uint32_t *)command) & 0xFF00) >> 8));
|
|
|
|
} else {
|
|
ret = tng_context_switch(dev, file_priv,
|
|
*((uint32_t *)command + 1),
|
|
((*((uint32_t *)command) & 0xFF00) >> 8));
|
|
}
|
|
if (ret) {
|
|
DRM_ERROR("Failed to switch context");
|
|
return ret;
|
|
}
|
|
|
|
break;
|
|
case MTX_CMDID_SW_WRITEREG:
|
|
ret = tng_topaz_set_bias(dev, file_priv,
|
|
(const uint32_t *)command, codec,
|
|
&cur_cmd_size);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to set BIAS table");
|
|
return ret;
|
|
}
|
|
|
|
/*
|
|
* cur_cmd_size if the register count here,
|
|
* reg_id, reg_off and reg_val are stored in a 3 words
|
|
* */
|
|
cur_cmd_size *= 3;
|
|
/* Header size, 2 words */
|
|
cur_cmd_size += 2;
|
|
break;
|
|
|
|
case MTX_CMDID_SW_FILL_INPUT_CTRL:
|
|
ret = tng_fill_input_control (dev, file_priv,
|
|
*((uint32_t *)command + 1),//slot
|
|
*((uint32_t *)command + 3),//ir
|
|
*((uint32_t *)command + 4),//initqp
|
|
*((uint32_t *)command + 5),//minqp
|
|
*((uint32_t *)command + 6),//bufsize
|
|
*((uint32_t *)command + 7));//seed
|
|
if (ret) {
|
|
DRM_ERROR("Failed to fill " \
|
|
"input control buffer");
|
|
return ret;
|
|
}
|
|
cur_cmd_size = 8;
|
|
break;
|
|
case MTX_CMDID_SW_UPDATE_AIR_SEND:
|
|
ret = tng_update_air_send (dev, file_priv,
|
|
*((uint32_t *)command + 1),//slot
|
|
*((uint32_t *)command + 3),//air_skip_count
|
|
*((uint32_t *)command + 4),//air_per_frame
|
|
*((uint32_t *)command + 5),//bufsize
|
|
*((uint32_t *)command + 6));//frame_count
|
|
if (ret) {
|
|
DRM_ERROR("Failed to update air " \
|
|
"send");
|
|
return ret;
|
|
}
|
|
cur_cmd_size = 7;
|
|
break;
|
|
case MTX_CMDID_SW_AIR_BUF_CLEAR:
|
|
ret = tng_air_buf_clear(dev, file_priv);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to clear " \
|
|
"AIR buffer");
|
|
return ret;
|
|
}
|
|
cur_cmd_size = 3;
|
|
break;
|
|
case MTX_CMDID_SW_UPDATE_AIR_CALC:
|
|
ret = tng_update_air_calc(dev, file_priv,
|
|
*((uint32_t *)command + 1),//slot
|
|
*((uint32_t *)command + 3),//buf_size
|
|
*((uint32_t *)command + 4),//sad_threashold
|
|
*((uint32_t *)command + 5));//enable_seld_stats_flag
|
|
if (ret) {
|
|
DRM_ERROR("Failed to update " \
|
|
"air calc");
|
|
return ret;
|
|
}
|
|
cur_cmd_size = 6;
|
|
break;
|
|
case MTX_CMDID_PAD:
|
|
/*Ignore this command, which is used to skip
|
|
* some commands in user space*/
|
|
cur_cmd_size = 4;
|
|
break;
|
|
/* Ordinary commmand */
|
|
case MTX_CMDID_SETUP_INTERFACE:
|
|
if (video_ctx && video_ctx->wb_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: reset\n");
|
|
if (Is_Secure_Fw()) {
|
|
tng_topaz_power_off(dev);
|
|
tng_topaz_power_up(dev, IMG_CODEC_JPEG);
|
|
tng_topaz_fw_run(dev, video_ctx, IMG_CODEC_JPEG);
|
|
} else {
|
|
tng_topaz_reset(dev_priv);
|
|
tng_topaz_mmu_hwsetup(dev_priv, video_ctx);
|
|
tng_topaz_setup_fw(dev, video_ctx, topaz_priv->cur_codec);
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: unref write back bo\n");
|
|
ttm_bo_kunmap(&video_ctx->wb_bo_kmap);
|
|
ttm_bo_unreserve(video_ctx->wb_bo);
|
|
ttm_bo_unref(&video_ctx->wb_bo);
|
|
video_ctx->wb_bo = NULL;
|
|
}
|
|
case MTX_CMDID_SETVIDEO:
|
|
ret = tng_setup_WB_mem(dev, file_priv,
|
|
(const void *)command);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to setup " \
|
|
"write back memory region");
|
|
return ret;
|
|
}
|
|
|
|
case MTX_CMDID_DO_HEADER:
|
|
case MTX_CMDID_ENCODE_FRAME:
|
|
case MTX_CMDID_GETVIDEO:
|
|
case MTX_CMDID_PICMGMT:
|
|
case (MTX_CMDID_PICMGMT | MTX_CMDID_PRIORITY):
|
|
|
|
case MTX_CMDID_START_FRAME:
|
|
case MTX_CMDID_ENCODE_SLICE:
|
|
case MTX_CMDID_END_FRAME:
|
|
case MTX_CMDID_RC_UPDATE:
|
|
case (MTX_CMDID_RC_UPDATE | MTX_CMDID_PRIORITY):
|
|
case MTX_CMDID_PROVIDE_SOURCE_BUFFER:
|
|
case MTX_CMDID_PROVIDE_REF_BUFFER:
|
|
case MTX_CMDID_PROVIDE_CODED_BUFFER:
|
|
case (MTX_CMDID_PROVIDE_SOURCE_BUFFER | MTX_CMDID_PRIORITY):
|
|
case (MTX_CMDID_PROVIDE_REF_BUFFER | MTX_CMDID_PRIORITY):
|
|
case (MTX_CMDID_PROVIDE_CODED_BUFFER | MTX_CMDID_PRIORITY):
|
|
|
|
case MTX_CMDID_SETQUANT:
|
|
case MTX_CMDID_ISSUEBUFF:
|
|
case MTX_CMDID_SETUP:
|
|
case MTX_CMDID_SHUTDOWN:
|
|
/*
|
|
if (cur_cmd_header->id == MTX_CMDID_SHUTDOWN) {
|
|
cur_cmd_size = 4;
|
|
PSB_DEBUG_TOPAZ("TOPAZ : Doesn't handle " \
|
|
"SHUTDOWN command for now\n");
|
|
break;
|
|
}
|
|
*/
|
|
|
|
if (video_ctx) {
|
|
video_ctx->cur_sequence = sync_seq;
|
|
video_ctx->handle_sequence_needed = true;
|
|
}
|
|
|
|
/* Write command to FIFO */
|
|
ret = mtx_write_FIFO(dev, cur_cmd_header,
|
|
*((uint32_t *)(command) + 1),
|
|
*((uint32_t *)(command) + 2), sync_seq);
|
|
if (ret) {
|
|
DRM_ERROR("Failed to write command to FIFO");
|
|
goto out;
|
|
}
|
|
|
|
/*tng_wait_on_sync(dev, sync_seq, cur_cmd_id);*/
|
|
|
|
/*
|
|
for (m = 0; m < 1000; m++) {
|
|
PSB_UDELAY(100);
|
|
}
|
|
PSB_UDELAY(6);
|
|
*/
|
|
|
|
/* Calculate command size */
|
|
switch (cur_cmd_id) {
|
|
case MTX_CMDID_SETVIDEO:
|
|
cur_cmd_size = (video_ctx->codec == IMG_CODEC_JPEG) ? (6 + 1) : (7 + 1);
|
|
break;
|
|
case MTX_CMDID_SETUP_INTERFACE:
|
|
case MTX_CMDID_SHUTDOWN:
|
|
cur_cmd_size = 4;
|
|
break;
|
|
case (MTX_CMDID_PROVIDE_SOURCE_BUFFER |
|
|
MTX_CMDID_PRIORITY):
|
|
case (MTX_CMDID_PROVIDE_REF_BUFFER |
|
|
MTX_CMDID_PRIORITY):
|
|
case (MTX_CMDID_PROVIDE_CODED_BUFFER |
|
|
MTX_CMDID_PRIORITY):
|
|
case (MTX_CMDID_PICMGMT | MTX_CMDID_PRIORITY):
|
|
cur_cmd_size = 3;
|
|
break;
|
|
default:
|
|
cur_cmd_size = 3;
|
|
break;
|
|
}
|
|
|
|
|
|
break;
|
|
default:
|
|
DRM_ERROR("TOPAZ: unsupported command id: %x\n",
|
|
cur_cmd_id);
|
|
return -1;
|
|
}
|
|
|
|
/*cur_cmd_size indicate the number of words of
|
|
current command*/
|
|
command += cur_cmd_size * 4;
|
|
cmd_size -= cur_cmd_size * 4;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ : remaining cmd size is(%d)\n",
|
|
cmd_size);
|
|
|
|
}
|
|
|
|
tng_topaz_kick_null_cmd(dev, sync_seq);
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
int tng_topaz_remove_ctx(
|
|
struct drm_psb_private *dev_priv,
|
|
struct psb_video_ctx *video_ctx)
|
|
{
|
|
struct tng_topaz_private *topaz_priv;
|
|
struct tng_topaz_cmd_queue *entry, *next;
|
|
unsigned long flags;
|
|
|
|
topaz_priv = dev_priv->topaz_private;
|
|
|
|
mutex_lock(&topaz_priv->ctx_mutex);
|
|
|
|
if (video_ctx == topaz_priv->irq_context)
|
|
topaz_priv->irq_context = NULL;
|
|
if (video_ctx == topaz_priv->cur_context)
|
|
topaz_priv->cur_context = NULL;
|
|
|
|
/* topaz_priv->topaz_busy = 0; */
|
|
/* video_ctx = NULL; */
|
|
|
|
/* Disable ISR */
|
|
/*if (TOPAZHP_IRQ_ENABLED) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Disalbe IRQ and " \
|
|
"Wait for MTX completion\n");
|
|
tng_topaz_disableirq(dev_priv);
|
|
}*/
|
|
|
|
/* Stop the MTX */
|
|
/*
|
|
mtx_stop(dev_priv);
|
|
ret = mtx_wait_for_completion(dev_priv);
|
|
if (ret) {
|
|
DRM_ERROR("Mtx wait for completion error");
|
|
return ret;
|
|
}
|
|
|
|
list_for_each_entry(pos, &dev_priv->video_ctx, head) {
|
|
if (pos->filp == filp) {
|
|
video_ctx = pos;
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
|
|
if (video_ctx == NULL) {
|
|
DRM_ERROR("Invalid video context\n");
|
|
mutex_unlock(&topaz_priv->ctx_mutex);
|
|
return -1;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: release context %p(%s)\n",
|
|
video_ctx, codec_to_string(video_ctx->codec));
|
|
|
|
if (video_ctx->bias_reg) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Free bias reg saving memory\n");
|
|
kfree(video_ctx->bias_reg);
|
|
video_ctx->bias_reg = NULL;
|
|
}
|
|
|
|
if (video_ctx->wb_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: unref write back bo\n");
|
|
ttm_bo_kunmap(&video_ctx->wb_bo_kmap);
|
|
ttm_bo_unreserve(video_ctx->wb_bo);
|
|
ttm_bo_unref(&video_ctx->wb_bo);
|
|
video_ctx->wb_bo = NULL;
|
|
}
|
|
|
|
if (video_ctx->mtx_ctx_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: unref setvideo bo\n");
|
|
ttm_bo_kunmap(&video_ctx->mtx_ctx_kmap);
|
|
/* unreserve if reserved in tng_setup_WB_mem() */
|
|
if (0 != atomic_read(&video_ctx->mtx_ctx_bo->reserved)) {
|
|
PSB_DEBUG_TOPAZ("MTX context reserved, unreserve it now\n");
|
|
ttm_bo_unreserve(video_ctx->mtx_ctx_bo);
|
|
}
|
|
ttm_bo_unref(&video_ctx->mtx_ctx_bo);
|
|
video_ctx->mtx_ctx_bo = NULL;
|
|
}
|
|
|
|
if (video_ctx->cir_input_ctrl_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: unref cir input ctrl bo\n");
|
|
ttm_bo_unref(&video_ctx->cir_input_ctrl_bo);
|
|
video_ctx->cir_input_ctrl_bo = NULL;
|
|
}
|
|
|
|
if (video_ctx->bufs_first_pass_out_best_multipass_param_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: unref first pass out best multipass param bo\n");
|
|
ttm_bo_unref(&video_ctx->bufs_first_pass_out_best_multipass_param_bo);
|
|
video_ctx->bufs_first_pass_out_best_multipass_param_bo = NULL;
|
|
}
|
|
|
|
if (video_ctx->bufs_first_pass_out_params_bo) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: unref first pass out param bo\n");
|
|
ttm_bo_unref(&video_ctx->bufs_first_pass_out_params_bo);
|
|
video_ctx->bufs_first_pass_out_params_bo = NULL;
|
|
}
|
|
|
|
if (video_ctx->air_info.air_table) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: free air table\n");
|
|
kfree(video_ctx->air_info.air_table);
|
|
video_ctx->air_info.air_table = NULL;
|
|
}
|
|
|
|
video_ctx->status = 0;
|
|
video_ctx->codec = 0;
|
|
|
|
/* If shutdown before completion, need to handle the fence.*/
|
|
if (video_ctx->handle_sequence_needed) {
|
|
*topaz_priv->topaz_sync_addr = video_ctx->cur_sequence;
|
|
psb_fence_handler(dev_priv->dev, LNC_ENGINE_ENCODE);
|
|
video_ctx->handle_sequence_needed = false;
|
|
}
|
|
|
|
if (!list_empty(&topaz_priv->topaz_queue) &&
|
|
get_ctx_cnt(dev_priv->dev) == 0) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Flush all commands " \
|
|
"the in queue\n");
|
|
/* clear all the commands in queue */
|
|
list_for_each_entry_safe(entry, next,
|
|
&topaz_priv->topaz_queue,
|
|
head) {
|
|
list_del(&entry->head);
|
|
kfree(entry->cmd);
|
|
kfree(entry);
|
|
}
|
|
}
|
|
|
|
if (get_ctx_cnt(dev_priv->dev) == 0) {
|
|
PSB_DEBUG_TOPAZ("No more active VEC context\n");
|
|
dev_priv->topaz_ctx = NULL;
|
|
}
|
|
|
|
mutex_unlock(&topaz_priv->ctx_mutex);
|
|
|
|
return 0;
|
|
}
|
|
|
|
void tng_topaz_handle_sigint(
|
|
struct drm_device *dev,
|
|
struct file *filp)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
struct psb_video_ctx *video_ctx;
|
|
uint32_t count = 0;
|
|
|
|
video_ctx = get_ctx_from_fp(dev, filp);
|
|
if (video_ctx) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Prepare to handle CTRL + C\n");
|
|
} else {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Not VEC context or already released\n");
|
|
return;
|
|
}
|
|
|
|
while (topaz_priv->topaz_busy == 1 &&
|
|
count++ < 20000)
|
|
PSB_UDELAY(6);
|
|
|
|
if (count == 20000)
|
|
DRM_ERROR("Failed to handle sigint event\n");
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Start to handle CTRL + C\n");
|
|
psb_remove_videoctx(dev_priv, filp);
|
|
}
|
|
|
|
int tng_topaz_dequeue_send(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_cmd_queue *topaz_cmd = NULL;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
if (topaz_priv->vec_err == 1) {
|
|
DRM_ERROR("TOPAZ: VEC has error, bypass dequeue and send cmd");
|
|
return -1;
|
|
}
|
|
|
|
/* Avoid race condition with queue buffer when topaz_busy = 1 */
|
|
mutex_lock(&topaz_priv->topaz_mutex);
|
|
if (list_empty(&topaz_priv->topaz_queue)) {
|
|
topaz_priv->topaz_busy = 0;
|
|
PSB_DEBUG_TOPAZ("TOPAZ: empty command queue, " \
|
|
"set topaz_busy = 0, directly return\n");
|
|
mutex_unlock(&topaz_priv->topaz_mutex);
|
|
return ret;
|
|
}
|
|
|
|
topaz_cmd = list_first_entry(&topaz_priv->topaz_queue,
|
|
struct tng_topaz_cmd_queue, head);
|
|
|
|
if (topaz_priv->saved_queue == NULL ||
|
|
topaz_priv->saved_cmd == NULL) {
|
|
DRM_ERROR("TOPAZ: Failed to get saved queue/cmd pointer");
|
|
return -1;
|
|
}
|
|
|
|
memset(topaz_priv->saved_queue, 0, sizeof(struct tng_topaz_cmd_queue));
|
|
memset(topaz_priv->saved_cmd, 0, MAX_CMD_SIZE);
|
|
|
|
topaz_priv->saved_queue->file_priv = topaz_cmd->file_priv;
|
|
topaz_priv->saved_queue->cmd_size = topaz_cmd->cmd_size;
|
|
topaz_priv->saved_queue->sequence = topaz_cmd->sequence;
|
|
topaz_priv->saved_queue->head = topaz_cmd->head;
|
|
|
|
memcpy(topaz_priv->saved_cmd, topaz_cmd->cmd, topaz_cmd->cmd_size);
|
|
|
|
list_del(&topaz_cmd->head);
|
|
kfree(topaz_cmd->cmd);
|
|
kfree(topaz_cmd);
|
|
mutex_unlock(&topaz_priv->topaz_mutex);
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: dequeue command of sequence %08x " \
|
|
"and send it to topaz\n", \
|
|
topaz_priv->saved_queue->sequence);
|
|
|
|
ret = tng_topaz_send(dev,
|
|
topaz_priv->saved_queue->file_priv,
|
|
topaz_priv->saved_cmd,
|
|
topaz_priv->saved_queue->cmd_size,
|
|
topaz_priv->saved_queue->sequence);
|
|
if (ret) {
|
|
DRM_ERROR("TOPAZ: tng_topaz_send in dequeue failed.\n");
|
|
topaz_priv->vec_err = 1;
|
|
return -EINVAL;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: dequeue command of sequence %08x " \
|
|
"finished\n", topaz_priv->saved_queue->sequence);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int32_t tng_check_topaz_idle(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
(struct drm_psb_private *)dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
uint32_t reg_val;
|
|
|
|
if (dev_priv->topaz_ctx == NULL) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: topaz context is null\n");
|
|
return 0;
|
|
}
|
|
|
|
/*HW is stuck. Need to power off TopazSC to reset HW*/
|
|
if (1 == topaz_priv->topaz_needs_reset) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Topaz needs reset\n");
|
|
return 0;
|
|
}
|
|
|
|
if (topaz_priv->topaz_busy) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: can't save, topaz_busy = %d\n", \
|
|
topaz_priv->topaz_busy);
|
|
return -EBUSY;
|
|
}
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_CMD_FIFO_WRITE_SPACE,
|
|
®_val);
|
|
reg_val &= MASK_TOPAZHP_TOP_CR_CMD_FIFO_SPACE;
|
|
if (reg_val != 32) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: HW is busy. Free words in command" \
|
|
"FIFO is %d.\n",
|
|
reg_val);
|
|
return -EBUSY;
|
|
}
|
|
|
|
return 0; /* we think it is idle */
|
|
}
|
|
|
|
|
|
int32_t tng_video_get_core_num(struct drm_device *dev, uint64_t user_pointer)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
(struct drm_psb_private *)dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
ret = copy_to_user((void __user *)((unsigned long)user_pointer),
|
|
&topaz_priv->topaz_num_pipes,
|
|
sizeof(topaz_priv->topaz_num_pipes));
|
|
|
|
if (ret)
|
|
return -EFAULT;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
int32_t tng_video_frameskip(struct drm_device *dev, uint64_t user_pointer)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
(struct drm_psb_private *)dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
int32_t ret = 0;
|
|
|
|
ret = copy_to_user((void __user *)((unsigned long)user_pointer),
|
|
&topaz_priv->frame_skip, sizeof(topaz_priv->frame_skip));
|
|
|
|
if (ret)
|
|
return -EFAULT;
|
|
|
|
return ret;
|
|
}
|
|
|
|
static void tng_topaz_flush_cmd_queue(struct tng_topaz_private *topaz_priv)
|
|
{
|
|
struct tng_topaz_cmd_queue *entry, *next;
|
|
|
|
/* remind to reset topaz */
|
|
topaz_priv->topaz_needs_reset = 1;
|
|
topaz_priv->topaz_busy = 0;
|
|
|
|
if (list_empty(&topaz_priv->topaz_queue))
|
|
return;
|
|
|
|
/* flush all command in queue */
|
|
list_for_each_entry_safe(entry, next,
|
|
&topaz_priv->topaz_queue,
|
|
head) {
|
|
list_del(&entry->head);
|
|
kfree(entry->cmd);
|
|
kfree(entry);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void tng_topaz_handle_timeout(struct ttm_fence_device *fdev)
|
|
{
|
|
struct drm_psb_private *dev_priv =
|
|
container_of(fdev, struct drm_psb_private, fdev);
|
|
/*struct drm_device *dev =
|
|
container_of((void *)dev_priv,
|
|
struct drm_device, dev_private);*/
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
|
|
/* if (IS_MRST(dev))
|
|
return lnc_topaz_handle_timeout(fdev);
|
|
*/
|
|
DRM_ERROR("TOPAZ: current codec is %s\n",
|
|
codec_to_string(topaz_priv->cur_codec));
|
|
tng_topaz_flush_cmd_queue(topaz_priv);
|
|
|
|
|
|
/* Power down TopazSC to reset HW*/
|
|
/* schedule_delayed_work(&topaz_priv->topaz_suspend_wq, 0); */
|
|
}
|
|
|
|
void tng_topaz_enableirq(struct drm_device *dev)
|
|
{
|
|
#ifdef TOPAZHP_IRQ_ENABLED
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
uint32_t crImgTopazIntenab;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Enable TOPAZHP IRQ\n");
|
|
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB,
|
|
&crImgTopazIntenab);
|
|
|
|
crImgTopazIntenab |= (MASK_TOPAZHP_TOP_CR_MTX_INTEN_MTX |
|
|
MASK_TOPAZHP_TOP_CR_HOST_TOPAZHP_MAS_INTEN);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB,
|
|
crImgTopazIntenab);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_MTX_INT_ENAB,
|
|
MASK_MTX_INT_ENAB);
|
|
#else
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
void tng_topaz_disableirq(struct drm_device *dev)
|
|
{
|
|
uint32_t crImgTopazIntenab;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: Disable TOPAZHP IRQ\n");
|
|
MULTICORE_READ32(TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB,
|
|
&crImgTopazIntenab);
|
|
|
|
crImgTopazIntenab &= ~(MASK_TOPAZHP_TOP_CR_MTX_INTEN_MTX);
|
|
|
|
MULTICORE_WRITE32(TOPAZHP_TOP_CR_MULTICORE_HOST_INT_ENAB,
|
|
crImgTopazIntenab);
|
|
}
|
|
|
|
/* Disable VEC or GFX clock gating */
|
|
void tng_topaz_CG_disable(struct drm_device *dev)
|
|
{
|
|
int reg_val;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
|
|
if (drm_topaz_cgpolicy & PSB_CGPOLICY_GFXCG_DIS) {
|
|
reg_val = ioread32(dev_priv->wrapper_reg + 0);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: GFX CG 0 = %08x, " \
|
|
"disable GFX CG\n", reg_val);
|
|
iowrite32(0x103, dev_priv->wrapper_reg + 0);
|
|
reg_val = ioread32(dev_priv->wrapper_reg + 0);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: GFX CG 0 = %08x\n", reg_val);
|
|
}
|
|
|
|
if (drm_topaz_cgpolicy & PSB_CGPOLICY_VECCG_DIS) {
|
|
reg_val = ioread32(dev_priv->vec_wrapper_reg + 0);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: VEC CG 0 = %08x, " \
|
|
"disable VEC CG\n", reg_val);
|
|
iowrite32(0x03, dev_priv->vec_wrapper_reg + 0);
|
|
reg_val = ioread32(dev_priv->vec_wrapper_reg + 0);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: VEC CG 0 = %08x\n", reg_val);
|
|
}
|
|
}
|
|
|
|
static int pm_cmd_freq_wait(u32 reg_freq)
|
|
{
|
|
int tcount;
|
|
u32 freq_val;
|
|
|
|
for (tcount = 0; ; tcount++) {
|
|
freq_val = intel_mid_msgbus_read32(PUNIT_PORT, reg_freq);
|
|
if ((freq_val & IP_FREQ_VALID) == 0)
|
|
break;
|
|
if (tcount > 500) {
|
|
DRM_ERROR("P-Unit freq request wait timeout");
|
|
return -EBUSY;
|
|
}
|
|
udelay(1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pm_cmd_freq_set(u32 reg_freq, u32 freq_code)
|
|
{
|
|
u32 freq_val;
|
|
int rva;
|
|
|
|
pm_cmd_freq_wait(reg_freq);
|
|
|
|
freq_val = IP_FREQ_VALID | freq_code;
|
|
intel_mid_msgbus_write32(PUNIT_PORT, reg_freq, freq_val);
|
|
|
|
rva = pm_cmd_freq_wait(reg_freq);
|
|
|
|
return rva;
|
|
}
|
|
|
|
int tng_topaz_set_vec_freq(u32 freq_code)
|
|
{
|
|
return pm_cmd_freq_set(VEC_SS_PM1, freq_code);
|
|
}
|
|
|
|
#define PMU_ENC 0x1
|
|
/* Workaround to disable D0i3 */
|
|
bool power_island_get_dummy(struct drm_device *dev)
|
|
{
|
|
int pm_ret = 0;
|
|
unsigned long irqflags;
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
|
|
if (atomic_read(&topaz_priv->vec_ref_count))
|
|
goto out;
|
|
|
|
pm_ret = pmu_nc_set_power_state(PMU_ENC, OSPM_ISLAND_UP, VEC_SS_PM0);
|
|
if (pm_ret) {
|
|
PSB_DEBUG_PM("power up vec failed\n");
|
|
return false;
|
|
}
|
|
|
|
spin_lock_irqsave(&dev_priv->irqmask_lock, irqflags);
|
|
|
|
dev_priv->vdc_irq_mask |= _LNC_IRQ_TOPAZ_FLAG;
|
|
PSB_WVDC32(~dev_priv->vdc_irq_mask, PSB_INT_MASK_R);
|
|
PSB_WVDC32(dev_priv->vdc_irq_mask, PSB_INT_ENABLE_R);
|
|
|
|
spin_unlock_irqrestore(&dev_priv->irqmask_lock, irqflags);
|
|
|
|
atomic_inc(&topaz_priv->vec_ref_count);
|
|
|
|
if (drm_topaz_cgpolicy != PSB_CGPOLICY_ON)
|
|
tng_topaz_CG_disable(dev);
|
|
out:
|
|
return true;
|
|
}
|
|
|
|
/* Workaround to disable D0i3 */
|
|
bool power_island_put_dummy(struct drm_device *dev)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
int tng_topaz_power_up(
|
|
struct drm_device *dev,
|
|
enum drm_tng_topaz_codec codec)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
u32 reg_val = 0;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: power up start\n");
|
|
|
|
if (Is_Secure_Fw()) {
|
|
if (is_island_on(OSPM_VIDEO_ENC_ISLAND)) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: power is already up, end and return\n");
|
|
return 0;
|
|
}
|
|
reg_val = intel_mid_msgbus_read32(PUNIT_PORT, VEC_SS_PM0);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: VECSSPM0 (0) = 0x%08x\n", reg_val);
|
|
reg_val &= ~((u32)0x7c);
|
|
reg_val |= ((u32)codec) << 2;
|
|
intel_mid_msgbus_write32(PUNIT_PORT, VEC_SS_PM0, reg_val);
|
|
PSB_DEBUG_TOPAZ("TOPAZ: VECSSPM0 (1) = 0x%08x\n", reg_val);
|
|
/* udelay(2); */
|
|
}
|
|
|
|
#ifdef MRFLD_B0_DEBUG
|
|
reg_val = intel_mid_msgbus_read32(PUNIT_PORT, VEC_SS_PM0);
|
|
PSB_DEBUG_TOPAZ("Read R(0x%08x) V(0x%08x)\n",
|
|
VEC_SS_PM0, reg_val);
|
|
reg_val &= ~((u32)0x3);
|
|
|
|
intel_mid_msgbus_write32(PUNIT_PORT, VEC_SS_PM0, reg_val);
|
|
PSB_DEBUG_TOPAZ("write R(0x%08x) V(0x%08x)\n",
|
|
VEC_SS_PM0, reg_val);
|
|
while (count != 0) {
|
|
reg_val = intel_mid_msgbus_read32(PUNIT_PORT, DPC_SSC);
|
|
PSB_DEBUG_TOPAZ("RR (%d), A(0x%08x) V(0x%08x)\n",
|
|
count, DPC_SSC, reg_val);
|
|
reg_val = intel_mid_msgbus_read32(PUNIT_PORT, VEC_SS_PM0);
|
|
count -= 1;
|
|
if (reg_val == (codec<<2))
|
|
count = 0;
|
|
PSB_DEBUG_TOPAZ("RR (%d), A(0x%08x) V(0x%08x)\n",
|
|
count, VEC_SS_PM0, reg_val);
|
|
udelay(20);
|
|
if (count != 0) {
|
|
reg_val &= ~((u32)0x3);
|
|
intel_mid_msgbus_write32(PUNIT_PORT,
|
|
VEC_SS_PM0, reg_val);
|
|
PSB_DEBUG_TOPAZ("WW (%d), A(0x%08x) V(0x%08x)\n",
|
|
count, VEC_SS_PM0, reg_val);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (drm_topaz_pmpolicy == PSB_PMPOLICY_NOPM)
|
|
PSB_DEBUG_TOPAZ("Topaz: NOPM policy, but still need powerup here\n");
|
|
|
|
/* Reduce D0i0 residency, original it is 0 set by GFX driver */
|
|
topaz_priv->dev->pdev->d3_delay = 10;
|
|
|
|
if (!power_island_get(OSPM_VIDEO_ENC_ISLAND)) {
|
|
DRM_ERROR("Failed to power on ENC island\n");
|
|
return -1;
|
|
}
|
|
|
|
/* Must flush here in case of invalid cache data */
|
|
/* tng_topaz_mmu_flushcache(dev_priv); */
|
|
PSB_DEBUG_TOPAZ("TOPAZ: power up end\n");
|
|
return 0;
|
|
}
|
|
|
|
int tng_topaz_power_off(struct drm_device *dev)
|
|
{
|
|
struct drm_psb_private *dev_priv = dev->dev_private;
|
|
struct tng_topaz_private *topaz_priv = dev_priv->topaz_private;
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: power off start\n");
|
|
if (Is_Secure_Fw()) {
|
|
if (!is_island_on(OSPM_VIDEO_ENC_ISLAND)) {
|
|
PSB_DEBUG_TOPAZ("TOPAZ: power is already off\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (drm_topaz_pmpolicy == PSB_PMPOLICY_NOPM)
|
|
PSB_DEBUG_TOPAZ("TOPAZ: skip power off since NOPM policy\n");
|
|
else {
|
|
power_island_put(OSPM_VIDEO_ENC_ISLAND);
|
|
/* Restore delay to 0 */
|
|
topaz_priv->dev->pdev->d3_delay = 0;
|
|
}
|
|
|
|
PSB_DEBUG_TOPAZ("TOPAZ: power off end\n");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int Is_Secure_Fw()
|
|
{
|
|
if (intel_mid_identify_cpu() == INTEL_MID_CPU_CHIP_TANGIER &&
|
|
intel_mid_soc_stepping() < 1)
|
|
return 0;
|
|
return 1;
|
|
}
|