1 /*
2 * drivers/amlogic/media/stream_input/amports/adec.c
3 *
4 * Copyright (C) 2016 Amlogic, Inc. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 */
17
18 #include <linux/kernel.h>
19 #include <linux/types.h>
20 #include <linux/errno.h>
21 #include <linux/platform_device.h>
22 #include <linux/slab.h>
23 #include <linux/uio_driver.h>
24 #include <linux/amlogic/media/utils/aformat.h>
25 #include <linux/amlogic/media/frame_sync/ptsserv.h>
26 #include <linux/amlogic/media/registers/register.h>
27 #include <linux/amlogic/media/codec_mm/configs.h>
28 #include "../amports/streambuf.h"
29 #include <linux/module.h>
30 #include <linux/of.h>
31 #include "amports_priv.h"
32 #include "../../common/chips/decoder_cpu_ver_info.h"
33 #define INFO_VALID ((astream_dev) && (astream_dev->format))
34
35 struct astream_device_s {
36 char *name;
37 char *format;
38 s32 channum;
39 s32 samplerate;
40 s32 datawidth;
41 int offset;
42
43 struct device dev;
44 };
45
46 static char *astream_format[] = {
47 "amadec_mpeg",
48 "amadec_pcm_s16le",
49 "amadec_aac",
50 "amadec_ac3",
51 "amadec_alaw",
52 "amadec_mulaw",
53 "amadec_dts",
54 "amadec_pcm_s16be",
55 "amadec_flac",
56 "amadec_cook",
57 "amadec_pcm_u8",
58 "amadec_adpcm",
59 "amadec_amr",
60 "amadec_raac",
61 "amadec_wma",
62 "amadec_wmapro",
63 "amadec_pcm_bluray",
64 "amadec_alac",
65 "amadec_vorbis",
66 "amadec_aac_latm",
67 "amadec_ape",
68 "amadec_eac3",
69 "amadec_pcm_widi",
70 "amadec_dra",
71 "amadec_sipr",
72 "amadec_truehd",
73 "amadec_mpeg1",
74 "amadec_mpeg2",
75 "amadec_wmavoi",
76 "amadec_wmalossless",
77 "amadec_pcm_s24le",
78 "adec_max"
79 };
80
81 static const char *na_string = "NA";
82 static struct astream_device_s *astream_dev;
83
format_show(struct class * class,struct class_attribute * attr,char * buf)84 static ssize_t format_show(struct class *class, struct class_attribute *attr,
85 char *buf)
86 {
87 if (INFO_VALID && astream_dev->format)
88 return sprintf(buf, "%s\n", astream_dev->format);
89 else
90 return sprintf(buf, "%s\n", na_string);
91 }
92
channum_show(struct class * class,struct class_attribute * attr,char * buf)93 static ssize_t channum_show(struct class *class, struct class_attribute *attr,
94 char *buf)
95 {
96 if (INFO_VALID)
97 return sprintf(buf, "%u\n", astream_dev->channum);
98 else
99 return sprintf(buf, "%s\n", na_string);
100 }
101
samplerate_show(struct class * class,struct class_attribute * attr,char * buf)102 static ssize_t samplerate_show(struct class *class,
103 struct class_attribute *attr, char *buf)
104 {
105 if (INFO_VALID)
106 return sprintf(buf, "%u\n", astream_dev->samplerate);
107 else
108 return sprintf(buf, "%s\n", na_string);
109 }
110
datawidth_show(struct class * class,struct class_attribute * attr,char * buf)111 static ssize_t datawidth_show(struct class *class,
112 struct class_attribute *attr,
113 char *buf)
114 {
115 if (INFO_VALID)
116 return sprintf(buf, "%u\n", astream_dev->datawidth);
117 else
118 return sprintf(buf, "%s\n", na_string);
119 }
120
pts_show(struct class * class,struct class_attribute * attr,char * buf)121 static ssize_t pts_show(struct class *class, struct class_attribute *attr,
122 char *buf)
123 {
124 u32 pts, frame_size;
125 u32 pts_margin = 0;
126
127 if (astream_dev->samplerate <= 12000)
128 pts_margin = 512;
129
130 if (INFO_VALID && (pts_lookup(PTS_TYPE_AUDIO, &pts,
131 &frame_size, pts_margin) >= 0))
132 return sprintf(buf, "0x%x\n", pts);
133 else
134 return sprintf(buf, "%s\n", na_string);
135 }
136
addr_offset_show(struct class * class,struct class_attribute * attr,char * buf)137 static ssize_t addr_offset_show(struct class *class,
138 struct class_attribute *attr, char *buf)
139 {
140 return sprintf(buf, "%d\n", astream_dev->offset);
141 }
142
143 static struct class_attribute astream_class_attrs[] = {
144 __ATTR_RO(format),
145 __ATTR_RO(samplerate),
146 __ATTR_RO(channum),
147 __ATTR_RO(datawidth),
148 __ATTR_RO(pts),
149 __ATTR_RO(addr_offset),
150 __ATTR_NULL
151 };
152
153 static struct class astream_class = {
154 .name = "astream",
155 .class_attrs = astream_class_attrs,
156 };
157
158 #if 1
159 #define IO_CBUS_PHY_BASE 0xc1100000ULL
160 #define IO_AOBUS_PHY_BASE 0xc8100000ULL
161 #define CBUS_REG_OFFSET(reg) ((reg) << 2)
162 #define IO_SECBUS_PHY_BASE 0xda000000ULL
163
164
165 #define IO_AOBUS_PHY_BASE_AFTER_G12A 0xff800000ULL
166
167 static struct uio_info astream_uio_info = {
168 .name = "astream_uio",
169 .version = "0.1",
170 .irq = UIO_IRQ_NONE,
171
172 .mem = {
173 [0] = {
174 .name = "AIFIFO",
175 .memtype = UIO_MEM_PHYS,
176 .addr =
177 (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL))
178 &(PAGE_MASK),
179 .size = PAGE_SIZE,
180 },
181 [1] = {
182 .memtype = UIO_MEM_PHYS,
183 .addr =
184 (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(VCOP_CTRL_REG)),
185 .size = PAGE_SIZE,
186 },
187 /*
188 [2] = {
189 .name = "SECBUS",
190 .memtype = UIO_MEM_PHYS,
191 .addr = (IO_SECBUS_PHY_BASE),
192 .size = PAGE_SIZE,
193 },
194 */
195 [2] = {
196 .name = "CBUS",
197 .memtype = UIO_MEM_PHYS,
198 .addr =
199 (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(ASSIST_HW_REV))
200 &(PAGE_MASK),
201 .size = PAGE_SIZE,
202 },
203 [3] = {
204 .name = "CBUS-START",
205 .memtype = UIO_MEM_PHYS,
206 .addr = (IO_CBUS_PHY_BASE + CBUS_REG_OFFSET(0x1000)),
207 .size = PAGE_SIZE,
208 },
209 [4] = {
210 .name = "AOBUS-START",
211 .memtype = UIO_MEM_PHYS,
212 .addr = (IO_AOBUS_PHY_BASE),
213 .size = PAGE_SIZE,
214 },
215 },
216 };
217 #endif
218
astream_release(struct device * dev)219 static void astream_release(struct device *dev)
220 {
221 kfree(astream_dev);
222
223 astream_dev = NULL;
224 }
225
adec_init(struct stream_port_s * port)226 s32 adec_init(struct stream_port_s *port)
227 {
228 enum aformat_e af;
229
230 if (!astream_dev)
231 return -ENODEV;
232
233 af = port->aformat;
234
235 astream_dev->channum = port->achanl;
236 astream_dev->samplerate = port->asamprate;
237 astream_dev->datawidth = port->adatawidth;
238
239 /*wmb();don't need it...*/
240 if (af < ARRAY_SIZE(astream_format))
241 astream_dev->format = astream_format[af];
242 else
243 astream_dev->format = NULL;
244 return 0;
245 }
246 EXPORT_SYMBOL(adec_init);
247
adec_release(enum aformat_e vf)248 s32 adec_release(enum aformat_e vf)
249 {
250 pr_info("adec_release\n");
251
252 if (!astream_dev)
253 return -ENODEV;
254
255 astream_dev->format = NULL;
256
257 return 0;
258 }
259 EXPORT_SYMBOL(adec_release);
260
amstream_adec_show_fun(const char * trigger,int id,char * sbuf,int size)261 int amstream_adec_show_fun(const char *trigger, int id, char *sbuf, int size)
262 {
263 int ret = -1;
264 void *buf, *getbuf = NULL;
265 if (size < PAGE_SIZE) {
266 getbuf = (void *)__get_free_page(GFP_KERNEL);
267 if (!getbuf)
268 return -ENOMEM;
269 buf = getbuf;
270 } else {
271 buf = sbuf;
272 }
273 switch (trigger[0]) {
274 case 'f':
275 ret = format_show(NULL, NULL, buf);
276 break;
277 case 's':
278 ret = samplerate_show(NULL, NULL, buf);
279 break;
280 case 'c':
281 ret = channum_show(NULL, NULL, buf);
282 break;
283 case 'd':
284 ret = datawidth_show(NULL, NULL, buf);
285 break;
286 case 'p':
287 ret = pts_show(NULL, NULL, buf);
288 break;
289 default:
290 ret = -1;
291 }
292 if (ret > 0 && getbuf != NULL) {
293 ret = min_t(int, ret, size);
294 strncpy(sbuf, buf, ret);
295 }
296 if (getbuf != NULL)
297 free_page((unsigned long)getbuf);
298 return ret;
299 }
300
301 static struct mconfig adec_configs[] = {
302 MC_FUN("format", &amstream_adec_show_fun, NULL),
303 MC_FUN("samplerate", &amstream_adec_show_fun, NULL),
304 MC_FUN("channum", &amstream_adec_show_fun, NULL),
305 MC_FUN("datawidth", &amstream_adec_show_fun, NULL),
306 MC_FUN("pts", &amstream_adec_show_fun, NULL),
307 };
308 static struct mconfig_node adec_node;
309
310
astream_dev_register(void)311 s32 astream_dev_register(void)
312 {
313 s32 r;
314 struct device_node *node;
315 unsigned int cbus_base = 0xffd00000;
316
317 r = class_register(&astream_class);
318 if (r) {
319 pr_info("astream class create fail.\n");
320 return r;
321 }
322
323 astream_dev = kzalloc(sizeof(struct astream_device_s), GFP_KERNEL);
324
325 if (!astream_dev) {
326 pr_info("astream device create fail.\n");
327 r = -ENOMEM;
328 goto err_3;
329 }
330
331 astream_dev->dev.class = &astream_class;
332 astream_dev->dev.release = astream_release;
333 astream_dev->offset = 0;
334 dev_set_name(&astream_dev->dev, "astream-dev");
335
336 dev_set_drvdata(&astream_dev->dev, astream_dev);
337
338 r = device_register(&astream_dev->dev);
339 if (r) {
340 pr_info("astream device register fail.\n");
341 goto err_2;
342 }
343
344 if (AM_MESON_CPU_MAJOR_ID_TXL < get_cpu_major_id()
345 && MESON_CPU_MAJOR_ID_GXLX != get_cpu_type()) {
346 node = of_find_node_by_path("/codec_io/io_cbus_base");
347 if (!node) {
348 pr_info("No io_cbus_base node found.");
349 goto err_1;
350 }
351
352 #ifdef CONFIG_ARM64_A32
353 r = of_property_read_u32_index(node, "reg", 0, &cbus_base);
354 #else
355 r = of_property_read_u32_index(node, "reg", 1, &cbus_base);
356 #endif
357 if (r) {
358 pr_info("No find node.\n");
359 goto err_1;
360 }
361
362 /*need to offset -0x100 in txlx.*/
363 astream_dev->offset = -0x100;
364
365 /*need to offset -0x180 in g12a.*/
366 if (AM_MESON_CPU_MAJOR_ID_G12A <= get_cpu_major_id()) {
367 astream_dev->offset = -0x180;
368 /* after G12A chip, the aobus base addr changed */
369 astream_uio_info.mem[4].addr = IO_AOBUS_PHY_BASE_AFTER_G12A;
370 }
371 astream_uio_info.mem[0].addr =
372 (cbus_base + CBUS_REG_OFFSET(AIU_AIFIFO_CTRL +
373 astream_dev->offset)) & (PAGE_MASK);
374
375 astream_uio_info.mem[3].addr =
376 (cbus_base + CBUS_REG_OFFSET(ASSIST_HW_REV +
377 0x100)) & (PAGE_MASK);
378 }
379
380 #if 1
381 if (uio_register_device(&astream_dev->dev, &astream_uio_info)) {
382 pr_info("astream UIO device register fail.\n");
383 r = -ENODEV;
384 goto err_1;
385 }
386 #endif
387 INIT_REG_NODE_CONFIGS("media", &adec_node,
388 "adec", adec_configs, CONFIG_FOR_R);
389 return 0;
390
391 err_1:
392 device_unregister(&astream_dev->dev);
393
394 err_2:
395 kfree(astream_dev);
396 astream_dev = NULL;
397
398 err_3:
399 class_unregister(&astream_class);
400
401 return r;
402 }
403
astream_dev_unregister(void)404 void astream_dev_unregister(void)
405 {
406 if (astream_dev) {
407 #if 1
408 uio_unregister_device(&astream_uio_info);
409 #endif
410
411 device_unregister(&astream_dev->dev);
412
413 class_unregister(&astream_class);
414 }
415 }
416