Skip to content

Commit

Permalink
media: chips-media: wave5: Add vpuapi layer
Browse files Browse the repository at this point in the history
Add the vpuapi layer of the wave5 codec driver.
This layer is used to configure the hardware according
to the parameters.

Signed-off-by: Sebastian Fricke <sebastian.fricke@collabora.com>
Signed-off-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
Signed-off-by: Dafna Hirschfeld <dafna.hirschfeld@collabora.com>
Signed-off-by: Robert Beckett <bob.beckett@collabora.com>
Signed-off-by: Nas Chung <nas.chung@chipsnmedia.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
  • Loading branch information
Nas Chung authored and Hans Verkuil committed Nov 16, 2023
1 parent 02a8b42 commit 45d1a2b
Show file tree
Hide file tree
Showing 9 changed files with 5,839 additions and 0 deletions.
2,554 changes: 2,554 additions & 0 deletions drivers/media/platform/chips-media/wave5/wave5-hw.c

Large diffs are not rendered by default.

732 changes: 732 additions & 0 deletions drivers/media/platform/chips-media/wave5/wave5-regdefine.h

Large diffs are not rendered by default.

205 changes: 205 additions & 0 deletions drivers/media/platform/chips-media/wave5/wave5-vdi.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
/*
* Wave5 series multi-standard codec IP - low level access functions
*
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/

#include <linux/bug.h>
#include "wave5-vdi.h"
#include "wave5-vpu.h"
#include "wave5-regdefine.h"
#include <linux/delay.h>

static int wave5_vdi_allocate_common_memory(struct device *dev)
{
struct vpu_device *vpu_dev = dev_get_drvdata(dev);

if (!vpu_dev->common_mem.vaddr) {
int ret;

vpu_dev->common_mem.size = SIZE_COMMON;
ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem);
if (ret) {
dev_err(dev, "unable to allocate common buffer\n");
return ret;
}
}

dev_dbg(dev, "[VDI] common_mem: daddr=%pad size=%zu vaddr=0x%p\n",
&vpu_dev->common_mem.daddr, vpu_dev->common_mem.size, vpu_dev->common_mem.vaddr);

return 0;
}

int wave5_vdi_init(struct device *dev)
{
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
int ret;

ret = wave5_vdi_allocate_common_memory(dev);
if (ret < 0) {
dev_err(dev, "[VDI] failed to get vpu common buffer from driver\n");
return ret;
}

if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) {
WARN_ONCE(1, "unsupported product code: 0x%x\n", vpu_dev->product_code);
return -EOPNOTSUPP;
}

/* if BIT processor is not running. */
if (wave5_vdi_read_register(vpu_dev, W5_VCPU_CUR_PC) == 0) {
int i;

for (i = 0; i < 64; i++)
wave5_vdi_write_register(vpu_dev, (i * 4) + 0x100, 0x0);
}

dev_dbg(dev, "[VDI] driver initialized successfully\n");

return 0;
}

int wave5_vdi_release(struct device *dev)
{
struct vpu_device *vpu_dev = dev_get_drvdata(dev);

vpu_dev->vdb_register = NULL;
wave5_vdi_free_dma_memory(vpu_dev, &vpu_dev->common_mem);

return 0;
}

void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data)
{
writel(data, vpu_dev->vdb_register + addr);
}

unsigned int wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr)
{
return readl(vpu_dev->vdb_register + addr);
}

int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
{
if (!vb || !vb->vaddr) {
dev_err(vpu_dev->dev, "%s: unable to clear unmapped buffer\n", __func__);
return -EINVAL;
}

memset(vb->vaddr, 0, vb->size);
return vb->size;
}

int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset,
u8 *data, size_t len)
{
if (!vb || !vb->vaddr) {
dev_err(vpu_dev->dev, "%s: unable to write to unmapped buffer\n", __func__);
return -EINVAL;
}

if (offset > vb->size || len > vb->size || offset + len > vb->size) {
dev_err(vpu_dev->dev, "%s: buffer too small\n", __func__);
return -ENOSPC;
}

memcpy(vb->vaddr + offset, data, len);

return len;
}

int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
{
void *vaddr;
dma_addr_t daddr;

if (!vb->size) {
dev_err(vpu_dev->dev, "%s: requested size==0\n", __func__);
return -EINVAL;
}

vaddr = dma_alloc_coherent(vpu_dev->dev, vb->size, &daddr, GFP_KERNEL);
if (!vaddr)
return -ENOMEM;
vb->vaddr = vaddr;
vb->daddr = daddr;

return 0;
}

int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
{
if (vb->size == 0)
return -EINVAL;

if (!vb->vaddr)
dev_err(vpu_dev->dev, "%s: requested free of unmapped buffer\n", __func__);
else
dma_free_coherent(vpu_dev->dev, vb->size, vb->vaddr, vb->daddr);

memset(vb, 0, sizeof(*vb));

return 0;
}

int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count,
size_t size)
{
struct vpu_buf vb_buf;
int i, ret = 0;

vb_buf.size = size;

for (i = 0; i < count; i++) {
if (array[i].size == size)
continue;

if (array[i].size != 0)
wave5_vdi_free_dma_memory(vpu_dev, &array[i]);

ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_buf);
if (ret)
return -ENOMEM;
array[i] = vb_buf;
}

for (i = count; i < MAX_REG_FRAME; i++)
wave5_vdi_free_dma_memory(vpu_dev, &array[i]);

return 0;
}

void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev)
{
struct vpu_buf *vb = &vpu_dev->sram_buf;

if (!vpu_dev->sram_pool || !vpu_dev->sram_size)
return;

if (!vb->vaddr) {
vb->size = vpu_dev->sram_size;
vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size,
&vb->daddr);
if (!vb->vaddr)
vb->size = 0;
}

dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n",
__func__, &vb->daddr, vb->size, vb->vaddr);
}

void wave5_vdi_free_sram(struct vpu_device *vpu_dev)
{
struct vpu_buf *vb = &vpu_dev->sram_buf;

if (!vb->size || !vb->vaddr)
return;

if (vb->vaddr)
gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr,
vb->size);

memset(vb, 0, sizeof(*vb));
}
35 changes: 35 additions & 0 deletions drivers/media/platform/chips-media/wave5/wave5-vdi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
/*
* Wave5 series multi-standard codec IP - low level access functions
*
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/

#ifndef _VDI_H_
#define _VDI_H_

#include "wave5-vpuconfig.h"
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/device.h>

/************************************************************************/
/* COMMON REGISTERS */
/************************************************************************/
#define VPU_PRODUCT_CODE_REGISTER 0x1044

/* system register write */
#define vpu_write_reg(VPU_INST, ADDR, DATA) wave5_vdi_write_register(VPU_INST, ADDR, DATA)
/* system register read */
#define vpu_read_reg(CORE, ADDR) wave5_vdi_read_register(CORE, ADDR)

struct vpu_buf {
size_t size;
dma_addr_t daddr;
void *vaddr;
};

int wave5_vdi_init(struct device *dev);
int wave5_vdi_release(struct device *dev); //this function may be called only at system off.

#endif //#ifndef _VDI_H_
Loading

0 comments on commit 45d1a2b

Please sign in to comment.