1 /*
2 * linux-5.4/drivers/media/platform/sunxi-vin/vin-tdm/vin_tdm.c
3 *
4 * Copyright (c) 2007-2019 Allwinnertech Co., Ltd.
5 *
6 * Authors: Zheng Zequn <zequnzheng@allwinnertech.com>
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19 #include <linux/platform_device.h>
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/delay.h>
23 #include <media/v4l2-device.h>
24 #include <media/v4l2-mediabus.h>
25 #include <media/v4l2-subdev.h>
26 #include "vin_tdm.h"
27 #include "../platform/platform_cfg.h"
28 #include "../vin-video/vin_video.h"
29
30 #define TDM_MODULE_NAME "vin_tdm"
31
32 struct tdm_dev *glb_tdm[VIN_MAX_TDM];
33
34 static struct tdm_format sunxi_tdm_formats[] = {
35 {
36 .code = MEDIA_BUS_FMT_SBGGR8_1X8,
37 .input_type = INPUTTPYE_8BIT,
38 .input_bit_width = RAW_8BIT,
39 }, {
40 .code = MEDIA_BUS_FMT_SGBRG8_1X8,
41 .input_type = INPUTTPYE_8BIT,
42 .input_bit_width = RAW_8BIT,
43 }, {
44 .code = MEDIA_BUS_FMT_SGRBG8_1X8,
45 .input_type = INPUTTPYE_8BIT,
46 .input_bit_width = RAW_8BIT,
47 }, {
48 .code = MEDIA_BUS_FMT_SRGGB8_1X8,
49 .input_type = INPUTTPYE_8BIT,
50 .input_bit_width = RAW_8BIT,
51 }, {
52 .code = MEDIA_BUS_FMT_SBGGR10_1X10,
53 .input_type = INPUTTPYE_10BIT,
54 .input_bit_width = RAW_10BIT,
55 }, {
56 .code = MEDIA_BUS_FMT_SGBRG10_1X10,
57 .input_type = INPUTTPYE_10BIT,
58 .input_bit_width = RAW_10BIT,
59 }, {
60 .code = MEDIA_BUS_FMT_SGRBG10_1X10,
61 .input_type = INPUTTPYE_10BIT,
62 .input_bit_width = RAW_10BIT,
63 }, {
64 .code = MEDIA_BUS_FMT_SRGGB10_1X10,
65 .input_type = INPUTTPYE_10BIT,
66 .input_bit_width = RAW_10BIT,
67 }, {
68 .code = MEDIA_BUS_FMT_SBGGR12_1X12,
69 .input_type = INPUTTPYE_12BIT,
70 .input_bit_width = RAW_12BIT,
71 }, {
72 .code = MEDIA_BUS_FMT_SGBRG12_1X12,
73 .input_type = INPUTTPYE_12BIT,
74 .input_bit_width = RAW_12BIT,
75 }, {
76 .code = MEDIA_BUS_FMT_SGRBG12_1X12,
77 .input_type = INPUTTPYE_12BIT,
78 .input_bit_width = RAW_12BIT,
79 }, {
80 .code = MEDIA_BUS_FMT_SRGGB12_1X12,
81 .input_type = INPUTTPYE_12BIT,
82 .input_bit_width = RAW_12BIT,
83 }
84 };
85
tdm_set_tx_blank(struct tdm_dev * tdm)86 static void tdm_set_tx_blank(struct tdm_dev *tdm)
87 {
88 csic_tdm_omode(tdm->id, 1);
89 csic_tdm_set_hblank(tdm->id, TDM_TX_HBLANK);
90 csic_tdm_set_bblank_fe(tdm->id, TDM_TX_VBLANK/2);
91 csic_tdm_set_bblank_be(tdm->id, TDM_TX_VBLANK/2);
92 }
93
tdm_rx_bufs_free(struct tdm_rx_dev * tdm_rx)94 static void tdm_rx_bufs_free(struct tdm_rx_dev *tdm_rx)
95 {
96 struct tdm_dev *tdm = container_of(tdm_rx, struct tdm_dev, tdm_rx[tdm_rx->id]);
97 int i;
98
99 if (tdm->tdm_rx_buf_en[tdm_rx->id] == 0)
100 return;
101
102 for (i = 0; i < tdm_rx->buf_cnt; i++) {
103 struct tdm_buffer *buf = &tdm_rx->buf[i];
104 struct vin_mm *mm = &tdm_rx->ion_man[i];
105
106 mm->size = tdm_rx->buf_size;
107 if (!buf->virt_addr)
108 continue;
109
110 mm->vir_addr = buf->virt_addr;
111 mm->dma_addr = buf->dma_addr;
112 os_mem_free(&tdm->pdev->dev, mm);
113
114 buf->dma_addr = NULL;
115 buf->virt_addr = NULL;
116 }
117
118 vin_log(VIN_LOG_TDM, "%s: all buffers were freed.\n", tdm_rx->subdev.name);
119
120 tdm->tdm_rx_buf_en[tdm_rx->id] = 0;
121 tdm_rx->buf_size = 0;
122 }
123
tdm_rx_bufs_alloc(struct tdm_rx_dev * tdm_rx,u32 size,u32 count)124 static int tdm_rx_bufs_alloc(struct tdm_rx_dev *tdm_rx, u32 size, u32 count)
125 {
126 struct tdm_dev *tdm = container_of(tdm_rx, struct tdm_dev, tdm_rx[tdm_rx->id]);
127 int i;
128
129 if (tdm->tdm_rx_buf_en[tdm_rx->id] == 1)
130 return 0;
131
132 tdm_rx->buf_size = size;
133 tdm_rx->buf_cnt = count;
134
135 for (i = 0; i < tdm_rx->buf_cnt; i++) {
136 struct tdm_buffer *buf = &tdm_rx->buf[i];
137 struct vin_mm *mm = &tdm_rx->ion_man[i];
138
139 mm->size = size;
140 if (!os_mem_alloc(&tdm->pdev->dev, mm)) {
141 buf->virt_addr = mm->vir_addr;
142 buf->dma_addr = mm->dma_addr;
143 }
144 if (!buf->virt_addr || !buf->dma_addr) {
145 vin_err("%s: Can't acquire memory for DMA buffer %d\n", tdm_rx->subdev.name, i);
146 tdm_rx_bufs_free(tdm_rx);
147 return -ENOMEM;
148 }
149 }
150
151 vin_log(VIN_LOG_TDM, "%s: allocing buffers successfully, buf_cnt and size is %d and %d.\n",
152 tdm_rx->subdev.name, tdm_rx->buf_cnt, tdm_rx->buf_size);
153
154 tdm->tdm_rx_buf_en[tdm_rx->id] = 1;
155 return 0;
156 }
157
tdm_set_rx_cfg(struct tdm_rx_dev * tdm_rx)158 static int tdm_set_rx_cfg(struct tdm_rx_dev *tdm_rx)
159 {
160 struct tdm_dev *tdm = container_of(tdm_rx, struct tdm_dev, tdm_rx[tdm_rx->id]);
161 u32 size;
162 int ret, i;
163
164 csic_tdm_rx_set_buf_num(tdm->id, tdm_rx->id, TDM_BUFS_NUM - 1);
165 csic_tdm_rx_ch0_en(tdm->id, tdm_rx->id, 1);
166 csic_tdm_rx_set_min_ddr_size(tdm->id, tdm_rx->id, DDRSIZE_256b);
167 csic_tdm_rx_input_bit(tdm->id, tdm_rx->id, tdm_rx->tdm_fmt->input_type);
168 csic_tdm_rx_input_size(tdm->id, tdm_rx->id, tdm_rx->format.width, tdm_rx->format.height);
169
170 tdm_rx->width = tdm_rx->format.width;
171 tdm_rx->heigtht = tdm_rx->format.height;
172 size = (roundup(tdm_rx->width, 512)) * tdm_rx->heigtht * tdm_rx->tdm_fmt->input_bit_width / 8;
173 ret = tdm_rx_bufs_alloc(tdm_rx, size, TDM_BUFS_NUM);
174 if (ret)
175 return ret;
176 for (i = 0; i < TDM_BUFS_NUM; i++)
177 csic_tdm_rx_set_address(tdm->id, tdm_rx->id, (unsigned long)tdm_rx->buf[i].dma_addr);
178
179 return 0;
180
181 }
182
sunxi_tdm_subdev_s_stream(struct v4l2_subdev * sd,int enable)183 static int sunxi_tdm_subdev_s_stream(struct v4l2_subdev *sd, int enable)
184 {
185 struct tdm_rx_dev *tdm_rx = v4l2_get_subdevdata(sd);
186 struct tdm_dev *tdm = container_of(tdm_rx, struct tdm_dev, tdm_rx[tdm_rx->id]);
187 struct v4l2_mbus_framefmt *mf = &tdm_rx->format;
188 struct mbus_framefmt_res *res = (void *)mf->reserved;
189 int i;
190
191 switch (res->res_pix_fmt) {
192 case V4L2_PIX_FMT_SBGGR8:
193 case V4L2_PIX_FMT_SGBRG8:
194 case V4L2_PIX_FMT_SGRBG8:
195 case V4L2_PIX_FMT_SRGGB8:
196 case V4L2_PIX_FMT_SBGGR10:
197 case V4L2_PIX_FMT_SGBRG10:
198 case V4L2_PIX_FMT_SGRBG10:
199 case V4L2_PIX_FMT_SRGGB10:
200 case V4L2_PIX_FMT_SBGGR12:
201 case V4L2_PIX_FMT_SGBRG12:
202 case V4L2_PIX_FMT_SGRBG12:
203 case V4L2_PIX_FMT_SRGGB12:
204 vin_log(VIN_LOG_FMT, "%s output fmt is raw, return directly\n", __func__);
205 return 0;
206 default:
207 break;
208 }
209
210 if (enable) {
211 tdm->stream_cnt++;
212 tdm_rx->stream_cnt++;
213
214 if (tdm->stream_cnt == 1)
215 csic_tdm_top_enable(tdm->id);
216
217 if (tdm_rx->stream_cnt == 1) {
218 tdm_set_rx_cfg(tdm_rx);
219 vin_log(VIN_LOG_TDM, "tdm_rx%d open first, setting rx configuration!\n", tdm_rx->id);
220 } else {
221 if (tdm_rx->width != tdm_rx->format.width || tdm_rx->heigtht != tdm_rx->format.height) {
222 vin_err("The size of the %d time opening tdm_rx%d is different from the first time opened\n",
223 tdm_rx->stream_cnt, tdm_rx->id);
224 return -1;
225 }
226 }
227 if (tdm->stream_cnt == 1) {
228 tdm_set_tx_blank(tdm);
229 csic_tdm_fifo_max_layer_en(tdm->id, 1);
230 csic_tdm_int_enable(tdm->id, RX_FRM_LOST_INT_EN | RX_FRM_ERR_INT_EN |
231 RX_BTYPE_ERR_INT_EN | RX_BUF_FULL_INT_EN | RX_COMP_ERR_INT_EN |
232 RX_HB_SHORT_INT_EN | RX_FIFO_FULL_INT_EN);
233 csic_tdm_enable(tdm->id);
234 csic_tdm_tx_cap_enable(tdm->id);
235 vin_log(VIN_LOG_TDM, "tdm%d open first, setting the interrupt and tx configuration!\n", tdm->id);
236 }
237 csic_tdm_rx_enable(tdm->id, tdm_rx->id);
238 csic_tdm_rx_cap_enable(tdm->id, tdm_rx->id);
239 } else {
240 tdm->stream_cnt--;
241 if (tdm->stream_cnt == 0) {
242 csic_tdm_int_disable(tdm->id, TDM_INT_ALL);
243 csic_tdm_rx_cap_disable(tdm->id, tdm_rx->id);
244 csic_tdm_tx_cap_disable(tdm->id);
245 csic_tdm_top_disable(tdm->id);
246
247 for (i = 0; i < TDM_RX_NUM; i++) {
248 if (tdm->tdm_rx_buf_en[i] == 1)
249 tdm_rx_bufs_free(&tdm->tdm_rx[i]);
250 tdm->tdm_rx[i].stream_cnt = 0;
251 }
252 vin_log(VIN_LOG_TDM, "tdm%d close, closing the interrupt and tx/rx configuration!\n", tdm->id);
253 } else
254 vin_warn("TDM is used, cannot stream off!\n");
255 }
256
257 vin_log(VIN_LOG_FMT, "tdm_rx%d %s, %d*%d==%d*%d?\n",
258 tdm_rx->id, enable ? "stream on" : "stream off",
259 tdm_rx->width, tdm_rx->heigtht,
260 tdm_rx->format.width, tdm_rx->format.height);
261 return 0;
262 }
263
264
sunxi_tdm_subdev_get_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)265 static int sunxi_tdm_subdev_get_fmt(struct v4l2_subdev *sd,
266 struct v4l2_subdev_pad_config *cfg,
267 struct v4l2_subdev_format *fmt)
268 {
269 struct tdm_rx_dev *tdm_rx = v4l2_get_subdevdata(sd);
270 struct v4l2_mbus_framefmt *mf;
271
272 mf = &tdm_rx->format;
273 if (!mf)
274 return -EINVAL;
275
276 mutex_lock(&tdm_rx->subdev_lock);
277 fmt->format = *mf;
278 mutex_unlock(&tdm_rx->subdev_lock);
279 return 0;
280 }
281
__tdm_try_format(struct v4l2_mbus_framefmt * mf)282 static struct tdm_format *__tdm_try_format(struct v4l2_mbus_framefmt *mf)
283 {
284 struct tdm_format *tdm_fmt = NULL;
285 int i;
286
287 for (i = 0; i < ARRAY_SIZE(sunxi_tdm_formats); i++)
288 if (mf->code == sunxi_tdm_formats[i].code)
289 tdm_fmt = &sunxi_tdm_formats[i];
290
291 if (tdm_fmt == NULL)
292 tdm_fmt = &sunxi_tdm_formats[0];
293
294 mf->code = tdm_fmt->code;
295
296 return tdm_fmt;
297 }
298
sunxi_tdm_subdev_set_fmt(struct v4l2_subdev * sd,struct v4l2_subdev_pad_config * cfg,struct v4l2_subdev_format * fmt)299 static int sunxi_tdm_subdev_set_fmt(struct v4l2_subdev *sd,
300 struct v4l2_subdev_pad_config *cfg,
301 struct v4l2_subdev_format *fmt)
302 {
303 struct tdm_rx_dev *tdm_rx = v4l2_get_subdevdata(sd);
304 struct v4l2_mbus_framefmt *mf;
305 struct tdm_format *tdm_fmt;
306
307 vin_log(VIN_LOG_FMT, "%s %d*%d %x %d\n", __func__,
308 fmt->format.width, fmt->format.height,
309 fmt->format.code, fmt->format.field);
310
311 mf = &tdm_rx->format;
312
313 if (fmt->pad == MIPI_PAD_SOURCE) {
314 if (mf) {
315 mutex_lock(&tdm_rx->subdev_lock);
316 fmt->format = *mf;
317 mutex_unlock(&tdm_rx->subdev_lock);
318 }
319 return 0;
320 }
321
322 tdm_fmt = __tdm_try_format(&fmt->format);
323 if (mf) {
324 mutex_lock(&tdm_rx->subdev_lock);
325 *mf = fmt->format;
326 if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
327 tdm_rx->tdm_fmt = tdm_fmt;
328 mutex_unlock(&tdm_rx->subdev_lock);
329 }
330
331 return 0;
332 }
333
334
335 static const struct v4l2_subdev_video_ops sunxi_tdm_subdev_video_ops = {
336 .s_stream = sunxi_tdm_subdev_s_stream,
337 };
338
339 static const struct v4l2_subdev_pad_ops sunxi_tdm_subdev_pad_ops = {
340 .get_fmt = sunxi_tdm_subdev_get_fmt,
341 .set_fmt = sunxi_tdm_subdev_set_fmt,
342 };
343
344 static struct v4l2_subdev_ops sunxi_tdm_subdev_ops = {
345 .video = &sunxi_tdm_subdev_video_ops,
346 .pad = &sunxi_tdm_subdev_pad_ops,
347 };
348
__tdm_init_subdev(struct tdm_rx_dev * tdm_rx)349 static int __tdm_init_subdev(struct tdm_rx_dev *tdm_rx)
350 {
351 struct v4l2_subdev *sd = &tdm_rx->subdev;
352 int ret;
353
354 mutex_init(&tdm_rx->subdev_lock);
355 v4l2_subdev_init(sd, &sunxi_tdm_subdev_ops);
356 sd->grp_id = VIN_GRP_ID_TDM_RX;
357 sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
358 snprintf(sd->name, sizeof(sd->name), "sunxi_tdm_rx.%u", tdm_rx->id);
359 v4l2_set_subdevdata(sd, tdm_rx);
360
361 tdm_rx->tdm_pads[TDM_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
362 tdm_rx->tdm_pads[TDM_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
363 sd->entity.function = MEDIA_ENT_F_IO_V4L;
364
365 ret = media_entity_pads_init(&sd->entity, TDM_PAD_NUM, tdm_rx->tdm_pads);
366 if (ret < 0)
367 return ret;
368
369 return 0;
370 }
371
__sunxi_tdm_reset(struct tdm_dev * tdm)372 static void __sunxi_tdm_reset(struct tdm_dev *tdm)
373 {
374 struct tdm_rx_dev *tdm_rx;
375 struct vin_md *vind = dev_get_drvdata(tdm->tdm_rx[0].subdev.v4l2_dev->dev);
376 struct vin_core *vinc = NULL;
377 struct prs_cap_mode mode = {.mode = VCAP};
378 bool flags = 1;
379 int i, j, w;
380
381 vin_print("%s:tdm%d reset!!!\n", __func__, tdm->id);
382 /*****************stop*******************/
383 for (i = 0; i < VIN_MAX_DEV; i++) {
384 if (vind->vinc[i] == NULL)
385 continue;
386 if (!vin_streaming(&vind->vinc[i]->vid_cap))
387 continue;
388
389 for (j = 0; j < TDM_RX_NUM; j++) {
390 if (!tdm->tdm_rx[j].stream_cnt)
391 continue;
392 if (vind->vinc[i]->tdm_rx_sel == tdm->tdm_rx[j].id) {
393 vinc = vind->vinc[i];
394 tdm_rx = &tdm->tdm_rx[j];
395
396 vin_print("video%d reset, frame count is %d\n", vinc->id, vinc->vin_status.frame_cnt);
397
398 if (flags) {
399 csic_prs_capture_stop(vinc->csi_sel);
400
401 csic_tdm_int_clear_status(tdm->id, TDM_INT_ALL);
402 csic_tdm_rx_cap_disable(tdm->id, tdm_rx->id);
403 csic_tdm_rx_disable(tdm->id, tdm_rx->id);
404 csic_tdm_tx_cap_disable(tdm->id);
405 csic_tdm_disable(tdm->id);
406 csic_tdm_top_disable(tdm->id);
407
408 bsp_isp_clr_irq_status(vinc->isp_sel, ISP_IRQ_EN_ALL);
409 for (w = 0; w < VIN_MAX_ISP; w++)
410 bsp_isp_enable(w, 0);
411 bsp_isp_capture_stop(vinc->isp_sel);
412 }
413 vipp_disable(vinc->vipp_sel);
414 vipp_top_clk_en(vinc->vipp_sel, 0);
415 csic_dma_int_clear_status(vinc->vipp_sel, DMA_INT_ALL);
416 csic_dma_top_disable(vinc->vipp_sel);
417
418 if (flags) {
419 csic_prs_disable(vinc->csi_sel);
420 csic_isp_bridge_disable(0);
421 }
422 }
423 }
424 }
425
426 /*****************start*******************/
427 for (i = 0; i < VIN_MAX_DEV; i++) {
428 if (vind->vinc[i] == NULL)
429 continue;
430 if (!vin_streaming(&vind->vinc[i]->vid_cap))
431 continue;
432
433 for (j = 0; j < TDM_RX_NUM; j++) {
434 if (!tdm->tdm_rx[j].stream_cnt)
435 continue;
436 if (vind->vinc[i]->tdm_rx_sel == tdm->tdm_rx[j].id) {
437 vinc = vind->vinc[i];
438 tdm_rx = &tdm->tdm_rx[j];
439
440 csic_dma_top_enable(vinc->vipp_sel);
441 vipp_top_clk_en(vinc->vipp_sel, 1);
442 vipp_enable(vinc->vipp_sel);
443 vinc->vin_status.frame_cnt = 0;
444 vinc->vin_status.lost_cnt = 0;
445
446 if (flags) {
447 for (w = 0; w < VIN_MAX_ISP; w++)
448 bsp_isp_enable(w, 1);
449 bsp_isp_capture_start(vinc->isp_sel);
450
451 csic_isp_bridge_enable(0);
452
453 csic_tdm_top_enable(tdm->id);
454 csic_tdm_enable(tdm->id);
455 csic_tdm_tx_cap_enable(tdm->id);
456 csic_tdm_rx_enable(tdm->id, tdm_rx->id);
457 csic_tdm_rx_cap_enable(tdm->id, tdm_rx->id);
458
459 csic_prs_enable(vinc->csi_sel);
460 csic_prs_capture_start(vinc->csi_sel, 1, &mode);
461 }
462 }
463 }
464 }
465 }
466
tdm_isr(int irq,void * priv)467 static irqreturn_t tdm_isr(int irq, void *priv)
468 {
469 struct tdm_dev *tdm = (struct tdm_dev *)priv;
470 struct tdm_int_status status;
471 unsigned int hb_min = 0xffff, hb_max = 0;
472 unsigned int width = 0, height = 0;
473 unsigned long flags;
474
475 if (tdm->stream_cnt == 0) {
476 csic_tdm_int_clear_status(tdm->id, TDM_INT_ALL);
477 return IRQ_HANDLED;
478 }
479
480 csic_tdm_int_get_status(tdm->id, &status);
481
482 spin_lock_irqsave(&tdm->slock, flags);
483
484 if (status.rx_frm_lost) {
485 csic_tdm_int_clear_status(tdm->id, RX_FRM_LOST_INT_EN);
486 if (csic_tdm_internal_get_status0(tdm->id, RX0_FRM_LOST_PD)) {
487 vin_err("tdm%d rx0 frame lost!\n", tdm->id);
488 csic_tdm_internal_clear_status0(tdm->id, RX0_FRM_LOST_PD);
489 }
490 if (csic_tdm_internal_get_status0(tdm->id, RX1_FRM_LOST_PD)) {
491 vin_err("tdm%d rx1 frame lost!\n", tdm->id);
492 csic_tdm_internal_clear_status0(tdm->id, RX1_FRM_LOST_PD);
493 }
494 __sunxi_tdm_reset(tdm);
495 }
496
497 if (status.rx_frm_err) {
498 csic_tdm_int_clear_status(tdm->id, RX_FRM_ERR_INT_EN);
499 if (csic_tdm_internal_get_status0(tdm->id, RX0_FRM_ERR_PD)) {
500 csic_tdm_rx_get_size(tdm->id, 0, &width, &height);
501 vin_err("tdm%d rx0 frame error! width is %d, height is %d\n", tdm->id, width, height);
502 csic_tdm_internal_clear_status0(tdm->id, RX0_FRM_ERR_PD);
503 }
504 if (csic_tdm_internal_get_status0(tdm->id, RX1_FRM_ERR_PD)) {
505 csic_tdm_rx_get_size(tdm->id, 1, &width, &height);
506 vin_err("tdm%d rx1 frame error! width is %d, height is %d\n", tdm->id, width, height);
507 csic_tdm_internal_clear_status0(tdm->id, RX1_FRM_ERR_PD);
508 }
509 __sunxi_tdm_reset(tdm);
510 }
511
512 if (status.rx_btype_err) {
513 csic_tdm_int_clear_status(tdm->id, RX_BTYPE_ERR_INT_EN);
514 if (csic_tdm_internal_get_status0(tdm->id, RX0_BTYPE_ERR_PD)) {
515 vin_err("tdm%d rx0 btype error!\n", tdm->id);
516 csic_tdm_internal_clear_status0(tdm->id, RX0_BTYPE_ERR_PD);
517 }
518 if (csic_tdm_internal_get_status0(tdm->id, RX1_BTYPE_ERR_PD)) {
519 vin_err("tdm%d rx1 btype error!\n", tdm->id);
520 csic_tdm_internal_clear_status0(tdm->id, RX1_BTYPE_ERR_PD);
521 }
522 __sunxi_tdm_reset(tdm);
523 }
524
525 if (status.rx_buf_full) {
526 csic_tdm_int_clear_status(tdm->id, RX_BUF_FULL_INT_EN);
527 if (csic_tdm_internal_get_status0(tdm->id, RX0_BUF_FULL_PD)) {
528 vin_err("tdm%d rx0 buffer full!\n", tdm->id);
529 csic_tdm_internal_clear_status0(tdm->id, RX0_BUF_FULL_PD);
530 }
531 if (csic_tdm_internal_get_status0(tdm->id, RX1_BUF_FULL_PD)) {
532 vin_err("tdm%d rx1 buffer full!\n", tdm->id);
533 csic_tdm_internal_clear_status0(tdm->id, RX1_BUF_FULL_PD);
534 }
535 __sunxi_tdm_reset(tdm);
536 }
537
538 if (status.rx_comp_err) {
539 csic_tdm_int_clear_status(tdm->id, RX_COMP_ERR_INT_EN);
540 if (csic_tdm_internal_get_status1(tdm->id, RX0_COMP_ERR_PD)) {
541 vin_err("tdm%d rx0 compose error!\n", tdm->id);
542 csic_tdm_internal_clear_status1(tdm->id, RX0_COMP_ERR_PD);
543 }
544 if (csic_tdm_internal_get_status1(tdm->id, RX1_COMP_ERR_PD)) {
545 vin_err("tdm%d rx1 compose error!\n", tdm->id);
546 csic_tdm_internal_clear_status1(tdm->id, RX1_COMP_ERR_PD);
547 }
548 __sunxi_tdm_reset(tdm);
549 }
550
551 if (status.rx_hb_short) {
552 csic_tdm_int_clear_status(tdm->id, RX_HB_SHORT_INT_EN);
553 if (csic_tdm_internal_get_status1(tdm->id, RX0_HB_SHORT_PD)) {
554 csic_tdm_rx_get_hblank(tdm->id, 0, &hb_min, &hb_max);
555 vin_err("tdm%d rx0 hblank short! min is %d, max is %d\n", tdm->id, hb_min, hb_max);
556 csic_tdm_internal_clear_status1(tdm->id, RX0_HB_SHORT_PD);
557 }
558 if (csic_tdm_internal_get_status1(tdm->id, RX1_HB_SHORT_PD)) {
559 csic_tdm_rx_get_hblank(tdm->id, 1, &hb_min, &hb_max);
560 vin_err("tdm%d rx1 hblank short! min is %d, max is %d\n", tdm->id, hb_min, hb_max);
561 csic_tdm_internal_clear_status1(tdm->id, RX1_HB_SHORT_PD);
562 }
563 __sunxi_tdm_reset(tdm);
564 }
565
566 if (status.rx_fifo_full) {
567 csic_tdm_int_clear_status(tdm->id, RX_FIFO_FULL_INT_EN);
568 if (csic_tdm_internal_get_status1(tdm->id, RX0_FIFO_FULL_PD)) {
569 vin_err("tdm%d rx0 write DMA fifo overflow!\n", tdm->id);
570 csic_tdm_internal_clear_status1(tdm->id, RX0_FIFO_FULL_PD);
571 }
572 if (csic_tdm_internal_get_status1(tdm->id, RX1_FIFO_FULL_PD)) {
573 vin_err("tdm%d rx1 write DMA fifo overflow!\n", tdm->id);
574 csic_tdm_internal_clear_status1(tdm->id, RX1_FIFO_FULL_PD);
575 }
576 __sunxi_tdm_reset(tdm);
577 }
578
579 spin_unlock_irqrestore(&tdm->slock, flags);
580
581 return IRQ_HANDLED;
582 }
583
584
tdm_probe(struct platform_device * pdev)585 static int tdm_probe(struct platform_device *pdev)
586 {
587 struct device_node *np = pdev->dev.of_node;
588 struct tdm_dev *tdm = NULL;
589 unsigned int i;
590 int ret = 0;
591
592 if (np == NULL) {
593 vin_err("TDM failed to get of node\n");
594 return -ENODEV;
595 }
596
597 tdm = kzalloc(sizeof(struct tdm_dev), GFP_KERNEL);
598 if (!tdm) {
599 ret = -ENOMEM;
600 goto ekzalloc;
601 }
602 of_property_read_u32(np, "device_id", &pdev->id);
603 if (pdev->id < 0) {
604 vin_err("TDM failed to get device id\n");
605 ret = -EINVAL;
606 goto freedev;
607 }
608
609 tdm->id = pdev->id;
610 tdm->pdev = pdev;
611 tdm->stream_cnt = 0;
612
613 tdm->base = of_iomap(np, 0);
614 if (!tdm->base) {
615 tdm->is_empty = 1;
616 } else {
617 tdm->is_empty = 0;
618 /*get irq resource */
619 tdm->irq = irq_of_parse_and_map(np, 0);
620 if (tdm->irq <= 0) {
621 vin_err("failed to get TDM IRQ resource\n");
622 goto unmap;
623 }
624 ret = request_irq(tdm->irq, tdm_isr, IRQF_SHARED, tdm->pdev->name, tdm);
625 if (ret) {
626 vin_err("tdm%d request tdm failed\n", tdm->id);
627 goto unmap;
628 }
629 }
630
631 spin_lock_init(&tdm->slock);
632
633 csic_tdm_set_base_addr(tdm->id, (unsigned long)tdm->base);
634
635 for (i = 0; i < TDM_RX_NUM; i++) {
636 tdm->tdm_rx[i].id = i;
637 ret = __tdm_init_subdev(&tdm->tdm_rx[i]);
638 if (ret < 0) {
639 vin_err("tdm_rx%d init error!\n", i);
640 goto unmap;
641 }
642 tdm->tdm_rx[i].stream_cnt = 0;
643 tdm->tdm_rx_buf_en[i] = 0;
644 }
645
646 platform_set_drvdata(pdev, tdm);
647 glb_tdm[tdm->id] = tdm;
648
649 vin_log(VIN_LOG_TDM, "tdm%d probe end!\n", tdm->id);
650 return 0;
651
652 unmap:
653 iounmap(tdm->base);
654 freedev:
655 kfree(tdm);
656 ekzalloc:
657 vin_err("tdm probe err!\n");
658 return ret;
659 }
660
tdm_remove(struct platform_device * pdev)661 static int tdm_remove(struct platform_device *pdev)
662 {
663 struct tdm_dev *tdm = platform_get_drvdata(pdev);
664 struct v4l2_subdev *sd;
665 unsigned int i;
666
667 platform_set_drvdata(pdev, NULL);
668
669 if (!tdm->is_empty) {
670 free_irq(tdm->irq, tdm);
671 if (tdm->base)
672 iounmap(tdm->base);
673 }
674
675 for (i = 0; i < TDM_RX_NUM; i++) {
676 sd = &tdm->tdm_rx[i].subdev;
677 v4l2_set_subdevdata(sd, NULL);
678 media_entity_cleanup(&tdm->tdm_rx[i].subdev.entity);
679 }
680
681 kfree(tdm);
682 return 0;
683 }
684
685 static const struct of_device_id sunxi_tdm_match[] = {
686 {.compatible = "allwinner,sunxi-tdm",},
687 {},
688 };
689
690 static struct platform_driver tdm_platform_driver = {
691 .probe = tdm_probe,
692 .remove = tdm_remove,
693 .driver = {
694 .name = TDM_MODULE_NAME,
695 .owner = THIS_MODULE,
696 .of_match_table = sunxi_tdm_match,
697 }
698 };
699
sunxi_tdm_get_subdev(int id,int tdm_rx_num)700 struct v4l2_subdev *sunxi_tdm_get_subdev(int id, int tdm_rx_num)
701 {
702 if (id < VIN_MAX_TDM && glb_tdm[id])
703 return &glb_tdm[id]->tdm_rx[tdm_rx_num].subdev;
704 else
705 return NULL;
706 }
707
sunxi_tdm_platform_register(void)708 int sunxi_tdm_platform_register(void)
709 {
710 return platform_driver_register(&tdm_platform_driver);
711 }
712
sunxi_tdm_platform_unregister(void)713 void sunxi_tdm_platform_unregister(void)
714 {
715 platform_driver_unregister(&tdm_platform_driver);
716 vin_log(VIN_LOG_TDM, "tdm_exit end\n");
717 }
718
719