1// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
2/*
3 * Wave5 series multi-standard codec IP - low level access functions
4 *
5 * Copyright (C) 2021-2023 CHIPS&MEDIA INC
6 */
7
8#include <linux/bug.h>
9#include "wave5-vdi.h"
10#include "wave5-vpu.h"
11#include "wave5-regdefine.h"
12#include <linux/delay.h>
13
14static int wave5_vdi_allocate_common_memory(struct device *dev)
15{
16	struct vpu_device *vpu_dev = dev_get_drvdata(dev);
17
18	if (!vpu_dev->common_mem.vaddr) {
19		int ret;
20
21		vpu_dev->common_mem.size = SIZE_COMMON;
22		ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem);
23		if (ret) {
24			dev_err(dev, "unable to allocate common buffer\n");
25			return ret;
26		}
27	}
28
29	dev_dbg(dev, "[VDI] common_mem: daddr=%pad size=%zu vaddr=0x%p\n",
30		&vpu_dev->common_mem.daddr, vpu_dev->common_mem.size, vpu_dev->common_mem.vaddr);
31
32	return 0;
33}
34
35int wave5_vdi_init(struct device *dev)
36{
37	struct vpu_device *vpu_dev = dev_get_drvdata(dev);
38	int ret;
39
40	ret = wave5_vdi_allocate_common_memory(dev);
41	if (ret < 0) {
42		dev_err(dev, "[VDI] failed to get vpu common buffer from driver\n");
43		return ret;
44	}
45
46	if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) {
47		WARN_ONCE(1, "unsupported product code: 0x%x\n", vpu_dev->product_code);
48		return -EOPNOTSUPP;
49	}
50
51	/* if BIT processor is not running. */
52	if (wave5_vdi_read_register(vpu_dev, W5_VCPU_CUR_PC) == 0) {
53		int i;
54
55		for (i = 0; i < 64; i++)
56			wave5_vdi_write_register(vpu_dev, (i * 4) + 0x100, 0x0);
57	}
58
59	dev_dbg(dev, "[VDI] driver initialized successfully\n");
60
61	return 0;
62}
63
64int wave5_vdi_release(struct device *dev)
65{
66	struct vpu_device *vpu_dev = dev_get_drvdata(dev);
67
68	vpu_dev->vdb_register = NULL;
69	wave5_vdi_free_dma_memory(vpu_dev, &vpu_dev->common_mem);
70
71	return 0;
72}
73
74void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data)
75{
76	writel(data, vpu_dev->vdb_register + addr);
77}
78
79unsigned int wave5_vdi_read_register(struct vpu_device *vpu_dev, u32 addr)
80{
81	return readl(vpu_dev->vdb_register + addr);
82}
83
84int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
85{
86	if (!vb || !vb->vaddr) {
87		dev_err(vpu_dev->dev, "%s: unable to clear unmapped buffer\n", __func__);
88		return -EINVAL;
89	}
90
91	memset(vb->vaddr, 0, vb->size);
92	return vb->size;
93}
94
95int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset,
96			   u8 *data, size_t len)
97{
98	if (!vb || !vb->vaddr) {
99		dev_err(vpu_dev->dev, "%s: unable to write to unmapped buffer\n", __func__);
100		return -EINVAL;
101	}
102
103	if (offset > vb->size || len > vb->size || offset + len > vb->size) {
104		dev_err(vpu_dev->dev, "%s: buffer too small\n", __func__);
105		return -ENOSPC;
106	}
107
108	memcpy(vb->vaddr + offset, data, len);
109
110	return len;
111}
112
113int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
114{
115	void *vaddr;
116	dma_addr_t daddr;
117
118	if (!vb->size) {
119		dev_err(vpu_dev->dev, "%s: requested size==0\n", __func__);
120		return -EINVAL;
121	}
122
123	vaddr = dma_alloc_coherent(vpu_dev->dev, vb->size, &daddr, GFP_KERNEL);
124	if (!vaddr)
125		return -ENOMEM;
126	vb->vaddr = vaddr;
127	vb->daddr = daddr;
128
129	return 0;
130}
131
132int wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
133{
134	if (vb->size == 0)
135		return -EINVAL;
136
137	if (!vb->vaddr)
138		dev_err(vpu_dev->dev, "%s: requested free of unmapped buffer\n", __func__);
139	else
140		dma_free_coherent(vpu_dev->dev, vb->size, vb->vaddr, vb->daddr);
141
142	memset(vb, 0, sizeof(*vb));
143
144	return 0;
145}
146
147int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, unsigned int count,
148			     size_t size)
149{
150	struct vpu_buf vb_buf;
151	int i, ret = 0;
152
153	vb_buf.size = size;
154
155	for (i = 0; i < count; i++) {
156		if (array[i].size == size)
157			continue;
158
159		if (array[i].size != 0)
160			wave5_vdi_free_dma_memory(vpu_dev, &array[i]);
161
162		ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_buf);
163		if (ret)
164			return -ENOMEM;
165		array[i] = vb_buf;
166	}
167
168	for (i = count; i < MAX_REG_FRAME; i++)
169		wave5_vdi_free_dma_memory(vpu_dev, &array[i]);
170
171	return 0;
172}
173
174void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev)
175{
176	struct vpu_buf *vb = &vpu_dev->sram_buf;
177
178	if (!vpu_dev->sram_pool || !vpu_dev->sram_size)
179		return;
180
181	if (!vb->vaddr) {
182		vb->size = vpu_dev->sram_size;
183		vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size,
184					       &vb->daddr);
185		if (!vb->vaddr)
186			vb->size = 0;
187	}
188
189	dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n",
190		__func__, &vb->daddr, vb->size, vb->vaddr);
191}
192
193void wave5_vdi_free_sram(struct vpu_device *vpu_dev)
194{
195	struct vpu_buf *vb = &vpu_dev->sram_buf;
196
197	if (!vb->size || !vb->vaddr)
198		return;
199
200	if (vb->vaddr)
201		gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr,
202			      vb->size);
203
204	memset(vb, 0, sizeof(*vb));
205}
206