a21ac2a7c02dd1c503cce79016a982a1b835c54d
[openwrt/staging/ldir.git] / target / linux / at91 / patches-5.10 / 185-media-atmel-atmel-isc-add-microchip-xisc-driver.patch
1 From 74fd7ea680cb1a3a43b51a7279aea45efdf9ec42 Mon Sep 17 00:00:00 2001
2 From: Eugen Hristev <eugen.hristev@microchip.com>
3 Date: Tue, 13 Apr 2021 12:57:29 +0200
4 Subject: [PATCH 185/247] media: atmel: atmel-isc: add microchip-xisc driver
5
6 Add driver for the extended variant of the isc, the microchip XISC
7 present on sama7g5 product.
8
9 [hverkuil: drop MODULE_SUPPORTED_DEVICE, no longer exists]
10 [hverkuil: made isc_sama7g5_config_csc et al static]
11 [hverkuil: made sama7g5_controller_formats et al static]
12
13 Signed-off-by: Eugen Hristev <eugen.hristev@microchip.com>
14 Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
15 Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
16 ---
17 drivers/media/platform/Makefile | 1 +
18 drivers/media/platform/atmel/Kconfig | 11 +
19 drivers/media/platform/atmel/Makefile | 2 +
20 drivers/media/platform/atmel/atmel-isc-base.c | 2 +-
21 drivers/media/platform/atmel/atmel-isc-regs.h | 26 +
22 .../media/platform/atmel/atmel-sama7g5-isc.c | 630 ++++++++++++++++++
23 6 files changed, 671 insertions(+), 1 deletion(-)
24 create mode 100644 drivers/media/platform/atmel/atmel-sama7g5-isc.c
25
26 --- a/drivers/media/platform/Makefile
27 +++ b/drivers/media/platform/Makefile
28 @@ -64,6 +64,7 @@ obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vi
29
30 obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel/
31 obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel/
32 +obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel/
33
34 obj-$(CONFIG_VIDEO_STM32_DCMI) += stm32/
35
36 --- a/drivers/media/platform/atmel/Kconfig
37 +++ b/drivers/media/platform/atmel/Kconfig
38 @@ -12,6 +12,17 @@ config VIDEO_ATMEL_ISC
39 This module makes the ATMEL Image Sensor Controller available
40 as a v4l2 device.
41
42 +config VIDEO_ATMEL_XISC
43 + tristate "ATMEL eXtended Image Sensor Controller (XISC) support"
44 + depends on VIDEO_V4L2 && COMMON_CLK && VIDEO_V4L2_SUBDEV_API
45 + depends on ARCH_AT91 || COMPILE_TEST
46 + select VIDEOBUF2_DMA_CONTIG
47 + select REGMAP_MMIO
48 + select V4L2_FWNODE
49 + help
50 + This module makes the ATMEL eXtended Image Sensor Controller
51 + available as a v4l2 device.
52 +
53 config VIDEO_ATMEL_ISI
54 tristate "ATMEL Image Sensor Interface (ISI) support"
55 depends on VIDEO_V4L2 && OF
56 --- a/drivers/media/platform/atmel/Makefile
57 +++ b/drivers/media/platform/atmel/Makefile
58 @@ -1,5 +1,7 @@
59 # SPDX-License-Identifier: GPL-2.0-only
60 atmel-isc-objs = atmel-sama5d2-isc.o atmel-isc-base.o
61 +atmel-xisc-objs = atmel-sama7g5-isc.o atmel-isc-base.o
62
63 obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
64 obj-$(CONFIG_VIDEO_ATMEL_ISC) += atmel-isc.o
65 +obj-$(CONFIG_VIDEO_ATMEL_XISC) += atmel-xisc.o
66 --- a/drivers/media/platform/atmel/atmel-isc-base.c
67 +++ b/drivers/media/platform/atmel/atmel-isc-base.c
68 @@ -600,7 +600,7 @@ static int isc_configure(struct isc_devi
69 mask = ISC_PFE_CFG0_BPS_MASK | ISC_PFE_CFG0_HPOL_LOW |
70 ISC_PFE_CFG0_VPOL_LOW | ISC_PFE_CFG0_PPOL_LOW |
71 ISC_PFE_CFG0_MODE_MASK | ISC_PFE_CFG0_CCIR_CRC |
72 - ISC_PFE_CFG0_CCIR656;
73 + ISC_PFE_CFG0_CCIR656 | ISC_PFE_CFG0_MIPI;
74
75 regmap_update_bits(regmap, ISC_PFE_CFG0, mask, pfe_cfg0);
76
77 --- a/drivers/media/platform/atmel/atmel-isc-regs.h
78 +++ b/drivers/media/platform/atmel/atmel-isc-regs.h
79 @@ -26,6 +26,7 @@
80 #define ISC_PFE_CFG0_PPOL_LOW BIT(2)
81 #define ISC_PFE_CFG0_CCIR656 BIT(9)
82 #define ISC_PFE_CFG0_CCIR_CRC BIT(10)
83 +#define ISC_PFE_CFG0_MIPI BIT(14)
84
85 #define ISC_PFE_CFG0_MODE_PROGRESSIVE (0x0 << 4)
86 #define ISC_PFE_CFG0_MODE_MASK GENMASK(6, 4)
87 @@ -184,6 +185,8 @@
88 /* ISC Gamma Correction Control Register */
89 #define ISC_GAM_CTRL 0x00000094
90
91 +#define ISC_GAM_CTRL_BIPART BIT(4)
92 +
93 /* ISC_Gamma Correction Blue Entry Register */
94 #define ISC_GAM_BENTRY 0x00000098
95
96 @@ -222,6 +225,8 @@
97
98 /* Offset for CSC register specific to sama5d2 product */
99 #define ISC_SAMA5D2_CSC_OFFSET 0
100 +/* Offset for CSC register specific to sama7g5 product */
101 +#define ISC_SAMA7G5_CSC_OFFSET 0x11c
102
103 /* Color Space Conversion Control Register */
104 #define ISC_CSC_CTRL 0x00000398
105 @@ -246,6 +251,8 @@
106
107 /* Offset for CBC register specific to sama5d2 product */
108 #define ISC_SAMA5D2_CBC_OFFSET 0
109 +/* Offset for CBC register specific to sama7g5 product */
110 +#define ISC_SAMA7G5_CBC_OFFSET 0x11c
111
112 /* Contrast And Brightness Control Register */
113 #define ISC_CBC_CTRL 0x000003b4
114 @@ -261,18 +268,30 @@
115 #define ISC_CBC_CONTRAST 0x000003c0
116 #define ISC_CBC_CONTRAST_MASK GENMASK(11, 0)
117
118 +/* Hue Register */
119 +#define ISC_CBCHS_HUE 0x4e0
120 +/* Saturation Register */
121 +#define ISC_CBCHS_SAT 0x4e4
122 +
123 /* Offset for SUB422 register specific to sama5d2 product */
124 #define ISC_SAMA5D2_SUB422_OFFSET 0
125 +/* Offset for SUB422 register specific to sama7g5 product */
126 +#define ISC_SAMA7G5_SUB422_OFFSET 0x124
127 +
128 /* Subsampling 4:4:4 to 4:2:2 Control Register */
129 #define ISC_SUB422_CTRL 0x000003c4
130
131 /* Offset for SUB420 register specific to sama5d2 product */
132 #define ISC_SAMA5D2_SUB420_OFFSET 0
133 +/* Offset for SUB420 register specific to sama7g5 product */
134 +#define ISC_SAMA7G5_SUB420_OFFSET 0x124
135 /* Subsampling 4:2:2 to 4:2:0 Control Register */
136 #define ISC_SUB420_CTRL 0x000003cc
137
138 /* Offset for RLP register specific to sama5d2 product */
139 #define ISC_SAMA5D2_RLP_OFFSET 0
140 +/* Offset for RLP register specific to sama7g5 product */
141 +#define ISC_SAMA7G5_RLP_OFFSET 0x124
142 /* Rounding, Limiting and Packing Configuration Register */
143 #define ISC_RLP_CFG 0x000003d0
144
145 @@ -303,6 +322,8 @@
146
147 /* Offset for HIS register specific to sama5d2 product */
148 #define ISC_SAMA5D2_HIS_OFFSET 0
149 +/* Offset for HIS register specific to sama7g5 product */
150 +#define ISC_SAMA7G5_HIS_OFFSET 0x124
151 /* Histogram Control Register */
152 #define ISC_HIS_CTRL 0x000003d4
153
154 @@ -326,6 +347,8 @@
155
156 /* Offset for DMA register specific to sama5d2 product */
157 #define ISC_SAMA5D2_DMA_OFFSET 0
158 +/* Offset for DMA register specific to sama7g5 product */
159 +#define ISC_SAMA7G5_DMA_OFFSET 0x13c
160
161 /* DMA Configuration Register */
162 #define ISC_DCFG 0x000003e0
163 @@ -376,11 +399,14 @@
164
165 /* Offset for version register specific to sama5d2 product */
166 #define ISC_SAMA5D2_VERSION_OFFSET 0
167 +#define ISC_SAMA7G5_VERSION_OFFSET 0x13c
168 /* Version Register */
169 #define ISC_VERSION 0x0000040c
170
171 /* Offset for version register specific to sama5d2 product */
172 #define ISC_SAMA5D2_HIS_ENTRY_OFFSET 0
173 +/* Offset for version register specific to sama7g5 product */
174 +#define ISC_SAMA7G5_HIS_ENTRY_OFFSET 0x14c
175 /* Histogram Entry */
176 #define ISC_HIS_ENTRY 0x00000410
177
178 --- /dev/null
179 +++ b/drivers/media/platform/atmel/atmel-sama7g5-isc.c
180 @@ -0,0 +1,630 @@
181 +// SPDX-License-Identifier: GPL-2.0
182 +/*
183 + * Microchip eXtended Image Sensor Controller (XISC) driver
184 + *
185 + * Copyright (C) 2019-2021 Microchip Technology, Inc. and its subsidiaries
186 + *
187 + * Author: Eugen Hristev <eugen.hristev@microchip.com>
188 + *
189 + * Sensor-->PFE-->DPC-->WB-->CFA-->CC-->GAM-->VHXS-->CSC-->CBHS-->SUB-->RLP-->DMA-->HIS
190 + *
191 + * ISC video pipeline integrates the following submodules:
192 + * PFE: Parallel Front End to sample the camera sensor input stream
193 + * DPC: Defective Pixel Correction with black offset correction, green disparity
194 + * correction and defective pixel correction (3 modules total)
195 + * WB: Programmable white balance in the Bayer domain
196 + * CFA: Color filter array interpolation module
197 + * CC: Programmable color correction
198 + * GAM: Gamma correction
199 + *VHXS: Vertical and Horizontal Scaler
200 + * CSC: Programmable color space conversion
201 + *CBHS: Contrast Brightness Hue and Saturation control
202 + * SUB: This module performs YCbCr444 to YCbCr420 chrominance subsampling
203 + * RLP: This module performs rounding, range limiting
204 + * and packing of the incoming data
205 + * DMA: This module performs DMA master accesses to write frames to external RAM
206 + * HIS: Histogram module performs statistic counters on the frames
207 + */
208 +
209 +#include <linux/clk.h>
210 +#include <linux/clkdev.h>
211 +#include <linux/clk-provider.h>
212 +#include <linux/delay.h>
213 +#include <linux/interrupt.h>
214 +#include <linux/math64.h>
215 +#include <linux/module.h>
216 +#include <linux/of.h>
217 +#include <linux/of_graph.h>
218 +#include <linux/platform_device.h>
219 +#include <linux/pm_runtime.h>
220 +#include <linux/regmap.h>
221 +#include <linux/videodev2.h>
222 +
223 +#include <media/v4l2-ctrls.h>
224 +#include <media/v4l2-device.h>
225 +#include <media/v4l2-event.h>
226 +#include <media/v4l2-image-sizes.h>
227 +#include <media/v4l2-ioctl.h>
228 +#include <media/v4l2-fwnode.h>
229 +#include <media/v4l2-subdev.h>
230 +#include <media/videobuf2-dma-contig.h>
231 +
232 +#include "atmel-isc-regs.h"
233 +#include "atmel-isc.h"
234 +
235 +#define ISC_SAMA7G5_MAX_SUPPORT_WIDTH 3264
236 +#define ISC_SAMA7G5_MAX_SUPPORT_HEIGHT 2464
237 +
238 +#define ISC_SAMA7G5_PIPELINE \
239 + (WB_ENABLE | CFA_ENABLE | CC_ENABLE | GAM_ENABLES | CSC_ENABLE | \
240 + CBC_ENABLE | SUB422_ENABLE | SUB420_ENABLE)
241 +
242 +/* This is a list of the formats that the ISC can *output* */
243 +static const struct isc_format sama7g5_controller_formats[] = {
244 + {
245 + .fourcc = V4L2_PIX_FMT_ARGB444,
246 + },
247 + {
248 + .fourcc = V4L2_PIX_FMT_ARGB555,
249 + },
250 + {
251 + .fourcc = V4L2_PIX_FMT_RGB565,
252 + },
253 + {
254 + .fourcc = V4L2_PIX_FMT_ABGR32,
255 + },
256 + {
257 + .fourcc = V4L2_PIX_FMT_XBGR32,
258 + },
259 + {
260 + .fourcc = V4L2_PIX_FMT_YUV420,
261 + },
262 + {
263 + .fourcc = V4L2_PIX_FMT_UYVY,
264 + },
265 + {
266 + .fourcc = V4L2_PIX_FMT_VYUY,
267 + },
268 + {
269 + .fourcc = V4L2_PIX_FMT_YUYV,
270 + },
271 + {
272 + .fourcc = V4L2_PIX_FMT_YUV422P,
273 + },
274 + {
275 + .fourcc = V4L2_PIX_FMT_GREY,
276 + },
277 + {
278 + .fourcc = V4L2_PIX_FMT_Y10,
279 + },
280 + {
281 + .fourcc = V4L2_PIX_FMT_Y16,
282 + },
283 +};
284 +
285 +/* This is a list of formats that the ISC can receive as *input* */
286 +static struct isc_format sama7g5_formats_list[] = {
287 + {
288 + .fourcc = V4L2_PIX_FMT_SBGGR8,
289 + .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
290 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
291 + .cfa_baycfg = ISC_BAY_CFG_BGBG,
292 + },
293 + {
294 + .fourcc = V4L2_PIX_FMT_SGBRG8,
295 + .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8,
296 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
297 + .cfa_baycfg = ISC_BAY_CFG_GBGB,
298 + },
299 + {
300 + .fourcc = V4L2_PIX_FMT_SGRBG8,
301 + .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
302 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
303 + .cfa_baycfg = ISC_BAY_CFG_GRGR,
304 + },
305 + {
306 + .fourcc = V4L2_PIX_FMT_SRGGB8,
307 + .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8,
308 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
309 + .cfa_baycfg = ISC_BAY_CFG_RGRG,
310 + },
311 + {
312 + .fourcc = V4L2_PIX_FMT_SBGGR10,
313 + .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10,
314 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
315 + .cfa_baycfg = ISC_BAY_CFG_RGRG,
316 + },
317 + {
318 + .fourcc = V4L2_PIX_FMT_SGBRG10,
319 + .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10,
320 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
321 + .cfa_baycfg = ISC_BAY_CFG_GBGB,
322 + },
323 + {
324 + .fourcc = V4L2_PIX_FMT_SGRBG10,
325 + .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
326 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
327 + .cfa_baycfg = ISC_BAY_CFG_GRGR,
328 + },
329 + {
330 + .fourcc = V4L2_PIX_FMT_SRGGB10,
331 + .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10,
332 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
333 + .cfa_baycfg = ISC_BAY_CFG_RGRG,
334 + },
335 + {
336 + .fourcc = V4L2_PIX_FMT_SBGGR12,
337 + .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12,
338 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
339 + .cfa_baycfg = ISC_BAY_CFG_BGBG,
340 + },
341 + {
342 + .fourcc = V4L2_PIX_FMT_SGBRG12,
343 + .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12,
344 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
345 + .cfa_baycfg = ISC_BAY_CFG_GBGB,
346 + },
347 + {
348 + .fourcc = V4L2_PIX_FMT_SGRBG12,
349 + .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
350 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
351 + .cfa_baycfg = ISC_BAY_CFG_GRGR,
352 + },
353 + {
354 + .fourcc = V4L2_PIX_FMT_SRGGB12,
355 + .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12,
356 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TWELVE,
357 + .cfa_baycfg = ISC_BAY_CFG_RGRG,
358 + },
359 + {
360 + .fourcc = V4L2_PIX_FMT_GREY,
361 + .mbus_code = MEDIA_BUS_FMT_Y8_1X8,
362 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
363 + },
364 + {
365 + .fourcc = V4L2_PIX_FMT_YUYV,
366 + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
367 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
368 + },
369 + {
370 + .fourcc = V4L2_PIX_FMT_UYVY,
371 + .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
372 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
373 + },
374 + {
375 + .fourcc = V4L2_PIX_FMT_RGB565,
376 + .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
377 + .pfe_cfg0_bps = ISC_PFE_CFG0_BPS_EIGHT,
378 + },
379 + {
380 + .fourcc = V4L2_PIX_FMT_Y10,
381 + .mbus_code = MEDIA_BUS_FMT_Y10_1X10,
382 + .pfe_cfg0_bps = ISC_PFG_CFG0_BPS_TEN,
383 + },
384 +
385 +};
386 +
387 +static void isc_sama7g5_config_csc(struct isc_device *isc)
388 +{
389 + struct regmap *regmap = isc->regmap;
390 +
391 + /* Convert RGB to YUV */
392 + regmap_write(regmap, ISC_CSC_YR_YG + isc->offsets.csc,
393 + 0x42 | (0x81 << 16));
394 + regmap_write(regmap, ISC_CSC_YB_OY + isc->offsets.csc,
395 + 0x19 | (0x10 << 16));
396 + regmap_write(regmap, ISC_CSC_CBR_CBG + isc->offsets.csc,
397 + 0xFDA | (0xFB6 << 16));
398 + regmap_write(regmap, ISC_CSC_CBB_OCB + isc->offsets.csc,
399 + 0x70 | (0x80 << 16));
400 + regmap_write(regmap, ISC_CSC_CRR_CRG + isc->offsets.csc,
401 + 0x70 | (0xFA2 << 16));
402 + regmap_write(regmap, ISC_CSC_CRB_OCR + isc->offsets.csc,
403 + 0xFEE | (0x80 << 16));
404 +}
405 +
406 +static void isc_sama7g5_config_cbc(struct isc_device *isc)
407 +{
408 + struct regmap *regmap = isc->regmap;
409 +
410 + /* Configure what is set via v4l2 ctrls */
411 + regmap_write(regmap, ISC_CBC_BRIGHT + isc->offsets.cbc, isc->ctrls.brightness);
412 + regmap_write(regmap, ISC_CBC_CONTRAST + isc->offsets.cbc, isc->ctrls.contrast);
413 + /* Configure Hue and Saturation as neutral midpoint */
414 + regmap_write(regmap, ISC_CBCHS_HUE, 0);
415 + regmap_write(regmap, ISC_CBCHS_SAT, (1 << 4));
416 +}
417 +
418 +static void isc_sama7g5_config_cc(struct isc_device *isc)
419 +{
420 + struct regmap *regmap = isc->regmap;
421 +
422 + /* Configure each register at the neutral fixed point 1.0 or 0.0 */
423 + regmap_write(regmap, ISC_CC_RR_RG, (1 << 8));
424 + regmap_write(regmap, ISC_CC_RB_OR, 0);
425 + regmap_write(regmap, ISC_CC_GR_GG, (1 << 8) << 16);
426 + regmap_write(regmap, ISC_CC_GB_OG, 0);
427 + regmap_write(regmap, ISC_CC_BR_BG, 0);
428 + regmap_write(regmap, ISC_CC_BB_OB, (1 << 8));
429 +}
430 +
431 +static void isc_sama7g5_config_ctrls(struct isc_device *isc,
432 + const struct v4l2_ctrl_ops *ops)
433 +{
434 + struct isc_ctrls *ctrls = &isc->ctrls;
435 + struct v4l2_ctrl_handler *hdl = &ctrls->handler;
436 +
437 + ctrls->contrast = 16;
438 +
439 + v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -2048, 2047, 1, 16);
440 +}
441 +
442 +static void isc_sama7g5_config_dpc(struct isc_device *isc)
443 +{
444 + u32 bay_cfg = isc->config.sd_format->cfa_baycfg;
445 + struct regmap *regmap = isc->regmap;
446 +
447 + regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BLOFF_MASK,
448 + (64 << ISC_DPC_CFG_BLOFF_SHIFT));
449 + regmap_update_bits(regmap, ISC_DPC_CFG, ISC_DPC_CFG_BAYCFG_MASK,
450 + (bay_cfg << ISC_DPC_CFG_BAYCFG_SHIFT));
451 +}
452 +
453 +static void isc_sama7g5_config_gam(struct isc_device *isc)
454 +{
455 + struct regmap *regmap = isc->regmap;
456 +
457 + regmap_update_bits(regmap, ISC_GAM_CTRL, ISC_GAM_CTRL_BIPART,
458 + ISC_GAM_CTRL_BIPART);
459 +}
460 +
461 +static void isc_sama7g5_config_rlp(struct isc_device *isc)
462 +{
463 + struct regmap *regmap = isc->regmap;
464 + u32 rlp_mode = isc->config.rlp_cfg_mode;
465 +
466 + regmap_update_bits(regmap, ISC_RLP_CFG + isc->offsets.rlp,
467 + ISC_RLP_CFG_MODE_MASK | ISC_RLP_CFG_LSH |
468 + ISC_RLP_CFG_YMODE_MASK, rlp_mode);
469 +}
470 +
471 +static void isc_sama7g5_adapt_pipeline(struct isc_device *isc)
472 +{
473 + isc->try_config.bits_pipeline &= ISC_SAMA7G5_PIPELINE;
474 +}
475 +
476 +/* Gamma table with gamma 1/2.2 */
477 +static const u32 isc_sama7g5_gamma_table[][GAMMA_ENTRIES] = {
478 + /* index 0 --> gamma bipartite */
479 + {
480 + 0x980, 0x4c0320, 0x650260, 0x7801e0, 0x8701a0, 0x940180,
481 + 0xa00160, 0xab0120, 0xb40120, 0xbd0120, 0xc60100, 0xce0100,
482 + 0xd600e0, 0xdd00e0, 0xe400e0, 0xeb00c0, 0xf100c0, 0xf700c0,
483 + 0xfd00c0, 0x10300a0, 0x10800c0, 0x10e00a0, 0x11300a0, 0x11800a0,
484 + 0x11d00a0, 0x12200a0, 0x12700a0, 0x12c0080, 0x13000a0, 0x1350080,
485 + 0x13900a0, 0x13e0080, 0x1420076, 0x17d0062, 0x1ae0054, 0x1d8004a,
486 + 0x1fd0044, 0x21f003e, 0x23e003a, 0x25b0036, 0x2760032, 0x28f0030,
487 + 0x2a7002e, 0x2be002c, 0x2d4002c, 0x2ea0028, 0x2fe0028, 0x3120026,
488 + 0x3250024, 0x3370024, 0x3490022, 0x35a0022, 0x36b0020, 0x37b0020,
489 + 0x38b0020, 0x39b001e, 0x3aa001e, 0x3b9001c, 0x3c7001c, 0x3d5001c,
490 + 0x3e3001c, 0x3f1001c, 0x3ff001a, 0x40c001a },
491 +};
492 +
493 +static int xisc_parse_dt(struct device *dev, struct isc_device *isc)
494 +{
495 + struct device_node *np = dev->of_node;
496 + struct device_node *epn = NULL;
497 + struct isc_subdev_entity *subdev_entity;
498 + unsigned int flags;
499 + int ret;
500 + bool mipi_mode;
501 +
502 + INIT_LIST_HEAD(&isc->subdev_entities);
503 +
504 + mipi_mode = of_property_read_bool(np, "microchip,mipi-mode");
505 +
506 + while (1) {
507 + struct v4l2_fwnode_endpoint v4l2_epn = { .bus_type = 0 };
508 +
509 + epn = of_graph_get_next_endpoint(np, epn);
510 + if (!epn)
511 + return 0;
512 +
513 + ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(epn),
514 + &v4l2_epn);
515 + if (ret) {
516 + ret = -EINVAL;
517 + dev_err(dev, "Could not parse the endpoint\n");
518 + break;
519 + }
520 +
521 + subdev_entity = devm_kzalloc(dev, sizeof(*subdev_entity),
522 + GFP_KERNEL);
523 + if (!subdev_entity) {
524 + ret = -ENOMEM;
525 + break;
526 + }
527 + subdev_entity->epn = epn;
528 +
529 + flags = v4l2_epn.bus.parallel.flags;
530 +
531 + if (flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
532 + subdev_entity->pfe_cfg0 = ISC_PFE_CFG0_HPOL_LOW;
533 +
534 + if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
535 + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_VPOL_LOW;
536 +
537 + if (flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
538 + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_PPOL_LOW;
539 +
540 + if (v4l2_epn.bus_type == V4L2_MBUS_BT656)
541 + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_CCIR_CRC |
542 + ISC_PFE_CFG0_CCIR656;
543 +
544 + if (mipi_mode)
545 + subdev_entity->pfe_cfg0 |= ISC_PFE_CFG0_MIPI;
546 +
547 + list_add_tail(&subdev_entity->list, &isc->subdev_entities);
548 + }
549 + of_node_put(epn);
550 +
551 + return ret;
552 +}
553 +
554 +static int microchip_xisc_probe(struct platform_device *pdev)
555 +{
556 + struct device *dev = &pdev->dev;
557 + struct isc_device *isc;
558 + struct resource *res;
559 + void __iomem *io_base;
560 + struct isc_subdev_entity *subdev_entity;
561 + int irq;
562 + int ret;
563 + u32 ver;
564 +
565 + isc = devm_kzalloc(dev, sizeof(*isc), GFP_KERNEL);
566 + if (!isc)
567 + return -ENOMEM;
568 +
569 + platform_set_drvdata(pdev, isc);
570 + isc->dev = dev;
571 +
572 + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
573 + io_base = devm_ioremap_resource(dev, res);
574 + if (IS_ERR(io_base))
575 + return PTR_ERR(io_base);
576 +
577 + isc->regmap = devm_regmap_init_mmio(dev, io_base, &isc_regmap_config);
578 + if (IS_ERR(isc->regmap)) {
579 + ret = PTR_ERR(isc->regmap);
580 + dev_err(dev, "failed to init register map: %d\n", ret);
581 + return ret;
582 + }
583 +
584 + irq = platform_get_irq(pdev, 0);
585 + if (irq < 0)
586 + return irq;
587 +
588 + ret = devm_request_irq(dev, irq, isc_interrupt, 0,
589 + "microchip-sama7g5-xisc", isc);
590 + if (ret < 0) {
591 + dev_err(dev, "can't register ISR for IRQ %u (ret=%i)\n",
592 + irq, ret);
593 + return ret;
594 + }
595 +
596 + isc->gamma_table = isc_sama7g5_gamma_table;
597 + isc->gamma_max = 0;
598 +
599 + isc->max_width = ISC_SAMA7G5_MAX_SUPPORT_WIDTH;
600 + isc->max_height = ISC_SAMA7G5_MAX_SUPPORT_HEIGHT;
601 +
602 + isc->config_dpc = isc_sama7g5_config_dpc;
603 + isc->config_csc = isc_sama7g5_config_csc;
604 + isc->config_cbc = isc_sama7g5_config_cbc;
605 + isc->config_cc = isc_sama7g5_config_cc;
606 + isc->config_gam = isc_sama7g5_config_gam;
607 + isc->config_rlp = isc_sama7g5_config_rlp;
608 + isc->config_ctrls = isc_sama7g5_config_ctrls;
609 +
610 + isc->adapt_pipeline = isc_sama7g5_adapt_pipeline;
611 +
612 + isc->offsets.csc = ISC_SAMA7G5_CSC_OFFSET;
613 + isc->offsets.cbc = ISC_SAMA7G5_CBC_OFFSET;
614 + isc->offsets.sub422 = ISC_SAMA7G5_SUB422_OFFSET;
615 + isc->offsets.sub420 = ISC_SAMA7G5_SUB420_OFFSET;
616 + isc->offsets.rlp = ISC_SAMA7G5_RLP_OFFSET;
617 + isc->offsets.his = ISC_SAMA7G5_HIS_OFFSET;
618 + isc->offsets.dma = ISC_SAMA7G5_DMA_OFFSET;
619 + isc->offsets.version = ISC_SAMA7G5_VERSION_OFFSET;
620 + isc->offsets.his_entry = ISC_SAMA7G5_HIS_ENTRY_OFFSET;
621 +
622 + isc->controller_formats = sama7g5_controller_formats;
623 + isc->controller_formats_size = ARRAY_SIZE(sama7g5_controller_formats);
624 + isc->formats_list = sama7g5_formats_list;
625 + isc->formats_list_size = ARRAY_SIZE(sama7g5_formats_list);
626 +
627 + /* sama7g5-isc RAM access port is full AXI4 - 32 bits per beat */
628 + isc->dcfg = ISC_DCFG_YMBSIZE_BEATS32 | ISC_DCFG_CMBSIZE_BEATS32;
629 +
630 + ret = isc_pipeline_init(isc);
631 + if (ret)
632 + return ret;
633 +
634 + isc->hclock = devm_clk_get(dev, "hclock");
635 + if (IS_ERR(isc->hclock)) {
636 + ret = PTR_ERR(isc->hclock);
637 + dev_err(dev, "failed to get hclock: %d\n", ret);
638 + return ret;
639 + }
640 +
641 + ret = clk_prepare_enable(isc->hclock);
642 + if (ret) {
643 + dev_err(dev, "failed to enable hclock: %d\n", ret);
644 + return ret;
645 + }
646 +
647 + ret = isc_clk_init(isc);
648 + if (ret) {
649 + dev_err(dev, "failed to init isc clock: %d\n", ret);
650 + goto unprepare_hclk;
651 + }
652 +
653 + isc->ispck = isc->isc_clks[ISC_ISPCK].clk;
654 +
655 + ret = clk_prepare_enable(isc->ispck);
656 + if (ret) {
657 + dev_err(dev, "failed to enable ispck: %d\n", ret);
658 + goto unprepare_hclk;
659 + }
660 +
661 + /* ispck should be greater or equal to hclock */
662 + ret = clk_set_rate(isc->ispck, clk_get_rate(isc->hclock));
663 + if (ret) {
664 + dev_err(dev, "failed to set ispck rate: %d\n", ret);
665 + goto unprepare_clk;
666 + }
667 +
668 + ret = v4l2_device_register(dev, &isc->v4l2_dev);
669 + if (ret) {
670 + dev_err(dev, "unable to register v4l2 device.\n");
671 + goto unprepare_clk;
672 + }
673 +
674 + ret = xisc_parse_dt(dev, isc);
675 + if (ret) {
676 + dev_err(dev, "fail to parse device tree\n");
677 + goto unregister_v4l2_device;
678 + }
679 +
680 + if (list_empty(&isc->subdev_entities)) {
681 + dev_err(dev, "no subdev found\n");
682 + ret = -ENODEV;
683 + goto unregister_v4l2_device;
684 + }
685 +
686 + list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
687 + struct v4l2_async_subdev *asd;
688 +
689 + v4l2_async_notifier_init(&subdev_entity->notifier);
690 +
691 + asd = v4l2_async_notifier_add_fwnode_remote_subdev(
692 + &subdev_entity->notifier,
693 + of_fwnode_handle(subdev_entity->epn),
694 + struct v4l2_async_subdev);
695 +
696 + of_node_put(subdev_entity->epn);
697 + subdev_entity->epn = NULL;
698 +
699 + if (IS_ERR(asd)) {
700 + ret = PTR_ERR(asd);
701 + goto cleanup_subdev;
702 + }
703 +
704 + subdev_entity->notifier.ops = &isc_async_ops;
705 +
706 + ret = v4l2_async_notifier_register(&isc->v4l2_dev,
707 + &subdev_entity->notifier);
708 + if (ret) {
709 + dev_err(dev, "fail to register async notifier\n");
710 + goto cleanup_subdev;
711 + }
712 +
713 + if (video_is_registered(&isc->video_dev))
714 + break;
715 + }
716 +
717 + pm_runtime_set_active(dev);
718 + pm_runtime_enable(dev);
719 + pm_request_idle(dev);
720 +
721 + regmap_read(isc->regmap, ISC_VERSION + isc->offsets.version, &ver);
722 + dev_info(dev, "Microchip XISC version %x\n", ver);
723 +
724 + return 0;
725 +
726 +cleanup_subdev:
727 + isc_subdev_cleanup(isc);
728 +
729 +unregister_v4l2_device:
730 + v4l2_device_unregister(&isc->v4l2_dev);
731 +
732 +unprepare_clk:
733 + clk_disable_unprepare(isc->ispck);
734 +unprepare_hclk:
735 + clk_disable_unprepare(isc->hclock);
736 +
737 + isc_clk_cleanup(isc);
738 +
739 + return ret;
740 +}
741 +
742 +static int microchip_xisc_remove(struct platform_device *pdev)
743 +{
744 + struct isc_device *isc = platform_get_drvdata(pdev);
745 +
746 + pm_runtime_disable(&pdev->dev);
747 +
748 + isc_subdev_cleanup(isc);
749 +
750 + v4l2_device_unregister(&isc->v4l2_dev);
751 +
752 + clk_disable_unprepare(isc->ispck);
753 + clk_disable_unprepare(isc->hclock);
754 +
755 + isc_clk_cleanup(isc);
756 +
757 + return 0;
758 +}
759 +
760 +static int __maybe_unused xisc_runtime_suspend(struct device *dev)
761 +{
762 + struct isc_device *isc = dev_get_drvdata(dev);
763 +
764 + clk_disable_unprepare(isc->ispck);
765 + clk_disable_unprepare(isc->hclock);
766 +
767 + return 0;
768 +}
769 +
770 +static int __maybe_unused xisc_runtime_resume(struct device *dev)
771 +{
772 + struct isc_device *isc = dev_get_drvdata(dev);
773 + int ret;
774 +
775 + ret = clk_prepare_enable(isc->hclock);
776 + if (ret)
777 + return ret;
778 +
779 + ret = clk_prepare_enable(isc->ispck);
780 + if (ret)
781 + clk_disable_unprepare(isc->hclock);
782 +
783 + return ret;
784 +}
785 +
786 +static const struct dev_pm_ops microchip_xisc_dev_pm_ops = {
787 + SET_RUNTIME_PM_OPS(xisc_runtime_suspend, xisc_runtime_resume, NULL)
788 +};
789 +
790 +static const struct of_device_id microchip_xisc_of_match[] = {
791 + { .compatible = "microchip,sama7g5-isc" },
792 + { }
793 +};
794 +MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
795 +
796 +static struct platform_driver microchip_xisc_driver = {
797 + .probe = microchip_xisc_probe,
798 + .remove = microchip_xisc_remove,
799 + .driver = {
800 + .name = "microchip-sama7g5-xisc",
801 + .pm = &microchip_xisc_dev_pm_ops,
802 + .of_match_table = of_match_ptr(microchip_xisc_of_match),
803 + },
804 +};
805 +
806 +module_platform_driver(microchip_xisc_driver);
807 +
808 +MODULE_AUTHOR("Eugen Hristev <eugen.hristev@microchip.com>");
809 +MODULE_DESCRIPTION("The V4L2 driver for Microchip-XISC");
810 +MODULE_LICENSE("GPL v2");