2 * Tegra Video Input 2 device common APIs
4 * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
6 * Author: Bryan Wu <pengw@nvidia.com>
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.
13 #include <linux/device.h>
14 #include <linux/nvhost.h>
15 #include <linux/tegra-powergate.h>
17 #include "camera/mc_common.h"
19 /* VI2 register accessors */
20 void vi2_write(struct tegra_mc_vi *vi, unsigned int addr, u32 val)
22 writel(val, vi->iomem + addr);
25 u32 vi2_channel_read(struct tegra_channel *chan,
28 return readl(chan->vi->iomem + addr);
31 void vi2_channel_write(struct tegra_channel *chan,
32 unsigned int addr, u32 val)
34 writel(val, chan->vi->iomem + addr);
37 static void vi2_channel_csi_write(struct tegra_channel *chan,
38 unsigned int index, unsigned int addr,
41 writel(val, chan->csibase[index] + addr);
44 static u32 vi2_channel_csi_read(struct tegra_channel *chan, unsigned int index,
47 return readl(chan->csibase[index] + addr);
50 /* VI2 Media-Controller releated fops */
51 int vi2_power_on(struct tegra_mc_vi *vi)
55 vi2_write(vi, TEGRA_VI_CFG_CG_CTRL, 1);
58 ret = tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
60 dev_err(vi->dev, "failed to unpower gate VI\n");
65 void vi2_power_off(struct tegra_mc_vi *vi)
67 tegra_powergate_partition(TEGRA_POWERGATE_VENC);
70 /* VI2 channel operation related fops */
71 void vi2_channel_ec_init(struct tegra_channel *chan)
74 * Sync point FIFO full blocks host interface
75 * Below setting enables SW to process error recovery
77 vi2_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT_CNTRL, 0x100);
80 int vi2_channel_capture_setup(struct tegra_channel *chan)
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;
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);
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;
101 for (index = 0; index < chan->valid_ports; index++) {
102 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_ERROR_STATUS,
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,
109 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_IMAGE_SIZE_WC,
111 vi2_channel_csi_write(chan, index, TEGRA_VI_CSI_IMAGE_SIZE,
112 (height << IMAGE_SIZE_HEIGHT_OFFSET) | width);
118 void vi2_channel_capture_frame_init(struct tegra_channel *chan,
119 struct tegra_channel_buffer *buf,
123 int valid_ports = chan->valid_ports;
124 int bytes_per_line = chan->format.bytesperline;
125 u32 val, frame_start;
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);
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) |
145 vi2_channel_write(chan,
146 TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
148 chan->syncpoint_fifo[index]--;
152 void vi2_channel_capture_frame_enable(struct tegra_channel *chan)
156 int valid_ports = chan->valid_ports;
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);
168 int vi2_channel_capture_frame(struct tegra_channel *chan,
169 struct timespec *ts, u32 *thresh)
173 int valid_ports = chan->valid_ports;
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);
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);
187 dev_err(&chan->video.dev,
188 "frame start syncpt timeout!%d\n", index);
189 chan->capture_state = CAPTURE_TIMEOUT;
197 int vi2_channel_error_status(struct tegra_channel *chan)
203 for (index = 0; index < chan->valid_ports; index++) {
204 /* Ignore error based on resolution but reset status */
205 val = vi2_channel_csi_read(chan, index,
206 TEGRA_VI_CSI_ERROR_STATUS);
207 vi2_channel_csi_write(chan, index,
208 TEGRA_VI_CSI_ERROR_STATUS, val);
209 err = tegra_csi_error(chan->vi->csi, chan->port[index]);
213 dev_err(chan->vi->dev, "%s:error %x frame %d\n",
214 __func__, err, chan->sequence);
218 int vi2_channel_capture_done(struct tegra_channel *chan,
219 struct tegra_channel_buffer *buf,
223 int bytes_per_line = chan->format.bytesperline;
224 u32 val, mw_ack_done;
225 u32 thresh[TEGRA_CSI_BLOCKS] = { 0 };
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);
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) |
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);
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);
254 dev_err(&chan->video.dev,
255 "MW_ACK_DONE syncpoint time out!%d\n", index);
263 void vi2_channel_ec_recover(struct tegra_channel *chan)
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;
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]);
279 /* Disable clock gating to enable continuous clock */
280 vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, DISABLE);
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);
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;
301 /* Clear FIFO error status */
302 vi2_channel_write(chan,
303 TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR, error_val);
305 /* Enable clock gating so VI can be clock gated if necessary */
306 vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, ENABLE);
309 void vi2_channel_stop_streaming(struct tegra_channel *chan)
313 /* Disable clock gating to enable continuous clock */
314 vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, DISABLE);
316 for (index = 0; index < chan->valid_ports; index++) {
317 tegra_csi_stop_streaming(chan->vi->csi,
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);
329 /* Enable clock gating so VI can be clock gated if necessary */
330 vi2_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, ENABLE);