Media:wave5: wave5 v4l2 driver support gst/ffmpeg
[platform/kernel/linux-starfive.git] / drivers / media / platform / chips-media / wave5 / wave5-vdi.c
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 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 #ifdef CONFIG_SIFIVE_FLUSH
14 #include <soc/sifive/sifive_l2_cache.h>
15 #endif
16
17 #define VDI_SRAM_BASE_ADDR              0x00
18
19 #define VDI_SYSTEM_ENDIAN               VDI_LITTLE_ENDIAN
20 #define VDI_128BIT_BUS_SYSTEM_ENDIAN    VDI_128BIT_LITTLE_ENDIAN
21
22 static int wave5_vdi_allocate_common_memory(struct device *dev)
23 {
24         struct vpu_device *vpu_dev = dev_get_drvdata(dev);
25
26         if (!vpu_dev->common_mem.vaddr) {
27                 int ret;
28
29                 vpu_dev->common_mem.size = SIZE_COMMON;
30                 ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem);
31                 if (ret) {
32                         dev_err(dev, "unable to allocate common buffer\n");
33                         return ret;
34                 }
35         }
36
37         dev_dbg(dev, "[VDI] common_mem: daddr=%pad size=%zu vaddr=0x%p\n",
38                 &vpu_dev->common_mem.daddr, vpu_dev->common_mem.size, vpu_dev->common_mem.vaddr);
39
40         return 0;
41 }
42
43 int wave5_vdi_init(struct device *dev)
44 {
45         struct vpu_device *vpu_dev = dev_get_drvdata(dev);
46         int ret;
47
48         ret = wave5_vdi_allocate_common_memory(dev);
49         if (ret < 0) {
50                 dev_err(dev, "[VDI] failed to get vpu common buffer from driver\n");
51                 return ret;
52         }
53
54         if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) {
55                 WARN_ONCE(1, "unsupported product code: 0x%x\n", vpu_dev->product_code);
56                 return 0;
57         }
58
59         // if BIT processor is not running.
60         if (wave5_vdi_readl(vpu_dev, W5_VCPU_CUR_PC) == 0) {
61                 int i;
62
63                 for (i = 0; i < 64; i++)
64                         wave5_vdi_write_register(vpu_dev, (i * 4) + 0x100, 0x0);
65         }
66
67         dev_dbg(dev, "[VDI] driver initialized successfully\n");
68
69         return 0;
70 }
71
72 int wave5_vdi_release(struct device *dev)
73 {
74         struct vpu_device *vpu_dev = dev_get_drvdata(dev);
75
76         vpu_dev->vdb_register = NULL;
77         wave5_vdi_free_dma_memory(vpu_dev, &vpu_dev->common_mem);
78
79         return 0;
80 }
81
82 void wave5_vdi_write_register(struct vpu_device *vpu_dev, u32 addr, u32 data)
83 {
84         writel(data, vpu_dev->vdb_register + addr);
85 }
86
87 unsigned int wave5_vdi_readl(struct vpu_device *vpu_dev, u32 addr)
88 {
89         return readl(vpu_dev->vdb_register + addr);
90 }
91
92 int wave5_vdi_clear_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
93 {
94         if (!vb || !vb->vaddr) {
95                 dev_err(vpu_dev->dev, "%s: unable to clear unmapped buffer\n", __func__);
96                 return -EINVAL;
97         }
98
99         memset(vb->vaddr, 0, vb->size);
100 #ifdef CONFIG_SIFIVE_FLUSH
101         sifive_flush64_range(vb->daddr, vb->size);
102 #endif
103         return vb->size;
104 }
105
106 static void wave5_swap_endian(struct vpu_device *vpu_dev, u8 *data, size_t len,
107                               unsigned int endian);
108
109 int wave5_vdi_write_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb, size_t offset,
110                            u8 *data, size_t len, unsigned int endian)
111 {
112         if (!vb || !vb->vaddr) {
113                 dev_err(vpu_dev->dev, "%s: unable to write to unmapped buffer\n", __func__);
114                 return -EINVAL;
115         }
116
117         if (offset > vb->size || len > vb->size || offset + len > vb->size) {
118                 dev_err(vpu_dev->dev, "%s: buffer too small\n", __func__);
119                 return -ENOSPC;
120         }
121
122         wave5_swap_endian(vpu_dev, data, len, endian);
123         memcpy(vb->vaddr + offset, data, len);
124 #ifdef CONFIG_SIFIVE_FLUSH
125         sifive_flush64_range(vb->daddr + offset, len);
126 #endif
127
128         return len;
129 }
130
131 int wave5_vdi_allocate_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
132 {
133         void *vaddr;
134         dma_addr_t daddr;
135
136         if (!vb->size) {
137                 dev_err(vpu_dev->dev, "%s: requested size==0\n", __func__);
138                 return -EINVAL;
139         }
140
141         vaddr = dma_alloc_coherent(vpu_dev->dev, vb->size, &daddr, GFP_KERNEL);
142         if (!vaddr)
143                 return -ENOMEM;
144         vb->vaddr = vaddr;
145         vb->daddr = daddr;
146
147 #ifdef CONFIG_SIFIVE_FLUSH
148         sifive_flush64_range(daddr, vb->size);
149 #endif
150
151         return 0;
152 }
153
154 void wave5_vdi_free_dma_memory(struct vpu_device *vpu_dev, struct vpu_buf *vb)
155 {
156         if (vb->size == 0)
157                 return;
158
159         if (!vb->vaddr)
160                 dev_err(vpu_dev->dev, "%s: requested free of unmapped buffer\n", __func__);
161         else
162                 dma_free_coherent(vpu_dev->dev, vb->size, vb->vaddr, vb->daddr);
163
164         memset(vb, 0, sizeof(*vb));
165 }
166
167 unsigned int wave5_vdi_convert_endian(struct vpu_device *vpu_dev, unsigned int endian)
168 {
169         if (PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) {
170                 switch (endian) {
171                 case VDI_LITTLE_ENDIAN:
172                         endian = 0x00;
173                         break;
174                 case VDI_BIG_ENDIAN:
175                         endian = 0x0f;
176                         break;
177                 case VDI_32BIT_LITTLE_ENDIAN:
178                         endian = 0x04;
179                         break;
180                 case VDI_32BIT_BIG_ENDIAN:
181                         endian = 0x03;
182                         break;
183                 }
184         }
185
186         return (endian & 0x0f);
187 }
188
189 static void byte_swap(unsigned char *data, size_t len)
190 {
191         unsigned int i;
192
193         for (i = 0; i < len; i += 2)
194                 swap(data[i], data[i + 1]);
195 }
196
197 static void word_swap(unsigned char *data, size_t len)
198 {
199         u16 *ptr = (u16 *)data;
200         unsigned int i;
201         size_t size = len / sizeof(uint16_t);
202
203         for (i = 0; i < size; i += 2)
204                 swap(ptr[i], ptr[i + 1]);
205 }
206
207 static void dword_swap(unsigned char *data, size_t len)
208 {
209         u32 *ptr = (u32 *)data;
210         size_t size = len / sizeof(u32);
211         unsigned int i;
212
213         for (i = 0; i < size; i += 2)
214                 swap(ptr[i], ptr[i + 1]);
215 }
216
217 static void lword_swap(unsigned char *data, size_t len)
218 {
219         u64 *ptr = (u64 *)data;
220         size_t size = len / sizeof(uint64_t);
221         unsigned int i;
222
223         for (i = 0; i < size; i += 2)
224                 swap(ptr[i], ptr[i + 1]);
225 }
226
227 static void wave5_swap_endian(struct vpu_device *vpu_dev, u8 *data, size_t len,
228                               unsigned int endian)
229 {
230         int changes;
231         unsigned int sys_endian = VDI_128BIT_BUS_SYSTEM_ENDIAN;
232         bool byte_change, word_change, dword_change, lword_change;
233
234         if (!PRODUCT_CODE_W_SERIES(vpu_dev->product_code)) {
235                 dev_err(vpu_dev->dev, "unknown product id: %08x\n", vpu_dev->product_code);
236                 return;
237         }
238
239         endian = wave5_vdi_convert_endian(vpu_dev, endian);
240         sys_endian = wave5_vdi_convert_endian(vpu_dev, sys_endian);
241         if (endian == sys_endian)
242                 return;
243
244         changes = endian ^ sys_endian;
245         byte_change = changes & 0x01;
246         word_change = ((changes & 0x02) == 0x02);
247         dword_change = ((changes & 0x04) == 0x04);
248         lword_change = ((changes & 0x08) == 0x08);
249
250         if (byte_change)
251                 byte_swap(data, len);
252         if (word_change)
253                 word_swap(data, len);
254         if (dword_change)
255                 dword_swap(data, len);
256         if (lword_change)
257                 lword_swap(data, len);
258 }