1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2011-2018 Magewell Electronics Co., Ltd. (Nanjing)
4  * All rights reserved.
5  * Author: Yong Deng <yong.deng@magewell.com>
6  */
7 
8 #include <linux/clk.h>
9 #include <linux/delay.h>
10 #include <linux/dma-mapping.h>
11 #include <linux/err.h>
12 #include <linux/fs.h>
13 #include <linux/interrupt.h>
14 #include <linux/io.h>
15 #include <linux/ioctl.h>
16 #include <linux/module.h>
17 #include <linux/of.h>
18 #include <linux/platform_device.h>
19 #include <linux/pm_runtime.h>
20 #include <linux/regmap.h>
21 #include <linux/reset.h>
22 #include <linux/sched.h>
23 #include <linux/sizes.h>
24 #include <linux/slab.h>
25 
26 #include "sun6i_csi.h"
27 #include "sun6i_csi_reg.h"
28 
29 #define MODULE_NAME	"sun6i-csi"
30 
31 struct sun6i_csi_dev {
32 	struct sun6i_csi		csi;
33 	struct device			*dev;
34 
35 	struct regmap			*regmap;
36 	struct clk			*clk_mod;
37 	struct clk			*clk_ram;
38 	struct reset_control		*rstc_bus;
39 
40 	int				planar_offset[3];
41 };
42 
43 static inline struct sun6i_csi_dev *sun6i_csi_to_dev(struct sun6i_csi *csi)
44 {
45 	return container_of(csi, struct sun6i_csi_dev, csi);
46 }
47 
48 /* TODO add 10&12 bit YUV, RGB support */
49 bool sun6i_csi_is_format_supported(struct sun6i_csi *csi,
50 				   u32 pixformat, u32 mbus_code)
51 {
52 	struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
53 
54 	/*
55 	 * Some video receivers have the ability to be compatible with
56 	 * 8bit and 16bit bus width.
57 	 * Identify the media bus format from device tree.
58 	 */
59 	if ((sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_PARALLEL
60 	     || sdev->csi.v4l2_ep.bus_type == V4L2_MBUS_BT656)
61 	     && sdev->csi.v4l2_ep.bus.parallel.bus_width == 16) {
62 		switch (pixformat) {
63 		case V4L2_PIX_FMT_HM12:
64 		case V4L2_PIX_FMT_NV12:
65 		case V4L2_PIX_FMT_NV21:
66 		case V4L2_PIX_FMT_NV16:
67 		case V4L2_PIX_FMT_NV61:
68 		case V4L2_PIX_FMT_YUV420:
69 		case V4L2_PIX_FMT_YVU420:
70 		case V4L2_PIX_FMT_YUV422P:
71 			switch (mbus_code) {
72 			case MEDIA_BUS_FMT_UYVY8_1X16:
73 			case MEDIA_BUS_FMT_VYUY8_1X16:
74 			case MEDIA_BUS_FMT_YUYV8_1X16:
75 			case MEDIA_BUS_FMT_YVYU8_1X16:
76 				return true;
77 			default:
78 				dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
79 					mbus_code);
80 				break;
81 			}
82 			break;
83 		default:
84 			dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n",
85 				pixformat);
86 			break;
87 		}
88 		return false;
89 	}
90 
91 	switch (pixformat) {
92 	case V4L2_PIX_FMT_SBGGR8:
93 		return (mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8);
94 	case V4L2_PIX_FMT_SGBRG8:
95 		return (mbus_code == MEDIA_BUS_FMT_SGBRG8_1X8);
96 	case V4L2_PIX_FMT_SGRBG8:
97 		return (mbus_code == MEDIA_BUS_FMT_SGRBG8_1X8);
98 	case V4L2_PIX_FMT_SRGGB8:
99 		return (mbus_code == MEDIA_BUS_FMT_SRGGB8_1X8);
100 	case V4L2_PIX_FMT_SBGGR10:
101 		return (mbus_code == MEDIA_BUS_FMT_SBGGR10_1X10);
102 	case V4L2_PIX_FMT_SGBRG10:
103 		return (mbus_code == MEDIA_BUS_FMT_SGBRG10_1X10);
104 	case V4L2_PIX_FMT_SGRBG10:
105 		return (mbus_code == MEDIA_BUS_FMT_SGRBG10_1X10);
106 	case V4L2_PIX_FMT_SRGGB10:
107 		return (mbus_code == MEDIA_BUS_FMT_SRGGB10_1X10);
108 	case V4L2_PIX_FMT_SBGGR12:
109 		return (mbus_code == MEDIA_BUS_FMT_SBGGR12_1X12);
110 	case V4L2_PIX_FMT_SGBRG12:
111 		return (mbus_code == MEDIA_BUS_FMT_SGBRG12_1X12);
112 	case V4L2_PIX_FMT_SGRBG12:
113 		return (mbus_code == MEDIA_BUS_FMT_SGRBG12_1X12);
114 	case V4L2_PIX_FMT_SRGGB12:
115 		return (mbus_code == MEDIA_BUS_FMT_SRGGB12_1X12);
116 
117 	case V4L2_PIX_FMT_YUYV:
118 		return (mbus_code == MEDIA_BUS_FMT_YUYV8_2X8);
119 	case V4L2_PIX_FMT_YVYU:
120 		return (mbus_code == MEDIA_BUS_FMT_YVYU8_2X8);
121 	case V4L2_PIX_FMT_UYVY:
122 		return (mbus_code == MEDIA_BUS_FMT_UYVY8_2X8);
123 	case V4L2_PIX_FMT_VYUY:
124 		return (mbus_code == MEDIA_BUS_FMT_VYUY8_2X8);
125 
126 	case V4L2_PIX_FMT_HM12:
127 	case V4L2_PIX_FMT_NV12:
128 	case V4L2_PIX_FMT_NV21:
129 	case V4L2_PIX_FMT_NV16:
130 	case V4L2_PIX_FMT_NV61:
131 	case V4L2_PIX_FMT_YUV420:
132 	case V4L2_PIX_FMT_YVU420:
133 	case V4L2_PIX_FMT_YUV422P:
134 		switch (mbus_code) {
135 		case MEDIA_BUS_FMT_UYVY8_2X8:
136 		case MEDIA_BUS_FMT_VYUY8_2X8:
137 		case MEDIA_BUS_FMT_YUYV8_2X8:
138 		case MEDIA_BUS_FMT_YVYU8_2X8:
139 			return true;
140 		default:
141 			dev_dbg(sdev->dev, "Unsupported mbus code: 0x%x\n",
142 				mbus_code);
143 			break;
144 		}
145 		break;
146 	default:
147 		dev_dbg(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
148 		break;
149 	}
150 
151 	return false;
152 }
153 
154 int sun6i_csi_set_power(struct sun6i_csi *csi, bool enable)
155 {
156 	struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
157 	struct regmap *regmap = sdev->regmap;
158 	int ret;
159 
160 	if (!enable) {
161 		regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
162 
163 		clk_disable_unprepare(sdev->clk_ram);
164 		clk_disable_unprepare(sdev->clk_mod);
165 		reset_control_assert(sdev->rstc_bus);
166 		return 0;
167 	}
168 
169 	ret = clk_prepare_enable(sdev->clk_mod);
170 	if (ret) {
171 		dev_err(sdev->dev, "Enable csi clk err %d\n", ret);
172 		return ret;
173 	}
174 
175 	ret = clk_prepare_enable(sdev->clk_ram);
176 	if (ret) {
177 		dev_err(sdev->dev, "Enable clk_dram_csi clk err %d\n", ret);
178 		goto clk_mod_disable;
179 	}
180 
181 	ret = reset_control_deassert(sdev->rstc_bus);
182 	if (ret) {
183 		dev_err(sdev->dev, "reset err %d\n", ret);
184 		goto clk_ram_disable;
185 	}
186 
187 	regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, CSI_EN_CSI_EN);
188 
189 	return 0;
190 
191 clk_ram_disable:
192 	clk_disable_unprepare(sdev->clk_ram);
193 clk_mod_disable:
194 	clk_disable_unprepare(sdev->clk_mod);
195 	return ret;
196 }
197 
198 static enum csi_input_fmt get_csi_input_format(struct sun6i_csi_dev *sdev,
199 					       u32 mbus_code, u32 pixformat)
200 {
201 	/* bayer */
202 	if ((mbus_code & 0xF000) == 0x3000)
203 		return CSI_INPUT_FORMAT_RAW;
204 
205 	switch (pixformat) {
206 	case V4L2_PIX_FMT_YUYV:
207 	case V4L2_PIX_FMT_YVYU:
208 	case V4L2_PIX_FMT_UYVY:
209 	case V4L2_PIX_FMT_VYUY:
210 		return CSI_INPUT_FORMAT_RAW;
211 	default:
212 		break;
213 	}
214 
215 	/* not support YUV420 input format yet */
216 	dev_dbg(sdev->dev, "Select YUV422 as default input format of CSI.\n");
217 	return CSI_INPUT_FORMAT_YUV422;
218 }
219 
220 static enum csi_output_fmt get_csi_output_format(struct sun6i_csi_dev *sdev,
221 						 u32 pixformat, u32 field)
222 {
223 	bool buf_interlaced = false;
224 
225 	if (field == V4L2_FIELD_INTERLACED
226 	    || field == V4L2_FIELD_INTERLACED_TB
227 	    || field == V4L2_FIELD_INTERLACED_BT)
228 		buf_interlaced = true;
229 
230 	switch (pixformat) {
231 	case V4L2_PIX_FMT_SBGGR8:
232 	case V4L2_PIX_FMT_SGBRG8:
233 	case V4L2_PIX_FMT_SGRBG8:
234 	case V4L2_PIX_FMT_SRGGB8:
235 		return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
236 	case V4L2_PIX_FMT_SBGGR10:
237 	case V4L2_PIX_FMT_SGBRG10:
238 	case V4L2_PIX_FMT_SGRBG10:
239 	case V4L2_PIX_FMT_SRGGB10:
240 		return buf_interlaced ? CSI_FRAME_RAW_10 : CSI_FIELD_RAW_10;
241 	case V4L2_PIX_FMT_SBGGR12:
242 	case V4L2_PIX_FMT_SGBRG12:
243 	case V4L2_PIX_FMT_SGRBG12:
244 	case V4L2_PIX_FMT_SRGGB12:
245 		return buf_interlaced ? CSI_FRAME_RAW_12 : CSI_FIELD_RAW_12;
246 
247 	case V4L2_PIX_FMT_YUYV:
248 	case V4L2_PIX_FMT_YVYU:
249 	case V4L2_PIX_FMT_UYVY:
250 	case V4L2_PIX_FMT_VYUY:
251 		return buf_interlaced ? CSI_FRAME_RAW_8 : CSI_FIELD_RAW_8;
252 
253 	case V4L2_PIX_FMT_HM12:
254 		return buf_interlaced ? CSI_FRAME_MB_YUV420 :
255 					CSI_FIELD_MB_YUV420;
256 	case V4L2_PIX_FMT_NV12:
257 	case V4L2_PIX_FMT_NV21:
258 		return buf_interlaced ? CSI_FRAME_UV_CB_YUV420 :
259 					CSI_FIELD_UV_CB_YUV420;
260 	case V4L2_PIX_FMT_YUV420:
261 	case V4L2_PIX_FMT_YVU420:
262 		return buf_interlaced ? CSI_FRAME_PLANAR_YUV420 :
263 					CSI_FIELD_PLANAR_YUV420;
264 	case V4L2_PIX_FMT_NV16:
265 	case V4L2_PIX_FMT_NV61:
266 		return buf_interlaced ? CSI_FRAME_UV_CB_YUV422 :
267 					CSI_FIELD_UV_CB_YUV422;
268 	case V4L2_PIX_FMT_YUV422P:
269 		return buf_interlaced ? CSI_FRAME_PLANAR_YUV422 :
270 					CSI_FIELD_PLANAR_YUV422;
271 	default:
272 		dev_warn(sdev->dev, "Unsupported pixformat: 0x%x\n", pixformat);
273 		break;
274 	}
275 
276 	return CSI_FIELD_RAW_8;
277 }
278 
279 static enum csi_input_seq get_csi_input_seq(struct sun6i_csi_dev *sdev,
280 					    u32 mbus_code, u32 pixformat)
281 {
282 	switch (pixformat) {
283 	case V4L2_PIX_FMT_HM12:
284 	case V4L2_PIX_FMT_NV12:
285 	case V4L2_PIX_FMT_NV16:
286 	case V4L2_PIX_FMT_YUV420:
287 	case V4L2_PIX_FMT_YUV422P:
288 		switch (mbus_code) {
289 		case MEDIA_BUS_FMT_UYVY8_2X8:
290 		case MEDIA_BUS_FMT_UYVY8_1X16:
291 			return CSI_INPUT_SEQ_UYVY;
292 		case MEDIA_BUS_FMT_VYUY8_2X8:
293 		case MEDIA_BUS_FMT_VYUY8_1X16:
294 			return CSI_INPUT_SEQ_VYUY;
295 		case MEDIA_BUS_FMT_YUYV8_2X8:
296 		case MEDIA_BUS_FMT_YUYV8_1X16:
297 			return CSI_INPUT_SEQ_YUYV;
298 		case MEDIA_BUS_FMT_YVYU8_1X16:
299 		case MEDIA_BUS_FMT_YVYU8_2X8:
300 			return CSI_INPUT_SEQ_YVYU;
301 		default:
302 			dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
303 				 mbus_code);
304 			break;
305 		}
306 		break;
307 	case V4L2_PIX_FMT_NV21:
308 	case V4L2_PIX_FMT_NV61:
309 	case V4L2_PIX_FMT_YVU420:
310 		switch (mbus_code) {
311 		case MEDIA_BUS_FMT_UYVY8_2X8:
312 		case MEDIA_BUS_FMT_UYVY8_1X16:
313 			return CSI_INPUT_SEQ_VYUY;
314 		case MEDIA_BUS_FMT_VYUY8_2X8:
315 		case MEDIA_BUS_FMT_VYUY8_1X16:
316 			return CSI_INPUT_SEQ_UYVY;
317 		case MEDIA_BUS_FMT_YUYV8_2X8:
318 		case MEDIA_BUS_FMT_YUYV8_1X16:
319 			return CSI_INPUT_SEQ_YVYU;
320 		case MEDIA_BUS_FMT_YVYU8_1X16:
321 		case MEDIA_BUS_FMT_YVYU8_2X8:
322 			return CSI_INPUT_SEQ_YUYV;
323 		default:
324 			dev_warn(sdev->dev, "Unsupported mbus code: 0x%x\n",
325 				 mbus_code);
326 			break;
327 		}
328 		break;
329 
330 	case V4L2_PIX_FMT_YUYV:
331 		return CSI_INPUT_SEQ_YUYV;
332 
333 	default:
334 		dev_warn(sdev->dev, "Unsupported pixformat: 0x%x, defaulting to YUYV\n",
335 			 pixformat);
336 		break;
337 	}
338 
339 	return CSI_INPUT_SEQ_YUYV;
340 }
341 
342 static void sun6i_csi_setup_bus(struct sun6i_csi_dev *sdev)
343 {
344 	struct v4l2_fwnode_endpoint *endpoint = &sdev->csi.v4l2_ep;
345 	struct sun6i_csi *csi = &sdev->csi;
346 	unsigned char bus_width;
347 	u32 flags;
348 	u32 cfg;
349 	bool input_interlaced = false;
350 
351 	if (csi->config.field == V4L2_FIELD_INTERLACED
352 	    || csi->config.field == V4L2_FIELD_INTERLACED_TB
353 	    || csi->config.field == V4L2_FIELD_INTERLACED_BT)
354 		input_interlaced = true;
355 
356 	bus_width = endpoint->bus.parallel.bus_width;
357 
358 	regmap_read(sdev->regmap, CSI_IF_CFG_REG, &cfg);
359 
360 	cfg &= ~(CSI_IF_CFG_CSI_IF_MASK | CSI_IF_CFG_MIPI_IF_MASK |
361 		 CSI_IF_CFG_IF_DATA_WIDTH_MASK |
362 		 CSI_IF_CFG_CLK_POL_MASK | CSI_IF_CFG_VREF_POL_MASK |
363 		 CSI_IF_CFG_HREF_POL_MASK | CSI_IF_CFG_FIELD_MASK |
364 		 CSI_IF_CFG_SRC_TYPE_MASK);
365 
366 	if (input_interlaced)
367 		cfg |= CSI_IF_CFG_SRC_TYPE_INTERLACED;
368 	else
369 		cfg |= CSI_IF_CFG_SRC_TYPE_PROGRESSED;
370 
371 	switch (endpoint->bus_type) {
372 	case V4L2_MBUS_PARALLEL:
373 		cfg |= CSI_IF_CFG_MIPI_IF_CSI;
374 
375 		flags = endpoint->bus.parallel.flags;
376 
377 		cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_YUV422_16BIT :
378 					   CSI_IF_CFG_CSI_IF_YUV422_INTLV;
379 
380 		if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
381 			cfg |= CSI_IF_CFG_FIELD_POSITIVE;
382 
383 		if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
384 			cfg |= CSI_IF_CFG_VREF_POL_POSITIVE;
385 		if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
386 			cfg |= CSI_IF_CFG_HREF_POL_POSITIVE;
387 
388 		if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
389 			cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
390 		break;
391 	case V4L2_MBUS_BT656:
392 		cfg |= CSI_IF_CFG_MIPI_IF_CSI;
393 
394 		flags = endpoint->bus.parallel.flags;
395 
396 		cfg |= (bus_width == 16) ? CSI_IF_CFG_CSI_IF_BT1120 :
397 					   CSI_IF_CFG_CSI_IF_BT656;
398 
399 		if (flags & V4L2_MBUS_FIELD_EVEN_LOW)
400 			cfg |= CSI_IF_CFG_FIELD_POSITIVE;
401 
402 		if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
403 			cfg |= CSI_IF_CFG_CLK_POL_FALLING_EDGE;
404 		break;
405 	default:
406 		dev_warn(sdev->dev, "Unsupported bus type: %d\n",
407 			 endpoint->bus_type);
408 		break;
409 	}
410 
411 	switch (bus_width) {
412 	case 8:
413 		cfg |= CSI_IF_CFG_IF_DATA_WIDTH_8BIT;
414 		break;
415 	case 10:
416 		cfg |= CSI_IF_CFG_IF_DATA_WIDTH_10BIT;
417 		break;
418 	case 12:
419 		cfg |= CSI_IF_CFG_IF_DATA_WIDTH_12BIT;
420 		break;
421 	case 16: /* No need to configure DATA_WIDTH for 16bit */
422 		break;
423 	default:
424 		dev_warn(sdev->dev, "Unsupported bus width: %u\n", bus_width);
425 		break;
426 	}
427 
428 	regmap_write(sdev->regmap, CSI_IF_CFG_REG, cfg);
429 }
430 
431 static void sun6i_csi_set_format(struct sun6i_csi_dev *sdev)
432 {
433 	struct sun6i_csi *csi = &sdev->csi;
434 	u32 cfg;
435 	u32 val;
436 
437 	regmap_read(sdev->regmap, CSI_CH_CFG_REG, &cfg);
438 
439 	cfg &= ~(CSI_CH_CFG_INPUT_FMT_MASK |
440 		 CSI_CH_CFG_OUTPUT_FMT_MASK | CSI_CH_CFG_VFLIP_EN |
441 		 CSI_CH_CFG_HFLIP_EN | CSI_CH_CFG_FIELD_SEL_MASK |
442 		 CSI_CH_CFG_INPUT_SEQ_MASK);
443 
444 	val = get_csi_input_format(sdev, csi->config.code,
445 				   csi->config.pixelformat);
446 	cfg |= CSI_CH_CFG_INPUT_FMT(val);
447 
448 	val = get_csi_output_format(sdev, csi->config.pixelformat,
449 				    csi->config.field);
450 	cfg |= CSI_CH_CFG_OUTPUT_FMT(val);
451 
452 	val = get_csi_input_seq(sdev, csi->config.code,
453 				csi->config.pixelformat);
454 	cfg |= CSI_CH_CFG_INPUT_SEQ(val);
455 
456 	if (csi->config.field == V4L2_FIELD_TOP)
457 		cfg |= CSI_CH_CFG_FIELD_SEL_FIELD0;
458 	else if (csi->config.field == V4L2_FIELD_BOTTOM)
459 		cfg |= CSI_CH_CFG_FIELD_SEL_FIELD1;
460 	else
461 		cfg |= CSI_CH_CFG_FIELD_SEL_BOTH;
462 
463 	regmap_write(sdev->regmap, CSI_CH_CFG_REG, cfg);
464 }
465 
466 static void sun6i_csi_set_window(struct sun6i_csi_dev *sdev)
467 {
468 	struct sun6i_csi_config *config = &sdev->csi.config;
469 	u32 bytesperline_y;
470 	u32 bytesperline_c;
471 	int *planar_offset = sdev->planar_offset;
472 	u32 width = config->width;
473 	u32 height = config->height;
474 	u32 hor_len = width;
475 
476 	switch (config->pixelformat) {
477 	case V4L2_PIX_FMT_YUYV:
478 	case V4L2_PIX_FMT_YVYU:
479 	case V4L2_PIX_FMT_UYVY:
480 	case V4L2_PIX_FMT_VYUY:
481 		dev_dbg(sdev->dev,
482 			"Horizontal length should be 2 times of width for packed YUV formats!\n");
483 		hor_len = width * 2;
484 		break;
485 	default:
486 		break;
487 	}
488 
489 	regmap_write(sdev->regmap, CSI_CH_HSIZE_REG,
490 		     CSI_CH_HSIZE_HOR_LEN(hor_len) |
491 		     CSI_CH_HSIZE_HOR_START(0));
492 	regmap_write(sdev->regmap, CSI_CH_VSIZE_REG,
493 		     CSI_CH_VSIZE_VER_LEN(height) |
494 		     CSI_CH_VSIZE_VER_START(0));
495 
496 	planar_offset[0] = 0;
497 	switch (config->pixelformat) {
498 	case V4L2_PIX_FMT_HM12:
499 	case V4L2_PIX_FMT_NV12:
500 	case V4L2_PIX_FMT_NV21:
501 	case V4L2_PIX_FMT_NV16:
502 	case V4L2_PIX_FMT_NV61:
503 		bytesperline_y = width;
504 		bytesperline_c = width;
505 		planar_offset[1] = bytesperline_y * height;
506 		planar_offset[2] = -1;
507 		break;
508 	case V4L2_PIX_FMT_YUV420:
509 	case V4L2_PIX_FMT_YVU420:
510 		bytesperline_y = width;
511 		bytesperline_c = width / 2;
512 		planar_offset[1] = bytesperline_y * height;
513 		planar_offset[2] = planar_offset[1] +
514 				bytesperline_c * height / 2;
515 		break;
516 	case V4L2_PIX_FMT_YUV422P:
517 		bytesperline_y = width;
518 		bytesperline_c = width / 2;
519 		planar_offset[1] = bytesperline_y * height;
520 		planar_offset[2] = planar_offset[1] +
521 				bytesperline_c * height;
522 		break;
523 	default: /* raw */
524 		dev_dbg(sdev->dev,
525 			"Calculating pixelformat(0x%x)'s bytesperline as a packed format\n",
526 			config->pixelformat);
527 		bytesperline_y = (sun6i_csi_get_bpp(config->pixelformat) *
528 				  config->width) / 8;
529 		bytesperline_c = 0;
530 		planar_offset[1] = -1;
531 		planar_offset[2] = -1;
532 		break;
533 	}
534 
535 	regmap_write(sdev->regmap, CSI_CH_BUF_LEN_REG,
536 		     CSI_CH_BUF_LEN_BUF_LEN_C(bytesperline_c) |
537 		     CSI_CH_BUF_LEN_BUF_LEN_Y(bytesperline_y));
538 }
539 
540 int sun6i_csi_update_config(struct sun6i_csi *csi,
541 			    struct sun6i_csi_config *config)
542 {
543 	struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
544 
545 	if (!config)
546 		return -EINVAL;
547 
548 	memcpy(&csi->config, config, sizeof(csi->config));
549 
550 	sun6i_csi_setup_bus(sdev);
551 	sun6i_csi_set_format(sdev);
552 	sun6i_csi_set_window(sdev);
553 
554 	return 0;
555 }
556 
557 void sun6i_csi_update_buf_addr(struct sun6i_csi *csi, dma_addr_t addr)
558 {
559 	struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
560 
561 	regmap_write(sdev->regmap, CSI_CH_F0_BUFA_REG,
562 		     (addr + sdev->planar_offset[0]) >> 2);
563 	if (sdev->planar_offset[1] != -1)
564 		regmap_write(sdev->regmap, CSI_CH_F1_BUFA_REG,
565 			     (addr + sdev->planar_offset[1]) >> 2);
566 	if (sdev->planar_offset[2] != -1)
567 		regmap_write(sdev->regmap, CSI_CH_F2_BUFA_REG,
568 			     (addr + sdev->planar_offset[2]) >> 2);
569 }
570 
571 void sun6i_csi_set_stream(struct sun6i_csi *csi, bool enable)
572 {
573 	struct sun6i_csi_dev *sdev = sun6i_csi_to_dev(csi);
574 	struct regmap *regmap = sdev->regmap;
575 
576 	if (!enable) {
577 		regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON, 0);
578 		regmap_write(regmap, CSI_CH_INT_EN_REG, 0);
579 		return;
580 	}
581 
582 	regmap_write(regmap, CSI_CH_INT_STA_REG, 0xFF);
583 	regmap_write(regmap, CSI_CH_INT_EN_REG,
584 		     CSI_CH_INT_EN_HB_OF_INT_EN |
585 		     CSI_CH_INT_EN_FIFO2_OF_INT_EN |
586 		     CSI_CH_INT_EN_FIFO1_OF_INT_EN |
587 		     CSI_CH_INT_EN_FIFO0_OF_INT_EN |
588 		     CSI_CH_INT_EN_FD_INT_EN |
589 		     CSI_CH_INT_EN_CD_INT_EN);
590 
591 	regmap_update_bits(regmap, CSI_CAP_REG, CSI_CAP_CH0_VCAP_ON,
592 			   CSI_CAP_CH0_VCAP_ON);
593 }
594 
595 /* -----------------------------------------------------------------------------
596  * Media Controller and V4L2
597  */
598 static int sun6i_csi_link_entity(struct sun6i_csi *csi,
599 				 struct media_entity *entity,
600 				 struct fwnode_handle *fwnode)
601 {
602 	struct media_entity *sink;
603 	struct media_pad *sink_pad;
604 	int src_pad_index;
605 	int ret;
606 
607 	ret = media_entity_get_fwnode_pad(entity, fwnode, MEDIA_PAD_FL_SOURCE);
608 	if (ret < 0) {
609 		dev_err(csi->dev, "%s: no source pad in external entity %s\n",
610 			__func__, entity->name);
611 		return -EINVAL;
612 	}
613 
614 	src_pad_index = ret;
615 
616 	sink = &csi->video.vdev.entity;
617 	sink_pad = &csi->video.pad;
618 
619 	dev_dbg(csi->dev, "creating %s:%u -> %s:%u link\n",
620 		entity->name, src_pad_index, sink->name, sink_pad->index);
621 	ret = media_create_pad_link(entity, src_pad_index, sink,
622 				    sink_pad->index,
623 				    MEDIA_LNK_FL_ENABLED |
624 				    MEDIA_LNK_FL_IMMUTABLE);
625 	if (ret < 0) {
626 		dev_err(csi->dev, "failed to create %s:%u -> %s:%u link\n",
627 			entity->name, src_pad_index,
628 			sink->name, sink_pad->index);
629 		return ret;
630 	}
631 
632 	return 0;
633 }
634 
635 static int sun6i_subdev_notify_complete(struct v4l2_async_notifier *notifier)
636 {
637 	struct sun6i_csi *csi = container_of(notifier, struct sun6i_csi,
638 					     notifier);
639 	struct v4l2_device *v4l2_dev = &csi->v4l2_dev;
640 	struct v4l2_subdev *sd;
641 	int ret;
642 
643 	dev_dbg(csi->dev, "notify complete, all subdevs registered\n");
644 
645 	sd = list_first_entry(&v4l2_dev->subdevs, struct v4l2_subdev, list);
646 	if (!sd)
647 		return -EINVAL;
648 
649 	ret = sun6i_csi_link_entity(csi, &sd->entity, sd->fwnode);
650 	if (ret < 0)
651 		return ret;
652 
653 	ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev);
654 	if (ret < 0)
655 		return ret;
656 
657 	return media_device_register(&csi->media_dev);
658 }
659 
660 static const struct v4l2_async_notifier_operations sun6i_csi_async_ops = {
661 	.complete = sun6i_subdev_notify_complete,
662 };
663 
664 static int sun6i_csi_fwnode_parse(struct device *dev,
665 				  struct v4l2_fwnode_endpoint *vep,
666 				  struct v4l2_async_subdev *asd)
667 {
668 	struct sun6i_csi *csi = dev_get_drvdata(dev);
669 
670 	if (vep->base.port || vep->base.id) {
671 		dev_warn(dev, "Only support a single port with one endpoint\n");
672 		return -ENOTCONN;
673 	}
674 
675 	switch (vep->bus_type) {
676 	case V4L2_MBUS_PARALLEL:
677 	case V4L2_MBUS_BT656:
678 		csi->v4l2_ep = *vep;
679 		return 0;
680 	default:
681 		dev_err(dev, "Unsupported media bus type\n");
682 		return -ENOTCONN;
683 	}
684 }
685 
686 static void sun6i_csi_v4l2_cleanup(struct sun6i_csi *csi)
687 {
688 	media_device_unregister(&csi->media_dev);
689 	v4l2_async_notifier_unregister(&csi->notifier);
690 	v4l2_async_notifier_cleanup(&csi->notifier);
691 	sun6i_video_cleanup(&csi->video);
692 	v4l2_device_unregister(&csi->v4l2_dev);
693 	v4l2_ctrl_handler_free(&csi->ctrl_handler);
694 	media_device_cleanup(&csi->media_dev);
695 }
696 
697 static int sun6i_csi_v4l2_init(struct sun6i_csi *csi)
698 {
699 	int ret;
700 
701 	csi->media_dev.dev = csi->dev;
702 	strscpy(csi->media_dev.model, "Allwinner Video Capture Device",
703 		sizeof(csi->media_dev.model));
704 	csi->media_dev.hw_revision = 0;
705 
706 	media_device_init(&csi->media_dev);
707 	v4l2_async_notifier_init(&csi->notifier);
708 
709 	ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 0);
710 	if (ret) {
711 		dev_err(csi->dev, "V4L2 controls handler init failed (%d)\n",
712 			ret);
713 		goto clean_media;
714 	}
715 
716 	csi->v4l2_dev.mdev = &csi->media_dev;
717 	csi->v4l2_dev.ctrl_handler = &csi->ctrl_handler;
718 	ret = v4l2_device_register(csi->dev, &csi->v4l2_dev);
719 	if (ret) {
720 		dev_err(csi->dev, "V4L2 device registration failed (%d)\n",
721 			ret);
722 		goto free_ctrl;
723 	}
724 
725 	ret = sun6i_video_init(&csi->video, csi, "sun6i-csi");
726 	if (ret)
727 		goto unreg_v4l2;
728 
729 	ret = v4l2_async_notifier_parse_fwnode_endpoints(csi->dev,
730 							 &csi->notifier,
731 							 sizeof(struct v4l2_async_subdev),
732 							 sun6i_csi_fwnode_parse);
733 	if (ret)
734 		goto clean_video;
735 
736 	csi->notifier.ops = &sun6i_csi_async_ops;
737 
738 	ret = v4l2_async_notifier_register(&csi->v4l2_dev, &csi->notifier);
739 	if (ret) {
740 		dev_err(csi->dev, "notifier registration failed\n");
741 		goto clean_video;
742 	}
743 
744 	return 0;
745 
746 clean_video:
747 	sun6i_video_cleanup(&csi->video);
748 unreg_v4l2:
749 	v4l2_device_unregister(&csi->v4l2_dev);
750 free_ctrl:
751 	v4l2_ctrl_handler_free(&csi->ctrl_handler);
752 clean_media:
753 	v4l2_async_notifier_cleanup(&csi->notifier);
754 	media_device_cleanup(&csi->media_dev);
755 
756 	return ret;
757 }
758 
759 /* -----------------------------------------------------------------------------
760  * Resources and IRQ
761  */
762 static irqreturn_t sun6i_csi_isr(int irq, void *dev_id)
763 {
764 	struct sun6i_csi_dev *sdev = (struct sun6i_csi_dev *)dev_id;
765 	struct regmap *regmap = sdev->regmap;
766 	u32 status;
767 
768 	regmap_read(regmap, CSI_CH_INT_STA_REG, &status);
769 
770 	if (!(status & 0xFF))
771 		return IRQ_NONE;
772 
773 	if ((status & CSI_CH_INT_STA_FIFO0_OF_PD) ||
774 	    (status & CSI_CH_INT_STA_FIFO1_OF_PD) ||
775 	    (status & CSI_CH_INT_STA_FIFO2_OF_PD) ||
776 	    (status & CSI_CH_INT_STA_HB_OF_PD)) {
777 		regmap_write(regmap, CSI_CH_INT_STA_REG, status);
778 		regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN, 0);
779 		regmap_update_bits(regmap, CSI_EN_REG, CSI_EN_CSI_EN,
780 				   CSI_EN_CSI_EN);
781 		return IRQ_HANDLED;
782 	}
783 
784 	if (status & CSI_CH_INT_STA_FD_PD)
785 		sun6i_video_frame_done(&sdev->csi.video);
786 
787 	regmap_write(regmap, CSI_CH_INT_STA_REG, status);
788 
789 	return IRQ_HANDLED;
790 }
791 
792 static const struct regmap_config sun6i_csi_regmap_config = {
793 	.reg_bits       = 32,
794 	.reg_stride     = 4,
795 	.val_bits       = 32,
796 	.max_register	= 0x1000,
797 };
798 
799 static int sun6i_csi_resource_request(struct sun6i_csi_dev *sdev,
800 				      struct platform_device *pdev)
801 {
802 	struct resource *res;
803 	void __iomem *io_base;
804 	int ret;
805 	int irq;
806 
807 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
808 	io_base = devm_ioremap_resource(&pdev->dev, res);
809 	if (IS_ERR(io_base))
810 		return PTR_ERR(io_base);
811 
812 	sdev->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", io_base,
813 						 &sun6i_csi_regmap_config);
814 	if (IS_ERR(sdev->regmap)) {
815 		dev_err(&pdev->dev, "Failed to init register map\n");
816 		return PTR_ERR(sdev->regmap);
817 	}
818 
819 	sdev->clk_mod = devm_clk_get(&pdev->dev, "mod");
820 	if (IS_ERR(sdev->clk_mod)) {
821 		dev_err(&pdev->dev, "Unable to acquire csi clock\n");
822 		return PTR_ERR(sdev->clk_mod);
823 	}
824 
825 	sdev->clk_ram = devm_clk_get(&pdev->dev, "ram");
826 	if (IS_ERR(sdev->clk_ram)) {
827 		dev_err(&pdev->dev, "Unable to acquire dram-csi clock\n");
828 		return PTR_ERR(sdev->clk_ram);
829 	}
830 
831 	sdev->rstc_bus = devm_reset_control_get_shared(&pdev->dev, NULL);
832 	if (IS_ERR(sdev->rstc_bus)) {
833 		dev_err(&pdev->dev, "Cannot get reset controller\n");
834 		return PTR_ERR(sdev->rstc_bus);
835 	}
836 
837 	irq = platform_get_irq(pdev, 0);
838 	if (irq < 0) {
839 		dev_err(&pdev->dev, "No csi IRQ specified\n");
840 		ret = -ENXIO;
841 		return ret;
842 	}
843 
844 	ret = devm_request_irq(&pdev->dev, irq, sun6i_csi_isr, 0, MODULE_NAME,
845 			       sdev);
846 	if (ret) {
847 		dev_err(&pdev->dev, "Cannot request csi IRQ\n");
848 		return ret;
849 	}
850 
851 	return 0;
852 }
853 
854 /*
855  * PHYS_OFFSET isn't available on all architectures. In order to
856  * accommodate for COMPILE_TEST, let's define it to something dumb.
857  */
858 #if defined(CONFIG_COMPILE_TEST) && !defined(PHYS_OFFSET)
859 #define PHYS_OFFSET 0
860 #endif
861 
862 static int sun6i_csi_probe(struct platform_device *pdev)
863 {
864 	struct sun6i_csi_dev *sdev;
865 	int ret;
866 
867 	sdev = devm_kzalloc(&pdev->dev, sizeof(*sdev), GFP_KERNEL);
868 	if (!sdev)
869 		return -ENOMEM;
870 
871 	sdev->dev = &pdev->dev;
872 	/* The DMA bus has the memory mapped at 0 */
873 	sdev->dev->dma_pfn_offset = PHYS_OFFSET >> PAGE_SHIFT;
874 
875 	ret = sun6i_csi_resource_request(sdev, pdev);
876 	if (ret)
877 		return ret;
878 
879 	platform_set_drvdata(pdev, sdev);
880 
881 	sdev->csi.dev = &pdev->dev;
882 	return sun6i_csi_v4l2_init(&sdev->csi);
883 }
884 
885 static int sun6i_csi_remove(struct platform_device *pdev)
886 {
887 	struct sun6i_csi_dev *sdev = platform_get_drvdata(pdev);
888 
889 	sun6i_csi_v4l2_cleanup(&sdev->csi);
890 
891 	return 0;
892 }
893 
894 static const struct of_device_id sun6i_csi_of_match[] = {
895 	{ .compatible = "allwinner,sun6i-a31-csi", },
896 	{ .compatible = "allwinner,sun8i-v3s-csi", },
897 	{},
898 };
899 MODULE_DEVICE_TABLE(of, sun6i_csi_of_match);
900 
901 static struct platform_driver sun6i_csi_platform_driver = {
902 	.probe = sun6i_csi_probe,
903 	.remove = sun6i_csi_remove,
904 	.driver = {
905 		.name = MODULE_NAME,
906 		.of_match_table = of_match_ptr(sun6i_csi_of_match),
907 	},
908 };
909 module_platform_driver(sun6i_csi_platform_driver);
910 
911 MODULE_DESCRIPTION("Allwinner V3s Camera Sensor Interface driver");
912 MODULE_AUTHOR("Yong Deng <yong.deng@magewell.com>");
913 MODULE_LICENSE("GPL");
914