1ba5bf51aSVishal Sagar // SPDX-License-Identifier: GPL-2.0
2ba5bf51aSVishal Sagar /*
3ba5bf51aSVishal Sagar * Driver for Xilinx MIPI CSI-2 Rx Subsystem
4ba5bf51aSVishal Sagar *
5ba5bf51aSVishal Sagar * Copyright (C) 2016 - 2020 Xilinx, Inc.
6ba5bf51aSVishal Sagar *
7ba5bf51aSVishal Sagar * Contacts: Vishal Sagar <vishal.sagar@xilinx.com>
8ba5bf51aSVishal Sagar *
9ba5bf51aSVishal Sagar */
10ba5bf51aSVishal Sagar #include <linux/clk.h>
11ba5bf51aSVishal Sagar #include <linux/delay.h>
12ba5bf51aSVishal Sagar #include <linux/gpio/consumer.h>
13ba5bf51aSVishal Sagar #include <linux/interrupt.h>
14ba5bf51aSVishal Sagar #include <linux/module.h>
15ba5bf51aSVishal Sagar #include <linux/mutex.h>
16ba5bf51aSVishal Sagar #include <linux/of.h>
17ba5bf51aSVishal Sagar #include <linux/of_irq.h>
18ba5bf51aSVishal Sagar #include <linux/platform_device.h>
19ba5bf51aSVishal Sagar #include <linux/v4l2-subdev.h>
20ba5bf51aSVishal Sagar #include <media/media-entity.h>
212b891d39SLaurent Pinchart #include <media/mipi-csi2.h>
22ba5bf51aSVishal Sagar #include <media/v4l2-common.h>
23ba5bf51aSVishal Sagar #include <media/v4l2-ctrls.h>
24ba5bf51aSVishal Sagar #include <media/v4l2-fwnode.h>
25ba5bf51aSVishal Sagar #include <media/v4l2-subdev.h>
26ba5bf51aSVishal Sagar #include "xilinx-vip.h"
27ba5bf51aSVishal Sagar
28ba5bf51aSVishal Sagar /* Register register map */
29ba5bf51aSVishal Sagar #define XCSI_CCR_OFFSET 0x00
30ba5bf51aSVishal Sagar #define XCSI_CCR_SOFTRESET BIT(1)
31ba5bf51aSVishal Sagar #define XCSI_CCR_ENABLE BIT(0)
32ba5bf51aSVishal Sagar
33ba5bf51aSVishal Sagar #define XCSI_PCR_OFFSET 0x04
34ba5bf51aSVishal Sagar #define XCSI_PCR_MAXLANES_MASK GENMASK(4, 3)
35ba5bf51aSVishal Sagar #define XCSI_PCR_ACTLANES_MASK GENMASK(1, 0)
36ba5bf51aSVishal Sagar
37ba5bf51aSVishal Sagar #define XCSI_CSR_OFFSET 0x10
38ba5bf51aSVishal Sagar #define XCSI_CSR_PKTCNT GENMASK(31, 16)
39ba5bf51aSVishal Sagar #define XCSI_CSR_SPFIFOFULL BIT(3)
40ba5bf51aSVishal Sagar #define XCSI_CSR_SPFIFONE BIT(2)
41ba5bf51aSVishal Sagar #define XCSI_CSR_SLBF BIT(1)
42ba5bf51aSVishal Sagar #define XCSI_CSR_RIPCD BIT(0)
43ba5bf51aSVishal Sagar
44ba5bf51aSVishal Sagar #define XCSI_GIER_OFFSET 0x20
45ba5bf51aSVishal Sagar #define XCSI_GIER_GIE BIT(0)
46ba5bf51aSVishal Sagar
47ba5bf51aSVishal Sagar #define XCSI_ISR_OFFSET 0x24
48ba5bf51aSVishal Sagar #define XCSI_IER_OFFSET 0x28
49ba5bf51aSVishal Sagar
50ba5bf51aSVishal Sagar #define XCSI_ISR_FR BIT(31)
51ba5bf51aSVishal Sagar #define XCSI_ISR_VCXFE BIT(30)
52ba5bf51aSVishal Sagar #define XCSI_ISR_WCC BIT(22)
53ba5bf51aSVishal Sagar #define XCSI_ISR_ILC BIT(21)
54ba5bf51aSVishal Sagar #define XCSI_ISR_SPFIFOF BIT(20)
55ba5bf51aSVishal Sagar #define XCSI_ISR_SPFIFONE BIT(19)
56ba5bf51aSVishal Sagar #define XCSI_ISR_SLBF BIT(18)
57ba5bf51aSVishal Sagar #define XCSI_ISR_STOP BIT(17)
58ba5bf51aSVishal Sagar #define XCSI_ISR_SOTERR BIT(13)
59ba5bf51aSVishal Sagar #define XCSI_ISR_SOTSYNCERR BIT(12)
60ba5bf51aSVishal Sagar #define XCSI_ISR_ECC2BERR BIT(11)
61ba5bf51aSVishal Sagar #define XCSI_ISR_ECC1BERR BIT(10)
62ba5bf51aSVishal Sagar #define XCSI_ISR_CRCERR BIT(9)
63ba5bf51aSVishal Sagar #define XCSI_ISR_DATAIDERR BIT(8)
64ba5bf51aSVishal Sagar #define XCSI_ISR_VC3FSYNCERR BIT(7)
65ba5bf51aSVishal Sagar #define XCSI_ISR_VC3FLVLERR BIT(6)
66ba5bf51aSVishal Sagar #define XCSI_ISR_VC2FSYNCERR BIT(5)
67ba5bf51aSVishal Sagar #define XCSI_ISR_VC2FLVLERR BIT(4)
68ba5bf51aSVishal Sagar #define XCSI_ISR_VC1FSYNCERR BIT(3)
69ba5bf51aSVishal Sagar #define XCSI_ISR_VC1FLVLERR BIT(2)
70ba5bf51aSVishal Sagar #define XCSI_ISR_VC0FSYNCERR BIT(1)
71ba5bf51aSVishal Sagar #define XCSI_ISR_VC0FLVLERR BIT(0)
72ba5bf51aSVishal Sagar
73ba5bf51aSVishal Sagar #define XCSI_ISR_ALLINTR_MASK (0xc07e3fff)
74ba5bf51aSVishal Sagar
75ba5bf51aSVishal Sagar /*
76ba5bf51aSVishal Sagar * Removed VCXFE mask as it doesn't exist in IER
77ba5bf51aSVishal Sagar * Removed STOP state irq as this will keep driver in irq handler only
78ba5bf51aSVishal Sagar */
79ba5bf51aSVishal Sagar #define XCSI_IER_INTR_MASK (XCSI_ISR_ALLINTR_MASK &\
80ba5bf51aSVishal Sagar ~(XCSI_ISR_STOP | XCSI_ISR_VCXFE))
81ba5bf51aSVishal Sagar
82ba5bf51aSVishal Sagar #define XCSI_SPKTR_OFFSET 0x30
83ba5bf51aSVishal Sagar #define XCSI_SPKTR_DATA GENMASK(23, 8)
84ba5bf51aSVishal Sagar #define XCSI_SPKTR_VC GENMASK(7, 6)
85ba5bf51aSVishal Sagar #define XCSI_SPKTR_DT GENMASK(5, 0)
86ba5bf51aSVishal Sagar #define XCSI_SPKT_FIFO_DEPTH 31
87ba5bf51aSVishal Sagar
88ba5bf51aSVishal Sagar #define XCSI_VCXR_OFFSET 0x34
89ba5bf51aSVishal Sagar #define XCSI_VCXR_VCERR GENMASK(23, 0)
90ba5bf51aSVishal Sagar #define XCSI_VCXR_FSYNCERR BIT(1)
91ba5bf51aSVishal Sagar #define XCSI_VCXR_FLVLERR BIT(0)
92ba5bf51aSVishal Sagar
93ba5bf51aSVishal Sagar #define XCSI_CLKINFR_OFFSET 0x3C
94ba5bf51aSVishal Sagar #define XCSI_CLKINFR_STOP BIT(1)
95ba5bf51aSVishal Sagar
96ba5bf51aSVishal Sagar #define XCSI_DLXINFR_OFFSET 0x40
97ba5bf51aSVishal Sagar #define XCSI_DLXINFR_STOP BIT(5)
98ba5bf51aSVishal Sagar #define XCSI_DLXINFR_SOTERR BIT(1)
99ba5bf51aSVishal Sagar #define XCSI_DLXINFR_SOTSYNCERR BIT(0)
100ba5bf51aSVishal Sagar #define XCSI_MAXDL_COUNT 0x4
101ba5bf51aSVishal Sagar
102ba5bf51aSVishal Sagar #define XCSI_VCXINF1R_OFFSET 0x60
103ba5bf51aSVishal Sagar #define XCSI_VCXINF1R_LINECOUNT GENMASK(31, 16)
104ba5bf51aSVishal Sagar #define XCSI_VCXINF1R_LINECOUNT_SHIFT 16
105ba5bf51aSVishal Sagar #define XCSI_VCXINF1R_BYTECOUNT GENMASK(15, 0)
106ba5bf51aSVishal Sagar
107ba5bf51aSVishal Sagar #define XCSI_VCXINF2R_OFFSET 0x64
108ba5bf51aSVishal Sagar #define XCSI_VCXINF2R_DT GENMASK(5, 0)
109ba5bf51aSVishal Sagar #define XCSI_MAXVCX_COUNT 16
110ba5bf51aSVishal Sagar
111ba5bf51aSVishal Sagar /*
112ba5bf51aSVishal Sagar * Sink pad connected to sensor source pad.
113ba5bf51aSVishal Sagar * Source pad connected to next module like demosaic.
114ba5bf51aSVishal Sagar */
115ba5bf51aSVishal Sagar #define XCSI_MEDIA_PADS 2
116ba5bf51aSVishal Sagar #define XCSI_DEFAULT_WIDTH 1920
117ba5bf51aSVishal Sagar #define XCSI_DEFAULT_HEIGHT 1080
118ba5bf51aSVishal Sagar
119ba5bf51aSVishal Sagar #define XCSI_VCX_START 4
120ba5bf51aSVishal Sagar #define XCSI_MAX_VC 4
121ba5bf51aSVishal Sagar #define XCSI_MAX_VCX 16
122ba5bf51aSVishal Sagar
123ba5bf51aSVishal Sagar #define XCSI_NEXTREG_OFFSET 4
124ba5bf51aSVishal Sagar
125ba5bf51aSVishal Sagar /* There are 2 events frame sync and frame level error per VC */
126ba5bf51aSVishal Sagar #define XCSI_VCX_NUM_EVENTS ((XCSI_MAX_VCX - XCSI_MAX_VC) * 2)
127ba5bf51aSVishal Sagar
128ba5bf51aSVishal Sagar /**
129ba5bf51aSVishal Sagar * struct xcsi2rxss_event - Event log structure
130ba5bf51aSVishal Sagar * @mask: Event mask
131ba5bf51aSVishal Sagar * @name: Name of the event
132ba5bf51aSVishal Sagar */
133ba5bf51aSVishal Sagar struct xcsi2rxss_event {
134ba5bf51aSVishal Sagar u32 mask;
135ba5bf51aSVishal Sagar const char *name;
136ba5bf51aSVishal Sagar };
137ba5bf51aSVishal Sagar
138ba5bf51aSVishal Sagar static const struct xcsi2rxss_event xcsi2rxss_events[] = {
139ba5bf51aSVishal Sagar { XCSI_ISR_FR, "Frame Received" },
140ba5bf51aSVishal Sagar { XCSI_ISR_VCXFE, "VCX Frame Errors" },
141ba5bf51aSVishal Sagar { XCSI_ISR_WCC, "Word Count Errors" },
142ba5bf51aSVishal Sagar { XCSI_ISR_ILC, "Invalid Lane Count Error" },
143ba5bf51aSVishal Sagar { XCSI_ISR_SPFIFOF, "Short Packet FIFO OverFlow Error" },
144ba5bf51aSVishal Sagar { XCSI_ISR_SPFIFONE, "Short Packet FIFO Not Empty" },
145ba5bf51aSVishal Sagar { XCSI_ISR_SLBF, "Streamline Buffer Full Error" },
146ba5bf51aSVishal Sagar { XCSI_ISR_STOP, "Lane Stop State" },
147ba5bf51aSVishal Sagar { XCSI_ISR_SOTERR, "SOT Error" },
148ba5bf51aSVishal Sagar { XCSI_ISR_SOTSYNCERR, "SOT Sync Error" },
149ba5bf51aSVishal Sagar { XCSI_ISR_ECC2BERR, "2 Bit ECC Unrecoverable Error" },
150ba5bf51aSVishal Sagar { XCSI_ISR_ECC1BERR, "1 Bit ECC Recoverable Error" },
151ba5bf51aSVishal Sagar { XCSI_ISR_CRCERR, "CRC Error" },
152ba5bf51aSVishal Sagar { XCSI_ISR_DATAIDERR, "Data Id Error" },
153ba5bf51aSVishal Sagar { XCSI_ISR_VC3FSYNCERR, "Virtual Channel 3 Frame Sync Error" },
154ba5bf51aSVishal Sagar { XCSI_ISR_VC3FLVLERR, "Virtual Channel 3 Frame Level Error" },
155ba5bf51aSVishal Sagar { XCSI_ISR_VC2FSYNCERR, "Virtual Channel 2 Frame Sync Error" },
156ba5bf51aSVishal Sagar { XCSI_ISR_VC2FLVLERR, "Virtual Channel 2 Frame Level Error" },
157ba5bf51aSVishal Sagar { XCSI_ISR_VC1FSYNCERR, "Virtual Channel 1 Frame Sync Error" },
158ba5bf51aSVishal Sagar { XCSI_ISR_VC1FLVLERR, "Virtual Channel 1 Frame Level Error" },
159ba5bf51aSVishal Sagar { XCSI_ISR_VC0FSYNCERR, "Virtual Channel 0 Frame Sync Error" },
160ba5bf51aSVishal Sagar { XCSI_ISR_VC0FLVLERR, "Virtual Channel 0 Frame Level Error" }
161ba5bf51aSVishal Sagar };
162ba5bf51aSVishal Sagar
163ba5bf51aSVishal Sagar #define XCSI_NUM_EVENTS ARRAY_SIZE(xcsi2rxss_events)
164ba5bf51aSVishal Sagar
165ba5bf51aSVishal Sagar /*
166ba5bf51aSVishal Sagar * This table provides a mapping between CSI-2 Data type
167ba5bf51aSVishal Sagar * and media bus formats
168ba5bf51aSVishal Sagar */
169ba5bf51aSVishal Sagar static const u32 xcsi2dt_mbus_lut[][2] = {
1702b891d39SLaurent Pinchart { MIPI_CSI2_DT_YUV422_8B, MEDIA_BUS_FMT_UYVY8_1X16 },
1712b891d39SLaurent Pinchart { MIPI_CSI2_DT_YUV422_10B, MEDIA_BUS_FMT_UYVY10_1X20 },
1722b891d39SLaurent Pinchart { MIPI_CSI2_DT_RGB444, 0 },
1732b891d39SLaurent Pinchart { MIPI_CSI2_DT_RGB555, 0 },
1742b891d39SLaurent Pinchart { MIPI_CSI2_DT_RGB565, 0 },
1752b891d39SLaurent Pinchart { MIPI_CSI2_DT_RGB666, 0 },
1762b891d39SLaurent Pinchart { MIPI_CSI2_DT_RGB888, MEDIA_BUS_FMT_RBG888_1X24 },
1772b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW6, 0 },
1782b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW7, 0 },
1792b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW8, MEDIA_BUS_FMT_SRGGB8_1X8 },
1802b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW8, MEDIA_BUS_FMT_SBGGR8_1X8 },
1812b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW8, MEDIA_BUS_FMT_SGBRG8_1X8 },
1822b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW8, MEDIA_BUS_FMT_SGRBG8_1X8 },
1832b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW10, MEDIA_BUS_FMT_SRGGB10_1X10 },
1842b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW10, MEDIA_BUS_FMT_SBGGR10_1X10 },
1852b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW10, MEDIA_BUS_FMT_SGBRG10_1X10 },
1862b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW10, MEDIA_BUS_FMT_SGRBG10_1X10 },
1872b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SRGGB12_1X12 },
1882b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SBGGR12_1X12 },
1892b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SGBRG12_1X12 },
1902b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_SGRBG12_1X12 },
1911a4f8d7dSVolodymyr Kharuk { MIPI_CSI2_DT_RAW12, MEDIA_BUS_FMT_Y12_1X12 },
1922b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SRGGB16_1X16 },
1932b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SBGGR16_1X16 },
1942b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SGBRG16_1X16 },
1952b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW16, MEDIA_BUS_FMT_SGRBG16_1X16 },
1962b891d39SLaurent Pinchart { MIPI_CSI2_DT_RAW20, 0 },
197ba5bf51aSVishal Sagar };
198ba5bf51aSVishal Sagar
199ba5bf51aSVishal Sagar /**
200ba5bf51aSVishal Sagar * struct xcsi2rxss_state - CSI-2 Rx Subsystem device structure
201ba5bf51aSVishal Sagar * @subdev: The v4l2 subdev structure
202ba5bf51aSVishal Sagar * @format: Active V4L2 formats on each pad
203ba5bf51aSVishal Sagar * @default_format: Default V4L2 format
204ba5bf51aSVishal Sagar * @events: counter for events
205ba5bf51aSVishal Sagar * @vcx_events: counter for vcx_events
206ba5bf51aSVishal Sagar * @dev: Platform structure
207ba5bf51aSVishal Sagar * @rsubdev: Remote subdev connected to sink pad
208ba5bf51aSVishal Sagar * @rst_gpio: reset to video_aresetn
209ba5bf51aSVishal Sagar * @clks: array of clocks
210ba5bf51aSVishal Sagar * @iomem: Base address of subsystem
211ba5bf51aSVishal Sagar * @max_num_lanes: Maximum number of lanes present
212ba5bf51aSVishal Sagar * @datatype: Data type filter
213ba5bf51aSVishal Sagar * @lock: mutex for accessing this structure
214ba5bf51aSVishal Sagar * @pads: media pads
215ba5bf51aSVishal Sagar * @streaming: Flag for storing streaming state
216ba5bf51aSVishal Sagar * @enable_active_lanes: If number of active lanes can be modified
217ba5bf51aSVishal Sagar * @en_vcx: If more than 4 VC are enabled
218ba5bf51aSVishal Sagar *
219ba5bf51aSVishal Sagar * This structure contains the device driver related parameters
220ba5bf51aSVishal Sagar */
221ba5bf51aSVishal Sagar struct xcsi2rxss_state {
222ba5bf51aSVishal Sagar struct v4l2_subdev subdev;
223ba5bf51aSVishal Sagar struct v4l2_mbus_framefmt format;
224ba5bf51aSVishal Sagar struct v4l2_mbus_framefmt default_format;
225ba5bf51aSVishal Sagar u32 events[XCSI_NUM_EVENTS];
226ba5bf51aSVishal Sagar u32 vcx_events[XCSI_VCX_NUM_EVENTS];
227ba5bf51aSVishal Sagar struct device *dev;
228ba5bf51aSVishal Sagar struct v4l2_subdev *rsubdev;
229ba5bf51aSVishal Sagar struct gpio_desc *rst_gpio;
230ba5bf51aSVishal Sagar struct clk_bulk_data *clks;
231ba5bf51aSVishal Sagar void __iomem *iomem;
232ba5bf51aSVishal Sagar u32 max_num_lanes;
233ba5bf51aSVishal Sagar u32 datatype;
234ba5bf51aSVishal Sagar /* used to protect access to this struct */
235ba5bf51aSVishal Sagar struct mutex lock;
236ba5bf51aSVishal Sagar struct media_pad pads[XCSI_MEDIA_PADS];
237ba5bf51aSVishal Sagar bool streaming;
238ba5bf51aSVishal Sagar bool enable_active_lanes;
239ba5bf51aSVishal Sagar bool en_vcx;
240ba5bf51aSVishal Sagar };
241ba5bf51aSVishal Sagar
242ba5bf51aSVishal Sagar static const struct clk_bulk_data xcsi2rxss_clks[] = {
243ba5bf51aSVishal Sagar { .id = "lite_aclk" },
244ba5bf51aSVishal Sagar { .id = "video_aclk" },
245ba5bf51aSVishal Sagar };
246ba5bf51aSVishal Sagar
247ba5bf51aSVishal Sagar static inline struct xcsi2rxss_state *
to_xcsi2rxssstate(struct v4l2_subdev * subdev)248ba5bf51aSVishal Sagar to_xcsi2rxssstate(struct v4l2_subdev *subdev)
249ba5bf51aSVishal Sagar {
250ba5bf51aSVishal Sagar return container_of(subdev, struct xcsi2rxss_state, subdev);
251ba5bf51aSVishal Sagar }
252ba5bf51aSVishal Sagar
253ba5bf51aSVishal Sagar /*
254ba5bf51aSVishal Sagar * Register related operations
255ba5bf51aSVishal Sagar */
xcsi2rxss_read(struct xcsi2rxss_state * xcsi2rxss,u32 addr)256ba5bf51aSVishal Sagar static inline u32 xcsi2rxss_read(struct xcsi2rxss_state *xcsi2rxss, u32 addr)
257ba5bf51aSVishal Sagar {
258ba5bf51aSVishal Sagar return ioread32(xcsi2rxss->iomem + addr);
259ba5bf51aSVishal Sagar }
260ba5bf51aSVishal Sagar
xcsi2rxss_write(struct xcsi2rxss_state * xcsi2rxss,u32 addr,u32 value)261ba5bf51aSVishal Sagar static inline void xcsi2rxss_write(struct xcsi2rxss_state *xcsi2rxss, u32 addr,
262ba5bf51aSVishal Sagar u32 value)
263ba5bf51aSVishal Sagar {
264ba5bf51aSVishal Sagar iowrite32(value, xcsi2rxss->iomem + addr);
265ba5bf51aSVishal Sagar }
266ba5bf51aSVishal Sagar
xcsi2rxss_clr(struct xcsi2rxss_state * xcsi2rxss,u32 addr,u32 clr)267ba5bf51aSVishal Sagar static inline void xcsi2rxss_clr(struct xcsi2rxss_state *xcsi2rxss, u32 addr,
268ba5bf51aSVishal Sagar u32 clr)
269ba5bf51aSVishal Sagar {
270ba5bf51aSVishal Sagar xcsi2rxss_write(xcsi2rxss, addr,
271ba5bf51aSVishal Sagar xcsi2rxss_read(xcsi2rxss, addr) & ~clr);
272ba5bf51aSVishal Sagar }
273ba5bf51aSVishal Sagar
xcsi2rxss_set(struct xcsi2rxss_state * xcsi2rxss,u32 addr,u32 set)274ba5bf51aSVishal Sagar static inline void xcsi2rxss_set(struct xcsi2rxss_state *xcsi2rxss, u32 addr,
275ba5bf51aSVishal Sagar u32 set)
276ba5bf51aSVishal Sagar {
277ba5bf51aSVishal Sagar xcsi2rxss_write(xcsi2rxss, addr, xcsi2rxss_read(xcsi2rxss, addr) | set);
278ba5bf51aSVishal Sagar }
279ba5bf51aSVishal Sagar
280ba5bf51aSVishal Sagar /*
281ba5bf51aSVishal Sagar * This function returns the nth mbus for a data type.
282ba5bf51aSVishal Sagar * In case of error, mbus code returned is 0.
283ba5bf51aSVishal Sagar */
xcsi2rxss_get_nth_mbus(u32 dt,u32 n)284ba5bf51aSVishal Sagar static u32 xcsi2rxss_get_nth_mbus(u32 dt, u32 n)
285ba5bf51aSVishal Sagar {
286ba5bf51aSVishal Sagar unsigned int i;
287ba5bf51aSVishal Sagar
288ba5bf51aSVishal Sagar for (i = 0; i < ARRAY_SIZE(xcsi2dt_mbus_lut); i++) {
289ba5bf51aSVishal Sagar if (xcsi2dt_mbus_lut[i][0] == dt) {
290ba5bf51aSVishal Sagar if (n-- == 0)
291ba5bf51aSVishal Sagar return xcsi2dt_mbus_lut[i][1];
292ba5bf51aSVishal Sagar }
293ba5bf51aSVishal Sagar }
294ba5bf51aSVishal Sagar
295ba5bf51aSVishal Sagar return 0;
296ba5bf51aSVishal Sagar }
297ba5bf51aSVishal Sagar
298ba5bf51aSVishal Sagar /* This returns the data type for a media bus format else 0 */
xcsi2rxss_get_dt(u32 mbus)299ba5bf51aSVishal Sagar static u32 xcsi2rxss_get_dt(u32 mbus)
300ba5bf51aSVishal Sagar {
301ba5bf51aSVishal Sagar unsigned int i;
302ba5bf51aSVishal Sagar
303ba5bf51aSVishal Sagar for (i = 0; i < ARRAY_SIZE(xcsi2dt_mbus_lut); i++) {
304ba5bf51aSVishal Sagar if (xcsi2dt_mbus_lut[i][1] == mbus)
305ba5bf51aSVishal Sagar return xcsi2dt_mbus_lut[i][0];
306ba5bf51aSVishal Sagar }
307ba5bf51aSVishal Sagar
308ba5bf51aSVishal Sagar return 0;
309ba5bf51aSVishal Sagar }
310ba5bf51aSVishal Sagar
311ba5bf51aSVishal Sagar /**
312ba5bf51aSVishal Sagar * xcsi2rxss_soft_reset - Does a soft reset of the MIPI CSI-2 Rx Subsystem
313ba5bf51aSVishal Sagar * @state: Xilinx CSI-2 Rx Subsystem structure pointer
314ba5bf51aSVishal Sagar *
315ba5bf51aSVishal Sagar * Core takes less than 100 video clock cycles to reset.
316ba5bf51aSVishal Sagar * So a larger timeout value is chosen for margin.
317ba5bf51aSVishal Sagar *
318ba5bf51aSVishal Sagar * Return: 0 - on success OR -ETIME if reset times out
319ba5bf51aSVishal Sagar */
xcsi2rxss_soft_reset(struct xcsi2rxss_state * state)320ba5bf51aSVishal Sagar static int xcsi2rxss_soft_reset(struct xcsi2rxss_state *state)
321ba5bf51aSVishal Sagar {
322ba5bf51aSVishal Sagar u32 timeout = 1000; /* us */
323ba5bf51aSVishal Sagar
324ba5bf51aSVishal Sagar xcsi2rxss_set(state, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET);
325ba5bf51aSVishal Sagar
326ba5bf51aSVishal Sagar while (xcsi2rxss_read(state, XCSI_CSR_OFFSET) & XCSI_CSR_RIPCD) {
327ba5bf51aSVishal Sagar if (timeout == 0) {
328ba5bf51aSVishal Sagar dev_err(state->dev, "soft reset timed out!\n");
329ba5bf51aSVishal Sagar return -ETIME;
330ba5bf51aSVishal Sagar }
331ba5bf51aSVishal Sagar
332ba5bf51aSVishal Sagar timeout--;
333ba5bf51aSVishal Sagar udelay(1);
334ba5bf51aSVishal Sagar }
335ba5bf51aSVishal Sagar
336ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_SOFTRESET);
337ba5bf51aSVishal Sagar return 0;
338ba5bf51aSVishal Sagar }
339ba5bf51aSVishal Sagar
xcsi2rxss_hard_reset(struct xcsi2rxss_state * state)340ba5bf51aSVishal Sagar static void xcsi2rxss_hard_reset(struct xcsi2rxss_state *state)
341ba5bf51aSVishal Sagar {
342ba5bf51aSVishal Sagar if (!state->rst_gpio)
343ba5bf51aSVishal Sagar return;
344ba5bf51aSVishal Sagar
345ba5bf51aSVishal Sagar /* minimum of 40 dphy_clk_200M cycles */
346ba5bf51aSVishal Sagar gpiod_set_value_cansleep(state->rst_gpio, 1);
347ba5bf51aSVishal Sagar usleep_range(1, 2);
348ba5bf51aSVishal Sagar gpiod_set_value_cansleep(state->rst_gpio, 0);
349ba5bf51aSVishal Sagar }
350ba5bf51aSVishal Sagar
xcsi2rxss_reset_event_counters(struct xcsi2rxss_state * state)351ba5bf51aSVishal Sagar static void xcsi2rxss_reset_event_counters(struct xcsi2rxss_state *state)
352ba5bf51aSVishal Sagar {
353ba5bf51aSVishal Sagar unsigned int i;
354ba5bf51aSVishal Sagar
355ba5bf51aSVishal Sagar for (i = 0; i < XCSI_NUM_EVENTS; i++)
356ba5bf51aSVishal Sagar state->events[i] = 0;
357ba5bf51aSVishal Sagar
358ba5bf51aSVishal Sagar for (i = 0; i < XCSI_VCX_NUM_EVENTS; i++)
359ba5bf51aSVishal Sagar state->vcx_events[i] = 0;
360ba5bf51aSVishal Sagar }
361ba5bf51aSVishal Sagar
362ba5bf51aSVishal Sagar /* Print event counters */
xcsi2rxss_log_counters(struct xcsi2rxss_state * state)363ba5bf51aSVishal Sagar static void xcsi2rxss_log_counters(struct xcsi2rxss_state *state)
364ba5bf51aSVishal Sagar {
365ba5bf51aSVishal Sagar struct device *dev = state->dev;
366ba5bf51aSVishal Sagar unsigned int i;
367ba5bf51aSVishal Sagar
368ba5bf51aSVishal Sagar for (i = 0; i < XCSI_NUM_EVENTS; i++) {
369ba5bf51aSVishal Sagar if (state->events[i] > 0) {
370ba5bf51aSVishal Sagar dev_info(dev, "%s events: %d\n",
371ba5bf51aSVishal Sagar xcsi2rxss_events[i].name,
372ba5bf51aSVishal Sagar state->events[i]);
373ba5bf51aSVishal Sagar }
374ba5bf51aSVishal Sagar }
375ba5bf51aSVishal Sagar
376ba5bf51aSVishal Sagar if (state->en_vcx) {
377ba5bf51aSVishal Sagar for (i = 0; i < XCSI_VCX_NUM_EVENTS; i++) {
378ba5bf51aSVishal Sagar if (state->vcx_events[i] > 0) {
379ba5bf51aSVishal Sagar dev_info(dev,
380ba5bf51aSVishal Sagar "VC %d Frame %s err vcx events: %d\n",
381ba5bf51aSVishal Sagar (i / 2) + XCSI_VCX_START,
382ba5bf51aSVishal Sagar i & 1 ? "Sync" : "Level",
383ba5bf51aSVishal Sagar state->vcx_events[i]);
384ba5bf51aSVishal Sagar }
385ba5bf51aSVishal Sagar }
386ba5bf51aSVishal Sagar }
387ba5bf51aSVishal Sagar }
388ba5bf51aSVishal Sagar
389ba5bf51aSVishal Sagar /**
390ba5bf51aSVishal Sagar * xcsi2rxss_log_status - Logs the status of the CSI-2 Receiver
391ba5bf51aSVishal Sagar * @sd: Pointer to V4L2 subdevice structure
392ba5bf51aSVishal Sagar *
393ba5bf51aSVishal Sagar * This function prints the current status of Xilinx MIPI CSI-2
394ba5bf51aSVishal Sagar *
395ba5bf51aSVishal Sagar * Return: 0 on success
396ba5bf51aSVishal Sagar */
xcsi2rxss_log_status(struct v4l2_subdev * sd)397ba5bf51aSVishal Sagar static int xcsi2rxss_log_status(struct v4l2_subdev *sd)
398ba5bf51aSVishal Sagar {
399ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
400ba5bf51aSVishal Sagar struct device *dev = xcsi2rxss->dev;
401ba5bf51aSVishal Sagar u32 reg, data;
402ba5bf51aSVishal Sagar unsigned int i, max_vc;
403ba5bf51aSVishal Sagar
404ba5bf51aSVishal Sagar mutex_lock(&xcsi2rxss->lock);
405ba5bf51aSVishal Sagar
406ba5bf51aSVishal Sagar xcsi2rxss_log_counters(xcsi2rxss);
407ba5bf51aSVishal Sagar
408ba5bf51aSVishal Sagar dev_info(dev, "***** Core Status *****\n");
409ba5bf51aSVishal Sagar data = xcsi2rxss_read(xcsi2rxss, XCSI_CSR_OFFSET);
410ba5bf51aSVishal Sagar dev_info(dev, "Short Packet FIFO Full = %s\n",
411ba5bf51aSVishal Sagar data & XCSI_CSR_SPFIFOFULL ? "true" : "false");
412ba5bf51aSVishal Sagar dev_info(dev, "Short Packet FIFO Not Empty = %s\n",
413ba5bf51aSVishal Sagar data & XCSI_CSR_SPFIFONE ? "true" : "false");
414ba5bf51aSVishal Sagar dev_info(dev, "Stream line buffer full = %s\n",
415ba5bf51aSVishal Sagar data & XCSI_CSR_SLBF ? "true" : "false");
416ba5bf51aSVishal Sagar dev_info(dev, "Soft reset/Core disable in progress = %s\n",
417ba5bf51aSVishal Sagar data & XCSI_CSR_RIPCD ? "true" : "false");
418ba5bf51aSVishal Sagar
419ba5bf51aSVishal Sagar /* Clk & Lane Info */
420ba5bf51aSVishal Sagar dev_info(dev, "******** Clock Lane Info *********\n");
421ba5bf51aSVishal Sagar data = xcsi2rxss_read(xcsi2rxss, XCSI_CLKINFR_OFFSET);
422ba5bf51aSVishal Sagar dev_info(dev, "Clock Lane in Stop State = %s\n",
423ba5bf51aSVishal Sagar data & XCSI_CLKINFR_STOP ? "true" : "false");
424ba5bf51aSVishal Sagar
425ba5bf51aSVishal Sagar dev_info(dev, "******** Data Lane Info *********\n");
426ba5bf51aSVishal Sagar dev_info(dev, "Lane\tSoT Error\tSoT Sync Error\tStop State\n");
427ba5bf51aSVishal Sagar reg = XCSI_DLXINFR_OFFSET;
428ba5bf51aSVishal Sagar for (i = 0; i < XCSI_MAXDL_COUNT; i++) {
429ba5bf51aSVishal Sagar data = xcsi2rxss_read(xcsi2rxss, reg);
430ba5bf51aSVishal Sagar
431ba5bf51aSVishal Sagar dev_info(dev, "%d\t%s\t\t%s\t\t%s\n", i,
432ba5bf51aSVishal Sagar data & XCSI_DLXINFR_SOTERR ? "true" : "false",
433ba5bf51aSVishal Sagar data & XCSI_DLXINFR_SOTSYNCERR ? "true" : "false",
434ba5bf51aSVishal Sagar data & XCSI_DLXINFR_STOP ? "true" : "false");
435ba5bf51aSVishal Sagar
436ba5bf51aSVishal Sagar reg += XCSI_NEXTREG_OFFSET;
437ba5bf51aSVishal Sagar }
438ba5bf51aSVishal Sagar
439ba5bf51aSVishal Sagar /* Virtual Channel Image Information */
440ba5bf51aSVishal Sagar dev_info(dev, "********** Virtual Channel Info ************\n");
441ba5bf51aSVishal Sagar dev_info(dev, "VC\tLine Count\tByte Count\tData Type\n");
442ba5bf51aSVishal Sagar if (xcsi2rxss->en_vcx)
443ba5bf51aSVishal Sagar max_vc = XCSI_MAX_VCX;
444ba5bf51aSVishal Sagar else
445ba5bf51aSVishal Sagar max_vc = XCSI_MAX_VC;
446ba5bf51aSVishal Sagar
447ba5bf51aSVishal Sagar reg = XCSI_VCXINF1R_OFFSET;
448ba5bf51aSVishal Sagar for (i = 0; i < max_vc; i++) {
449ba5bf51aSVishal Sagar u32 line_count, byte_count, data_type;
450ba5bf51aSVishal Sagar
451ba5bf51aSVishal Sagar /* Get line and byte count from VCXINFR1 Register */
452ba5bf51aSVishal Sagar data = xcsi2rxss_read(xcsi2rxss, reg);
453ba5bf51aSVishal Sagar byte_count = data & XCSI_VCXINF1R_BYTECOUNT;
454ba5bf51aSVishal Sagar line_count = data & XCSI_VCXINF1R_LINECOUNT;
455ba5bf51aSVishal Sagar line_count >>= XCSI_VCXINF1R_LINECOUNT_SHIFT;
456ba5bf51aSVishal Sagar
457ba5bf51aSVishal Sagar /* Get data type from VCXINFR2 Register */
458ba5bf51aSVishal Sagar reg += XCSI_NEXTREG_OFFSET;
459ba5bf51aSVishal Sagar data = xcsi2rxss_read(xcsi2rxss, reg);
460ba5bf51aSVishal Sagar data_type = data & XCSI_VCXINF2R_DT;
461ba5bf51aSVishal Sagar
462ba5bf51aSVishal Sagar dev_info(dev, "%d\t%d\t\t%d\t\t0x%x\n", i, line_count,
463ba5bf51aSVishal Sagar byte_count, data_type);
464ba5bf51aSVishal Sagar
465ba5bf51aSVishal Sagar /* Move to next pair of VC Info registers */
466ba5bf51aSVishal Sagar reg += XCSI_NEXTREG_OFFSET;
467ba5bf51aSVishal Sagar }
468ba5bf51aSVishal Sagar
469ba5bf51aSVishal Sagar mutex_unlock(&xcsi2rxss->lock);
470ba5bf51aSVishal Sagar
471ba5bf51aSVishal Sagar return 0;
472ba5bf51aSVishal Sagar }
473ba5bf51aSVishal Sagar
xcsi2rxss_get_remote_subdev(struct media_pad * local)474ba5bf51aSVishal Sagar static struct v4l2_subdev *xcsi2rxss_get_remote_subdev(struct media_pad *local)
475ba5bf51aSVishal Sagar {
476ba5bf51aSVishal Sagar struct media_pad *remote;
477ba5bf51aSVishal Sagar
478b2e44430SLaurent Pinchart remote = media_pad_remote_pad_first(local);
479ba5bf51aSVishal Sagar if (!remote || !is_media_entity_v4l2_subdev(remote->entity))
480ba5bf51aSVishal Sagar return NULL;
481ba5bf51aSVishal Sagar
482ba5bf51aSVishal Sagar return media_entity_to_v4l2_subdev(remote->entity);
483ba5bf51aSVishal Sagar }
484ba5bf51aSVishal Sagar
xcsi2rxss_start_stream(struct xcsi2rxss_state * state)485ba5bf51aSVishal Sagar static int xcsi2rxss_start_stream(struct xcsi2rxss_state *state)
486ba5bf51aSVishal Sagar {
487ba5bf51aSVishal Sagar int ret = 0;
488ba5bf51aSVishal Sagar
489ba5bf51aSVishal Sagar /* enable core */
490ba5bf51aSVishal Sagar xcsi2rxss_set(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE);
491ba5bf51aSVishal Sagar
492ba5bf51aSVishal Sagar ret = xcsi2rxss_soft_reset(state);
493ba5bf51aSVishal Sagar if (ret) {
494ba5bf51aSVishal Sagar state->streaming = false;
495ba5bf51aSVishal Sagar return ret;
496ba5bf51aSVishal Sagar }
497ba5bf51aSVishal Sagar
498ba5bf51aSVishal Sagar /* enable interrupts */
499ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE);
500ba5bf51aSVishal Sagar xcsi2rxss_write(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK);
501ba5bf51aSVishal Sagar xcsi2rxss_set(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE);
502ba5bf51aSVishal Sagar
503ba5bf51aSVishal Sagar state->streaming = true;
504ba5bf51aSVishal Sagar
505ba5bf51aSVishal Sagar state->rsubdev =
506ba5bf51aSVishal Sagar xcsi2rxss_get_remote_subdev(&state->pads[XVIP_PAD_SINK]);
507ba5bf51aSVishal Sagar
508ba5bf51aSVishal Sagar ret = v4l2_subdev_call(state->rsubdev, video, s_stream, 1);
509ba5bf51aSVishal Sagar if (ret) {
510ba5bf51aSVishal Sagar /* disable interrupts */
511ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK);
512ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE);
513ba5bf51aSVishal Sagar
514ba5bf51aSVishal Sagar /* disable core */
515ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE);
516ba5bf51aSVishal Sagar state->streaming = false;
517ba5bf51aSVishal Sagar }
518ba5bf51aSVishal Sagar
519ba5bf51aSVishal Sagar return ret;
520ba5bf51aSVishal Sagar }
521ba5bf51aSVishal Sagar
xcsi2rxss_stop_stream(struct xcsi2rxss_state * state)522ba5bf51aSVishal Sagar static void xcsi2rxss_stop_stream(struct xcsi2rxss_state *state)
523ba5bf51aSVishal Sagar {
524ba5bf51aSVishal Sagar v4l2_subdev_call(state->rsubdev, video, s_stream, 0);
525ba5bf51aSVishal Sagar
526ba5bf51aSVishal Sagar /* disable interrupts */
527ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK);
528ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE);
529ba5bf51aSVishal Sagar
530ba5bf51aSVishal Sagar /* disable core */
531ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE);
532ba5bf51aSVishal Sagar state->streaming = false;
533ba5bf51aSVishal Sagar }
534ba5bf51aSVishal Sagar
535ba5bf51aSVishal Sagar /**
536ba5bf51aSVishal Sagar * xcsi2rxss_irq_handler - Interrupt handler for CSI-2
537ba5bf51aSVishal Sagar * @irq: IRQ number
538ba5bf51aSVishal Sagar * @data: Pointer to device state
539ba5bf51aSVishal Sagar *
540ba5bf51aSVishal Sagar * In the interrupt handler, a list of event counters are updated for
541ba5bf51aSVishal Sagar * corresponding interrupts. This is useful to get status / debug.
542ba5bf51aSVishal Sagar *
543ba5bf51aSVishal Sagar * Return: IRQ_HANDLED after handling interrupts
544ba5bf51aSVishal Sagar */
xcsi2rxss_irq_handler(int irq,void * data)545ba5bf51aSVishal Sagar static irqreturn_t xcsi2rxss_irq_handler(int irq, void *data)
546ba5bf51aSVishal Sagar {
547ba5bf51aSVishal Sagar struct xcsi2rxss_state *state = (struct xcsi2rxss_state *)data;
548ba5bf51aSVishal Sagar struct device *dev = state->dev;
549ba5bf51aSVishal Sagar u32 status;
550ba5bf51aSVishal Sagar
551ba5bf51aSVishal Sagar status = xcsi2rxss_read(state, XCSI_ISR_OFFSET) & XCSI_ISR_ALLINTR_MASK;
552ba5bf51aSVishal Sagar xcsi2rxss_write(state, XCSI_ISR_OFFSET, status);
553ba5bf51aSVishal Sagar
554ba5bf51aSVishal Sagar /* Received a short packet */
555ba5bf51aSVishal Sagar if (status & XCSI_ISR_SPFIFONE) {
556ba5bf51aSVishal Sagar u32 count = 0;
557ba5bf51aSVishal Sagar
558ba5bf51aSVishal Sagar /*
559ba5bf51aSVishal Sagar * Drain generic short packet FIFO by reading max 31
560ba5bf51aSVishal Sagar * (fifo depth) short packets from fifo or till fifo is empty.
561ba5bf51aSVishal Sagar */
562ba5bf51aSVishal Sagar for (count = 0; count < XCSI_SPKT_FIFO_DEPTH; ++count) {
563ba5bf51aSVishal Sagar u32 spfifostat, spkt;
564ba5bf51aSVishal Sagar
565ba5bf51aSVishal Sagar spkt = xcsi2rxss_read(state, XCSI_SPKTR_OFFSET);
566ba5bf51aSVishal Sagar dev_dbg(dev, "Short packet = 0x%08x\n", spkt);
567ba5bf51aSVishal Sagar spfifostat = xcsi2rxss_read(state, XCSI_ISR_OFFSET);
568ba5bf51aSVishal Sagar spfifostat &= XCSI_ISR_SPFIFONE;
569ba5bf51aSVishal Sagar if (!spfifostat)
570ba5bf51aSVishal Sagar break;
571ba5bf51aSVishal Sagar xcsi2rxss_write(state, XCSI_ISR_OFFSET, spfifostat);
572ba5bf51aSVishal Sagar }
573ba5bf51aSVishal Sagar }
574ba5bf51aSVishal Sagar
575ba5bf51aSVishal Sagar /* Short packet FIFO overflow */
576ba5bf51aSVishal Sagar if (status & XCSI_ISR_SPFIFOF)
577ba5bf51aSVishal Sagar dev_dbg_ratelimited(dev, "Short packet FIFO overflowed\n");
578ba5bf51aSVishal Sagar
579ba5bf51aSVishal Sagar /*
580ba5bf51aSVishal Sagar * Stream line buffer full
581ba5bf51aSVishal Sagar * This means there is a backpressure from downstream IP
582ba5bf51aSVishal Sagar */
583ba5bf51aSVishal Sagar if (status & XCSI_ISR_SLBF) {
584ba5bf51aSVishal Sagar dev_alert_ratelimited(dev, "Stream Line Buffer Full!\n");
585ba5bf51aSVishal Sagar
586ba5bf51aSVishal Sagar /* disable interrupts */
587ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_IER_OFFSET, XCSI_IER_INTR_MASK);
588ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_GIER_OFFSET, XCSI_GIER_GIE);
589ba5bf51aSVishal Sagar
590ba5bf51aSVishal Sagar /* disable core */
591ba5bf51aSVishal Sagar xcsi2rxss_clr(state, XCSI_CCR_OFFSET, XCSI_CCR_ENABLE);
592ba5bf51aSVishal Sagar
593ba5bf51aSVishal Sagar /*
594ba5bf51aSVishal Sagar * The IP needs to be hard reset before it can be used now.
595ba5bf51aSVishal Sagar * This will be done in streamoff.
596ba5bf51aSVishal Sagar */
597ba5bf51aSVishal Sagar
598ba5bf51aSVishal Sagar /*
599ba5bf51aSVishal Sagar * TODO: Notify the whole pipeline with v4l2_subdev_notify() to
600ba5bf51aSVishal Sagar * inform userspace.
601ba5bf51aSVishal Sagar */
602ba5bf51aSVishal Sagar }
603ba5bf51aSVishal Sagar
604ba5bf51aSVishal Sagar /* Increment event counters */
605ba5bf51aSVishal Sagar if (status & XCSI_ISR_ALLINTR_MASK) {
606ba5bf51aSVishal Sagar unsigned int i;
607ba5bf51aSVishal Sagar
608ba5bf51aSVishal Sagar for (i = 0; i < XCSI_NUM_EVENTS; i++) {
609ba5bf51aSVishal Sagar if (!(status & xcsi2rxss_events[i].mask))
610ba5bf51aSVishal Sagar continue;
611ba5bf51aSVishal Sagar state->events[i]++;
612ba5bf51aSVishal Sagar dev_dbg_ratelimited(dev, "%s: %u\n",
613ba5bf51aSVishal Sagar xcsi2rxss_events[i].name,
614ba5bf51aSVishal Sagar state->events[i]);
615ba5bf51aSVishal Sagar }
616ba5bf51aSVishal Sagar
617ba5bf51aSVishal Sagar if (status & XCSI_ISR_VCXFE && state->en_vcx) {
618ba5bf51aSVishal Sagar u32 vcxstatus;
619ba5bf51aSVishal Sagar
620ba5bf51aSVishal Sagar vcxstatus = xcsi2rxss_read(state, XCSI_VCXR_OFFSET);
621ba5bf51aSVishal Sagar vcxstatus &= XCSI_VCXR_VCERR;
622ba5bf51aSVishal Sagar for (i = 0; i < XCSI_VCX_NUM_EVENTS; i++) {
623ba5bf51aSVishal Sagar if (!(vcxstatus & BIT(i)))
624ba5bf51aSVishal Sagar continue;
625ba5bf51aSVishal Sagar state->vcx_events[i]++;
626ba5bf51aSVishal Sagar }
627ba5bf51aSVishal Sagar xcsi2rxss_write(state, XCSI_VCXR_OFFSET, vcxstatus);
628ba5bf51aSVishal Sagar }
629ba5bf51aSVishal Sagar }
630ba5bf51aSVishal Sagar
631ba5bf51aSVishal Sagar return IRQ_HANDLED;
632ba5bf51aSVishal Sagar }
633ba5bf51aSVishal Sagar
634ba5bf51aSVishal Sagar /**
635ba5bf51aSVishal Sagar * xcsi2rxss_s_stream - It is used to start/stop the streaming.
636ba5bf51aSVishal Sagar * @sd: V4L2 Sub device
637ba5bf51aSVishal Sagar * @enable: Flag (True / False)
638ba5bf51aSVishal Sagar *
639ba5bf51aSVishal Sagar * This function controls the start or stop of streaming for the
640ba5bf51aSVishal Sagar * Xilinx MIPI CSI-2 Rx Subsystem.
641ba5bf51aSVishal Sagar *
642ba5bf51aSVishal Sagar * Return: 0 on success, errors otherwise
643ba5bf51aSVishal Sagar */
xcsi2rxss_s_stream(struct v4l2_subdev * sd,int enable)644ba5bf51aSVishal Sagar static int xcsi2rxss_s_stream(struct v4l2_subdev *sd, int enable)
645ba5bf51aSVishal Sagar {
646ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
647ba5bf51aSVishal Sagar int ret = 0;
648ba5bf51aSVishal Sagar
649ba5bf51aSVishal Sagar mutex_lock(&xcsi2rxss->lock);
650ba5bf51aSVishal Sagar
651ba5bf51aSVishal Sagar if (enable == xcsi2rxss->streaming)
652ba5bf51aSVishal Sagar goto stream_done;
653ba5bf51aSVishal Sagar
654ba5bf51aSVishal Sagar if (enable) {
655ba5bf51aSVishal Sagar xcsi2rxss_reset_event_counters(xcsi2rxss);
656ba5bf51aSVishal Sagar ret = xcsi2rxss_start_stream(xcsi2rxss);
657ba5bf51aSVishal Sagar } else {
658ba5bf51aSVishal Sagar xcsi2rxss_stop_stream(xcsi2rxss);
659ba5bf51aSVishal Sagar xcsi2rxss_hard_reset(xcsi2rxss);
660ba5bf51aSVishal Sagar }
661ba5bf51aSVishal Sagar
662ba5bf51aSVishal Sagar stream_done:
663ba5bf51aSVishal Sagar mutex_unlock(&xcsi2rxss->lock);
664ba5bf51aSVishal Sagar return ret;
665ba5bf51aSVishal Sagar }
666ba5bf51aSVishal Sagar
667ba5bf51aSVishal Sagar static struct v4l2_mbus_framefmt *
__xcsi2rxss_get_pad_format(struct xcsi2rxss_state * xcsi2rxss,struct v4l2_subdev_state * sd_state,unsigned int pad,u32 which)668ba5bf51aSVishal Sagar __xcsi2rxss_get_pad_format(struct xcsi2rxss_state *xcsi2rxss,
6690d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
670ba5bf51aSVishal Sagar unsigned int pad, u32 which)
671ba5bf51aSVishal Sagar {
672ba5bf51aSVishal Sagar switch (which) {
673ba5bf51aSVishal Sagar case V4L2_SUBDEV_FORMAT_TRY:
6740d346d2aSTomi Valkeinen return v4l2_subdev_get_try_format(&xcsi2rxss->subdev,
6750d346d2aSTomi Valkeinen sd_state, pad);
676ba5bf51aSVishal Sagar case V4L2_SUBDEV_FORMAT_ACTIVE:
677ba5bf51aSVishal Sagar return &xcsi2rxss->format;
678ba5bf51aSVishal Sagar default:
679ba5bf51aSVishal Sagar return NULL;
680ba5bf51aSVishal Sagar }
681ba5bf51aSVishal Sagar }
682ba5bf51aSVishal Sagar
683ba5bf51aSVishal Sagar /**
684ba5bf51aSVishal Sagar * xcsi2rxss_init_cfg - Initialise the pad format config to default
685ba5bf51aSVishal Sagar * @sd: Pointer to V4L2 Sub device structure
6860d346d2aSTomi Valkeinen * @sd_state: Pointer to sub device state structure
687ba5bf51aSVishal Sagar *
688ba5bf51aSVishal Sagar * This function is used to initialize the pad format with the default
689ba5bf51aSVishal Sagar * values.
690ba5bf51aSVishal Sagar *
691ba5bf51aSVishal Sagar * Return: 0 on success
692ba5bf51aSVishal Sagar */
xcsi2rxss_init_cfg(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state)693ba5bf51aSVishal Sagar static int xcsi2rxss_init_cfg(struct v4l2_subdev *sd,
6940d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state)
695ba5bf51aSVishal Sagar {
696ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
697ba5bf51aSVishal Sagar struct v4l2_mbus_framefmt *format;
698ba5bf51aSVishal Sagar unsigned int i;
699ba5bf51aSVishal Sagar
700ba5bf51aSVishal Sagar mutex_lock(&xcsi2rxss->lock);
701ba5bf51aSVishal Sagar for (i = 0; i < XCSI_MEDIA_PADS; i++) {
7020d346d2aSTomi Valkeinen format = v4l2_subdev_get_try_format(sd, sd_state, i);
703ba5bf51aSVishal Sagar *format = xcsi2rxss->default_format;
704ba5bf51aSVishal Sagar }
705ba5bf51aSVishal Sagar mutex_unlock(&xcsi2rxss->lock);
706ba5bf51aSVishal Sagar
707ba5bf51aSVishal Sagar return 0;
708ba5bf51aSVishal Sagar }
709ba5bf51aSVishal Sagar
710ba5bf51aSVishal Sagar /**
711ba5bf51aSVishal Sagar * xcsi2rxss_get_format - Get the pad format
712ba5bf51aSVishal Sagar * @sd: Pointer to V4L2 Sub device structure
7130d346d2aSTomi Valkeinen * @sd_state: Pointer to sub device state structure
714ba5bf51aSVishal Sagar * @fmt: Pointer to pad level media bus format
715ba5bf51aSVishal Sagar *
716ba5bf51aSVishal Sagar * This function is used to get the pad format information.
717ba5bf51aSVishal Sagar *
718ba5bf51aSVishal Sagar * Return: 0 on success
719ba5bf51aSVishal Sagar */
xcsi2rxss_get_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)720ba5bf51aSVishal Sagar static int xcsi2rxss_get_format(struct v4l2_subdev *sd,
7210d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
722ba5bf51aSVishal Sagar struct v4l2_subdev_format *fmt)
723ba5bf51aSVishal Sagar {
724ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
725ba5bf51aSVishal Sagar
726ba5bf51aSVishal Sagar mutex_lock(&xcsi2rxss->lock);
7270d346d2aSTomi Valkeinen fmt->format = *__xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
7280d346d2aSTomi Valkeinen fmt->pad,
729ba5bf51aSVishal Sagar fmt->which);
730ba5bf51aSVishal Sagar mutex_unlock(&xcsi2rxss->lock);
731ba5bf51aSVishal Sagar
732ba5bf51aSVishal Sagar return 0;
733ba5bf51aSVishal Sagar }
734ba5bf51aSVishal Sagar
735ba5bf51aSVishal Sagar /**
736ba5bf51aSVishal Sagar * xcsi2rxss_set_format - This is used to set the pad format
737ba5bf51aSVishal Sagar * @sd: Pointer to V4L2 Sub device structure
7380d346d2aSTomi Valkeinen * @sd_state: Pointer to sub device state structure
739ba5bf51aSVishal Sagar * @fmt: Pointer to pad level media bus format
740ba5bf51aSVishal Sagar *
741ba5bf51aSVishal Sagar * This function is used to set the pad format. Since the pad format is fixed
742ba5bf51aSVishal Sagar * in hardware, it can't be modified on run time. So when a format set is
743ba5bf51aSVishal Sagar * requested by application, all parameters except the format type is saved
744ba5bf51aSVishal Sagar * for the pad and the original pad format is sent back to the application.
745ba5bf51aSVishal Sagar *
746ba5bf51aSVishal Sagar * Return: 0 on success
747ba5bf51aSVishal Sagar */
xcsi2rxss_set_format(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_format * fmt)748ba5bf51aSVishal Sagar static int xcsi2rxss_set_format(struct v4l2_subdev *sd,
7490d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
750ba5bf51aSVishal Sagar struct v4l2_subdev_format *fmt)
751ba5bf51aSVishal Sagar {
752ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss = to_xcsi2rxssstate(sd);
753ba5bf51aSVishal Sagar struct v4l2_mbus_framefmt *__format;
754ba5bf51aSVishal Sagar u32 dt;
755ba5bf51aSVishal Sagar
756ba5bf51aSVishal Sagar mutex_lock(&xcsi2rxss->lock);
757ba5bf51aSVishal Sagar
758ba5bf51aSVishal Sagar /*
759ba5bf51aSVishal Sagar * Only the format->code parameter matters for CSI as the
760ba5bf51aSVishal Sagar * CSI format cannot be changed at runtime.
761ba5bf51aSVishal Sagar * Ensure that format to set is copied to over to CSI pad format
762ba5bf51aSVishal Sagar */
7630d346d2aSTomi Valkeinen __format = __xcsi2rxss_get_pad_format(xcsi2rxss, sd_state,
764ba5bf51aSVishal Sagar fmt->pad, fmt->which);
765ba5bf51aSVishal Sagar
766ba5bf51aSVishal Sagar /* only sink pad format can be updated */
767ba5bf51aSVishal Sagar if (fmt->pad == XVIP_PAD_SOURCE) {
768ba5bf51aSVishal Sagar fmt->format = *__format;
769ba5bf51aSVishal Sagar mutex_unlock(&xcsi2rxss->lock);
770ba5bf51aSVishal Sagar return 0;
771ba5bf51aSVishal Sagar }
772ba5bf51aSVishal Sagar
773ba5bf51aSVishal Sagar /*
774ba5bf51aSVishal Sagar * RAW8 is supported in all datatypes. So if requested media bus format
775ba5bf51aSVishal Sagar * is of RAW8 type, then allow to be set. In case core is configured to
776ba5bf51aSVishal Sagar * other RAW, YUV422 8/10 or RGB888, set appropriate media bus format.
777ba5bf51aSVishal Sagar */
778ba5bf51aSVishal Sagar dt = xcsi2rxss_get_dt(fmt->format.code);
7792b891d39SLaurent Pinchart if (dt != xcsi2rxss->datatype && dt != MIPI_CSI2_DT_RAW8) {
780ba5bf51aSVishal Sagar dev_dbg(xcsi2rxss->dev, "Unsupported media bus format");
781ba5bf51aSVishal Sagar /* set the default format for the data type */
782ba5bf51aSVishal Sagar fmt->format.code = xcsi2rxss_get_nth_mbus(xcsi2rxss->datatype,
783ba5bf51aSVishal Sagar 0);
784ba5bf51aSVishal Sagar }
785ba5bf51aSVishal Sagar
786ba5bf51aSVishal Sagar *__format = fmt->format;
787ba5bf51aSVishal Sagar mutex_unlock(&xcsi2rxss->lock);
788ba5bf51aSVishal Sagar
789ba5bf51aSVishal Sagar return 0;
790ba5bf51aSVishal Sagar }
791ba5bf51aSVishal Sagar
792ba5bf51aSVishal Sagar /*
793ba5bf51aSVishal Sagar * xcsi2rxss_enum_mbus_code - Handle pixel format enumeration
794ba5bf51aSVishal Sagar * @sd: pointer to v4l2 subdev structure
795ba5bf51aSVishal Sagar * @cfg: V4L2 subdev pad configuration
796ba5bf51aSVishal Sagar * @code: pointer to v4l2_subdev_mbus_code_enum structure
797ba5bf51aSVishal Sagar *
798ba5bf51aSVishal Sagar * Return: -EINVAL or zero on success
799ba5bf51aSVishal Sagar */
xcsi2rxss_enum_mbus_code(struct v4l2_subdev * sd,struct v4l2_subdev_state * sd_state,struct v4l2_subdev_mbus_code_enum * code)800ba5bf51aSVishal Sagar static int xcsi2rxss_enum_mbus_code(struct v4l2_subdev *sd,
8010d346d2aSTomi Valkeinen struct v4l2_subdev_state *sd_state,
802ba5bf51aSVishal Sagar struct v4l2_subdev_mbus_code_enum *code)
803ba5bf51aSVishal Sagar {
804ba5bf51aSVishal Sagar struct xcsi2rxss_state *state = to_xcsi2rxssstate(sd);
805ba5bf51aSVishal Sagar u32 dt, n;
806ba5bf51aSVishal Sagar int ret = 0;
807ba5bf51aSVishal Sagar
808ba5bf51aSVishal Sagar /* RAW8 dt packets are available in all DT configurations */
809ba5bf51aSVishal Sagar if (code->index < 4) {
810ba5bf51aSVishal Sagar n = code->index;
8112b891d39SLaurent Pinchart dt = MIPI_CSI2_DT_RAW8;
8122b891d39SLaurent Pinchart } else if (state->datatype != MIPI_CSI2_DT_RAW8) {
813ba5bf51aSVishal Sagar n = code->index - 4;
814ba5bf51aSVishal Sagar dt = state->datatype;
815ba5bf51aSVishal Sagar } else {
816ba5bf51aSVishal Sagar return -EINVAL;
817ba5bf51aSVishal Sagar }
818ba5bf51aSVishal Sagar
819ba5bf51aSVishal Sagar code->code = xcsi2rxss_get_nth_mbus(dt, n);
820ba5bf51aSVishal Sagar if (!code->code)
821ba5bf51aSVishal Sagar ret = -EINVAL;
822ba5bf51aSVishal Sagar
823ba5bf51aSVishal Sagar return ret;
824ba5bf51aSVishal Sagar }
825ba5bf51aSVishal Sagar
826ba5bf51aSVishal Sagar /* -----------------------------------------------------------------------------
827ba5bf51aSVishal Sagar * Media Operations
828ba5bf51aSVishal Sagar */
829ba5bf51aSVishal Sagar
830ba5bf51aSVishal Sagar static const struct media_entity_operations xcsi2rxss_media_ops = {
831ba5bf51aSVishal Sagar .link_validate = v4l2_subdev_link_validate
832ba5bf51aSVishal Sagar };
833ba5bf51aSVishal Sagar
834ba5bf51aSVishal Sagar static const struct v4l2_subdev_core_ops xcsi2rxss_core_ops = {
835ba5bf51aSVishal Sagar .log_status = xcsi2rxss_log_status,
836ba5bf51aSVishal Sagar };
837ba5bf51aSVishal Sagar
838ba5bf51aSVishal Sagar static const struct v4l2_subdev_video_ops xcsi2rxss_video_ops = {
839ba5bf51aSVishal Sagar .s_stream = xcsi2rxss_s_stream
840ba5bf51aSVishal Sagar };
841ba5bf51aSVishal Sagar
842ba5bf51aSVishal Sagar static const struct v4l2_subdev_pad_ops xcsi2rxss_pad_ops = {
843ba5bf51aSVishal Sagar .init_cfg = xcsi2rxss_init_cfg,
844ba5bf51aSVishal Sagar .get_fmt = xcsi2rxss_get_format,
845ba5bf51aSVishal Sagar .set_fmt = xcsi2rxss_set_format,
846ba5bf51aSVishal Sagar .enum_mbus_code = xcsi2rxss_enum_mbus_code,
847ba5bf51aSVishal Sagar .link_validate = v4l2_subdev_link_validate_default,
848ba5bf51aSVishal Sagar };
849ba5bf51aSVishal Sagar
850ba5bf51aSVishal Sagar static const struct v4l2_subdev_ops xcsi2rxss_ops = {
851ba5bf51aSVishal Sagar .core = &xcsi2rxss_core_ops,
852ba5bf51aSVishal Sagar .video = &xcsi2rxss_video_ops,
853ba5bf51aSVishal Sagar .pad = &xcsi2rxss_pad_ops
854ba5bf51aSVishal Sagar };
855ba5bf51aSVishal Sagar
xcsi2rxss_parse_of(struct xcsi2rxss_state * xcsi2rxss)856ba5bf51aSVishal Sagar static int xcsi2rxss_parse_of(struct xcsi2rxss_state *xcsi2rxss)
857ba5bf51aSVishal Sagar {
858ba5bf51aSVishal Sagar struct device *dev = xcsi2rxss->dev;
859ba5bf51aSVishal Sagar struct device_node *node = dev->of_node;
860ba5bf51aSVishal Sagar
861ba5bf51aSVishal Sagar struct fwnode_handle *ep;
862ba5bf51aSVishal Sagar struct v4l2_fwnode_endpoint vep = {
863ba5bf51aSVishal Sagar .bus_type = V4L2_MBUS_CSI2_DPHY
864ba5bf51aSVishal Sagar };
865ba5bf51aSVishal Sagar bool en_csi_v20, vfb;
866ba5bf51aSVishal Sagar int ret;
867ba5bf51aSVishal Sagar
868ba5bf51aSVishal Sagar en_csi_v20 = of_property_read_bool(node, "xlnx,en-csi-v2-0");
869ba5bf51aSVishal Sagar if (en_csi_v20)
870ba5bf51aSVishal Sagar xcsi2rxss->en_vcx = of_property_read_bool(node, "xlnx,en-vcx");
871ba5bf51aSVishal Sagar
872ba5bf51aSVishal Sagar xcsi2rxss->enable_active_lanes =
873ba5bf51aSVishal Sagar of_property_read_bool(node, "xlnx,en-active-lanes");
874ba5bf51aSVishal Sagar
875ba5bf51aSVishal Sagar ret = of_property_read_u32(node, "xlnx,csi-pxl-format",
876ba5bf51aSVishal Sagar &xcsi2rxss->datatype);
877ba5bf51aSVishal Sagar if (ret < 0) {
878ba5bf51aSVishal Sagar dev_err(dev, "missing xlnx,csi-pxl-format property\n");
879ba5bf51aSVishal Sagar return ret;
880ba5bf51aSVishal Sagar }
881ba5bf51aSVishal Sagar
882ba5bf51aSVishal Sagar switch (xcsi2rxss->datatype) {
8832b891d39SLaurent Pinchart case MIPI_CSI2_DT_YUV422_8B:
8842b891d39SLaurent Pinchart case MIPI_CSI2_DT_RGB444:
8852b891d39SLaurent Pinchart case MIPI_CSI2_DT_RGB555:
8862b891d39SLaurent Pinchart case MIPI_CSI2_DT_RGB565:
8872b891d39SLaurent Pinchart case MIPI_CSI2_DT_RGB666:
8882b891d39SLaurent Pinchart case MIPI_CSI2_DT_RGB888:
8892b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW6:
8902b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW7:
8912b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW8:
8922b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW10:
8932b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW12:
8942b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW14:
895ba5bf51aSVishal Sagar break;
8962b891d39SLaurent Pinchart case MIPI_CSI2_DT_YUV422_10B:
8972b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW16:
8982b891d39SLaurent Pinchart case MIPI_CSI2_DT_RAW20:
899ba5bf51aSVishal Sagar if (!en_csi_v20) {
900ba5bf51aSVishal Sagar ret = -EINVAL;
901ba5bf51aSVishal Sagar dev_dbg(dev, "enable csi v2 for this pixel format");
902ba5bf51aSVishal Sagar }
903ba5bf51aSVishal Sagar break;
904ba5bf51aSVishal Sagar default:
905ba5bf51aSVishal Sagar ret = -EINVAL;
906ba5bf51aSVishal Sagar }
907ba5bf51aSVishal Sagar if (ret < 0) {
908ba5bf51aSVishal Sagar dev_err(dev, "invalid csi-pxl-format property!\n");
909ba5bf51aSVishal Sagar return ret;
910ba5bf51aSVishal Sagar }
911ba5bf51aSVishal Sagar
912ba5bf51aSVishal Sagar vfb = of_property_read_bool(node, "xlnx,vfb");
913ba5bf51aSVishal Sagar if (!vfb) {
914ba5bf51aSVishal Sagar dev_err(dev, "operation without VFB is not supported\n");
915ba5bf51aSVishal Sagar return -EINVAL;
916ba5bf51aSVishal Sagar }
917ba5bf51aSVishal Sagar
918ba5bf51aSVishal Sagar ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
919ba5bf51aSVishal Sagar XVIP_PAD_SINK, 0,
920ba5bf51aSVishal Sagar FWNODE_GRAPH_ENDPOINT_NEXT);
921ba5bf51aSVishal Sagar if (!ep) {
922ba5bf51aSVishal Sagar dev_err(dev, "no sink port found");
923ba5bf51aSVishal Sagar return -EINVAL;
924ba5bf51aSVishal Sagar }
925ba5bf51aSVishal Sagar
926ba5bf51aSVishal Sagar ret = v4l2_fwnode_endpoint_parse(ep, &vep);
927ba5bf51aSVishal Sagar fwnode_handle_put(ep);
928ba5bf51aSVishal Sagar if (ret) {
929ba5bf51aSVishal Sagar dev_err(dev, "error parsing sink port");
930ba5bf51aSVishal Sagar return ret;
931ba5bf51aSVishal Sagar }
932ba5bf51aSVishal Sagar
933ba5bf51aSVishal Sagar dev_dbg(dev, "mipi number lanes = %d\n",
934ba5bf51aSVishal Sagar vep.bus.mipi_csi2.num_data_lanes);
935ba5bf51aSVishal Sagar
936ba5bf51aSVishal Sagar xcsi2rxss->max_num_lanes = vep.bus.mipi_csi2.num_data_lanes;
937ba5bf51aSVishal Sagar
938ba5bf51aSVishal Sagar ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
939ba5bf51aSVishal Sagar XVIP_PAD_SOURCE, 0,
940ba5bf51aSVishal Sagar FWNODE_GRAPH_ENDPOINT_NEXT);
941ba5bf51aSVishal Sagar if (!ep) {
942ba5bf51aSVishal Sagar dev_err(dev, "no source port found");
943ba5bf51aSVishal Sagar return -EINVAL;
944ba5bf51aSVishal Sagar }
945ba5bf51aSVishal Sagar
946ba5bf51aSVishal Sagar fwnode_handle_put(ep);
947ba5bf51aSVishal Sagar
948ba5bf51aSVishal Sagar dev_dbg(dev, "vcx %s, %u data lanes (%s), data type 0x%02x\n",
949ba5bf51aSVishal Sagar xcsi2rxss->en_vcx ? "enabled" : "disabled",
950ba5bf51aSVishal Sagar xcsi2rxss->max_num_lanes,
951ba5bf51aSVishal Sagar xcsi2rxss->enable_active_lanes ? "dynamic" : "static",
952ba5bf51aSVishal Sagar xcsi2rxss->datatype);
953ba5bf51aSVishal Sagar
954ba5bf51aSVishal Sagar return 0;
955ba5bf51aSVishal Sagar }
956ba5bf51aSVishal Sagar
xcsi2rxss_probe(struct platform_device * pdev)957ba5bf51aSVishal Sagar static int xcsi2rxss_probe(struct platform_device *pdev)
958ba5bf51aSVishal Sagar {
959ba5bf51aSVishal Sagar struct v4l2_subdev *subdev;
960ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss;
961ba5bf51aSVishal Sagar int num_clks = ARRAY_SIZE(xcsi2rxss_clks);
962ba5bf51aSVishal Sagar struct device *dev = &pdev->dev;
963ba5bf51aSVishal Sagar int irq, ret;
964ba5bf51aSVishal Sagar
965ba5bf51aSVishal Sagar xcsi2rxss = devm_kzalloc(dev, sizeof(*xcsi2rxss), GFP_KERNEL);
966ba5bf51aSVishal Sagar if (!xcsi2rxss)
967ba5bf51aSVishal Sagar return -ENOMEM;
968ba5bf51aSVishal Sagar
969ba5bf51aSVishal Sagar xcsi2rxss->dev = dev;
970ba5bf51aSVishal Sagar
971ba5bf51aSVishal Sagar xcsi2rxss->clks = devm_kmemdup(dev, xcsi2rxss_clks,
972ba5bf51aSVishal Sagar sizeof(xcsi2rxss_clks), GFP_KERNEL);
973ba5bf51aSVishal Sagar if (!xcsi2rxss->clks)
974ba5bf51aSVishal Sagar return -ENOMEM;
975ba5bf51aSVishal Sagar
976ba5bf51aSVishal Sagar /* Reset GPIO */
977ba5bf51aSVishal Sagar xcsi2rxss->rst_gpio = devm_gpiod_get_optional(dev, "video-reset",
978ba5bf51aSVishal Sagar GPIOD_OUT_HIGH);
9796cb7d1b3SYang Yingliang if (IS_ERR(xcsi2rxss->rst_gpio))
9806cb7d1b3SYang Yingliang return dev_err_probe(dev, PTR_ERR(xcsi2rxss->rst_gpio),
9816cb7d1b3SYang Yingliang "Video Reset GPIO not setup in DT\n");
982ba5bf51aSVishal Sagar
983ba5bf51aSVishal Sagar ret = xcsi2rxss_parse_of(xcsi2rxss);
984ba5bf51aSVishal Sagar if (ret < 0)
985ba5bf51aSVishal Sagar return ret;
986ba5bf51aSVishal Sagar
987ba5bf51aSVishal Sagar xcsi2rxss->iomem = devm_platform_ioremap_resource(pdev, 0);
988ba5bf51aSVishal Sagar if (IS_ERR(xcsi2rxss->iomem))
989ba5bf51aSVishal Sagar return PTR_ERR(xcsi2rxss->iomem);
990ba5bf51aSVishal Sagar
991ba5bf51aSVishal Sagar irq = platform_get_irq(pdev, 0);
992ba5bf51aSVishal Sagar if (irq < 0)
993ba5bf51aSVishal Sagar return irq;
994ba5bf51aSVishal Sagar
995ba5bf51aSVishal Sagar ret = devm_request_threaded_irq(dev, irq, NULL,
996ba5bf51aSVishal Sagar xcsi2rxss_irq_handler, IRQF_ONESHOT,
997ba5bf51aSVishal Sagar dev_name(dev), xcsi2rxss);
998ba5bf51aSVishal Sagar if (ret) {
999ba5bf51aSVishal Sagar dev_err(dev, "Err = %d Interrupt handler reg failed!\n", ret);
1000ba5bf51aSVishal Sagar return ret;
1001ba5bf51aSVishal Sagar }
1002ba5bf51aSVishal Sagar
1003ba5bf51aSVishal Sagar ret = clk_bulk_get(dev, num_clks, xcsi2rxss->clks);
1004ba5bf51aSVishal Sagar if (ret)
1005ba5bf51aSVishal Sagar return ret;
1006ba5bf51aSVishal Sagar
1007ba5bf51aSVishal Sagar /* TODO: Enable/disable clocks at stream on/off time. */
1008ba5bf51aSVishal Sagar ret = clk_bulk_prepare_enable(num_clks, xcsi2rxss->clks);
1009ba5bf51aSVishal Sagar if (ret)
1010ba5bf51aSVishal Sagar goto err_clk_put;
1011ba5bf51aSVishal Sagar
1012ba5bf51aSVishal Sagar mutex_init(&xcsi2rxss->lock);
1013ba5bf51aSVishal Sagar
1014ba5bf51aSVishal Sagar xcsi2rxss_hard_reset(xcsi2rxss);
1015ba5bf51aSVishal Sagar xcsi2rxss_soft_reset(xcsi2rxss);
1016ba5bf51aSVishal Sagar
1017ba5bf51aSVishal Sagar /* Initialize V4L2 subdevice and media entity */
1018ba5bf51aSVishal Sagar xcsi2rxss->pads[XVIP_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
1019ba5bf51aSVishal Sagar xcsi2rxss->pads[XVIP_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
1020ba5bf51aSVishal Sagar
1021ba5bf51aSVishal Sagar /* Initialize the default format */
1022ba5bf51aSVishal Sagar xcsi2rxss->default_format.code =
1023ba5bf51aSVishal Sagar xcsi2rxss_get_nth_mbus(xcsi2rxss->datatype, 0);
1024ba5bf51aSVishal Sagar xcsi2rxss->default_format.field = V4L2_FIELD_NONE;
1025ba5bf51aSVishal Sagar xcsi2rxss->default_format.colorspace = V4L2_COLORSPACE_SRGB;
1026ba5bf51aSVishal Sagar xcsi2rxss->default_format.width = XCSI_DEFAULT_WIDTH;
1027ba5bf51aSVishal Sagar xcsi2rxss->default_format.height = XCSI_DEFAULT_HEIGHT;
1028ba5bf51aSVishal Sagar xcsi2rxss->format = xcsi2rxss->default_format;
1029ba5bf51aSVishal Sagar
1030ba5bf51aSVishal Sagar /* Initialize V4L2 subdevice and media entity */
1031ba5bf51aSVishal Sagar subdev = &xcsi2rxss->subdev;
1032ba5bf51aSVishal Sagar v4l2_subdev_init(subdev, &xcsi2rxss_ops);
1033ba5bf51aSVishal Sagar subdev->dev = dev;
1034ba5bf51aSVishal Sagar strscpy(subdev->name, dev_name(dev), sizeof(subdev->name));
1035ba5bf51aSVishal Sagar subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
1036ba5bf51aSVishal Sagar subdev->entity.ops = &xcsi2rxss_media_ops;
1037ba5bf51aSVishal Sagar v4l2_set_subdevdata(subdev, xcsi2rxss);
1038ba5bf51aSVishal Sagar
1039ba5bf51aSVishal Sagar ret = media_entity_pads_init(&subdev->entity, XCSI_MEDIA_PADS,
1040ba5bf51aSVishal Sagar xcsi2rxss->pads);
1041ba5bf51aSVishal Sagar if (ret < 0)
1042ba5bf51aSVishal Sagar goto error;
1043ba5bf51aSVishal Sagar
1044ba5bf51aSVishal Sagar platform_set_drvdata(pdev, xcsi2rxss);
1045ba5bf51aSVishal Sagar
1046ba5bf51aSVishal Sagar ret = v4l2_async_register_subdev(subdev);
1047ba5bf51aSVishal Sagar if (ret < 0) {
1048ba5bf51aSVishal Sagar dev_err(dev, "failed to register subdev\n");
1049ba5bf51aSVishal Sagar goto error;
1050ba5bf51aSVishal Sagar }
1051ba5bf51aSVishal Sagar
1052ba5bf51aSVishal Sagar return 0;
1053ba5bf51aSVishal Sagar error:
1054ba5bf51aSVishal Sagar media_entity_cleanup(&subdev->entity);
1055ba5bf51aSVishal Sagar mutex_destroy(&xcsi2rxss->lock);
1056ba5bf51aSVishal Sagar clk_bulk_disable_unprepare(num_clks, xcsi2rxss->clks);
1057ba5bf51aSVishal Sagar err_clk_put:
1058ba5bf51aSVishal Sagar clk_bulk_put(num_clks, xcsi2rxss->clks);
1059ba5bf51aSVishal Sagar return ret;
1060ba5bf51aSVishal Sagar }
1061ba5bf51aSVishal Sagar
xcsi2rxss_remove(struct platform_device * pdev)1062*993bfd14SUwe Kleine-König static void xcsi2rxss_remove(struct platform_device *pdev)
1063ba5bf51aSVishal Sagar {
1064ba5bf51aSVishal Sagar struct xcsi2rxss_state *xcsi2rxss = platform_get_drvdata(pdev);
1065ba5bf51aSVishal Sagar struct v4l2_subdev *subdev = &xcsi2rxss->subdev;
1066ba5bf51aSVishal Sagar int num_clks = ARRAY_SIZE(xcsi2rxss_clks);
1067ba5bf51aSVishal Sagar
1068ba5bf51aSVishal Sagar v4l2_async_unregister_subdev(subdev);
1069ba5bf51aSVishal Sagar media_entity_cleanup(&subdev->entity);
1070ba5bf51aSVishal Sagar mutex_destroy(&xcsi2rxss->lock);
1071ba5bf51aSVishal Sagar clk_bulk_disable_unprepare(num_clks, xcsi2rxss->clks);
1072ba5bf51aSVishal Sagar clk_bulk_put(num_clks, xcsi2rxss->clks);
1073ba5bf51aSVishal Sagar }
1074ba5bf51aSVishal Sagar
1075ba5bf51aSVishal Sagar static const struct of_device_id xcsi2rxss_of_id_table[] = {
1076ba5bf51aSVishal Sagar { .compatible = "xlnx,mipi-csi2-rx-subsystem-5.0", },
1077ba5bf51aSVishal Sagar { }
1078ba5bf51aSVishal Sagar };
1079ba5bf51aSVishal Sagar MODULE_DEVICE_TABLE(of, xcsi2rxss_of_id_table);
1080ba5bf51aSVishal Sagar
1081ba5bf51aSVishal Sagar static struct platform_driver xcsi2rxss_driver = {
1082ba5bf51aSVishal Sagar .driver = {
1083ba5bf51aSVishal Sagar .name = "xilinx-csi2rxss",
1084ba5bf51aSVishal Sagar .of_match_table = xcsi2rxss_of_id_table,
1085ba5bf51aSVishal Sagar },
1086ba5bf51aSVishal Sagar .probe = xcsi2rxss_probe,
1087*993bfd14SUwe Kleine-König .remove_new = xcsi2rxss_remove,
1088ba5bf51aSVishal Sagar };
1089ba5bf51aSVishal Sagar
1090ba5bf51aSVishal Sagar module_platform_driver(xcsi2rxss_driver);
1091ba5bf51aSVishal Sagar
1092ba5bf51aSVishal Sagar MODULE_AUTHOR("Vishal Sagar <vsagar@xilinx.com>");
1093ba5bf51aSVishal Sagar MODULE_DESCRIPTION("Xilinx MIPI CSI-2 Rx Subsystem Driver");
1094ba5bf51aSVishal Sagar MODULE_LICENSE("GPL v2");
1095