mirror of https://gitee.com/openkylin/linux.git
[media] coda: update CODA7541 to firmware 1.4.50
This patch splits the global workbuf into a global tempbuf and a per-context workbuf, adds the codec mode aux register, and restores the work buffer pointer on commands. With the new firmware, there is only a single set of read/write pointers which need to be restored between context switches. This allows more than four active contexts at the same time. All auxiliary buffers are now allocated through a helper function to avoid code duplication. Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de> Signed-off-by: Kamil Debski <k.debski@samsung.com> Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
This commit is contained in:
parent
2039749ec2
commit
5677e3b04d
|
@ -41,7 +41,8 @@
|
|||
|
||||
#define CODA_FMO_BUF_SIZE 32
|
||||
#define CODADX6_WORK_BUF_SIZE (288 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
|
||||
#define CODA7_WORK_BUF_SIZE (512 * 1024 + CODA_FMO_BUF_SIZE * 8 * 1024)
|
||||
#define CODA7_WORK_BUF_SIZE (128 * 1024)
|
||||
#define CODA7_TEMP_BUF_SIZE (304 * 1024)
|
||||
#define CODA_PARA_BUF_SIZE (10 * 1024)
|
||||
#define CODA_ISRAM_SIZE (2048 * 2)
|
||||
#define CODADX6_IRAM_SIZE 0xb000
|
||||
|
@ -129,6 +130,7 @@ struct coda_dev {
|
|||
struct clk *clk_ahb;
|
||||
|
||||
struct coda_aux_buf codebuf;
|
||||
struct coda_aux_buf tempbuf;
|
||||
struct coda_aux_buf workbuf;
|
||||
struct gen_pool *iram_pool;
|
||||
long unsigned int iram_vaddr;
|
||||
|
@ -153,6 +155,7 @@ struct coda_params {
|
|||
u8 mpeg4_inter_qp;
|
||||
u8 gop_size;
|
||||
int codec_mode;
|
||||
int codec_mode_aux;
|
||||
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
|
||||
u32 framerate;
|
||||
u16 bitrate;
|
||||
|
@ -192,8 +195,10 @@ struct coda_ctx {
|
|||
int vpu_header_size[3];
|
||||
struct coda_aux_buf parabuf;
|
||||
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
|
||||
struct coda_aux_buf workbuf;
|
||||
int num_internal_frames;
|
||||
int idx;
|
||||
int reg_idx;
|
||||
struct coda_iram_info iram_info;
|
||||
};
|
||||
|
||||
|
@ -241,10 +246,18 @@ static int coda_wait_timeout(struct coda_dev *dev)
|
|||
static void coda_command_async(struct coda_ctx *ctx, int cmd)
|
||||
{
|
||||
struct coda_dev *dev = ctx->dev;
|
||||
|
||||
if (dev->devtype->product == CODA_7541) {
|
||||
/* Restore context related registers to CODA */
|
||||
coda_write(dev, ctx->workbuf.paddr, CODA_REG_BIT_WORK_BUF_ADDR);
|
||||
}
|
||||
|
||||
coda_write(dev, CODA_REG_BIT_BUSY_FLAG, CODA_REG_BIT_BUSY);
|
||||
|
||||
coda_write(dev, ctx->idx, CODA_REG_BIT_RUN_INDEX);
|
||||
coda_write(dev, ctx->params.codec_mode, CODA_REG_BIT_RUN_COD_STD);
|
||||
coda_write(dev, ctx->params.codec_mode_aux, CODA7_REG_BIT_RUN_AUX_STD);
|
||||
|
||||
coda_write(dev, cmd, CODA_REG_BIT_RUN_COMMAND);
|
||||
}
|
||||
|
||||
|
@ -968,21 +981,6 @@ static void coda_wait_finish(struct vb2_queue *q)
|
|||
coda_lock(ctx);
|
||||
}
|
||||
|
||||
static void coda_free_framebuffers(struct coda_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++) {
|
||||
if (ctx->internal_frames[i].vaddr) {
|
||||
dma_free_coherent(&ctx->dev->plat_dev->dev,
|
||||
ctx->internal_frames[i].size,
|
||||
ctx->internal_frames[i].vaddr,
|
||||
ctx->internal_frames[i].paddr);
|
||||
ctx->internal_frames[i].vaddr = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
|
||||
{
|
||||
struct coda_dev *dev = ctx->dev;
|
||||
|
@ -994,28 +992,69 @@ static void coda_parabuf_write(struct coda_ctx *ctx, int index, u32 value)
|
|||
p[index ^ 1] = value;
|
||||
}
|
||||
|
||||
static int coda_alloc_aux_buf(struct coda_dev *dev,
|
||||
struct coda_aux_buf *buf, size_t size)
|
||||
{
|
||||
buf->vaddr = dma_alloc_coherent(&dev->plat_dev->dev, size, &buf->paddr,
|
||||
GFP_KERNEL);
|
||||
if (!buf->vaddr)
|
||||
return -ENOMEM;
|
||||
|
||||
buf->size = size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int coda_alloc_context_buf(struct coda_ctx *ctx,
|
||||
struct coda_aux_buf *buf, size_t size)
|
||||
{
|
||||
return coda_alloc_aux_buf(ctx->dev, buf, size);
|
||||
}
|
||||
|
||||
static void coda_free_aux_buf(struct coda_dev *dev,
|
||||
struct coda_aux_buf *buf)
|
||||
{
|
||||
if (buf->vaddr) {
|
||||
dma_free_coherent(&dev->plat_dev->dev, buf->size,
|
||||
buf->vaddr, buf->paddr);
|
||||
buf->vaddr = NULL;
|
||||
buf->size = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void coda_free_framebuffers(struct coda_ctx *ctx)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < CODA_MAX_FRAMEBUFFERS; i++)
|
||||
coda_free_aux_buf(ctx->dev, &ctx->internal_frames[i]);
|
||||
}
|
||||
|
||||
static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_data, u32 fourcc)
|
||||
{
|
||||
struct coda_dev *dev = ctx->dev;
|
||||
|
||||
int height = q_data->height;
|
||||
dma_addr_t paddr;
|
||||
int ysize;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (ctx->codec && ctx->codec->src_fourcc == V4L2_PIX_FMT_H264)
|
||||
height = round_up(height, 16);
|
||||
ysize = round_up(q_data->width, 8) * height;
|
||||
|
||||
/* Allocate frame buffers */
|
||||
for (i = 0; i < ctx->num_internal_frames; i++) {
|
||||
ctx->internal_frames[i].size = q_data->sizeimage;
|
||||
if (fourcc == V4L2_PIX_FMT_H264 && dev->devtype->product != CODA_DX6)
|
||||
size_t size;
|
||||
|
||||
size = q_data->sizeimage;
|
||||
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
|
||||
dev->devtype->product != CODA_DX6)
|
||||
ctx->internal_frames[i].size += ysize/4;
|
||||
ctx->internal_frames[i].vaddr = dma_alloc_coherent(
|
||||
&dev->plat_dev->dev, ctx->internal_frames[i].size,
|
||||
&ctx->internal_frames[i].paddr, GFP_KERNEL);
|
||||
if (!ctx->internal_frames[i].vaddr) {
|
||||
ret = coda_alloc_context_buf(ctx, &ctx->internal_frames[i], size);
|
||||
if (ret < 0) {
|
||||
coda_free_framebuffers(ctx);
|
||||
return -ENOMEM;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1026,10 +1065,20 @@ static int coda_alloc_framebuffers(struct coda_ctx *ctx, struct coda_q_data *q_d
|
|||
coda_parabuf_write(ctx, i * 3 + 1, paddr + ysize); /* Cb */
|
||||
coda_parabuf_write(ctx, i * 3 + 2, paddr + ysize + ysize/4); /* Cr */
|
||||
|
||||
if (dev->devtype->product != CODA_DX6 && fourcc == V4L2_PIX_FMT_H264)
|
||||
coda_parabuf_write(ctx, 96 + i, ctx->internal_frames[i].paddr + ysize + ysize/4 + ysize/4);
|
||||
/* mvcol buffer for h.264 */
|
||||
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_H264 &&
|
||||
dev->devtype->product != CODA_DX6)
|
||||
coda_parabuf_write(ctx, 96 + i,
|
||||
ctx->internal_frames[i].paddr +
|
||||
ysize + ysize/4 + ysize/4);
|
||||
}
|
||||
|
||||
/* mvcol buffer for mpeg4 */
|
||||
if ((dev->devtype->product != CODA_DX6) &&
|
||||
(ctx->codec->src_fourcc == V4L2_PIX_FMT_MPEG4))
|
||||
coda_parabuf_write(ctx, 97, ctx->internal_frames[i].paddr +
|
||||
ysize + ysize/4 + ysize/4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1155,6 +1204,49 @@ static void coda_setup_iram(struct coda_ctx *ctx)
|
|||
}
|
||||
}
|
||||
|
||||
static void coda_free_context_buffers(struct coda_ctx *ctx)
|
||||
{
|
||||
struct coda_dev *dev = ctx->dev;
|
||||
|
||||
if (dev->devtype->product != CODA_DX6)
|
||||
coda_free_aux_buf(dev, &ctx->workbuf);
|
||||
}
|
||||
|
||||
static int coda_alloc_context_buffers(struct coda_ctx *ctx,
|
||||
struct coda_q_data *q_data)
|
||||
{
|
||||
struct coda_dev *dev = ctx->dev;
|
||||
size_t size;
|
||||
int ret;
|
||||
|
||||
switch (dev->devtype->product) {
|
||||
case CODA_7541:
|
||||
size = CODA7_WORK_BUF_SIZE;
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ctx->workbuf.vaddr) {
|
||||
v4l2_err(&dev->v4l2_dev, "context buffer still allocated\n");
|
||||
ret = -EBUSY;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = coda_alloc_context_buf(ctx, &ctx->workbuf, size);
|
||||
if (ret < 0) {
|
||||
v4l2_err(&dev->v4l2_dev, "failed to allocate %d byte context buffer",
|
||||
ctx->workbuf.size);
|
||||
goto err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
coda_free_context_buffers(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
|
||||
int header_code, u8 *header, int *size)
|
||||
{
|
||||
|
@ -1170,7 +1262,7 @@ static int coda_encode_header(struct coda_ctx *ctx, struct vb2_buffer *buf,
|
|||
v4l2_err(&dev->v4l2_dev, "CODA_COMMAND_ENCODE_HEADER timeout\n");
|
||||
return ret;
|
||||
}
|
||||
*size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx)) -
|
||||
*size = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx)) -
|
||||
coda_read(dev, CODA_CMD_ENC_HEADER_BB_START);
|
||||
memcpy(header, vb2_plane_vaddr(buf, 0), *size);
|
||||
|
||||
|
@ -1223,6 +1315,11 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Allocate per-instance buffers */
|
||||
ret = coda_alloc_context_buffers(ctx, q_data_src);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
if (!coda_is_initialized(dev)) {
|
||||
v4l2_err(v4l2_dev, "coda is not initialized.\n");
|
||||
return -EFAULT;
|
||||
|
@ -1231,8 +1328,8 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
|
|||
mutex_lock(&dev->coda_mutex);
|
||||
|
||||
coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
|
||||
coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->idx));
|
||||
coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->idx));
|
||||
coda_write(dev, bitstream_buf, CODA_REG_BIT_RD_PTR(ctx->reg_idx));
|
||||
coda_write(dev, bitstream_buf, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
|
||||
switch (dev->devtype->product) {
|
||||
case CODA_DX6:
|
||||
coda_write(dev, CODADX6_STREAM_BUF_DYNALLOC_EN |
|
||||
|
@ -1657,7 +1754,13 @@ static int coda_open(struct file *file)
|
|||
v4l2_fh_add(&ctx->fh);
|
||||
ctx->dev = dev;
|
||||
ctx->idx = idx;
|
||||
|
||||
switch (dev->devtype->product) {
|
||||
case CODA_7541:
|
||||
ctx->reg_idx = 0;
|
||||
break;
|
||||
default:
|
||||
ctx->reg_idx = idx;
|
||||
}
|
||||
set_default_params(ctx);
|
||||
ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx,
|
||||
&coda_queue_init);
|
||||
|
@ -1676,11 +1779,9 @@ static int coda_open(struct file *file)
|
|||
|
||||
ctx->fh.ctrl_handler = &ctx->ctrls;
|
||||
|
||||
ctx->parabuf.vaddr = dma_alloc_coherent(&dev->plat_dev->dev,
|
||||
CODA_PARA_BUF_SIZE, &ctx->parabuf.paddr, GFP_KERNEL);
|
||||
if (!ctx->parabuf.vaddr) {
|
||||
ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE);
|
||||
if (ret < 0) {
|
||||
v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
|
||||
ret = -ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
|
@ -1715,9 +1816,11 @@ static int coda_release(struct file *file)
|
|||
list_del(&ctx->list);
|
||||
coda_unlock(ctx);
|
||||
|
||||
dma_free_coherent(&dev->plat_dev->dev, CODA_PARA_BUF_SIZE,
|
||||
ctx->parabuf.vaddr, ctx->parabuf.paddr);
|
||||
v4l2_m2m_ctx_release(ctx->m2m_ctx);
|
||||
coda_free_context_buffers(ctx);
|
||||
if (ctx->dev->devtype->product == CODA_DX6)
|
||||
coda_free_aux_buf(dev, &ctx->workbuf);
|
||||
|
||||
coda_free_aux_buf(dev, &ctx->parabuf);
|
||||
v4l2_ctrl_handler_free(&ctx->ctrls);
|
||||
clk_disable_unprepare(dev->clk_per);
|
||||
clk_disable_unprepare(dev->clk_ahb);
|
||||
|
@ -1797,7 +1900,8 @@ static irqreturn_t coda_irq_handler(int irq, void *data)
|
|||
/* Get results from the coda */
|
||||
coda_read(dev, CODA_RET_ENC_PIC_TYPE);
|
||||
start_ptr = coda_read(dev, CODA_CMD_ENC_PIC_BB_START);
|
||||
wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->idx));
|
||||
wr_ptr = coda_read(dev, CODA_REG_BIT_WR_PTR(ctx->reg_idx));
|
||||
|
||||
/* Calculate bytesused field */
|
||||
if (dst_buf->v4l2_buf.sequence == 0) {
|
||||
vb2_set_plane_payload(dst_buf, 0, wr_ptr - start_ptr +
|
||||
|
@ -1867,7 +1971,7 @@ static void coda_timeout(struct work_struct *work)
|
|||
|
||||
static u32 coda_supported_firmwares[] = {
|
||||
CODA_FIRMWARE_VERNUM(CODA_DX6, 2, 2, 5),
|
||||
CODA_FIRMWARE_VERNUM(CODA_7541, 13, 4, 29),
|
||||
CODA_FIRMWARE_VERNUM(CODA_7541, 1, 4, 50),
|
||||
};
|
||||
|
||||
static bool coda_firmware_supported(u32 vernum)
|
||||
|
@ -1932,8 +2036,13 @@ static int coda_hw_init(struct coda_dev *dev)
|
|||
coda_write(dev, 0, CODA_REG_BIT_CODE_BUF_ADDR + i * 4);
|
||||
|
||||
/* Tell the BIT where to find everything it needs */
|
||||
coda_write(dev, dev->workbuf.paddr,
|
||||
CODA_REG_BIT_WORK_BUF_ADDR);
|
||||
if (dev->devtype->product == CODA_7541) {
|
||||
coda_write(dev, dev->tempbuf.paddr,
|
||||
CODA_REG_BIT_TEMP_BUF_ADDR);
|
||||
} else {
|
||||
coda_write(dev, dev->workbuf.paddr,
|
||||
CODA_REG_BIT_WORK_BUF_ADDR);
|
||||
}
|
||||
coda_write(dev, dev->codebuf.paddr,
|
||||
CODA_REG_BIT_CODE_BUF_ADDR);
|
||||
coda_write(dev, 0, CODA_REG_BIT_CODE_RUN);
|
||||
|
@ -2020,11 +2129,8 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
|
|||
}
|
||||
|
||||
/* allocate auxiliary per-device code buffer for the BIT processor */
|
||||
dev->codebuf.size = fw->size;
|
||||
dev->codebuf.vaddr = dma_alloc_coherent(&pdev->dev, fw->size,
|
||||
&dev->codebuf.paddr,
|
||||
GFP_KERNEL);
|
||||
if (!dev->codebuf.vaddr) {
|
||||
ret = coda_alloc_aux_buf(dev, &dev->codebuf, fw->size);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to allocate code buffer\n");
|
||||
return;
|
||||
}
|
||||
|
@ -2214,18 +2320,26 @@ static int coda_probe(struct platform_device *pdev)
|
|||
/* allocate auxiliary per-device buffers for the BIT processor */
|
||||
switch (dev->devtype->product) {
|
||||
case CODA_DX6:
|
||||
dev->workbuf.size = CODADX6_WORK_BUF_SIZE;
|
||||
ret = coda_alloc_aux_buf(dev, &dev->workbuf,
|
||||
CODADX6_WORK_BUF_SIZE);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to allocate work buffer\n");
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
return ret;
|
||||
}
|
||||
break;
|
||||
case CODA_7541:
|
||||
dev->tempbuf.size = CODA7_TEMP_BUF_SIZE;
|
||||
break;
|
||||
default:
|
||||
dev->workbuf.size = CODA7_WORK_BUF_SIZE;
|
||||
}
|
||||
dev->workbuf.vaddr = dma_alloc_coherent(&pdev->dev, dev->workbuf.size,
|
||||
&dev->workbuf.paddr,
|
||||
GFP_KERNEL);
|
||||
if (!dev->workbuf.vaddr) {
|
||||
dev_err(&pdev->dev, "failed to allocate work buffer\n");
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
return -ENOMEM;
|
||||
if (dev->tempbuf.size) {
|
||||
ret = coda_alloc_aux_buf(dev, &dev->tempbuf,
|
||||
dev->tempbuf.size);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "failed to allocate temp buffer\n");
|
||||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev->devtype->product == CODA_DX6)
|
||||
|
@ -2257,12 +2371,9 @@ static int coda_remove(struct platform_device *pdev)
|
|||
v4l2_device_unregister(&dev->v4l2_dev);
|
||||
if (dev->iram_vaddr)
|
||||
gen_pool_free(dev->iram_pool, dev->iram_vaddr, dev->iram_size);
|
||||
if (dev->codebuf.vaddr)
|
||||
dma_free_coherent(&pdev->dev, dev->codebuf.size,
|
||||
&dev->codebuf.vaddr, dev->codebuf.paddr);
|
||||
if (dev->workbuf.vaddr)
|
||||
dma_free_coherent(&pdev->dev, dev->workbuf.size, &dev->workbuf.vaddr,
|
||||
dev->workbuf.paddr);
|
||||
coda_free_aux_buf(dev, &dev->codebuf);
|
||||
coda_free_aux_buf(dev, &dev->tempbuf);
|
||||
coda_free_aux_buf(dev, &dev->workbuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#define CODA_STREAM_ENDIAN_SELECT (1 << 0)
|
||||
#define CODA_REG_BIT_FRAME_MEM_CTRL 0x110
|
||||
#define CODA_IMAGE_ENDIAN_SELECT (1 << 0)
|
||||
#define CODA_REG_BIT_TEMP_BUF_ADDR 0x118
|
||||
#define CODA_REG_BIT_RD_PTR(x) (0x120 + 8 * (x))
|
||||
#define CODA_REG_BIT_WR_PTR(x) (0x124 + 8 * (x))
|
||||
#define CODADX6_REG_BIT_SEARCH_RAM_BASE_ADDR 0x140
|
||||
|
@ -91,6 +92,14 @@
|
|||
#define CODA_MODE_INVALID 0xffff
|
||||
#define CODA_REG_BIT_INT_ENABLE 0x170
|
||||
#define CODA_INT_INTERRUPT_ENABLE (1 << 3)
|
||||
#define CODA7_REG_BIT_RUN_AUX_STD 0x178
|
||||
#define CODA_MP4_AUX_MPEG4 0
|
||||
#define CODA_MP4_AUX_DIVX3 1
|
||||
#define CODA_VPX_AUX_THO 0
|
||||
#define CODA_VPX_AUX_VP6 1
|
||||
#define CODA_VPX_AUX_VP8 2
|
||||
#define CODA_H264_AUX_AVC 0
|
||||
#define CODA_H264_AUX_MVC 1
|
||||
|
||||
/*
|
||||
* Commands' mailbox:
|
||||
|
|
Loading…
Reference in New Issue