]> rtime.felk.cvut.cz Git - sojka/nv-tegra/linux-3.10.git/blob - drivers/media/platform/tegra/camera/vi2_fops.c
1333de333db1a3e28976b133c6ddfd0c33925228
[sojka/nv-tegra/linux-3.10.git] / drivers / media / platform / tegra / camera / vi2_fops.c
1 /*
2  * Tegra Video Input 2 device common APIs
3  *
4  * Copyright (c) 2016, NVIDIA CORPORATION.  All rights reserved.
5  *
6  * Author: Bryan Wu <pengw@nvidia.com>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/device.h>
14 #include <linux/nvhost.h>
15 #include <linux/tegra-powergate.h>
16
17 #include "camera/mc_common.h"
18
19 /* VI2 register accessors */
20 void vi2_write(struct tegra_mc_vi *vi, unsigned int addr, u32 val)
21 {
22         writel(val, vi->iomem + addr);
23 }
24
25 u32 vi2_channel_read(struct tegra_channel *chan,
26                         unsigned int addr)
27 {
28         return readl(chan->vi->iomem + addr);
29 }
30
31 void vi2_channel_write(struct tegra_channel *chan,
32                         unsigned int addr, u32 val)
33 {
34         writel(val, chan->vi->iomem + addr);
35 }
36
37 static void vi2_channel_csi_write(struct tegra_channel *chan,
38                                    unsigned int index, unsigned int addr,
39                                    u32 val)
40 {
41         writel(val, chan->csibase[index] + addr);
42 }
43
44 static u32 vi2_channel_csi_read(struct tegra_channel *chan, unsigned int index,
45                                         unsigned int addr)
46 {
47         return readl(chan->csibase[index] + addr);
48 }
49
50 /* VI2 Media-Controller releated fops */
51 int vi2_power_on(struct tegra_mc_vi *vi)
52 {
53         int ret;
54
55         vi2_write(vi, TEGRA_VI_CFG_CG_CTRL, 1);
56
57         /* unpowergate VE */
58         ret = tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
59         if (ret)
60                 dev_err(vi->dev, "failed to unpower gate VI\n");
61
62         return ret;
63 }
64
65 void vi2_power_off(struct tegra_mc_vi *vi)
66 {
67         tegra_powergate_partition(TEGRA_POWERGATE_VENC);
68 }
69
70 /* VI2 channel operation related fops */
71 void vi2_channel_ec_init(struct tegra_channel *chan)
72 {
73         /*
74          * Sync point FIFO full blocks host interface
75          * Below setting enables SW to process error recovery
76          */
77         vi2_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_CNTRL, 0x100);
78 }
79
80 int vi2_channel_capture_setup(struct tegra_channel *chan)
81 {
82         u32 height = chan->format.height;
83         u32 width = chan->format.width;
84         u32 format = chan->fmtinfo->img_fmt;
85         u32 data_type = chan->fmtinfo->img_dt;
86         u32 word_count = tegra_core_get_word_count(width, chan->fmtinfo);
87         u32 bypass_pixel_transform = 1;
88         int index;
89
90         if (chan->valid_ports > 1) {
91                 height = chan->gang_height;
92                 width = chan->gang_width;
93                 word_count = tegra_core_get_word_count(width, chan->fmtinfo);
94         }
95
96         if (chan->vi->pg_mode ||
97            (chan->fmtinfo->vf_code == TEGRA_VF_YUV422) ||
98            (chan->fmtinfo->vf_code == TEGRA_VF_RGB888))
99                 bypass_pixel_transform = 0;
100
101         for (index = 0; index < chan->valid_ports; index++) {
102                 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_ERROR_STATUS,
103                                        0xFFFFFFFF);
104                 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_IMAGE_DEF,
105                   (bypass_pixel_transform << BYPASS_PXL_TRANSFORM_OFFSET) |
106                   (format << IMAGE_DEF_FORMAT_OFFSET));
107                 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_IMAGE_DT,
108                                        data_type);
109                 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_IMAGE_SIZE_WC,
110                                        word_count);
111                 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_IMAGE_SIZE,
112                           (height << IMAGE_SIZE_HEIGHT_OFFSET) | width);
113         }
114
115         return 0;
116 }
117
118 void vi2_channel_capture_frame_init(struct tegra_channel *chan,
119                                      struct tegra_channel_buffer *buf,
120                                      u32 *thresh)
121 {
122         int index = 0;
123         int valid_ports = chan->valid_ports;
124         int bytes_per_line = chan->format.bytesperline;
125         u32 val, frame_start;
126
127         for (index = 0; index < valid_ports; index++) {
128                 /* Program buffer address by using surface 0 */
129                 vi2_channel_csi_write(chan, index,
130                                 TEGRA_VI_CSI_SURFACE0_OFFSET_MSB, 0x0);
131                 vi2_channel_csi_write(chan, index,
132                         TEGRA_VI_CSI_SURFACE0_OFFSET_LSB,
133                         (buf->addr + chan->buffer_offset[index]));
134                 vi2_channel_csi_write(chan, index,
135                         TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line);
136
137                 /* Program syncpoints */
138                 thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev,
139                                         chan->syncpt[index], 1);
140                 /* Do not arm sync points if FIFO had entries before */
141                 if (!chan->syncpoint_fifo[index]) {
142                         frame_start = VI_CSI_PP_FRAME_START(chan->port[index]);
143                         val = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) |
144                                 chan->syncpt[index];
145                         vi2_channel_write(chan,
146                                 TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
147                 } else
148                         chan->syncpoint_fifo[index]--;
149         }
150 }
151
152 void vi2_channel_capture_frame_enable(struct tegra_channel *chan)
153 {
154         int index;
155         u32 val;
156         int valid_ports = chan->valid_ports;
157
158         /* Bit controls VI memory write, enable after all regs */
159         for (index = 0; index < valid_ports; index++) {
160                 val = vi2_channel_csi_read(chan, index,
161                                 TEGRA_VI_CSI_IMAGE_DEF);
162                 vi2_channel_csi_write(chan, index,
163                                 TEGRA_VI_CSI_IMAGE_DEF,
164                                 val | IMAGE_DEF_DEST_MEM);
165         }
166 }
167
168 int vi2_channel_capture_frame(struct tegra_channel *chan,
169                                struct timespec *ts, u32 *thresh)
170 {
171
172         int index = 0;
173         int valid_ports = chan->valid_ports;
174         int err = 0;
175
176         /* Ensure all CSI ports are ready with setup to avoid timing issue */
177         for (index = 0; index < valid_ports; index++)
178                 vi2_channel_csi_write(chan, index,
179                         TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);
180
181         chan->capture_state = CAPTURE_GOOD;
182         for (index = 0; index < valid_ports; index++) {
183                 err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev,
184                         chan->syncpt[index], thresh[index],
185                         chan->timeout, NULL, ts);
186                 if (err) {
187                         dev_err(&chan->video.dev,
188                                 "frame start syncpt timeout!%d\n", index);
189                         chan->capture_state = CAPTURE_TIMEOUT;
190                         return err;
191                 }
192         }
193
194         return err;
195 }
196
197 int vi2_channel_error_status(struct tegra_channel *chan)
198 {
199         u32 val;
200         int err = 0;
201         int index = 0;
202
203         for (index = 0; index < chan->valid_ports; index++) {
204                 val = vi2_channel_csi_read(chan, index,
205                                 TEGRA_VI_CSI_ERROR_STATUS);
206                 vi2_channel_csi_write(chan, index,
207                                 TEGRA_VI_CSI_ERROR_STATUS, val);
208                 err |= val;
209                 err |= tegra_csi_error(chan->vi->csi, chan->port[index]);
210         }
211
212         if (err)
213                 dev_err(chan->vi->dev, "%s:error %x frame %d\n",
214                                 __func__, err, chan->sequence);
215         return err;
216 }
217
218 int vi2_channel_capture_done(struct tegra_channel *chan,
219                               struct tegra_channel_buffer *buf,
220                               struct timespec *ts)
221 {
222         int index, err;
223         int bytes_per_line = chan->format.bytesperline;
224         u32 val, mw_ack_done;
225         u32 thresh[TEGRA_CSI_BLOCKS] = { 0 };
226
227         for (index = 0; index < chan->valid_ports; index++) {
228                 /* Program buffer address by using surface 0 */
229                 vi2_channel_csi_write(chan, index,
230                                 TEGRA_VI_CSI_SURFACE0_OFFSET_MSB, 0x0);
231                 vi2_channel_csi_write(chan, index,
232                         TEGRA_VI_CSI_SURFACE0_OFFSET_LSB,
233                         (buf->addr + chan->buffer_offset[index]));
234                 vi2_channel_csi_write(chan, index,
235                         TEGRA_VI_CSI_SURFACE0_STRIDE, bytes_per_line);
236
237                 /* Program syncpoints */
238                 thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev,
239                                         chan->syncpt[index], 1);
240                 mw_ack_done = VI_CSI_MW_ACK_DONE(chan->port[index]);
241                 val = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
242                                 chan->syncpt[index];
243                 vi2_channel_write(chan,
244                                 TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
245                 vi2_channel_csi_write(chan, index,
246                         TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);
247         }
248
249         for (index = 0; index < chan->valid_ports; index++) {
250                 err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev,
251                         chan->syncpt[index], thresh[index],
252                         chan->timeout, NULL, ts);
253                 if (err) {
254                         dev_err(&chan->video.dev,
255                                 "MW_ACK_DONE syncpoint time out!%d\n", index);
256                         return err;
257                 }
258         }
259
260         return 0;
261 }
262
263 void vi2_channel_ec_recover(struct tegra_channel *chan)
264 {
265         u32 error_val = vi2_channel_read(chan,
266                                 TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR);
267         int index, valid_ports = chan->valid_ports;
268         u32 frame_start, val;
269
270         /* Get error status for debugging */
271         for (index = 0; index < valid_ports; index++) {
272                 val = vi2_channel_csi_read(chan, index,
273                                 TEGRA_VI_CSI_ERROR_STATUS);
274                 dev_dbg(&chan->video.dev,
275                         "TEGRA_VI_CSI_ERROR_STATUS 0x%08x\n", val);
276                 tegra_csi_status(chan->vi->csi, chan->port[index]);
277         }
278
279         /* Disable clock gating to enable continuous clock */
280         vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, DISABLE);
281
282         /* Clear CSI state */
283         for (index = 0; index < valid_ports; index++) {
284                 tegra_csi_error_recover(chan->vi->csi, chan->port[index]);
285                 vi2_channel_csi_write(chan, index,
286                                 TEGRA_VI_CSI_IMAGE_DEF, 0);
287                 /* Clear single shot */
288                 vi2_channel_csi_write(chan, index,
289                                 TEGRA_VI_CSI_SW_RESET, 0xF);
290                 vi2_channel_csi_write(chan, index,
291                                 TEGRA_VI_CSI_SW_RESET, 0x0);
292         }
293
294         /* Clear VI errors */
295         for (index = 0; index < valid_ports; index++) {
296                 frame_start = VI_CSI_PP_FRAME_START(chan->port[index]);
297                 if (error_val & frame_start)
298                         chan->syncpoint_fifo[index] = SYNCPT_FIFO_DEPTH;
299         }
300
301         /* Clear FIFO error status */
302         vi2_channel_write(chan,
303                 TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR, error_val);
304
305         /* Enable clock gating so VI can be clock gated if necessary */
306         vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, ENABLE);
307 }
308
309 void vi2_channel_stop_streaming(struct tegra_channel *chan)
310 {
311         int index;
312
313         /* Disable clock gating to enable continuous clock */
314         vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, DISABLE);
315
316         for (index = 0; index < chan->valid_ports; index++) {
317                 tegra_csi_stop_streaming(chan->vi->csi,
318                                 chan->port[index]);
319                 /* Always clear single shot if armed at close */
320                 if (vi2_channel_csi_read(chan, index,
321                                         TEGRA_VI_CSI_SINGLE_SHOT)) {
322                         vi2_channel_csi_write(chan, index,
323                                         TEGRA_VI_CSI_SW_RESET, 0xF);
324                         vi2_channel_csi_write(chan, index,
325                                         TEGRA_VI_CSI_SW_RESET, 0x0);
326                 }
327         }
328
329         /* Enable clock gating so VI can be clock gated if necessary */
330         vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, ENABLE);
331 }