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