Pull media updates from Mauro Carvalho Chehab: - New sensor drivers: gc05a2, gc08a3 and imx283 - New serializer/deserializer drivers: max96714 and max96717 - New JPEG encoder driver: e5010 - Support for Raspberry Pi PiSP Backend (BE) ISP driver - Old documentation for av7110 driver removed, as a new version was added as Documentation/userspace-api/media/dvb/legacy*.rst - atompisp: Linux firmwares are now available, so drop firmware-related task from TODO and update firmware logic - The imx258 driver has gained several improvements - wave5 driver has gained support for HEVC decoding - em28xx gained support for MyGica UTV3 - av7110 budget-patch driver removed - Lots of other cleanups, improvements and fixes * tag 'media/v6.11-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (301 commits) media: raspberrypi: Switch to remove_new media: uapi: pisp_be_config: Add extra config fields media: uapi: pisp_be_config: Re-sort pisp_be_tiles_config media: uapi: pisp_common: Capitalize all macros media: uapi: pisp_common: Add 32 bpp format test media: uapi: pisp_be_config: Drop BIT() from uAPI media: stm32: dcmipp: correct error handling in dcmipp_create_subdevs media: atomisp: Fix spelling mistakes in sh_css_sp.c media: atomisp: Fix spelling mistake in ia_css_debug.c media: atomisp: Fix spelling mistake in hmm_bo.c media: atomisp: Fix spelling mistake in ia_css_eed1_8.host.c media: atomisp: Fix spelling mistake in sh_css_internal.h media: atomisp: Fix spelling mistake "pipline" -> "pipeline" media: atomisp: Remove unused GPIO related defines and APIs media: atomisp: Replace COMPILATION_ERROR_IF() by static_assert() media: atomisp: Clean up unused macros from math_support.h media: atomisp: csi2-bridge: Add DMI quirk for OV5693 on Xiaomi Mipad2 media: atomisp: Update TODO media: atomisp: Prefix firmware paths with "intel/ipu/" media: atomisp: Remove firmware_name module parameter ...
Unified · Split
| @@ -438,3 +438,11 @@ EM28xx cards list · 437 unmodified lines | ||
| 438 | 438 | - MyGica iGrabber |
| 439 | 439 | - em2860 |
| 440 | 440 | - 1f4d:1abe |
| 441 | + * - 106 | |
| 442 | + - Hauppauge USB QuadHD ATSC | |
| 443 | + - em28274 | |
| 444 | + - 2040:846d | |
| 445 | + * - 107 | |
| 446 | + - MyGica UTV3 Analog USB2.0 TV Box | |
| 447 | + - em2860 | |
| 448 | + - eb1a:2860 | |
| @@ -135,16 +135,16 @@ sensor ov2740 on Lenovo X1 Yoga laptop. · 134 unmodified lines | ||
| 135 | 135 | .. code-block:: none |
| 136 | 136 | |
| 137 | 137 | media-ctl -l "\"ov2740 14-0036\":0 -> \"Intel IPU6 CSI2 1\":0[1]" |
| 138 | − media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[5]" | |
| 139 | − media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[5]" | |
| 138 | + media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[1]" | |
| 139 | + media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[1]" | |
| 140 | 140 | |
| 141 | 141 | # set routing |
| 142 | − media-ctl -v -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]" | |
| 142 | + media-ctl -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]" | |
| 143 | 143 | |
| 144 | − media-ctl -v "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]" | |
| 145 | − media-ctl -v "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]" | |
| 146 | − media-ctl -v "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]" | |
| 147 | − media-ctl -v "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]" | |
| 144 | + media-ctl -V "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]" | |
| 145 | + media-ctl -V "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]" | |
| 146 | + media-ctl -V "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]" | |
| 147 | + media-ctl -V "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]" | |
| 148 | 148 | |
| 149 | 149 | CAPTURE_DEV=$(media-ctl -e "Intel IPU6 ISYS Capture 0") |
| 150 | 150 | ./yavta --data-prefix -c100 -n5 -I -s1932x1092 --file=/tmp/frame-#.bin \ |
| @@ -0,0 +1,20 @@ | ||
| 1 | +digraph board { | |
| 2 | + rankdir=TB | |
| 3 | + n00000001 [label="{{<port0> 0 | <port1> 1 | <port2> 2 | <port7> 7} | pispbe\n | {<port3> 3 | <port4> 4 | <port5> 5 | <port6> 6}}", shape=Mrecord, style=filled, fillcolor=green] | |
| 4 | + n00000001:port3 -> n0000001c [style=bold] | |
| 5 | + n00000001:port4 -> n00000022 [style=bold] | |
| 6 | + n00000001:port5 -> n00000028 [style=bold] | |
| 7 | + n00000001:port6 -> n0000002e [style=bold] | |
| 8 | + n0000000a [label="pispbe-input\n/dev/video0", shape=box, style=filled, fillcolor=yellow] | |
| 9 | + n0000000a -> n00000001:port0 [style=bold] | |
| 10 | + n00000010 [label="pispbe-tdn_input\n/dev/video1", shape=box, style=filled, fillcolor=yellow] | |
| 11 | + n00000010 -> n00000001:port1 [style=bold] | |
| 12 | + n00000016 [label="pispbe-stitch_input\n/dev/video2", shape=box, style=filled, fillcolor=yellow] | |
| 13 | + n00000016 -> n00000001:port2 [style=bold] | |
| 14 | + n0000001c [label="pispbe-output0\n/dev/video3", shape=box, style=filled, fillcolor=yellow] | |
| 15 | + n00000022 [label="pispbe-output1\n/dev/video4", shape=box, style=filled, fillcolor=yellow] | |
| 16 | + n00000028 [label="pispbe-tdn_output\n/dev/video5", shape=box, style=filled, fillcolor=yellow] | |
| 17 | + n0000002e [label="pispbe-stitch_output\n/dev/video6", shape=box, style=filled, fillcolor=yellow] | |
| 18 | + n00000034 [label="pispbe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow] | |
| 19 | + n00000034 -> n00000001:port7 [style=bold] | |
| 20 | +} | |
| @@ -0,0 +1,109 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +========================================================= | |
| 4 | +Raspberry Pi PiSP Back End Memory-to-Memory ISP (pisp-be) | |
| 5 | +========================================================= | |
| 6 | + | |
| 7 | +The PiSP Back End | |
| 8 | +================= | |
| 9 | + | |
| 10 | +The PiSP Back End is a memory-to-memory Image Signal Processor (ISP) which reads | |
| 11 | +image data from DRAM memory and performs image processing as specified by the | |
| 12 | +application through the parameters in a configuration buffer, before writing | |
| 13 | +pixel data back to memory through two distinct output channels. | |
| 14 | + | |
| 15 | +The ISP registers and programming model are documented in the `Raspberry Pi | |
| 16 | +Image Signal Processor (PiSP) Specification document`_ | |
| 17 | + | |
| 18 | +The PiSP Back End ISP processes images in tiles. The handling of image | |
| 19 | +tessellation and the computation of low-level configuration parameters is | |
| 20 | +realized by a free software library called `libpisp | |
| 21 | +<https://github.com/raspberrypi/libpisp>`_. | |
| 22 | + | |
| 23 | +The full image processing pipeline, which involves capturing RAW Bayer data from | |
| 24 | +an image sensor through a MIPI CSI-2 compatible capture interface, storing them | |
| 25 | +in DRAM memory and processing them in the PiSP Back End to obtain images usable | |
| 26 | +by an application is implemented in `libcamera <https://libcamera.org>`_ as | |
| 27 | +part of the Raspberry Pi platform support. | |
| 28 | + | |
| 29 | +The pisp-be driver | |
| 30 | +================== | |
| 31 | + | |
| 32 | +The Raspberry Pi PiSP Back End (pisp-be) driver is located under | |
| 33 | +drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register | |
| 34 | +a number of video capture and output devices, the `V4L2 subdev API` to register | |
| 35 | +a subdevice for the ISP that connects the video devices in a single media graph | |
| 36 | +realized using the `Media Controller (MC) API`. | |
| 37 | + | |
| 38 | +The media topology registered by the `pisp-be` driver is represented below: | |
| 39 | + | |
| 40 | +.. _pips-be-topology: | |
| 41 | + | |
| 42 | +.. kernel-figure:: raspberrypi-pisp-be.dot | |
| 43 | + :alt: Diagram of the default media pipeline topology | |
| 44 | + :align: center | |
| 45 | + | |
| 46 | + | |
| 47 | +The media graph registers the following video device nodes: | |
| 48 | + | |
| 49 | +- pispbe-input: output device for images to be submitted to the ISP for | |
| 50 | + processing. | |
| 51 | +- pispbe-tdn_input: output device for temporal denoise. | |
| 52 | +- pispbe-stitch_input: output device for image stitching (HDR). | |
| 53 | +- pispbe-output0: first capture device for processed images. | |
| 54 | +- pispbe-output1: second capture device for processed images. | |
| 55 | +- pispbe-tdn_output: capture device for temporal denoise. | |
| 56 | +- pispbe-stitch_output: capture device for image stitching (HDR). | |
| 57 | +- pispbe-config: output device for ISP configuration parameters. | |
| 58 | + | |
| 59 | +pispbe-input | |
| 60 | +------------ | |
| 61 | + | |
| 62 | +Images to be processed by the ISP are queued to the `pispbe-input` output device | |
| 63 | +node. For a list of image formats supported as input to the ISP refer to the | |
| 64 | +`Raspberry Pi Image Signal Processor (PiSP) Specification document`_. | |
| 65 | + | |
| 66 | +pispbe-tdn_input, pispbe-tdn_output | |
| 67 | +----------------------------------- | |
| 68 | + | |
| 69 | +The `pispbe-tdn_input` output video device receives images to be processed by | |
| 70 | +the temporal denoise block which are captured from the `pispbe-tdn_output` | |
| 71 | +capture video device. Userspace is responsible for maintaining queues on both | |
| 72 | +devices, and ensuring that buffers completed on the output are queued to the | |
| 73 | +input. | |
| 74 | + | |
| 75 | +pispbe-stitch_input, pispbe-stitch_output | |
| 76 | +----------------------------------------- | |
| 77 | + | |
| 78 | +To realize HDR (high dynamic range) image processing the image stitching and | |
| 79 | +tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory | |
| 80 | +and the `pispbe-stitch_input` receives the previously written frame to process | |
| 81 | +it along with the current input image. Userspace is responsible for maintaining | |
| 82 | +queues on both devices, and ensuring that buffers completed on the output are | |
| 83 | +queued to the input. | |
| 84 | + | |
| 85 | +pispbe-output0, pispbe-output1 | |
| 86 | +------------------------------ | |
| 87 | + | |
| 88 | +The two capture devices write to memory the pixel data as processed by the ISP. | |
| 89 | + | |
| 90 | +pispbe-config | |
| 91 | +------------- | |
| 92 | + | |
| 93 | +The `pispbe-config` output video devices receives a buffer of configuration | |
| 94 | +parameters that define the desired image processing to be performed by the ISP. | |
| 95 | + | |
| 96 | +The format of the ISP configuration parameter is defined by | |
| 97 | +:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is | |
| 98 | +described in the `Raspberry Pi Image Signal Processor (PiSP) Specification | |
| 99 | +document`_. | |
| 100 | + | |
| 101 | +ISP configuration | |
| 102 | +================= | |
| 103 | + | |
| 104 | +The ISP configuration is described solely by the content of the parameters | |
| 105 | +buffer. The only parameter that userspace needs to configure using the V4L2 API | |
| 106 | +is the image format on the output and capture video devices for validation of | |
| 107 | +the content of the parameters buffer. | |
| 108 | + | |
| 109 | +.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf | |
| @@ -97,4 +97,6 @@ Tuner number Card name · 96 unmodified lines | ||
| 97 | 97 | 89 Sony BTF-PG472Z PAL/SECAM |
| 98 | 98 | 90 Sony BTF-PK467Z NTSC-M-JP |
| 99 | 99 | 91 Sony BTF-PB463Z NTSC-M |
| 100 | +92 Silicon Labs Si2157 tuner | |
| 101 | +93 Tena TNF931D-DFDR1 | |
| 100 | 102 | ============ ===================================================== |
| @@ -23,6 +23,7 @@ Video4Linux (V4L) driver-specific documentation · 22 unmodified lines | ||
| 23 | 23 | omap4_camera |
| 24 | 24 | philips |
| 25 | 25 | qcom_camss |
| 26 | + raspberrypi-pisp-be | |
| 26 | 27 | rcar-fdp1 |
| 27 | 28 | rkisp1 |
| 28 | 29 | saa7134 |
| @@ -302,6 +302,15 @@ all configurable using the following module options: · 301 unmodified lines | ||
| 302 | 302 | - 0: forbid hints |
| 303 | 303 | - 1: allow hints |
| 304 | 304 | |
| 305 | +- supports_requests: | |
| 306 | + | |
| 307 | + specifies if the device should support the Request API. There are | |
| 308 | + three possible values, default is 1: | |
| 309 | + | |
| 310 | + - 0: no request | |
| 311 | + - 1: supports requests | |
| 312 | + - 2: requires requests | |
| 313 | + | |
| 305 | 314 | Taken together, all these module options allow you to precisely customize |
| 306 | 315 | the driver behavior and test your application with all sorts of permutations. |
| 307 | 316 | It is also very suitable to emulate hardware that is not yet available, e.g. |
| @@ -313,10 +322,10 @@ Video Capture · 5 unmodified lines | ||
| 313 | 322 | |
| 314 | 323 | This is probably the most frequently used feature. The video capture device |
| 315 | 324 | can be configured by using the module options num_inputs, input_types and |
| 316 | −ccs_cap_mode (see section 1 for more detailed information), but by default | |
| 317 | −four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI | |
| 318 | −input, one input for each input type. Those are described in more detail | |
| 319 | −below. | |
| 325 | +ccs_cap_mode (see "Configuring the driver" for more detailed information), | |
| 326 | +but by default four inputs are configured: a webcam, a TV tuner, an S-Video | |
| 327 | +and an HDMI input, one input for each input type. Those are described in more | |
| 328 | +detail below. | |
| 320 | 329 | |
| 321 | 330 | Special attention has been given to the rate at which new frames become |
| 322 | 331 | available. The jitter will be around 1 jiffie (that depends on the HZ |
| @@ -434,10 +443,10 @@ Video Output · 111 unmodified lines | ||
| 434 | 443 | ------------ |
| 435 | 444 | |
| 436 | 445 | The video output device can be configured by using the module options |
| 437 | −num_outputs, output_types and ccs_out_mode (see section 1 for more detailed | |
| 438 | −information), but by default two outputs are configured: an S-Video and an | |
| 439 | −HDMI input, one output for each output type. Those are described in more detail | |
| 440 | −below. | |
| 446 | +num_outputs, output_types and ccs_out_mode (see "Configuring the driver" | |
| 447 | +for more detailed information), but by default two outputs are configured: | |
| 448 | +an S-Video and an HDMI input, one output for each output type. Those are | |
| 449 | +described in more detail below. | |
| 441 | 450 | |
| 442 | 451 | Like with video capture the framerate is also exact in the long term. |
| 443 | 452 | |
| @@ -1011,11 +1020,6 @@ Digital Video Controls · 567 unmodified lines | ||
| 1011 | 1020 | affects the reported colorspace since DVI_D outputs will always use |
| 1012 | 1021 | sRGB. |
| 1013 | 1022 | |
| 1014 | −- Display Present: | |
| 1015 | − | |
| 1016 | − sets the presence of a "display" on the HDMI output. This affects | |
| 1017 | − the tx_edid_present, tx_hotplug and tx_rxsense controls. | |
| 1018 | − | |
| 1019 | 1023 | |
| 1020 | 1024 | FM Radio Receiver Controls |
| 1021 | 1025 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -1130,35 +1134,34 @@ Metadata Capture Controls · 108 unmodified lines | ||
| 1130 | 1134 | |
| 1131 | 1135 | if set, then the generated metadata stream contains Source Clock information. |
| 1132 | 1136 | |
| 1133 | −Video, VBI and RDS Looping | |
| 1134 | −-------------------------- | |
| 1135 | 1137 | |
| 1136 | −The vivid driver supports looping of video output to video input, VBI output | |
| 1137 | −to VBI input and RDS output to RDS input. For video/VBI looping this emulates | |
| 1138 | −as if a cable was hooked up between the output and input connector. So video | |
| 1139 | −and VBI looping is only supported between S-Video and HDMI inputs and outputs. | |
| 1140 | −VBI is only valid for S-Video as it makes no sense for HDMI. | |
| 1138 | +Video, Sliced VBI and HDMI CEC Looping | |
| 1139 | +-------------------------------------- | |
| 1141 | 1140 | |
| 1142 | −Since radio is wireless this looping always happens if the radio receiver | |
| 1143 | −frequency is close to the radio transmitter frequency. In that case the radio | |
| 1144 | −transmitter will 'override' the emulated radio stations. | |
| 1145 | − | |
| 1146 | −Looping is currently supported only between devices created by the same | |
| 1147 | −vivid driver instance. | |
| 1141 | +Video Looping functionality is supported for devices created by the same | |
| 1142 | +vivid driver instance, as well as across multiple instances of the vivid driver. | |
| 1143 | +The vivid driver supports looping of video and Sliced VBI data between an S-Video output | |
| 1144 | +and an S-Video input. It also supports looping of video and HDMI CEC data between an | |
| 1145 | +HDMI output and an HDMI input. | |
| 1148 | 1146 | |
| 1147 | +To enable looping, set the 'HDMI/S-Video XXX-N Is Connected To' control(s) to select | |
| 1148 | +whether an input uses the Test Pattern Generator, or is disconnected, or is connected | |
| 1149 | +to an output. An input can be connected to an output from any vivid instance. | |
| 1150 | +The inputs and outputs are numbered XXX-N where XXX is the vivid instance number | |
| 1151 | +(see module option n_devs). If there is only one vivid instance (the default), then | |
| 1152 | +XXX will be 000. And N is the Nth S-Video/HDMI input or output of that instance. | |
| 1153 | +If vivid is loaded without module options, then you can connect the S-Video 000-0 input | |
| 1154 | +to the S-Video 000-0 output, or the HDMI 000-0 input to the HDMI 000-0 output. | |
| 1155 | +This is the equivalent of connecting or disconnecting a cable between an input and an | |
| 1156 | +output in a physical device. | |
| 1149 | 1157 | |
| 1150 | −Video and Sliced VBI looping | |
| 1151 | −~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
| 1158 | +If an 'HDMI/S-Video XXX-N Is Connected To' control selected an output, then the video | |
| 1159 | +output will be looped to the video input provided that: | |
| 1152 | 1160 | |
| 1153 | −The way to enable video/VBI looping is currently fairly crude. A 'Loop Video' | |
| 1154 | −control is available in the "Vivid" control class of the video | |
| 1155 | −capture and VBI capture devices. When checked the video looping will be enabled. | |
| 1156 | −Once enabled any video S-Video or HDMI input will show a static test pattern | |
| 1157 | −until the video output has started. At that time the video output will be | |
| 1158 | −looped to the video input provided that: | |
| 1161 | +- the currently selected input matches the input indicated by the control name. | |
| 1159 | 1162 | |
| 1160 | −- the input type matches the output type. So the HDMI input cannot receive | |
| 1161 | − video from the S-Video output. | |
| 1163 | +- in the vivid instance of the output connector, the currently selected output matches | |
| 1164 | + the output indicated by the control's value. | |
| 1162 | 1165 | |
| 1163 | 1166 | - the video resolution of the video input must match that of the video output. |
| 1164 | 1167 | So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz |
| @@ -1185,6 +1188,8 @@ looped to the video input provided that: · 20 unmodified lines | ||
| 1185 | 1188 | "DV Timings Signal Mode" for the HDMI input should be configured so that a |
| 1186 | 1189 | valid signal is passed to the video input. |
| 1187 | 1190 | |
| 1191 | +If any condition is not valid, then the 'Noise' test pattern is shown. | |
| 1192 | + | |
| 1188 | 1193 | The framerates do not have to match, although this might change in the future. |
| 1189 | 1194 | |
| 1190 | 1195 | By default you will see the OSD text superimposed on top of the looped video. |
| @@ -1198,17 +1203,26 @@ and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped. · 7 unmodified lines | ||
| 1198 | 1203 | |
| 1199 | 1204 | |
| 1200 | 1205 | Radio & RDS Looping |
| 1201 | −~~~~~~~~~~~~~~~~~~~ | |
| 1202 | − | |
| 1203 | −As mentioned in section 6 the radio receiver emulates stations are regular | |
| 1204 | −frequency intervals. Depending on the frequency of the radio receiver a | |
| 1205 | −signal strength value is calculated (this is returned by VIDIOC_G_TUNER). | |
| 1206 | −However, it will also look at the frequency set by the radio transmitter and | |
| 1207 | −if that results in a higher signal strength than the settings of the radio | |
| 1208 | −transmitter will be used as if it was a valid station. This also includes | |
| 1209 | −the RDS data (if any) that the transmitter 'transmits'. This is received | |
| 1210 | −faithfully on the receiver side. Note that when the driver is loaded the | |
| 1211 | −frequencies of the radio receiver and transmitter are not identical, so | |
| 1206 | +------------------- | |
| 1207 | + | |
| 1208 | +The vivid driver supports looping of RDS output to RDS input. | |
| 1209 | + | |
| 1210 | +Since radio is wireless this looping always happens if the radio receiver | |
| 1211 | +frequency is close to the radio transmitter frequency. In that case the radio | |
| 1212 | +transmitter will 'override' the emulated radio stations. | |
| 1213 | + | |
| 1214 | +RDS looping is currently supported only between devices created by the same | |
| 1215 | +vivid driver instance. | |
| 1216 | + | |
| 1217 | +As mentioned in the "Radio Receiver" section, the radio receiver emulates | |
| 1218 | +stations at regular frequency intervals. Depending on the frequency of the | |
| 1219 | +radio receiver a signal strength value is calculated (this is returned by | |
| 1220 | +VIDIOC_G_TUNER). However, it will also look at the frequency set by the radio | |
| 1221 | +transmitter and if that results in a higher signal strength than the settings | |
| 1222 | +of the radio transmitter will be used as if it was a valid station. This also | |
| 1223 | +includes the RDS data (if any) that the transmitter 'transmits'. This is | |
| 1224 | +received faithfully on the receiver side. Note that when the driver is loaded | |
| 1225 | +the frequencies of the radio receiver and transmitter are not identical, so | |
| 1212 | 1226 | initially no looping takes place. |
| 1213 | 1227 | |
| 1214 | 1228 | |
| @@ -1218,8 +1232,8 @@ Cropping, Composing, Scaling · 3 unmodified lines | ||
| 1218 | 1232 | This driver supports cropping, composing and scaling in any combination. Normally |
| 1219 | 1233 | which features are supported can be selected through the Vivid controls, |
| 1220 | 1234 | but it is also possible to hardcode it when the module is loaded through the |
| 1221 | −ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of | |
| 1222 | −these module options. | |
| 1235 | +ccs_cap_mode and ccs_out_mode module options. See "Configuring the driver" on | |
| 1236 | +the details of these module options. | |
| 1223 | 1237 | |
| 1224 | 1238 | This allows you to test your application for all these variations. |
| 1225 | 1239 | |
| @@ -1260,7 +1274,8 @@ is set, then the alpha component is only used for the color red and set to · 34 unmodified lines | ||
| 1260 | 1274 | |
| 1261 | 1275 | The driver has to be configured to support the multiplanar formats. By default |
| 1262 | 1276 | the driver instances are single-planar. This can be changed by setting the |
| 1263 | −multiplanar module option, see section 1 for more details on that option. | |
| 1277 | +multiplanar module option, see "Configuring the driver" for more details on that | |
| 1278 | +option. | |
| 1264 | 1279 | |
| 1265 | 1280 | If the driver instance is using the multiplanar formats/API, then the first |
| 1266 | 1281 | single planar format (YUYV) and the multiplanar NV16M and NV61M formats the |
| @@ -1270,74 +1285,6 @@ data_offset to be non-zero, so this is a useful feature for testing applications · 3 unmodified lines | ||
| 1270 | 1285 | Video output will also honor any data_offset that the application set. |
| 1271 | 1286 | |
| 1272 | 1287 | |
| 1273 | −Capture Overlay | |
| 1274 | −--------------- | |
| 1275 | − | |
| 1276 | −Note: capture overlay support is implemented primarily to test the existing | |
| 1277 | −V4L2 capture overlay API. In practice few if any GPUs support such overlays | |
| 1278 | −anymore, and neither are they generally needed anymore since modern hardware | |
| 1279 | −is so much more capable. By setting flag 0x10000 in the node_types module | |
| 1280 | −option the vivid driver will create a simple framebuffer device that can be | |
| 1281 | −used for testing this API. Whether this API should be used for new drivers is | |
| 1282 | −questionable. | |
| 1283 | − | |
| 1284 | −This driver has support for a destructive capture overlay with bitmap clipping | |
| 1285 | −and list clipping (up to 16 rectangles) capabilities. Overlays are not | |
| 1286 | −supported for multiplanar formats. It also honors the struct v4l2_window field | |
| 1287 | −setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is | |
| 1288 | −FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay. | |
| 1289 | − | |
| 1290 | −The overlay only works if you are also capturing at that same time. This is a | |
| 1291 | −vivid limitation since it copies from a buffer to the overlay instead of | |
| 1292 | −filling the overlay directly. And if you are not capturing, then no buffers | |
| 1293 | −are available to fill. | |
| 1294 | − | |
| 1295 | −In addition, the pixelformat of the capture format and that of the framebuffer | |
| 1296 | −must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return | |
| 1297 | −an error. | |
| 1298 | − | |
| 1299 | −In order to really see what it going on you will need to create two vivid | |
| 1300 | −instances: the first with a framebuffer enabled. You configure the capture | |
| 1301 | −overlay of the second instance to use the framebuffer of the first, then | |
| 1302 | −you start capturing in the second instance. For the first instance you setup | |
| 1303 | −the output overlay for the video output, turn on video looping and capture | |
| 1304 | −to see the blended framebuffer overlay that's being written to by the second | |
| 1305 | −instance. This setup would require the following commands: | |
| 1306 | − | |
| 1307 | −.. code-block:: none | |
| 1308 | − | |
| 1309 | − $ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1 | |
| 1310 | − $ v4l2-ctl -d1 --find-fb | |
| 1311 | − /dev/fb1 is the framebuffer associated with base address 0x12800000 | |
| 1312 | − $ sudo v4l2-ctl -d2 --set-fbuf fb=1 | |
| 1313 | − $ v4l2-ctl -d1 --set-fbuf fb=1 | |
| 1314 | − $ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15' | |
| 1315 | − $ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15' | |
| 1316 | − $ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15' | |
| 1317 | − $ v4l2-ctl -d0 -i2 | |
| 1318 | − $ v4l2-ctl -d2 -i2 | |
| 1319 | − $ v4l2-ctl -d2 -c horizontal_movement=4 | |
| 1320 | − $ v4l2-ctl -d1 --overlay=1 | |
| 1321 | − $ v4l2-ctl -d0 -c loop_video=1 | |
| 1322 | − $ v4l2-ctl -d2 --stream-mmap --overlay=1 | |
| 1323 | − | |
| 1324 | −And from another console: | |
| 1325 | − | |
| 1326 | −.. code-block:: none | |
| 1327 | − | |
| 1328 | − $ v4l2-ctl -d1 --stream-out-mmap | |
| 1329 | − | |
| 1330 | −And yet another console: | |
| 1331 | − | |
| 1332 | −.. code-block:: none | |
| 1333 | − | |
| 1334 | − $ qv4l2 | |
| 1335 | − | |
| 1336 | −and start streaming. | |
| 1337 | − | |
| 1338 | −As you can see, this is not for the faint of heart... | |
| 1339 | − | |
| 1340 | − | |
| 1341 | 1288 | Output Overlay |
| 1342 | 1289 | -------------- |
| 1343 | 1290 | |
| @@ -1405,8 +1352,6 @@ Just as a reminder and in no particular order: · 61 unmodified lines | ||
| 1405 | 1352 | - Add ARGB888 overlay support: better testing of the alpha channel |
| 1406 | 1353 | - Improve pixel aspect support in the tpg code by passing a real v4l2_fract |
| 1407 | 1354 | - Use per-queue locks and/or per-device locks to improve throughput |
| 1408 | −- Add support to loop from a specific output to a specific input across | |
| 1409 | − vivid instances | |
| 1410 | 1355 | - The SDR radio should use the same 'frequencies' for stations as the normal |
| 1411 | 1356 | radio receiver, and give back noise if the frequency doesn't match up with |
| 1412 | 1357 | a station frequency |
| @@ -0,0 +1,112 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +# Copyright (c) 2023 MediaTek Inc. | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc05a2.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | + | |
| 8 | +title: GalaxyCore gc05a2 1/5" 5M Pixel MIPI CSI-2 sensor | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Zhi Mao <zhi.mao@mediatek.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The gc05a2 is a raw image sensor with an MIPI CSI-2 image data | |
| 15 | + interface and CCI (I2C compatible) control bus. The output format | |
| 16 | + is raw Bayer. | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + const: galaxycore,gc05a2 | |
| 21 | + | |
| 22 | + reg: | |
| 23 | + maxItems: 1 | |
| 24 | + | |
| 25 | + clocks: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + dovdd-supply: true | |
| 29 | + | |
| 30 | + avdd-supply: true | |
| 31 | + | |
| 32 | + dvdd-supply: true | |
| 33 | + | |
| 34 | + reset-gpios: | |
| 35 | + description: Reference to the GPIO connected to the RESETB pin. | |
| 36 | + maxItems: 1 | |
| 37 | + | |
| 38 | + port: | |
| 39 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 40 | + additionalProperties: false | |
| 41 | + description: | |
| 42 | + Output port node, single endpoint describing the CSI-2 transmitter. | |
| 43 | + | |
| 44 | + properties: | |
| 45 | + endpoint: | |
| 46 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 47 | + unevaluatedProperties: false | |
| 48 | + | |
| 49 | + properties: | |
| 50 | + data-lanes: | |
| 51 | + oneOf: | |
| 52 | + - items: | |
| 53 | + - const: 1 | |
| 54 | + - const: 2 | |
| 55 | + - const: 3 | |
| 56 | + - const: 4 | |
| 57 | + - items: | |
| 58 | + - const: 1 | |
| 59 | + - const: 2 | |
| 60 | + | |
| 61 | + link-frequencies: true | |
| 62 | + | |
| 63 | + required: | |
| 64 | + - data-lanes | |
| 65 | + - link-frequencies | |
| 66 | + | |
| 67 | + required: | |
| 68 | + - endpoint | |
| 69 | + | |
| 70 | +required: | |
| 71 | + - compatible | |
| 72 | + - reg | |
| 73 | + - clocks | |
| 74 | + - dovdd-supply | |
| 75 | + - avdd-supply | |
| 76 | + - dvdd-supply | |
| 77 | + - reset-gpios | |
| 78 | + - port | |
| 79 | + | |
| 80 | +additionalProperties: false | |
| 81 | + | |
| 82 | +examples: | |
| 83 | + - | | |
| 84 | + #include <dt-bindings/gpio/gpio.h> | |
| 85 | + | |
| 86 | + i2c { | |
| 87 | + #address-cells = <1>; | |
| 88 | + #size-cells = <0>; | |
| 89 | + | |
| 90 | + sensor@37 { | |
| 91 | + compatible = "galaxycore,gc05a2"; | |
| 92 | + reg = <0x37>; | |
| 93 | + | |
| 94 | + clocks = <&gc05a2_clk>; | |
| 95 | + | |
| 96 | + reset-gpios = <&pio 21 GPIO_ACTIVE_LOW>; | |
| 97 | + | |
| 98 | + avdd-supply = <&gc05a2_avdd>; | |
| 99 | + dovdd-supply = <&gc05a2_dovdd>; | |
| 100 | + dvdd-supply = <&gc05a2_dvdd>; | |
| 101 | + | |
| 102 | + port { | |
| 103 | + sensor_out: endpoint { | |
| 104 | + data-lanes = <1 2>; | |
| 105 | + link-frequencies = /bits/ 64 <448000000 224000000>; | |
| 106 | + remote-endpoint = <&seninf_csi_port_1_in>; | |
| 107 | + }; | |
| 108 | + }; | |
| 109 | + }; | |
| 110 | + }; | |
| 111 | + | |
| 112 | +... | |
| @@ -0,0 +1,112 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause) | |
| 2 | +# Copyright (c) 2023 MediaTek Inc. | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc08a3.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | + | |
| 8 | +title: GalaxyCore gc08a3 1/4" 8M Pixel MIPI CSI-2 sensor | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Zhi Mao <zhi.mao@mediatek.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The gc08a3 is a raw image sensor with an MIPI CSI-2 image data | |
| 15 | + interface and CCI (I2C compatible) control bus. The output format | |
| 16 | + is raw Bayer. | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + const: galaxycore,gc08a3 | |
| 21 | + | |
| 22 | + reg: | |
| 23 | + maxItems: 1 | |
| 24 | + | |
| 25 | + clocks: | |
| 26 | + maxItems: 1 | |
| 27 | + | |
| 28 | + dovdd-supply: true | |
| 29 | + | |
| 30 | + avdd-supply: true | |
| 31 | + | |
| 32 | + dvdd-supply: true | |
| 33 | + | |
| 34 | + reset-gpios: | |
| 35 | + description: Reference to the GPIO connected to the RESETB pin. | |
| 36 | + maxItems: 1 | |
| 37 | + | |
| 38 | + port: | |
| 39 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 40 | + additionalProperties: false | |
| 41 | + description: | |
| 42 | + Output port node, single endpoint describing the CSI-2 transmitter. | |
| 43 | + | |
| 44 | + properties: | |
| 45 | + endpoint: | |
| 46 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 47 | + unevaluatedProperties: false | |
| 48 | + | |
| 49 | + properties: | |
| 50 | + data-lanes: | |
| 51 | + oneOf: | |
| 52 | + - items: | |
| 53 | + - const: 1 | |
| 54 | + - const: 2 | |
| 55 | + - const: 3 | |
| 56 | + - const: 4 | |
| 57 | + - items: | |
| 58 | + - const: 1 | |
| 59 | + - const: 2 | |
| 60 | + | |
| 61 | + link-frequencies: true | |
| 62 | + | |
| 63 | + required: | |
| 64 | + - data-lanes | |
| 65 | + - link-frequencies | |
| 66 | + | |
| 67 | + required: | |
| 68 | + - endpoint | |
| 69 | + | |
| 70 | +required: | |
| 71 | + - compatible | |
| 72 | + - reg | |
| 73 | + - clocks | |
| 74 | + - dovdd-supply | |
| 75 | + - avdd-supply | |
| 76 | + - dvdd-supply | |
| 77 | + - reset-gpios | |
| 78 | + - port | |
| 79 | + | |
| 80 | +additionalProperties: false | |
| 81 | + | |
| 82 | +examples: | |
| 83 | + - | | |
| 84 | + #include <dt-bindings/gpio/gpio.h> | |
| 85 | + | |
| 86 | + i2c { | |
| 87 | + #address-cells = <1>; | |
| 88 | + #size-cells = <0>; | |
| 89 | + | |
| 90 | + sensor@31 { | |
| 91 | + compatible = "galaxycore,gc08a3"; | |
| 92 | + reg = <0x31>; | |
| 93 | + | |
| 94 | + clocks = <&gc08a3_clk>; | |
| 95 | + | |
| 96 | + reset-gpios = <&pio 19 GPIO_ACTIVE_LOW>; | |
| 97 | + | |
| 98 | + avdd-supply = <&gc08a3_avdd>; | |
| 99 | + dovdd-supply = <&gc08a3_dovdd>; | |
| 100 | + dvdd-supply = <&gc08a3_dvdd>; | |
| 101 | + | |
| 102 | + port { | |
| 103 | + sensor_out: endpoint { | |
| 104 | + data-lanes = <1 2 3 4>; | |
| 105 | + link-frequencies = /bits/ 64 <336000000 207000000>; | |
| 106 | + remote-endpoint = <&seninf_csi_port_0_in>; | |
| 107 | + }; | |
| 108 | + }; | |
| 109 | + }; | |
| 110 | + }; | |
| 111 | + | |
| 112 | +... | |
| @@ -0,0 +1,174 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +# Copyright (C) 2024 Collabora Ltd. | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: http://devicetree.org/schemas/media/i2c/maxim,max96714.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | + | |
| 8 | +title: Maxim MAX96714 GMSL2 to CSI-2 Deserializer | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Julien Massot <julien.massot@collabora.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The MAX96714 deserializer converts GMSL2 serial inputs into MIPI | |
| 15 | + CSI-2 D-PHY formatted output. The device allows the GMSL2 link to | |
| 16 | + simultaneously transmit bidirectional control-channel data while forward | |
| 17 | + video transmissions are in progress. The MAX96714 can connect to one | |
| 18 | + remotely located serializer using industry-standard coax or STP | |
| 19 | + interconnects. The device cans operate in pixel or tunnel mode. In pixel mode | |
| 20 | + the MAX96714 can select individual video stream, while the tunnel mode forward all | |
| 21 | + the MIPI data received by the serializer. | |
| 22 | + | |
| 23 | + The GMSL2 serial link operates at a fixed rate of 3Gbps or 6Gbps in the | |
| 24 | + forward direction and 187.5Mbps in the reverse direction. | |
| 25 | + MAX96714F only supports a fixed rate of 3Gbps in the forward direction. | |
| 26 | + | |
| 27 | +properties: | |
| 28 | + compatible: | |
| 29 | + oneOf: | |
| 30 | + - const: maxim,max96714f | |
| 31 | + - items: | |
| 32 | + - enum: | |
| 33 | + - maxim,max96714 | |
| 34 | + - const: maxim,max96714f | |
| 35 | + | |
| 36 | + reg: | |
| 37 | + maxItems: 1 | |
| 38 | + | |
| 39 | + powerdown-gpios: | |
| 40 | + maxItems: 1 | |
| 41 | + description: | |
| 42 | + Specifier for the GPIO connected to the PWDNB pin. | |
| 43 | + | |
| 44 | + ports: | |
| 45 | + $ref: /schemas/graph.yaml#/properties/ports | |
| 46 | + | |
| 47 | + properties: | |
| 48 | + port@0: | |
| 49 | + $ref: /schemas/graph.yaml#/properties/port | |
| 50 | + unevaluatedProperties: false | |
| 51 | + description: GMSL Input | |
| 52 | + properties: | |
| 53 | + endpoint: | |
| 54 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 55 | + unevaluatedProperties: false | |
| 56 | + description: | |
| 57 | + Endpoint for GMSL2-Link port. | |
| 58 | + | |
| 59 | + port@1: | |
| 60 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 61 | + unevaluatedProperties: false | |
| 62 | + description: CSI-2 Output port | |
| 63 | + | |
| 64 | + properties: | |
| 65 | + endpoint: | |
| 66 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 67 | + unevaluatedProperties: false | |
| 68 | + | |
| 69 | + properties: | |
| 70 | + data-lanes: | |
| 71 | + minItems: 1 | |
| 72 | + maxItems: 4 | |
| 73 | + | |
| 74 | + lane-polarities: | |
| 75 | + minItems: 1 | |
| 76 | + maxItems: 5 | |
| 77 | + | |
| 78 | + link-frequencies: | |
| 79 | + maxItems: 1 | |
| 80 | + | |
| 81 | + required: | |
| 82 | + - data-lanes | |
| 83 | + | |
| 84 | + required: | |
| 85 | + - port@1 | |
| 86 | + | |
| 87 | + i2c-gate: | |
| 88 | + $ref: /schemas/i2c/i2c-gate.yaml | |
| 89 | + unevaluatedProperties: false | |
| 90 | + description: | |
| 91 | + The MAX96714 will pass through and forward the I2C requests from the | |
| 92 | + incoming I2C bus over the GMSL2 link. Therefore it supports an i2c-gate | |
| 93 | + subnode to configure a serializer. | |
| 94 | + | |
| 95 | + port0-poc-supply: | |
| 96 | + description: Regulator providing Power over Coax for the GMSL port | |
| 97 | + | |
| 98 | +required: | |
| 99 | + - compatible | |
| 100 | + - reg | |
| 101 | + - ports | |
| 102 | + | |
| 103 | +additionalProperties: false | |
| 104 | + | |
| 105 | +examples: | |
| 106 | + - | | |
| 107 | + #include <dt-bindings/gpio/gpio.h> | |
| 108 | + #include <dt-bindings/media/video-interfaces.h> | |
| 109 | + | |
| 110 | + i2c { | |
| 111 | + #address-cells = <1>; | |
| 112 | + #size-cells = <0>; | |
| 113 | + | |
| 114 | + deserializer@28 { | |
| 115 | + compatible = "maxim,max96714f"; | |
| 116 | + reg = <0x28>; | |
| 117 | + powerdown-gpios = <&main_gpio0 37 GPIO_ACTIVE_LOW>; | |
| 118 | + | |
| 119 | + ports { | |
| 120 | + #address-cells = <1>; | |
| 121 | + #size-cells = <0>; | |
| 122 | + port@0 { | |
| 123 | + reg = <0>; | |
| 124 | + max96714_gmsl_in: endpoint { | |
| 125 | + remote-endpoint = <&max96917f_gmsl_out>; | |
| 126 | + }; | |
| 127 | + }; | |
| 128 | + | |
| 129 | + port@1 { | |
| 130 | + reg = <1>; | |
| 131 | + max96714_csi_out: endpoint { | |
| 132 | + data-lanes = <1 2 3 4>; | |
| 133 | + link-frequencies = /bits/ 64 <400000000>; | |
| 134 | + remote-endpoint = <&csi_in>; | |
| 135 | + }; | |
| 136 | + }; | |
| 137 | + }; | |
| 138 | + | |
| 139 | + i2c-gate { | |
| 140 | + #address-cells = <1>; | |
| 141 | + #size-cells = <0>; | |
| 142 | + | |
| 143 | + serializer@40 { | |
| 144 | + compatible = "maxim,max96717f"; | |
| 145 | + reg = <0x40>; | |
| 146 | + gpio-controller; | |
| 147 | + #gpio-cells = <2>; | |
| 148 | + #clock-cells = <0>; | |
| 149 | + | |
| 150 | + ports { | |
| 151 | + #address-cells = <1>; | |
| 152 | + #size-cells = <0>; | |
| 153 | + | |
| 154 | + port@0 { | |
| 155 | + reg = <0>; | |
| 156 | + max96717f_csi_in: endpoint { | |
| 157 | + data-lanes = <1 2>; | |
| 158 | + lane-polarities = <1 0 1>; | |
| 159 | + remote-endpoint = <&sensor_out>; | |
| 160 | + }; | |
| 161 | + }; | |
| 162 | + | |
| 163 | + port@1 { | |
| 164 | + reg = <1>; | |
| 165 | + max96917f_gmsl_out: endpoint { | |
| 166 | + remote-endpoint = <&max96714_gmsl_in>; | |
| 167 | + }; | |
| 168 | + }; | |
| 169 | + }; | |
| 170 | + }; | |
| 171 | + }; | |
| 172 | + }; | |
| 173 | + }; | |
| 174 | +... | |
| @@ -0,0 +1,157 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +# Copyright (C) 2024 Collabora Ltd. | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: http://devicetree.org/schemas/media/i2c/maxim,max96717.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | + | |
| 8 | +title: MAX96717 CSI-2 to GMSL2 Serializer | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Julien Massot <julien.massot@collabora.com> | |
| 12 | + | |
| 13 | +description: | |
| 14 | + The MAX96717 serializer converts MIPI CSI-2 D-PHY formatted input | |
| 15 | + into GMSL2 serial outputs. The device allows the GMSL2 link to | |
| 16 | + simultaneously transmit bidirectional control-channel data while forward | |
| 17 | + video transmissions are in progress. The MAX96717 can connect to one | |
| 18 | + remotely located deserializer using industry-standard coax or STP | |
| 19 | + interconnects. The device cans operate in pixel or tunnel mode. In pixel mode | |
| 20 | + the MAX96717 can select the MIPI datatype, while the tunnel mode forward all the MIPI | |
| 21 | + data received by the serializer. | |
| 22 | + The MAX96717 supports Reference Over Reverse (channel), | |
| 23 | + to generate a clock output for the sensor from the GMSL reverse channel. | |
| 24 | + | |
| 25 | + The GMSL2 serial link operates at a fixed rate of 3Gbps or 6Gbps in the | |
| 26 | + forward direction and 187.5Mbps in the reverse direction. | |
| 27 | + MAX96717F only supports a fixed rate of 3Gbps in the forward direction. | |
| 28 | + | |
| 29 | +properties: | |
| 30 | + compatible: | |
| 31 | + oneOf: | |
| 32 | + - const: maxim,max96717f | |
| 33 | + - items: | |
| 34 | + - enum: | |
| 35 | + - maxim,max96717 | |
| 36 | + - const: maxim,max96717f | |
| 37 | + | |
| 38 | + '#gpio-cells': | |
| 39 | + const: 2 | |
| 40 | + description: | |
| 41 | + First cell is the GPIO pin number, second cell is the flags. The GPIO pin | |
| 42 | + number must be in range of [0, 10]. | |
| 43 | + | |
| 44 | + gpio-controller: true | |
| 45 | + | |
| 46 | + '#clock-cells': | |
| 47 | + const: 0 | |
| 48 | + | |
| 49 | + reg: | |
| 50 | + maxItems: 1 | |
| 51 | + | |
| 52 | + ports: | |
| 53 | + $ref: /schemas/graph.yaml#/properties/ports | |
| 54 | + | |
| 55 | + properties: | |
| 56 | + port@0: | |
| 57 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 58 | + unevaluatedProperties: false | |
| 59 | + description: CSI-2 Input port | |
| 60 | + | |
| 61 | + properties: | |
| 62 | + endpoint: | |
| 63 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 64 | + unevaluatedProperties: false | |
| 65 | + | |
| 66 | + properties: | |
| 67 | + data-lanes: | |
| 68 | + minItems: 1 | |
| 69 | + maxItems: 4 | |
| 70 | + | |
| 71 | + lane-polarities: | |
| 72 | + minItems: 1 | |
| 73 | + maxItems: 5 | |
| 74 | + | |
| 75 | + required: | |
| 76 | + - data-lanes | |
| 77 | + | |
| 78 | + port@1: | |
| 79 | + $ref: /schemas/graph.yaml#/properties/port | |
| 80 | + unevaluatedProperties: false | |
| 81 | + description: GMSL Output port | |
| 82 | + | |
| 83 | + required: | |
| 84 | + - port@1 | |
| 85 | + | |
| 86 | + i2c-gate: | |
| 87 | + $ref: /schemas/i2c/i2c-gate.yaml | |
| 88 | + unevaluatedProperties: false | |
| 89 | + description: | |
| 90 | + The MAX96717 will forward the I2C requests from the | |
| 91 | + incoming GMSL2 link. Therefore, it supports an i2c-gate | |
| 92 | + subnode to configure a sensor. | |
| 93 | + | |
| 94 | +required: | |
| 95 | + - compatible | |
| 96 | + - reg | |
| 97 | + - ports | |
| 98 | + | |
| 99 | +additionalProperties: false | |
| 100 | + | |
| 101 | +examples: | |
| 102 | + - | | |
| 103 | + #include <dt-bindings/gpio/gpio.h> | |
| 104 | + #include <dt-bindings/media/video-interfaces.h> | |
| 105 | + | |
| 106 | + i2c { | |
| 107 | + #address-cells = <1>; | |
| 108 | + #size-cells = <0>; | |
| 109 | + serializer: serializer@40 { | |
| 110 | + compatible = "maxim,max96717f"; | |
| 111 | + reg = <0x40>; | |
| 112 | + gpio-controller; | |
| 113 | + #gpio-cells = <2>; | |
| 114 | + #clock-cells = <0>; | |
| 115 | + | |
| 116 | + ports { | |
| 117 | + #address-cells = <1>; | |
| 118 | + #size-cells = <0>; | |
| 119 | + | |
| 120 | + port@0 { | |
| 121 | + reg = <0>; | |
| 122 | + max96717f_csi_in: endpoint { | |
| 123 | + data-lanes = <1 2 3 4>; | |
| 124 | + remote-endpoint = <&sensor_out>; | |
| 125 | + }; | |
| 126 | + }; | |
| 127 | + | |
| 128 | + port@1 { | |
| 129 | + reg = <1>; | |
| 130 | + max96917f_gmsl_out: endpoint { | |
| 131 | + remote-endpoint = <&deser_gmsl_in>; | |
| 132 | + }; | |
| 133 | + }; | |
| 134 | + }; | |
| 135 | + | |
| 136 | + i2c-gate { | |
| 137 | + #address-cells = <1>; | |
| 138 | + #size-cells = <0>; | |
| 139 | + sensor@10 { | |
| 140 | + compatible = "st,st-vgxy61"; | |
| 141 | + reg = <0x10>; | |
| 142 | + reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>; | |
| 143 | + clocks = <&serializer>; | |
| 144 | + VCORE-supply = <&v1v2>; | |
| 145 | + VDDIO-supply = <&v1v8>; | |
| 146 | + VANA-supply = <&v2v8>; | |
| 147 | + port { | |
| 148 | + sensor_out: endpoint { | |
| 149 | + data-lanes = <1 2 3 4>; | |
| 150 | + remote-endpoint = <&max96717f_csi_in>; | |
| 151 | + }; | |
| 152 | + }; | |
| 153 | + }; | |
| 154 | + }; | |
| 155 | + }; | |
| 156 | + }; | |
| 157 | +... | |
| @@ -1,7 +1,7 @@ | ||
| 1 | 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
| 2 | 2 | %YAML 1.2 |
| 3 | 3 | --- |
| 4 | −$id: http://devicetree.org/schemas/media/i2c/imx258.yaml# | |
| 4 | +$id: http://devicetree.org/schemas/media/i2c/sony,imx258.yaml# | |
| 5 | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | |
| 7 | 7 | title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor |
| @@ -13,11 +13,16 @@ description: |- · 5 unmodified lines | ||
| 13 | 13 | IMX258 is a diagonal 5.867mm (Type 1/3.06) 13 Mega-pixel CMOS active pixel |
| 14 | 14 | type stacked image sensor with a square pixel array of size 4208 x 3120. It |
| 15 | 15 | is programmable through I2C interface. Image data is sent through MIPI |
| 16 | − CSI-2. | |
| 16 | + CSI-2. The sensor exists in two different models, a standard variant | |
| 17 | + (IMX258) and a variant with phase detection autofocus (IMX258-PDAF). | |
| 18 | + The camera module does not expose the model through registers, so the | |
| 19 | + exact model needs to be specified. | |
| 17 | 20 | |
| 18 | 21 | properties: |
| 19 | 22 | compatible: |
| 20 | − const: sony,imx258 | |
| 23 | + enum: | |
| 24 | + - sony,imx258 | |
| 25 | + - sony,imx258-pdaf | |
| 21 | 26 | |
| 22 | 27 | assigned-clocks: true |
| 23 | 28 | assigned-clock-parents: true |
| @@ -0,0 +1,107 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +# Copyright (C) 2024 Ideas on Board Oy | |
| 3 | +%YAML 1.2 | |
| 4 | +--- | |
| 5 | +$id: http://devicetree.org/schemas/media/i2c/sony,imx283.yaml# | |
| 6 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 7 | + | |
| 8 | +title: Sony IMX283 Sensor | |
| 9 | + | |
| 10 | +maintainers: | |
| 11 | + - Kieran Bingham <kieran.bingham@ideasonboard.com> | |
| 12 | + - Umang Jain <umang.jain@ideasonboard.com> | |
| 13 | + | |
| 14 | +description: | |
| 15 | + IMX283 sensor is a Sony CMOS active pixel digital image sensor with an active | |
| 16 | + array size of 5472H x 3648V. It is programmable through I2C interface. The | |
| 17 | + I2C client address is fixed to 0x1a as per sensor data sheet. Image data is | |
| 18 | + sent through MIPI CSI-2. | |
| 19 | + | |
| 20 | +properties: | |
| 21 | + compatible: | |
| 22 | + const: sony,imx283 | |
| 23 | + | |
| 24 | + reg: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + description: Clock frequency from 6 to 24 MHz. | |
| 29 | + maxItems: 1 | |
| 30 | + | |
| 31 | + vadd-supply: | |
| 32 | + description: Analog power supply (2.9V) | |
| 33 | + | |
| 34 | + vdd1-supply: | |
| 35 | + description: Interface power supply (1.8V) | |
| 36 | + | |
| 37 | + vdd2-supply: | |
| 38 | + description: Digital power supply (1.2V) | |
| 39 | + | |
| 40 | + reset-gpios: | |
| 41 | + description: Sensor reset (XCLR) GPIO | |
| 42 | + maxItems: 1 | |
| 43 | + | |
| 44 | + port: | |
| 45 | + $ref: /schemas/graph.yaml#/$defs/port-base | |
| 46 | + additionalProperties: false | |
| 47 | + | |
| 48 | + properties: | |
| 49 | + endpoint: | |
| 50 | + $ref: /schemas/media/video-interfaces.yaml# | |
| 51 | + unevaluatedProperties: false | |
| 52 | + | |
| 53 | + properties: | |
| 54 | + data-lanes: | |
| 55 | + anyOf: | |
| 56 | + - items: | |
| 57 | + - const: 1 | |
| 58 | + - const: 2 | |
| 59 | + - const: 3 | |
| 60 | + - const: 4 | |
| 61 | + | |
| 62 | + link-frequencies: true | |
| 63 | + | |
| 64 | + required: | |
| 65 | + - data-lanes | |
| 66 | + - link-frequencies | |
| 67 | + | |
| 68 | + required: | |
| 69 | + - endpoint | |
| 70 | + | |
| 71 | +required: | |
| 72 | + - compatible | |
| 73 | + - reg | |
| 74 | + - clocks | |
| 75 | + - port | |
| 76 | + | |
| 77 | +additionalProperties: false | |
| 78 | + | |
| 79 | +examples: | |
| 80 | + - | | |
| 81 | + i2c { | |
| 82 | + #address-cells = <1>; | |
| 83 | + #size-cells = <0>; | |
| 84 | + | |
| 85 | + camera@1a { | |
| 86 | + compatible = "sony,imx283"; | |
| 87 | + reg = <0x1a>; | |
| 88 | + clocks = <&imx283_clk>; | |
| 89 | + | |
| 90 | + assigned-clocks = <&imx283_clk>; | |
| 91 | + assigned-clock-parents = <&imx283_clk_parent>; | |
| 92 | + assigned-clock-rates = <12000000>; | |
| 93 | + | |
| 94 | + vadd-supply = <&camera_vadd_2v9>; | |
| 95 | + vdd1-supply = <&camera_vdd1_1v8>; | |
| 96 | + vdd2-supply = <&camera_vdd2_1v2>; | |
| 97 | + | |
| 98 | + port { | |
| 99 | + imx283: endpoint { | |
| 100 | + remote-endpoint = <&cam>; | |
| 101 | + data-lanes = <1 2 3 4>; | |
| 102 | + link-frequencies = /bits/ 64 <360000000>; | |
| 103 | + }; | |
| 104 | + }; | |
| 105 | + }; | |
| 106 | + }; | |
| 107 | +... | |
| @@ -0,0 +1,75 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/img,e5010-jpeg-enc.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Imagination E5010 JPEG Encoder | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Devarsh Thakkar <devarsht@ti.com> | |
| 11 | + | |
| 12 | +description: | | |
| 13 | + The E5010 is a JPEG encoder from Imagination Technologies implemented on | |
| 14 | + TI's AM62A SoC. It is capable of real time encoding of YUV420 and YUV422 | |
| 15 | + inputs to JPEG and M-JPEG. It supports baseline JPEG Encoding up to | |
| 16 | + 8Kx8K resolution. | |
| 17 | + | |
| 18 | +properties: | |
| 19 | + compatible: | |
| 20 | + oneOf: | |
| 21 | + - items: | |
| 22 | + - const: ti,am62a-jpeg-enc | |
| 23 | + - const: img,e5010-jpeg-enc | |
| 24 | + - const: img,e5010-jpeg-enc | |
| 25 | + | |
| 26 | + reg: | |
| 27 | + items: | |
| 28 | + - description: The E5010 core register region | |
| 29 | + - description: The E5010 mmu register region | |
| 30 | + | |
| 31 | + reg-names: | |
| 32 | + items: | |
| 33 | + - const: core | |
| 34 | + - const: mmu | |
| 35 | + | |
| 36 | + power-domains: | |
| 37 | + maxItems: 1 | |
| 38 | + | |
| 39 | + resets: | |
| 40 | + maxItems: 1 | |
| 41 | + | |
| 42 | + clocks: | |
| 43 | + maxItems: 1 | |
| 44 | + | |
| 45 | + interrupts: | |
| 46 | + maxItems: 1 | |
| 47 | + | |
| 48 | +required: | |
| 49 | + - compatible | |
| 50 | + - reg | |
| 51 | + - reg-names | |
| 52 | + - interrupts | |
| 53 | + - clocks | |
| 54 | + | |
| 55 | +additionalProperties: false | |
| 56 | + | |
| 57 | +examples: | |
| 58 | + - | | |
| 59 | + #include <dt-bindings/soc/ti,sci_pm_domain.h> | |
| 60 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 61 | + #include <dt-bindings/interrupt-controller/irq.h> | |
| 62 | + | |
| 63 | + soc { | |
| 64 | + #address-cells = <2>; | |
| 65 | + #size-cells = <2>; | |
| 66 | + jpeg-encoder@fd20000 { | |
| 67 | + compatible = "img,e5010-jpeg-enc"; | |
| 68 | + reg = <0x00 0xfd20000 0x00 0x100>, | |
| 69 | + <0x00 0xfd20200 0x00 0x200>; | |
| 70 | + reg-names = "core", "mmu"; | |
| 71 | + clocks = <&k3_clks 201 0>; | |
| 72 | + power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>; | |
| 73 | + interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>; | |
| 74 | + }; | |
| 75 | + }; | |
| @@ -23,6 +23,7 @@ properties: · 22 unmodified lines | ||
| 23 | 23 | oneOf: |
| 24 | 24 | - enum: |
| 25 | 25 | - mediatek,mt8183-mdp3-rdma |
| 26 | + - mediatek,mt8188-mdp3-rdma | |
| 26 | 27 | - mediatek,mt8195-mdp3-rdma |
| 27 | 28 | - mediatek,mt8195-vdo1-rdma |
| 28 | 29 | - items: |
| @@ -0,0 +1,55 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/mediatek,mt7622-cir.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: MediaTek Consumer Infrared Receiver on-SoC Controller | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Sean Wang <sean.wang@mediatek.com> | |
| 11 | + | |
| 12 | +allOf: | |
| 13 | + - $ref: rc.yaml# | |
| 14 | + | |
| 15 | +properties: | |
| 16 | + compatible: | |
| 17 | + enum: | |
| 18 | + - mediatek,mt7622-cir | |
| 19 | + - mediatek,mt7623-cir | |
| 20 | + | |
| 21 | + reg: | |
| 22 | + maxItems: 1 | |
| 23 | + | |
| 24 | + interrupts: | |
| 25 | + maxItems: 1 | |
| 26 | + | |
| 27 | + clocks: | |
| 28 | + maxItems: 2 | |
| 29 | + | |
| 30 | + clock-names: | |
| 31 | + items: | |
| 32 | + - const: clk | |
| 33 | + - const: bus | |
| 34 | + | |
| 35 | +required: | |
| 36 | + - reg | |
| 37 | + - interrupts | |
| 38 | + - clocks | |
| 39 | + - clock-names | |
| 40 | + | |
| 41 | +unevaluatedProperties: false | |
| 42 | + | |
| 43 | +examples: | |
| 44 | + - | | |
| 45 | + #include <dt-bindings/clock/mt2701-clk.h> | |
| 46 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 47 | + | |
| 48 | + ir@10013000 { | |
| 49 | + compatible = "mediatek,mt7623-cir"; | |
| 50 | + reg = <0x10013000 0x1000>; | |
| 51 | + interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>; | |
| 52 | + clocks = <&infracfg CLK_INFRA_IRRX>, <&topckgen CLK_TOP_AXI_SEL>; | |
| 53 | + clock-names = "clk", "bus"; | |
| 54 | + linux,rc-map-name = "rc-rc6-mce"; | |
| 55 | + }; | |
| @@ -1,28 +0,0 @@ | ||
| 1 | −Device-Tree bindings for Mediatek consumer IR controller | |
| 2 | −found in Mediatek SoC family | |
| 3 | − | |
| 4 | −Required properties: | |
| 5 | −- compatible : Should be | |
| 6 | − "mediatek,mt7623-cir": for MT7623 SoC | |
| 7 | − "mediatek,mt7622-cir": for MT7622 SoC | |
| 8 | −- clocks : list of clock specifiers, corresponding to | |
| 9 | − entries in clock-names property; | |
| 10 | −- clock-names : should contain | |
| 11 | − - "clk" entries: for MT7623 SoC | |
| 12 | − - "clk", "bus" entries: for MT7622 SoC | |
| 13 | −- interrupts : should contain IR IRQ number; | |
| 14 | −- reg : should contain IO map address for IR. | |
| 15 | − | |
| 16 | −Optional properties: | |
| 17 | −- linux,rc-map-name : see rc.txt file in the same directory. | |
| 18 | − | |
| 19 | −Example: | |
| 20 | − | |
| 21 | −cir: cir@10013000 { | |
| 22 | − compatible = "mediatek,mt7623-cir"; | |
| 23 | − reg = <0 0x10013000 0 0x1000>; | |
| 24 | − interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>; | |
| 25 | − clocks = <&infracfg CLK_INFRA_IRRX>; | |
| 26 | − clock-names = "clk"; | |
| 27 | − linux,rc-map-name = "rc-rc6-mce"; | |
| 28 | −}; | |
| @@ -18,7 +18,9 @@ allOf: · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | properties: |
| 20 | 20 | compatible: |
| 21 | − const: qcom,msm8996-venus | |
| 21 | + enum: | |
| 22 | + - qcom,msm8996-venus | |
| 23 | + - qcom,msm8998-venus | |
| 22 | 24 | |
| 23 | 25 | power-domains: |
| 24 | 26 | maxItems: 1 |
| @@ -0,0 +1,63 @@ | ||
| 1 | +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | |
| 2 | +%YAML 1.2 | |
| 3 | +--- | |
| 4 | +$id: http://devicetree.org/schemas/media/raspberrypi,pispbe.yaml# | |
| 5 | +$schema: http://devicetree.org/meta-schemas/core.yaml# | |
| 6 | + | |
| 7 | +title: Raspberry Pi PiSP Image Signal Processor (ISP) Back End | |
| 8 | + | |
| 9 | +maintainers: | |
| 10 | + - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com> | |
| 11 | + - Jacopo Mondi <jacopo.mondi@ideasonboard.com> | |
| 12 | + | |
| 13 | +description: | | |
| 14 | + The Raspberry Pi PiSP Image Signal Processor (ISP) Back End is an image | |
| 15 | + processor that fetches images in Bayer or Grayscale format from DRAM memory | |
| 16 | + in tiles and produces images consumable by applications. | |
| 17 | + | |
| 18 | + The full ISP documentation is available at | |
| 19 | + https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf | |
| 20 | + | |
| 21 | +properties: | |
| 22 | + compatible: | |
| 23 | + items: | |
| 24 | + - enum: | |
| 25 | + - brcm,bcm2712-pispbe | |
| 26 | + - const: raspberrypi,pispbe | |
| 27 | + | |
| 28 | + reg: | |
| 29 | + maxItems: 1 | |
| 30 | + | |
| 31 | + interrupts: | |
| 32 | + maxItems: 1 | |
| 33 | + | |
| 34 | + clocks: | |
| 35 | + maxItems: 1 | |
| 36 | + | |
| 37 | + iommus: | |
| 38 | + maxItems: 1 | |
| 39 | + | |
| 40 | +required: | |
| 41 | + - compatible | |
| 42 | + - reg | |
| 43 | + - interrupts | |
| 44 | + - clocks | |
| 45 | + | |
| 46 | +additionalProperties: false | |
| 47 | + | |
| 48 | +examples: | |
| 49 | + - | | |
| 50 | + #include <dt-bindings/interrupt-controller/arm-gic.h> | |
| 51 | + | |
| 52 | + soc { | |
| 53 | + #address-cells = <2>; | |
| 54 | + #size-cells = <2>; | |
| 55 | + | |
| 56 | + isp@880000 { | |
| 57 | + compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe"; | |
| 58 | + reg = <0x10 0x00880000 0x0 0x4000>; | |
| 59 | + interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>; | |
| 60 | + clocks = <&firmware_clocks 7>; | |
| 61 | + iommus = <&iommu2>; | |
| 62 | + }; | |
| 63 | + }; | |
| @@ -103,6 +103,7 @@ properties: · 102 unmodified lines | ||
| 103 | 103 | - rc-msi-digivox-iii |
| 104 | 104 | - rc-msi-tvanywhere |
| 105 | 105 | - rc-msi-tvanywhere-plus |
| 106 | + - rc-mygica-utv3 | |
| 106 | 107 | - rc-nebula |
| 107 | 108 | - rc-nec-terratec-cinergy-xs |
| 108 | 109 | - rc-norwood |
| @@ -24,6 +24,7 @@ properties: · 23 unmodified lines | ||
| 24 | 24 | - enum: |
| 25 | 25 | - rockchip,rk3228-rga |
| 26 | 26 | - rockchip,rk3568-rga |
| 27 | + - rockchip,rk3588-rga | |
| 27 | 28 | - const: rockchip,rk3288-rga |
| 28 | 29 | |
| 29 | 30 | reg: |
| @@ -26,3 +26,4 @@ Video4Linux devices · 25 unmodified lines | ||
| 26 | 26 | v4l2-tuner |
| 27 | 27 | v4l2-common |
| 28 | 28 | v4l2-tveeprom |
| 29 | + v4l2-jpeg | |
| @@ -0,0 +1,10 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +V4L2 JPEG header related functions and data structures | |
| 4 | +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | |
| 5 | + | |
| 6 | +.. kernel-doc:: include/media/v4l2-jpeg.h | |
| 7 | + :internal: | |
| 8 | + | |
| 9 | +.. kernel-doc:: drivers/media/v4l2-core/v4l2-jpeg.c | |
| 10 | + :export: | |
| @@ -35,6 +35,6 @@ For more details see the file COPYING in the source distribution of Linux. · 34 unmodified lines | ||
| 35 | 35 | max2175 |
| 36 | 36 | npcm-video |
| 37 | 37 | omap3isp-uapi |
| 38 | − st-vgxy61 | |
| 39 | 38 | thp7312 |
| 40 | 39 | uvcvideo |
| 40 | + vgxy61 | |
File renamed without changes.
| @@ -971,8 +971,8 @@ FWHT Flags · 970 unmodified lines | ||
| 971 | 971 | - ``horizontal_scale`` |
| 972 | 972 | - Horizontal scaling factor. |
| 973 | 973 | * - __u8 |
| 974 | − - ``vertical_scaling factor`` | |
| 975 | − - Vertical scale. | |
| 974 | + - ``vertical_scale`` | |
| 975 | + - Vertical scaling factor. | |
| 976 | 976 | * - __u8 |
| 977 | 977 | - ``version`` |
| 978 | 978 | - Bitstream version. |
| @@ -1653,6 +1653,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - · 1652 unmodified lines | ||
| 1653 | 1653 | Quantization parameter for a P frame for FWHT. Valid range: from 1 |
| 1654 | 1654 | to 31. |
| 1655 | 1655 | |
| 1656 | +``V4L2_CID_MPEG_VIDEO_AVERAGE_QP (integer)`` | |
| 1657 | + This read-only control returns the average QP value of the currently | |
| 1658 | + encoded frame. The value applies to the last dequeued capture buffer | |
| 1659 | + (VIDIOC_DQBUF). Its valid range depends on the encoding format and parameters. | |
| 1660 | + For H264, its valid range is from 0 to 51. | |
| 1661 | + For HEVC, its valid range is from 0 to 51 for 8 bit and | |
| 1662 | + from 0 to 63 for 10 bit. | |
| 1663 | + For H263 and MPEG4, its valid range is from 1 to 31. | |
| 1664 | + For VP8, its valid range is from 0 to 127. | |
| 1665 | + For VP9, its valid range is from 0 to 255. | |
| 1666 | + If the codec's MIN_QP and MAX_QP are set, then the QP will meet both requirements. | |
| 1667 | + Codecs need to always use the specified range, rather then a HW custom range. | |
| 1668 | + Applicable to encoders | |
| 1669 | + | |
| 1656 | 1670 | .. raw:: latex |
| 1657 | 1671 | |
| 1658 | 1672 | \normalsize |
| @@ -15,6 +15,7 @@ These formats are used for the :ref:`metadata` interface only. · 14 unmodified lines | ||
| 15 | 15 | metafmt-d4xx |
| 16 | 16 | metafmt-generic |
| 17 | 17 | metafmt-intel-ipu3 |
| 18 | + metafmt-pisp-be | |
| 18 | 19 | metafmt-rkisp1 |
| 19 | 20 | metafmt-uvc |
| 20 | 21 | metafmt-vivid |
| @@ -0,0 +1,56 @@ | ||
| 1 | +.. SPDX-License-Identifier: GPL-2.0 | |
| 2 | + | |
| 3 | +.. _v4l2-meta-fmt-rpi-be-cfg: | |
| 4 | + | |
| 5 | +************************ | |
| 6 | +V4L2_META_FMT_RPI_BE_CFG | |
| 7 | +************************ | |
| 8 | + | |
| 9 | +Raspberry Pi PiSP Back End configuration format | |
| 10 | +=============================================== | |
| 11 | + | |
| 12 | +The Raspberry Pi PiSP Back End memory-to-memory image signal processor is | |
| 13 | +configured by userspace by providing a buffer of configuration parameters | |
| 14 | +to the `pispbe-config` output video device node using the | |
| 15 | +:c:type:`v4l2_meta_format` interface. | |
| 16 | + | |
| 17 | +The PiSP Back End processes images in tiles, and its configuration requires | |
| 18 | +specifying two different sets of parameters by populating the members of | |
| 19 | +:c:type:`pisp_be_tiles_config` defined in the ``pisp_be_config.h`` header file. | |
| 20 | + | |
| 21 | +The `Raspberry Pi PiSP technical specification | |
| 22 | +<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_ | |
| 23 | +provide detailed description of the ISP back end configuration and programming | |
| 24 | +model. | |
| 25 | + | |
| 26 | +Global configuration data | |
| 27 | +------------------------- | |
| 28 | + | |
| 29 | +The global configuration data describe how the pixels in a particular image are | |
| 30 | +to be processed and is therefore shared across all the tiles of the image. So | |
| 31 | +for example, LSC (Lens Shading Correction) or Denoise parameters would be common | |
| 32 | +across all tiles from the same frame. | |
| 33 | + | |
| 34 | +Global configuration data are passed to the ISP by populating the member of | |
| 35 | +:c:type:`pisp_be_config`. | |
| 36 | + | |
| 37 | +Tile parameters | |
| 38 | +--------------- | |
| 39 | + | |
| 40 | +As the ISP processes images in tiles, each set of tiles parameters describe how | |
| 41 | +a single tile in an image is going to be processed. A single set of tile | |
| 42 | +parameters consist of 160 bytes of data and to process a batch of tiles several | |
| 43 | +sets of tiles parameters are required. | |
| 44 | + | |
| 45 | +Tiles parameters are passed to the ISP by populating the member of | |
| 46 | +``pisp_tile`` and the ``num_tiles`` fields of :c:type:`pisp_be_tiles_config`. | |
| 47 | + | |
| 48 | +Raspberry Pi PiSP Back End uAPI data types | |
| 49 | +========================================== | |
| 50 | + | |
| 51 | +This section describes the data types exposed to userspace by the Raspberry Pi | |
| 52 | +PiSP Back End. The section is informative only, for a detailed description of | |
| 53 | +each field refer to the `Raspberry Pi PiSP technical specification | |
| 54 | +<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_. | |
| 55 | + | |
| 56 | +.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h | |
| @@ -20,6 +20,7 @@ orders. See also `the Wikipedia article on Bayer filter · 19 unmodified lines | ||
| 20 | 20 | :maxdepth: 1 |
| 21 | 21 | |
| 22 | 22 | pixfmt-srggb8 |
| 23 | + pixfmt-srggb8-pisp-comp | |
| 23 | 24 | pixfmt-srggb10 |
| 24 | 25 | pixfmt-srggb10p |
| 25 | 26 | pixfmt-srggb10alaw8 |
| @@ -996,6 +996,60 @@ arranged in little endian order. · 995 unmodified lines | ||
| 996 | 996 | |
| 997 | 997 | \normalsize |
| 998 | 998 | |
| 999 | +16 Bits Per Component | |
| 1000 | +===================== | |
| 1001 | + | |
| 1002 | +These formats store an RGB triplet in six bytes, with 16 bits per component | |
| 1003 | +stored in memory in little endian byte order. They are named based on the order | |
| 1004 | +of the RGB components as stored in memory. For instance, RGB48 stores R\ | |
| 1005 | +:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from | |
| 1006 | +the DRM format nomenclature that instead uses the order of components as seen in | |
| 1007 | +the 48-bits little endian word. | |
| 1008 | + | |
| 1009 | +.. raw:: latex | |
| 1010 | + | |
| 1011 | + \small | |
| 1012 | + | |
| 1013 | +.. flat-table:: RGB Formats With 16 Bits Per Component | |
| 1014 | + :header-rows: 1 | |
| 1015 | + | |
| 1016 | + * - Identifier | |
| 1017 | + - Code | |
| 1018 | + - Byte 0 | |
| 1019 | + - Byte 1 | |
| 1020 | + - Byte 2 | |
| 1021 | + - Byte 3 | |
| 1022 | + - Byte 4 | |
| 1023 | + - Byte 5 | |
| 1024 | + | |
| 1025 | + * .. _V4L2-PIX-FMT-BGR48: | |
| 1026 | + | |
| 1027 | + - ``V4L2_PIX_FMT_BGR48`` | |
| 1028 | + - 'BGR6' | |
| 1029 | + | |
| 1030 | + - B\ :sub:`7-0` | |
| 1031 | + - B\ :sub:`15-8` | |
| 1032 | + - G\ :sub:`7-0` | |
| 1033 | + - G\ :sub:`15-8` | |
| 1034 | + - R\ :sub:`7-0` | |
| 1035 | + - R\ :sub:`15-8` | |
| 1036 | + | |
| 1037 | + * .. _V4L2-PIX-FMT-RGB48: | |
| 1038 | + | |
| 1039 | + - ``V4L2_PIX_FMT_RGB48`` | |
| 1040 | + - 'RGB6' | |
| 1041 | + | |
| 1042 | + - R\ :sub:`7-0` | |
| 1043 | + - R\ :sub:`15-8` | |
| 1044 | + - G\ :sub:`7-0` | |
| 1045 | + - G\ :sub:`15-8` | |
| 1046 | + - B\ :sub:`7-0` | |
| 1047 | + - B\ :sub:`15-8` | |
| 1048 | + | |
| 1049 | +.. raw:: latex | |
| 1050 | + | |
| 1051 | + \normalsize | |
| 1052 | + | |
| 999 | 1053 | Deprecated RGB Formats |
| 1000 | 1054 | ====================== |
| 1001 | 1055 | |
| @@ -0,0 +1,74 @@ | ||
| 1 | +.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later | |
| 2 | + | |
| 3 | +.. _v4l2-pix-fmt-pisp-comp1-rggb: | |
| 4 | +.. _v4l2-pix-fmt-pisp-comp1-grbg: | |
| 5 | +.. _v4l2-pix-fmt-pisp-comp1-gbrg: | |
| 6 | +.. _v4l2-pix-fmt-pisp-comp1-bggr: | |
| 7 | +.. _v4l2-pix-fmt-pisp-comp1-mono: | |
| 8 | +.. _v4l2-pix-fmt-pisp-comp2-rggb: | |
| 9 | +.. _v4l2-pix-fmt-pisp-comp2-grbg: | |
| 10 | +.. _v4l2-pix-fmt-pisp-comp2-gbrg: | |
| 11 | +.. _v4l2-pix-fmt-pisp-comp2-bggr: | |
| 12 | +.. _v4l2-pix-fmt-pisp-comp2-mono: | |
| 13 | + | |
| 14 | +************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** | |
| 15 | +V4L2_PIX_FMT_PISP_COMP1_RGGB ('PC1R'), V4L2_PIX_FMT_PISP_COMP1_GRBG ('PC1G'), V4L2_PIX_FMT_PISP_COMP1_GBRG ('PC1g'), V4L2_PIX_FMT_PISP_COMP1_BGGR ('PC1B), V4L2_PIX_FMT_PISP_COMP1_MONO ('PC1M'), V4L2_PIX_FMT_PISP_COMP2_RGGB ('PC2R'), V4L2_PIX_FMT_PISP_COMP2_GRBG ('PC2G'), V4L2_PIX_FMT_PISP_COMP2_GBRG ('PC2g'), V4L2_PIX_FMT_PISP_COMP2_BGGR ('PC2B), V4L2_PIX_FMT_PISP_COMP2_MONO ('PC2M') | |
| 16 | +************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** | |
| 17 | + | |
| 18 | +================================================ | |
| 19 | +Raspberry Pi PiSP compressed 8-bit Bayer formats | |
| 20 | +================================================ | |
| 21 | + | |
| 22 | +Description | |
| 23 | +=========== | |
| 24 | + | |
| 25 | +The Raspberry Pi ISP (PiSP) uses a family of three fixed-rate compressed Bayer | |
| 26 | +formats. A black-level offset may be subtracted to improve compression | |
| 27 | +efficiency; the nominal black level and amount of offset must be signalled out | |
| 28 | +of band. Each scanline is padded to a multiple of 8 pixels wide, and each block | |
| 29 | +of 8 horizontally-contiguous pixels is coded using 8 bytes. | |
| 30 | + | |
| 31 | +Mode 1 uses a quantization and delta-based coding scheme which preserves up to | |
| 32 | +12 significant bits. Mode 2 is a simple sqrt-like companding scheme with 6 PWL | |
| 33 | +chords, preserving up to 12 significant bits. Mode 3 combines both companding | |
| 34 | +(with 4 chords) and the delta scheme, preserving up to 14 significant bits. | |
| 35 | + | |
| 36 | +The remainder of this description applies to Modes 1 and 3. | |
| 37 | + | |
| 38 | +Each block of 8 pixels is separated into even and odd phases of 4 pixels, | |
| 39 | +coded independently by 32-bit words at successive locations in memory. | |
| 40 | +The two LS bits of each 32-bit word give its "quantization mode". | |
| 41 | + | |
| 42 | +In quantization mode 0, the lowest 321 quantization levels are multiples of | |
| 43 | +FSD/4096 and the remaining levels are successive multiples of FSD/2048. | |
| 44 | +Quantization modes 1 and 2 use linear quantization with step sizes of | |
| 45 | +FSD/1024 and FSD/512 respectively. Each of the four pixels is quantized | |
| 46 | +independently, with rounding to the nearest level. | |
| 47 | +In quantization mode 2 where the middle two samples have quantized values | |
| 48 | +(q1,q2) both in the range [384..511], they are coded using 9 bits for q1 | |
| 49 | +followed by 7 bits for (q2 & 127). Otherwise, for quantization modes | |
| 50 | +0, 1 and 2: a 9-bit field encodes MIN(q1,q2) which must be in the range | |
| 51 | +[0..511] and a 7-bit field encodes (q2-q1+64) which must be in [0..127]. | |
| 52 | + | |
| 53 | +Each of the outer samples (q0,q3) is encoded using a 7-bit field based | |
| 54 | +on its inner neighbour q1 or q2. In quantization mode 2 where the inner | |
| 55 | +sample has a quantized value in the range [448..511], the field value is | |
| 56 | +(q0-384). Otherwise for quantization modes 0, 1 and 2: The outer sample | |
| 57 | +is encoded as (q0-MAX(0,q1-64)). q3 is likewise coded based on q2. | |
| 58 | +Each of these values must be in the range [0..127]. All these fields | |
| 59 | +of 2, 9, 7, 7, 7 bits respectively are packed in little-endian order | |
| 60 | +to give a 32-bit word with LE byte order. | |
| 61 | + | |
| 62 | +Quantization mode 3 has a "7.5-bit" escape, used when none of the above | |
| 63 | +encodings will fit. Each pixel value is quantized to the nearest of 176 | |
| 64 | +levels, where the lowest 95 levels are multiples of FSD/256 and the | |
| 65 | +remaining levels are multiples of FSD/128 (level 175 represents values | |
| 66 | +very close to FSD and may require saturating arithmetic to decode). | |
| 67 | + | |
| 68 | +Each pair of quantized pixels (q0,q1) or (q2,q3) is jointly coded | |
| 69 | +by a 15-bit field: 2816*(q0>>4) + 16*q1 + (q0&15). | |
| 70 | +Three fields of 2, 15, 15 bits are packed in LE order {15,15,2}. | |
| 71 | + | |
| 72 | +An implementation of a software decoder of compressed formats is available | |
| 73 | +in `Raspberry Pi camera applications code base | |
| 74 | +<https://github.com/raspberrypi/rpicam-apps/blob/main/image/dng.cpp>`_. | |
| @@ -209,3 +209,7 @@ are often referred to as greyscale formats. · 208 unmodified lines | ||
| 209 | 209 | For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with |
| 210 | 210 | padding zeros in the 4 low bits, in contrast to the Y12 format, which has |
| 211 | 211 | its padding located in the most significant bits of the 16 bit word. |
| 212 | + | |
| 213 | + The 'P' variations of the Y10, Y12 and Y14 formats are packed according to | |
| 214 | + the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2 | |
| 215 | + specification. | |
| @@ -9190,6 +9190,20 @@ S: Maintained · 9189 unmodified lines | ||
| 9190 | 9190 | F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml |
| 9191 | 9191 | F: drivers/media/i2c/gc0308.c |
| 9192 | 9192 | |
| 9193 | +GALAXYCORE GC05a2 CAMERA SENSOR DRIVER | |
| 9194 | +M: Zhi Mao <zhi.mao@mediatek.com> | |
| 9195 | +L: linux-media@vger.kernel.org | |
| 9196 | +S: Maintained | |
| 9197 | +F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml | |
| 9198 | +F: drivers/media/i2c/gc05a2.c | |
| 9199 | + | |
| 9200 | +GALAXYCORE GC08A3 CAMERA SENSOR DRIVER | |
| 9201 | +M: Zhi Mao <zhi.mao@mediatek.com> | |
| 9202 | +L: linux-media@vger.kernel.org | |
| 9203 | +S: Maintained | |
| 9204 | +F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml | |
| 9205 | +F: drivers/media/i2c/gc08a3.c | |
| 9206 | + | |
| 9193 | 9207 | GALAXYCORE GC2145 SENSOR DRIVER |
| 9194 | 9208 | M: Alain Volmat <alain.volmat@foss.st.com> |
| 9195 | 9209 | L: linux-media@vger.kernel.org |
| @@ -10872,6 +10886,13 @@ S: Maintained · 1676 unmodified lines | ||
| 10872 | 10886 | F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml |
| 10873 | 10887 | F: drivers/auxdisplay/img-ascii-lcd.c |
| 10874 | 10888 | |
| 10889 | +IMGTEC JPEG ENCODER DRIVER | |
| 10890 | +M: Devarsh Thakkar <devarsht@ti.com> | |
| 10891 | +L: linux-media@vger.kernel.org | |
| 10892 | +S: Supported | |
| 10893 | +F: Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml | |
| 10894 | +F: drivers/media/platform/imagination/e5010* | |
| 10895 | + | |
| 10875 | 10896 | IMGTEC IR DECODER DRIVER |
| 10876 | 10897 | S: Orphan |
| 10877 | 10898 | F: drivers/media/rc/img-ir/ |
| @@ -13632,6 +13653,20 @@ S: Maintained · 2754 unmodified lines | ||
| 13632 | 13653 | F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml |
| 13633 | 13654 | F: drivers/staging/media/max96712/max96712.c |
| 13634 | 13655 | |
| 13656 | +MAX96714 GMSL2 DESERIALIZER DRIVER | |
| 13657 | +M: Julien Massot <julien.massot@collabora.com> | |
| 13658 | +L: linux-media@vger.kernel.org | |
| 13659 | +S: Maintained | |
| 13660 | +F: Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml | |
| 13661 | +F: drivers/media/i2c/max96714.c | |
| 13662 | + | |
| 13663 | +MAX96717 GMSL2 SERIALIZER DRIVER | |
| 13664 | +M: Julien Massot <julien.massot@collabora.com> | |
| 13665 | +L: linux-media@vger.kernel.org | |
| 13666 | +S: Maintained | |
| 13667 | +F: Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml | |
| 13668 | +F: drivers/media/i2c/max96717.c | |
| 13669 | + | |
| 13635 | 13670 | MAX9860 MONO AUDIO VOICE CODEC DRIVER |
| 13636 | 13671 | M: Peter Rosin <peda@axentia.se> |
| 13637 | 13672 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) |
| @@ -18948,6 +18983,15 @@ L: linux-edac@vger.kernel.org · 5310 unmodified lines | ||
| 18948 | 18983 | S: Maintained |
| 18949 | 18984 | F: drivers/ras/amd/fmpm.c |
| 18950 | 18985 | |
| 18986 | +RASPBERRY PI PISP BACK END | |
| 18987 | +M: Jacopo Mondi <jacopo.mondi@ideasonboard.com> | |
| 18988 | +L: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com> | |
| 18989 | +L: linux-media@vger.kernel.org | |
| 18990 | +S: Maintained | |
| 18991 | +F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml | |
| 18992 | +F: drivers/media/platform/raspberrypi/pisp_be/ | |
| 18993 | +F: include/uapi/linux/media/raspberrypi/ | |
| 18994 | + | |
| 18951 | 18995 | RC-CORE / LIRC FRAMEWORK |
| 18952 | 18996 | M: Sean Young <sean@mess.org> |
| 18953 | 18997 | L: linux-media@vger.kernel.org |
| @@ -20898,7 +20942,6 @@ F: include/uapi/rdma/rdma_user_rxe.h · 1944 unmodified lines | ||
| 20898 | 20942 | |
| 20899 | 20943 | SOFTLOGIC 6x10 MPEG CODEC |
| 20900 | 20944 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> |
| 20901 | −M: Anton Sviridenko <anton@corp.bluecherry.net> | |
| 20902 | 20945 | M: Andrey Utkin <andrey_utkin@fastmail.com> |
| 20903 | 20946 | M: Ismael Luceno <ismael@iodev.co.uk> |
| 20904 | 20947 | L: linux-media@vger.kernel.org |
| @@ -20994,7 +21037,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com> · 89 unmodified lines | ||
| 20994 | 21037 | L: linux-media@vger.kernel.org |
| 20995 | 21038 | S: Maintained |
| 20996 | 21039 | T: git git://linuxtv.org/media_tree.git |
| 20997 | −F: Documentation/devicetree/bindings/media/i2c/imx258.yaml | |
| 21040 | +F: Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml | |
| 20998 | 21041 | F: drivers/media/i2c/imx258.c |
| 20999 | 21042 | |
| 21000 | 21043 | SONY IMX274 SENSOR DRIVER |
| @@ -21005,6 +21048,15 @@ T: git git://linuxtv.org/media_tree.git · 4 unmodified lines | ||
| 21005 | 21048 | F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml |
| 21006 | 21049 | F: drivers/media/i2c/imx274.c |
| 21007 | 21050 | |
| 21051 | +SONY IMX283 SENSOR DRIVER | |
| 21052 | +M: Kieran Bingham <kieran.bingham@ideasonboard.com> | |
| 21053 | +M: Umang Jain <umang.jain@ideasonboard.com> | |
| 21054 | +L: linux-media@vger.kernel.org | |
| 21055 | +S: Maintained | |
| 21056 | +T: git git://linuxtv.org/media_tree.git | |
| 21057 | +F: Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml | |
| 21058 | +F: drivers/media/i2c/imx283.c | |
| 21059 | + | |
| 21008 | 21060 | SONY IMX290 SENSOR DRIVER |
| 21009 | 21061 | M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
| 21010 | 21062 | L: linux-media@vger.kernel.org |
| @@ -21381,8 +21433,8 @@ L: linux-media@vger.kernel.org · 370 unmodified lines | ||
| 21381 | 21433 | S: Maintained |
| 21382 | 21434 | T: git git://linuxtv.org/media_tree.git |
| 21383 | 21435 | F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml |
| 21384 | −F: Documentation/userspace-api/media/drivers/st-vgxy61.rst | |
| 21385 | −F: drivers/media/i2c/st-vgxy61.c | |
| 21436 | +F: Documentation/userspace-api/media/drivers/vgxy61.rst | |
| 21437 | +F: drivers/media/i2c/vgxy61.c | |
| 21386 | 21438 | |
| 21387 | 21439 | ST VL53L0X ToF RANGER(I2C) IIO DRIVER |
| 21388 | 21440 | M: Song Qiang <songqiang1304521@gmail.com> |
| @@ -23108,7 +23160,6 @@ F: tools/testing/selftests/turbostat/ · 1719 unmodified lines | ||
| 23108 | 23160 | |
| 23109 | 23161 | TW5864 VIDEO4LINUX DRIVER |
| 23110 | 23162 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> |
| 23111 | −M: Anton Sviridenko <anton@corp.bluecherry.net> | |
| 23112 | 23163 | M: Andrey Utkin <andrey.utkin@corp.bluecherry.net> |
| 23113 | 23164 | M: Andrey Utkin <andrey_utkin@fastmail.com> |
| 23114 | 23165 | L: linux-media@vger.kernel.org |
| @@ -23725,7 +23776,7 @@ F: drivers/media/i2c/mt* · 610 unmodified lines | ||
| 23725 | 23776 | F: drivers/media/i2c/og* |
| 23726 | 23777 | F: drivers/media/i2c/ov* |
| 23727 | 23778 | F: drivers/media/i2c/s5* |
| 23728 | −F: drivers/media/i2c/st-vgxy61.c | |
| 23779 | +F: drivers/media/i2c/vgxy61.c | |
| 23729 | 23780 | |
| 23730 | 23781 | VF610 NAND DRIVER |
| 23731 | 23782 | M: Stefan Agner <stefan@agner.ch> |
| @@ -839,7 +839,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev) · 838 unmodified lines | ||
| 839 | 839 | mtu_msg.x_msg_header.msg_flags = 0; |
| 840 | 840 | mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; |
| 841 | 841 | mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg); |
| 842 | − mtu_msg.msg_data[0] = board->mtu; | |
| 842 | + mtu_msg.msg_data = board->mtu; | |
| 843 | 843 | |
| 844 | 844 | coredev->sendrequest_handler(coredev->context, &mtu_msg, |
| 845 | 845 | sizeof(mtu_msg)); |
| @@ -852,7 +852,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev) · 6 unmodified lines | ||
| 852 | 852 | SMS_INIT_MSG(&crys_msg.x_msg_header, |
| 853 | 853 | MSG_SMS_NEW_CRYSTAL_REQ, |
| 854 | 854 | sizeof(crys_msg)); |
| 855 | − crys_msg.msg_data[0] = board->crystal; | |
| 855 | + crys_msg.msg_data = board->crystal; | |
| 856 | 856 | |
| 857 | 857 | coredev->sendrequest_handler(coredev->context, &crys_msg, |
| 858 | 858 | sizeof(crys_msg)); |
| @@ -1306,7 +1306,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode) · 447 unmodified lines | ||
| 1306 | 1306 | msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); |
| 1307 | 1307 | SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, |
| 1308 | 1308 | sizeof(struct sms_msg_data)); |
| 1309 | − msg->msg_data[0] = mode; | |
| 1309 | + msg->msg_data = mode; | |
| 1310 | 1310 | |
| 1311 | 1311 | rc = smscore_sendrequest_and_wait(coredev, msg, |
| 1312 | 1312 | msg->x_msg_header. msg_length, |
| @@ -1394,7 +1394,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode) · 81 unmodified lines | ||
| 1394 | 1394 | |
| 1395 | 1395 | SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, |
| 1396 | 1396 | sizeof(struct sms_msg_data)); |
| 1397 | − msg->msg_data[0] = mode; | |
| 1397 | + msg->msg_data = mode; | |
| 1398 | 1398 | |
| 1399 | 1399 | rc = smscore_sendrequest_and_wait( |
| 1400 | 1400 | coredev, msg, msg->x_msg_header.msg_length, |
| @@ -1554,7 +1554,7 @@ void smscore_onresponse(struct smscore_device_t *coredev, · 153 unmodified lines | ||
| 1554 | 1554 | struct sms_msg_data *validity = (struct sms_msg_data *) phdr; |
| 1555 | 1555 | |
| 1556 | 1556 | pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n", |
| 1557 | − validity->msg_data[0]); | |
| 1557 | + validity->msg_data); | |
| 1558 | 1558 | complete(&coredev->data_validity_done); |
| 1559 | 1559 | break; |
| 1560 | 1560 | } |
| @@ -616,7 +616,7 @@ struct sms_msg_hdr { · 615 unmodified lines | ||
| 616 | 616 | |
| 617 | 617 | struct sms_msg_data { |
| 618 | 618 | struct sms_msg_hdr x_msg_header; |
| 619 | − u32 msg_data[1]; | |
| 619 | + u32 msg_data; | |
| 620 | 620 | }; |
| 621 | 621 | |
| 622 | 622 | struct sms_msg_data2 { |
| @@ -666,7 +666,7 @@ struct sms_firmware { · 43 unmodified lines | ||
| 666 | 666 | u32 check_sum; |
| 667 | 667 | u32 length; |
| 668 | 668 | u32 start_address; |
| 669 | − u8 payload[1]; | |
| 669 | + u8 payload[]; | |
| 670 | 670 | }; |
| 671 | 671 | |
| 672 | 672 | /* statistics information returned as response for |
| @@ -1042,20 +1042,6 @@ struct sms_srvm_signal_status { · 369 unmodified lines | ||
| 1042 | 1042 | u32 request_id; |
| 1043 | 1043 | }; |
| 1044 | 1044 | |
| 1045 | −struct sms_i2c_req { | |
| 1046 | − u32 device_address; /* I2c device address */ | |
| 1047 | − u32 write_count; /* number of bytes to write */ | |
| 1048 | − u32 read_count; /* number of bytes to read */ | |
| 1049 | − u8 Data[1]; | |
| 1050 | −}; | |
| 1051 | − | |
| 1052 | −struct sms_i2c_res { | |
| 1053 | − u32 status; /* non-zero value in case of failure */ | |
| 1054 | − u32 read_count; /* number of bytes read */ | |
| 1055 | − u8 Data[1]; | |
| 1056 | −}; | |
| 1057 | − | |
| 1058 | − | |
| 1059 | 1045 | struct smscore_config_gpio { |
| 1060 | 1046 | #define SMS_GPIO_DIRECTION_INPUT 0 |
| 1061 | 1047 | #define SMS_GPIO_DIRECTION_OUTPUT 1 |
| @@ -689,7 +689,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed) · 688 unmodified lines | ||
| 689 | 689 | pid_msg.x_msg_header.msg_flags = 0; |
| 690 | 690 | pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; |
| 691 | 691 | pid_msg.x_msg_header.msg_length = sizeof(pid_msg); |
| 692 | − pid_msg.msg_data[0] = feed->pid; | |
| 692 | + pid_msg.msg_data = feed->pid; | |
| 693 | 693 | |
| 694 | 694 | return smsclient_sendrequest(client->smsclient, |
| 695 | 695 | &pid_msg, sizeof(pid_msg)); |
| @@ -711,7 +711,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) · 15 unmodified lines | ||
| 711 | 711 | pid_msg.x_msg_header.msg_flags = 0; |
| 712 | 712 | pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; |
| 713 | 713 | pid_msg.x_msg_header.msg_length = sizeof(pid_msg); |
| 714 | − pid_msg.msg_data[0] = feed->pid; | |
| 714 | + pid_msg.msg_data = feed->pid; | |
| 715 | 715 | |
| 716 | 716 | return smsclient_sendrequest(client->smsclient, |
| 717 | 717 | &pid_msg, sizeof(pid_msg)); |
| @@ -20,11 +20,12 @@ void smsendian_handle_tx_message(void *buffer) · 19 unmodified lines | ||
| 20 | 20 | struct sms_msg_data *msg = buffer; |
| 21 | 21 | int i; |
| 22 | 22 | int msg_words; |
| 23 | + u32 *msg_data = &msg->msg_data; | |
| 23 | 24 | |
| 24 | 25 | switch (msg->x_msg_header.msg_type) { |
| 25 | 26 | case MSG_SMS_DATA_DOWNLOAD_REQ: |
| 26 | 27 | { |
| 27 | − msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0])); | |
| 28 | + msg->msg_data = le32_to_cpu((__force __le32)(msg->msg_data)); | |
| 28 | 29 | break; |
| 29 | 30 | } |
| 30 | 31 | |
| @@ -33,7 +34,7 @@ void smsendian_handle_tx_message(void *buffer) · 2 unmodified lines | ||
| 33 | 34 | sizeof(struct sms_msg_hdr))/4; |
| 34 | 35 | |
| 35 | 36 | for (i = 0; i < msg_words; i++) |
| 36 | − msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); | |
| 37 | + msg_data[i] = le32_to_cpu((__force __le32)msg_data[i]); | |
| 37 | 38 | |
| 38 | 39 | break; |
| 39 | 40 | } |
| @@ -66,11 +67,12 @@ void smsendian_handle_rx_message(void *buffer) · 26 unmodified lines | ||
| 66 | 67 | |
| 67 | 68 | default: |
| 68 | 69 | { |
| 70 | + u32 *msg_data = &msg->msg_data; | |
| 69 | 71 | msg_words = (msg->x_msg_header.msg_length - |
| 70 | 72 | sizeof(struct sms_msg_hdr))/4; |
| 71 | 73 | |
| 72 | 74 | for (i = 0; i < msg_words; i++) |
| 73 | − msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]); | |
| 75 | + msg_data[i] = le32_to_cpu((__force __le32)msg_data[i]); | |
| 74 | 76 | |
| 75 | 77 | break; |
| 76 | 78 | } |
| @@ -180,4 +180,5 @@ const struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16]) · 179 unmodified lines | ||
| 180 | 180 | } |
| 181 | 181 | EXPORT_SYMBOL_GPL(uvc_format_by_guid); |
| 182 | 182 | |
| 183 | +MODULE_DESCRIPTION("USB Video Class common code"); | |
| 183 | 184 | MODULE_LICENSE("GPL"); |
| @@ -199,7 +199,6 @@ module_param(debug, int, 0644); · 198 unmodified lines | ||
| 199 | 199 | }) |
| 200 | 200 | |
| 201 | 201 | static void __vb2_queue_cancel(struct vb2_queue *q); |
| 202 | −static void __enqueue_in_driver(struct vb2_buffer *vb); | |
| 203 | 202 | |
| 204 | 203 | static const char *vb2_state_name(enum vb2_buffer_state s) |
| 205 | 204 | { |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | /* ------------------------------------------------------------------ */ |
| 20 | 20 | |
| 21 | 21 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
| 22 | +MODULE_DESCRIPTION("Videobuf2 helper library for simple DVB cards"); | |
| 22 | 23 | MODULE_LICENSE("GPL"); |
| 23 | 24 | |
| 24 | 25 | /* ------------------------------------------------------------------ */ |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | ||
| 25 | 25 | #include "au8522_priv.h" |
| 26 | 26 | |
| 27 | 27 | MODULE_AUTHOR("Devin Heitmueller"); |
| 28 | +MODULE_DESCRIPTION("Auvitek AU8522 QAM/8VSB demodulator driver and video decoder"); | |
| 28 | 29 | MODULE_LICENSE("GPL"); |
| 29 | 30 | |
| 30 | 31 | static int au8522_analog_debug; |
| @@ -32,11 +32,6 @@ MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (defau · 31 unmodified lines | ||
| 32 | 32 | __func__, ##arg); \ |
| 33 | 33 | } while (0) |
| 34 | 34 | |
| 35 | −struct i2c_device { | |
| 36 | − struct i2c_adapter *i2c_adap; | |
| 37 | − u8 i2c_addr; | |
| 38 | −}; | |
| 39 | − | |
| 40 | 35 | struct dib7000p_state { |
| 41 | 36 | struct dvb_frontend demod; |
| 42 | 37 | struct dib7000p_config cfg; |
| @@ -976,13 +976,6 @@ static struct drx_aud_data drxj_default_aud_data_g = { · 975 unmodified lines | ||
| 976 | 976 | /*----------------------------------------------------------------------------- |
| 977 | 977 | STRUCTURES |
| 978 | 978 | ----------------------------------------------------------------------------*/ |
| 979 | −struct drxjeq_stat { | |
| 980 | − u16 eq_mse; | |
| 981 | − u8 eq_mode; | |
| 982 | − u8 eq_ctrl; | |
| 983 | − u8 eq_stat; | |
| 984 | −}; | |
| 985 | − | |
| 986 | 979 | /* HI command */ |
| 987 | 980 | struct drxj_hi_cmd { |
| 988 | 981 | u16 cmd; |
| @@ -1854,5 +1854,6 @@ error: · 1853 unmodified lines | ||
| 1854 | 1854 | return NULL; |
| 1855 | 1855 | } |
| 1856 | 1856 | EXPORT_SYMBOL_GPL(mb86a16_attach); |
| 1857 | +MODULE_DESCRIPTION("Fujitsu MB86A16 DVB-S/DSS DC Receiver driver"); | |
| 1857 | 1858 | MODULE_LICENSE("GPL"); |
| 1858 | 1859 | MODULE_AUTHOR("Manu Abraham"); |
| @@ -168,7 +168,7 @@ struct MBIN_FILE_HEADER_T { · 167 unmodified lines | ||
| 168 | 168 | |
| 169 | 169 | struct MBIN_FILE_T { |
| 170 | 170 | struct MBIN_FILE_HEADER_T header; |
| 171 | − u8 data[1]; | |
| 171 | + u8 data[]; | |
| 172 | 172 | }; |
| 173 | 173 | |
| 174 | 174 | struct MBIN_SEGMENT_HEADER_T { |
| @@ -179,7 +179,7 @@ struct MBIN_SEGMENT_HEADER_T { · 4 unmodified lines | ||
| 179 | 179 | |
| 180 | 180 | struct MBIN_SEGMENT_T { |
| 181 | 181 | struct MBIN_SEGMENT_HEADER_T header; |
| 182 | − u8 data[1]; | |
| 182 | + u8 data[]; | |
| 183 | 183 | }; |
| 184 | 184 | |
| 185 | 185 | enum MXL_CMD_TYPE_E { MXL_CMD_WRITE = 0, MXL_CMD_READ }; |
| @@ -748,6 +748,22 @@ static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 d · 747 unmodified lines | ||
| 748 | 748 | return stv090x_write_regs(state, reg, &tmp, 1); |
| 749 | 749 | } |
| 750 | 750 | |
| 751 | +static inline void stv090x_tuner_i2c_lock(struct stv090x_state *state) | |
| 752 | +{ | |
| 753 | + if (state->config->tuner_i2c_lock) | |
| 754 | + state->config->tuner_i2c_lock(&state->frontend, 1); | |
| 755 | + else | |
| 756 | + mutex_lock(&state->internal->tuner_lock); | |
| 757 | +} | |
| 758 | + | |
| 759 | +static inline void stv090x_tuner_i2c_unlock(struct stv090x_state *state) | |
| 760 | +{ | |
| 761 | + if (state->config->tuner_i2c_lock) | |
| 762 | + state->config->tuner_i2c_lock(&state->frontend, 0); | |
| 763 | + else | |
| 764 | + mutex_unlock(&state->internal->tuner_lock); | |
| 765 | +} | |
| 766 | + | |
| 751 | 767 | static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) |
| 752 | 768 | { |
| 753 | 769 | u32 reg; |
| @@ -761,12 +777,8 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) · 7 unmodified lines | ||
| 761 | 777 | * In case of any error, the lock is unlocked and exit within the |
| 762 | 778 | * relevant operations themselves. |
| 763 | 779 | */ |
| 764 | − if (enable) { | |
| 765 | − if (state->config->tuner_i2c_lock) | |
| 766 | − state->config->tuner_i2c_lock(&state->frontend, 1); | |
| 767 | − else | |
| 768 | − mutex_lock(&state->internal->tuner_lock); | |
| 769 | − } | |
| 780 | + if (enable) | |
| 781 | + stv090x_tuner_i2c_lock(state); | |
| 770 | 782 | |
| 771 | 783 | reg = STV090x_READ_DEMOD(state, I2CRPT); |
| 772 | 784 | if (enable) { |
| @@ -782,20 +794,13 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) · 9 unmodified lines | ||
| 782 | 794 | goto err; |
| 783 | 795 | } |
| 784 | 796 | |
| 785 | − if (!enable) { | |
| 786 | − if (state->config->tuner_i2c_lock) | |
| 787 | − state->config->tuner_i2c_lock(&state->frontend, 0); | |
| 788 | − else | |
| 789 | − mutex_unlock(&state->internal->tuner_lock); | |
| 790 | − } | |
| 797 | + if (!enable) | |
| 798 | + stv090x_tuner_i2c_unlock(state); | |
| 791 | 799 | |
| 792 | 800 | return 0; |
| 793 | 801 | err: |
| 794 | 802 | dprintk(FE_ERROR, 1, "I/O error"); |
| 795 | − if (state->config->tuner_i2c_lock) | |
| 796 | − state->config->tuner_i2c_lock(&state->frontend, 0); | |
| 797 | − else | |
| 798 | − mutex_unlock(&state->internal->tuner_lock); | |
| 803 | + stv090x_tuner_i2c_unlock(state); | |
| 799 | 804 | return -1; |
| 800 | 805 | } |
| 801 | 806 | |
| @@ -119,11 +119,6 @@ struct stv { · 118 unmodified lines | ||
| 119 | 119 | u8 vth[6]; |
| 120 | 120 | }; |
| 121 | 121 | |
| 122 | −struct sinit_table { | |
| 123 | − u16 address; | |
| 124 | − u8 data; | |
| 125 | −}; | |
| 126 | − | |
| 127 | 122 | struct slookup { |
| 128 | 123 | s16 value; |
| 129 | 124 | u32 reg_value; |
| @@ -70,6 +70,26 @@ config VIDEO_GC0308 · 69 unmodified lines | ||
| 70 | 70 | To compile this driver as a module, choose M here: the |
| 71 | 71 | module will be called gc0308. |
| 72 | 72 | |
| 73 | +config VIDEO_GC05A2 | |
| 74 | + tristate "GalaxyCore gc05a2 sensor support" | |
| 75 | + select V4L2_CCI_I2C | |
| 76 | + help | |
| 77 | + This is a Video4Linux2 sensor driver for the GalaxyCore gc05a2 | |
| 78 | + camera. | |
| 79 | + | |
| 80 | + To compile this driver as a module, choose M here: the | |
| 81 | + module will be called gc05a2. | |
| 82 | + | |
| 83 | +config VIDEO_GC08A3 | |
| 84 | + tristate "GalaxyCore gc08a3 sensor support" | |
| 85 | + select V4L2_CCI_I2C | |
| 86 | + help | |
| 87 | + This is a Video4Linux2 sensor driver for the GalaxyCore gc08a3 | |
| 88 | + camera. | |
| 89 | + | |
| 90 | + To compile this driver as a module, choose M here: the | |
| 91 | + module will be called gc08a3. | |
| 92 | + | |
| 73 | 93 | config VIDEO_GC2145 |
| 74 | 94 | select V4L2_CCI_I2C |
| 75 | 95 | tristate "GalaxyCore GC2145 sensor support" |
| @@ -139,6 +159,7 @@ config VIDEO_IMX219 · 63 unmodified lines | ||
| 139 | 159 | |
| 140 | 160 | config VIDEO_IMX258 |
| 141 | 161 | tristate "Sony IMX258 sensor support" |
| 162 | + select V4L2_CCI_I2C | |
| 142 | 163 | help |
| 143 | 164 | This is a Video4Linux2 sensor driver for the Sony |
| 144 | 165 | IMX258 camera. |
| @@ -153,6 +174,16 @@ config VIDEO_IMX274 · 8 unmodified lines | ||
| 153 | 174 | This is a V4L2 sensor driver for the Sony IMX274 |
| 154 | 175 | CMOS image sensor. |
| 155 | 176 | |
| 177 | +config VIDEO_IMX283 | |
| 178 | + tristate "Sony IMX283 sensor support" | |
| 179 | + select V4L2_CCI_I2C | |
| 180 | + help | |
| 181 | + This is a V4L2 sensor driver for the Sony IMX283 | |
| 182 | + CMOS image sensor. | |
| 183 | + | |
| 184 | + To compile this driver as a module, choose M here: the | |
| 185 | + module will be called imx283. | |
| 186 | + | |
| 156 | 187 | config VIDEO_IMX290 |
| 157 | 188 | tristate "Sony IMX290 sensor support" |
| 158 | 189 | select REGMAP_I2C |
| @@ -659,7 +690,7 @@ config VIDEO_S5K6A3 · 500 unmodified lines | ||
| 659 | 690 | This is a V4L2 sensor driver for Samsung S5K6A3 raw |
| 660 | 691 | camera sensor. |
| 661 | 692 | |
| 662 | −config VIDEO_ST_VGXY61 | |
| 693 | +config VIDEO_VGXY61 | |
| 663 | 694 | tristate "ST VGXY61 sensor support" |
| 664 | 695 | select V4L2_CCI_I2C |
| 665 | 696 | depends on OF && GPIOLIB |
| @@ -679,6 +710,7 @@ config VIDEO_THP7312 · 13 unmodified lines | ||
| 679 | 710 | tristate "THine THP7312 support" |
| 680 | 711 | depends on I2C |
| 681 | 712 | select FW_LOADER |
| 713 | + select FW_UPLOAD | |
| 682 | 714 | select MEDIA_CONTROLLER |
| 683 | 715 | select V4L2_CCI_I2C |
| 684 | 716 | select V4L2_FWNODE |
| @@ -1575,6 +1607,40 @@ config VIDEO_DS90UB960 · 890 unmodified lines | ||
| 1575 | 1607 | Device driver for the Texas Instruments DS90UB960 |
| 1576 | 1608 | FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer. |
| 1577 | 1609 | |
| 1610 | +config VIDEO_MAX96714 | |
| 1611 | + tristate "Maxim MAX96714 GMSL2 deserializer" | |
| 1612 | + depends on OF && I2C && VIDEO_DEV | |
| 1613 | + select I2C_MUX | |
| 1614 | + select MEDIA_CONTROLLER | |
| 1615 | + select GPIOLIB | |
| 1616 | + select V4L2_CCI_I2C | |
| 1617 | + select V4L2_FWNODE | |
| 1618 | + select VIDEO_V4L2_SUBDEV_API | |
| 1619 | + help | |
| 1620 | + Device driver for the Maxim MAX96714 GMSL2 Deserializer. | |
| 1621 | + MAX96714 deserializers convert a GMSL2 input to MIPI CSI-2 | |
| 1622 | + output. | |
| 1623 | + | |
| 1624 | + To compile this driver as a module, choose M here: the | |
| 1625 | + module will be called max96714. | |
| 1626 | + | |
| 1627 | +config VIDEO_MAX96717 | |
| 1628 | + tristate "Maxim MAX96717 GMSL2 Serializer support" | |
| 1629 | + depends on OF && I2C && VIDEO_DEV && COMMON_CLK | |
| 1630 | + select I2C_MUX | |
| 1631 | + select MEDIA_CONTROLLER | |
| 1632 | + select GPIOLIB | |
| 1633 | + select V4L2_CCI_I2C | |
| 1634 | + select V4L2_FWNODE | |
| 1635 | + select VIDEO_V4L2_SUBDEV_API | |
| 1636 | + help | |
| 1637 | + Device driver for the Maxim MAX96717 GMSL2 Serializer. | |
| 1638 | + MAX96717 serializers convert video on a MIPI CSI-2 | |
| 1639 | + input to a GMSL2 output. | |
| 1640 | + | |
| 1641 | + To compile this driver as a module, choose M here: the | |
| 1642 | + module will be called max96717. | |
| 1643 | + | |
| 1578 | 1644 | endmenu |
| 1579 | 1645 | |
| 1580 | 1646 | endif # VIDEO_DEV |
| @@ -38,6 +38,8 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o · 37 unmodified lines | ||
| 38 | 38 | obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o |
| 39 | 39 | obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ |
| 40 | 40 | obj-$(CONFIG_VIDEO_GC0308) += gc0308.o |
| 41 | +obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o | |
| 42 | +obj-$(CONFIG_VIDEO_GC08A3) += gc08a3.o | |
| 41 | 43 | obj-$(CONFIG_VIDEO_GC2145) += gc2145.o |
| 42 | 44 | obj-$(CONFIG_VIDEO_HI556) += hi556.o |
| 43 | 45 | obj-$(CONFIG_VIDEO_HI846) += hi846.o |
| @@ -48,6 +50,7 @@ obj-$(CONFIG_VIDEO_IMX214) += imx214.o · 4 unmodified lines | ||
| 48 | 50 | obj-$(CONFIG_VIDEO_IMX219) += imx219.o |
| 49 | 51 | obj-$(CONFIG_VIDEO_IMX258) += imx258.o |
| 50 | 52 | obj-$(CONFIG_VIDEO_IMX274) += imx274.o |
| 53 | +obj-$(CONFIG_VIDEO_IMX283) += imx283.o | |
| 51 | 54 | obj-$(CONFIG_VIDEO_IMX290) += imx290.o |
| 52 | 55 | obj-$(CONFIG_VIDEO_IMX296) += imx296.o |
| 53 | 56 | obj-$(CONFIG_VIDEO_IMX319) += imx319.o |
| @@ -64,6 +67,8 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o · 10 unmodified lines | ||
| 64 | 67 | obj-$(CONFIG_VIDEO_M52790) += m52790.o |
| 65 | 68 | obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o |
| 66 | 69 | obj-$(CONFIG_VIDEO_MAX9286) += max9286.o |
| 70 | +obj-$(CONFIG_VIDEO_MAX96714) += max96714.o | |
| 71 | +obj-$(CONFIG_VIDEO_MAX96717) += max96717.o | |
| 67 | 72 | obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o |
| 68 | 73 | obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o |
| 69 | 74 | obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o |
| @@ -124,7 +129,6 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o · 54 unmodified lines | ||
| 124 | 129 | obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o |
| 125 | 130 | obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o |
| 126 | 131 | obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o |
| 127 | −obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o | |
| 128 | 132 | obj-$(CONFIG_VIDEO_TC358743) += tc358743.o |
| 129 | 133 | obj-$(CONFIG_VIDEO_TC358746) += tc358746.o |
| 130 | 134 | obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o |
| @@ -148,6 +152,7 @@ obj-$(CONFIG_VIDEO_TW9910) += tw9910.o · 17 unmodified lines | ||
| 148 | 152 | obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o |
| 149 | 153 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o |
| 150 | 154 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o |
| 155 | +obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o | |
| 151 | 156 | obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o |
| 152 | 157 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o |
| 153 | 158 | obj-$(CONFIG_VIDEO_WM8739) += wm8739.o |
| @@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe, · 113 unmodified lines | ||
| 114 | 114 | { |
| 115 | 115 | memset(fmt, 0, sizeof(*fmt)); |
| 116 | 116 | |
| 117 | − fmt->code = MEDIA_BUS_FMT_UYVY8_2X8; | |
| 117 | + fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; | |
| 118 | 118 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 119 | 119 | fmt->field = V4L2_FIELD_ALTERNATE; |
| 120 | 120 | |
| @@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd, · 216 unmodified lines | ||
| 337 | 337 | if (code->index != 0) |
| 338 | 338 | return -EINVAL; |
| 339 | 339 | |
| 340 | − code->code = MEDIA_BUS_FMT_UYVY8_2X8; | |
| 340 | + code->code = MEDIA_BUS_FMT_UYVY8_1X16; | |
| 341 | 341 | |
| 342 | 342 | return 0; |
| 343 | 343 | } |
| @@ -6,7 +6,6 @@ · 5 unmodified lines | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | #include <linux/module.h> |
| 9 | −#include <linux/mutex.h> | |
| 10 | 9 | |
| 11 | 10 | #include <media/v4l2-ctrls.h> |
| 12 | 11 | #include <media/v4l2-device.h> |
| @@ -14,6 +13,15 @@ · 1 unmodified line | ||
| 14 | 13 | |
| 15 | 14 | #include "adv748x.h" |
| 16 | 15 | |
| 16 | +static const unsigned int adv748x_csi2_txa_fmts[] = { | |
| 17 | + MEDIA_BUS_FMT_UYVY8_1X16, | |
| 18 | + MEDIA_BUS_FMT_RGB888_1X24, | |
| 19 | +}; | |
| 20 | + | |
| 21 | +static const unsigned int adv748x_csi2_txb_fmts[] = { | |
| 22 | + MEDIA_BUS_FMT_UYVY8_1X16, | |
| 23 | +}; | |
| 24 | + | |
| 17 | 25 | int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc) |
| 18 | 26 | { |
| 19 | 27 | return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT); |
| @@ -59,7 +67,33 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx, · 39 unmodified lines | ||
| 59 | 67 | |
| 60 | 68 | /* ----------------------------------------------------------------------------- |
| 61 | 69 | * v4l2_subdev_internal_ops |
| 62 | − * | |
| 70 | + */ | |
| 71 | + | |
| 72 | +static int adv748x_csi2_init_state(struct v4l2_subdev *sd, | |
| 73 | + struct v4l2_subdev_state *state) | |
| 74 | +{ | |
| 75 | + static const struct v4l2_mbus_framefmt adv748x_csi2_default_fmt = { | |
| 76 | + .width = 1280, | |
| 77 | + .height = 720, | |
| 78 | + .code = MEDIA_BUS_FMT_UYVY8_1X16, | |
| 79 | + .colorspace = V4L2_COLORSPACE_SRGB, | |
| 80 | + .field = V4L2_FIELD_NONE, | |
| 81 | + .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT, | |
| 82 | + .quantization = V4L2_QUANTIZATION_DEFAULT, | |
| 83 | + .xfer_func = V4L2_XFER_FUNC_DEFAULT, | |
| 84 | + }; | |
| 85 | + struct v4l2_mbus_framefmt *fmt; | |
| 86 | + | |
| 87 | + fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SINK); | |
| 88 | + *fmt = adv748x_csi2_default_fmt; | |
| 89 | + | |
| 90 | + fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SOURCE); | |
| 91 | + *fmt = adv748x_csi2_default_fmt; | |
| 92 | + | |
| 93 | + return 0; | |
| 94 | +} | |
| 95 | + | |
| 96 | +/* | |
| 63 | 97 | * We use the internal registered operation to be able to ensure that our |
| 64 | 98 | * incremental subdevices (not connected in the forward path) can be registered |
| 65 | 99 | * against the resulting video path and media device. |
| @@ -109,6 +143,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd) · 43 unmodified lines | ||
| 109 | 143 | } |
| 110 | 144 | |
| 111 | 145 | static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = { |
| 146 | + .init_state = adv748x_csi2_init_state, | |
| 112 | 147 | .registered = adv748x_csi2_registered, |
| 113 | 148 | }; |
| 114 | 149 | |
| @@ -139,39 +174,55 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = { · 24 unmodified lines | ||
| 139 | 174 | * But we must support setting the pad formats for format propagation. |
| 140 | 175 | */ |
| 141 | 176 | |
| 142 | −static struct v4l2_mbus_framefmt * | |
| 143 | −adv748x_csi2_get_pad_format(struct v4l2_subdev *sd, | |
| 144 | − struct v4l2_subdev_state *sd_state, | |
| 145 | − unsigned int pad, u32 which) | |
| 177 | +static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd, | |
| 178 | + struct v4l2_subdev_state *sd_state, | |
| 179 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 146 | 180 | { |
| 147 | 181 | struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); |
| 182 | + const unsigned int *codes = is_txa(tx) ? | |
| 183 | + adv748x_csi2_txa_fmts : | |
| 184 | + adv748x_csi2_txb_fmts; | |
| 185 | + size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts) | |
| 186 | + : ARRAY_SIZE(adv748x_csi2_txb_fmts); | |
| 148 | 187 | |
| 149 | − if (which == V4L2_SUBDEV_FORMAT_TRY) | |
| 150 | − return v4l2_subdev_state_get_format(sd_state, pad); | |
| 188 | + /* | |
| 189 | + * The format available on the source pad is the one applied on the sink | |
| 190 | + * pad. | |
| 191 | + */ | |
| 192 | + if (code->pad == ADV748X_CSI2_SOURCE) { | |
| 193 | + struct v4l2_mbus_framefmt *fmt; | |
| 151 | 194 | |
| 152 | − return &tx->format; | |
| 153 | −} | |
| 195 | + if (code->index) | |
| 196 | + return -EINVAL; | |
| 154 | 197 | |
| 155 | −static int adv748x_csi2_get_format(struct v4l2_subdev *sd, | |
| 156 | − struct v4l2_subdev_state *sd_state, | |
| 157 | − struct v4l2_subdev_format *sdformat) | |
| 158 | −{ | |
| 159 | − struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); | |
| 160 | − struct adv748x_state *state = tx->state; | |
| 161 | − struct v4l2_mbus_framefmt *mbusformat; | |
| 198 | + fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK); | |
| 199 | + code->code = fmt->code; | |
| 162 | 200 | |
| 163 | − mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad, | |
| 164 | − sdformat->which); | |
| 165 | − if (!mbusformat) | |
| 201 | + return 0; | |
| 202 | + } | |
| 203 | + | |
| 204 | + if (code->index >= num_fmts) | |
| 166 | 205 | return -EINVAL; |
| 167 | 206 | |
| 168 | − mutex_lock(&state->mutex); | |
| 207 | + code->code = codes[code->index]; | |
| 169 | 208 | |
| 170 | − sdformat->format = *mbusformat; | |
| 209 | + return 0; | |
| 210 | +} | |
| 171 | 211 | |
| 172 | − mutex_unlock(&state->mutex); | |
| 212 | +static bool adv748x_csi2_is_fmt_supported(struct adv748x_csi2 *tx, u32 code) | |
| 213 | +{ | |
| 214 | + const unsigned int *codes = is_txa(tx) ? | |
| 215 | + adv748x_csi2_txa_fmts : | |
| 216 | + adv748x_csi2_txb_fmts; | |
| 217 | + size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts) | |
| 218 | + : ARRAY_SIZE(adv748x_csi2_txb_fmts); | |
| 219 | + | |
| 220 | + for (unsigned int i = 0; i < num_fmts; i++) { | |
| 221 | + if (codes[i] == code) | |
| 222 | + return true; | |
| 223 | + } | |
| 173 | 224 | |
| 174 | − return 0; | |
| 225 | + return false; | |
| 175 | 226 | } |
| 176 | 227 | |
| 177 | 228 | static int adv748x_csi2_set_format(struct v4l2_subdev *sd, |
| @@ -179,38 +230,26 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd, · 1 unmodified line | ||
| 179 | 230 | struct v4l2_subdev_format *sdformat) |
| 180 | 231 | { |
| 181 | 232 | struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); |
| 182 | − struct adv748x_state *state = tx->state; | |
| 183 | 233 | struct v4l2_mbus_framefmt *mbusformat; |
| 184 | − int ret = 0; | |
| 185 | − | |
| 186 | − mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad, | |
| 187 | − sdformat->which); | |
| 188 | − if (!mbusformat) | |
| 189 | − return -EINVAL; | |
| 190 | − | |
| 191 | − mutex_lock(&state->mutex); | |
| 192 | 234 | |
| 193 | − if (sdformat->pad == ADV748X_CSI2_SOURCE) { | |
| 194 | − const struct v4l2_mbus_framefmt *sink_fmt; | |
| 235 | + if (sdformat->pad == ADV748X_CSI2_SOURCE) | |
| 236 | + return v4l2_subdev_get_fmt(sd, sd_state, sdformat); | |
| 195 | 237 | |
| 196 | − sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state, | |
| 197 | − ADV748X_CSI2_SINK, | |
| 198 | − sdformat->which); | |
| 199 | − | |
| 200 | − if (!sink_fmt) { | |
| 201 | − ret = -EINVAL; | |
| 202 | − goto unlock; | |
| 203 | − } | |
| 204 | − | |
| 205 | − sdformat->format = *sink_fmt; | |
| 206 | − } | |
| 238 | + /* | |
| 239 | + * Make sure the format is supported, if not default it to | |
| 240 | + * UYVY8 as it's supported by both TXes. | |
| 241 | + */ | |
| 242 | + if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code)) | |
| 243 | + sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16; | |
| 207 | 244 | |
| 245 | + mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad); | |
| 208 | 246 | *mbusformat = sdformat->format; |
| 209 | 247 | |
| 210 | −unlock: | |
| 211 | − mutex_unlock(&state->mutex); | |
| 248 | + /* Propagate format to the source pad. */ | |
| 249 | + mbusformat = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SOURCE); | |
| 250 | + *mbusformat = sdformat->format; | |
| 212 | 251 | |
| 213 | − return ret; | |
| 252 | + return 0; | |
| 214 | 253 | } |
| 215 | 254 | |
| 216 | 255 | static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, |
| @@ -228,7 +267,8 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad · 11 unmodified lines | ||
| 228 | 267 | } |
| 229 | 268 | |
| 230 | 269 | static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = { |
| 231 | − .get_fmt = adv748x_csi2_get_format, | |
| 270 | + .enum_mbus_code = adv748x_csi2_enum_mbus_code, | |
| 271 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 232 | 272 | .set_fmt = adv748x_csi2_set_format, |
| 233 | 273 | .get_mbus_config = adv748x_csi2_get_mbus_config, |
| 234 | 274 | }; |
| @@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx) · 85 unmodified lines | ||
| 320 | 360 | if (ret) |
| 321 | 361 | goto err_cleanup_subdev; |
| 322 | 362 | |
| 363 | + tx->sd.state_lock = &state->mutex; | |
| 364 | + ret = v4l2_subdev_init_finalize(&tx->sd); | |
| 365 | + if (ret) | |
| 366 | + goto err_free_ctrl; | |
| 367 | + | |
| 323 | 368 | ret = v4l2_async_register_subdev(&tx->sd); |
| 324 | 369 | if (ret) |
| 325 | 370 | goto err_free_ctrl; |
| @@ -75,7 +75,6 @@ enum adv748x_csi2_pads { · 74 unmodified lines | ||
| 75 | 75 | |
| 76 | 76 | struct adv748x_csi2 { |
| 77 | 77 | struct adv748x_state *state; |
| 78 | − struct v4l2_mbus_framefmt format; | |
| 79 | 78 | unsigned int page; |
| 80 | 79 | unsigned int port; |
| 81 | 80 | unsigned int num_lanes; |
| @@ -62,11 +62,6 @@ MODULE_LICENSE("GPL v2"); · 61 unmodified lines | ||
| 62 | 62 | ********************************************************************** |
| 63 | 63 | */ |
| 64 | 64 | |
| 65 | −struct i2c_reg_value { | |
| 66 | − unsigned char reg; | |
| 67 | − unsigned char value; | |
| 68 | −}; | |
| 69 | − | |
| 70 | 65 | struct adv7511_state_edid { |
| 71 | 66 | /* total number of blocks */ |
| 72 | 67 | u32 blocks; |
| @@ -403,21 +403,22 @@ static int alvium_get_bcrm_vers(struct alvium_dev *alvium) · 402 unmodified lines | ||
| 403 | 403 | static int alvium_get_fw_version(struct alvium_dev *alvium) |
| 404 | 404 | { |
| 405 | 405 | struct device *dev = &alvium->i2c_client->dev; |
| 406 | − u64 spec, maj, min, pat; | |
| 407 | − int ret = 0; | |
| 406 | + u64 val; | |
| 407 | + int ret; | |
| 408 | 408 | |
| 409 | − ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_SPEC_VERSION_R, | |
| 410 | − &spec, &ret); | |
| 411 | − ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MAJOR_VERSION_R, | |
| 412 | − &maj, &ret); | |
| 413 | − ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MINOR_VERSION_R, | |
| 414 | − &min, &ret); | |
| 415 | − ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_PATCH_VERSION_R, | |
| 416 | − &pat, &ret); | |
| 409 | + ret = alvium_read(alvium, REG_BCRM_DEVICE_FW, &val, NULL); | |
| 417 | 410 | if (ret) |
| 418 | 411 | return ret; |
| 419 | 412 | |
| 420 | − dev_info(dev, "fw version: %llu.%llu.%llu.%llu\n", spec, maj, min, pat); | |
| 413 | + dev_info(dev, "fw version: %02u.%02u.%04u.%08x\n", | |
| 414 | + (u8)((val & BCRM_DEVICE_FW_SPEC_MASK) >> | |
| 415 | + BCRM_DEVICE_FW_SPEC_SHIFT), | |
| 416 | + (u8)((val & BCRM_DEVICE_FW_MAJOR_MASK) >> | |
| 417 | + BCRM_DEVICE_FW_MAJOR_SHIFT), | |
| 418 | + (u16)((val & BCRM_DEVICE_FW_MINOR_MASK) >> | |
| 419 | + BCRM_DEVICE_FW_MINOR_SHIFT), | |
| 420 | + (u32)((val & BCRM_DEVICE_FW_PATCH_MASK) >> | |
| 421 | + BCRM_DEVICE_FW_PATCH_SHIFT)); | |
| 421 | 422 | |
| 422 | 423 | return 0; |
| 423 | 424 | } |
| @@ -1188,6 +1189,20 @@ static int alvium_set_frame_rate(struct alvium_dev *alvium, u64 fr) · 764 unmodified lines | ||
| 1188 | 1189 | struct device *dev = &alvium->i2c_client->dev; |
| 1189 | 1190 | int ret; |
| 1190 | 1191 | |
| 1192 | + ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW, | |
| 1193 | + 1); | |
| 1194 | + if (ret) { | |
| 1195 | + dev_err(dev, "Fail to set acquisition frame rate enable reg\n"); | |
| 1196 | + return ret; | |
| 1197 | + } | |
| 1198 | + | |
| 1199 | + ret = alvium_write_hshake(alvium, REG_BCRM_FRAME_START_TRIGGER_MODE_RW, | |
| 1200 | + 0); | |
| 1201 | + if (ret) { | |
| 1202 | + dev_err(dev, "Fail to set frame start trigger mode reg\n"); | |
| 1203 | + return ret; | |
| 1204 | + } | |
| 1205 | + | |
| 1191 | 1206 | ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW, |
| 1192 | 1207 | fr); |
| 1193 | 1208 | if (ret) { |
| @@ -1707,6 +1722,27 @@ alvium_code_to_pixfmt(struct alvium_dev *alvium, u32 code) · 513 unmodified lines | ||
| 1707 | 1722 | return &alvium->alvium_csi2_fmt[0]; |
| 1708 | 1723 | } |
| 1709 | 1724 | |
| 1725 | +static int alvium_enum_frame_size(struct v4l2_subdev *sd, | |
| 1726 | + struct v4l2_subdev_state *state, | |
| 1727 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 1728 | +{ | |
| 1729 | + struct alvium_dev *alvium = sd_to_alvium(sd); | |
| 1730 | + const struct alvium_pixfmt *alvium_csi2_fmt; | |
| 1731 | + | |
| 1732 | + if (fse->index) | |
| 1733 | + return -EINVAL; | |
| 1734 | + | |
| 1735 | + alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, fse->code); | |
| 1736 | + if (fse->code != alvium_csi2_fmt->code) | |
| 1737 | + return -EINVAL; | |
| 1738 | + | |
| 1739 | + fse->min_width = alvium->img_min_width; | |
| 1740 | + fse->max_width = alvium->img_max_width; | |
| 1741 | + fse->min_height = alvium->img_min_height; | |
| 1742 | + fse->max_height = alvium->img_max_height; | |
| 1743 | + return 0; | |
| 1744 | +} | |
| 1745 | + | |
| 1710 | 1746 | static int alvium_set_mode(struct alvium_dev *alvium, |
| 1711 | 1747 | struct v4l2_subdev_state *state) |
| 1712 | 1748 | { |
| @@ -1962,7 +1998,7 @@ static int alvium_g_volatile_ctrl(struct v4l2_ctrl *ctrl) · 249 unmodified lines | ||
| 1962 | 1998 | int val; |
| 1963 | 1999 | |
| 1964 | 2000 | switch (ctrl->id) { |
| 1965 | − case V4L2_CID_GAIN: | |
| 2001 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 1966 | 2002 | val = alvium_get_gain(alvium); |
| 1967 | 2003 | if (val < 0) |
| 1968 | 2004 | return val; |
| @@ -1994,7 +2030,7 @@ static int alvium_s_ctrl(struct v4l2_ctrl *ctrl) · 25 unmodified lines | ||
| 1994 | 2030 | return 0; |
| 1995 | 2031 | |
| 1996 | 2032 | switch (ctrl->id) { |
| 1997 | − case V4L2_CID_GAIN: | |
| 2033 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 1998 | 2034 | ret = alvium_set_ctrl_gain(alvium, ctrl->val); |
| 1999 | 2035 | break; |
| 2000 | 2036 | case V4L2_CID_AUTOGAIN: |
| @@ -2123,7 +2159,7 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) · 122 unmodified lines | ||
| 2123 | 2159 | |
| 2124 | 2160 | if (alvium->avail_ft.gain) { |
| 2125 | 2161 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, |
| 2126 | − V4L2_CID_GAIN, | |
| 2162 | + V4L2_CID_ANALOGUE_GAIN, | |
| 2127 | 2163 | alvium->min_gain, |
| 2128 | 2164 | alvium->max_gain, |
| 2129 | 2165 | alvium->inc_gain, |
| @@ -2214,6 +2250,7 @@ static const struct v4l2_subdev_video_ops alvium_video_ops = { · 84 unmodified lines | ||
| 2214 | 2250 | |
| 2215 | 2251 | static const struct v4l2_subdev_pad_ops alvium_pad_ops = { |
| 2216 | 2252 | .enum_mbus_code = alvium_enum_mbus_code, |
| 2253 | + .enum_frame_size = alvium_enum_frame_size, | |
| 2217 | 2254 | .get_fmt = v4l2_subdev_get_fmt, |
| 2218 | 2255 | .set_fmt = alvium_set_fmt, |
| 2219 | 2256 | .get_selection = alvium_get_selection, |
| @@ -31,10 +31,7 @@ · 30 unmodified lines | ||
| 31 | 31 | #define REG_BCRM_REG_ADDR_R CCI_REG16(0x0014) |
| 32 | 32 | |
| 33 | 33 | #define REG_BCRM_FEATURE_INQUIRY_R REG_BCRM_V4L2_64BIT(0x0008) |
| 34 | −#define REG_BCRM_DEVICE_FW_SPEC_VERSION_R REG_BCRM_V4L2_8BIT(0x0010) | |
| 35 | −#define REG_BCRM_DEVICE_FW_MAJOR_VERSION_R REG_BCRM_V4L2_8BIT(0x0011) | |
| 36 | −#define REG_BCRM_DEVICE_FW_MINOR_VERSION_R REG_BCRM_V4L2_16BIT(0x0012) | |
| 37 | −#define REG_BCRM_DEVICE_FW_PATCH_VERSION_R REG_BCRM_V4L2_32BIT(0x0014) | |
| 34 | +#define REG_BCRM_DEVICE_FW REG_BCRM_V4L2_64BIT(0x0010) | |
| 38 | 35 | #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0018) |
| 39 | 36 | |
| 40 | 37 | /* Streaming Control Registers */ |
| @@ -66,7 +63,7 @@ · 25 unmodified lines | ||
| 66 | 63 | #define REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R REG_BCRM_V4L2_64BIT(0x0098) |
| 67 | 64 | #define REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R REG_BCRM_V4L2_64BIT(0x00a0) |
| 68 | 65 | #define REG_BCRM_ACQUISITION_FRAME_RATE_INC_R REG_BCRM_V4L2_64BIT(0x00a8) |
| 69 | −#define REG_BCRM_ACQUISITION_FRAME_RATE_ENABLE_RW REG_BCRM_V4L2_8BIT(0x00b0) | |
| 66 | +#define REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW REG_BCRM_V4L2_8BIT(0x00b0) | |
| 70 | 67 | |
| 71 | 68 | #define REG_BCRM_FRAME_START_TRIGGER_MODE_RW REG_BCRM_V4L2_8BIT(0x00b4) |
| 72 | 69 | #define REG_BCRM_FRAME_START_TRIGGER_SOURCE_RW REG_BCRM_V4L2_8BIT(0x00b8) |
| @@ -205,6 +202,15 @@ · 132 unmodified lines | ||
| 205 | 202 | |
| 206 | 203 | #define ALVIUM_LP2HS_DELAY_MS 100 |
| 207 | 204 | |
| 205 | +#define BCRM_DEVICE_FW_MAJOR_MASK GENMASK_ULL(15, 8) | |
| 206 | +#define BCRM_DEVICE_FW_MAJOR_SHIFT 8 | |
| 207 | +#define BCRM_DEVICE_FW_MINOR_MASK GENMASK_ULL(31, 16) | |
| 208 | +#define BCRM_DEVICE_FW_MINOR_SHIFT 16 | |
| 209 | +#define BCRM_DEVICE_FW_PATCH_MASK GENMASK_ULL(63, 32) | |
| 210 | +#define BCRM_DEVICE_FW_PATCH_SHIFT 32 | |
| 211 | +#define BCRM_DEVICE_FW_SPEC_MASK GENMASK_ULL(7, 0) | |
| 212 | +#define BCRM_DEVICE_FW_SPEC_SHIFT 0 | |
| 213 | + | |
| 208 | 214 | enum alvium_bcrm_mode { |
| 209 | 215 | ALVIUM_BCM_MODE, |
| 210 | 216 | ALVIUM_GENCP_MODE, |
| @@ -115,11 +115,6 @@ static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev) · 114 unmodified lines | ||
| 115 | 115 | return container_of(subdev, struct dw9768, sd); |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | −struct regval_list { | |
| 119 | − u8 reg_num; | |
| 120 | − u8 value; | |
| 121 | −}; | |
| 122 | − | |
| 123 | 118 | struct dw9768_aac_mode_ot_multi { |
| 124 | 119 | u32 aac_mode_enum; |
| 125 | 120 | u32 ot_multi_base100; |
| @@ -0,0 +1,1359 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Driver for GalaxyCore gc05a2 image sensor | |
| 4 | + * | |
| 5 | + * Copyright 2024 MediaTek | |
| 6 | + * | |
| 7 | + * Zhi Mao <zhi.mao@mediatek.com> | |
| 8 | + */ | |
| 9 | +#include <linux/array_size.h> | |
| 10 | +#include <linux/bits.h> | |
| 11 | +#include <linux/clk.h> | |
| 12 | +#include <linux/container_of.h> | |
| 13 | +#include <linux/delay.h> | |
| 14 | +#include <linux/device.h> | |
| 15 | +#include <linux/err.h> | |
| 16 | +#include <linux/gpio/consumer.h> | |
| 17 | +#include <linux/math64.h> | |
| 18 | +#include <linux/mod_devicetable.h> | |
| 19 | +#include <linux/pm_runtime.h> | |
| 20 | +#include <linux/property.h> | |
| 21 | +#include <linux/regulator/consumer.h> | |
| 22 | +#include <linux/types.h> | |
| 23 | +#include <linux/units.h> | |
| 24 | + | |
| 25 | +#include <media/v4l2-cci.h> | |
| 26 | +#include <media/v4l2-ctrls.h> | |
| 27 | +#include <media/v4l2-event.h> | |
| 28 | +#include <media/v4l2-fwnode.h> | |
| 29 | +#include <media/v4l2-subdev.h> | |
| 30 | + | |
| 31 | +#define GC05A2_REG_TEST_PATTERN_EN CCI_REG8(0x008c) | |
| 32 | +#define GC05A2_REG_TEST_PATTERN_IDX CCI_REG8(0x008d) | |
| 33 | +#define GC05A2_TEST_PATTERN_EN 0x01 | |
| 34 | + | |
| 35 | +#define GC05A2_STREAMING_REG CCI_REG8(0x0100) | |
| 36 | + | |
| 37 | +#define GC05A2_FLIP_REG CCI_REG8(0x0101) | |
| 38 | +#define GC05A2_FLIP_H_MASK BIT(0) | |
| 39 | +#define GC05A2_FLIP_V_MASK BIT(1) | |
| 40 | + | |
| 41 | +#define GC05A2_EXP_REG CCI_REG16(0x0202) | |
| 42 | +#define GC05A2_EXP_MARGIN 16 | |
| 43 | +#define GC05A2_EXP_MIN 4 | |
| 44 | +#define GC05A2_EXP_STEP 1 | |
| 45 | + | |
| 46 | +#define GC05A2_AGAIN_REG CCI_REG16(0x0204) | |
| 47 | +#define GC05A2_AGAIN_MIN 1024 | |
| 48 | +#define GC05A2_AGAIN_MAX (1024 * 16) | |
| 49 | +#define GC05A2_AGAIN_STEP 1 | |
| 50 | + | |
| 51 | +#define GC05A2_FRAME_LENGTH_REG CCI_REG16(0x0340) | |
| 52 | +#define GC05A2_VTS_MAX 0xffff | |
| 53 | + | |
| 54 | +#define GC05A2_REG_CHIP_ID CCI_REG16(0x03f0) | |
| 55 | +#define GC05A2_CHIP_ID 0x05a2 | |
| 56 | + | |
| 57 | +#define GC05A2_NATIVE_WIDTH 2592 | |
| 58 | +#define GC05A2_NATIVE_HEIGHT 1944 | |
| 59 | + | |
| 60 | +#define GC05A2_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ) | |
| 61 | +#define GC05A2_MBUS_CODE MEDIA_BUS_FMT_SGRBG10_1X10 | |
| 62 | +#define GC05A2_DATA_LANES 2 | |
| 63 | +#define GC05A2_RGB_DEPTH 10 | |
| 64 | +#define GC05A2_SLEEP_US (2 * USEC_PER_MSEC) | |
| 65 | + | |
| 66 | +static const char *const gc05a2_test_pattern_menu[] = { | |
| 67 | + "No Pattern", "Fade_to_gray_Color Bar", "Color Bar", | |
| 68 | + "PN9", "Horizental_gradient", "Checkboard Pattern", | |
| 69 | + "Slant", "Resolution", "Solid Black", | |
| 70 | + "Solid White", | |
| 71 | +}; | |
| 72 | + | |
| 73 | +static const s64 gc05a2_link_freq_menu_items[] = { | |
| 74 | + (448 * HZ_PER_MHZ), | |
| 75 | + (224 * HZ_PER_MHZ), | |
| 76 | +}; | |
| 77 | + | |
| 78 | +static const char *const gc05a2_supply_name[] = { | |
| 79 | + "avdd", | |
| 80 | + "dvdd", | |
| 81 | + "dovdd", | |
| 82 | +}; | |
| 83 | + | |
| 84 | +struct gc05a2 { | |
| 85 | + struct device *dev; | |
| 86 | + struct v4l2_subdev sd; | |
| 87 | + struct media_pad pad; | |
| 88 | + | |
| 89 | + struct clk *xclk; | |
| 90 | + struct regulator_bulk_data supplies[ARRAY_SIZE(gc05a2_supply_name)]; | |
| 91 | + struct gpio_desc *reset_gpio; | |
| 92 | + | |
| 93 | + struct v4l2_ctrl_handler ctrls; | |
| 94 | + struct v4l2_ctrl *pixel_rate; | |
| 95 | + struct v4l2_ctrl *link_freq; | |
| 96 | + struct v4l2_ctrl *exposure; | |
| 97 | + struct v4l2_ctrl *vblank; | |
| 98 | + struct v4l2_ctrl *hblank; | |
| 99 | + struct v4l2_ctrl *hflip; | |
| 100 | + struct v4l2_ctrl *vflip; | |
| 101 | + | |
| 102 | + struct regmap *regmap; | |
| 103 | + unsigned long link_freq_bitmap; | |
| 104 | + | |
| 105 | + /* True if the device has been identified */ | |
| 106 | + bool identified; | |
| 107 | + const struct gc05a2_mode *cur_mode; | |
| 108 | +}; | |
| 109 | + | |
| 110 | +struct gc05a2_reg_list { | |
| 111 | + u32 num_of_regs; | |
| 112 | + const struct cci_reg_sequence *regs; | |
| 113 | +}; | |
| 114 | + | |
| 115 | +static const struct cci_reg_sequence mode_2592x1944[] = { | |
| 116 | + /* system */ | |
| 117 | + { CCI_REG8(0x0135), 0x01 }, | |
| 118 | + { CCI_REG8(0x0084), 0x21 }, | |
| 119 | + { CCI_REG8(0x0d05), 0xcc }, | |
| 120 | + { CCI_REG8(0x0218), 0x00 }, | |
| 121 | + { CCI_REG8(0x005e), 0x48 }, | |
| 122 | + { CCI_REG8(0x0d06), 0x01 }, | |
| 123 | + { CCI_REG8(0x0007), 0x16 }, | |
| 124 | + { CCI_REG8(0x0101), 0x00 }, | |
| 125 | + | |
| 126 | + /* analog */ | |
| 127 | + { CCI_REG8(0x0342), 0x07 }, | |
| 128 | + { CCI_REG8(0x0343), 0x28 }, | |
| 129 | + { CCI_REG8(0x0220), 0x07 }, | |
| 130 | + { CCI_REG8(0x0221), 0xd0 }, | |
| 131 | + { CCI_REG8(0x0202), 0x07 }, | |
| 132 | + { CCI_REG8(0x0203), 0x32 }, | |
| 133 | + { CCI_REG8(0x0340), 0x07 }, | |
| 134 | + { CCI_REG8(0x0341), 0xf0 }, | |
| 135 | + { CCI_REG8(0x0219), 0x00 }, | |
| 136 | + { CCI_REG8(0x0346), 0x00 }, | |
| 137 | + { CCI_REG8(0x0347), 0x04 }, | |
| 138 | + { CCI_REG8(0x0d14), 0x00 }, | |
| 139 | + { CCI_REG8(0x0d13), 0x05 }, | |
| 140 | + { CCI_REG8(0x0d16), 0x05 }, | |
| 141 | + { CCI_REG8(0x0d15), 0x1d }, | |
| 142 | + { CCI_REG8(0x00c0), 0x0a }, | |
| 143 | + { CCI_REG8(0x00c1), 0x30 }, | |
| 144 | + { CCI_REG8(0x034a), 0x07 }, | |
| 145 | + { CCI_REG8(0x034b), 0xa8 }, | |
| 146 | + { CCI_REG8(0x0e0a), 0x00 }, | |
| 147 | + { CCI_REG8(0x0e0b), 0x00 }, | |
| 148 | + { CCI_REG8(0x0e0e), 0x03 }, | |
| 149 | + { CCI_REG8(0x0e0f), 0x00 }, | |
| 150 | + { CCI_REG8(0x0e06), 0x0a }, | |
| 151 | + { CCI_REG8(0x0e23), 0x15 }, | |
| 152 | + { CCI_REG8(0x0e24), 0x15 }, | |
| 153 | + { CCI_REG8(0x0e2a), 0x10 }, | |
| 154 | + { CCI_REG8(0x0e2b), 0x10 }, | |
| 155 | + { CCI_REG8(0x0e17), 0x49 }, | |
| 156 | + { CCI_REG8(0x0e1b), 0x1c }, | |
| 157 | + { CCI_REG8(0x0e3a), 0x36 }, | |
| 158 | + { CCI_REG8(0x0d11), 0x84 }, | |
| 159 | + { CCI_REG8(0x0e52), 0x14 }, | |
| 160 | + { CCI_REG8(0x000b), 0x10 }, | |
| 161 | + { CCI_REG8(0x0008), 0x08 }, | |
| 162 | + { CCI_REG8(0x0223), 0x17 }, | |
| 163 | + { CCI_REG8(0x0d27), 0x39 }, | |
| 164 | + { CCI_REG8(0x0d22), 0x00 }, | |
| 165 | + { CCI_REG8(0x03f6), 0x0d }, | |
| 166 | + { CCI_REG8(0x0d04), 0x07 }, | |
| 167 | + { CCI_REG8(0x03f3), 0x72 }, | |
| 168 | + { CCI_REG8(0x03f4), 0xb8 }, | |
| 169 | + { CCI_REG8(0x03f5), 0xbc }, | |
| 170 | + { CCI_REG8(0x0d02), 0x73 }, | |
| 171 | + | |
| 172 | + /* auto load start */ | |
| 173 | + { CCI_REG8(0x00cb), 0x00 }, | |
| 174 | + | |
| 175 | + /* OUT 2592*1944 */ | |
| 176 | + { CCI_REG8(0x0350), 0x01 }, | |
| 177 | + { CCI_REG8(0x0353), 0x00 }, | |
| 178 | + { CCI_REG8(0x0354), 0x08 }, | |
| 179 | + { CCI_REG16(0x034c), 2592 }, /* Width */ | |
| 180 | + { CCI_REG8(0x021f), 0x14 }, | |
| 181 | + | |
| 182 | + /* MIPI */ | |
| 183 | + { CCI_REG8(0x0107), 0x05 }, | |
| 184 | + { CCI_REG8(0x0117), 0x01 }, | |
| 185 | + { CCI_REG8(0x0d81), 0x00 }, | |
| 186 | + { CCI_REG8(0x0d84), 0x0c }, | |
| 187 | + { CCI_REG8(0x0d85), 0xa8 }, | |
| 188 | + { CCI_REG8(0x0d86), 0x06 }, | |
| 189 | + { CCI_REG8(0x0d87), 0x55 }, | |
| 190 | + { CCI_REG8(0x0db3), 0x06 }, | |
| 191 | + { CCI_REG8(0x0db4), 0x08 }, | |
| 192 | + { CCI_REG8(0x0db5), 0x1e }, | |
| 193 | + { CCI_REG8(0x0db6), 0x02 }, | |
| 194 | + { CCI_REG8(0x0db8), 0x12 }, | |
| 195 | + { CCI_REG8(0x0db9), 0x0a }, | |
| 196 | + { CCI_REG8(0x0d93), 0x06 }, | |
| 197 | + { CCI_REG8(0x0d94), 0x09 }, | |
| 198 | + { CCI_REG8(0x0d95), 0x0d }, | |
| 199 | + { CCI_REG8(0x0d99), 0x0b }, | |
| 200 | + { CCI_REG8(0x0084), 0x01 }, | |
| 201 | + { CCI_REG8(0x0110), 0x01 }, | |
| 202 | +}; | |
| 203 | + | |
| 204 | +static const struct cci_reg_sequence mode_1280x720[] = { | |
| 205 | + /* system */ | |
| 206 | + { CCI_REG8(0x0135), 0x05 }, | |
| 207 | + { CCI_REG8(0x0084), 0x21 }, | |
| 208 | + { CCI_REG8(0x0d05), 0xcc }, | |
| 209 | + { CCI_REG8(0x0218), 0x80 }, | |
| 210 | + { CCI_REG8(0x005e), 0x49 }, | |
| 211 | + { CCI_REG8(0x0d06), 0x81 }, | |
| 212 | + { CCI_REG8(0x0007), 0x16 }, | |
| 213 | + { CCI_REG8(0x0101), 0x00 }, | |
| 214 | + | |
| 215 | + /* analog */ | |
| 216 | + { CCI_REG8(0x0342), 0x07 }, | |
| 217 | + { CCI_REG8(0x0343), 0x10 }, | |
| 218 | + { CCI_REG8(0x0220), 0x07 }, | |
| 219 | + { CCI_REG8(0x0221), 0xd0 }, | |
| 220 | + { CCI_REG8(0x0202), 0x03 }, | |
| 221 | + { CCI_REG8(0x0203), 0x32 }, | |
| 222 | + { CCI_REG8(0x0340), 0x04 }, | |
| 223 | + { CCI_REG8(0x0341), 0x08 }, | |
| 224 | + { CCI_REG8(0x0219), 0x00 }, | |
| 225 | + { CCI_REG8(0x0346), 0x01 }, | |
| 226 | + { CCI_REG8(0x0347), 0x00 }, | |
| 227 | + { CCI_REG8(0x0d14), 0x00 }, | |
| 228 | + { CCI_REG8(0x0d13), 0x05 }, | |
| 229 | + { CCI_REG8(0x0d16), 0x05 }, | |
| 230 | + { CCI_REG8(0x0d15), 0x1d }, | |
| 231 | + { CCI_REG8(0x00c0), 0x0a }, | |
| 232 | + { CCI_REG8(0x00c1), 0x30 }, | |
| 233 | + { CCI_REG8(0x034a), 0x05 }, | |
| 234 | + { CCI_REG8(0x034b), 0xb0 }, | |
| 235 | + { CCI_REG8(0x0e0a), 0x00 }, | |
| 236 | + { CCI_REG8(0x0e0b), 0x00 }, | |
| 237 | + { CCI_REG8(0x0e0e), 0x03 }, | |
| 238 | + { CCI_REG8(0x0e0f), 0x00 }, | |
| 239 | + { CCI_REG8(0x0e06), 0x0a }, | |
| 240 | + { CCI_REG8(0x0e23), 0x15 }, | |
| 241 | + { CCI_REG8(0x0e24), 0x15 }, | |
| 242 | + { CCI_REG8(0x0e2a), 0x10 }, | |
| 243 | + { CCI_REG8(0x0e2b), 0x10 }, | |
| 244 | + { CCI_REG8(0x0e17), 0x49 }, | |
| 245 | + { CCI_REG8(0x0e1b), 0x1c }, | |
| 246 | + { CCI_REG8(0x0e3a), 0x36 }, | |
| 247 | + { CCI_REG8(0x0d11), 0x84 }, | |
| 248 | + { CCI_REG8(0x0e52), 0x14 }, | |
| 249 | + { CCI_REG8(0x000b), 0x0e }, | |
| 250 | + { CCI_REG8(0x0008), 0x03 }, | |
| 251 | + { CCI_REG8(0x0223), 0x16 }, | |
| 252 | + { CCI_REG8(0x0d27), 0x39 }, | |
| 253 | + { CCI_REG8(0x0d22), 0x00 }, | |
| 254 | + { CCI_REG8(0x03f6), 0x0d }, | |
| 255 | + { CCI_REG8(0x0d04), 0x07 }, | |
| 256 | + { CCI_REG8(0x03f3), 0x72 }, | |
| 257 | + { CCI_REG8(0x03f4), 0xb8 }, | |
| 258 | + { CCI_REG8(0x03f5), 0xbc }, | |
| 259 | + { CCI_REG8(0x0d02), 0x73 }, | |
| 260 | + | |
| 261 | + /* auto load start */ | |
| 262 | + { CCI_REG8(0x00cb), 0xfc }, | |
| 263 | + | |
| 264 | + /* OUT 1280x720 */ | |
| 265 | + { CCI_REG8(0x0350), 0x01 }, | |
| 266 | + { CCI_REG8(0x0353), 0x00 }, | |
| 267 | + { CCI_REG8(0x0354), 0x0c }, | |
| 268 | + { CCI_REG16(0x034c), 1280 }, /* Width */ | |
| 269 | + { CCI_REG8(0x021f), 0x14 }, | |
| 270 | + | |
| 271 | + /* MIPI */ | |
| 272 | + { CCI_REG8(0x0107), 0x05 }, | |
| 273 | + { CCI_REG8(0x0117), 0x01 }, | |
| 274 | + { CCI_REG8(0x0d81), 0x00 }, | |
| 275 | + { CCI_REG8(0x0d84), 0x06 }, | |
| 276 | + { CCI_REG8(0x0d85), 0x40 }, | |
| 277 | + { CCI_REG8(0x0d86), 0x03 }, | |
| 278 | + { CCI_REG8(0x0d87), 0x21 }, | |
| 279 | + { CCI_REG8(0x0db3), 0x03 }, | |
| 280 | + { CCI_REG8(0x0db4), 0x04 }, | |
| 281 | + { CCI_REG8(0x0db5), 0x0d }, | |
| 282 | + { CCI_REG8(0x0db6), 0x01 }, | |
| 283 | + { CCI_REG8(0x0db8), 0x04 }, | |
| 284 | + { CCI_REG8(0x0db9), 0x06 }, | |
| 285 | + { CCI_REG8(0x0d93), 0x03 }, | |
| 286 | + { CCI_REG8(0x0d94), 0x04 }, | |
| 287 | + { CCI_REG8(0x0d95), 0x05 }, | |
| 288 | + { CCI_REG8(0x0d99), 0x06 }, | |
| 289 | + { CCI_REG8(0x0084), 0x01 }, | |
| 290 | + { CCI_REG8(0x0110), 0x01 }, | |
| 291 | +}; | |
| 292 | + | |
| 293 | +static const struct cci_reg_sequence mode_table_common[] = { | |
| 294 | + { GC05A2_STREAMING_REG, 0x00 }, | |
| 295 | + /* system */ | |
| 296 | + { CCI_REG8(0x0315), 0xd4 }, | |
| 297 | + { CCI_REG8(0x0d06), 0x01 }, | |
| 298 | + { CCI_REG8(0x0a70), 0x80 }, | |
| 299 | + { CCI_REG8(0x031a), 0x00 }, | |
| 300 | + { CCI_REG8(0x0314), 0x00 }, | |
| 301 | + { CCI_REG8(0x0130), 0x08 }, | |
| 302 | + { CCI_REG8(0x0132), 0x01 }, | |
| 303 | + { CCI_REG8(0x0136), 0x38 }, | |
| 304 | + { CCI_REG8(0x0137), 0x03 }, | |
| 305 | + { CCI_REG8(0x0134), 0x5b }, | |
| 306 | + { CCI_REG8(0x031c), 0xe0 }, | |
| 307 | + { CCI_REG8(0x0d82), 0x14 }, | |
| 308 | + { CCI_REG8(0x0dd1), 0x56 }, | |
| 309 | + { CCI_REG8(0x0af4), 0x01 }, | |
| 310 | + { CCI_REG8(0x0002), 0x10 }, | |
| 311 | + { CCI_REG8(0x00c3), 0x34 }, | |
| 312 | + { CCI_REG8(0x00c4), 0x00 }, | |
| 313 | + { CCI_REG8(0x00c5), 0x01 }, | |
| 314 | + { CCI_REG8(0x0af6), 0x00 }, | |
| 315 | + { CCI_REG8(0x0ba0), 0x17 }, | |
| 316 | + { CCI_REG8(0x0ba1), 0x00 }, | |
| 317 | + { CCI_REG8(0x0ba2), 0x00 }, | |
| 318 | + { CCI_REG8(0x0ba3), 0x00 }, | |
| 319 | + { CCI_REG8(0x0ba4), 0x03 }, | |
| 320 | + { CCI_REG8(0x0ba5), 0x00 }, | |
| 321 | + { CCI_REG8(0x0ba6), 0x00 }, | |
| 322 | + { CCI_REG8(0x0ba7), 0x00 }, | |
| 323 | + { CCI_REG8(0x0ba8), 0x40 }, | |
| 324 | + { CCI_REG8(0x0ba9), 0x00 }, | |
| 325 | + { CCI_REG8(0x0baa), 0x00 }, | |
| 326 | + { CCI_REG8(0x0bab), 0x00 }, | |
| 327 | + { CCI_REG8(0x0bac), 0x40 }, | |
| 328 | + { CCI_REG8(0x0bad), 0x00 }, | |
| 329 | + { CCI_REG8(0x0bae), 0x00 }, | |
| 330 | + { CCI_REG8(0x0baf), 0x00 }, | |
| 331 | + { CCI_REG8(0x0bb0), 0x02 }, | |
| 332 | + { CCI_REG8(0x0bb1), 0x00 }, | |
| 333 | + { CCI_REG8(0x0bb2), 0x00 }, | |
| 334 | + { CCI_REG8(0x0bb3), 0x00 }, | |
| 335 | + { CCI_REG8(0x0bb8), 0x02 }, | |
| 336 | + { CCI_REG8(0x0bb9), 0x00 }, | |
| 337 | + { CCI_REG8(0x0bba), 0x00 }, | |
| 338 | + { CCI_REG8(0x0bbb), 0x00 }, | |
| 339 | + { CCI_REG8(0x0a70), 0x80 }, | |
| 340 | + { CCI_REG8(0x0a71), 0x00 }, | |
| 341 | + { CCI_REG8(0x0a72), 0x00 }, | |
| 342 | + { CCI_REG8(0x0a66), 0x00 }, | |
| 343 | + { CCI_REG8(0x0a67), 0x80 }, | |
| 344 | + { CCI_REG8(0x0a4d), 0x4e }, | |
| 345 | + { CCI_REG8(0x0a50), 0x00 }, | |
| 346 | + { CCI_REG8(0x0a4f), 0x0c }, | |
| 347 | + { CCI_REG8(0x0a66), 0x00 }, | |
| 348 | + { CCI_REG8(0x00ca), 0x00 }, | |
| 349 | + { CCI_REG8(0x00cc), 0x00 }, | |
| 350 | + { CCI_REG8(0x00cd), 0x00 }, | |
| 351 | + { CCI_REG8(0x0aa1), 0x00 }, | |
| 352 | + { CCI_REG8(0x0aa2), 0xe0 }, | |
| 353 | + { CCI_REG8(0x0aa3), 0x00 }, | |
| 354 | + { CCI_REG8(0x0aa4), 0x40 }, | |
| 355 | + { CCI_REG8(0x0a90), 0x03 }, | |
| 356 | + { CCI_REG8(0x0a91), 0x0e }, | |
| 357 | + { CCI_REG8(0x0a94), 0x80 }, | |
| 358 | + { CCI_REG8(0x0af6), 0x20 }, | |
| 359 | + { CCI_REG8(0x0b00), 0x91 }, | |
| 360 | + { CCI_REG8(0x0b01), 0x17 }, | |
| 361 | + { CCI_REG8(0x0b02), 0x01 }, | |
| 362 | + { CCI_REG8(0x0b03), 0x00 }, | |
| 363 | + { CCI_REG8(0x0b04), 0x01 }, | |
| 364 | + { CCI_REG8(0x0b05), 0x17 }, | |
| 365 | + { CCI_REG8(0x0b06), 0x01 }, | |
| 366 | + { CCI_REG8(0x0b07), 0x00 }, | |
| 367 | + { CCI_REG8(0x0ae9), 0x01 }, | |
| 368 | + { CCI_REG8(0x0aea), 0x02 }, | |
| 369 | + { CCI_REG8(0x0ae8), 0x53 }, | |
| 370 | + { CCI_REG8(0x0ae8), 0x43 }, | |
| 371 | + { CCI_REG8(0x0af6), 0x30 }, | |
| 372 | + { CCI_REG8(0x0b00), 0x08 }, | |
| 373 | + { CCI_REG8(0x0b01), 0x0f }, | |
| 374 | + { CCI_REG8(0x0b02), 0x00 }, | |
| 375 | + { CCI_REG8(0x0b04), 0x1c }, | |
| 376 | + { CCI_REG8(0x0b05), 0x24 }, | |
| 377 | + { CCI_REG8(0x0b06), 0x00 }, | |
| 378 | + { CCI_REG8(0x0b08), 0x30 }, | |
| 379 | + { CCI_REG8(0x0b09), 0x40 }, | |
| 380 | + { CCI_REG8(0x0b0a), 0x00 }, | |
| 381 | + { CCI_REG8(0x0b0c), 0x0e }, | |
| 382 | + { CCI_REG8(0x0b0d), 0x2a }, | |
| 383 | + { CCI_REG8(0x0b0e), 0x00 }, | |
| 384 | + { CCI_REG8(0x0b10), 0x0e }, | |
| 385 | + { CCI_REG8(0x0b11), 0x2b }, | |
| 386 | + { CCI_REG8(0x0b12), 0x00 }, | |
| 387 | + { CCI_REG8(0x0b14), 0x0e }, | |
| 388 | + { CCI_REG8(0x0b15), 0x23 }, | |
| 389 | + { CCI_REG8(0x0b16), 0x00 }, | |
| 390 | + { CCI_REG8(0x0b18), 0x0e }, | |
| 391 | + { CCI_REG8(0x0b19), 0x24 }, | |
| 392 | + { CCI_REG8(0x0b1a), 0x00 }, | |
| 393 | + { CCI_REG8(0x0b1c), 0x0c }, | |
| 394 | + { CCI_REG8(0x0b1d), 0x0c }, | |
| 395 | + { CCI_REG8(0x0b1e), 0x00 }, | |
| 396 | + { CCI_REG8(0x0b20), 0x03 }, | |
| 397 | + { CCI_REG8(0x0b21), 0x03 }, | |
| 398 | + { CCI_REG8(0x0b22), 0x00 }, | |
| 399 | + { CCI_REG8(0x0b24), 0x0e }, | |
| 400 | + { CCI_REG8(0x0b25), 0x0e }, | |
| 401 | + { CCI_REG8(0x0b26), 0x00 }, | |
| 402 | + { CCI_REG8(0x0b28), 0x03 }, | |
| 403 | + { CCI_REG8(0x0b29), 0x03 }, | |
| 404 | + { CCI_REG8(0x0b2a), 0x00 }, | |
| 405 | + { CCI_REG8(0x0b2c), 0x12 }, | |
| 406 | + { CCI_REG8(0x0b2d), 0x12 }, | |
| 407 | + { CCI_REG8(0x0b2e), 0x00 }, | |
| 408 | + { CCI_REG8(0x0b30), 0x08 }, | |
| 409 | + { CCI_REG8(0x0b31), 0x08 }, | |
| 410 | + { CCI_REG8(0x0b32), 0x00 }, | |
| 411 | + { CCI_REG8(0x0b34), 0x14 }, | |
| 412 | + { CCI_REG8(0x0b35), 0x14 }, | |
| 413 | + { CCI_REG8(0x0b36), 0x00 }, | |
| 414 | + { CCI_REG8(0x0b38), 0x10 }, | |
| 415 | + { CCI_REG8(0x0b39), 0x10 }, | |
| 416 | + { CCI_REG8(0x0b3a), 0x00 }, | |
| 417 | + { CCI_REG8(0x0b3c), 0x16 }, | |
| 418 | + { CCI_REG8(0x0b3d), 0x16 }, | |
| 419 | + { CCI_REG8(0x0b3e), 0x00 }, | |
| 420 | + { CCI_REG8(0x0b40), 0x10 }, | |
| 421 | + { CCI_REG8(0x0b41), 0x10 }, | |
| 422 | + { CCI_REG8(0x0b42), 0x00 }, | |
| 423 | + { CCI_REG8(0x0b44), 0x19 }, | |
| 424 | + { CCI_REG8(0x0b45), 0x19 }, | |
| 425 | + { CCI_REG8(0x0b46), 0x00 }, | |
| 426 | + { CCI_REG8(0x0b48), 0x16 }, | |
| 427 | + { CCI_REG8(0x0b49), 0x16 }, | |
| 428 | + { CCI_REG8(0x0b4a), 0x00 }, | |
| 429 | + { CCI_REG8(0x0b4c), 0x19 }, | |
| 430 | + { CCI_REG8(0x0b4d), 0x19 }, | |
| 431 | + { CCI_REG8(0x0b4e), 0x00 }, | |
| 432 | + { CCI_REG8(0x0b50), 0x16 }, | |
| 433 | + { CCI_REG8(0x0b51), 0x16 }, | |
| 434 | + { CCI_REG8(0x0b52), 0x00 }, | |
| 435 | + { CCI_REG8(0x0b80), 0x01 }, | |
| 436 | + { CCI_REG8(0x0b81), 0x00 }, | |
| 437 | + { CCI_REG8(0x0b82), 0x00 }, | |
| 438 | + { CCI_REG8(0x0b84), 0x00 }, | |
| 439 | + { CCI_REG8(0x0b85), 0x00 }, | |
| 440 | + { CCI_REG8(0x0b86), 0x00 }, | |
| 441 | + { CCI_REG8(0x0b88), 0x01 }, | |
| 442 | + { CCI_REG8(0x0b89), 0x6a }, | |
| 443 | + { CCI_REG8(0x0b8a), 0x00 }, | |
| 444 | + { CCI_REG8(0x0b8c), 0x00 }, | |
| 445 | + { CCI_REG8(0x0b8d), 0x01 }, | |
| 446 | + { CCI_REG8(0x0b8e), 0x00 }, | |
| 447 | + { CCI_REG8(0x0b90), 0x01 }, | |
| 448 | + { CCI_REG8(0x0b91), 0xf6 }, | |
| 449 | + { CCI_REG8(0x0b92), 0x00 }, | |
| 450 | + { CCI_REG8(0x0b94), 0x00 }, | |
| 451 | + { CCI_REG8(0x0b95), 0x02 }, | |
| 452 | + { CCI_REG8(0x0b96), 0x00 }, | |
| 453 | + { CCI_REG8(0x0b98), 0x02 }, | |
| 454 | + { CCI_REG8(0x0b99), 0xc4 }, | |
| 455 | + { CCI_REG8(0x0b9a), 0x00 }, | |
| 456 | + { CCI_REG8(0x0b9c), 0x00 }, | |
| 457 | + { CCI_REG8(0x0b9d), 0x03 }, | |
| 458 | + { CCI_REG8(0x0b9e), 0x00 }, | |
| 459 | + { CCI_REG8(0x0ba0), 0x03 }, | |
| 460 | + { CCI_REG8(0x0ba1), 0xd8 }, | |
| 461 | + { CCI_REG8(0x0ba2), 0x00 }, | |
| 462 | + { CCI_REG8(0x0ba4), 0x00 }, | |
| 463 | + { CCI_REG8(0x0ba5), 0x04 }, | |
| 464 | + { CCI_REG8(0x0ba6), 0x00 }, | |
| 465 | + { CCI_REG8(0x0ba8), 0x05 }, | |
| 466 | + { CCI_REG8(0x0ba9), 0x4d }, | |
| 467 | + { CCI_REG8(0x0baa), 0x00 }, | |
| 468 | + { CCI_REG8(0x0bac), 0x00 }, | |
| 469 | + { CCI_REG8(0x0bad), 0x05 }, | |
| 470 | + { CCI_REG8(0x0bae), 0x00 }, | |
| 471 | + { CCI_REG8(0x0bb0), 0x07 }, | |
| 472 | + { CCI_REG8(0x0bb1), 0x3e }, | |
| 473 | + { CCI_REG8(0x0bb2), 0x00 }, | |
| 474 | + { CCI_REG8(0x0bb4), 0x00 }, | |
| 475 | + { CCI_REG8(0x0bb5), 0x06 }, | |
| 476 | + { CCI_REG8(0x0bb6), 0x00 }, | |
| 477 | + { CCI_REG8(0x0bb8), 0x0a }, | |
| 478 | + { CCI_REG8(0x0bb9), 0x1a }, | |
| 479 | + { CCI_REG8(0x0bba), 0x00 }, | |
| 480 | + { CCI_REG8(0x0bbc), 0x09 }, | |
| 481 | + { CCI_REG8(0x0bbd), 0x36 }, | |
| 482 | + { CCI_REG8(0x0bbe), 0x00 }, | |
| 483 | + { CCI_REG8(0x0bc0), 0x0e }, | |
| 484 | + { CCI_REG8(0x0bc1), 0x66 }, | |
| 485 | + { CCI_REG8(0x0bc2), 0x00 }, | |
| 486 | + { CCI_REG8(0x0bc4), 0x10 }, | |
| 487 | + { CCI_REG8(0x0bc5), 0x06 }, | |
| 488 | + { CCI_REG8(0x0bc6), 0x00 }, | |
| 489 | + { CCI_REG8(0x02c1), 0xe0 }, | |
| 490 | + { CCI_REG8(0x0207), 0x04 }, | |
| 491 | + { CCI_REG8(0x02c2), 0x10 }, | |
| 492 | + { CCI_REG8(0x02c3), 0x74 }, | |
| 493 | + { CCI_REG8(0x02c5), 0x09 }, | |
| 494 | + { CCI_REG8(0x02c1), 0xe0 }, | |
| 495 | + { CCI_REG8(0x0207), 0x04 }, | |
| 496 | + { CCI_REG8(0x02c2), 0x10 }, | |
| 497 | + { CCI_REG8(0x02c5), 0x09 }, | |
| 498 | + { CCI_REG8(0x02c1), 0xe0 }, | |
| 499 | + { CCI_REG8(0x0207), 0x04 }, | |
| 500 | + { CCI_REG8(0x02c2), 0x10 }, | |
| 501 | + { CCI_REG8(0x02c5), 0x09 }, | |
| 502 | + { CCI_REG8(0x0aa1), 0x15 }, | |
| 503 | + { CCI_REG8(0x0aa2), 0x50 }, | |
| 504 | + { CCI_REG8(0x0aa3), 0x00 }, | |
| 505 | + { CCI_REG8(0x0aa4), 0x09 }, | |
| 506 | + { CCI_REG8(0x0a90), 0x25 }, | |
| 507 | + { CCI_REG8(0x0a91), 0x0e }, | |
| 508 | + { CCI_REG8(0x0a94), 0x80 }, | |
| 509 | + | |
| 510 | + /* ISP */ | |
| 511 | + { CCI_REG8(0x0050), 0x00 }, | |
| 512 | + { CCI_REG8(0x0089), 0x83 }, | |
| 513 | + { CCI_REG8(0x005a), 0x40 }, | |
| 514 | + { CCI_REG8(0x00c3), 0x35 }, | |
| 515 | + { CCI_REG8(0x00c4), 0x80 }, | |
| 516 | + { CCI_REG8(0x0080), 0x10 }, | |
| 517 | + { CCI_REG8(0x0040), 0x12 }, | |
| 518 | + { CCI_REG8(0x0053), 0x0a }, | |
| 519 | + { CCI_REG8(0x0054), 0x44 }, | |
| 520 | + { CCI_REG8(0x0055), 0x32 }, | |
| 521 | + { CCI_REG8(0x0058), 0x89 }, | |
| 522 | + { CCI_REG8(0x004a), 0x03 }, | |
| 523 | + { CCI_REG8(0x0048), 0xf0 }, | |
| 524 | + { CCI_REG8(0x0049), 0x0f }, | |
| 525 | + { CCI_REG8(0x0041), 0x20 }, | |
| 526 | + { CCI_REG8(0x0043), 0x0a }, | |
| 527 | + { CCI_REG8(0x009d), 0x08 }, | |
| 528 | + { CCI_REG8(0x0236), 0x40 }, | |
| 529 | + { CCI_REG8(0x0204), 0x04 }, | |
| 530 | + { CCI_REG8(0x0205), 0x00 }, | |
| 531 | + { CCI_REG8(0x02b3), 0x00 }, | |
| 532 | + { CCI_REG8(0x02b4), 0x00 }, | |
| 533 | + { CCI_REG8(0x009e), 0x01 }, | |
| 534 | + { CCI_REG8(0x009f), 0x94 }, | |
| 535 | + | |
| 536 | + /* auto load REG */ | |
| 537 | + { CCI_REG8(0x0aa1), 0x10 }, | |
| 538 | + { CCI_REG8(0x0aa2), 0xf8 }, | |
| 539 | + { CCI_REG8(0x0aa3), 0x00 }, | |
| 540 | + { CCI_REG8(0x0aa4), 0x1f }, | |
| 541 | + { CCI_REG8(0x0a90), 0x11 }, | |
| 542 | + { CCI_REG8(0x0a91), 0x0e }, | |
| 543 | + { CCI_REG8(0x0a94), 0x80 }, | |
| 544 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 545 | + { CCI_REG8(0x0a90), 0x00 }, | |
| 546 | + { CCI_REG8(0x0a70), 0x00 }, | |
| 547 | + { CCI_REG8(0x0a67), 0x00 }, | |
| 548 | + { CCI_REG8(0x0af4), 0x29 }, | |
| 549 | + | |
| 550 | + /* DPHY */ | |
| 551 | + { CCI_REG8(0x0d80), 0x07 }, | |
| 552 | + { CCI_REG8(0x0dd3), 0x18 }, | |
| 553 | + | |
| 554 | + /* CISCTL_Reset */ | |
| 555 | + { CCI_REG8(0x031c), 0x80 }, | |
| 556 | + { CCI_REG8(0x03fe), 0x30 }, | |
| 557 | + { CCI_REG8(0x0d17), 0x06 }, | |
| 558 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 559 | + { CCI_REG8(0x0d17), 0x00 }, | |
| 560 | + { CCI_REG8(0x031c), 0x93 }, | |
| 561 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 562 | + { CCI_REG8(0x031c), 0x80 }, | |
| 563 | + { CCI_REG8(0x03fe), 0x30 }, | |
| 564 | + { CCI_REG8(0x0d17), 0x06 }, | |
| 565 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 566 | + { CCI_REG8(0x0d17), 0x00 }, | |
| 567 | + { CCI_REG8(0x031c), 0x93 }, | |
| 568 | +}; | |
| 569 | + | |
| 570 | +struct gc05a2_mode { | |
| 571 | + u32 width; | |
| 572 | + u32 height; | |
| 573 | + const struct gc05a2_reg_list reg_list; | |
| 574 | + | |
| 575 | + u32 hts; /* Horizontal timining size */ | |
| 576 | + u32 vts_def; /* Default vertical timining size */ | |
| 577 | + u32 vts_min; /* Min vertical timining size */ | |
| 578 | +}; | |
| 579 | + | |
| 580 | +/* Declare modes in order, from biggest to smallest height. */ | |
| 581 | +static const struct gc05a2_mode gc05a2_modes[] = { | |
| 582 | + { | |
| 583 | + /* 2592*1944@30fps */ | |
| 584 | + .width = GC05A2_NATIVE_WIDTH, | |
| 585 | + .height = GC05A2_NATIVE_HEIGHT, | |
| 586 | + .reg_list = { | |
| 587 | + .num_of_regs = ARRAY_SIZE(mode_2592x1944), | |
| 588 | + .regs = mode_2592x1944, | |
| 589 | + }, | |
| 590 | + .hts = 3664, | |
| 591 | + .vts_def = 2032, | |
| 592 | + .vts_min = 2032, | |
| 593 | + }, | |
| 594 | + { | |
| 595 | + /* 1280*720@60fps */ | |
| 596 | + .width = 1280, | |
| 597 | + .height = 720, | |
| 598 | + .reg_list = { | |
| 599 | + .num_of_regs = ARRAY_SIZE(mode_1280x720), | |
| 600 | + .regs = mode_1280x720, | |
| 601 | + }, | |
| 602 | + .hts = 3616, | |
| 603 | + .vts_def = 1032, | |
| 604 | + .vts_min = 1032, | |
| 605 | + }, | |
| 606 | +}; | |
| 607 | + | |
| 608 | +static inline struct gc05a2 *to_gc05a2(struct v4l2_subdev *sd) | |
| 609 | +{ | |
| 610 | + return container_of(sd, struct gc05a2, sd); | |
| 611 | +} | |
| 612 | + | |
| 613 | +static int gc05a2_power_on(struct device *dev) | |
| 614 | +{ | |
| 615 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 616 | + struct gc05a2 *gc05a2 = to_gc05a2(sd); | |
| 617 | + int ret; | |
| 618 | + | |
| 619 | + ret = regulator_bulk_enable(ARRAY_SIZE(gc05a2_supply_name), | |
| 620 | + gc05a2->supplies); | |
| 621 | + if (ret < 0) { | |
| 622 | + dev_err(gc05a2->dev, "failed to enable regulators: %d\n", ret); | |
| 623 | + return ret; | |
| 624 | + } | |
| 625 | + | |
| 626 | + ret = clk_prepare_enable(gc05a2->xclk); | |
| 627 | + if (ret < 0) { | |
| 628 | + regulator_bulk_disable(ARRAY_SIZE(gc05a2_supply_name), | |
| 629 | + gc05a2->supplies); | |
| 630 | + dev_err(gc05a2->dev, "clk prepare enable failed\n"); | |
| 631 | + return ret; | |
| 632 | + } | |
| 633 | + | |
| 634 | + fsleep(GC05A2_SLEEP_US); | |
| 635 | + | |
| 636 | + gpiod_set_value_cansleep(gc05a2->reset_gpio, 0); | |
| 637 | + fsleep(GC05A2_SLEEP_US); | |
| 638 | + | |
| 639 | + return 0; | |
| 640 | +} | |
| 641 | + | |
| 642 | +static int gc05a2_power_off(struct device *dev) | |
| 643 | +{ | |
| 644 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 645 | + struct gc05a2 *gc05a2 = to_gc05a2(sd); | |
| 646 | + | |
| 647 | + clk_disable_unprepare(gc05a2->xclk); | |
| 648 | + gpiod_set_value_cansleep(gc05a2->reset_gpio, 1); | |
| 649 | + regulator_bulk_disable(ARRAY_SIZE(gc05a2_supply_name), | |
| 650 | + gc05a2->supplies); | |
| 651 | + | |
| 652 | + return 0; | |
| 653 | +} | |
| 654 | + | |
| 655 | +static int gc05a2_enum_mbus_code(struct v4l2_subdev *sd, | |
| 656 | + struct v4l2_subdev_state *sd_state, | |
| 657 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 658 | +{ | |
| 659 | + if (code->index > 0) | |
| 660 | + return -EINVAL; | |
| 661 | + | |
| 662 | + code->code = GC05A2_MBUS_CODE; | |
| 663 | + | |
| 664 | + return 0; | |
| 665 | +} | |
| 666 | + | |
| 667 | +static int gc05a2_enum_frame_size(struct v4l2_subdev *subdev, | |
| 668 | + struct v4l2_subdev_state *sd_state, | |
| 669 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 670 | +{ | |
| 671 | + if (fse->code != GC05A2_MBUS_CODE) | |
| 672 | + return -EINVAL; | |
| 673 | + | |
| 674 | + if (fse->index >= ARRAY_SIZE(gc05a2_modes)) | |
| 675 | + return -EINVAL; | |
| 676 | + | |
| 677 | + fse->min_width = gc05a2_modes[fse->index].width; | |
| 678 | + fse->max_width = gc05a2_modes[fse->index].width; | |
| 679 | + fse->min_height = gc05a2_modes[fse->index].height; | |
| 680 | + fse->max_height = gc05a2_modes[fse->index].height; | |
| 681 | + | |
| 682 | + return 0; | |
| 683 | +} | |
| 684 | + | |
| 685 | +static int gc05a2_update_cur_mode_controls(struct gc05a2 *gc05a2, | |
| 686 | + const struct gc05a2_mode *mode) | |
| 687 | +{ | |
| 688 | + s64 exposure_max, h_blank; | |
| 689 | + int ret; | |
| 690 | + | |
| 691 | + ret = __v4l2_ctrl_modify_range(gc05a2->vblank, | |
| 692 | + mode->vts_min - mode->height, | |
| 693 | + GC05A2_VTS_MAX - mode->height, 1, | |
| 694 | + mode->vts_def - mode->height); | |
| 695 | + if (ret) { | |
| 696 | + dev_err(gc05a2->dev, "VB ctrl range update failed\n"); | |
| 697 | + return ret; | |
| 698 | + } | |
| 699 | + | |
| 700 | + h_blank = mode->hts - mode->width; | |
| 701 | + ret = __v4l2_ctrl_modify_range(gc05a2->hblank, h_blank, h_blank, 1, | |
| 702 | + h_blank); | |
| 703 | + if (ret) { | |
| 704 | + dev_err(gc05a2->dev, "HB ctrl range update failed\n"); | |
| 705 | + return ret; | |
| 706 | + } | |
| 707 | + | |
| 708 | + exposure_max = mode->vts_def - GC05A2_EXP_MARGIN; | |
| 709 | + ret = __v4l2_ctrl_modify_range(gc05a2->exposure, GC05A2_EXP_MIN, | |
| 710 | + exposure_max, GC05A2_EXP_STEP, | |
| 711 | + exposure_max); | |
| 712 | + if (ret) { | |
| 713 | + dev_err(gc05a2->dev, "exposure ctrl range update failed\n"); | |
| 714 | + return ret; | |
| 715 | + } | |
| 716 | + | |
| 717 | + return 0; | |
| 718 | +} | |
| 719 | + | |
| 720 | +static void gc05a2_update_pad_format(struct gc05a2 *gc08a3, | |
| 721 | + const struct gc05a2_mode *mode, | |
| 722 | + struct v4l2_mbus_framefmt *fmt) | |
| 723 | +{ | |
| 724 | + fmt->width = mode->width; | |
| 725 | + fmt->height = mode->height; | |
| 726 | + fmt->code = GC05A2_MBUS_CODE; | |
| 727 | + fmt->field = V4L2_FIELD_NONE; | |
| 728 | + fmt->colorspace = V4L2_COLORSPACE_RAW; | |
| 729 | + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); | |
| 730 | + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; | |
| 731 | + fmt->xfer_func = V4L2_XFER_FUNC_NONE; | |
| 732 | +} | |
| 733 | + | |
| 734 | +static int gc05a2_set_format(struct v4l2_subdev *sd, | |
| 735 | + struct v4l2_subdev_state *state, | |
| 736 | + struct v4l2_subdev_format *fmt) | |
| 737 | +{ | |
| 738 | + struct gc05a2 *gc05a2 = to_gc05a2(sd); | |
| 739 | + struct v4l2_mbus_framefmt *mbus_fmt; | |
| 740 | + struct v4l2_rect *crop; | |
| 741 | + const struct gc05a2_mode *mode; | |
| 742 | + | |
| 743 | + mode = v4l2_find_nearest_size(gc05a2_modes, ARRAY_SIZE(gc05a2_modes), | |
| 744 | + width, height, fmt->format.width, | |
| 745 | + fmt->format.height); | |
| 746 | + | |
| 747 | + /* update crop info to subdev state */ | |
| 748 | + crop = v4l2_subdev_state_get_crop(state, 0); | |
| 749 | + crop->width = mode->width; | |
| 750 | + crop->height = mode->height; | |
| 751 | + | |
| 752 | + /* update fmt info to subdev state */ | |
| 753 | + gc05a2_update_pad_format(gc05a2, mode, &fmt->format); | |
| 754 | + mbus_fmt = v4l2_subdev_state_get_format(state, 0); | |
| 755 | + *mbus_fmt = fmt->format; | |
| 756 | + | |
| 757 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 758 | + return 0; | |
| 759 | + gc05a2->cur_mode = mode; | |
| 760 | + gc05a2_update_cur_mode_controls(gc05a2, mode); | |
| 761 | + | |
| 762 | + return 0; | |
| 763 | +} | |
| 764 | + | |
| 765 | +static int gc05a2_get_selection(struct v4l2_subdev *sd, | |
| 766 | + struct v4l2_subdev_state *state, | |
| 767 | + struct v4l2_subdev_selection *sel) | |
| 768 | +{ | |
| 769 | + switch (sel->target) { | |
| 770 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 771 | + case V4L2_SEL_TGT_CROP: | |
| 772 | + sel->r = *v4l2_subdev_state_get_crop(state, 0); | |
| 773 | + break; | |
| 774 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 775 | + sel->r.top = 0; | |
| 776 | + sel->r.left = 0; | |
| 777 | + sel->r.width = GC05A2_NATIVE_WIDTH; | |
| 778 | + sel->r.height = GC05A2_NATIVE_HEIGHT; | |
| 779 | + break; | |
| 780 | + default: | |
| 781 | + return -EINVAL; | |
| 782 | + } | |
| 783 | + | |
| 784 | + return 0; | |
| 785 | +} | |
| 786 | + | |
| 787 | +static int gc05a2_init_state(struct v4l2_subdev *sd, | |
| 788 | + struct v4l2_subdev_state *state) | |
| 789 | +{ | |
| 790 | + struct v4l2_subdev_format fmt = { | |
| 791 | + .which = V4L2_SUBDEV_FORMAT_TRY, | |
| 792 | + .pad = 0, | |
| 793 | + .format = { | |
| 794 | + .code = GC05A2_MBUS_CODE, | |
| 795 | + .width = gc05a2_modes[0].width, | |
| 796 | + .height = gc05a2_modes[0].height, | |
| 797 | + }, | |
| 798 | + }; | |
| 799 | + | |
| 800 | + gc05a2_set_format(sd, state, &fmt); | |
| 801 | + | |
| 802 | + return 0; | |
| 803 | +} | |
| 804 | + | |
| 805 | +static int gc05a2_set_ctrl_hflip(struct gc05a2 *gc05a2, u32 ctrl_val) | |
| 806 | +{ | |
| 807 | + int ret; | |
| 808 | + u64 val; | |
| 809 | + | |
| 810 | + ret = cci_read(gc05a2->regmap, GC05A2_FLIP_REG, &val, NULL); | |
| 811 | + if (ret) { | |
| 812 | + dev_err(gc05a2->dev, "read hflip register failed: %d\n", ret); | |
| 813 | + return ret; | |
| 814 | + } | |
| 815 | + | |
| 816 | + return cci_update_bits(gc05a2->regmap, GC05A2_FLIP_REG, | |
| 817 | + GC05A2_FLIP_H_MASK, | |
| 818 | + ctrl_val ? GC05A2_FLIP_H_MASK : 0, NULL); | |
| 819 | +} | |
| 820 | + | |
| 821 | +static int gc05a2_set_ctrl_vflip(struct gc05a2 *gc05a2, u32 ctrl_val) | |
| 822 | +{ | |
| 823 | + int ret; | |
| 824 | + u64 val; | |
| 825 | + | |
| 826 | + ret = cci_read(gc05a2->regmap, GC05A2_FLIP_REG, &val, NULL); | |
| 827 | + if (ret) { | |
| 828 | + dev_err(gc05a2->dev, "read vflip register failed: %d\n", ret); | |
| 829 | + return ret; | |
| 830 | + } | |
| 831 | + | |
| 832 | + return cci_update_bits(gc05a2->regmap, GC05A2_FLIP_REG, | |
| 833 | + GC05A2_FLIP_V_MASK, | |
| 834 | + ctrl_val ? GC05A2_FLIP_V_MASK : 0, NULL); | |
| 835 | +} | |
| 836 | + | |
| 837 | +static int gc05a2_test_pattern(struct gc05a2 *gc05a2, u32 pattern_menu) | |
| 838 | +{ | |
| 839 | + u32 pattern; | |
| 840 | + int ret; | |
| 841 | + | |
| 842 | + if (pattern_menu) { | |
| 843 | + switch (pattern_menu) { | |
| 844 | + case 1: | |
| 845 | + case 2: | |
| 846 | + case 3: | |
| 847 | + case 4: | |
| 848 | + case 5: | |
| 849 | + case 6: | |
| 850 | + case 7: | |
| 851 | + pattern = pattern_menu << 4; | |
| 852 | + break; | |
| 853 | + | |
| 854 | + case 8: | |
| 855 | + pattern = 0; | |
| 856 | + break; | |
| 857 | + | |
| 858 | + case 9: | |
| 859 | + pattern = 4; | |
| 860 | + break; | |
| 861 | + | |
| 862 | + default: | |
| 863 | + /* Set pattern to 0, it's a safe default. */ | |
| 864 | + pattern = 0; | |
| 865 | + break; | |
| 866 | + } | |
| 867 | + | |
| 868 | + ret = cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_IDX, | |
| 869 | + pattern, NULL); | |
| 870 | + if (ret) | |
| 871 | + return ret; | |
| 872 | + | |
| 873 | + return cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_EN, | |
| 874 | + GC05A2_TEST_PATTERN_EN, NULL); | |
| 875 | + } else { | |
| 876 | + return cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_EN, | |
| 877 | + 0x00, NULL); | |
| 878 | + } | |
| 879 | +} | |
| 880 | + | |
| 881 | +static int gc05a2_set_ctrl(struct v4l2_ctrl *ctrl) | |
| 882 | +{ | |
| 883 | + struct gc05a2 *gc05a2 = | |
| 884 | + container_of(ctrl->handler, struct gc05a2, ctrls); | |
| 885 | + int ret = 0; | |
| 886 | + s64 exposure_max; | |
| 887 | + struct v4l2_subdev_state *state; | |
| 888 | + const struct v4l2_mbus_framefmt *format; | |
| 889 | + | |
| 890 | + state = v4l2_subdev_get_locked_active_state(&gc05a2->sd); | |
| 891 | + format = v4l2_subdev_state_get_format(state, 0); | |
| 892 | + | |
| 893 | + if (ctrl->id == V4L2_CID_VBLANK) { | |
| 894 | + /* Update max exposure while meeting expected vblanking */ | |
| 895 | + exposure_max = format->height + ctrl->val - GC05A2_EXP_MARGIN; | |
| 896 | + __v4l2_ctrl_modify_range(gc05a2->exposure, | |
| 897 | + gc05a2->exposure->minimum, | |
| 898 | + exposure_max, gc05a2->exposure->step, | |
| 899 | + exposure_max); | |
| 900 | + } | |
| 901 | + | |
| 902 | + /* | |
| 903 | + * Applying V4L2 control value only happens | |
| 904 | + * when power is on for streaming. | |
| 905 | + */ | |
| 906 | + if (!pm_runtime_get_if_active(gc05a2->dev)) | |
| 907 | + return 0; | |
| 908 | + | |
| 909 | + switch (ctrl->id) { | |
| 910 | + case V4L2_CID_EXPOSURE: | |
| 911 | + ret = cci_write(gc05a2->regmap, GC05A2_EXP_REG, | |
| 912 | + ctrl->val, NULL); | |
| 913 | + break; | |
| 914 | + | |
| 915 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 916 | + ret = cci_write(gc05a2->regmap, GC05A2_AGAIN_REG, | |
| 917 | + ctrl->val, NULL); | |
| 918 | + break; | |
| 919 | + | |
| 920 | + case V4L2_CID_VBLANK: | |
| 921 | + ret = cci_write(gc05a2->regmap, GC05A2_FRAME_LENGTH_REG, | |
| 922 | + gc05a2->cur_mode->height + ctrl->val, NULL); | |
| 923 | + break; | |
| 924 | + | |
| 925 | + case V4L2_CID_HFLIP: | |
| 926 | + ret = gc05a2_set_ctrl_hflip(gc05a2, ctrl->val); | |
| 927 | + break; | |
| 928 | + | |
| 929 | + case V4L2_CID_VFLIP: | |
| 930 | + ret = gc05a2_set_ctrl_vflip(gc05a2, ctrl->val); | |
| 931 | + break; | |
| 932 | + | |
| 933 | + case V4L2_CID_TEST_PATTERN: | |
| 934 | + ret = gc05a2_test_pattern(gc05a2, ctrl->val); | |
| 935 | + break; | |
| 936 | + | |
| 937 | + default: | |
| 938 | + break; | |
| 939 | + } | |
| 940 | + | |
| 941 | + pm_runtime_put(gc05a2->dev); | |
| 942 | + | |
| 943 | + return ret; | |
| 944 | +} | |
| 945 | + | |
| 946 | +static const struct v4l2_ctrl_ops gc05a2_ctrl_ops = { | |
| 947 | + .s_ctrl = gc05a2_set_ctrl, | |
| 948 | +}; | |
| 949 | + | |
| 950 | +static int gc05a2_identify_module(struct gc05a2 *gc05a2) | |
| 951 | +{ | |
| 952 | + u64 val; | |
| 953 | + int ret; | |
| 954 | + | |
| 955 | + if (gc05a2->identified) | |
| 956 | + return 0; | |
| 957 | + | |
| 958 | + ret = cci_read(gc05a2->regmap, GC05A2_REG_CHIP_ID, &val, NULL); | |
| 959 | + if (ret) | |
| 960 | + return ret; | |
| 961 | + | |
| 962 | + if (val != GC05A2_CHIP_ID) { | |
| 963 | + dev_err(gc05a2->dev, "chip id mismatch: 0x%x!=0x%llx", | |
| 964 | + GC05A2_CHIP_ID, val); | |
| 965 | + return -ENXIO; | |
| 966 | + } | |
| 967 | + | |
| 968 | + gc05a2->identified = true; | |
| 969 | + | |
| 970 | + return 0; | |
| 971 | +} | |
| 972 | + | |
| 973 | +static int gc05a2_start_streaming(struct gc05a2 *gc05a2) | |
| 974 | +{ | |
| 975 | + const struct gc05a2_mode *mode; | |
| 976 | + const struct gc05a2_reg_list *reg_list; | |
| 977 | + int ret; | |
| 978 | + | |
| 979 | + ret = pm_runtime_resume_and_get(gc05a2->dev); | |
| 980 | + if (ret < 0) | |
| 981 | + return ret; | |
| 982 | + | |
| 983 | + ret = gc05a2_identify_module(gc05a2); | |
| 984 | + if (ret) | |
| 985 | + goto err_rpm_put; | |
| 986 | + | |
| 987 | + ret = cci_multi_reg_write(gc05a2->regmap, | |
| 988 | + mode_table_common, | |
| 989 | + ARRAY_SIZE(mode_table_common), NULL); | |
| 990 | + if (ret) | |
| 991 | + goto err_rpm_put; | |
| 992 | + | |
| 993 | + mode = gc05a2->cur_mode; | |
| 994 | + reg_list = &mode->reg_list; | |
| 995 | + | |
| 996 | + ret = cci_multi_reg_write(gc05a2->regmap, | |
| 997 | + reg_list->regs, reg_list->num_of_regs, NULL); | |
| 998 | + if (ret < 0) | |
| 999 | + goto err_rpm_put; | |
| 1000 | + | |
| 1001 | + ret = __v4l2_ctrl_handler_setup(&gc05a2->ctrls); | |
| 1002 | + if (ret < 0) { | |
| 1003 | + dev_err(gc05a2->dev, "could not sync v4l2 controls\n"); | |
| 1004 | + goto err_rpm_put; | |
| 1005 | + } | |
| 1006 | + | |
| 1007 | + ret = cci_write(gc05a2->regmap, GC05A2_STREAMING_REG, 1, NULL); | |
| 1008 | + if (ret < 0) { | |
| 1009 | + dev_err(gc05a2->dev, "write STREAMING_REG failed: %d\n", ret); | |
| 1010 | + goto err_rpm_put; | |
| 1011 | + } | |
| 1012 | + | |
| 1013 | + return 0; | |
| 1014 | + | |
| 1015 | +err_rpm_put: | |
| 1016 | + pm_runtime_put(gc05a2->dev); | |
| 1017 | + return ret; | |
| 1018 | +} | |
| 1019 | + | |
| 1020 | +static int gc05a2_stop_streaming(struct gc05a2 *gc05a2) | |
| 1021 | +{ | |
| 1022 | + int ret; | |
| 1023 | + | |
| 1024 | + ret = cci_write(gc05a2->regmap, GC05A2_STREAMING_REG, 0, NULL); | |
| 1025 | + if (ret < 0) | |
| 1026 | + dev_err(gc05a2->dev, "could not sent stop streaming %d\n", ret); | |
| 1027 | + | |
| 1028 | + pm_runtime_put(gc05a2->dev); | |
| 1029 | + return ret; | |
| 1030 | +} | |
| 1031 | + | |
| 1032 | +static int gc05a2_s_stream(struct v4l2_subdev *subdev, int enable) | |
| 1033 | +{ | |
| 1034 | + struct gc05a2 *gc05a2 = to_gc05a2(subdev); | |
| 1035 | + struct v4l2_subdev_state *state; | |
| 1036 | + int ret; | |
| 1037 | + | |
| 1038 | + state = v4l2_subdev_lock_and_get_active_state(subdev); | |
| 1039 | + | |
| 1040 | + if (enable) | |
| 1041 | + ret = gc05a2_start_streaming(gc05a2); | |
| 1042 | + else | |
| 1043 | + ret = gc05a2_stop_streaming(gc05a2); | |
| 1044 | + | |
| 1045 | + v4l2_subdev_unlock_state(state); | |
| 1046 | + | |
| 1047 | + return ret; | |
| 1048 | +} | |
| 1049 | + | |
| 1050 | +static const struct v4l2_subdev_video_ops gc05a2_video_ops = { | |
| 1051 | + .s_stream = gc05a2_s_stream, | |
| 1052 | +}; | |
| 1053 | + | |
| 1054 | +static const struct v4l2_subdev_pad_ops gc05a2_subdev_pad_ops = { | |
| 1055 | + .enum_mbus_code = gc05a2_enum_mbus_code, | |
| 1056 | + .enum_frame_size = gc05a2_enum_frame_size, | |
| 1057 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 1058 | + .set_fmt = gc05a2_set_format, | |
| 1059 | + .get_selection = gc05a2_get_selection, | |
| 1060 | +}; | |
| 1061 | + | |
| 1062 | +static const struct v4l2_subdev_core_ops gc05a2_core_ops = { | |
| 1063 | + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | |
| 1064 | + .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
| 1065 | +}; | |
| 1066 | + | |
| 1067 | +static const struct v4l2_subdev_ops gc05a2_subdev_ops = { | |
| 1068 | + .core = &gc05a2_core_ops, | |
| 1069 | + .video = &gc05a2_video_ops, | |
| 1070 | + .pad = &gc05a2_subdev_pad_ops, | |
| 1071 | +}; | |
| 1072 | + | |
| 1073 | +static const struct v4l2_subdev_internal_ops gc05a2_internal_ops = { | |
| 1074 | + .init_state = gc05a2_init_state, | |
| 1075 | +}; | |
| 1076 | + | |
| 1077 | +static int gc05a2_get_regulators(struct device *dev, struct gc05a2 *gc05a2) | |
| 1078 | +{ | |
| 1079 | + unsigned int i; | |
| 1080 | + | |
| 1081 | + for (i = 0; i < ARRAY_SIZE(gc05a2_supply_name); i++) | |
| 1082 | + gc05a2->supplies[i].supply = gc05a2_supply_name[i]; | |
| 1083 | + | |
| 1084 | + return devm_regulator_bulk_get(dev, ARRAY_SIZE(gc05a2_supply_name), | |
| 1085 | + gc05a2->supplies); | |
| 1086 | +} | |
| 1087 | + | |
| 1088 | +static int gc05a2_parse_fwnode(struct gc05a2 *gc05a2) | |
| 1089 | +{ | |
| 1090 | + struct fwnode_handle *endpoint; | |
| 1091 | + struct v4l2_fwnode_endpoint bus_cfg = { | |
| 1092 | + .bus_type = V4L2_MBUS_CSI2_DPHY, | |
| 1093 | + }; | |
| 1094 | + int ret; | |
| 1095 | + struct device *dev = gc05a2->dev; | |
| 1096 | + | |
| 1097 | + endpoint = | |
| 1098 | + fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, | |
| 1099 | + FWNODE_GRAPH_ENDPOINT_NEXT); | |
| 1100 | + if (!endpoint) | |
| 1101 | + return dev_err_probe(dev, -EINVAL, "Missing endpoint node\n"); | |
| 1102 | + | |
| 1103 | + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); | |
| 1104 | + if (ret) { | |
| 1105 | + dev_err_probe(dev, ret, "parsing endpoint node failed\n"); | |
| 1106 | + goto done; | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, | |
| 1110 | + bus_cfg.nr_of_link_frequencies, | |
| 1111 | + gc05a2_link_freq_menu_items, | |
| 1112 | + ARRAY_SIZE(gc05a2_link_freq_menu_items), | |
| 1113 | + &gc05a2->link_freq_bitmap); | |
| 1114 | + if (ret) | |
| 1115 | + goto done; | |
| 1116 | + | |
| 1117 | +done: | |
| 1118 | + v4l2_fwnode_endpoint_free(&bus_cfg); | |
| 1119 | + fwnode_handle_put(endpoint); | |
| 1120 | + return ret; | |
| 1121 | +} | |
| 1122 | + | |
| 1123 | +static u64 gc05a2_to_pixel_rate(u32 f_index) | |
| 1124 | +{ | |
| 1125 | + u64 pixel_rate = | |
| 1126 | + gc05a2_link_freq_menu_items[f_index] * 2 * GC05A2_DATA_LANES; | |
| 1127 | + | |
| 1128 | + return div_u64(pixel_rate, GC05A2_RGB_DEPTH); | |
| 1129 | +} | |
| 1130 | + | |
| 1131 | +static int gc05a2_init_controls(struct gc05a2 *gc05a2) | |
| 1132 | +{ | |
| 1133 | + struct i2c_client *client = v4l2_get_subdevdata(&gc05a2->sd); | |
| 1134 | + const struct gc05a2_mode *mode = &gc05a2_modes[0]; | |
| 1135 | + const struct v4l2_ctrl_ops *ops = &gc05a2_ctrl_ops; | |
| 1136 | + struct v4l2_fwnode_device_properties props; | |
| 1137 | + struct v4l2_ctrl_handler *ctrl_hdlr; | |
| 1138 | + s64 exposure_max, h_blank; | |
| 1139 | + int ret; | |
| 1140 | + | |
| 1141 | + ctrl_hdlr = &gc05a2->ctrls; | |
| 1142 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); | |
| 1143 | + if (ret) | |
| 1144 | + return ret; | |
| 1145 | + | |
| 1146 | + gc05a2->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops, | |
| 1147 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 1148 | + gc05a2->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops, | |
| 1149 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 1150 | + v4l2_ctrl_cluster(2, &gc05a2->hflip); | |
| 1151 | + | |
| 1152 | + gc05a2->link_freq = | |
| 1153 | + v4l2_ctrl_new_int_menu(ctrl_hdlr, | |
| 1154 | + &gc05a2_ctrl_ops, | |
| 1155 | + V4L2_CID_LINK_FREQ, | |
| 1156 | + ARRAY_SIZE(gc05a2_link_freq_menu_items) - 1, | |
| 1157 | + 0, | |
| 1158 | + gc05a2_link_freq_menu_items); | |
| 1159 | + if (gc05a2->link_freq) | |
| 1160 | + gc05a2->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1161 | + | |
| 1162 | + gc05a2->pixel_rate = | |
| 1163 | + v4l2_ctrl_new_std(ctrl_hdlr, | |
| 1164 | + &gc05a2_ctrl_ops, | |
| 1165 | + V4L2_CID_PIXEL_RATE, 0, | |
| 1166 | + gc05a2_to_pixel_rate(0), | |
| 1167 | + 1, | |
| 1168 | + gc05a2_to_pixel_rate(0)); | |
| 1169 | + | |
| 1170 | + gc05a2->vblank = | |
| 1171 | + v4l2_ctrl_new_std(ctrl_hdlr, | |
| 1172 | + &gc05a2_ctrl_ops, V4L2_CID_VBLANK, | |
| 1173 | + mode->vts_min - mode->height, | |
| 1174 | + GC05A2_VTS_MAX - mode->height, 1, | |
| 1175 | + mode->vts_def - mode->height); | |
| 1176 | + | |
| 1177 | + h_blank = mode->hts - mode->width; | |
| 1178 | + gc05a2->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops, | |
| 1179 | + V4L2_CID_HBLANK, h_blank, h_blank, 1, | |
| 1180 | + h_blank); | |
| 1181 | + if (gc05a2->hblank) | |
| 1182 | + gc05a2->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1183 | + | |
| 1184 | + v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops, | |
| 1185 | + V4L2_CID_ANALOGUE_GAIN, GC05A2_AGAIN_MIN, | |
| 1186 | + GC05A2_AGAIN_MAX, GC05A2_AGAIN_STEP, | |
| 1187 | + GC05A2_AGAIN_MIN); | |
| 1188 | + | |
| 1189 | + exposure_max = mode->vts_def - GC05A2_EXP_MARGIN; | |
| 1190 | + gc05a2->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops, | |
| 1191 | + V4L2_CID_EXPOSURE, GC05A2_EXP_MIN, | |
| 1192 | + exposure_max, GC05A2_EXP_STEP, | |
| 1193 | + exposure_max); | |
| 1194 | + | |
| 1195 | + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &gc05a2_ctrl_ops, | |
| 1196 | + V4L2_CID_TEST_PATTERN, | |
| 1197 | + ARRAY_SIZE(gc05a2_test_pattern_menu) - 1, | |
| 1198 | + 0, 0, gc05a2_test_pattern_menu); | |
| 1199 | + | |
| 1200 | + /* register properties to fwnode (e.g. rotation, orientation) */ | |
| 1201 | + ret = v4l2_fwnode_device_parse(&client->dev, &props); | |
| 1202 | + if (ret) | |
| 1203 | + goto error_ctrls; | |
| 1204 | + | |
| 1205 | + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ops, &props); | |
| 1206 | + if (ret) | |
| 1207 | + goto error_ctrls; | |
| 1208 | + | |
| 1209 | + if (ctrl_hdlr->error) { | |
| 1210 | + ret = ctrl_hdlr->error; | |
| 1211 | + goto error_ctrls; | |
| 1212 | + } | |
| 1213 | + | |
| 1214 | + gc05a2->sd.ctrl_handler = ctrl_hdlr; | |
| 1215 | + | |
| 1216 | + return 0; | |
| 1217 | + | |
| 1218 | +error_ctrls: | |
| 1219 | + v4l2_ctrl_handler_free(ctrl_hdlr); | |
| 1220 | + | |
| 1221 | + return ret; | |
| 1222 | +} | |
| 1223 | + | |
| 1224 | +static int gc05a2_probe(struct i2c_client *client) | |
| 1225 | +{ | |
| 1226 | + struct device *dev = &client->dev; | |
| 1227 | + struct gc05a2 *gc05a2; | |
| 1228 | + int ret; | |
| 1229 | + | |
| 1230 | + gc05a2 = devm_kzalloc(dev, sizeof(*gc05a2), GFP_KERNEL); | |
| 1231 | + if (!gc05a2) | |
| 1232 | + return -ENOMEM; | |
| 1233 | + | |
| 1234 | + gc05a2->dev = dev; | |
| 1235 | + | |
| 1236 | + ret = gc05a2_parse_fwnode(gc05a2); | |
| 1237 | + if (ret) | |
| 1238 | + return ret; | |
| 1239 | + | |
| 1240 | + gc05a2->regmap = devm_cci_regmap_init_i2c(client, 16); | |
| 1241 | + if (IS_ERR(gc05a2->regmap)) | |
| 1242 | + return dev_err_probe(dev, PTR_ERR(gc05a2->regmap), | |
| 1243 | + "failed to init CCI\n"); | |
| 1244 | + | |
| 1245 | + gc05a2->xclk = devm_clk_get(dev, NULL); | |
| 1246 | + if (IS_ERR(gc05a2->xclk)) | |
| 1247 | + return dev_err_probe(dev, PTR_ERR(gc05a2->xclk), | |
| 1248 | + "failed to get xclk\n"); | |
| 1249 | + | |
| 1250 | + ret = clk_set_rate(gc05a2->xclk, GC05A2_DEFAULT_CLK_FREQ); | |
| 1251 | + if (ret) | |
| 1252 | + return dev_err_probe(dev, ret, | |
| 1253 | + "failed to set xclk frequency\n"); | |
| 1254 | + | |
| 1255 | + ret = gc05a2_get_regulators(dev, gc05a2); | |
| 1256 | + if (ret < 0) | |
| 1257 | + return dev_err_probe(dev, ret, | |
| 1258 | + "failed to get regulators\n"); | |
| 1259 | + | |
| 1260 | + gc05a2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 1261 | + if (IS_ERR(gc05a2->reset_gpio)) | |
| 1262 | + return dev_err_probe(dev, PTR_ERR(gc05a2->reset_gpio), | |
| 1263 | + "failed to get gpio\n"); | |
| 1264 | + | |
| 1265 | + v4l2_i2c_subdev_init(&gc05a2->sd, client, &gc05a2_subdev_ops); | |
| 1266 | + gc05a2->sd.internal_ops = &gc05a2_internal_ops; | |
| 1267 | + gc05a2->cur_mode = &gc05a2_modes[0]; | |
| 1268 | + | |
| 1269 | + ret = gc05a2_init_controls(gc05a2); | |
| 1270 | + if (ret) | |
| 1271 | + return dev_err_probe(dev, ret, | |
| 1272 | + "failed to init controls\n"); | |
| 1273 | + | |
| 1274 | + gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | |
| 1275 | + V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 1276 | + gc05a2->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1277 | + gc05a2->sd.dev = &client->dev; | |
| 1278 | + gc05a2->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1279 | + | |
| 1280 | + ret = media_entity_pads_init(&gc05a2->sd.entity, 1, &gc05a2->pad); | |
| 1281 | + if (ret < 0) { | |
| 1282 | + dev_err_probe(dev, ret, "could not register media entity\n"); | |
| 1283 | + goto err_v4l2_ctrl_handler_free; | |
| 1284 | + } | |
| 1285 | + | |
| 1286 | + gc05a2->sd.state_lock = gc05a2->ctrls.lock; | |
| 1287 | + ret = v4l2_subdev_init_finalize(&gc05a2->sd); | |
| 1288 | + if (ret < 0) { | |
| 1289 | + dev_err_probe(dev, ret, "v4l2 subdev init error\n"); | |
| 1290 | + goto err_media_entity_cleanup; | |
| 1291 | + } | |
| 1292 | + | |
| 1293 | + pm_runtime_enable(gc05a2->dev); | |
| 1294 | + pm_runtime_set_autosuspend_delay(gc05a2->dev, 1000); | |
| 1295 | + pm_runtime_use_autosuspend(gc05a2->dev); | |
| 1296 | + pm_runtime_idle(gc05a2->dev); | |
| 1297 | + | |
| 1298 | + ret = v4l2_async_register_subdev_sensor(&gc05a2->sd); | |
| 1299 | + if (ret < 0) { | |
| 1300 | + dev_err_probe(dev, ret, "could not register v4l2 device\n"); | |
| 1301 | + goto err_rpm; | |
| 1302 | + } | |
| 1303 | + | |
| 1304 | + return 0; | |
| 1305 | + | |
| 1306 | +err_rpm: | |
| 1307 | + pm_runtime_disable(gc05a2->dev); | |
| 1308 | + v4l2_subdev_cleanup(&gc05a2->sd); | |
| 1309 | + | |
| 1310 | +err_media_entity_cleanup: | |
| 1311 | + media_entity_cleanup(&gc05a2->sd.entity); | |
| 1312 | + | |
| 1313 | +err_v4l2_ctrl_handler_free: | |
| 1314 | + v4l2_ctrl_handler_free(&gc05a2->ctrls); | |
| 1315 | + | |
| 1316 | + return ret; | |
| 1317 | +} | |
| 1318 | + | |
| 1319 | +static void gc05a2_remove(struct i2c_client *client) | |
| 1320 | +{ | |
| 1321 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1322 | + struct gc05a2 *gc05a2 = to_gc05a2(sd); | |
| 1323 | + | |
| 1324 | + v4l2_async_unregister_subdev(&gc05a2->sd); | |
| 1325 | + v4l2_subdev_cleanup(sd); | |
| 1326 | + media_entity_cleanup(&gc05a2->sd.entity); | |
| 1327 | + v4l2_ctrl_handler_free(&gc05a2->ctrls); | |
| 1328 | + | |
| 1329 | + pm_runtime_disable(&client->dev); | |
| 1330 | + if (!pm_runtime_status_suspended(&client->dev)) | |
| 1331 | + gc05a2_power_off(gc05a2->dev); | |
| 1332 | + pm_runtime_set_suspended(&client->dev); | |
| 1333 | +} | |
| 1334 | + | |
| 1335 | +static const struct of_device_id gc05a2_of_match[] = { | |
| 1336 | + { .compatible = "galaxycore,gc05a2" }, | |
| 1337 | + {} | |
| 1338 | +}; | |
| 1339 | +MODULE_DEVICE_TABLE(of, gc05a2_of_match); | |
| 1340 | + | |
| 1341 | +static DEFINE_RUNTIME_DEV_PM_OPS(gc05a2_pm_ops, | |
| 1342 | + gc05a2_power_off, | |
| 1343 | + gc05a2_power_on, | |
| 1344 | + NULL); | |
| 1345 | + | |
| 1346 | +static struct i2c_driver gc05a2_i2c_driver = { | |
| 1347 | + .driver = { | |
| 1348 | + .of_match_table = gc05a2_of_match, | |
| 1349 | + .pm = pm_ptr(&gc05a2_pm_ops), | |
| 1350 | + .name = "gc05a2", | |
| 1351 | + }, | |
| 1352 | + .probe = gc05a2_probe, | |
| 1353 | + .remove = gc05a2_remove, | |
| 1354 | +}; | |
| 1355 | +module_i2c_driver(gc05a2_i2c_driver); | |
| 1356 | + | |
| 1357 | +MODULE_DESCRIPTION("GalaxyCore gc05a2 Camera driver"); | |
| 1358 | +MODULE_AUTHOR("Zhi Mao <zhi.mao@mediatek.com>"); | |
| 1359 | +MODULE_LICENSE("GPL"); | |
| @@ -0,0 +1,1339 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Driver for GalaxyCore gc08a3 image sensor | |
| 4 | + * | |
| 5 | + * Copyright 2024 MediaTek | |
| 6 | + * | |
| 7 | + * Zhi Mao <zhi.mao@mediatek.com> | |
| 8 | + */ | |
| 9 | +#include <linux/array_size.h> | |
| 10 | +#include <linux/bits.h> | |
| 11 | +#include <linux/clk.h> | |
| 12 | +#include <linux/container_of.h> | |
| 13 | +#include <linux/delay.h> | |
| 14 | +#include <linux/device.h> | |
| 15 | +#include <linux/err.h> | |
| 16 | +#include <linux/gpio/consumer.h> | |
| 17 | +#include <linux/math64.h> | |
| 18 | +#include <linux/mod_devicetable.h> | |
| 19 | +#include <linux/pm_runtime.h> | |
| 20 | +#include <linux/property.h> | |
| 21 | +#include <linux/regulator/consumer.h> | |
| 22 | +#include <linux/types.h> | |
| 23 | +#include <linux/units.h> | |
| 24 | + | |
| 25 | +#include <media/v4l2-cci.h> | |
| 26 | +#include <media/v4l2-ctrls.h> | |
| 27 | +#include <media/v4l2-event.h> | |
| 28 | +#include <media/v4l2-fwnode.h> | |
| 29 | +#include <media/v4l2-subdev.h> | |
| 30 | + | |
| 31 | +#define GC08A3_REG_TEST_PATTERN_EN CCI_REG8(0x008c) | |
| 32 | +#define GC08A3_REG_TEST_PATTERN_IDX CCI_REG8(0x008d) | |
| 33 | +#define GC08A3_TEST_PATTERN_EN 0x01 | |
| 34 | + | |
| 35 | +#define GC08A3_STREAMING_REG CCI_REG8(0x0100) | |
| 36 | + | |
| 37 | +#define GC08A3_FLIP_REG CCI_REG8(0x0101) | |
| 38 | +#define GC08A3_FLIP_H_MASK BIT(0) | |
| 39 | +#define GC08A3_FLIP_V_MASK BIT(1) | |
| 40 | + | |
| 41 | +#define GC08A3_EXP_REG CCI_REG16(0x0202) | |
| 42 | +#define GC08A3_EXP_MARGIN 16 | |
| 43 | +#define GC08A3_EXP_MIN 4 | |
| 44 | +#define GC08A3_EXP_STEP 1 | |
| 45 | + | |
| 46 | +#define GC08A3_AGAIN_REG CCI_REG16(0x0204) | |
| 47 | +#define GC08A3_AGAIN_MIN 1024 | |
| 48 | +#define GC08A3_AGAIN_MAX (1024 * 16) | |
| 49 | +#define GC08A3_AGAIN_STEP 1 | |
| 50 | + | |
| 51 | +#define GC08A3_FRAME_LENGTH_REG CCI_REG16(0x0340) | |
| 52 | +#define GC08A3_VTS_MAX 0xfff0 | |
| 53 | + | |
| 54 | +#define GC08A3_REG_CHIP_ID CCI_REG16(0x03f0) | |
| 55 | +#define GC08A3_CHIP_ID 0x08a3 | |
| 56 | + | |
| 57 | +#define GC08A3_NATIVE_WIDTH 3264 | |
| 58 | +#define GC08A3_NATIVE_HEIGHT 2448 | |
| 59 | + | |
| 60 | +#define GC08A3_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ) | |
| 61 | +#define GC08A3_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10 | |
| 62 | +#define GC08A3_DATA_LANES 4 | |
| 63 | + | |
| 64 | +#define GC08A3_RGB_DEPTH 10 | |
| 65 | + | |
| 66 | +#define GC08A3_SLEEP_US (2 * USEC_PER_MSEC) | |
| 67 | + | |
| 68 | +static const char *const gc08a3_test_pattern_menu[] = { | |
| 69 | + "No Pattern", "Solid Black", "Colour Bar", "Solid White", | |
| 70 | + "Solid Red", "Solid Green", "Solid Blue", "Solid Yellow", | |
| 71 | +}; | |
| 72 | + | |
| 73 | +static const s64 gc08a3_link_freq_menu_items[] = { | |
| 74 | + (336 * HZ_PER_MHZ), | |
| 75 | + (207 * HZ_PER_MHZ), | |
| 76 | +}; | |
| 77 | + | |
| 78 | +static const char *const gc08a3_supply_name[] = { | |
| 79 | + "avdd", | |
| 80 | + "dvdd", | |
| 81 | + "dovdd", | |
| 82 | +}; | |
| 83 | + | |
| 84 | +struct gc08a3 { | |
| 85 | + struct device *dev; | |
| 86 | + struct v4l2_subdev sd; | |
| 87 | + struct media_pad pad; | |
| 88 | + | |
| 89 | + struct clk *xclk; | |
| 90 | + struct regulator_bulk_data supplies[ARRAY_SIZE(gc08a3_supply_name)]; | |
| 91 | + struct gpio_desc *reset_gpio; | |
| 92 | + | |
| 93 | + struct v4l2_ctrl_handler ctrls; | |
| 94 | + struct v4l2_ctrl *pixel_rate; | |
| 95 | + struct v4l2_ctrl *link_freq; | |
| 96 | + struct v4l2_ctrl *exposure; | |
| 97 | + struct v4l2_ctrl *vblank; | |
| 98 | + struct v4l2_ctrl *hblank; | |
| 99 | + struct v4l2_ctrl *hflip; | |
| 100 | + struct v4l2_ctrl *vflip; | |
| 101 | + | |
| 102 | + struct regmap *regmap; | |
| 103 | + unsigned long link_freq_bitmap; | |
| 104 | + const struct gc08a3_mode *cur_mode; | |
| 105 | +}; | |
| 106 | + | |
| 107 | +struct gc08a3_reg_list { | |
| 108 | + u32 num_of_regs; | |
| 109 | + const struct cci_reg_sequence *regs; | |
| 110 | +}; | |
| 111 | + | |
| 112 | +static const struct cci_reg_sequence mode_3264x2448[] = { | |
| 113 | + /* system */ | |
| 114 | + { CCI_REG8(0x0336), 0x70 }, | |
| 115 | + { CCI_REG8(0x0383), 0xbb }, | |
| 116 | + { CCI_REG8(0x0344), 0x00 }, | |
| 117 | + { CCI_REG8(0x0345), 0x06 }, | |
| 118 | + { CCI_REG8(0x0346), 0x00 }, | |
| 119 | + { CCI_REG8(0x0347), 0x04 }, | |
| 120 | + { CCI_REG8(0x0348), 0x0c }, | |
| 121 | + { CCI_REG8(0x0349), 0xd0 }, | |
| 122 | + { CCI_REG8(0x034a), 0x09 }, | |
| 123 | + { CCI_REG8(0x034b), 0x9c }, | |
| 124 | + { CCI_REG8(0x0202), 0x09 }, | |
| 125 | + { CCI_REG8(0x0203), 0x04 }, | |
| 126 | + { CCI_REG8(0x0340), 0x09 }, | |
| 127 | + { CCI_REG8(0x0341), 0xf4 }, | |
| 128 | + { CCI_REG8(0x0342), 0x07 }, | |
| 129 | + { CCI_REG8(0x0343), 0x1c }, | |
| 130 | + | |
| 131 | + { CCI_REG8(0x0226), 0x00 }, | |
| 132 | + { CCI_REG8(0x0227), 0x28 }, | |
| 133 | + { CCI_REG8(0x0e38), 0x49 }, | |
| 134 | + { CCI_REG8(0x0210), 0x13 }, | |
| 135 | + { CCI_REG8(0x0218), 0x00 }, | |
| 136 | + { CCI_REG8(0x0241), 0x88 }, | |
| 137 | + { CCI_REG8(0x0392), 0x60 }, | |
| 138 | + | |
| 139 | + /* ISP */ | |
| 140 | + { CCI_REG8(0x00a2), 0x00 }, | |
| 141 | + { CCI_REG8(0x00a3), 0x00 }, | |
| 142 | + { CCI_REG8(0x00ab), 0x00 }, | |
| 143 | + { CCI_REG8(0x00ac), 0x00 }, | |
| 144 | + | |
| 145 | + /* GAIN */ | |
| 146 | + { CCI_REG8(0x0204), 0x04 }, | |
| 147 | + { CCI_REG8(0x0205), 0x00 }, | |
| 148 | + { CCI_REG8(0x0050), 0x5c }, | |
| 149 | + { CCI_REG8(0x0051), 0x44 }, | |
| 150 | + | |
| 151 | + /* out window */ | |
| 152 | + { CCI_REG8(0x009a), 0x66 }, | |
| 153 | + { CCI_REG8(0x0351), 0x00 }, | |
| 154 | + { CCI_REG8(0x0352), 0x06 }, | |
| 155 | + { CCI_REG8(0x0353), 0x00 }, | |
| 156 | + { CCI_REG8(0x0354), 0x08 }, | |
| 157 | + { CCI_REG8(0x034c), 0x0c }, | |
| 158 | + { CCI_REG8(0x034d), 0xc0 }, | |
| 159 | + { CCI_REG8(0x034e), 0x09 }, | |
| 160 | + { CCI_REG8(0x034f), 0x90 }, | |
| 161 | + | |
| 162 | + /* MIPI */ | |
| 163 | + { CCI_REG8(0x0114), 0x03 }, | |
| 164 | + { CCI_REG8(0x0180), 0x65 }, | |
| 165 | + { CCI_REG8(0x0181), 0xf0 }, | |
| 166 | + { CCI_REG8(0x0185), 0x01 }, | |
| 167 | + { CCI_REG8(0x0115), 0x30 }, | |
| 168 | + { CCI_REG8(0x011b), 0x12 }, | |
| 169 | + { CCI_REG8(0x011c), 0x12 }, | |
| 170 | + { CCI_REG8(0x0121), 0x06 }, | |
| 171 | + { CCI_REG8(0x0122), 0x06 }, | |
| 172 | + { CCI_REG8(0x0123), 0x15 }, | |
| 173 | + { CCI_REG8(0x0124), 0x01 }, | |
| 174 | + { CCI_REG8(0x0125), 0x0b }, | |
| 175 | + { CCI_REG8(0x0126), 0x08 }, | |
| 176 | + { CCI_REG8(0x0129), 0x06 }, | |
| 177 | + { CCI_REG8(0x012a), 0x08 }, | |
| 178 | + { CCI_REG8(0x012b), 0x08 }, | |
| 179 | + | |
| 180 | + { CCI_REG8(0x0a73), 0x60 }, | |
| 181 | + { CCI_REG8(0x0a70), 0x11 }, | |
| 182 | + { CCI_REG8(0x0313), 0x80 }, | |
| 183 | + { CCI_REG8(0x0aff), 0x00 }, | |
| 184 | + { CCI_REG8(0x0a70), 0x00 }, | |
| 185 | + { CCI_REG8(0x00a4), 0x80 }, | |
| 186 | + { CCI_REG8(0x0316), 0x01 }, | |
| 187 | + { CCI_REG8(0x0a67), 0x00 }, | |
| 188 | + { CCI_REG8(0x0084), 0x10 }, | |
| 189 | + { CCI_REG8(0x0102), 0x09 }, | |
| 190 | +}; | |
| 191 | + | |
| 192 | +static const struct cci_reg_sequence mode_1920x1080[] = { | |
| 193 | + /* system */ | |
| 194 | + { CCI_REG8(0x0336), 0x45 }, | |
| 195 | + { CCI_REG8(0x0383), 0x8b }, | |
| 196 | + { CCI_REG8(0x0344), 0x02 }, | |
| 197 | + { CCI_REG8(0x0345), 0xa6 }, | |
| 198 | + { CCI_REG8(0x0346), 0x02 }, | |
| 199 | + { CCI_REG8(0x0347), 0xb0 }, | |
| 200 | + { CCI_REG8(0x0348), 0x07 }, | |
| 201 | + { CCI_REG8(0x0349), 0x90 }, | |
| 202 | + { CCI_REG8(0x034a), 0x04 }, | |
| 203 | + { CCI_REG8(0x034b), 0x44 }, | |
| 204 | + { CCI_REG8(0x0202), 0x03 }, | |
| 205 | + { CCI_REG8(0x0203), 0x00 }, | |
| 206 | + { CCI_REG8(0x0340), 0x04 }, | |
| 207 | + { CCI_REG8(0x0341), 0xfc }, | |
| 208 | + { CCI_REG8(0x0342), 0x07 }, | |
| 209 | + { CCI_REG8(0x0343), 0x1c }, | |
| 210 | + { CCI_REG8(0x0226), 0x00 }, | |
| 211 | + { CCI_REG8(0x0227), 0x88 }, | |
| 212 | + { CCI_REG8(0x0e38), 0x49 }, | |
| 213 | + { CCI_REG8(0x0210), 0x13 }, | |
| 214 | + { CCI_REG8(0x0218), 0x00 }, | |
| 215 | + { CCI_REG8(0x0241), 0x88 }, | |
| 216 | + { CCI_REG8(0x0392), 0x60 }, | |
| 217 | + | |
| 218 | + /* ISP */ | |
| 219 | + { CCI_REG8(0x00a2), 0xac }, | |
| 220 | + { CCI_REG8(0x00a3), 0x02 }, | |
| 221 | + { CCI_REG8(0x00ab), 0xa0 }, | |
| 222 | + { CCI_REG8(0x00ac), 0x02 }, | |
| 223 | + | |
| 224 | + /* GAIN */ | |
| 225 | + { CCI_REG8(0x0204), 0x04 }, | |
| 226 | + { CCI_REG8(0x0205), 0x00 }, | |
| 227 | + { CCI_REG8(0x0050), 0x38 }, | |
| 228 | + { CCI_REG8(0x0051), 0x20 }, | |
| 229 | + | |
| 230 | + /* out window */ | |
| 231 | + { CCI_REG8(0x009a), 0x66 }, | |
| 232 | + { CCI_REG8(0x0351), 0x00 }, | |
| 233 | + { CCI_REG8(0x0352), 0x06 }, | |
| 234 | + { CCI_REG8(0x0353), 0x00 }, | |
| 235 | + { CCI_REG8(0x0354), 0x08 }, | |
| 236 | + { CCI_REG8(0x034c), 0x07 }, | |
| 237 | + { CCI_REG8(0x034d), 0x80 }, | |
| 238 | + { CCI_REG8(0x034e), 0x04 }, | |
| 239 | + { CCI_REG8(0x034f), 0x38 }, | |
| 240 | + | |
| 241 | + /* MIPI */ | |
| 242 | + { CCI_REG8(0x0114), 0x03 }, | |
| 243 | + { CCI_REG8(0x0180), 0x65 }, | |
| 244 | + { CCI_REG8(0x0181), 0xf0 }, | |
| 245 | + { CCI_REG8(0x0185), 0x01 }, | |
| 246 | + { CCI_REG8(0x0115), 0x30 }, | |
| 247 | + { CCI_REG8(0x011b), 0x12 }, | |
| 248 | + { CCI_REG8(0x011c), 0x12 }, | |
| 249 | + { CCI_REG8(0x0121), 0x02 }, | |
| 250 | + { CCI_REG8(0x0122), 0x03 }, | |
| 251 | + { CCI_REG8(0x0123), 0x0c }, | |
| 252 | + { CCI_REG8(0x0124), 0x00 }, | |
| 253 | + { CCI_REG8(0x0125), 0x09 }, | |
| 254 | + { CCI_REG8(0x0126), 0x06 }, | |
| 255 | + { CCI_REG8(0x0129), 0x04 }, | |
| 256 | + { CCI_REG8(0x012a), 0x03 }, | |
| 257 | + { CCI_REG8(0x012b), 0x06 }, | |
| 258 | + | |
| 259 | + { CCI_REG8(0x0a73), 0x60 }, | |
| 260 | + { CCI_REG8(0x0a70), 0x11 }, | |
| 261 | + { CCI_REG8(0x0313), 0x80 }, | |
| 262 | + { CCI_REG8(0x0aff), 0x00 }, | |
| 263 | + { CCI_REG8(0x0a70), 0x00 }, | |
| 264 | + { CCI_REG8(0x00a4), 0x80 }, | |
| 265 | + { CCI_REG8(0x0316), 0x01 }, | |
| 266 | + { CCI_REG8(0x0a67), 0x00 }, | |
| 267 | + { CCI_REG8(0x0084), 0x10 }, | |
| 268 | + { CCI_REG8(0x0102), 0x09 }, | |
| 269 | +}; | |
| 270 | + | |
| 271 | +static const struct cci_reg_sequence mode_table_common[] = { | |
| 272 | + { GC08A3_STREAMING_REG, 0x00 }, | |
| 273 | + /* system */ | |
| 274 | + { CCI_REG8(0x031c), 0x60 }, | |
| 275 | + { CCI_REG8(0x0337), 0x04 }, | |
| 276 | + { CCI_REG8(0x0335), 0x51 }, | |
| 277 | + { CCI_REG8(0x0336), 0x70 }, | |
| 278 | + { CCI_REG8(0x0383), 0xbb }, | |
| 279 | + { CCI_REG8(0x031a), 0x00 }, | |
| 280 | + { CCI_REG8(0x0321), 0x10 }, | |
| 281 | + { CCI_REG8(0x0327), 0x03 }, | |
| 282 | + { CCI_REG8(0x0325), 0x40 }, | |
| 283 | + { CCI_REG8(0x0326), 0x23 }, | |
| 284 | + { CCI_REG8(0x0314), 0x11 }, | |
| 285 | + { CCI_REG8(0x0315), 0xd6 }, | |
| 286 | + { CCI_REG8(0x0316), 0x01 }, | |
| 287 | + { CCI_REG8(0x0334), 0x40 }, | |
| 288 | + { CCI_REG8(0x0324), 0x42 }, | |
| 289 | + { CCI_REG8(0x031c), 0x00 }, | |
| 290 | + { CCI_REG8(0x031c), 0x9f }, | |
| 291 | + { CCI_REG8(0x039a), 0x13 }, | |
| 292 | + { CCI_REG8(0x0084), 0x30 }, | |
| 293 | + { CCI_REG8(0x02b3), 0x08 }, | |
| 294 | + { CCI_REG8(0x0057), 0x0c }, | |
| 295 | + { CCI_REG8(0x05c3), 0x50 }, | |
| 296 | + { CCI_REG8(0x0311), 0x90 }, | |
| 297 | + { CCI_REG8(0x05a0), 0x02 }, | |
| 298 | + { CCI_REG8(0x0074), 0x0a }, | |
| 299 | + { CCI_REG8(0x0059), 0x11 }, | |
| 300 | + { CCI_REG8(0x0070), 0x05 }, | |
| 301 | + { CCI_REG8(0x0101), 0x00 }, | |
| 302 | + | |
| 303 | + /* analog */ | |
| 304 | + { CCI_REG8(0x0344), 0x00 }, | |
| 305 | + { CCI_REG8(0x0345), 0x06 }, | |
| 306 | + { CCI_REG8(0x0346), 0x00 }, | |
| 307 | + { CCI_REG8(0x0347), 0x04 }, | |
| 308 | + { CCI_REG8(0x0348), 0x0c }, | |
| 309 | + { CCI_REG8(0x0349), 0xd0 }, | |
| 310 | + { CCI_REG8(0x034a), 0x09 }, | |
| 311 | + { CCI_REG8(0x034b), 0x9c }, | |
| 312 | + { CCI_REG8(0x0202), 0x09 }, | |
| 313 | + { CCI_REG8(0x0203), 0x04 }, | |
| 314 | + | |
| 315 | + { CCI_REG8(0x0219), 0x05 }, | |
| 316 | + { CCI_REG8(0x0226), 0x00 }, | |
| 317 | + { CCI_REG8(0x0227), 0x28 }, | |
| 318 | + { CCI_REG8(0x0e0a), 0x00 }, | |
| 319 | + { CCI_REG8(0x0e0b), 0x00 }, | |
| 320 | + { CCI_REG8(0x0e24), 0x04 }, | |
| 321 | + { CCI_REG8(0x0e25), 0x04 }, | |
| 322 | + { CCI_REG8(0x0e26), 0x00 }, | |
| 323 | + { CCI_REG8(0x0e27), 0x10 }, | |
| 324 | + { CCI_REG8(0x0e01), 0x74 }, | |
| 325 | + { CCI_REG8(0x0e03), 0x47 }, | |
| 326 | + { CCI_REG8(0x0e04), 0x33 }, | |
| 327 | + { CCI_REG8(0x0e05), 0x44 }, | |
| 328 | + { CCI_REG8(0x0e06), 0x44 }, | |
| 329 | + { CCI_REG8(0x0e0c), 0x1e }, | |
| 330 | + { CCI_REG8(0x0e17), 0x3a }, | |
| 331 | + { CCI_REG8(0x0e18), 0x3c }, | |
| 332 | + { CCI_REG8(0x0e19), 0x40 }, | |
| 333 | + { CCI_REG8(0x0e1a), 0x42 }, | |
| 334 | + { CCI_REG8(0x0e28), 0x21 }, | |
| 335 | + { CCI_REG8(0x0e2b), 0x68 }, | |
| 336 | + { CCI_REG8(0x0e2c), 0x0d }, | |
| 337 | + { CCI_REG8(0x0e2d), 0x08 }, | |
| 338 | + { CCI_REG8(0x0e34), 0xf4 }, | |
| 339 | + { CCI_REG8(0x0e35), 0x44 }, | |
| 340 | + { CCI_REG8(0x0e36), 0x07 }, | |
| 341 | + { CCI_REG8(0x0e38), 0x49 }, | |
| 342 | + { CCI_REG8(0x0210), 0x13 }, | |
| 343 | + { CCI_REG8(0x0218), 0x00 }, | |
| 344 | + { CCI_REG8(0x0241), 0x88 }, | |
| 345 | + { CCI_REG8(0x0e32), 0x00 }, | |
| 346 | + { CCI_REG8(0x0e33), 0x18 }, | |
| 347 | + { CCI_REG8(0x0e42), 0x03 }, | |
| 348 | + { CCI_REG8(0x0e43), 0x80 }, | |
| 349 | + { CCI_REG8(0x0e44), 0x04 }, | |
| 350 | + { CCI_REG8(0x0e45), 0x00 }, | |
| 351 | + { CCI_REG8(0x0e4f), 0x04 }, | |
| 352 | + { CCI_REG8(0x057a), 0x20 }, | |
| 353 | + { CCI_REG8(0x0381), 0x7c }, | |
| 354 | + { CCI_REG8(0x0382), 0x9b }, | |
| 355 | + { CCI_REG8(0x0384), 0xfb }, | |
| 356 | + { CCI_REG8(0x0389), 0x38 }, | |
| 357 | + { CCI_REG8(0x038a), 0x03 }, | |
| 358 | + { CCI_REG8(0x0390), 0x6a }, | |
| 359 | + { CCI_REG8(0x0391), 0x0b }, | |
| 360 | + { CCI_REG8(0x0392), 0x60 }, | |
| 361 | + { CCI_REG8(0x0393), 0xc1 }, | |
| 362 | + { CCI_REG8(0x0396), 0xff }, | |
| 363 | + { CCI_REG8(0x0398), 0x62 }, | |
| 364 | + | |
| 365 | + /* cisctl reset */ | |
| 366 | + { CCI_REG8(0x031c), 0x80 }, | |
| 367 | + { CCI_REG8(0x03fe), 0x10 }, | |
| 368 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 369 | + { CCI_REG8(0x031c), 0x9f }, | |
| 370 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 371 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 372 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 373 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 374 | + { CCI_REG8(0x031c), 0x80 }, | |
| 375 | + { CCI_REG8(0x03fe), 0x10 }, | |
| 376 | + { CCI_REG8(0x03fe), 0x00 }, | |
| 377 | + { CCI_REG8(0x031c), 0x9f }, | |
| 378 | + { CCI_REG8(0x0360), 0x01 }, | |
| 379 | + { CCI_REG8(0x0360), 0x00 }, | |
| 380 | + { CCI_REG8(0x0316), 0x09 }, | |
| 381 | + { CCI_REG8(0x0a67), 0x80 }, | |
| 382 | + { CCI_REG8(0x0313), 0x00 }, | |
| 383 | + { CCI_REG8(0x0a53), 0x0e }, | |
| 384 | + { CCI_REG8(0x0a65), 0x17 }, | |
| 385 | + { CCI_REG8(0x0a68), 0xa1 }, | |
| 386 | + { CCI_REG8(0x0a58), 0x00 }, | |
| 387 | + { CCI_REG8(0x0ace), 0x0c }, | |
| 388 | + { CCI_REG8(0x00a4), 0x00 }, | |
| 389 | + { CCI_REG8(0x00a5), 0x01 }, | |
| 390 | + { CCI_REG8(0x00a7), 0x09 }, | |
| 391 | + { CCI_REG8(0x00a8), 0x9c }, | |
| 392 | + { CCI_REG8(0x00a9), 0x0c }, | |
| 393 | + { CCI_REG8(0x00aa), 0xd0 }, | |
| 394 | + { CCI_REG8(0x0a8a), 0x00 }, | |
| 395 | + { CCI_REG8(0x0a8b), 0xe0 }, | |
| 396 | + { CCI_REG8(0x0a8c), 0x13 }, | |
| 397 | + { CCI_REG8(0x0a8d), 0xe8 }, | |
| 398 | + { CCI_REG8(0x0a90), 0x0a }, | |
| 399 | + { CCI_REG8(0x0a91), 0x10 }, | |
| 400 | + { CCI_REG8(0x0a92), 0xf8 }, | |
| 401 | + { CCI_REG8(0x0a71), 0xf2 }, | |
| 402 | + { CCI_REG8(0x0a72), 0x12 }, | |
| 403 | + { CCI_REG8(0x0a73), 0x64 }, | |
| 404 | + { CCI_REG8(0x0a75), 0x41 }, | |
| 405 | + { CCI_REG8(0x0a70), 0x07 }, | |
| 406 | + { CCI_REG8(0x0313), 0x80 }, | |
| 407 | + | |
| 408 | + /* ISP */ | |
| 409 | + { CCI_REG8(0x00a0), 0x01 }, | |
| 410 | + { CCI_REG8(0x0080), 0xd2 }, | |
| 411 | + { CCI_REG8(0x0081), 0x3f }, | |
| 412 | + { CCI_REG8(0x0087), 0x51 }, | |
| 413 | + { CCI_REG8(0x0089), 0x03 }, | |
| 414 | + { CCI_REG8(0x009b), 0x40 }, | |
| 415 | + { CCI_REG8(0x05a0), 0x82 }, | |
| 416 | + { CCI_REG8(0x05ac), 0x00 }, | |
| 417 | + { CCI_REG8(0x05ad), 0x01 }, | |
| 418 | + { CCI_REG8(0x05ae), 0x00 }, | |
| 419 | + { CCI_REG8(0x0800), 0x0a }, | |
| 420 | + { CCI_REG8(0x0801), 0x14 }, | |
| 421 | + { CCI_REG8(0x0802), 0x28 }, | |
| 422 | + { CCI_REG8(0x0803), 0x34 }, | |
| 423 | + { CCI_REG8(0x0804), 0x0e }, | |
| 424 | + { CCI_REG8(0x0805), 0x33 }, | |
| 425 | + { CCI_REG8(0x0806), 0x03 }, | |
| 426 | + { CCI_REG8(0x0807), 0x8a }, | |
| 427 | + { CCI_REG8(0x0808), 0x50 }, | |
| 428 | + { CCI_REG8(0x0809), 0x00 }, | |
| 429 | + { CCI_REG8(0x080a), 0x34 }, | |
| 430 | + { CCI_REG8(0x080b), 0x03 }, | |
| 431 | + { CCI_REG8(0x080c), 0x26 }, | |
| 432 | + { CCI_REG8(0x080d), 0x03 }, | |
| 433 | + { CCI_REG8(0x080e), 0x18 }, | |
| 434 | + { CCI_REG8(0x080f), 0x03 }, | |
| 435 | + { CCI_REG8(0x0810), 0x10 }, | |
| 436 | + { CCI_REG8(0x0811), 0x03 }, | |
| 437 | + { CCI_REG8(0x0812), 0x00 }, | |
| 438 | + { CCI_REG8(0x0813), 0x00 }, | |
| 439 | + { CCI_REG8(0x0814), 0x01 }, | |
| 440 | + { CCI_REG8(0x0815), 0x00 }, | |
| 441 | + { CCI_REG8(0x0816), 0x01 }, | |
| 442 | + { CCI_REG8(0x0817), 0x00 }, | |
| 443 | + { CCI_REG8(0x0818), 0x00 }, | |
| 444 | + { CCI_REG8(0x0819), 0x0a }, | |
| 445 | + { CCI_REG8(0x081a), 0x01 }, | |
| 446 | + { CCI_REG8(0x081b), 0x6c }, | |
| 447 | + { CCI_REG8(0x081c), 0x00 }, | |
| 448 | + { CCI_REG8(0x081d), 0x0b }, | |
| 449 | + { CCI_REG8(0x081e), 0x02 }, | |
| 450 | + { CCI_REG8(0x081f), 0x00 }, | |
| 451 | + { CCI_REG8(0x0820), 0x00 }, | |
| 452 | + { CCI_REG8(0x0821), 0x0c }, | |
| 453 | + { CCI_REG8(0x0822), 0x02 }, | |
| 454 | + { CCI_REG8(0x0823), 0xd9 }, | |
| 455 | + { CCI_REG8(0x0824), 0x00 }, | |
| 456 | + { CCI_REG8(0x0825), 0x0d }, | |
| 457 | + { CCI_REG8(0x0826), 0x03 }, | |
| 458 | + { CCI_REG8(0x0827), 0xf0 }, | |
| 459 | + { CCI_REG8(0x0828), 0x00 }, | |
| 460 | + { CCI_REG8(0x0829), 0x0e }, | |
| 461 | + { CCI_REG8(0x082a), 0x05 }, | |
| 462 | + { CCI_REG8(0x082b), 0x94 }, | |
| 463 | + { CCI_REG8(0x082c), 0x09 }, | |
| 464 | + { CCI_REG8(0x082d), 0x6e }, | |
| 465 | + { CCI_REG8(0x082e), 0x07 }, | |
| 466 | + { CCI_REG8(0x082f), 0xe6 }, | |
| 467 | + { CCI_REG8(0x0830), 0x10 }, | |
| 468 | + { CCI_REG8(0x0831), 0x0e }, | |
| 469 | + { CCI_REG8(0x0832), 0x0b }, | |
| 470 | + { CCI_REG8(0x0833), 0x2c }, | |
| 471 | + { CCI_REG8(0x0834), 0x14 }, | |
| 472 | + { CCI_REG8(0x0835), 0xae }, | |
| 473 | + { CCI_REG8(0x0836), 0x0f }, | |
| 474 | + { CCI_REG8(0x0837), 0xc4 }, | |
| 475 | + { CCI_REG8(0x0838), 0x18 }, | |
| 476 | + { CCI_REG8(0x0839), 0x0e }, | |
| 477 | + { CCI_REG8(0x05ac), 0x01 }, | |
| 478 | + { CCI_REG8(0x059a), 0x00 }, | |
| 479 | + { CCI_REG8(0x059b), 0x00 }, | |
| 480 | + { CCI_REG8(0x059c), 0x01 }, | |
| 481 | + { CCI_REG8(0x0598), 0x00 }, | |
| 482 | + { CCI_REG8(0x0597), 0x14 }, | |
| 483 | + { CCI_REG8(0x05ab), 0x09 }, | |
| 484 | + { CCI_REG8(0x05a4), 0x02 }, | |
| 485 | + { CCI_REG8(0x05a3), 0x05 }, | |
| 486 | + { CCI_REG8(0x05a0), 0xc2 }, | |
| 487 | + { CCI_REG8(0x0207), 0xc4 }, | |
| 488 | + | |
| 489 | + /* GAIN */ | |
| 490 | + { CCI_REG8(0x0208), 0x01 }, | |
| 491 | + { CCI_REG8(0x0209), 0x72 }, | |
| 492 | + { CCI_REG8(0x0204), 0x04 }, | |
| 493 | + { CCI_REG8(0x0205), 0x00 }, | |
| 494 | + | |
| 495 | + { CCI_REG8(0x0040), 0x22 }, | |
| 496 | + { CCI_REG8(0x0041), 0x20 }, | |
| 497 | + { CCI_REG8(0x0043), 0x10 }, | |
| 498 | + { CCI_REG8(0x0044), 0x00 }, | |
| 499 | + { CCI_REG8(0x0046), 0x08 }, | |
| 500 | + { CCI_REG8(0x0047), 0xf0 }, | |
| 501 | + { CCI_REG8(0x0048), 0x0f }, | |
| 502 | + { CCI_REG8(0x004b), 0x0f }, | |
| 503 | + { CCI_REG8(0x004c), 0x00 }, | |
| 504 | + { CCI_REG8(0x0050), 0x5c }, | |
| 505 | + { CCI_REG8(0x0051), 0x44 }, | |
| 506 | + { CCI_REG8(0x005b), 0x03 }, | |
| 507 | + { CCI_REG8(0x00c0), 0x00 }, | |
| 508 | + { CCI_REG8(0x00c1), 0x80 }, | |
| 509 | + { CCI_REG8(0x00c2), 0x31 }, | |
| 510 | + { CCI_REG8(0x00c3), 0x00 }, | |
| 511 | + { CCI_REG8(0x0460), 0x04 }, | |
| 512 | + { CCI_REG8(0x0462), 0x08 }, | |
| 513 | + { CCI_REG8(0x0464), 0x0e }, | |
| 514 | + { CCI_REG8(0x0466), 0x0a }, | |
| 515 | + { CCI_REG8(0x0468), 0x12 }, | |
| 516 | + { CCI_REG8(0x046a), 0x12 }, | |
| 517 | + { CCI_REG8(0x046c), 0x10 }, | |
| 518 | + { CCI_REG8(0x046e), 0x0c }, | |
| 519 | + { CCI_REG8(0x0461), 0x03 }, | |
| 520 | + { CCI_REG8(0x0463), 0x03 }, | |
| 521 | + { CCI_REG8(0x0465), 0x03 }, | |
| 522 | + { CCI_REG8(0x0467), 0x03 }, | |
| 523 | + { CCI_REG8(0x0469), 0x04 }, | |
| 524 | + { CCI_REG8(0x046b), 0x04 }, | |
| 525 | + { CCI_REG8(0x046d), 0x04 }, | |
| 526 | + { CCI_REG8(0x046f), 0x04 }, | |
| 527 | + { CCI_REG8(0x0470), 0x04 }, | |
| 528 | + { CCI_REG8(0x0472), 0x10 }, | |
| 529 | + { CCI_REG8(0x0474), 0x26 }, | |
| 530 | + { CCI_REG8(0x0476), 0x38 }, | |
| 531 | + { CCI_REG8(0x0478), 0x20 }, | |
| 532 | + { CCI_REG8(0x047a), 0x30 }, | |
| 533 | + { CCI_REG8(0x047c), 0x38 }, | |
| 534 | + { CCI_REG8(0x047e), 0x60 }, | |
| 535 | + { CCI_REG8(0x0471), 0x05 }, | |
| 536 | + { CCI_REG8(0x0473), 0x05 }, | |
| 537 | + { CCI_REG8(0x0475), 0x05 }, | |
| 538 | + { CCI_REG8(0x0477), 0x05 }, | |
| 539 | + { CCI_REG8(0x0479), 0x04 }, | |
| 540 | + { CCI_REG8(0x047b), 0x04 }, | |
| 541 | + { CCI_REG8(0x047d), 0x04 }, | |
| 542 | + { CCI_REG8(0x047f), 0x04 }, | |
| 543 | +}; | |
| 544 | + | |
| 545 | +struct gc08a3_mode { | |
| 546 | + u32 width; | |
| 547 | + u32 height; | |
| 548 | + const struct gc08a3_reg_list reg_list; | |
| 549 | + | |
| 550 | + u32 hts; /* Horizontal timining size */ | |
| 551 | + u32 vts_def; /* Default vertical timining size */ | |
| 552 | + u32 vts_min; /* Min vertical timining size */ | |
| 553 | +}; | |
| 554 | + | |
| 555 | +/* Declare modes in order, from biggest to smallest height. */ | |
| 556 | +static const struct gc08a3_mode gc08a3_modes[] = { | |
| 557 | + { | |
| 558 | + /* 3264*2448@30fps */ | |
| 559 | + .width = GC08A3_NATIVE_WIDTH, | |
| 560 | + .height = GC08A3_NATIVE_HEIGHT, | |
| 561 | + .reg_list = { | |
| 562 | + .num_of_regs = ARRAY_SIZE(mode_3264x2448), | |
| 563 | + .regs = mode_3264x2448, | |
| 564 | + }, | |
| 565 | + .hts = 3640, | |
| 566 | + .vts_def = 2548, | |
| 567 | + .vts_min = 2548, | |
| 568 | + }, | |
| 569 | + { | |
| 570 | + /* 1920*1080@60fps */ | |
| 571 | + .width = 1920, | |
| 572 | + .height = 1080, | |
| 573 | + .reg_list = { | |
| 574 | + .num_of_regs = ARRAY_SIZE(mode_1920x1080), | |
| 575 | + .regs = mode_1920x1080, | |
| 576 | + }, | |
| 577 | + .hts = 3640, | |
| 578 | + .vts_def = 1276, | |
| 579 | + .vts_min = 1276, | |
| 580 | + }, | |
| 581 | +}; | |
| 582 | + | |
| 583 | +static inline struct gc08a3 *to_gc08a3(struct v4l2_subdev *sd) | |
| 584 | +{ | |
| 585 | + return container_of(sd, struct gc08a3, sd); | |
| 586 | +} | |
| 587 | + | |
| 588 | +static int gc08a3_power_on(struct device *dev) | |
| 589 | +{ | |
| 590 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 591 | + struct gc08a3 *gc08a3 = to_gc08a3(sd); | |
| 592 | + int ret; | |
| 593 | + | |
| 594 | + ret = regulator_bulk_enable(ARRAY_SIZE(gc08a3_supply_name), | |
| 595 | + gc08a3->supplies); | |
| 596 | + if (ret < 0) { | |
| 597 | + dev_err(gc08a3->dev, "failed to enable regulators: %d\n", ret); | |
| 598 | + return ret; | |
| 599 | + } | |
| 600 | + | |
| 601 | + ret = clk_prepare_enable(gc08a3->xclk); | |
| 602 | + if (ret < 0) { | |
| 603 | + regulator_bulk_disable(ARRAY_SIZE(gc08a3_supply_name), | |
| 604 | + gc08a3->supplies); | |
| 605 | + dev_err(gc08a3->dev, "clk prepare enable failed\n"); | |
| 606 | + return ret; | |
| 607 | + } | |
| 608 | + | |
| 609 | + fsleep(GC08A3_SLEEP_US); | |
| 610 | + | |
| 611 | + gpiod_set_value_cansleep(gc08a3->reset_gpio, 0); | |
| 612 | + fsleep(GC08A3_SLEEP_US); | |
| 613 | + | |
| 614 | + return 0; | |
| 615 | +} | |
| 616 | + | |
| 617 | +static int gc08a3_power_off(struct device *dev) | |
| 618 | +{ | |
| 619 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 620 | + struct gc08a3 *gc08a3 = to_gc08a3(sd); | |
| 621 | + | |
| 622 | + clk_disable_unprepare(gc08a3->xclk); | |
| 623 | + gpiod_set_value_cansleep(gc08a3->reset_gpio, 1); | |
| 624 | + regulator_bulk_disable(ARRAY_SIZE(gc08a3_supply_name), | |
| 625 | + gc08a3->supplies); | |
| 626 | + | |
| 627 | + return 0; | |
| 628 | +} | |
| 629 | + | |
| 630 | +static int gc08a3_enum_mbus_code(struct v4l2_subdev *sd, | |
| 631 | + struct v4l2_subdev_state *sd_state, | |
| 632 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 633 | +{ | |
| 634 | + if (code->index > 0) | |
| 635 | + return -EINVAL; | |
| 636 | + | |
| 637 | + code->code = GC08A3_MBUS_CODE; | |
| 638 | + | |
| 639 | + return 0; | |
| 640 | +} | |
| 641 | + | |
| 642 | +static int gc08a3_enum_frame_size(struct v4l2_subdev *subdev, | |
| 643 | + struct v4l2_subdev_state *sd_state, | |
| 644 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 645 | +{ | |
| 646 | + if (fse->code != GC08A3_MBUS_CODE) | |
| 647 | + return -EINVAL; | |
| 648 | + | |
| 649 | + if (fse->index >= ARRAY_SIZE(gc08a3_modes)) | |
| 650 | + return -EINVAL; | |
| 651 | + | |
| 652 | + fse->min_width = gc08a3_modes[fse->index].width; | |
| 653 | + fse->max_width = gc08a3_modes[fse->index].width; | |
| 654 | + fse->min_height = gc08a3_modes[fse->index].height; | |
| 655 | + fse->max_height = gc08a3_modes[fse->index].height; | |
| 656 | + | |
| 657 | + return 0; | |
| 658 | +} | |
| 659 | + | |
| 660 | +static int gc08a3_update_cur_mode_controls(struct gc08a3 *gc08a3, | |
| 661 | + const struct gc08a3_mode *mode) | |
| 662 | +{ | |
| 663 | + s64 exposure_max, h_blank; | |
| 664 | + int ret; | |
| 665 | + | |
| 666 | + ret = __v4l2_ctrl_modify_range(gc08a3->vblank, | |
| 667 | + mode->vts_min - mode->height, | |
| 668 | + GC08A3_VTS_MAX - mode->height, 1, | |
| 669 | + mode->vts_def - mode->height); | |
| 670 | + if (ret) { | |
| 671 | + dev_err(gc08a3->dev, "VB ctrl range update failed\n"); | |
| 672 | + return ret; | |
| 673 | + } | |
| 674 | + | |
| 675 | + h_blank = mode->hts - mode->width; | |
| 676 | + ret = __v4l2_ctrl_modify_range(gc08a3->hblank, h_blank, h_blank, 1, | |
| 677 | + h_blank); | |
| 678 | + if (ret) { | |
| 679 | + dev_err(gc08a3->dev, "HB ctrl range update failed\n"); | |
| 680 | + return ret; | |
| 681 | + } | |
| 682 | + | |
| 683 | + exposure_max = mode->vts_def - GC08A3_EXP_MARGIN; | |
| 684 | + ret = __v4l2_ctrl_modify_range(gc08a3->exposure, GC08A3_EXP_MIN, | |
| 685 | + exposure_max, GC08A3_EXP_STEP, | |
| 686 | + exposure_max); | |
| 687 | + if (ret) { | |
| 688 | + dev_err(gc08a3->dev, "exposure ctrl range update failed\n"); | |
| 689 | + return ret; | |
| 690 | + } | |
| 691 | + | |
| 692 | + return 0; | |
| 693 | +} | |
| 694 | + | |
| 695 | +static void gc08a3_update_pad_format(struct gc08a3 *gc08a3, | |
| 696 | + const struct gc08a3_mode *mode, | |
| 697 | + struct v4l2_mbus_framefmt *fmt) | |
| 698 | +{ | |
| 699 | + fmt->width = mode->width; | |
| 700 | + fmt->height = mode->height; | |
| 701 | + fmt->code = GC08A3_MBUS_CODE; | |
| 702 | + fmt->field = V4L2_FIELD_NONE; | |
| 703 | + fmt->colorspace = V4L2_COLORSPACE_RAW; | |
| 704 | + fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace); | |
| 705 | + fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE; | |
| 706 | + fmt->xfer_func = V4L2_XFER_FUNC_NONE; | |
| 707 | +} | |
| 708 | + | |
| 709 | +static int gc08a3_set_format(struct v4l2_subdev *sd, | |
| 710 | + struct v4l2_subdev_state *state, | |
| 711 | + struct v4l2_subdev_format *fmt) | |
| 712 | +{ | |
| 713 | + struct gc08a3 *gc08a3 = to_gc08a3(sd); | |
| 714 | + struct v4l2_mbus_framefmt *mbus_fmt; | |
| 715 | + struct v4l2_rect *crop; | |
| 716 | + const struct gc08a3_mode *mode; | |
| 717 | + | |
| 718 | + mode = v4l2_find_nearest_size(gc08a3_modes, ARRAY_SIZE(gc08a3_modes), | |
| 719 | + width, height, fmt->format.width, | |
| 720 | + fmt->format.height); | |
| 721 | + | |
| 722 | + /* update crop info to subdev state */ | |
| 723 | + crop = v4l2_subdev_state_get_crop(state, 0); | |
| 724 | + crop->width = mode->width; | |
| 725 | + crop->height = mode->height; | |
| 726 | + | |
| 727 | + /* update fmt info to subdev state */ | |
| 728 | + gc08a3_update_pad_format(gc08a3, mode, &fmt->format); | |
| 729 | + mbus_fmt = v4l2_subdev_state_get_format(state, 0); | |
| 730 | + *mbus_fmt = fmt->format; | |
| 731 | + | |
| 732 | + if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) | |
| 733 | + return 0; | |
| 734 | + | |
| 735 | + gc08a3->cur_mode = mode; | |
| 736 | + gc08a3_update_cur_mode_controls(gc08a3, mode); | |
| 737 | + | |
| 738 | + return 0; | |
| 739 | +} | |
| 740 | + | |
| 741 | +static int gc08a3_get_selection(struct v4l2_subdev *sd, | |
| 742 | + struct v4l2_subdev_state *state, | |
| 743 | + struct v4l2_subdev_selection *sel) | |
| 744 | +{ | |
| 745 | + switch (sel->target) { | |
| 746 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 747 | + case V4L2_SEL_TGT_CROP: | |
| 748 | + sel->r = *v4l2_subdev_state_get_crop(state, 0); | |
| 749 | + break; | |
| 750 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 751 | + sel->r.top = 0; | |
| 752 | + sel->r.left = 0; | |
| 753 | + sel->r.width = GC08A3_NATIVE_WIDTH; | |
| 754 | + sel->r.height = GC08A3_NATIVE_HEIGHT; | |
| 755 | + break; | |
| 756 | + default: | |
| 757 | + return -EINVAL; | |
| 758 | + } | |
| 759 | + | |
| 760 | + return 0; | |
| 761 | +} | |
| 762 | + | |
| 763 | +static int gc08a3_init_state(struct v4l2_subdev *sd, | |
| 764 | + struct v4l2_subdev_state *state) | |
| 765 | +{ | |
| 766 | + struct v4l2_subdev_format fmt = { | |
| 767 | + .which = V4L2_SUBDEV_FORMAT_TRY, | |
| 768 | + .pad = 0, | |
| 769 | + .format = { | |
| 770 | + .code = GC08A3_MBUS_CODE, | |
| 771 | + .width = gc08a3_modes[0].width, | |
| 772 | + .height = gc08a3_modes[0].height, | |
| 773 | + }, | |
| 774 | + }; | |
| 775 | + | |
| 776 | + gc08a3_set_format(sd, state, &fmt); | |
| 777 | + | |
| 778 | + return 0; | |
| 779 | +} | |
| 780 | + | |
| 781 | +static int gc08a3_set_ctrl_hflip(struct gc08a3 *gc08a3, u32 ctrl_val) | |
| 782 | +{ | |
| 783 | + int ret; | |
| 784 | + u64 val; | |
| 785 | + | |
| 786 | + ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL); | |
| 787 | + if (ret) { | |
| 788 | + dev_err(gc08a3->dev, "read hflip register failed: %d\n", ret); | |
| 789 | + return ret; | |
| 790 | + } | |
| 791 | + | |
| 792 | + return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG, | |
| 793 | + GC08A3_FLIP_H_MASK, | |
| 794 | + ctrl_val ? GC08A3_FLIP_H_MASK : 0, NULL); | |
| 795 | +} | |
| 796 | + | |
| 797 | +static int gc08a3_set_ctrl_vflip(struct gc08a3 *gc08a3, u32 ctrl_val) | |
| 798 | +{ | |
| 799 | + int ret; | |
| 800 | + u64 val; | |
| 801 | + | |
| 802 | + ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL); | |
| 803 | + if (ret) { | |
| 804 | + dev_err(gc08a3->dev, "read vflip register failed: %d\n", ret); | |
| 805 | + return ret; | |
| 806 | + } | |
| 807 | + | |
| 808 | + return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG, | |
| 809 | + GC08A3_FLIP_V_MASK, | |
| 810 | + ctrl_val ? GC08A3_FLIP_V_MASK : 0, NULL); | |
| 811 | +} | |
| 812 | + | |
| 813 | +static int gc08a3_test_pattern(struct gc08a3 *gc08a3, u32 pattern_menu) | |
| 814 | +{ | |
| 815 | + u32 pattern; | |
| 816 | + int ret; | |
| 817 | + | |
| 818 | + if (pattern_menu) { | |
| 819 | + switch (pattern_menu) { | |
| 820 | + case 1: | |
| 821 | + pattern = 0x00; | |
| 822 | + break; | |
| 823 | + case 2: | |
| 824 | + pattern = 0x10; | |
| 825 | + break; | |
| 826 | + case 3: | |
| 827 | + case 4: | |
| 828 | + case 5: | |
| 829 | + case 6: | |
| 830 | + case 7: | |
| 831 | + pattern = pattern_menu + 1; | |
| 832 | + break; | |
| 833 | + default: | |
| 834 | + pattern = 0x00; | |
| 835 | + break; | |
| 836 | + } | |
| 837 | + | |
| 838 | + ret = cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_IDX, | |
| 839 | + pattern, NULL); | |
| 840 | + if (ret) | |
| 841 | + return ret; | |
| 842 | + | |
| 843 | + return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN, | |
| 844 | + GC08A3_TEST_PATTERN_EN, NULL); | |
| 845 | + } else { | |
| 846 | + return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN, | |
| 847 | + 0x00, NULL); | |
| 848 | + } | |
| 849 | +} | |
| 850 | + | |
| 851 | +static int gc08a3_set_ctrl(struct v4l2_ctrl *ctrl) | |
| 852 | +{ | |
| 853 | + struct gc08a3 *gc08a3 = | |
| 854 | + container_of(ctrl->handler, struct gc08a3, ctrls); | |
| 855 | + int ret = 0; | |
| 856 | + s64 exposure_max; | |
| 857 | + struct v4l2_subdev_state *state; | |
| 858 | + const struct v4l2_mbus_framefmt *format; | |
| 859 | + | |
| 860 | + state = v4l2_subdev_get_locked_active_state(&gc08a3->sd); | |
| 861 | + format = v4l2_subdev_state_get_format(state, 0); | |
| 862 | + | |
| 863 | + if (ctrl->id == V4L2_CID_VBLANK) { | |
| 864 | + /* Update max exposure while meeting expected vblanking */ | |
| 865 | + exposure_max = format->height + ctrl->val - GC08A3_EXP_MARGIN; | |
| 866 | + __v4l2_ctrl_modify_range(gc08a3->exposure, | |
| 867 | + gc08a3->exposure->minimum, | |
| 868 | + exposure_max, gc08a3->exposure->step, | |
| 869 | + exposure_max); | |
| 870 | + } | |
| 871 | + | |
| 872 | + /* | |
| 873 | + * Applying V4L2 control value only happens | |
| 874 | + * when power is on for streaming. | |
| 875 | + */ | |
| 876 | + if (!pm_runtime_get_if_active(gc08a3->dev)) | |
| 877 | + return 0; | |
| 878 | + | |
| 879 | + switch (ctrl->id) { | |
| 880 | + case V4L2_CID_EXPOSURE: | |
| 881 | + ret = cci_write(gc08a3->regmap, GC08A3_EXP_REG, | |
| 882 | + ctrl->val, NULL); | |
| 883 | + break; | |
| 884 | + | |
| 885 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 886 | + ret = cci_write(gc08a3->regmap, GC08A3_AGAIN_REG, | |
| 887 | + ctrl->val, NULL); | |
| 888 | + break; | |
| 889 | + | |
| 890 | + case V4L2_CID_VBLANK: | |
| 891 | + ret = cci_write(gc08a3->regmap, GC08A3_FRAME_LENGTH_REG, | |
| 892 | + gc08a3->cur_mode->height + ctrl->val, NULL); | |
| 893 | + break; | |
| 894 | + | |
| 895 | + case V4L2_CID_HFLIP: | |
| 896 | + ret = gc08a3_set_ctrl_hflip(gc08a3, ctrl->val); | |
| 897 | + break; | |
| 898 | + | |
| 899 | + case V4L2_CID_VFLIP: | |
| 900 | + ret = gc08a3_set_ctrl_vflip(gc08a3, ctrl->val); | |
| 901 | + break; | |
| 902 | + | |
| 903 | + case V4L2_CID_TEST_PATTERN: | |
| 904 | + ret = gc08a3_test_pattern(gc08a3, ctrl->val); | |
| 905 | + break; | |
| 906 | + | |
| 907 | + default: | |
| 908 | + break; | |
| 909 | + } | |
| 910 | + | |
| 911 | + pm_runtime_put(gc08a3->dev); | |
| 912 | + | |
| 913 | + return ret; | |
| 914 | +} | |
| 915 | + | |
| 916 | +static const struct v4l2_ctrl_ops gc08a3_ctrl_ops = { | |
| 917 | + .s_ctrl = gc08a3_set_ctrl, | |
| 918 | +}; | |
| 919 | + | |
| 920 | +static int gc08a3_start_streaming(struct gc08a3 *gc08a3) | |
| 921 | +{ | |
| 922 | + const struct gc08a3_mode *mode; | |
| 923 | + const struct gc08a3_reg_list *reg_list; | |
| 924 | + int ret; | |
| 925 | + | |
| 926 | + ret = pm_runtime_resume_and_get(gc08a3->dev); | |
| 927 | + if (ret < 0) | |
| 928 | + return ret; | |
| 929 | + | |
| 930 | + ret = cci_multi_reg_write(gc08a3->regmap, | |
| 931 | + mode_table_common, | |
| 932 | + ARRAY_SIZE(mode_table_common), NULL); | |
| 933 | + if (ret) | |
| 934 | + goto err_rpm_put; | |
| 935 | + | |
| 936 | + mode = gc08a3->cur_mode; | |
| 937 | + reg_list = &mode->reg_list; | |
| 938 | + ret = cci_multi_reg_write(gc08a3->regmap, | |
| 939 | + reg_list->regs, reg_list->num_of_regs, NULL); | |
| 940 | + if (ret < 0) | |
| 941 | + goto err_rpm_put; | |
| 942 | + | |
| 943 | + ret = __v4l2_ctrl_handler_setup(&gc08a3->ctrls); | |
| 944 | + if (ret < 0) { | |
| 945 | + dev_err(gc08a3->dev, "could not sync v4l2 controls\n"); | |
| 946 | + goto err_rpm_put; | |
| 947 | + } | |
| 948 | + | |
| 949 | + ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 1, NULL); | |
| 950 | + if (ret < 0) { | |
| 951 | + dev_err(gc08a3->dev, "write STRAEMING_REG failed: %d\n", ret); | |
| 952 | + goto err_rpm_put; | |
| 953 | + } | |
| 954 | + | |
| 955 | + return 0; | |
| 956 | + | |
| 957 | +err_rpm_put: | |
| 958 | + pm_runtime_put(gc08a3->dev); | |
| 959 | + return ret; | |
| 960 | +} | |
| 961 | + | |
| 962 | +static int gc08a3_stop_streaming(struct gc08a3 *gc08a3) | |
| 963 | +{ | |
| 964 | + int ret; | |
| 965 | + | |
| 966 | + ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 0, NULL); | |
| 967 | + if (ret < 0) | |
| 968 | + dev_err(gc08a3->dev, "could not sent stop streaming %d\n", ret); | |
| 969 | + | |
| 970 | + pm_runtime_put(gc08a3->dev); | |
| 971 | + return ret; | |
| 972 | +} | |
| 973 | + | |
| 974 | +static int gc08a3_s_stream(struct v4l2_subdev *subdev, int enable) | |
| 975 | +{ | |
| 976 | + struct gc08a3 *gc08a3 = to_gc08a3(subdev); | |
| 977 | + struct v4l2_subdev_state *state; | |
| 978 | + int ret; | |
| 979 | + | |
| 980 | + state = v4l2_subdev_lock_and_get_active_state(subdev); | |
| 981 | + | |
| 982 | + if (enable) | |
| 983 | + ret = gc08a3_start_streaming(gc08a3); | |
| 984 | + else | |
| 985 | + ret = gc08a3_stop_streaming(gc08a3); | |
| 986 | + | |
| 987 | + v4l2_subdev_unlock_state(state); | |
| 988 | + | |
| 989 | + return ret; | |
| 990 | +} | |
| 991 | + | |
| 992 | +static const struct v4l2_subdev_video_ops gc08a3_video_ops = { | |
| 993 | + .s_stream = gc08a3_s_stream, | |
| 994 | +}; | |
| 995 | + | |
| 996 | +static const struct v4l2_subdev_pad_ops gc08a3_subdev_pad_ops = { | |
| 997 | + .enum_mbus_code = gc08a3_enum_mbus_code, | |
| 998 | + .enum_frame_size = gc08a3_enum_frame_size, | |
| 999 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 1000 | + .set_fmt = gc08a3_set_format, | |
| 1001 | + .get_selection = gc08a3_get_selection, | |
| 1002 | +}; | |
| 1003 | + | |
| 1004 | +static const struct v4l2_subdev_core_ops gc08a3_core_ops = { | |
| 1005 | + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | |
| 1006 | + .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
| 1007 | +}; | |
| 1008 | + | |
| 1009 | +static const struct v4l2_subdev_ops gc08a3_subdev_ops = { | |
| 1010 | + .core = &gc08a3_core_ops, | |
| 1011 | + .video = &gc08a3_video_ops, | |
| 1012 | + .pad = &gc08a3_subdev_pad_ops, | |
| 1013 | +}; | |
| 1014 | + | |
| 1015 | +static const struct v4l2_subdev_internal_ops gc08a3_internal_ops = { | |
| 1016 | + .init_state = gc08a3_init_state, | |
| 1017 | +}; | |
| 1018 | + | |
| 1019 | +static int gc08a3_get_regulators(struct device *dev, struct gc08a3 *gc08a3) | |
| 1020 | +{ | |
| 1021 | + unsigned int i; | |
| 1022 | + | |
| 1023 | + for (i = 0; i < ARRAY_SIZE(gc08a3_supply_name); i++) | |
| 1024 | + gc08a3->supplies[i].supply = gc08a3_supply_name[i]; | |
| 1025 | + | |
| 1026 | + return devm_regulator_bulk_get(dev, ARRAY_SIZE(gc08a3_supply_name), | |
| 1027 | + gc08a3->supplies); | |
| 1028 | +} | |
| 1029 | + | |
| 1030 | +static int gc08a3_parse_fwnode(struct gc08a3 *gc08a3) | |
| 1031 | +{ | |
| 1032 | + struct fwnode_handle *endpoint; | |
| 1033 | + struct v4l2_fwnode_endpoint bus_cfg = { | |
| 1034 | + .bus_type = V4L2_MBUS_CSI2_DPHY, | |
| 1035 | + }; | |
| 1036 | + int ret; | |
| 1037 | + struct device *dev = gc08a3->dev; | |
| 1038 | + | |
| 1039 | + endpoint = | |
| 1040 | + fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0, | |
| 1041 | + FWNODE_GRAPH_ENDPOINT_NEXT); | |
| 1042 | + if (!endpoint) { | |
| 1043 | + dev_err(dev, "endpoint node not found\n"); | |
| 1044 | + return -EINVAL; | |
| 1045 | + } | |
| 1046 | + | |
| 1047 | + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg); | |
| 1048 | + if (ret) { | |
| 1049 | + dev_err(dev, "parsing endpoint node failed\n"); | |
| 1050 | + goto done; | |
| 1051 | + } | |
| 1052 | + | |
| 1053 | + ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies, | |
| 1054 | + bus_cfg.nr_of_link_frequencies, | |
| 1055 | + gc08a3_link_freq_menu_items, | |
| 1056 | + ARRAY_SIZE(gc08a3_link_freq_menu_items), | |
| 1057 | + &gc08a3->link_freq_bitmap); | |
| 1058 | + if (ret) | |
| 1059 | + goto done; | |
| 1060 | + | |
| 1061 | +done: | |
| 1062 | + v4l2_fwnode_endpoint_free(&bus_cfg); | |
| 1063 | + fwnode_handle_put(endpoint); | |
| 1064 | + return ret; | |
| 1065 | +} | |
| 1066 | + | |
| 1067 | +static u64 gc08a3_to_pixel_rate(u32 f_index) | |
| 1068 | +{ | |
| 1069 | + u64 pixel_rate = | |
| 1070 | + gc08a3_link_freq_menu_items[f_index] * 2 * GC08A3_DATA_LANES; | |
| 1071 | + | |
| 1072 | + return div_u64(pixel_rate, GC08A3_RGB_DEPTH); | |
| 1073 | +} | |
| 1074 | + | |
| 1075 | +static int gc08a3_init_controls(struct gc08a3 *gc08a3) | |
| 1076 | +{ | |
| 1077 | + struct i2c_client *client = v4l2_get_subdevdata(&gc08a3->sd); | |
| 1078 | + const struct gc08a3_mode *mode = &gc08a3_modes[0]; | |
| 1079 | + const struct v4l2_ctrl_ops *ops = &gc08a3_ctrl_ops; | |
| 1080 | + struct v4l2_fwnode_device_properties props; | |
| 1081 | + struct v4l2_ctrl_handler *ctrl_hdlr; | |
| 1082 | + s64 exposure_max, h_blank; | |
| 1083 | + int ret; | |
| 1084 | + | |
| 1085 | + ctrl_hdlr = &gc08a3->ctrls; | |
| 1086 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9); | |
| 1087 | + if (ret) | |
| 1088 | + return ret; | |
| 1089 | + | |
| 1090 | + gc08a3->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops, | |
| 1091 | + V4L2_CID_HFLIP, 0, 1, 1, 0); | |
| 1092 | + gc08a3->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops, | |
| 1093 | + V4L2_CID_VFLIP, 0, 1, 1, 0); | |
| 1094 | + v4l2_ctrl_cluster(2, &gc08a3->hflip); | |
| 1095 | + | |
| 1096 | + gc08a3->link_freq = | |
| 1097 | + v4l2_ctrl_new_int_menu(ctrl_hdlr, | |
| 1098 | + &gc08a3_ctrl_ops, | |
| 1099 | + V4L2_CID_LINK_FREQ, | |
| 1100 | + ARRAY_SIZE(gc08a3_link_freq_menu_items) - 1, | |
| 1101 | + 0, | |
| 1102 | + gc08a3_link_freq_menu_items); | |
| 1103 | + if (gc08a3->link_freq) | |
| 1104 | + gc08a3->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1105 | + | |
| 1106 | + gc08a3->pixel_rate = | |
| 1107 | + v4l2_ctrl_new_std(ctrl_hdlr, | |
| 1108 | + &gc08a3_ctrl_ops, | |
| 1109 | + V4L2_CID_PIXEL_RATE, 0, | |
| 1110 | + gc08a3_to_pixel_rate(0), | |
| 1111 | + 1, | |
| 1112 | + gc08a3_to_pixel_rate(0)); | |
| 1113 | + | |
| 1114 | + gc08a3->vblank = | |
| 1115 | + v4l2_ctrl_new_std(ctrl_hdlr, | |
| 1116 | + &gc08a3_ctrl_ops, V4L2_CID_VBLANK, | |
| 1117 | + mode->vts_min - mode->height, | |
| 1118 | + GC08A3_VTS_MAX - mode->height, 1, | |
| 1119 | + mode->vts_def - mode->height); | |
| 1120 | + | |
| 1121 | + h_blank = mode->hts - mode->width; | |
| 1122 | + gc08a3->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops, | |
| 1123 | + V4L2_CID_HBLANK, h_blank, h_blank, 1, | |
| 1124 | + h_blank); | |
| 1125 | + if (gc08a3->hblank) | |
| 1126 | + gc08a3->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1127 | + | |
| 1128 | + v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops, | |
| 1129 | + V4L2_CID_ANALOGUE_GAIN, GC08A3_AGAIN_MIN, | |
| 1130 | + GC08A3_AGAIN_MAX, GC08A3_AGAIN_STEP, | |
| 1131 | + GC08A3_AGAIN_MIN); | |
| 1132 | + | |
| 1133 | + exposure_max = mode->vts_def - GC08A3_EXP_MARGIN; | |
| 1134 | + gc08a3->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops, | |
| 1135 | + V4L2_CID_EXPOSURE, GC08A3_EXP_MIN, | |
| 1136 | + exposure_max, GC08A3_EXP_STEP, | |
| 1137 | + exposure_max); | |
| 1138 | + | |
| 1139 | + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &gc08a3_ctrl_ops, | |
| 1140 | + V4L2_CID_TEST_PATTERN, | |
| 1141 | + ARRAY_SIZE(gc08a3_test_pattern_menu) - 1, | |
| 1142 | + 0, 0, gc08a3_test_pattern_menu); | |
| 1143 | + | |
| 1144 | + /* register properties to fwnode (e.g. rotation, orientation) */ | |
| 1145 | + ret = v4l2_fwnode_device_parse(&client->dev, &props); | |
| 1146 | + if (ret) | |
| 1147 | + goto error_ctrls; | |
| 1148 | + | |
| 1149 | + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ops, &props); | |
| 1150 | + if (ret) | |
| 1151 | + goto error_ctrls; | |
| 1152 | + | |
| 1153 | + if (ctrl_hdlr->error) { | |
| 1154 | + ret = ctrl_hdlr->error; | |
| 1155 | + goto error_ctrls; | |
| 1156 | + } | |
| 1157 | + | |
| 1158 | + gc08a3->sd.ctrl_handler = ctrl_hdlr; | |
| 1159 | + | |
| 1160 | + return 0; | |
| 1161 | + | |
| 1162 | +error_ctrls: | |
| 1163 | + v4l2_ctrl_handler_free(ctrl_hdlr); | |
| 1164 | + | |
| 1165 | + return ret; | |
| 1166 | +} | |
| 1167 | + | |
| 1168 | +static int gc08a3_identify_module(struct gc08a3 *gc08a3) | |
| 1169 | +{ | |
| 1170 | + u64 val; | |
| 1171 | + int ret; | |
| 1172 | + | |
| 1173 | + ret = cci_read(gc08a3->regmap, GC08A3_REG_CHIP_ID, &val, NULL); | |
| 1174 | + if (ret) { | |
| 1175 | + dev_err(gc08a3->dev, "failed to read chip id"); | |
| 1176 | + return ret; | |
| 1177 | + } | |
| 1178 | + | |
| 1179 | + if (val != GC08A3_CHIP_ID) { | |
| 1180 | + dev_err(gc08a3->dev, "chip id mismatch: 0x%x!=0x%llx", | |
| 1181 | + GC08A3_CHIP_ID, val); | |
| 1182 | + return -ENXIO; | |
| 1183 | + } | |
| 1184 | + | |
| 1185 | + return 0; | |
| 1186 | +} | |
| 1187 | + | |
| 1188 | +static int gc08a3_probe(struct i2c_client *client) | |
| 1189 | +{ | |
| 1190 | + struct device *dev = &client->dev; | |
| 1191 | + struct gc08a3 *gc08a3; | |
| 1192 | + int ret; | |
| 1193 | + | |
| 1194 | + gc08a3 = devm_kzalloc(dev, sizeof(*gc08a3), GFP_KERNEL); | |
| 1195 | + if (!gc08a3) | |
| 1196 | + return -ENOMEM; | |
| 1197 | + | |
| 1198 | + gc08a3->dev = dev; | |
| 1199 | + | |
| 1200 | + ret = gc08a3_parse_fwnode(gc08a3); | |
| 1201 | + if (ret) | |
| 1202 | + return ret; | |
| 1203 | + | |
| 1204 | + gc08a3->regmap = devm_cci_regmap_init_i2c(client, 16); | |
| 1205 | + if (IS_ERR(gc08a3->regmap)) | |
| 1206 | + return dev_err_probe(dev, PTR_ERR(gc08a3->regmap), | |
| 1207 | + "failed to init CCI\n"); | |
| 1208 | + | |
| 1209 | + gc08a3->xclk = devm_clk_get(dev, NULL); | |
| 1210 | + if (IS_ERR(gc08a3->xclk)) | |
| 1211 | + return dev_err_probe(dev, PTR_ERR(gc08a3->xclk), | |
| 1212 | + "failed to get xclk\n"); | |
| 1213 | + | |
| 1214 | + ret = clk_set_rate(gc08a3->xclk, GC08A3_DEFAULT_CLK_FREQ); | |
| 1215 | + if (ret) | |
| 1216 | + return dev_err_probe(dev, ret, | |
| 1217 | + "failed to set xclk frequency\n"); | |
| 1218 | + | |
| 1219 | + ret = gc08a3_get_regulators(dev, gc08a3); | |
| 1220 | + if (ret < 0) | |
| 1221 | + return dev_err_probe(dev, ret, | |
| 1222 | + "failed to get regulators\n"); | |
| 1223 | + | |
| 1224 | + gc08a3->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW); | |
| 1225 | + if (IS_ERR(gc08a3->reset_gpio)) | |
| 1226 | + return dev_err_probe(dev, PTR_ERR(gc08a3->reset_gpio), | |
| 1227 | + "failed to get gpio\n"); | |
| 1228 | + | |
| 1229 | + v4l2_i2c_subdev_init(&gc08a3->sd, client, &gc08a3_subdev_ops); | |
| 1230 | + gc08a3->sd.internal_ops = &gc08a3_internal_ops; | |
| 1231 | + gc08a3->cur_mode = &gc08a3_modes[0]; | |
| 1232 | + | |
| 1233 | + ret = gc08a3_power_on(gc08a3->dev); | |
| 1234 | + if (ret) | |
| 1235 | + return dev_err_probe(dev, ret, | |
| 1236 | + "failed to sensor power on\n"); | |
| 1237 | + | |
| 1238 | + ret = gc08a3_identify_module(gc08a3); | |
| 1239 | + if (ret) { | |
| 1240 | + dev_err(&client->dev, "failed to find sensor: %d\n", ret); | |
| 1241 | + goto err_power_off; | |
| 1242 | + } | |
| 1243 | + | |
| 1244 | + ret = gc08a3_init_controls(gc08a3); | |
| 1245 | + if (ret) { | |
| 1246 | + dev_err(&client->dev, "failed to init controls: %d", ret); | |
| 1247 | + goto err_power_off; | |
| 1248 | + } | |
| 1249 | + | |
| 1250 | + gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | |
| 1251 | + V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 1252 | + gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1253 | + gc08a3->sd.dev = &client->dev; | |
| 1254 | + gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1255 | + | |
| 1256 | + ret = media_entity_pads_init(&gc08a3->sd.entity, 1, &gc08a3->pad); | |
| 1257 | + if (ret < 0) { | |
| 1258 | + dev_err(dev, "could not register media entity\n"); | |
| 1259 | + goto err_v4l2_ctrl_handler_free; | |
| 1260 | + } | |
| 1261 | + | |
| 1262 | + gc08a3->sd.state_lock = gc08a3->ctrls.lock; | |
| 1263 | + ret = v4l2_subdev_init_finalize(&gc08a3->sd); | |
| 1264 | + if (ret < 0) { | |
| 1265 | + dev_err(dev, "v4l2 subdev init error: %d\n", ret); | |
| 1266 | + goto err_media_entity_cleanup; | |
| 1267 | + } | |
| 1268 | + | |
| 1269 | + pm_runtime_set_active(gc08a3->dev); | |
| 1270 | + pm_runtime_enable(gc08a3->dev); | |
| 1271 | + pm_runtime_set_autosuspend_delay(gc08a3->dev, 1000); | |
| 1272 | + pm_runtime_use_autosuspend(gc08a3->dev); | |
| 1273 | + pm_runtime_idle(gc08a3->dev); | |
| 1274 | + | |
| 1275 | + ret = v4l2_async_register_subdev_sensor(&gc08a3->sd); | |
| 1276 | + if (ret < 0) { | |
| 1277 | + dev_err(dev, "could not register v4l2 device\n"); | |
| 1278 | + goto err_rpm; | |
| 1279 | + } | |
| 1280 | + | |
| 1281 | + return 0; | |
| 1282 | + | |
| 1283 | +err_rpm: | |
| 1284 | + pm_runtime_disable(gc08a3->dev); | |
| 1285 | + v4l2_subdev_cleanup(&gc08a3->sd); | |
| 1286 | + | |
| 1287 | +err_media_entity_cleanup: | |
| 1288 | + media_entity_cleanup(&gc08a3->sd.entity); | |
| 1289 | + | |
| 1290 | +err_v4l2_ctrl_handler_free: | |
| 1291 | + v4l2_ctrl_handler_free(gc08a3->sd.ctrl_handler); | |
| 1292 | + | |
| 1293 | +err_power_off: | |
| 1294 | + gc08a3_power_off(gc08a3->dev); | |
| 1295 | + | |
| 1296 | + return ret; | |
| 1297 | +} | |
| 1298 | + | |
| 1299 | +static void gc08a3_remove(struct i2c_client *client) | |
| 1300 | +{ | |
| 1301 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1302 | + struct gc08a3 *gc08a3 = to_gc08a3(sd); | |
| 1303 | + | |
| 1304 | + v4l2_async_unregister_subdev(&gc08a3->sd); | |
| 1305 | + v4l2_subdev_cleanup(sd); | |
| 1306 | + media_entity_cleanup(&gc08a3->sd.entity); | |
| 1307 | + v4l2_ctrl_handler_free(&gc08a3->ctrls); | |
| 1308 | + | |
| 1309 | + pm_runtime_disable(&client->dev); | |
| 1310 | + if (!pm_runtime_status_suspended(&client->dev)) | |
| 1311 | + gc08a3_power_off(gc08a3->dev); | |
| 1312 | + pm_runtime_set_suspended(&client->dev); | |
| 1313 | +} | |
| 1314 | + | |
| 1315 | +static const struct of_device_id gc08a3_of_match[] = { | |
| 1316 | + { .compatible = "galaxycore,gc08a3" }, | |
| 1317 | + {} | |
| 1318 | +}; | |
| 1319 | +MODULE_DEVICE_TABLE(of, gc08a3_of_match); | |
| 1320 | + | |
| 1321 | +static DEFINE_RUNTIME_DEV_PM_OPS(gc08a3_pm_ops, | |
| 1322 | + gc08a3_power_off, | |
| 1323 | + gc08a3_power_on, | |
| 1324 | + NULL); | |
| 1325 | + | |
| 1326 | +static struct i2c_driver gc08a3_i2c_driver = { | |
| 1327 | + .driver = { | |
| 1328 | + .of_match_table = gc08a3_of_match, | |
| 1329 | + .pm = pm_ptr(&gc08a3_pm_ops), | |
| 1330 | + .name = "gc08a3", | |
| 1331 | + }, | |
| 1332 | + .probe = gc08a3_probe, | |
| 1333 | + .remove = gc08a3_remove, | |
| 1334 | +}; | |
| 1335 | +module_i2c_driver(gc08a3_i2c_driver); | |
| 1336 | + | |
| 1337 | +MODULE_DESCRIPTION("GalaxyCore gc08a3 Camera driver"); | |
| 1338 | +MODULE_AUTHOR("Zhi Mao <zhi.mao@mediatek.com>"); | |
| 1339 | +MODULE_LICENSE("GPL"); | |
| @@ -68,8 +68,7 @@ · 67 unmodified lines | ||
| 68 | 68 | #define GC2145_DPHY_CLK_DELAY BIT(4) |
| 69 | 69 | #define GC2145_DPHY_LANE0_DELAY BIT(5) |
| 70 | 70 | #define GC2145_DPHY_LANE1_DELAY BIT(6) |
| 71 | −#define GC2145_REG_FIFO_FULL_LVL_LOW CCI_REG8(0x04) | |
| 72 | −#define GC2145_REG_FIFO_FULL_LVL_HIGH CCI_REG8(0x05) | |
| 71 | +#define GC2145_REG_FIFO_FULL_LVL CCI_REG16_LE(0x04) | |
| 73 | 72 | #define GC2145_REG_FIFO_MODE CCI_REG8(0x06) |
| 74 | 73 | #define GC2145_FIFO_MODE_READ_GATE BIT(3) |
| 75 | 74 | #define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7) |
| @@ -79,8 +78,7 @@ · 3 unmodified lines | ||
| 79 | 78 | #define GC2145_CSI2_MODE_MIPI_EN BIT(4) |
| 80 | 79 | #define GC2145_CSI2_MODE_EN BIT(7) |
| 81 | 80 | #define GC2145_REG_MIPI_DT CCI_REG8(0x11) |
| 82 | −#define GC2145_REG_LWC_LOW CCI_REG8(0x12) | |
| 83 | −#define GC2145_REG_LWC_HIGH CCI_REG8(0x13) | |
| 81 | +#define GC2145_REG_LWC CCI_REG16_LE(0x12) | |
| 84 | 82 | #define GC2145_REG_DPHY_MODE CCI_REG8(0x15) |
| 85 | 83 | #define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4) |
| 86 | 84 | #define GC2145_REG_FIFO_GATE_MODE CCI_REG8(0x17) |
| @@ -542,45 +540,82 @@ static const struct gc2145_mode supported_modes[] = { · 455 unmodified lines | ||
| 542 | 540 | /** |
| 543 | 541 | * struct gc2145_format - GC2145 pixel format description |
| 544 | 542 | * @code: media bus (MBUS) associated code |
| 543 | + * @colorspace: V4L2 colorspace | |
| 545 | 544 | * @datatype: MIPI CSI2 data type |
| 546 | 545 | * @output_fmt: GC2145 output format |
| 547 | 546 | * @switch_bit: GC2145 first/second switch |
| 547 | + * @row_col_switch: GC2145 switch row and/or column | |
| 548 | 548 | */ |
| 549 | 549 | struct gc2145_format { |
| 550 | 550 | unsigned int code; |
| 551 | + unsigned int colorspace; | |
| 551 | 552 | unsigned char datatype; |
| 552 | 553 | unsigned char output_fmt; |
| 553 | 554 | bool switch_bit; |
| 555 | + unsigned char row_col_switch; | |
| 554 | 556 | }; |
| 555 | 557 | |
| 556 | 558 | /* All supported formats */ |
| 557 | 559 | static const struct gc2145_format supported_formats[] = { |
| 558 | 560 | { |
| 559 | 561 | .code = MEDIA_BUS_FMT_UYVY8_1X16, |
| 562 | + .colorspace = V4L2_COLORSPACE_SRGB, | |
| 560 | 563 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 561 | 564 | .output_fmt = 0x00, |
| 562 | 565 | }, |
| 563 | 566 | { |
| 564 | 567 | .code = MEDIA_BUS_FMT_VYUY8_1X16, |
| 568 | + .colorspace = V4L2_COLORSPACE_SRGB, | |
| 565 | 569 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 566 | 570 | .output_fmt = 0x01, |
| 567 | 571 | }, |
| 568 | 572 | { |
| 569 | 573 | .code = MEDIA_BUS_FMT_YUYV8_1X16, |
| 574 | + .colorspace = V4L2_COLORSPACE_SRGB, | |
| 570 | 575 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 571 | 576 | .output_fmt = 0x02, |
| 572 | 577 | }, |
| 573 | 578 | { |
| 574 | 579 | .code = MEDIA_BUS_FMT_YVYU8_1X16, |
| 580 | + .colorspace = V4L2_COLORSPACE_SRGB, | |
| 575 | 581 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 576 | 582 | .output_fmt = 0x03, |
| 577 | 583 | }, |
| 578 | 584 | { |
| 579 | 585 | .code = MEDIA_BUS_FMT_RGB565_1X16, |
| 586 | + .colorspace = V4L2_COLORSPACE_SRGB, | |
| 580 | 587 | .datatype = MIPI_CSI2_DT_RGB565, |
| 581 | 588 | .output_fmt = 0x06, |
| 582 | 589 | .switch_bit = true, |
| 583 | 590 | }, |
| 591 | + { | |
| 592 | + .code = MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 593 | + .colorspace = V4L2_COLORSPACE_RAW, | |
| 594 | + .datatype = MIPI_CSI2_DT_RAW8, | |
| 595 | + .output_fmt = 0x17, | |
| 596 | + .row_col_switch = GC2145_SYNC_MODE_COL_SWITCH, | |
| 597 | + }, | |
| 598 | + { | |
| 599 | + .code = MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 600 | + .colorspace = V4L2_COLORSPACE_RAW, | |
| 601 | + .datatype = MIPI_CSI2_DT_RAW8, | |
| 602 | + .output_fmt = 0x17, | |
| 603 | + .row_col_switch = GC2145_SYNC_MODE_COL_SWITCH | GC2145_SYNC_MODE_ROW_SWITCH, | |
| 604 | + }, | |
| 605 | + { | |
| 606 | + .code = MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 607 | + .colorspace = V4L2_COLORSPACE_RAW, | |
| 608 | + .datatype = MIPI_CSI2_DT_RAW8, | |
| 609 | + .output_fmt = 0x17, | |
| 610 | + .row_col_switch = 0, | |
| 611 | + }, | |
| 612 | + { | |
| 613 | + .code = MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 614 | + .colorspace = V4L2_COLORSPACE_RAW, | |
| 615 | + .datatype = MIPI_CSI2_DT_RAW8, | |
| 616 | + .output_fmt = 0x17, | |
| 617 | + .row_col_switch = GC2145_SYNC_MODE_ROW_SWITCH, | |
| 618 | + }, | |
| 584 | 619 | }; |
| 585 | 620 | |
| 586 | 621 | struct gc2145_ctrls { |
| @@ -641,7 +676,8 @@ gc2145_get_format_code(struct gc2145 *gc2145, u32 code) · 54 unmodified lines | ||
| 641 | 676 | |
| 642 | 677 | static void gc2145_update_pad_format(struct gc2145 *gc2145, |
| 643 | 678 | const struct gc2145_mode *mode, |
| 644 | − struct v4l2_mbus_framefmt *fmt, u32 code) | |
| 679 | + struct v4l2_mbus_framefmt *fmt, u32 code, | |
| 680 | + u32 colorspace) | |
| 645 | 681 | { |
| 646 | 682 | fmt->code = code; |
| 647 | 683 | fmt->width = mode->width; |
| @@ -663,7 +699,8 @@ static int gc2145_init_state(struct v4l2_subdev *sd, · 15 unmodified lines | ||
| 663 | 699 | /* Initialize pad format */ |
| 664 | 700 | format = v4l2_subdev_state_get_format(state, 0); |
| 665 | 701 | gc2145_update_pad_format(gc2145, &supported_modes[0], format, |
| 666 | − MEDIA_BUS_FMT_RGB565_1X16); | |
| 702 | + MEDIA_BUS_FMT_RGB565_1X16, | |
| 703 | + V4L2_COLORSPACE_SRGB); | |
| 667 | 704 | |
| 668 | 705 | /* Initialize crop rectangle. */ |
| 669 | 706 | crop = v4l2_subdev_state_get_crop(state, 0); |
| @@ -754,7 +791,13 @@ static int gc2145_set_pad_format(struct v4l2_subdev *sd, · 84 unmodified lines | ||
| 754 | 791 | width, height, |
| 755 | 792 | fmt->format.width, fmt->format.height); |
| 756 | 793 | |
| 757 | − gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code); | |
| 794 | + /* In RAW mode, VGA is not possible so use 720p instead */ | |
| 795 | + if (gc2145_fmt->colorspace == V4L2_COLORSPACE_RAW && | |
| 796 | + mode == &supported_modes[GC2145_MODE_640X480]) | |
| 797 | + mode = &supported_modes[GC2145_MODE_1280X720]; | |
| 798 | + | |
| 799 | + gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code, | |
| 800 | + gc2145_fmt->colorspace); | |
| 758 | 801 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
| 759 | 802 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
| 760 | 803 | gc2145->mode = mode; |
| @@ -811,9 +854,12 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145, · 50 unmodified lines | ||
| 811 | 854 | * For RAW8, LWC = image width |
| 812 | 855 | * For RAW10, LWC = image width * 1.25 |
| 813 | 856 | */ |
| 814 | − lwc = gc2145->mode->width * 2; | |
| 815 | − cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret); | |
| 816 | − cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret); | |
| 857 | + if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW) | |
| 858 | + lwc = gc2145->mode->width * 2; | |
| 859 | + else | |
| 860 | + lwc = gc2145->mode->width; | |
| 861 | + | |
| 862 | + cci_write(gc2145->regmap, GC2145_REG_LWC, lwc, &ret); | |
| 817 | 863 | |
| 818 | 864 | /* |
| 819 | 865 | * Adjust the MIPI FIFO Full Level |
| @@ -821,21 +867,25 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145, · 1 unmodified line | ||
| 821 | 867 | * 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001 |
| 822 | 868 | * 1600x1200 RAW: 0x0190 |
| 823 | 869 | */ |
| 824 | − if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600) | |
| 825 | − fifo_full_lvl = 0x0001; | |
| 826 | − else | |
| 870 | + if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW) { | |
| 871 | + if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600) | |
| 872 | + fifo_full_lvl = 0x0001; | |
| 873 | + else | |
| 874 | + fifo_full_lvl = 0x0190; | |
| 875 | + } else { | |
| 827 | 876 | fifo_full_lvl = 0x0190; |
| 877 | + } | |
| 828 | 878 | |
| 829 | − cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH, | |
| 830 | − fifo_full_lvl >> 8, &ret); | |
| 831 | − cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW, | |
| 832 | − fifo_full_lvl & 0xff, &ret); | |
| 879 | + cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL, | |
| 880 | + fifo_full_lvl, &ret); | |
| 833 | 881 | |
| 834 | 882 | /* |
| 835 | 883 | * Set the FIFO gate mode / MIPI wdiv set: |
| 836 | 884 | * 0xf1 in case of RAW mode and 0xf0 otherwise |
| 837 | 885 | */ |
| 838 | − cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, 0xf0, &ret); | |
| 886 | + cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, | |
| 887 | + gc2145_format->colorspace == V4L2_COLORSPACE_RAW ? | |
| 888 | + 0xf1 : 0xf0, &ret); | |
| 839 | 889 | |
| 840 | 890 | /* Set the MIPI data type */ |
| 841 | 891 | cci_write(gc2145->regmap, GC2145_REG_MIPI_DT, |
| @@ -883,6 +933,10 @@ static int gc2145_start_streaming(struct gc2145 *gc2145, · 41 unmodified lines | ||
| 883 | 933 | GC2145_BYPASS_MODE_SWITCH, |
| 884 | 934 | gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH |
| 885 | 935 | : 0, &ret); |
| 936 | + cci_update_bits(gc2145->regmap, GC2145_REG_SYNC_MODE, | |
| 937 | + GC2145_SYNC_MODE_COL_SWITCH | | |
| 938 | + GC2145_SYNC_MODE_ROW_SWITCH, | |
| 939 | + gc2145_format->row_col_switch, &ret); | |
| 886 | 940 | if (ret) { |
| 887 | 941 | dev_err(&client->dev, "%s failed to write regs\n", __func__); |
| 888 | 942 | goto err_rpm_put; |
| @@ -1851,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd, · 1850 unmodified lines | ||
| 1851 | 1851 | mutex_lock(&hi846->mutex); |
| 1852 | 1852 | switch (sel->which) { |
| 1853 | 1853 | case V4L2_SUBDEV_FORMAT_TRY: |
| 1854 | − v4l2_subdev_state_get_crop(sd_state, sel->pad); | |
| 1854 | + sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad); | |
| 1855 | 1855 | break; |
| 1856 | 1856 | case V4L2_SUBDEV_FORMAT_ACTIVE: |
| 1857 | 1857 | sel->r = hi846->cur_mode->crop; |
| @@ -162,8 +162,8 @@ static const struct cci_reg_sequence imx219_common_regs[] = { · 161 unmodified lines | ||
| 162 | 162 | { IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */ |
| 163 | 163 | |
| 164 | 164 | /* To Access Addresses 3000-5fff, send the following commands */ |
| 165 | − { CCI_REG8(0x30eb), 0x0c }, | |
| 166 | 165 | { CCI_REG8(0x30eb), 0x05 }, |
| 166 | + { CCI_REG8(0x30eb), 0x0c }, | |
| 167 | 167 | { CCI_REG8(0x300a), 0xff }, |
| 168 | 168 | { CCI_REG8(0x300b), 0xff }, |
| 169 | 169 | { CCI_REG8(0x30eb), 0x05 }, |
| @@ -7,97 +7,150 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/i2c.h> |
| 8 | 8 | #include <linux/module.h> |
| 9 | 9 | #include <linux/pm_runtime.h> |
| 10 | +#include <linux/regulator/consumer.h> | |
| 11 | +#include <media/v4l2-cci.h> | |
| 10 | 12 | #include <media/v4l2-ctrls.h> |
| 11 | 13 | #include <media/v4l2-device.h> |
| 12 | 14 | #include <media/v4l2-fwnode.h> |
| 13 | 15 | #include <asm/unaligned.h> |
| 14 | 16 | |
| 15 | −#define IMX258_REG_VALUE_08BIT 1 | |
| 16 | −#define IMX258_REG_VALUE_16BIT 2 | |
| 17 | − | |
| 18 | −#define IMX258_REG_MODE_SELECT 0x0100 | |
| 17 | +#define IMX258_REG_MODE_SELECT CCI_REG8(0x0100) | |
| 19 | 18 | #define IMX258_MODE_STANDBY 0x00 |
| 20 | 19 | #define IMX258_MODE_STREAMING 0x01 |
| 21 | 20 | |
| 21 | +#define IMX258_REG_RESET CCI_REG8(0x0103) | |
| 22 | + | |
| 22 | 23 | /* Chip ID */ |
| 23 | −#define IMX258_REG_CHIP_ID 0x0016 | |
| 24 | +#define IMX258_REG_CHIP_ID CCI_REG16(0x0016) | |
| 24 | 25 | #define IMX258_CHIP_ID 0x0258 |
| 25 | 26 | |
| 26 | 27 | /* V_TIMING internal */ |
| 27 | 28 | #define IMX258_VTS_30FPS 0x0c50 |
| 28 | 29 | #define IMX258_VTS_30FPS_2K 0x0638 |
| 29 | 30 | #define IMX258_VTS_30FPS_VGA 0x034c |
| 30 | −#define IMX258_VTS_MAX 0xffff | |
| 31 | − | |
| 32 | −/*Frame Length Line*/ | |
| 33 | −#define IMX258_FLL_MIN 0x08a6 | |
| 34 | −#define IMX258_FLL_MAX 0xffff | |
| 35 | −#define IMX258_FLL_STEP 1 | |
| 36 | −#define IMX258_FLL_DEFAULT 0x0c98 | |
| 31 | +#define IMX258_VTS_MAX 65525 | |
| 37 | 32 | |
| 38 | 33 | /* HBLANK control - read only */ |
| 39 | 34 | #define IMX258_PPL_DEFAULT 5352 |
| 40 | 35 | |
| 41 | 36 | /* Exposure control */ |
| 42 | −#define IMX258_REG_EXPOSURE 0x0202 | |
| 37 | +#define IMX258_REG_EXPOSURE CCI_REG16(0x0202) | |
| 38 | +#define IMX258_EXPOSURE_OFFSET 10 | |
| 43 | 39 | #define IMX258_EXPOSURE_MIN 4 |
| 44 | 40 | #define IMX258_EXPOSURE_STEP 1 |
| 45 | 41 | #define IMX258_EXPOSURE_DEFAULT 0x640 |
| 46 | −#define IMX258_EXPOSURE_MAX 65535 | |
| 42 | +#define IMX258_EXPOSURE_MAX (IMX258_VTS_MAX - IMX258_EXPOSURE_OFFSET) | |
| 47 | 43 | |
| 48 | 44 | /* Analog gain control */ |
| 49 | −#define IMX258_REG_ANALOG_GAIN 0x0204 | |
| 45 | +#define IMX258_REG_ANALOG_GAIN CCI_REG16(0x0204) | |
| 50 | 46 | #define IMX258_ANA_GAIN_MIN 0 |
| 51 | 47 | #define IMX258_ANA_GAIN_MAX 480 |
| 52 | 48 | #define IMX258_ANA_GAIN_STEP 1 |
| 53 | 49 | #define IMX258_ANA_GAIN_DEFAULT 0x0 |
| 54 | 50 | |
| 55 | 51 | /* Digital gain control */ |
| 56 | −#define IMX258_REG_GR_DIGITAL_GAIN 0x020e | |
| 57 | −#define IMX258_REG_R_DIGITAL_GAIN 0x0210 | |
| 58 | −#define IMX258_REG_B_DIGITAL_GAIN 0x0212 | |
| 59 | −#define IMX258_REG_GB_DIGITAL_GAIN 0x0214 | |
| 52 | +#define IMX258_REG_GR_DIGITAL_GAIN CCI_REG16(0x020e) | |
| 53 | +#define IMX258_REG_R_DIGITAL_GAIN CCI_REG16(0x0210) | |
| 54 | +#define IMX258_REG_B_DIGITAL_GAIN CCI_REG16(0x0212) | |
| 55 | +#define IMX258_REG_GB_DIGITAL_GAIN CCI_REG16(0x0214) | |
| 60 | 56 | #define IMX258_DGTL_GAIN_MIN 0 |
| 61 | 57 | #define IMX258_DGTL_GAIN_MAX 4096 /* Max = 0xFFF */ |
| 62 | 58 | #define IMX258_DGTL_GAIN_DEFAULT 1024 |
| 63 | 59 | #define IMX258_DGTL_GAIN_STEP 1 |
| 64 | 60 | |
| 65 | 61 | /* HDR control */ |
| 66 | −#define IMX258_REG_HDR 0x0220 | |
| 62 | +#define IMX258_REG_HDR CCI_REG8(0x0220) | |
| 67 | 63 | #define IMX258_HDR_ON BIT(0) |
| 68 | −#define IMX258_REG_HDR_RATIO 0x0222 | |
| 64 | +#define IMX258_REG_HDR_RATIO CCI_REG8(0x0222) | |
| 69 | 65 | #define IMX258_HDR_RATIO_MIN 0 |
| 70 | 66 | #define IMX258_HDR_RATIO_MAX 5 |
| 71 | 67 | #define IMX258_HDR_RATIO_STEP 1 |
| 72 | 68 | #define IMX258_HDR_RATIO_DEFAULT 0x0 |
| 73 | 69 | |
| 74 | 70 | /* Test Pattern Control */ |
| 75 | −#define IMX258_REG_TEST_PATTERN 0x0600 | |
| 71 | +#define IMX258_REG_TEST_PATTERN CCI_REG16(0x0600) | |
| 72 | + | |
| 73 | +#define IMX258_CLK_BLANK_STOP CCI_REG8(0x4040) | |
| 76 | 74 | |
| 77 | 75 | /* Orientation */ |
| 78 | −#define REG_MIRROR_FLIP_CONTROL 0x0101 | |
| 79 | −#define REG_CONFIG_MIRROR_FLIP 0x03 | |
| 80 | −#define REG_CONFIG_FLIP_TEST_PATTERN 0x02 | |
| 76 | +#define REG_MIRROR_FLIP_CONTROL CCI_REG8(0x0101) | |
| 77 | +#define REG_CONFIG_MIRROR_HFLIP 0x01 | |
| 78 | +#define REG_CONFIG_MIRROR_VFLIP 0x02 | |
| 79 | + | |
| 80 | +/* IMX258 native and active pixel array size. */ | |
| 81 | +#define IMX258_NATIVE_WIDTH 4224U | |
| 82 | +#define IMX258_NATIVE_HEIGHT 3192U | |
| 83 | +#define IMX258_PIXEL_ARRAY_LEFT 8U | |
| 84 | +#define IMX258_PIXEL_ARRAY_TOP 16U | |
| 85 | +#define IMX258_PIXEL_ARRAY_WIDTH 4208U | |
| 86 | +#define IMX258_PIXEL_ARRAY_HEIGHT 3120U | |
| 87 | + | |
| 88 | +/* regs */ | |
| 89 | +#define IMX258_REG_PLL_MULT_DRIV CCI_REG8(0x0310) | |
| 90 | +#define IMX258_REG_IVTPXCK_DIV CCI_REG8(0x0301) | |
| 91 | +#define IMX258_REG_IVTSYCK_DIV CCI_REG8(0x0303) | |
| 92 | +#define IMX258_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305) | |
| 93 | +#define IMX258_REG_IOPPXCK_DIV CCI_REG8(0x0309) | |
| 94 | +#define IMX258_REG_IOPSYCK_DIV CCI_REG8(0x030b) | |
| 95 | +#define IMX258_REG_PREPLLCK_OP_DIV CCI_REG8(0x030d) | |
| 96 | +#define IMX258_REG_PHASE_PIX_OUTEN CCI_REG8(0x3030) | |
| 97 | +#define IMX258_REG_PDPIX_DATA_RATE CCI_REG8(0x3032) | |
| 98 | +#define IMX258_REG_SCALE_MODE CCI_REG8(0x0401) | |
| 99 | +#define IMX258_REG_SCALE_MODE_EXT CCI_REG8(0x3038) | |
| 100 | +#define IMX258_REG_AF_WINDOW_MODE CCI_REG8(0x7bcd) | |
| 101 | +#define IMX258_REG_FRM_LENGTH_CTL CCI_REG8(0x0350) | |
| 102 | +#define IMX258_REG_CSI_LANE_MODE CCI_REG8(0x0114) | |
| 103 | +#define IMX258_REG_X_EVN_INC CCI_REG8(0x0381) | |
| 104 | +#define IMX258_REG_X_ODD_INC CCI_REG8(0x0383) | |
| 105 | +#define IMX258_REG_Y_EVN_INC CCI_REG8(0x0385) | |
| 106 | +#define IMX258_REG_Y_ODD_INC CCI_REG8(0x0387) | |
| 107 | +#define IMX258_REG_BINNING_MODE CCI_REG8(0x0900) | |
| 108 | +#define IMX258_REG_BINNING_TYPE_V CCI_REG8(0x0901) | |
| 109 | +#define IMX258_REG_FORCE_FD_SUM CCI_REG8(0x300d) | |
| 110 | +#define IMX258_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408) | |
| 111 | +#define IMX258_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a) | |
| 112 | +#define IMX258_REG_DIG_CROP_IMAGE_WIDTH CCI_REG16(0x040c) | |
| 113 | +#define IMX258_REG_DIG_CROP_IMAGE_HEIGHT CCI_REG16(0x040e) | |
| 114 | +#define IMX258_REG_SCALE_M CCI_REG16(0x0404) | |
| 115 | +#define IMX258_REG_X_OUT_SIZE CCI_REG16(0x034c) | |
| 116 | +#define IMX258_REG_Y_OUT_SIZE CCI_REG16(0x034e) | |
| 117 | +#define IMX258_REG_X_ADD_STA CCI_REG16(0x0344) | |
| 118 | +#define IMX258_REG_Y_ADD_STA CCI_REG16(0x0346) | |
| 119 | +#define IMX258_REG_X_ADD_END CCI_REG16(0x0348) | |
| 120 | +#define IMX258_REG_Y_ADD_END CCI_REG16(0x034a) | |
| 121 | +#define IMX258_REG_EXCK_FREQ CCI_REG16(0x0136) | |
| 122 | +#define IMX258_REG_CSI_DT_FMT CCI_REG16(0x0112) | |
| 123 | +#define IMX258_REG_LINE_LENGTH_PCK CCI_REG16(0x0342) | |
| 124 | +#define IMX258_REG_SCALE_M_EXT CCI_REG16(0x303a) | |
| 125 | +#define IMX258_REG_FRM_LENGTH_LINES CCI_REG16(0x0340) | |
| 126 | +#define IMX258_REG_FINE_INTEG_TIME CCI_REG8(0x0200) | |
| 127 | +#define IMX258_REG_PLL_IVT_MPY CCI_REG16(0x0306) | |
| 128 | +#define IMX258_REG_PLL_IOP_MPY CCI_REG16(0x030e) | |
| 129 | +#define IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H CCI_REG16(0x0820) | |
| 130 | +#define IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L CCI_REG16(0x0822) | |
| 81 | 131 | |
| 82 | −/* Input clock frequency in Hz */ | |
| 83 | −#define IMX258_INPUT_CLOCK_FREQ 19200000 | |
| 132 | +struct imx258_reg_list { | |
| 133 | + u32 num_of_regs; | |
| 134 | + const struct cci_reg_sequence *regs; | |
| 135 | +}; | |
| 84 | 136 | |
| 85 | −struct imx258_reg { | |
| 86 | − u16 address; | |
| 87 | − u8 val; | |
| 137 | +struct imx258_link_cfg { | |
| 138 | + unsigned int lf_to_pix_rate_factor; | |
| 139 | + struct imx258_reg_list reg_list; | |
| 88 | 140 | }; |
| 89 | 141 | |
| 90 | −struct imx258_reg_list { | |
| 91 | − u32 num_of_regs; | |
| 92 | − const struct imx258_reg *regs; | |
| 142 | +enum { | |
| 143 | + IMX258_2_LANE_MODE, | |
| 144 | + IMX258_4_LANE_MODE, | |
| 145 | + IMX258_LANE_CONFIGS, | |
| 93 | 146 | }; |
| 94 | 147 | |
| 95 | 148 | /* Link frequency config */ |
| 96 | 149 | struct imx258_link_freq_config { |
| 97 | 150 | u32 pixels_per_line; |
| 98 | 151 | |
| 99 | − /* PLL registers for this link frequency */ | |
| 100 | − struct imx258_reg_list reg_list; | |
| 152 | + /* Configuration for this link frequency / num lanes selection */ | |
| 153 | + struct imx258_link_cfg link_cfg[IMX258_LANE_CONFIGS]; | |
| 101 | 154 | }; |
| 102 | 155 | |
| 103 | 156 | /* Mode : resolution and related config&values */ |
| @@ -115,400 +168,307 @@ struct imx258_mode { · 11 unmodified lines | ||
| 115 | 168 | u32 link_freq_index; |
| 116 | 169 | /* Default register values */ |
| 117 | 170 | struct imx258_reg_list reg_list; |
| 171 | + | |
| 172 | + /* Analog crop rectangle */ | |
| 173 | + struct v4l2_rect crop; | |
| 174 | +}; | |
| 175 | + | |
| 176 | +/* | |
| 177 | + * 4208x3120 @ 30 fps needs 1267Mbps/lane, 4 lanes. | |
| 178 | + * To avoid further computation of clock settings, adopt the same per | |
| 179 | + * lane data rate when using 2 lanes, thus allowing a maximum of 15fps. | |
| 180 | + */ | |
| 181 | +static const struct cci_reg_sequence mipi_1267mbps_19_2mhz_2l[] = { | |
| 182 | + { IMX258_REG_EXCK_FREQ, 0x1333 }, | |
| 183 | + { IMX258_REG_IVTPXCK_DIV, 10 }, | |
| 184 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 185 | + { IMX258_REG_PREPLLCK_VT_DIV, 3 }, | |
| 186 | + { IMX258_REG_PLL_IVT_MPY, 198 }, | |
| 187 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 188 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 189 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 190 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 191 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 192 | + | |
| 193 | + { IMX258_REG_CSI_LANE_MODE, 1 }, | |
| 194 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1267 * 2 }, | |
| 195 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 196 | +}; | |
| 197 | + | |
| 198 | +static const struct cci_reg_sequence mipi_1267mbps_19_2mhz_4l[] = { | |
| 199 | + { IMX258_REG_EXCK_FREQ, 0x1333 }, | |
| 200 | + { IMX258_REG_IVTPXCK_DIV, 5 }, | |
| 201 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 202 | + { IMX258_REG_PREPLLCK_VT_DIV, 3 }, | |
| 203 | + { IMX258_REG_PLL_IVT_MPY, 198 }, | |
| 204 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 205 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 206 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 207 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 208 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 209 | + | |
| 210 | + { IMX258_REG_CSI_LANE_MODE, 3 }, | |
| 211 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1267 * 4 }, | |
| 212 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 213 | +}; | |
| 214 | + | |
| 215 | +static const struct cci_reg_sequence mipi_1272mbps_24mhz_2l[] = { | |
| 216 | + { IMX258_REG_EXCK_FREQ, 0x1800 }, | |
| 217 | + { IMX258_REG_IVTPXCK_DIV, 10 }, | |
| 218 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 219 | + { IMX258_REG_PREPLLCK_VT_DIV, 4 }, | |
| 220 | + { IMX258_REG_PLL_IVT_MPY, 212 }, | |
| 221 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 222 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 223 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 224 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 225 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 226 | + | |
| 227 | + { IMX258_REG_CSI_LANE_MODE, 1 }, | |
| 228 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1272 * 2 }, | |
| 229 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 230 | +}; | |
| 231 | + | |
| 232 | +static const struct cci_reg_sequence mipi_1272mbps_24mhz_4l[] = { | |
| 233 | + { IMX258_REG_EXCK_FREQ, 0x1800 }, | |
| 234 | + { IMX258_REG_IVTPXCK_DIV, 5 }, | |
| 235 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 236 | + { IMX258_REG_PREPLLCK_VT_DIV, 4 }, | |
| 237 | + { IMX258_REG_PLL_IVT_MPY, 212 }, | |
| 238 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 239 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 240 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 241 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 242 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 243 | + | |
| 244 | + { IMX258_REG_CSI_LANE_MODE, 3 }, | |
| 245 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1272 * 4 }, | |
| 246 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 247 | +}; | |
| 248 | + | |
| 249 | +static const struct cci_reg_sequence mipi_640mbps_19_2mhz_2l[] = { | |
| 250 | + { IMX258_REG_EXCK_FREQ, 0x1333 }, | |
| 251 | + { IMX258_REG_IVTPXCK_DIV, 5 }, | |
| 252 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 253 | + { IMX258_REG_PREPLLCK_VT_DIV, 3 }, | |
| 254 | + { IMX258_REG_PLL_IVT_MPY, 100 }, | |
| 255 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 256 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 257 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 258 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 259 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 260 | + | |
| 261 | + { IMX258_REG_CSI_LANE_MODE, 1 }, | |
| 262 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 640 * 2 }, | |
| 263 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 264 | +}; | |
| 265 | + | |
| 266 | +static const struct cci_reg_sequence mipi_640mbps_19_2mhz_4l[] = { | |
| 267 | + { IMX258_REG_EXCK_FREQ, 0x1333 }, | |
| 268 | + { IMX258_REG_IVTPXCK_DIV, 5 }, | |
| 269 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 270 | + { IMX258_REG_PREPLLCK_VT_DIV, 3 }, | |
| 271 | + { IMX258_REG_PLL_IVT_MPY, 100 }, | |
| 272 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 273 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 274 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 275 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 276 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 277 | + | |
| 278 | + { IMX258_REG_CSI_LANE_MODE, 3 }, | |
| 279 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 640 * 4 }, | |
| 280 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 118 | 281 | }; |
| 119 | 282 | |
| 120 | −/* 4208x3118 needs 1267Mbps/lane, 4 lanes */ | |
| 121 | −static const struct imx258_reg mipi_data_rate_1267mbps[] = { | |
| 122 | − { 0x0301, 0x05 }, | |
| 123 | − { 0x0303, 0x02 }, | |
| 124 | − { 0x0305, 0x03 }, | |
| 125 | − { 0x0306, 0x00 }, | |
| 126 | − { 0x0307, 0xC6 }, | |
| 127 | − { 0x0309, 0x0A }, | |
| 128 | − { 0x030B, 0x01 }, | |
| 129 | − { 0x030D, 0x02 }, | |
| 130 | − { 0x030E, 0x00 }, | |
| 131 | − { 0x030F, 0xD8 }, | |
| 132 | − { 0x0310, 0x00 }, | |
| 133 | − { 0x0820, 0x13 }, | |
| 134 | − { 0x0821, 0x4C }, | |
| 135 | − { 0x0822, 0xCC }, | |
| 136 | − { 0x0823, 0xCC }, | |
| 283 | +static const struct cci_reg_sequence mipi_642mbps_24mhz_2l[] = { | |
| 284 | + { IMX258_REG_EXCK_FREQ, 0x1800 }, | |
| 285 | + { IMX258_REG_IVTPXCK_DIV, 5 }, | |
| 286 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 287 | + { IMX258_REG_PREPLLCK_VT_DIV, 4 }, | |
| 288 | + { IMX258_REG_PLL_IVT_MPY, 107 }, | |
| 289 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 290 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 291 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 292 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 293 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 294 | + | |
| 295 | + { IMX258_REG_CSI_LANE_MODE, 1 }, | |
| 296 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 642 * 2 }, | |
| 297 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 137 | 298 | }; |
| 138 | 299 | |
| 139 | −static const struct imx258_reg mipi_data_rate_640mbps[] = { | |
| 140 | − { 0x0301, 0x05 }, | |
| 141 | − { 0x0303, 0x02 }, | |
| 142 | − { 0x0305, 0x03 }, | |
| 143 | − { 0x0306, 0x00 }, | |
| 144 | − { 0x0307, 0x64 }, | |
| 145 | − { 0x0309, 0x0A }, | |
| 146 | − { 0x030B, 0x01 }, | |
| 147 | − { 0x030D, 0x02 }, | |
| 148 | − { 0x030E, 0x00 }, | |
| 149 | − { 0x030F, 0xD8 }, | |
| 150 | − { 0x0310, 0x00 }, | |
| 151 | − { 0x0820, 0x0A }, | |
| 152 | − { 0x0821, 0x00 }, | |
| 153 | − { 0x0822, 0x00 }, | |
| 154 | − { 0x0823, 0x00 }, | |
| 300 | +static const struct cci_reg_sequence mipi_642mbps_24mhz_4l[] = { | |
| 301 | + { IMX258_REG_EXCK_FREQ, 0x1800 }, | |
| 302 | + { IMX258_REG_IVTPXCK_DIV, 5 }, | |
| 303 | + { IMX258_REG_IVTSYCK_DIV, 2 }, | |
| 304 | + { IMX258_REG_PREPLLCK_VT_DIV, 4 }, | |
| 305 | + { IMX258_REG_PLL_IVT_MPY, 107 }, | |
| 306 | + { IMX258_REG_IOPPXCK_DIV, 10 }, | |
| 307 | + { IMX258_REG_IOPSYCK_DIV, 1 }, | |
| 308 | + { IMX258_REG_PREPLLCK_OP_DIV, 2 }, | |
| 309 | + { IMX258_REG_PLL_IOP_MPY, 216 }, | |
| 310 | + { IMX258_REG_PLL_MULT_DRIV, 0 }, | |
| 311 | + | |
| 312 | + { IMX258_REG_CSI_LANE_MODE, 3 }, | |
| 313 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 642 * 4 }, | |
| 314 | + { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, | |
| 155 | 315 | }; |
| 156 | 316 | |
| 157 | −static const struct imx258_reg mode_4208x3118_regs[] = { | |
| 158 | − { 0x0136, 0x13 }, | |
| 159 | − { 0x0137, 0x33 }, | |
| 160 | − { 0x3051, 0x00 }, | |
| 161 | − { 0x3052, 0x00 }, | |
| 162 | − { 0x4E21, 0x14 }, | |
| 163 | − { 0x6B11, 0xCF }, | |
| 164 | − { 0x7FF0, 0x08 }, | |
| 165 | − { 0x7FF1, 0x0F }, | |
| 166 | − { 0x7FF2, 0x08 }, | |
| 167 | − { 0x7FF3, 0x1B }, | |
| 168 | − { 0x7FF4, 0x23 }, | |
| 169 | − { 0x7FF5, 0x60 }, | |
| 170 | − { 0x7FF6, 0x00 }, | |
| 171 | − { 0x7FF7, 0x01 }, | |
| 172 | − { 0x7FF8, 0x00 }, | |
| 173 | − { 0x7FF9, 0x78 }, | |
| 174 | − { 0x7FFA, 0x00 }, | |
| 175 | − { 0x7FFB, 0x00 }, | |
| 176 | − { 0x7FFC, 0x00 }, | |
| 177 | − { 0x7FFD, 0x00 }, | |
| 178 | − { 0x7FFE, 0x00 }, | |
| 179 | − { 0x7FFF, 0x03 }, | |
| 180 | − { 0x7F76, 0x03 }, | |
| 181 | − { 0x7F77, 0xFE }, | |
| 182 | − { 0x7FA8, 0x03 }, | |
| 183 | − { 0x7FA9, 0xFE }, | |
| 184 | − { 0x7B24, 0x81 }, | |
| 185 | − { 0x7B25, 0x00 }, | |
| 186 | − { 0x6564, 0x07 }, | |
| 187 | − { 0x6B0D, 0x41 }, | |
| 188 | − { 0x653D, 0x04 }, | |
| 189 | − { 0x6B05, 0x8C }, | |
| 190 | − { 0x6B06, 0xF9 }, | |
| 191 | − { 0x6B08, 0x65 }, | |
| 192 | − { 0x6B09, 0xFC }, | |
| 193 | − { 0x6B0A, 0xCF }, | |
| 194 | − { 0x6B0B, 0xD2 }, | |
| 195 | − { 0x6700, 0x0E }, | |
| 196 | − { 0x6707, 0x0E }, | |
| 197 | − { 0x9104, 0x00 }, | |
| 198 | − { 0x4648, 0x7F }, | |
| 199 | − { 0x7420, 0x00 }, | |
| 200 | − { 0x7421, 0x1C }, | |
| 201 | − { 0x7422, 0x00 }, | |
| 202 | − { 0x7423, 0xD7 }, | |
| 203 | − { 0x5F04, 0x00 }, | |
| 204 | − { 0x5F05, 0xED }, | |
| 205 | − { 0x0112, 0x0A }, | |
| 206 | − { 0x0113, 0x0A }, | |
| 207 | − { 0x0114, 0x03 }, | |
| 208 | − { 0x0342, 0x14 }, | |
| 209 | − { 0x0343, 0xE8 }, | |
| 210 | − { 0x0340, 0x0C }, | |
| 211 | − { 0x0341, 0x50 }, | |
| 212 | − { 0x0344, 0x00 }, | |
| 213 | − { 0x0345, 0x00 }, | |
| 214 | − { 0x0346, 0x00 }, | |
| 215 | − { 0x0347, 0x00 }, | |
| 216 | − { 0x0348, 0x10 }, | |
| 217 | − { 0x0349, 0x6F }, | |
| 218 | − { 0x034A, 0x0C }, | |
| 219 | − { 0x034B, 0x2E }, | |
| 220 | − { 0x0381, 0x01 }, | |
| 221 | − { 0x0383, 0x01 }, | |
| 222 | − { 0x0385, 0x01 }, | |
| 223 | − { 0x0387, 0x01 }, | |
| 224 | − { 0x0900, 0x00 }, | |
| 225 | − { 0x0901, 0x11 }, | |
| 226 | − { 0x0401, 0x00 }, | |
| 227 | − { 0x0404, 0x00 }, | |
| 228 | − { 0x0405, 0x10 }, | |
| 229 | − { 0x0408, 0x00 }, | |
| 230 | − { 0x0409, 0x00 }, | |
| 231 | − { 0x040A, 0x00 }, | |
| 232 | − { 0x040B, 0x00 }, | |
| 233 | − { 0x040C, 0x10 }, | |
| 234 | − { 0x040D, 0x70 }, | |
| 235 | − { 0x040E, 0x0C }, | |
| 236 | − { 0x040F, 0x30 }, | |
| 237 | − { 0x3038, 0x00 }, | |
| 238 | − { 0x303A, 0x00 }, | |
| 239 | − { 0x303B, 0x10 }, | |
| 240 | − { 0x300D, 0x00 }, | |
| 241 | − { 0x034C, 0x10 }, | |
| 242 | − { 0x034D, 0x70 }, | |
| 243 | − { 0x034E, 0x0C }, | |
| 244 | − { 0x034F, 0x30 }, | |
| 245 | − { 0x0350, 0x01 }, | |
| 246 | − { 0x0202, 0x0C }, | |
| 247 | − { 0x0203, 0x46 }, | |
| 248 | − { 0x0204, 0x00 }, | |
| 249 | − { 0x0205, 0x00 }, | |
| 250 | − { 0x020E, 0x01 }, | |
| 251 | − { 0x020F, 0x00 }, | |
| 252 | − { 0x0210, 0x01 }, | |
| 253 | − { 0x0211, 0x00 }, | |
| 254 | − { 0x0212, 0x01 }, | |
| 255 | − { 0x0213, 0x00 }, | |
| 256 | − { 0x0214, 0x01 }, | |
| 257 | − { 0x0215, 0x00 }, | |
| 258 | − { 0x7BCD, 0x00 }, | |
| 259 | − { 0x94DC, 0x20 }, | |
| 260 | − { 0x94DD, 0x20 }, | |
| 261 | − { 0x94DE, 0x20 }, | |
| 262 | − { 0x95DC, 0x20 }, | |
| 263 | − { 0x95DD, 0x20 }, | |
| 264 | − { 0x95DE, 0x20 }, | |
| 265 | − { 0x7FB0, 0x00 }, | |
| 266 | − { 0x9010, 0x3E }, | |
| 267 | − { 0x9419, 0x50 }, | |
| 268 | − { 0x941B, 0x50 }, | |
| 269 | − { 0x9519, 0x50 }, | |
| 270 | − { 0x951B, 0x50 }, | |
| 271 | − { 0x3030, 0x00 }, | |
| 272 | − { 0x3032, 0x00 }, | |
| 273 | − { 0x0220, 0x00 }, | |
| 317 | +static const struct cci_reg_sequence mode_common_regs[] = { | |
| 318 | + { CCI_REG8(0x3051), 0x00 }, | |
| 319 | + { CCI_REG8(0x6B11), 0xCF }, | |
| 320 | + { CCI_REG8(0x7FF0), 0x08 }, | |
| 321 | + { CCI_REG8(0x7FF1), 0x0F }, | |
| 322 | + { CCI_REG8(0x7FF2), 0x08 }, | |
| 323 | + { CCI_REG8(0x7FF3), 0x1B }, | |
| 324 | + { CCI_REG8(0x7FF4), 0x23 }, | |
| 325 | + { CCI_REG8(0x7FF5), 0x60 }, | |
| 326 | + { CCI_REG8(0x7FF6), 0x00 }, | |
| 327 | + { CCI_REG8(0x7FF7), 0x01 }, | |
| 328 | + { CCI_REG8(0x7FF8), 0x00 }, | |
| 329 | + { CCI_REG8(0x7FF9), 0x78 }, | |
| 330 | + { CCI_REG8(0x7FFA), 0x00 }, | |
| 331 | + { CCI_REG8(0x7FFB), 0x00 }, | |
| 332 | + { CCI_REG8(0x7FFC), 0x00 }, | |
| 333 | + { CCI_REG8(0x7FFD), 0x00 }, | |
| 334 | + { CCI_REG8(0x7FFE), 0x00 }, | |
| 335 | + { CCI_REG8(0x7FFF), 0x03 }, | |
| 336 | + { CCI_REG8(0x7F76), 0x03 }, | |
| 337 | + { CCI_REG8(0x7F77), 0xFE }, | |
| 338 | + { CCI_REG8(0x7FA8), 0x03 }, | |
| 339 | + { CCI_REG8(0x7FA9), 0xFE }, | |
| 340 | + { CCI_REG8(0x7B24), 0x81 }, | |
| 341 | + { CCI_REG8(0x6564), 0x07 }, | |
| 342 | + { CCI_REG8(0x6B0D), 0x41 }, | |
| 343 | + { CCI_REG8(0x653D), 0x04 }, | |
| 344 | + { CCI_REG8(0x6B05), 0x8C }, | |
| 345 | + { CCI_REG8(0x6B06), 0xF9 }, | |
| 346 | + { CCI_REG8(0x6B08), 0x65 }, | |
| 347 | + { CCI_REG8(0x6B09), 0xFC }, | |
| 348 | + { CCI_REG8(0x6B0A), 0xCF }, | |
| 349 | + { CCI_REG8(0x6B0B), 0xD2 }, | |
| 350 | + { CCI_REG8(0x6700), 0x0E }, | |
| 351 | + { CCI_REG8(0x6707), 0x0E }, | |
| 352 | + { CCI_REG8(0x9104), 0x00 }, | |
| 353 | + { CCI_REG8(0x4648), 0x7F }, | |
| 354 | + { CCI_REG8(0x7420), 0x00 }, | |
| 355 | + { CCI_REG8(0x7421), 0x1C }, | |
| 356 | + { CCI_REG8(0x7422), 0x00 }, | |
| 357 | + { CCI_REG8(0x7423), 0xD7 }, | |
| 358 | + { CCI_REG8(0x5F04), 0x00 }, | |
| 359 | + { CCI_REG8(0x5F05), 0xED }, | |
| 360 | + {IMX258_REG_CSI_DT_FMT, 0x0a0a}, | |
| 361 | + {IMX258_REG_LINE_LENGTH_PCK, 5352}, | |
| 362 | + {IMX258_REG_X_ADD_STA, 0}, | |
| 363 | + {IMX258_REG_Y_ADD_STA, 0}, | |
| 364 | + {IMX258_REG_X_ADD_END, 4207}, | |
| 365 | + {IMX258_REG_Y_ADD_END, 3119}, | |
| 366 | + {IMX258_REG_X_EVN_INC, 1}, | |
| 367 | + {IMX258_REG_X_ODD_INC, 1}, | |
| 368 | + {IMX258_REG_Y_EVN_INC, 1}, | |
| 369 | + {IMX258_REG_Y_ODD_INC, 1}, | |
| 370 | + {IMX258_REG_DIG_CROP_X_OFFSET, 0}, | |
| 371 | + {IMX258_REG_DIG_CROP_Y_OFFSET, 0}, | |
| 372 | + {IMX258_REG_DIG_CROP_IMAGE_WIDTH, 4208}, | |
| 373 | + {IMX258_REG_SCALE_MODE_EXT, 0}, | |
| 374 | + {IMX258_REG_SCALE_M_EXT, 16}, | |
| 375 | + {IMX258_REG_FORCE_FD_SUM, 0}, | |
| 376 | + {IMX258_REG_FRM_LENGTH_CTL, 0}, | |
| 377 | + {IMX258_REG_ANALOG_GAIN, 0}, | |
| 378 | + {IMX258_REG_GR_DIGITAL_GAIN, 256}, | |
| 379 | + {IMX258_REG_R_DIGITAL_GAIN, 256}, | |
| 380 | + {IMX258_REG_B_DIGITAL_GAIN, 256}, | |
| 381 | + {IMX258_REG_GB_DIGITAL_GAIN, 256}, | |
| 382 | + {IMX258_REG_AF_WINDOW_MODE, 0}, | |
| 383 | + { CCI_REG8(0x94DC), 0x20 }, | |
| 384 | + { CCI_REG8(0x94DD), 0x20 }, | |
| 385 | + { CCI_REG8(0x94DE), 0x20 }, | |
| 386 | + { CCI_REG8(0x95DC), 0x20 }, | |
| 387 | + { CCI_REG8(0x95DD), 0x20 }, | |
| 388 | + { CCI_REG8(0x95DE), 0x20 }, | |
| 389 | + { CCI_REG8(0x7FB0), 0x00 }, | |
| 390 | + { CCI_REG8(0x9010), 0x3E }, | |
| 391 | + { CCI_REG8(0x9419), 0x50 }, | |
| 392 | + { CCI_REG8(0x941B), 0x50 }, | |
| 393 | + { CCI_REG8(0x9519), 0x50 }, | |
| 394 | + { CCI_REG8(0x951B), 0x50 }, | |
| 395 | + {IMX258_REG_PHASE_PIX_OUTEN, 0}, | |
| 396 | + {IMX258_REG_PDPIX_DATA_RATE, 0}, | |
| 397 | + {IMX258_REG_HDR, 0}, | |
| 274 | 398 | }; |
| 275 | 399 | |
| 276 | −static const struct imx258_reg mode_2104_1560_regs[] = { | |
| 277 | − { 0x0136, 0x13 }, | |
| 278 | − { 0x0137, 0x33 }, | |
| 279 | − { 0x3051, 0x00 }, | |
| 280 | − { 0x3052, 0x00 }, | |
| 281 | − { 0x4E21, 0x14 }, | |
| 282 | − { 0x6B11, 0xCF }, | |
| 283 | − { 0x7FF0, 0x08 }, | |
| 284 | − { 0x7FF1, 0x0F }, | |
| 285 | − { 0x7FF2, 0x08 }, | |
| 286 | − { 0x7FF3, 0x1B }, | |
| 287 | − { 0x7FF4, 0x23 }, | |
| 288 | − { 0x7FF5, 0x60 }, | |
| 289 | − { 0x7FF6, 0x00 }, | |
| 290 | − { 0x7FF7, 0x01 }, | |
| 291 | − { 0x7FF8, 0x00 }, | |
| 292 | − { 0x7FF9, 0x78 }, | |
| 293 | − { 0x7FFA, 0x00 }, | |
| 294 | − { 0x7FFB, 0x00 }, | |
| 295 | − { 0x7FFC, 0x00 }, | |
| 296 | − { 0x7FFD, 0x00 }, | |
| 297 | − { 0x7FFE, 0x00 }, | |
| 298 | − { 0x7FFF, 0x03 }, | |
| 299 | − { 0x7F76, 0x03 }, | |
| 300 | − { 0x7F77, 0xFE }, | |
| 301 | − { 0x7FA8, 0x03 }, | |
| 302 | − { 0x7FA9, 0xFE }, | |
| 303 | − { 0x7B24, 0x81 }, | |
| 304 | − { 0x7B25, 0x00 }, | |
| 305 | − { 0x6564, 0x07 }, | |
| 306 | − { 0x6B0D, 0x41 }, | |
| 307 | − { 0x653D, 0x04 }, | |
| 308 | − { 0x6B05, 0x8C }, | |
| 309 | − { 0x6B06, 0xF9 }, | |
| 310 | − { 0x6B08, 0x65 }, | |
| 311 | − { 0x6B09, 0xFC }, | |
| 312 | − { 0x6B0A, 0xCF }, | |
| 313 | − { 0x6B0B, 0xD2 }, | |
| 314 | − { 0x6700, 0x0E }, | |
| 315 | − { 0x6707, 0x0E }, | |
| 316 | − { 0x9104, 0x00 }, | |
| 317 | − { 0x4648, 0x7F }, | |
| 318 | − { 0x7420, 0x00 }, | |
| 319 | − { 0x7421, 0x1C }, | |
| 320 | − { 0x7422, 0x00 }, | |
| 321 | − { 0x7423, 0xD7 }, | |
| 322 | − { 0x5F04, 0x00 }, | |
| 323 | − { 0x5F05, 0xED }, | |
| 324 | − { 0x0112, 0x0A }, | |
| 325 | − { 0x0113, 0x0A }, | |
| 326 | − { 0x0114, 0x03 }, | |
| 327 | − { 0x0342, 0x14 }, | |
| 328 | − { 0x0343, 0xE8 }, | |
| 329 | − { 0x0340, 0x06 }, | |
| 330 | − { 0x0341, 0x38 }, | |
| 331 | − { 0x0344, 0x00 }, | |
| 332 | − { 0x0345, 0x00 }, | |
| 333 | − { 0x0346, 0x00 }, | |
| 334 | − { 0x0347, 0x00 }, | |
| 335 | − { 0x0348, 0x10 }, | |
| 336 | − { 0x0349, 0x6F }, | |
| 337 | − { 0x034A, 0x0C }, | |
| 338 | − { 0x034B, 0x2E }, | |
| 339 | − { 0x0381, 0x01 }, | |
| 340 | − { 0x0383, 0x01 }, | |
| 341 | − { 0x0385, 0x01 }, | |
| 342 | − { 0x0387, 0x01 }, | |
| 343 | − { 0x0900, 0x01 }, | |
| 344 | − { 0x0901, 0x12 }, | |
| 345 | − { 0x0401, 0x01 }, | |
| 346 | − { 0x0404, 0x00 }, | |
| 347 | − { 0x0405, 0x20 }, | |
| 348 | − { 0x0408, 0x00 }, | |
| 349 | − { 0x0409, 0x02 }, | |
| 350 | − { 0x040A, 0x00 }, | |
| 351 | − { 0x040B, 0x00 }, | |
| 352 | − { 0x040C, 0x10 }, | |
| 353 | − { 0x040D, 0x6A }, | |
| 354 | − { 0x040E, 0x06 }, | |
| 355 | − { 0x040F, 0x18 }, | |
| 356 | − { 0x3038, 0x00 }, | |
| 357 | − { 0x303A, 0x00 }, | |
| 358 | − { 0x303B, 0x10 }, | |
| 359 | − { 0x300D, 0x00 }, | |
| 360 | − { 0x034C, 0x08 }, | |
| 361 | − { 0x034D, 0x38 }, | |
| 362 | − { 0x034E, 0x06 }, | |
| 363 | − { 0x034F, 0x18 }, | |
| 364 | − { 0x0350, 0x01 }, | |
| 365 | − { 0x0202, 0x06 }, | |
| 366 | − { 0x0203, 0x2E }, | |
| 367 | − { 0x0204, 0x00 }, | |
| 368 | − { 0x0205, 0x00 }, | |
| 369 | − { 0x020E, 0x01 }, | |
| 370 | − { 0x020F, 0x00 }, | |
| 371 | − { 0x0210, 0x01 }, | |
| 372 | − { 0x0211, 0x00 }, | |
| 373 | − { 0x0212, 0x01 }, | |
| 374 | − { 0x0213, 0x00 }, | |
| 375 | − { 0x0214, 0x01 }, | |
| 376 | − { 0x0215, 0x00 }, | |
| 377 | − { 0x7BCD, 0x01 }, | |
| 378 | − { 0x94DC, 0x20 }, | |
| 379 | − { 0x94DD, 0x20 }, | |
| 380 | − { 0x94DE, 0x20 }, | |
| 381 | − { 0x95DC, 0x20 }, | |
| 382 | − { 0x95DD, 0x20 }, | |
| 383 | − { 0x95DE, 0x20 }, | |
| 384 | − { 0x7FB0, 0x00 }, | |
| 385 | − { 0x9010, 0x3E }, | |
| 386 | − { 0x9419, 0x50 }, | |
| 387 | − { 0x941B, 0x50 }, | |
| 388 | − { 0x9519, 0x50 }, | |
| 389 | − { 0x951B, 0x50 }, | |
| 390 | − { 0x3030, 0x00 }, | |
| 391 | − { 0x3032, 0x00 }, | |
| 392 | − { 0x0220, 0x00 }, | |
| 400 | +static const struct cci_reg_sequence mode_4208x3120_regs[] = { | |
| 401 | + {IMX258_REG_BINNING_MODE, 0}, | |
| 402 | + {IMX258_REG_BINNING_TYPE_V, 0x11}, | |
| 403 | + {IMX258_REG_SCALE_MODE, 0}, | |
| 404 | + {IMX258_REG_SCALE_M, 16}, | |
| 405 | + {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 3120}, | |
| 406 | + {IMX258_REG_X_OUT_SIZE, 4208}, | |
| 407 | + {IMX258_REG_Y_OUT_SIZE, 3120}, | |
| 393 | 408 | }; |
| 394 | 409 | |
| 395 | −static const struct imx258_reg mode_1048_780_regs[] = { | |
| 396 | − { 0x0136, 0x13 }, | |
| 397 | − { 0x0137, 0x33 }, | |
| 398 | − { 0x3051, 0x00 }, | |
| 399 | − { 0x3052, 0x00 }, | |
| 400 | − { 0x4E21, 0x14 }, | |
| 401 | − { 0x6B11, 0xCF }, | |
| 402 | − { 0x7FF0, 0x08 }, | |
| 403 | − { 0x7FF1, 0x0F }, | |
| 404 | − { 0x7FF2, 0x08 }, | |
| 405 | − { 0x7FF3, 0x1B }, | |
| 406 | − { 0x7FF4, 0x23 }, | |
| 407 | − { 0x7FF5, 0x60 }, | |
| 408 | − { 0x7FF6, 0x00 }, | |
| 409 | − { 0x7FF7, 0x01 }, | |
| 410 | − { 0x7FF8, 0x00 }, | |
| 411 | − { 0x7FF9, 0x78 }, | |
| 412 | − { 0x7FFA, 0x00 }, | |
| 413 | − { 0x7FFB, 0x00 }, | |
| 414 | − { 0x7FFC, 0x00 }, | |
| 415 | − { 0x7FFD, 0x00 }, | |
| 416 | − { 0x7FFE, 0x00 }, | |
| 417 | − { 0x7FFF, 0x03 }, | |
| 418 | − { 0x7F76, 0x03 }, | |
| 419 | − { 0x7F77, 0xFE }, | |
| 420 | − { 0x7FA8, 0x03 }, | |
| 421 | − { 0x7FA9, 0xFE }, | |
| 422 | − { 0x7B24, 0x81 }, | |
| 423 | − { 0x7B25, 0x00 }, | |
| 424 | − { 0x6564, 0x07 }, | |
| 425 | − { 0x6B0D, 0x41 }, | |
| 426 | − { 0x653D, 0x04 }, | |
| 427 | − { 0x6B05, 0x8C }, | |
| 428 | − { 0x6B06, 0xF9 }, | |
| 429 | − { 0x6B08, 0x65 }, | |
| 430 | − { 0x6B09, 0xFC }, | |
| 431 | − { 0x6B0A, 0xCF }, | |
| 432 | − { 0x6B0B, 0xD2 }, | |
| 433 | − { 0x6700, 0x0E }, | |
| 434 | − { 0x6707, 0x0E }, | |
| 435 | − { 0x9104, 0x00 }, | |
| 436 | − { 0x4648, 0x7F }, | |
| 437 | − { 0x7420, 0x00 }, | |
| 438 | − { 0x7421, 0x1C }, | |
| 439 | − { 0x7422, 0x00 }, | |
| 440 | − { 0x7423, 0xD7 }, | |
| 441 | − { 0x5F04, 0x00 }, | |
| 442 | − { 0x5F05, 0xED }, | |
| 443 | − { 0x0112, 0x0A }, | |
| 444 | − { 0x0113, 0x0A }, | |
| 445 | − { 0x0114, 0x03 }, | |
| 446 | − { 0x0342, 0x14 }, | |
| 447 | − { 0x0343, 0xE8 }, | |
| 448 | − { 0x0340, 0x03 }, | |
| 449 | − { 0x0341, 0x4C }, | |
| 450 | − { 0x0344, 0x00 }, | |
| 451 | − { 0x0345, 0x00 }, | |
| 452 | − { 0x0346, 0x00 }, | |
| 453 | − { 0x0347, 0x00 }, | |
| 454 | − { 0x0348, 0x10 }, | |
| 455 | − { 0x0349, 0x6F }, | |
| 456 | − { 0x034A, 0x0C }, | |
| 457 | − { 0x034B, 0x2E }, | |
| 458 | − { 0x0381, 0x01 }, | |
| 459 | − { 0x0383, 0x01 }, | |
| 460 | − { 0x0385, 0x01 }, | |
| 461 | − { 0x0387, 0x01 }, | |
| 462 | − { 0x0900, 0x01 }, | |
| 463 | − { 0x0901, 0x14 }, | |
| 464 | − { 0x0401, 0x01 }, | |
| 465 | − { 0x0404, 0x00 }, | |
| 466 | − { 0x0405, 0x40 }, | |
| 467 | − { 0x0408, 0x00 }, | |
| 468 | − { 0x0409, 0x06 }, | |
| 469 | − { 0x040A, 0x00 }, | |
| 470 | − { 0x040B, 0x00 }, | |
| 471 | − { 0x040C, 0x10 }, | |
| 472 | − { 0x040D, 0x64 }, | |
| 473 | − { 0x040E, 0x03 }, | |
| 474 | − { 0x040F, 0x0C }, | |
| 475 | − { 0x3038, 0x00 }, | |
| 476 | − { 0x303A, 0x00 }, | |
| 477 | − { 0x303B, 0x10 }, | |
| 478 | − { 0x300D, 0x00 }, | |
| 479 | − { 0x034C, 0x04 }, | |
| 480 | − { 0x034D, 0x18 }, | |
| 481 | − { 0x034E, 0x03 }, | |
| 482 | − { 0x034F, 0x0C }, | |
| 483 | − { 0x0350, 0x01 }, | |
| 484 | − { 0x0202, 0x03 }, | |
| 485 | − { 0x0203, 0x42 }, | |
| 486 | − { 0x0204, 0x00 }, | |
| 487 | − { 0x0205, 0x00 }, | |
| 488 | − { 0x020E, 0x01 }, | |
| 489 | − { 0x020F, 0x00 }, | |
| 490 | − { 0x0210, 0x01 }, | |
| 491 | − { 0x0211, 0x00 }, | |
| 492 | − { 0x0212, 0x01 }, | |
| 493 | − { 0x0213, 0x00 }, | |
| 494 | − { 0x0214, 0x01 }, | |
| 495 | − { 0x0215, 0x00 }, | |
| 496 | − { 0x7BCD, 0x00 }, | |
| 497 | − { 0x94DC, 0x20 }, | |
| 498 | − { 0x94DD, 0x20 }, | |
| 499 | − { 0x94DE, 0x20 }, | |
| 500 | − { 0x95DC, 0x20 }, | |
| 501 | − { 0x95DD, 0x20 }, | |
| 502 | − { 0x95DE, 0x20 }, | |
| 503 | − { 0x7FB0, 0x00 }, | |
| 504 | − { 0x9010, 0x3E }, | |
| 505 | − { 0x9419, 0x50 }, | |
| 506 | − { 0x941B, 0x50 }, | |
| 507 | − { 0x9519, 0x50 }, | |
| 508 | − { 0x951B, 0x50 }, | |
| 509 | − { 0x3030, 0x00 }, | |
| 510 | − { 0x3032, 0x00 }, | |
| 511 | − { 0x0220, 0x00 }, | |
| 410 | +static const struct cci_reg_sequence mode_2104_1560_regs[] = { | |
| 411 | + {IMX258_REG_BINNING_MODE, 1}, | |
| 412 | + {IMX258_REG_BINNING_TYPE_V, 0x12}, | |
| 413 | + {IMX258_REG_SCALE_MODE, 1}, | |
| 414 | + {IMX258_REG_SCALE_M, 32}, | |
| 415 | + {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 1560}, | |
| 416 | + {IMX258_REG_X_OUT_SIZE, 2104}, | |
| 417 | + {IMX258_REG_Y_OUT_SIZE, 1560}, | |
| 418 | +}; | |
| 419 | + | |
| 420 | +static const struct cci_reg_sequence mode_1048_780_regs[] = { | |
| 421 | + {IMX258_REG_BINNING_MODE, 1}, | |
| 422 | + {IMX258_REG_BINNING_TYPE_V, 0x14}, | |
| 423 | + {IMX258_REG_SCALE_MODE, 1}, | |
| 424 | + {IMX258_REG_SCALE_M, 64}, | |
| 425 | + {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 780}, | |
| 426 | + {IMX258_REG_X_OUT_SIZE, 1048}, | |
| 427 | + {IMX258_REG_Y_OUT_SIZE, 780}, | |
| 428 | +}; | |
| 429 | + | |
| 430 | +struct imx258_variant_cfg { | |
| 431 | + const struct cci_reg_sequence *regs; | |
| 432 | + unsigned int num_regs; | |
| 433 | +}; | |
| 434 | + | |
| 435 | +static const struct cci_reg_sequence imx258_cfg_regs[] = { | |
| 436 | + { CCI_REG8(0x3052), 0x00 }, | |
| 437 | + { CCI_REG8(0x4E21), 0x14 }, | |
| 438 | + { CCI_REG8(0x7B25), 0x00 }, | |
| 439 | +}; | |
| 440 | + | |
| 441 | +static const struct imx258_variant_cfg imx258_cfg = { | |
| 442 | + .regs = imx258_cfg_regs, | |
| 443 | + .num_regs = ARRAY_SIZE(imx258_cfg_regs), | |
| 444 | +}; | |
| 445 | + | |
| 446 | +static const struct cci_reg_sequence imx258_pdaf_cfg_regs[] = { | |
| 447 | + { CCI_REG8(0x3052), 0x01 }, | |
| 448 | + { CCI_REG8(0x4E21), 0x10 }, | |
| 449 | + { CCI_REG8(0x7B25), 0x01 }, | |
| 450 | +}; | |
| 451 | + | |
| 452 | +static const struct imx258_variant_cfg imx258_pdaf_cfg = { | |
| 453 | + .regs = imx258_pdaf_cfg_regs, | |
| 454 | + .num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs), | |
| 455 | +}; | |
| 456 | + | |
| 457 | +/* | |
| 458 | + * The supported formats. | |
| 459 | + * This table MUST contain 4 entries per format, to cover the various flip | |
| 460 | + * combinations in the order | |
| 461 | + * - no flip | |
| 462 | + * - h flip | |
| 463 | + * - v flip | |
| 464 | + * - h&v flips | |
| 465 | + */ | |
| 466 | +static const u32 codes[] = { | |
| 467 | + /* 10-bit modes. */ | |
| 468 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 469 | + MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 470 | + MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 471 | + MEDIA_BUS_FMT_SBGGR10_1X10 | |
| 512 | 472 | }; |
| 513 | 473 | |
| 514 | 474 | static const char * const imx258_test_pattern_menu[] = { |
| @@ -519,9 +479,15 @@ static const char * const imx258_test_pattern_menu[] = { · 4 unmodified lines | ||
| 519 | 479 | "Pseudorandom Sequence (PN9)", |
| 520 | 480 | }; |
| 521 | 481 | |
| 522 | −/* Configurations for supported link frequencies */ | |
| 523 | −#define IMX258_LINK_FREQ_634MHZ 633600000ULL | |
| 524 | −#define IMX258_LINK_FREQ_320MHZ 320000000ULL | |
| 482 | +/* regulator supplies */ | |
| 483 | +static const char * const imx258_supply_name[] = { | |
| 484 | + /* Supplies can be enabled in any order */ | |
| 485 | + "vana", /* Analog (2.8V) supply */ | |
| 486 | + "vdig", /* Digital Core (1.2V) supply */ | |
| 487 | + "vif", /* IF (1.8V) supply */ | |
| 488 | +}; | |
| 489 | + | |
| 490 | +#define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name) | |
| 525 | 491 | |
| 526 | 492 | enum { |
| 527 | 493 | IMX258_LINK_FREQ_1267MBPS, |
| @@ -529,37 +495,96 @@ enum { · 1 unmodified line | ||
| 529 | 495 | }; |
| 530 | 496 | |
| 531 | 497 | /* |
| 532 | − * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample | |
| 533 | − * data rate => double data rate; number of lanes => 4; bits per pixel => 10 | |
| 498 | + * Pixel rate does not necessarily relate to link frequency on this sensor as | |
| 499 | + * there is a FIFO between the pixel array pipeline and the MIPI serializer. | |
| 500 | + * The recommendation from Sony is that the pixel array is always run with a | |
| 501 | + * line length of 5352 pixels, which means that there is a large amount of | |
| 502 | + * blanking time for the 1048x780 mode. There is no need to replicate this | |
| 503 | + * blanking on the CSI2 bus, and the configuration of register 0x0301 allows the | |
| 504 | + * divider to be altered. | |
| 505 | + * | |
| 506 | + * The actual factor between link frequency and pixel rate is in the | |
| 507 | + * imx258_link_cfg, so use this to convert between the two. | |
| 508 | + * bits per pixel being 10, and D-PHY being DDR is assumed by this function, so | |
| 509 | + * the value is only the combination of number of lanes and pixel clock divider. | |
| 534 | 510 | */ |
| 535 | −static u64 link_freq_to_pixel_rate(u64 f) | |
| 511 | +static u64 link_freq_to_pixel_rate(u64 f, const struct imx258_link_cfg *link_cfg) | |
| 536 | 512 | { |
| 537 | − f *= 2 * 4; | |
| 513 | + f *= 2 * link_cfg->lf_to_pix_rate_factor; | |
| 538 | 514 | do_div(f, 10); |
| 539 | 515 | |
| 540 | 516 | return f; |
| 541 | 517 | } |
| 542 | 518 | |
| 543 | 519 | /* Menu items for LINK_FREQ V4L2 control */ |
| 544 | −static const s64 link_freq_menu_items[] = { | |
| 545 | − IMX258_LINK_FREQ_634MHZ, | |
| 546 | − IMX258_LINK_FREQ_320MHZ, | |
| 520 | +/* Configurations for supported link frequencies */ | |
| 521 | +static const s64 link_freq_menu_items_19_2[] = { | |
| 522 | + 633600000ULL, | |
| 523 | + 320000000ULL, | |
| 547 | 524 | }; |
| 548 | 525 | |
| 526 | +static const s64 link_freq_menu_items_24[] = { | |
| 527 | + 636000000ULL, | |
| 528 | + 321000000ULL, | |
| 529 | +}; | |
| 530 | + | |
| 531 | +#define REGS(_list) { .num_of_regs = ARRAY_SIZE(_list), .regs = _list, } | |
| 532 | + | |
| 549 | 533 | /* Link frequency configs */ |
| 550 | −static const struct imx258_link_freq_config link_freq_configs[] = { | |
| 534 | +static const struct imx258_link_freq_config link_freq_configs_19_2[] = { | |
| 551 | 535 | [IMX258_LINK_FREQ_1267MBPS] = { |
| 552 | 536 | .pixels_per_line = IMX258_PPL_DEFAULT, |
| 553 | − .reg_list = { | |
| 554 | − .num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps), | |
| 555 | − .regs = mipi_data_rate_1267mbps, | |
| 537 | + .link_cfg = { | |
| 538 | + [IMX258_2_LANE_MODE] = { | |
| 539 | + .lf_to_pix_rate_factor = 2 * 2, | |
| 540 | + .reg_list = REGS(mipi_1267mbps_19_2mhz_2l), | |
| 541 | + }, | |
| 542 | + [IMX258_4_LANE_MODE] = { | |
| 543 | + .lf_to_pix_rate_factor = 4, | |
| 544 | + .reg_list = REGS(mipi_1267mbps_19_2mhz_4l), | |
| 545 | + }, | |
| 556 | 546 | } |
| 557 | 547 | }, |
| 558 | 548 | [IMX258_LINK_FREQ_640MBPS] = { |
| 559 | 549 | .pixels_per_line = IMX258_PPL_DEFAULT, |
| 560 | − .reg_list = { | |
| 561 | − .num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps), | |
| 562 | − .regs = mipi_data_rate_640mbps, | |
| 550 | + .link_cfg = { | |
| 551 | + [IMX258_2_LANE_MODE] = { | |
| 552 | + .lf_to_pix_rate_factor = 2, | |
| 553 | + .reg_list = REGS(mipi_640mbps_19_2mhz_2l), | |
| 554 | + }, | |
| 555 | + [IMX258_4_LANE_MODE] = { | |
| 556 | + .lf_to_pix_rate_factor = 4, | |
| 557 | + .reg_list = REGS(mipi_640mbps_19_2mhz_4l), | |
| 558 | + }, | |
| 559 | + } | |
| 560 | + }, | |
| 561 | +}; | |
| 562 | + | |
| 563 | +static const struct imx258_link_freq_config link_freq_configs_24[] = { | |
| 564 | + [IMX258_LINK_FREQ_1267MBPS] = { | |
| 565 | + .pixels_per_line = IMX258_PPL_DEFAULT, | |
| 566 | + .link_cfg = { | |
| 567 | + [IMX258_2_LANE_MODE] = { | |
| 568 | + .lf_to_pix_rate_factor = 2, | |
| 569 | + .reg_list = REGS(mipi_1272mbps_24mhz_2l), | |
| 570 | + }, | |
| 571 | + [IMX258_4_LANE_MODE] = { | |
| 572 | + .lf_to_pix_rate_factor = 4, | |
| 573 | + .reg_list = REGS(mipi_1272mbps_24mhz_4l), | |
| 574 | + }, | |
| 575 | + } | |
| 576 | + }, | |
| 577 | + [IMX258_LINK_FREQ_640MBPS] = { | |
| 578 | + .pixels_per_line = IMX258_PPL_DEFAULT, | |
| 579 | + .link_cfg = { | |
| 580 | + [IMX258_2_LANE_MODE] = { | |
| 581 | + .lf_to_pix_rate_factor = 2 * 2, | |
| 582 | + .reg_list = REGS(mipi_642mbps_24mhz_2l), | |
| 583 | + }, | |
| 584 | + [IMX258_4_LANE_MODE] = { | |
| 585 | + .lf_to_pix_rate_factor = 4, | |
| 586 | + .reg_list = REGS(mipi_642mbps_24mhz_4l), | |
| 587 | + }, | |
| 563 | 588 | } |
| 564 | 589 | }, |
| 565 | 590 | }; |
| @@ -568,14 +593,20 @@ static const struct imx258_link_freq_config link_freq_configs[] = { · 2 unmodified lines | ||
| 568 | 593 | static const struct imx258_mode supported_modes[] = { |
| 569 | 594 | { |
| 570 | 595 | .width = 4208, |
| 571 | − .height = 3118, | |
| 596 | + .height = 3120, | |
| 572 | 597 | .vts_def = IMX258_VTS_30FPS, |
| 573 | 598 | .vts_min = IMX258_VTS_30FPS, |
| 574 | 599 | .reg_list = { |
| 575 | − .num_of_regs = ARRAY_SIZE(mode_4208x3118_regs), | |
| 576 | − .regs = mode_4208x3118_regs, | |
| 600 | + .num_of_regs = ARRAY_SIZE(mode_4208x3120_regs), | |
| 601 | + .regs = mode_4208x3120_regs, | |
| 577 | 602 | }, |
| 578 | 603 | .link_freq_index = IMX258_LINK_FREQ_1267MBPS, |
| 604 | + .crop = { | |
| 605 | + .left = IMX258_PIXEL_ARRAY_LEFT, | |
| 606 | + .top = IMX258_PIXEL_ARRAY_TOP, | |
| 607 | + .width = 4208, | |
| 608 | + .height = 3120, | |
| 609 | + }, | |
| 579 | 610 | }, |
| 580 | 611 | { |
| 581 | 612 | .width = 2104, |
| @@ -587,6 +618,12 @@ static const struct imx258_mode supported_modes[] = { · 5 unmodified lines | ||
| 587 | 618 | .regs = mode_2104_1560_regs, |
| 588 | 619 | }, |
| 589 | 620 | .link_freq_index = IMX258_LINK_FREQ_640MBPS, |
| 621 | + .crop = { | |
| 622 | + .left = IMX258_PIXEL_ARRAY_LEFT, | |
| 623 | + .top = IMX258_PIXEL_ARRAY_TOP, | |
| 624 | + .width = 4208, | |
| 625 | + .height = 3120, | |
| 626 | + }, | |
| 590 | 627 | }, |
| 591 | 628 | { |
| 592 | 629 | .width = 1048, |
| @@ -598,12 +635,21 @@ static const struct imx258_mode supported_modes[] = { · 5 unmodified lines | ||
| 598 | 635 | .regs = mode_1048_780_regs, |
| 599 | 636 | }, |
| 600 | 637 | .link_freq_index = IMX258_LINK_FREQ_640MBPS, |
| 638 | + .crop = { | |
| 639 | + .left = IMX258_PIXEL_ARRAY_LEFT, | |
| 640 | + .top = IMX258_PIXEL_ARRAY_TOP, | |
| 641 | + .width = 4208, | |
| 642 | + .height = 3120, | |
| 643 | + }, | |
| 601 | 644 | }, |
| 602 | 645 | }; |
| 603 | 646 | |
| 604 | 647 | struct imx258 { |
| 605 | 648 | struct v4l2_subdev sd; |
| 606 | 649 | struct media_pad pad; |
| 650 | + struct regmap *regmap; | |
| 651 | + | |
| 652 | + const struct imx258_variant_cfg *variant_cfg; | |
| 607 | 653 | |
| 608 | 654 | struct v4l2_ctrl_handler ctrl_handler; |
| 609 | 655 | /* V4L2 Controls */ |
| @@ -612,10 +658,18 @@ struct imx258 { · 2 unmodified lines | ||
| 612 | 658 | struct v4l2_ctrl *vblank; |
| 613 | 659 | struct v4l2_ctrl *hblank; |
| 614 | 660 | struct v4l2_ctrl *exposure; |
| 661 | + struct v4l2_ctrl *hflip; | |
| 662 | + struct v4l2_ctrl *vflip; | |
| 615 | 663 | |
| 616 | 664 | /* Current mode */ |
| 617 | 665 | const struct imx258_mode *cur_mode; |
| 618 | 666 | |
| 667 | + unsigned long link_freq_bitmap; | |
| 668 | + const struct imx258_link_freq_config *link_freq_configs; | |
| 669 | + const s64 *link_freq_menu_items; | |
| 670 | + unsigned int lane_mode_idx; | |
| 671 | + unsigned int csi2_flags; | |
| 672 | + | |
| 619 | 673 | /* |
| 620 | 674 | * Mutex for serialized access: |
| 621 | 675 | * Protect sensor module set pad format and start/stop streaming safely. |
| @@ -623,6 +677,7 @@ struct imx258 { · 1 unmodified line | ||
| 623 | 677 | struct mutex mutex; |
| 624 | 678 | |
| 625 | 679 | struct clk *clk; |
| 680 | + struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES]; | |
| 626 | 681 | }; |
| 627 | 682 | |
| 628 | 683 | static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd) |
| @@ -630,120 +685,66 @@ static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd) · 1 unmodified line | ||
| 630 | 685 | return container_of(_sd, struct imx258, sd); |
| 631 | 686 | } |
| 632 | 687 | |
| 633 | −/* Read registers up to 2 at a time */ | |
| 634 | −static int imx258_read_reg(struct imx258 *imx258, u16 reg, u32 len, u32 *val) | |
| 688 | +/* Get bayer order based on flip setting. */ | |
| 689 | +static u32 imx258_get_format_code(const struct imx258 *imx258) | |
| 635 | 690 | { |
| 636 | − struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 637 | − struct i2c_msg msgs[2]; | |
| 638 | − u8 addr_buf[2] = { reg >> 8, reg & 0xff }; | |
| 639 | − u8 data_buf[4] = { 0, }; | |
| 640 | − int ret; | |
| 641 | − | |
| 642 | − if (len > 4) | |
| 643 | − return -EINVAL; | |
| 644 | − | |
| 645 | − /* Write register address */ | |
| 646 | − msgs[0].addr = client->addr; | |
| 647 | − msgs[0].flags = 0; | |
| 648 | − msgs[0].len = ARRAY_SIZE(addr_buf); | |
| 649 | − msgs[0].buf = addr_buf; | |
| 650 | − | |
| 651 | − /* Read data from register */ | |
| 652 | − msgs[1].addr = client->addr; | |
| 653 | − msgs[1].flags = I2C_M_RD; | |
| 654 | − msgs[1].len = len; | |
| 655 | − msgs[1].buf = &data_buf[4 - len]; | |
| 656 | − | |
| 657 | − ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); | |
| 658 | − if (ret != ARRAY_SIZE(msgs)) | |
| 659 | − return -EIO; | |
| 660 | − | |
| 661 | − *val = get_unaligned_be32(data_buf); | |
| 662 | − | |
| 663 | − return 0; | |
| 664 | −} | |
| 665 | − | |
| 666 | −/* Write registers up to 2 at a time */ | |
| 667 | −static int imx258_write_reg(struct imx258 *imx258, u16 reg, u32 len, u32 val) | |
| 668 | −{ | |
| 669 | − struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 670 | − u8 buf[6]; | |
| 671 | − | |
| 672 | − if (len > 4) | |
| 673 | − return -EINVAL; | |
| 674 | − | |
| 675 | − put_unaligned_be16(reg, buf); | |
| 676 | − put_unaligned_be32(val << (8 * (4 - len)), buf + 2); | |
| 677 | − if (i2c_master_send(client, buf, len + 2) != len + 2) | |
| 678 | − return -EIO; | |
| 679 | − | |
| 680 | − return 0; | |
| 681 | −} | |
| 682 | − | |
| 683 | −/* Write a list of registers */ | |
| 684 | −static int imx258_write_regs(struct imx258 *imx258, | |
| 685 | − const struct imx258_reg *regs, u32 len) | |
| 686 | −{ | |
| 687 | − struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | |
| 688 | 691 | unsigned int i; |
| 689 | − int ret; | |
| 690 | 692 | |
| 691 | − for (i = 0; i < len; i++) { | |
| 692 | − ret = imx258_write_reg(imx258, regs[i].address, 1, | |
| 693 | − regs[i].val); | |
| 694 | − if (ret) { | |
| 695 | − dev_err_ratelimited( | |
| 696 | − &client->dev, | |
| 697 | − "Failed to write reg 0x%4.4x. error = %d\n", | |
| 698 | − regs[i].address, ret); | |
| 693 | + lockdep_assert_held(&imx258->mutex); | |
| 699 | 694 | |
| 700 | − return ret; | |
| 701 | − } | |
| 702 | − } | |
| 695 | + i = (imx258->vflip->val ? 2 : 0) | | |
| 696 | + (imx258->hflip->val ? 1 : 0); | |
| 703 | 697 | |
| 704 | − return 0; | |
| 698 | + return codes[i]; | |
| 705 | 699 | } |
| 706 | 700 | |
| 707 | 701 | /* Open sub-device */ |
| 708 | 702 | static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
| 709 | 703 | { |
| 704 | + struct imx258 *imx258 = to_imx258(sd); | |
| 710 | 705 | struct v4l2_mbus_framefmt *try_fmt = |
| 711 | 706 | v4l2_subdev_state_get_format(fh->state, 0); |
| 707 | + struct v4l2_rect *try_crop; | |
| 712 | 708 | |
| 713 | 709 | /* Initialize try_fmt */ |
| 714 | 710 | try_fmt->width = supported_modes[0].width; |
| 715 | 711 | try_fmt->height = supported_modes[0].height; |
| 716 | − try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 712 | + try_fmt->code = imx258_get_format_code(imx258); | |
| 717 | 713 | try_fmt->field = V4L2_FIELD_NONE; |
| 718 | 714 | |
| 715 | + /* Initialize try_crop */ | |
| 716 | + try_crop = v4l2_subdev_state_get_crop(fh->state, 0); | |
| 717 | + try_crop->left = IMX258_PIXEL_ARRAY_LEFT; | |
| 718 | + try_crop->top = IMX258_PIXEL_ARRAY_TOP; | |
| 719 | + try_crop->width = IMX258_PIXEL_ARRAY_WIDTH; | |
| 720 | + try_crop->height = IMX258_PIXEL_ARRAY_HEIGHT; | |
| 721 | + | |
| 719 | 722 | return 0; |
| 720 | 723 | } |
| 721 | 724 | |
| 722 | −static int imx258_update_digital_gain(struct imx258 *imx258, u32 len, u32 val) | |
| 725 | +static int imx258_update_digital_gain(struct imx258 *imx258, u32 val) | |
| 723 | 726 | { |
| 724 | − int ret; | |
| 727 | + int ret = 0; | |
| 725 | 728 | |
| 726 | − ret = imx258_write_reg(imx258, IMX258_REG_GR_DIGITAL_GAIN, | |
| 727 | − IMX258_REG_VALUE_16BIT, | |
| 728 | − val); | |
| 729 | − if (ret) | |
| 730 | − return ret; | |
| 731 | − ret = imx258_write_reg(imx258, IMX258_REG_GB_DIGITAL_GAIN, | |
| 732 | − IMX258_REG_VALUE_16BIT, | |
| 733 | − val); | |
| 734 | − if (ret) | |
| 735 | − return ret; | |
| 736 | − ret = imx258_write_reg(imx258, IMX258_REG_R_DIGITAL_GAIN, | |
| 737 | − IMX258_REG_VALUE_16BIT, | |
| 738 | − val); | |
| 739 | − if (ret) | |
| 740 | − return ret; | |
| 741 | − ret = imx258_write_reg(imx258, IMX258_REG_B_DIGITAL_GAIN, | |
| 742 | − IMX258_REG_VALUE_16BIT, | |
| 743 | − val); | |
| 744 | − if (ret) | |
| 745 | − return ret; | |
| 746 | − return 0; | |
| 729 | + cci_write(imx258->regmap, IMX258_REG_GR_DIGITAL_GAIN, val, &ret); | |
| 730 | + cci_write(imx258->regmap, IMX258_REG_GB_DIGITAL_GAIN, val, &ret); | |
| 731 | + cci_write(imx258->regmap, IMX258_REG_R_DIGITAL_GAIN, val, &ret); | |
| 732 | + cci_write(imx258->regmap, IMX258_REG_B_DIGITAL_GAIN, val, &ret); | |
| 733 | + | |
| 734 | + return ret; | |
| 735 | +} | |
| 736 | + | |
| 737 | +static void imx258_adjust_exposure_range(struct imx258 *imx258) | |
| 738 | +{ | |
| 739 | + int exposure_max, exposure_def; | |
| 740 | + | |
| 741 | + /* Honour the VBLANK limits when setting exposure. */ | |
| 742 | + exposure_max = imx258->cur_mode->height + imx258->vblank->val - | |
| 743 | + IMX258_EXPOSURE_OFFSET; | |
| 744 | + exposure_def = min(exposure_max, imx258->exposure->val); | |
| 745 | + __v4l2_ctrl_modify_range(imx258->exposure, imx258->exposure->minimum, | |
| 746 | + exposure_max, imx258->exposure->step, | |
| 747 | + exposure_def); | |
| 747 | 748 | } |
| 748 | 749 | |
| 749 | 750 | static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) |
| @@ -753,6 +754,13 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) · 3 unmodified lines | ||
| 753 | 754 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 754 | 755 | int ret = 0; |
| 755 | 756 | |
| 757 | + /* | |
| 758 | + * The VBLANK control may change the limits of usable exposure, so check | |
| 759 | + * and adjust if necessary. | |
| 760 | + */ | |
| 761 | + if (ctrl->id == V4L2_CID_VBLANK) | |
| 762 | + imx258_adjust_exposure_range(imx258); | |
| 763 | + | |
| 756 | 764 | /* |
| 757 | 765 | * Applying V4L2 control value only happens |
| 758 | 766 | * when power is up for streaming |
| @@ -762,44 +770,46 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) · 3 unmodified lines | ||
| 762 | 770 | |
| 763 | 771 | switch (ctrl->id) { |
| 764 | 772 | case V4L2_CID_ANALOGUE_GAIN: |
| 765 | − ret = imx258_write_reg(imx258, IMX258_REG_ANALOG_GAIN, | |
| 766 | − IMX258_REG_VALUE_16BIT, | |
| 767 | − ctrl->val); | |
| 773 | + ret = cci_write(imx258->regmap, IMX258_REG_ANALOG_GAIN, | |
| 774 | + ctrl->val, NULL); | |
| 768 | 775 | break; |
| 769 | 776 | case V4L2_CID_EXPOSURE: |
| 770 | − ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE, | |
| 771 | − IMX258_REG_VALUE_16BIT, | |
| 772 | − ctrl->val); | |
| 777 | + ret = cci_write(imx258->regmap, IMX258_REG_EXPOSURE, | |
| 778 | + ctrl->val, NULL); | |
| 773 | 779 | break; |
| 774 | 780 | case V4L2_CID_DIGITAL_GAIN: |
| 775 | − ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT, | |
| 776 | − ctrl->val); | |
| 781 | + ret = imx258_update_digital_gain(imx258, ctrl->val); | |
| 777 | 782 | break; |
| 778 | 783 | case V4L2_CID_TEST_PATTERN: |
| 779 | − ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN, | |
| 780 | − IMX258_REG_VALUE_16BIT, | |
| 781 | − ctrl->val); | |
| 782 | − ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, | |
| 783 | − IMX258_REG_VALUE_08BIT, | |
| 784 | − !ctrl->val ? REG_CONFIG_MIRROR_FLIP : | |
| 785 | − REG_CONFIG_FLIP_TEST_PATTERN); | |
| 784 | + ret = cci_write(imx258->regmap, IMX258_REG_TEST_PATTERN, | |
| 785 | + ctrl->val, NULL); | |
| 786 | 786 | break; |
| 787 | 787 | case V4L2_CID_WIDE_DYNAMIC_RANGE: |
| 788 | 788 | if (!ctrl->val) { |
| 789 | − ret = imx258_write_reg(imx258, IMX258_REG_HDR, | |
| 790 | − IMX258_REG_VALUE_08BIT, | |
| 791 | − IMX258_HDR_RATIO_MIN); | |
| 789 | + ret = cci_write(imx258->regmap, IMX258_REG_HDR, | |
| 790 | + IMX258_HDR_RATIO_MIN, NULL); | |
| 792 | 791 | } else { |
| 793 | − ret = imx258_write_reg(imx258, IMX258_REG_HDR, | |
| 794 | − IMX258_REG_VALUE_08BIT, | |
| 795 | − IMX258_HDR_ON); | |
| 792 | + ret = cci_write(imx258->regmap, IMX258_REG_HDR, | |
| 793 | + IMX258_HDR_ON, NULL); | |
| 796 | 794 | if (ret) |
| 797 | 795 | break; |
| 798 | − ret = imx258_write_reg(imx258, IMX258_REG_HDR_RATIO, | |
| 799 | − IMX258_REG_VALUE_08BIT, | |
| 800 | − BIT(IMX258_HDR_RATIO_MAX)); | |
| 796 | + ret = cci_write(imx258->regmap, IMX258_REG_HDR_RATIO, | |
| 797 | + BIT(IMX258_HDR_RATIO_MAX), NULL); | |
| 801 | 798 | } |
| 802 | 799 | break; |
| 800 | + case V4L2_CID_VBLANK: | |
| 801 | + ret = cci_write(imx258->regmap, IMX258_REG_FRM_LENGTH_LINES, | |
| 802 | + imx258->cur_mode->height + ctrl->val, NULL); | |
| 803 | + break; | |
| 804 | + case V4L2_CID_VFLIP: | |
| 805 | + case V4L2_CID_HFLIP: | |
| 806 | + ret = cci_write(imx258->regmap, REG_MIRROR_FLIP_CONTROL, | |
| 807 | + (imx258->hflip->val ? | |
| 808 | + REG_CONFIG_MIRROR_HFLIP : 0) | | |
| 809 | + (imx258->vflip->val ? | |
| 810 | + REG_CONFIG_MIRROR_VFLIP : 0), | |
| 811 | + NULL); | |
| 812 | + break; | |
| 803 | 813 | default: |
| 804 | 814 | dev_info(&client->dev, |
| 805 | 815 | "ctrl(id:0x%x,val:0x%x) is not handled\n", |
| @@ -821,11 +831,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd, · 15 unmodified lines | ||
| 821 | 831 | struct v4l2_subdev_state *sd_state, |
| 822 | 832 | struct v4l2_subdev_mbus_code_enum *code) |
| 823 | 833 | { |
| 824 | − /* Only one bayer order(GRBG) is supported */ | |
| 834 | + struct imx258 *imx258 = to_imx258(sd); | |
| 835 | + | |
| 836 | + /* Only one bayer format (10 bit) is supported */ | |
| 825 | 837 | if (code->index > 0) |
| 826 | 838 | return -EINVAL; |
| 827 | 839 | |
| 828 | − code->code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 840 | + code->code = imx258_get_format_code(imx258); | |
| 829 | 841 | |
| 830 | 842 | return 0; |
| 831 | 843 | } |
| @@ -834,10 +846,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, · 2 unmodified lines | ||
| 834 | 846 | struct v4l2_subdev_state *sd_state, |
| 835 | 847 | struct v4l2_subdev_frame_size_enum *fse) |
| 836 | 848 | { |
| 849 | + struct imx258 *imx258 = to_imx258(sd); | |
| 837 | 850 | if (fse->index >= ARRAY_SIZE(supported_modes)) |
| 838 | 851 | return -EINVAL; |
| 839 | 852 | |
| 840 | − if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) | |
| 853 | + if (fse->code != imx258_get_format_code(imx258)) | |
| 841 | 854 | return -EINVAL; |
| 842 | 855 | |
| 843 | 856 | fse->min_width = supported_modes[fse->index].width; |
| @@ -848,12 +861,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, · 4 unmodified lines | ||
| 848 | 861 | return 0; |
| 849 | 862 | } |
| 850 | 863 | |
| 851 | −static void imx258_update_pad_format(const struct imx258_mode *mode, | |
| 864 | +static void imx258_update_pad_format(struct imx258 *imx258, | |
| 865 | + const struct imx258_mode *mode, | |
| 852 | 866 | struct v4l2_subdev_format *fmt) |
| 853 | 867 | { |
| 854 | 868 | fmt->format.width = mode->width; |
| 855 | 869 | fmt->format.height = mode->height; |
| 856 | − fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 870 | + fmt->format.code = imx258_get_format_code(imx258); | |
| 857 | 871 | fmt->format.field = V4L2_FIELD_NONE; |
| 858 | 872 | } |
| 859 | 873 | |
| @@ -865,7 +879,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258, · 5 unmodified lines | ||
| 865 | 879 | fmt->format = *v4l2_subdev_state_get_format(sd_state, |
| 866 | 880 | fmt->pad); |
| 867 | 881 | else |
| 868 | − imx258_update_pad_format(imx258->cur_mode, fmt); | |
| 882 | + imx258_update_pad_format(imx258, imx258->cur_mode, fmt); | |
| 869 | 883 | |
| 870 | 884 | return 0; |
| 871 | 885 | } |
| @@ -889,8 +903,10 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 17 unmodified lines | ||
| 889 | 903 | struct v4l2_subdev_format *fmt) |
| 890 | 904 | { |
| 891 | 905 | struct imx258 *imx258 = to_imx258(sd); |
| 892 | − const struct imx258_mode *mode; | |
| 906 | + const struct imx258_link_freq_config *link_freq_cfgs; | |
| 907 | + const struct imx258_link_cfg *link_cfg; | |
| 893 | 908 | struct v4l2_mbus_framefmt *framefmt; |
| 909 | + const struct imx258_mode *mode; | |
| 894 | 910 | s32 vblank_def; |
| 895 | 911 | s32 vblank_min; |
| 896 | 912 | s64 h_blank; |
| @@ -899,13 +915,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 2 unmodified lines | ||
| 899 | 915 | |
| 900 | 916 | mutex_lock(&imx258->mutex); |
| 901 | 917 | |
| 902 | − /* Only one raw bayer(GBRG) order is supported */ | |
| 903 | − fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | |
| 918 | + fmt->format.code = imx258_get_format_code(imx258); | |
| 904 | 919 | |
| 905 | 920 | mode = v4l2_find_nearest_size(supported_modes, |
| 906 | 921 | ARRAY_SIZE(supported_modes), width, height, |
| 907 | 922 | fmt->format.width, fmt->format.height); |
| 908 | − imx258_update_pad_format(mode, fmt); | |
| 923 | + imx258_update_pad_format(imx258, mode, fmt); | |
| 909 | 924 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 910 | 925 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
| 911 | 926 | *framefmt = fmt->format; |
| @@ -913,9 +928,14 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 1 unmodified line | ||
| 913 | 928 | imx258->cur_mode = mode; |
| 914 | 929 | __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); |
| 915 | 930 | |
| 916 | − link_freq = link_freq_menu_items[mode->link_freq_index]; | |
| 917 | − pixel_rate = link_freq_to_pixel_rate(link_freq); | |
| 918 | − __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); | |
| 931 | + link_freq = imx258->link_freq_menu_items[mode->link_freq_index]; | |
| 932 | + link_freq_cfgs = | |
| 933 | + &imx258->link_freq_configs[mode->link_freq_index]; | |
| 934 | + | |
| 935 | + link_cfg = &link_freq_cfgs->link_cfg[imx258->lane_mode_idx]; | |
| 936 | + pixel_rate = link_freq_to_pixel_rate(link_freq, link_cfg); | |
| 937 | + __v4l2_ctrl_modify_range(imx258->pixel_rate, pixel_rate, | |
| 938 | + pixel_rate, 1, pixel_rate); | |
| 919 | 939 | /* Update limits and set FPS to default */ |
| 920 | 940 | vblank_def = imx258->cur_mode->vts_def - |
| 921 | 941 | imx258->cur_mode->height; |
| @@ -927,7 +947,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 5 unmodified lines | ||
| 927 | 947 | vblank_def); |
| 928 | 948 | __v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def); |
| 929 | 949 | h_blank = |
| 930 | − link_freq_configs[mode->link_freq_index].pixels_per_line | |
| 950 | + imx258->link_freq_configs[mode->link_freq_index].pixels_per_line | |
| 931 | 951 | - imx258->cur_mode->width; |
| 932 | 952 | __v4l2_ctrl_modify_range(imx258->hblank, h_blank, |
| 933 | 953 | h_blank, 1, h_blank); |
| @@ -938,48 +958,125 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 4 unmodified lines | ||
| 938 | 958 | return 0; |
| 939 | 959 | } |
| 940 | 960 | |
| 961 | +static const struct v4l2_rect * | |
| 962 | +__imx258_get_pad_crop(struct imx258 *imx258, | |
| 963 | + struct v4l2_subdev_state *sd_state, | |
| 964 | + unsigned int pad, enum v4l2_subdev_format_whence which) | |
| 965 | +{ | |
| 966 | + switch (which) { | |
| 967 | + case V4L2_SUBDEV_FORMAT_TRY: | |
| 968 | + return v4l2_subdev_state_get_crop(sd_state, pad); | |
| 969 | + case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 970 | + return &imx258->cur_mode->crop; | |
| 971 | + } | |
| 972 | + | |
| 973 | + return NULL; | |
| 974 | +} | |
| 975 | + | |
| 976 | +static int imx258_get_selection(struct v4l2_subdev *sd, | |
| 977 | + struct v4l2_subdev_state *sd_state, | |
| 978 | + struct v4l2_subdev_selection *sel) | |
| 979 | +{ | |
| 980 | + switch (sel->target) { | |
| 981 | + case V4L2_SEL_TGT_CROP: { | |
| 982 | + struct imx258 *imx258 = to_imx258(sd); | |
| 983 | + | |
| 984 | + mutex_lock(&imx258->mutex); | |
| 985 | + sel->r = *__imx258_get_pad_crop(imx258, sd_state, sel->pad, | |
| 986 | + sel->which); | |
| 987 | + mutex_unlock(&imx258->mutex); | |
| 988 | + | |
| 989 | + return 0; | |
| 990 | + } | |
| 991 | + | |
| 992 | + case V4L2_SEL_TGT_NATIVE_SIZE: | |
| 993 | + sel->r.left = 0; | |
| 994 | + sel->r.top = 0; | |
| 995 | + sel->r.width = IMX258_NATIVE_WIDTH; | |
| 996 | + sel->r.height = IMX258_NATIVE_HEIGHT; | |
| 997 | + | |
| 998 | + return 0; | |
| 999 | + | |
| 1000 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 1001 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 1002 | + sel->r.left = IMX258_PIXEL_ARRAY_LEFT; | |
| 1003 | + sel->r.top = IMX258_PIXEL_ARRAY_TOP; | |
| 1004 | + sel->r.width = IMX258_PIXEL_ARRAY_WIDTH; | |
| 1005 | + sel->r.height = IMX258_PIXEL_ARRAY_HEIGHT; | |
| 1006 | + | |
| 1007 | + return 0; | |
| 1008 | + } | |
| 1009 | + | |
| 1010 | + return -EINVAL; | |
| 1011 | +} | |
| 1012 | + | |
| 941 | 1013 | /* Start streaming */ |
| 942 | 1014 | static int imx258_start_streaming(struct imx258 *imx258) |
| 943 | 1015 | { |
| 944 | 1016 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 945 | 1017 | const struct imx258_reg_list *reg_list; |
| 1018 | + const struct imx258_link_freq_config *link_freq_cfg; | |
| 946 | 1019 | int ret, link_freq_index; |
| 947 | 1020 | |
| 1021 | + ret = cci_write(imx258->regmap, IMX258_REG_RESET, 0x01, NULL); | |
| 1022 | + if (ret) { | |
| 1023 | + dev_err(&client->dev, "%s failed to reset sensor\n", __func__); | |
| 1024 | + return ret; | |
| 1025 | + } | |
| 1026 | + | |
| 1027 | + /* 12ms is required from poweron to standby */ | |
| 1028 | + fsleep(12000); | |
| 1029 | + | |
| 948 | 1030 | /* Setup PLL */ |
| 949 | 1031 | link_freq_index = imx258->cur_mode->link_freq_index; |
| 950 | − reg_list = &link_freq_configs[link_freq_index].reg_list; | |
| 951 | − ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); | |
| 1032 | + link_freq_cfg = &imx258->link_freq_configs[link_freq_index]; | |
| 1033 | + | |
| 1034 | + reg_list = &link_freq_cfg->link_cfg[imx258->lane_mode_idx].reg_list; | |
| 1035 | + ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL); | |
| 952 | 1036 | if (ret) { |
| 953 | 1037 | dev_err(&client->dev, "%s failed to set plls\n", __func__); |
| 954 | 1038 | return ret; |
| 955 | 1039 | } |
| 956 | 1040 | |
| 957 | − /* Apply default values of current mode */ | |
| 958 | − reg_list = &imx258->cur_mode->reg_list; | |
| 959 | − ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); | |
| 1041 | + ret = cci_multi_reg_write(imx258->regmap, mode_common_regs, | |
| 1042 | + ARRAY_SIZE(mode_common_regs), NULL); | |
| 960 | 1043 | if (ret) { |
| 961 | − dev_err(&client->dev, "%s failed to set mode\n", __func__); | |
| 1044 | + dev_err(&client->dev, "%s failed to set common regs\n", __func__); | |
| 962 | 1045 | return ret; |
| 963 | 1046 | } |
| 964 | 1047 | |
| 965 | − /* Set Orientation be 180 degree */ | |
| 966 | − ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, | |
| 967 | − IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP); | |
| 1048 | + ret = cci_multi_reg_write(imx258->regmap, imx258->variant_cfg->regs, | |
| 1049 | + imx258->variant_cfg->num_regs, NULL); | |
| 968 | 1050 | if (ret) { |
| 969 | − dev_err(&client->dev, "%s failed to set orientation\n", | |
| 1051 | + dev_err(&client->dev, "%s failed to set variant config\n", | |
| 970 | 1052 | __func__); |
| 971 | 1053 | return ret; |
| 972 | 1054 | } |
| 973 | 1055 | |
| 1056 | + ret = cci_write(imx258->regmap, IMX258_CLK_BLANK_STOP, | |
| 1057 | + !!(imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK), | |
| 1058 | + NULL); | |
| 1059 | + if (ret) { | |
| 1060 | + dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__); | |
| 1061 | + return ret; | |
| 1062 | + } | |
| 1063 | + | |
| 1064 | + /* Apply default values of current mode */ | |
| 1065 | + reg_list = &imx258->cur_mode->reg_list; | |
| 1066 | + ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL); | |
| 1067 | + if (ret) { | |
| 1068 | + dev_err(&client->dev, "%s failed to set mode\n", __func__); | |
| 1069 | + return ret; | |
| 1070 | + } | |
| 1071 | + | |
| 974 | 1072 | /* Apply customized values from user */ |
| 975 | 1073 | ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler); |
| 976 | 1074 | if (ret) |
| 977 | 1075 | return ret; |
| 978 | 1076 | |
| 979 | 1077 | /* set stream on register */ |
| 980 | − return imx258_write_reg(imx258, IMX258_REG_MODE_SELECT, | |
| 981 | − IMX258_REG_VALUE_08BIT, | |
| 982 | − IMX258_MODE_STREAMING); | |
| 1078 | + return cci_write(imx258->regmap, IMX258_REG_MODE_SELECT, | |
| 1079 | + IMX258_MODE_STREAMING, NULL); | |
| 983 | 1080 | } |
| 984 | 1081 | |
| 985 | 1082 | /* Stop streaming */ |
| @@ -989,8 +1086,8 @@ static int imx258_stop_streaming(struct imx258 *imx258) · 3 unmodified lines | ||
| 989 | 1086 | int ret; |
| 990 | 1087 | |
| 991 | 1088 | /* set stream off register */ |
| 992 | − ret = imx258_write_reg(imx258, IMX258_REG_MODE_SELECT, | |
| 993 | − IMX258_REG_VALUE_08BIT, IMX258_MODE_STANDBY); | |
| 1089 | + ret = cci_write(imx258->regmap, IMX258_REG_MODE_SELECT, | |
| 1090 | + IMX258_MODE_STANDBY, NULL); | |
| 994 | 1091 | if (ret) |
| 995 | 1092 | dev_err(&client->dev, "%s failed to set stream\n", __func__); |
| 996 | 1093 | |
| @@ -1007,9 +1104,19 @@ static int imx258_power_on(struct device *dev) · 10 unmodified lines | ||
| 1007 | 1104 | struct imx258 *imx258 = to_imx258(sd); |
| 1008 | 1105 | int ret; |
| 1009 | 1106 | |
| 1107 | + ret = regulator_bulk_enable(IMX258_NUM_SUPPLIES, | |
| 1108 | + imx258->supplies); | |
| 1109 | + if (ret) { | |
| 1110 | + dev_err(dev, "%s: failed to enable regulators\n", | |
| 1111 | + __func__); | |
| 1112 | + return ret; | |
| 1113 | + } | |
| 1114 | + | |
| 1010 | 1115 | ret = clk_prepare_enable(imx258->clk); |
| 1011 | − if (ret) | |
| 1116 | + if (ret) { | |
| 1012 | 1117 | dev_err(dev, "failed to enable clock\n"); |
| 1118 | + regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); | |
| 1119 | + } | |
| 1013 | 1120 | |
| 1014 | 1121 | return ret; |
| 1015 | 1122 | } |
| @@ -1020,6 +1127,7 @@ static int imx258_power_off(struct device *dev) · 4 unmodified lines | ||
| 1020 | 1127 | struct imx258 *imx258 = to_imx258(sd); |
| 1021 | 1128 | |
| 1022 | 1129 | clk_disable_unprepare(imx258->clk); |
| 1130 | + regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); | |
| 1023 | 1131 | |
| 1024 | 1132 | return 0; |
| 1025 | 1133 | } |
| @@ -1066,10 +1174,10 @@ static int imx258_identify_module(struct imx258 *imx258) · 40 unmodified lines | ||
| 1066 | 1174 | { |
| 1067 | 1175 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 1068 | 1176 | int ret; |
| 1069 | − u32 val; | |
| 1177 | + u64 val; | |
| 1070 | 1178 | |
| 1071 | − ret = imx258_read_reg(imx258, IMX258_REG_CHIP_ID, | |
| 1072 | − IMX258_REG_VALUE_16BIT, &val); | |
| 1179 | + ret = cci_read(imx258->regmap, IMX258_REG_CHIP_ID, | |
| 1180 | + &val, NULL); | |
| 1073 | 1181 | if (ret) { |
| 1074 | 1182 | dev_err(&client->dev, "failed to read chip id %x\n", |
| 1075 | 1183 | IMX258_CHIP_ID); |
| @@ -1077,7 +1185,7 @@ static int imx258_identify_module(struct imx258 *imx258) · 1 unmodified line | ||
| 1077 | 1185 | } |
| 1078 | 1186 | |
| 1079 | 1187 | if (val != IMX258_CHIP_ID) { |
| 1080 | − dev_err(&client->dev, "chip id mismatch: %x!=%x\n", | |
| 1188 | + dev_err(&client->dev, "chip id mismatch: %x!=%llx\n", | |
| 1081 | 1189 | IMX258_CHIP_ID, val); |
| 1082 | 1190 | return -EIO; |
| 1083 | 1191 | } |
| @@ -1094,6 +1202,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = { · 10 unmodified lines | ||
| 1094 | 1202 | .get_fmt = imx258_get_pad_format, |
| 1095 | 1203 | .set_fmt = imx258_set_pad_format, |
| 1096 | 1204 | .enum_frame_size = imx258_enum_frame_size, |
| 1205 | + .get_selection = imx258_get_selection, | |
| 1097 | 1206 | }; |
| 1098 | 1207 | |
| 1099 | 1208 | static const struct v4l2_subdev_ops imx258_subdev_ops = { |
| @@ -1109,13 +1218,13 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = { · 9 unmodified lines | ||
| 1109 | 1218 | static int imx258_init_controls(struct imx258 *imx258) |
| 1110 | 1219 | { |
| 1111 | 1220 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 1221 | + const struct imx258_link_freq_config *link_freq_cfgs; | |
| 1112 | 1222 | struct v4l2_fwnode_device_properties props; |
| 1113 | 1223 | struct v4l2_ctrl_handler *ctrl_hdlr; |
| 1114 | − struct v4l2_ctrl *vflip, *hflip; | |
| 1224 | + const struct imx258_link_cfg *link_cfg; | |
| 1115 | 1225 | s64 vblank_def; |
| 1116 | 1226 | s64 vblank_min; |
| 1117 | − s64 pixel_rate_min; | |
| 1118 | − s64 pixel_rate_max; | |
| 1227 | + s64 pixel_rate; | |
| 1119 | 1228 | int ret; |
| 1120 | 1229 | |
| 1121 | 1230 | ctrl_hdlr = &imx258->ctrl_handler; |
| @@ -1128,32 +1237,33 @@ static int imx258_init_controls(struct imx258 *imx258) · 6 unmodified lines | ||
| 1128 | 1237 | imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, |
| 1129 | 1238 | &imx258_ctrl_ops, |
| 1130 | 1239 | V4L2_CID_LINK_FREQ, |
| 1131 | − ARRAY_SIZE(link_freq_menu_items) - 1, | |
| 1240 | + ARRAY_SIZE(link_freq_menu_items_19_2) - 1, | |
| 1132 | 1241 | 0, |
| 1133 | − link_freq_menu_items); | |
| 1242 | + imx258->link_freq_menu_items); | |
| 1134 | 1243 | |
| 1135 | 1244 | if (imx258->link_freq) |
| 1136 | 1245 | imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 1137 | 1246 | |
| 1138 | − /* The driver only supports one bayer order and flips by default. */ | |
| 1139 | − hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1140 | − V4L2_CID_HFLIP, 1, 1, 1, 1); | |
| 1141 | − if (hflip) | |
| 1142 | − hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1247 | + imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1248 | + V4L2_CID_HFLIP, 0, 1, 1, 1); | |
| 1249 | + if (imx258->hflip) | |
| 1250 | + imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; | |
| 1251 | + | |
| 1252 | + imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1253 | + V4L2_CID_VFLIP, 0, 1, 1, 1); | |
| 1254 | + if (imx258->vflip) | |
| 1255 | + imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; | |
| 1143 | 1256 | |
| 1144 | − vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | |
| 1145 | − V4L2_CID_VFLIP, 1, 1, 1, 1); | |
| 1146 | − if (vflip) | |
| 1147 | − vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1257 | + link_freq_cfgs = &imx258->link_freq_configs[0]; | |
| 1258 | + link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg; | |
| 1259 | + pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items[0], | |
| 1260 | + link_cfg); | |
| 1148 | 1261 | |
| 1149 | − pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]); | |
| 1150 | − pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]); | |
| 1151 | 1262 | /* By default, PIXEL_RATE is read only */ |
| 1152 | 1263 | imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, |
| 1153 | 1264 | V4L2_CID_PIXEL_RATE, |
| 1154 | − pixel_rate_min, pixel_rate_max, | |
| 1155 | − 1, pixel_rate_max); | |
| 1156 | − | |
| 1265 | + pixel_rate, pixel_rate, | |
| 1266 | + 1, pixel_rate); | |
| 1157 | 1267 | |
| 1158 | 1268 | vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height; |
| 1159 | 1269 | vblank_min = imx258->cur_mode->vts_min - imx258->cur_mode->height; |
| @@ -1163,9 +1273,6 @@ static int imx258_init_controls(struct imx258 *imx258) · 3 unmodified lines | ||
| 1163 | 1273 | IMX258_VTS_MAX - imx258->cur_mode->height, 1, |
| 1164 | 1274 | vblank_def); |
| 1165 | 1275 | |
| 1166 | − if (imx258->vblank) | |
| 1167 | − imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1168 | − | |
| 1169 | 1276 | imx258->hblank = v4l2_ctrl_new_std( |
| 1170 | 1277 | ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK, |
| 1171 | 1278 | IMX258_PPL_DEFAULT - imx258->cur_mode->width, |
| @@ -1232,9 +1339,25 @@ static void imx258_free_controls(struct imx258 *imx258) · 60 unmodified lines | ||
| 1232 | 1339 | mutex_destroy(&imx258->mutex); |
| 1233 | 1340 | } |
| 1234 | 1341 | |
| 1342 | +static int imx258_get_regulators(struct imx258 *imx258, | |
| 1343 | + struct i2c_client *client) | |
| 1344 | +{ | |
| 1345 | + unsigned int i; | |
| 1346 | + | |
| 1347 | + for (i = 0; i < IMX258_NUM_SUPPLIES; i++) | |
| 1348 | + imx258->supplies[i].supply = imx258_supply_name[i]; | |
| 1349 | + | |
| 1350 | + return devm_regulator_bulk_get(&client->dev, | |
| 1351 | + IMX258_NUM_SUPPLIES, imx258->supplies); | |
| 1352 | +} | |
| 1353 | + | |
| 1235 | 1354 | static int imx258_probe(struct i2c_client *client) |
| 1236 | 1355 | { |
| 1237 | 1356 | struct imx258 *imx258; |
| 1357 | + struct fwnode_handle *endpoint; | |
| 1358 | + struct v4l2_fwnode_endpoint ep = { | |
| 1359 | + .bus_type = V4L2_MBUS_CSI2_DPHY | |
| 1360 | + }; | |
| 1238 | 1361 | int ret; |
| 1239 | 1362 | u32 val = 0; |
| 1240 | 1363 | |
| @@ -1242,6 +1365,18 @@ static int imx258_probe(struct i2c_client *client) · 1 unmodified line | ||
| 1242 | 1365 | if (!imx258) |
| 1243 | 1366 | return -ENOMEM; |
| 1244 | 1367 | |
| 1368 | + imx258->regmap = devm_cci_regmap_init_i2c(client, 16); | |
| 1369 | + if (IS_ERR(imx258->regmap)) { | |
| 1370 | + ret = PTR_ERR(imx258->regmap); | |
| 1371 | + dev_err(&client->dev, "failed to initialize CCI: %d\n", ret); | |
| 1372 | + return ret; | |
| 1373 | + } | |
| 1374 | + | |
| 1375 | + ret = imx258_get_regulators(imx258, client); | |
| 1376 | + if (ret) | |
| 1377 | + return dev_err_probe(&client->dev, ret, | |
| 1378 | + "failed to get regulators\n"); | |
| 1379 | + | |
| 1245 | 1380 | imx258->clk = devm_clk_get_optional(&client->dev, NULL); |
| 1246 | 1381 | if (IS_ERR(imx258->clk)) |
| 1247 | 1382 | return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), |
| @@ -1254,18 +1389,74 @@ static int imx258_probe(struct i2c_client *client) · 6 unmodified lines | ||
| 1254 | 1389 | } else { |
| 1255 | 1390 | val = clk_get_rate(imx258->clk); |
| 1256 | 1391 | } |
| 1257 | − if (val != IMX258_INPUT_CLOCK_FREQ) { | |
| 1258 | − dev_err(&client->dev, "input clock frequency not supported\n"); | |
| 1392 | + | |
| 1393 | + switch (val) { | |
| 1394 | + case 19200000: | |
| 1395 | + imx258->link_freq_configs = link_freq_configs_19_2; | |
| 1396 | + imx258->link_freq_menu_items = link_freq_menu_items_19_2; | |
| 1397 | + break; | |
| 1398 | + case 24000000: | |
| 1399 | + imx258->link_freq_configs = link_freq_configs_24; | |
| 1400 | + imx258->link_freq_menu_items = link_freq_menu_items_24; | |
| 1401 | + break; | |
| 1402 | + default: | |
| 1403 | + dev_err(&client->dev, "input clock frequency of %u not supported\n", | |
| 1404 | + val); | |
| 1259 | 1405 | return -EINVAL; |
| 1260 | 1406 | } |
| 1261 | 1407 | |
| 1408 | + endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL); | |
| 1409 | + if (!endpoint) { | |
| 1410 | + dev_err(&client->dev, "Endpoint node not found\n"); | |
| 1411 | + return -EINVAL; | |
| 1412 | + } | |
| 1413 | + | |
| 1414 | + ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep); | |
| 1415 | + fwnode_handle_put(endpoint); | |
| 1416 | + if (ret) { | |
| 1417 | + dev_err(&client->dev, "Parsing endpoint node failed\n"); | |
| 1418 | + return ret; | |
| 1419 | + } | |
| 1420 | + | |
| 1421 | + ret = v4l2_link_freq_to_bitmap(&client->dev, | |
| 1422 | + ep.link_frequencies, | |
| 1423 | + ep.nr_of_link_frequencies, | |
| 1424 | + imx258->link_freq_menu_items, | |
| 1425 | + ARRAY_SIZE(link_freq_menu_items_19_2), | |
| 1426 | + &imx258->link_freq_bitmap); | |
| 1427 | + if (ret) { | |
| 1428 | + dev_err(&client->dev, "Link frequency not supported\n"); | |
| 1429 | + goto error_endpoint_free; | |
| 1430 | + } | |
| 1431 | + | |
| 1432 | + /* Get number of data lanes */ | |
| 1433 | + switch (ep.bus.mipi_csi2.num_data_lanes) { | |
| 1434 | + case 2: | |
| 1435 | + imx258->lane_mode_idx = IMX258_2_LANE_MODE; | |
| 1436 | + break; | |
| 1437 | + case 4: | |
| 1438 | + imx258->lane_mode_idx = IMX258_4_LANE_MODE; | |
| 1439 | + break; | |
| 1440 | + default: | |
| 1441 | + dev_err(&client->dev, "Invalid data lanes: %u\n", | |
| 1442 | + ep.bus.mipi_csi2.num_data_lanes); | |
| 1443 | + ret = -EINVAL; | |
| 1444 | + goto error_endpoint_free; | |
| 1445 | + } | |
| 1446 | + | |
| 1447 | + imx258->csi2_flags = ep.bus.mipi_csi2.flags; | |
| 1448 | + | |
| 1449 | + imx258->variant_cfg = device_get_match_data(&client->dev); | |
| 1450 | + if (!imx258->variant_cfg) | |
| 1451 | + imx258->variant_cfg = &imx258_cfg; | |
| 1452 | + | |
| 1262 | 1453 | /* Initialize subdev */ |
| 1263 | 1454 | v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); |
| 1264 | 1455 | |
| 1265 | 1456 | /* Will be powered off via pm_runtime_idle */ |
| 1266 | 1457 | ret = imx258_power_on(&client->dev); |
| 1267 | 1458 | if (ret) |
| 1268 | − return ret; | |
| 1459 | + goto error_endpoint_free; | |
| 1269 | 1460 | |
| 1270 | 1461 | /* Check module identity */ |
| 1271 | 1462 | ret = imx258_identify_module(imx258); |
| @@ -1298,6 +1489,7 @@ static int imx258_probe(struct i2c_client *client) · 26 unmodified lines | ||
| 1298 | 1489 | pm_runtime_set_active(&client->dev); |
| 1299 | 1490 | pm_runtime_enable(&client->dev); |
| 1300 | 1491 | pm_runtime_idle(&client->dev); |
| 1492 | + v4l2_fwnode_endpoint_free(&ep); | |
| 1301 | 1493 | |
| 1302 | 1494 | return 0; |
| 1303 | 1495 | |
| @@ -1310,6 +1502,9 @@ error_handler_free: · 6 unmodified lines | ||
| 1310 | 1502 | error_identify: |
| 1311 | 1503 | imx258_power_off(&client->dev); |
| 1312 | 1504 | |
| 1505 | +error_endpoint_free: | |
| 1506 | + v4l2_fwnode_endpoint_free(&ep); | |
| 1507 | + | |
| 1313 | 1508 | return ret; |
| 1314 | 1509 | } |
| 1315 | 1510 | |
| @@ -1342,7 +1537,8 @@ MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids); · 26 unmodified lines | ||
| 1342 | 1537 | #endif |
| 1343 | 1538 | |
| 1344 | 1539 | static const struct of_device_id imx258_dt_ids[] = { |
| 1345 | − { .compatible = "sony,imx258" }, | |
| 1540 | + { .compatible = "sony,imx258", .data = &imx258_cfg }, | |
| 1541 | + { .compatible = "sony,imx258-pdaf", .data = &imx258_pdaf_cfg }, | |
| 1346 | 1542 | { /* sentinel */ } |
| 1347 | 1543 | }; |
| 1348 | 1544 | MODULE_DEVICE_TABLE(of, imx258_dt_ids); |
| @@ -0,0 +1,1612 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * V4L2 Support for the IMX283 | |
| 4 | + * | |
| 5 | + * Diagonal 15.86 mm (Type 1) CMOS Image Sensor with Square Pixel for Color | |
| 6 | + * Cameras. | |
| 7 | + * | |
| 8 | + * Copyright (C) 2024 Ideas on Board Oy. | |
| 9 | + * | |
| 10 | + * Based on Sony IMX283 driver prepared by Will Whang | |
| 11 | + * | |
| 12 | + * Based on Sony imx477 camera driver | |
| 13 | + * Copyright (C) 2019-2020 Raspberry Pi (Trading) Ltd | |
| 14 | + */ | |
| 15 | + | |
| 16 | +#include <linux/array_size.h> | |
| 17 | +#include <linux/bitops.h> | |
| 18 | +#include <linux/container_of.h> | |
| 19 | +#include <linux/clk.h> | |
| 20 | +#include <linux/delay.h> | |
| 21 | +#include <linux/err.h> | |
| 22 | +#include <linux/gpio/consumer.h> | |
| 23 | +#include <linux/i2c.h> | |
| 24 | +#include <linux/minmax.h> | |
| 25 | +#include <linux/module.h> | |
| 26 | +#include <linux/mutex.h> | |
| 27 | +#include <linux/pm_runtime.h> | |
| 28 | +#include <linux/property.h> | |
| 29 | +#include <linux/regulator/consumer.h> | |
| 30 | +#include <linux/types.h> | |
| 31 | +#include <linux/units.h> | |
| 32 | +#include <media/v4l2-cci.h> | |
| 33 | +#include <media/v4l2-ctrls.h> | |
| 34 | +#include <media/v4l2-device.h> | |
| 35 | +#include <media/v4l2-event.h> | |
| 36 | +#include <media/v4l2-fwnode.h> | |
| 37 | +#include <media/v4l2-mediabus.h> | |
| 38 | + | |
| 39 | +/* Chip ID */ | |
| 40 | +#define IMX283_REG_CHIP_ID CCI_REG8(0x3000) | |
| 41 | +#define IMX283_CHIP_ID 0x0b // Default power on state | |
| 42 | + | |
| 43 | +#define IMX283_REG_STANDBY CCI_REG8(0x3000) | |
| 44 | +#define IMX283_ACTIVE 0 | |
| 45 | +#define IMX283_STANDBY BIT(0) | |
| 46 | +#define IMX283_STBLOGIC BIT(1) | |
| 47 | +#define IMX283_STBMIPI BIT(2) | |
| 48 | +#define IMX283_STBDV BIT(3) | |
| 49 | +#define IMX283_SLEEP BIT(4) | |
| 50 | + | |
| 51 | +#define IMX283_REG_CLAMP CCI_REG8(0x3001) | |
| 52 | +#define IMX283_CLPSQRST BIT(4) | |
| 53 | + | |
| 54 | +#define IMX283_REG_PLSTMG08 CCI_REG8(0x3003) | |
| 55 | +#define IMX283_PLSTMG08_VAL 0x77 | |
| 56 | + | |
| 57 | +#define IMX283_REG_MDSEL1 CCI_REG8(0x3004) | |
| 58 | +#define IMX283_REG_MDSEL2 CCI_REG8(0x3005) | |
| 59 | +#define IMX283_REG_MDSEL3 CCI_REG8(0x3006) | |
| 60 | +#define IMX283_MDSEL3_VCROP_EN BIT(5) | |
| 61 | +#define IMX283_REG_MDSEL4 CCI_REG8(0x3007) | |
| 62 | +#define IMX283_MDSEL4_VCROP_EN (BIT(4) | BIT(6)) | |
| 63 | + | |
| 64 | +#define IMX283_REG_SVR CCI_REG16_LE(0x3009) | |
| 65 | + | |
| 66 | +#define IMX283_REG_HTRIMMING CCI_REG8(0x300b) | |
| 67 | +#define IMX283_MDVREV BIT(0) /* VFLIP */ | |
| 68 | +#define IMX283_HTRIMMING_EN BIT(4) | |
| 69 | + | |
| 70 | +#define IMX283_REG_VWINPOS CCI_REG16_LE(0x300f) | |
| 71 | +#define IMX283_REG_VWIDCUT CCI_REG16_LE(0x3011) | |
| 72 | + | |
| 73 | +#define IMX283_REG_MDSEL7 CCI_REG16_LE(0x3013) | |
| 74 | + | |
| 75 | +/* CSI Clock Configuration */ | |
| 76 | +#define IMX283_REG_TCLKPOST CCI_REG8(0x3018) | |
| 77 | +#define IMX283_REG_THSPREPARE CCI_REG8(0x301a) | |
| 78 | +#define IMX283_REG_THSZERO CCI_REG8(0x301c) | |
| 79 | +#define IMX283_REG_THSTRAIL CCI_REG8(0x301e) | |
| 80 | +#define IMX283_REG_TCLKTRAIL CCI_REG8(0x3020) | |
| 81 | +#define IMX283_REG_TCLKPREPARE CCI_REG8(0x3022) | |
| 82 | +#define IMX283_REG_TCLKZERO CCI_REG16_LE(0x3024) | |
| 83 | +#define IMX283_REG_TLPX CCI_REG8(0x3026) | |
| 84 | +#define IMX283_REG_THSEXIT CCI_REG8(0x3028) | |
| 85 | +#define IMX283_REG_TCLKPRE CCI_REG8(0x302a) | |
| 86 | +#define IMX283_REG_SYSMODE CCI_REG8(0x3104) | |
| 87 | + | |
| 88 | +#define IMX283_REG_Y_OUT_SIZE CCI_REG16_LE(0x302f) | |
| 89 | +#define IMX283_REG_WRITE_VSIZE CCI_REG16_LE(0x3031) | |
| 90 | +#define IMX283_REG_OB_SIZE_V CCI_REG8(0x3033) | |
| 91 | + | |
| 92 | +/* HMAX internal HBLANK */ | |
| 93 | +#define IMX283_REG_HMAX CCI_REG16_LE(0x3036) | |
| 94 | +#define IMX283_HMAX_MAX (BIT(16) - 1) | |
| 95 | + | |
| 96 | +/* VMAX internal VBLANK */ | |
| 97 | +#define IMX283_REG_VMAX CCI_REG24_LE(0x3038) | |
| 98 | +#define IMX283_VMAX_MAX (BIT(16) - 1) | |
| 99 | + | |
| 100 | +/* SHR internal */ | |
| 101 | +#define IMX283_REG_SHR CCI_REG16_LE(0x303b) | |
| 102 | +#define IMX283_SHR_MIN 11 | |
| 103 | + | |
| 104 | +/* | |
| 105 | + * Analog gain control | |
| 106 | + * Gain [dB] = -20log{(2048 - value [10:0]) /2048} | |
| 107 | + * Range: 0dB to approximately +27dB | |
| 108 | + */ | |
| 109 | +#define IMX283_REG_ANALOG_GAIN CCI_REG16_LE(0x3042) | |
| 110 | +#define IMX283_ANA_GAIN_MIN 0 | |
| 111 | +#define IMX283_ANA_GAIN_MAX 1957 | |
| 112 | +#define IMX283_ANA_GAIN_STEP 1 | |
| 113 | +#define IMX283_ANA_GAIN_DEFAULT 0x0 | |
| 114 | + | |
| 115 | +/* | |
| 116 | + * Digital gain control | |
| 117 | + * Gain [dB] = value * 6 | |
| 118 | + * Range: 0dB to +18db | |
| 119 | + */ | |
| 120 | +#define IMX283_REG_DIGITAL_GAIN CCI_REG8(0x3044) | |
| 121 | +#define IMX283_DGTL_GAIN_MIN 0 | |
| 122 | +#define IMX283_DGTL_GAIN_MAX 3 | |
| 123 | +#define IMX283_DGTL_GAIN_DEFAULT 0 | |
| 124 | +#define IMX283_DGTL_GAIN_STEP 1 | |
| 125 | + | |
| 126 | +#define IMX283_REG_HTRIMMING_START CCI_REG16_LE(0x3058) | |
| 127 | +#define IMX283_REG_HTRIMMING_END CCI_REG16_LE(0x305a) | |
| 128 | + | |
| 129 | +#define IMX283_REG_MDSEL18 CCI_REG16_LE(0x30f6) | |
| 130 | + | |
| 131 | +/* Master Mode Operation Control */ | |
| 132 | +#define IMX283_REG_XMSTA CCI_REG8(0x3105) | |
| 133 | +#define IMX283_XMSTA BIT(0) | |
| 134 | + | |
| 135 | +#define IMX283_REG_SYNCDRV CCI_REG8(0x3107) | |
| 136 | +#define IMX283_SYNCDRV_XHS_XVS (0xa0 | 0x02) | |
| 137 | +#define IMX283_SYNCDRV_HIZ (0xa0 | 0x03) | |
| 138 | + | |
| 139 | +/* PLL Standby */ | |
| 140 | +#define IMX283_REG_STBPL CCI_REG8(0x320b) | |
| 141 | +#define IMX283_STBPL_NORMAL 0x00 | |
| 142 | +#define IMX283_STBPL_STANDBY 0x03 | |
| 143 | + | |
| 144 | +/* Input Frequency Setting */ | |
| 145 | +#define IMX283_REG_PLRD1 CCI_REG8(0x36c1) | |
| 146 | +#define IMX283_REG_PLRD2 CCI_REG16_LE(0x36c2) | |
| 147 | +#define IMX283_REG_PLRD3 CCI_REG8(0x36f7) | |
| 148 | +#define IMX283_REG_PLRD4 CCI_REG8(0x36f8) | |
| 149 | + | |
| 150 | +#define IMX283_REG_PLSTMG02 CCI_REG8(0x36aa) | |
| 151 | +#define IMX283_PLSTMG02_VAL 0x00 | |
| 152 | + | |
| 153 | +#define IMX283_REG_EBD_X_OUT_SIZE CCI_REG16_LE(0x3a54) | |
| 154 | + | |
| 155 | +/* Test pattern generator */ | |
| 156 | +#define IMX283_REG_TPG_CTRL CCI_REG8(0x3156) | |
| 157 | +#define IMX283_TPG_CTRL_CLKEN BIT(0) | |
| 158 | +#define IMX283_TPG_CTRL_PATEN BIT(4) | |
| 159 | + | |
| 160 | +#define IMX283_REG_TPG_PAT CCI_REG8(0x3157) | |
| 161 | +#define IMX283_TPG_PAT_ALL_000 0x00 | |
| 162 | +#define IMX283_TPG_PAT_ALL_FFF 0x01 | |
| 163 | +#define IMX283_TPG_PAT_ALL_555 0x02 | |
| 164 | +#define IMX283_TPG_PAT_ALL_AAA 0x03 | |
| 165 | +#define IMX283_TPG_PAT_H_COLOR_BARS 0x0a | |
| 166 | +#define IMX283_TPG_PAT_V_COLOR_BARS 0x0b | |
| 167 | + | |
| 168 | +/* Exposure control */ | |
| 169 | +#define IMX283_EXPOSURE_MIN 52 | |
| 170 | +#define IMX283_EXPOSURE_STEP 1 | |
| 171 | +#define IMX283_EXPOSURE_DEFAULT 1000 | |
| 172 | +#define IMX283_EXPOSURE_MAX 49865 | |
| 173 | + | |
| 174 | +#define IMAGE_PAD 0 | |
| 175 | + | |
| 176 | +#define IMX283_XCLR_MIN_DELAY_US (1 * USEC_PER_MSEC) | |
| 177 | +#define IMX283_XCLR_DELAY_RANGE_US (1 * USEC_PER_MSEC) | |
| 178 | + | |
| 179 | +/* IMX283 native and active pixel array size. */ | |
| 180 | +static const struct v4l2_rect imx283_native_area = { | |
| 181 | + .top = 0, | |
| 182 | + .left = 0, | |
| 183 | + .width = 5592, | |
| 184 | + .height = 3710, | |
| 185 | +}; | |
| 186 | + | |
| 187 | +static const struct v4l2_rect imx283_active_area = { | |
| 188 | + .top = 40, | |
| 189 | + .left = 108, | |
| 190 | + .width = 5472, | |
| 191 | + .height = 3648, | |
| 192 | +}; | |
| 193 | + | |
| 194 | +struct imx283_reg_list { | |
| 195 | + unsigned int num_of_regs; | |
| 196 | + const struct cci_reg_sequence *regs; | |
| 197 | +}; | |
| 198 | + | |
| 199 | +/* Mode : resolution and related config values */ | |
| 200 | +struct imx283_mode { | |
| 201 | + unsigned int mode; | |
| 202 | + | |
| 203 | + /* Bits per pixel */ | |
| 204 | + unsigned int bpp; | |
| 205 | + | |
| 206 | + /* Frame width */ | |
| 207 | + unsigned int width; | |
| 208 | + | |
| 209 | + /* Frame height */ | |
| 210 | + unsigned int height; | |
| 211 | + | |
| 212 | + /* | |
| 213 | + * Minimum horizontal timing in pixel-units | |
| 214 | + * | |
| 215 | + * Note that HMAX is written in 72MHz units, and the datasheet assumes a | |
| 216 | + * 720MHz link frequency. Convert datasheet values with the following: | |
| 217 | + * | |
| 218 | + * For 12 bpp modes (480Mbps) convert with: | |
| 219 | + * hmax = [hmax in 72MHz units] * 480 / 72 | |
| 220 | + * | |
| 221 | + * For 10 bpp modes (576Mbps) convert with: | |
| 222 | + * hmax = [hmax in 72MHz units] * 576 / 72 | |
| 223 | + */ | |
| 224 | + u32 min_hmax; | |
| 225 | + | |
| 226 | + /* minimum V-timing in lines */ | |
| 227 | + u32 min_vmax; | |
| 228 | + | |
| 229 | + /* default H-timing */ | |
| 230 | + u32 default_hmax; | |
| 231 | + | |
| 232 | + /* default V-timing */ | |
| 233 | + u32 default_vmax; | |
| 234 | + | |
| 235 | + /* minimum SHR */ | |
| 236 | + u32 min_shr; | |
| 237 | + | |
| 238 | + /* | |
| 239 | + * Per-mode vertical crop constants used to calculate values | |
| 240 | + * of IMX283REG_WIDCUT and IMX283_REG_VWINPOS. | |
| 241 | + */ | |
| 242 | + u32 veff; | |
| 243 | + u32 vst; | |
| 244 | + u32 vct; | |
| 245 | + | |
| 246 | + /* Horizontal and vertical binning ratio */ | |
| 247 | + u8 hbin_ratio; | |
| 248 | + u8 vbin_ratio; | |
| 249 | + | |
| 250 | + /* Optical Blanking */ | |
| 251 | + u32 horizontal_ob; | |
| 252 | + u32 vertical_ob; | |
| 253 | + | |
| 254 | + /* Analog crop rectangle. */ | |
| 255 | + struct v4l2_rect crop; | |
| 256 | +}; | |
| 257 | + | |
| 258 | +struct imx283_input_frequency { | |
| 259 | + unsigned int mhz; | |
| 260 | + unsigned int reg_count; | |
| 261 | + struct cci_reg_sequence regs[4]; | |
| 262 | +}; | |
| 263 | + | |
| 264 | +static const struct imx283_input_frequency imx283_frequencies[] = { | |
| 265 | + { | |
| 266 | + .mhz = 6 * HZ_PER_MHZ, | |
| 267 | + .reg_count = 4, | |
| 268 | + .regs = { | |
| 269 | + { IMX283_REG_PLRD1, 0x00 }, | |
| 270 | + { IMX283_REG_PLRD2, 0x00f0 }, | |
| 271 | + { IMX283_REG_PLRD3, 0x00 }, | |
| 272 | + { IMX283_REG_PLRD4, 0xc0 }, | |
| 273 | + }, | |
| 274 | + }, | |
| 275 | + { | |
| 276 | + .mhz = 12 * HZ_PER_MHZ, | |
| 277 | + .reg_count = 4, | |
| 278 | + .regs = { | |
| 279 | + { IMX283_REG_PLRD1, 0x01 }, | |
| 280 | + { IMX283_REG_PLRD2, 0x00f0 }, | |
| 281 | + { IMX283_REG_PLRD3, 0x01 }, | |
| 282 | + { IMX283_REG_PLRD4, 0xc0 }, | |
| 283 | + }, | |
| 284 | + }, | |
| 285 | + { | |
| 286 | + .mhz = 18 * HZ_PER_MHZ, | |
| 287 | + .reg_count = 4, | |
| 288 | + .regs = { | |
| 289 | + { IMX283_REG_PLRD1, 0x01 }, | |
| 290 | + { IMX283_REG_PLRD2, 0x00a0 }, | |
| 291 | + { IMX283_REG_PLRD3, 0x01 }, | |
| 292 | + { IMX283_REG_PLRD4, 0x80 }, | |
| 293 | + }, | |
| 294 | + }, | |
| 295 | + { | |
| 296 | + .mhz = 24 * HZ_PER_MHZ, | |
| 297 | + .reg_count = 4, | |
| 298 | + .regs = { | |
| 299 | + { IMX283_REG_PLRD1, 0x02 }, | |
| 300 | + { IMX283_REG_PLRD2, 0x00f0 }, | |
| 301 | + { IMX283_REG_PLRD3, 0x02 }, | |
| 302 | + { IMX283_REG_PLRD4, 0xc0 }, | |
| 303 | + }, | |
| 304 | + }, | |
| 305 | +}; | |
| 306 | + | |
| 307 | +enum imx283_modes { | |
| 308 | + IMX283_MODE_0, | |
| 309 | + IMX283_MODE_1, | |
| 310 | + IMX283_MODE_1A, | |
| 311 | + IMX283_MODE_1S, | |
| 312 | + IMX283_MODE_2, | |
| 313 | + IMX283_MODE_2A, | |
| 314 | + IMX283_MODE_3, | |
| 315 | + IMX283_MODE_4, | |
| 316 | + IMX283_MODE_5, | |
| 317 | + IMX283_MODE_6, | |
| 318 | +}; | |
| 319 | + | |
| 320 | +struct imx283_readout_mode { | |
| 321 | + u8 mdsel1; | |
| 322 | + u8 mdsel2; | |
| 323 | + u8 mdsel3; | |
| 324 | + u8 mdsel4; | |
| 325 | +}; | |
| 326 | + | |
| 327 | +static const struct imx283_readout_mode imx283_readout_modes[] = { | |
| 328 | + /* All pixel scan modes */ | |
| 329 | + [IMX283_MODE_0] = { 0x04, 0x03, 0x10, 0x00 }, /* 12 bit */ | |
| 330 | + [IMX283_MODE_1] = { 0x04, 0x01, 0x00, 0x00 }, /* 10 bit */ | |
| 331 | + [IMX283_MODE_1A] = { 0x04, 0x01, 0x20, 0x50 }, /* 10 bit */ | |
| 332 | + [IMX283_MODE_1S] = { 0x04, 0x41, 0x20, 0x50 }, /* 10 bit */ | |
| 333 | + | |
| 334 | + /* Horizontal / Vertical 2/2-line binning */ | |
| 335 | + [IMX283_MODE_2] = { 0x0d, 0x11, 0x50, 0x00 }, /* 12 bit */ | |
| 336 | + [IMX283_MODE_2A] = { 0x0d, 0x11, 0x70, 0x50 }, /* 12 bit */ | |
| 337 | + | |
| 338 | + /* Horizontal / Vertical 3/3-line binning */ | |
| 339 | + [IMX283_MODE_3] = { 0x1e, 0x18, 0x10, 0x00 }, /* 12 bit */ | |
| 340 | + | |
| 341 | + /* Vertical 2/9 subsampling, horizontal 3 binning cropping */ | |
| 342 | + [IMX283_MODE_4] = { 0x29, 0x18, 0x30, 0x50 }, /* 12 bit */ | |
| 343 | + | |
| 344 | + /* Vertical 2/19 subsampling binning, horizontal 3 binning */ | |
| 345 | + [IMX283_MODE_5] = { 0x2d, 0x18, 0x10, 0x00 }, /* 12 bit */ | |
| 346 | + | |
| 347 | + /* Vertical 2 binning horizontal 2/4, subsampling 16:9 cropping */ | |
| 348 | + [IMX283_MODE_6] = { 0x18, 0x21, 0x00, 0x09 }, /* 10 bit */ | |
| 349 | + | |
| 350 | + /* | |
| 351 | + * New modes should make sure the offset period is complied. | |
| 352 | + * See imx283_exposure() for reference. | |
| 353 | + */ | |
| 354 | +}; | |
| 355 | + | |
| 356 | +static const struct cci_reg_sequence mipi_data_rate_1440Mbps[] = { | |
| 357 | + /* The default register settings provide the 1440Mbps rate */ | |
| 358 | + { CCI_REG8(0x36c5), 0x00 }, /* Undocumented */ | |
| 359 | + { CCI_REG8(0x3ac4), 0x00 }, /* Undocumented */ | |
| 360 | + | |
| 361 | + { IMX283_REG_STBPL, 0x00 }, | |
| 362 | + { IMX283_REG_TCLKPOST, 0xa7 }, | |
| 363 | + { IMX283_REG_THSPREPARE, 0x6f }, | |
| 364 | + { IMX283_REG_THSZERO, 0x9f }, | |
| 365 | + { IMX283_REG_THSTRAIL, 0x5f }, | |
| 366 | + { IMX283_REG_TCLKTRAIL, 0x5f }, | |
| 367 | + { IMX283_REG_TCLKPREPARE, 0x6f }, | |
| 368 | + { IMX283_REG_TCLKZERO, 0x017f }, | |
| 369 | + { IMX283_REG_TLPX, 0x4f }, | |
| 370 | + { IMX283_REG_THSEXIT, 0x47 }, | |
| 371 | + { IMX283_REG_TCLKPRE, 0x07 }, | |
| 372 | + { IMX283_REG_SYSMODE, 0x02 }, | |
| 373 | +}; | |
| 374 | + | |
| 375 | +static const struct cci_reg_sequence mipi_data_rate_720Mbps[] = { | |
| 376 | + /* Undocumented Additions "For 720MBps" Setting */ | |
| 377 | + { CCI_REG8(0x36c5), 0x01 }, /* Undocumented */ | |
| 378 | + { CCI_REG8(0x3ac4), 0x01 }, /* Undocumented */ | |
| 379 | + | |
| 380 | + { IMX283_REG_STBPL, 0x00 }, | |
| 381 | + { IMX283_REG_TCLKPOST, 0x77 }, | |
| 382 | + { IMX283_REG_THSPREPARE, 0x37 }, | |
| 383 | + { IMX283_REG_THSZERO, 0x67 }, | |
| 384 | + { IMX283_REG_THSTRAIL, 0x37 }, | |
| 385 | + { IMX283_REG_TCLKTRAIL, 0x37 }, | |
| 386 | + { IMX283_REG_TCLKPREPARE, 0x37 }, | |
| 387 | + { IMX283_REG_TCLKZERO, 0xdf }, | |
| 388 | + { IMX283_REG_TLPX, 0x2f }, | |
| 389 | + { IMX283_REG_THSEXIT, 0x47 }, | |
| 390 | + { IMX283_REG_TCLKPRE, 0x0f }, | |
| 391 | + { IMX283_REG_SYSMODE, 0x02 }, | |
| 392 | +}; | |
| 393 | + | |
| 394 | +static const s64 link_frequencies[] = { | |
| 395 | + 720 * HZ_PER_MHZ, /* 1440 Mbps lane data rate */ | |
| 396 | + 360 * HZ_PER_MHZ, /* 720 Mbps data lane rate */ | |
| 397 | +}; | |
| 398 | + | |
| 399 | +static const struct imx283_reg_list link_freq_reglist[] = { | |
| 400 | + { /* 720 MHz */ | |
| 401 | + .num_of_regs = ARRAY_SIZE(mipi_data_rate_1440Mbps), | |
| 402 | + .regs = mipi_data_rate_1440Mbps, | |
| 403 | + }, | |
| 404 | + { /* 360 MHz */ | |
| 405 | + .num_of_regs = ARRAY_SIZE(mipi_data_rate_720Mbps), | |
| 406 | + .regs = mipi_data_rate_720Mbps, | |
| 407 | + }, | |
| 408 | +}; | |
| 409 | + | |
| 410 | +/* Mode configs */ | |
| 411 | +static const struct imx283_mode supported_modes_12bit[] = { | |
| 412 | + { | |
| 413 | + /* 20MPix 21.40 fps readout mode 0 */ | |
| 414 | + .mode = IMX283_MODE_0, | |
| 415 | + .bpp = 12, | |
| 416 | + .width = 5472, | |
| 417 | + .height = 3648, | |
| 418 | + .min_hmax = 5914, /* 887 @ 480MHz/72MHz */ | |
| 419 | + .min_vmax = 3793, /* Lines */ | |
| 420 | + | |
| 421 | + .veff = 3694, | |
| 422 | + .vst = 0, | |
| 423 | + .vct = 0, | |
| 424 | + | |
| 425 | + .hbin_ratio = 1, | |
| 426 | + .vbin_ratio = 1, | |
| 427 | + | |
| 428 | + /* 20.00 FPS */ | |
| 429 | + .default_hmax = 6000, /* 900 @ 480MHz/72MHz */ | |
| 430 | + .default_vmax = 4000, | |
| 431 | + | |
| 432 | + .min_shr = 11, | |
| 433 | + .horizontal_ob = 96, | |
| 434 | + .vertical_ob = 16, | |
| 435 | + .crop = { | |
| 436 | + .top = 40, | |
| 437 | + .left = 108, | |
| 438 | + .width = 5472, | |
| 439 | + .height = 3648, | |
| 440 | + }, | |
| 441 | + }, | |
| 442 | + { | |
| 443 | + /* | |
| 444 | + * Readout mode 2 : 2/2 binned mode (2736x1824) | |
| 445 | + */ | |
| 446 | + .mode = IMX283_MODE_2, | |
| 447 | + .bpp = 12, | |
| 448 | + .width = 2736, | |
| 449 | + .height = 1824, | |
| 450 | + .min_hmax = 2414, /* Pixels (362 * 480MHz/72MHz + padding) */ | |
| 451 | + .min_vmax = 3840, /* Lines */ | |
| 452 | + | |
| 453 | + /* 50.00 FPS */ | |
| 454 | + .default_hmax = 2500, /* 375 @ 480MHz/72Mhz */ | |
| 455 | + .default_vmax = 3840, | |
| 456 | + | |
| 457 | + .veff = 1824, | |
| 458 | + .vst = 0, | |
| 459 | + .vct = 0, | |
| 460 | + | |
| 461 | + .hbin_ratio = 2, | |
| 462 | + .vbin_ratio = 2, | |
| 463 | + | |
| 464 | + .min_shr = 12, | |
| 465 | + .horizontal_ob = 48, | |
| 466 | + .vertical_ob = 4, | |
| 467 | + | |
| 468 | + .crop = { | |
| 469 | + .top = 40, | |
| 470 | + .left = 108, | |
| 471 | + .width = 5472, | |
| 472 | + .height = 3648, | |
| 473 | + }, | |
| 474 | + }, | |
| 475 | +}; | |
| 476 | + | |
| 477 | +static const struct imx283_mode supported_modes_10bit[] = { | |
| 478 | + { | |
| 479 | + /* 20MPix 25.48 fps readout mode 1 */ | |
| 480 | + .mode = IMX283_MODE_1, | |
| 481 | + .bpp = 10, | |
| 482 | + .width = 5472, | |
| 483 | + .height = 3648, | |
| 484 | + .min_hmax = 5960, /* 745 @ 576MHz / 72MHz */ | |
| 485 | + .min_vmax = 3793, | |
| 486 | + | |
| 487 | + /* 25.00 FPS */ | |
| 488 | + .default_hmax = 6000, /* 750 @ 576MHz / 72MHz */ | |
| 489 | + .default_vmax = 3840, | |
| 490 | + | |
| 491 | + .min_shr = 10, | |
| 492 | + .horizontal_ob = 96, | |
| 493 | + .vertical_ob = 16, | |
| 494 | + .crop = { | |
| 495 | + .top = 40, | |
| 496 | + .left = 108, | |
| 497 | + .width = 5472, | |
| 498 | + .height = 3648, | |
| 499 | + }, | |
| 500 | + }, | |
| 501 | +}; | |
| 502 | + | |
| 503 | +static const u32 imx283_mbus_codes[] = { | |
| 504 | + MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 505 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 506 | +}; | |
| 507 | + | |
| 508 | +/* regulator supplies */ | |
| 509 | +static const char *const imx283_supply_name[] = { | |
| 510 | + "vadd", /* Analog (2.9V) supply */ | |
| 511 | + "vdd1", /* Supply Voltage 2 (1.8V) supply */ | |
| 512 | + "vdd2", /* Supply Voltage 3 (1.2V) supply */ | |
| 513 | +}; | |
| 514 | + | |
| 515 | +struct imx283 { | |
| 516 | + struct device *dev; | |
| 517 | + struct regmap *cci; | |
| 518 | + | |
| 519 | + const struct imx283_input_frequency *freq; | |
| 520 | + | |
| 521 | + struct v4l2_subdev sd; | |
| 522 | + struct media_pad pad; | |
| 523 | + | |
| 524 | + struct clk *xclk; | |
| 525 | + | |
| 526 | + struct gpio_desc *reset_gpio; | |
| 527 | + struct regulator_bulk_data supplies[ARRAY_SIZE(imx283_supply_name)]; | |
| 528 | + | |
| 529 | + /* V4L2 Controls */ | |
| 530 | + struct v4l2_ctrl_handler ctrl_handler; | |
| 531 | + struct v4l2_ctrl *exposure; | |
| 532 | + struct v4l2_ctrl *vblank; | |
| 533 | + struct v4l2_ctrl *hblank; | |
| 534 | + struct v4l2_ctrl *vflip; | |
| 535 | + | |
| 536 | + unsigned long link_freq_bitmap; | |
| 537 | + | |
| 538 | + u16 hmax; | |
| 539 | + u32 vmax; | |
| 540 | +}; | |
| 541 | + | |
| 542 | +static inline struct imx283 *to_imx283(struct v4l2_subdev *sd) | |
| 543 | +{ | |
| 544 | + return container_of_const(sd, struct imx283, sd); | |
| 545 | +} | |
| 546 | + | |
| 547 | +static inline void get_mode_table(unsigned int code, | |
| 548 | + const struct imx283_mode **mode_list, | |
| 549 | + unsigned int *num_modes) | |
| 550 | +{ | |
| 551 | + switch (code) { | |
| 552 | + case MEDIA_BUS_FMT_SRGGB12_1X12: | |
| 553 | + case MEDIA_BUS_FMT_SGRBG12_1X12: | |
| 554 | + case MEDIA_BUS_FMT_SGBRG12_1X12: | |
| 555 | + case MEDIA_BUS_FMT_SBGGR12_1X12: | |
| 556 | + *mode_list = supported_modes_12bit; | |
| 557 | + *num_modes = ARRAY_SIZE(supported_modes_12bit); | |
| 558 | + break; | |
| 559 | + | |
| 560 | + case MEDIA_BUS_FMT_SRGGB10_1X10: | |
| 561 | + case MEDIA_BUS_FMT_SGRBG10_1X10: | |
| 562 | + case MEDIA_BUS_FMT_SGBRG10_1X10: | |
| 563 | + case MEDIA_BUS_FMT_SBGGR10_1X10: | |
| 564 | + *mode_list = supported_modes_10bit; | |
| 565 | + *num_modes = ARRAY_SIZE(supported_modes_10bit); | |
| 566 | + break; | |
| 567 | + default: | |
| 568 | + *mode_list = NULL; | |
| 569 | + *num_modes = 0; | |
| 570 | + break; | |
| 571 | + } | |
| 572 | +} | |
| 573 | + | |
| 574 | +/* Calculate the Pixel Rate based on the current mode */ | |
| 575 | +static u64 imx283_pixel_rate(struct imx283 *imx283, | |
| 576 | + const struct imx283_mode *mode) | |
| 577 | +{ | |
| 578 | + u64 link_frequency = link_frequencies[__ffs(imx283->link_freq_bitmap)]; | |
| 579 | + unsigned int bpp = mode->bpp; | |
| 580 | + const unsigned int ddr = 2; /* Double Data Rate */ | |
| 581 | + const unsigned int lanes = 4; /* Only 4 lane support */ | |
| 582 | + u64 numerator = link_frequency * ddr * lanes; | |
| 583 | + | |
| 584 | + do_div(numerator, bpp); | |
| 585 | + | |
| 586 | + return numerator; | |
| 587 | +} | |
| 588 | + | |
| 589 | +/* Convert from a variable pixel_rate to 72 MHz clock cycles */ | |
| 590 | +static u64 imx283_internal_clock(unsigned int pixel_rate, unsigned int pixels) | |
| 591 | +{ | |
| 592 | + /* | |
| 593 | + * Determine the following operation without overflow: | |
| 594 | + * pixels = 72 Mhz / pixel_rate | |
| 595 | + * | |
| 596 | + * The internal clock at 72MHz and Pixel Rate (between 240 and 576MHz) | |
| 597 | + * can easily overflow this calculation, so pre-divide to simplify. | |
| 598 | + */ | |
| 599 | + const u32 iclk_pre = 72; | |
| 600 | + const u32 pclk_pre = pixel_rate / HZ_PER_MHZ; | |
| 601 | + u64 numerator = pixels * iclk_pre; | |
| 602 | + | |
| 603 | + do_div(numerator, pclk_pre); | |
| 604 | + | |
| 605 | + return numerator; | |
| 606 | +} | |
| 607 | + | |
| 608 | +/* Internal clock (72MHz) to Pixel Rate clock (Variable) */ | |
| 609 | +static u64 imx283_iclk_to_pix(unsigned int pixel_rate, unsigned int cycles) | |
| 610 | +{ | |
| 611 | + /* | |
| 612 | + * Determine the following operation without overflow: | |
| 613 | + * cycles * pixel_rate / 72 MHz | |
| 614 | + * | |
| 615 | + * The internal clock at 72MHz and Pixel Rate (between 240 and 576MHz) | |
| 616 | + * can easily overflow this calculation, so pre-divide to simplify. | |
| 617 | + */ | |
| 618 | + const u32 iclk_pre = 72; | |
| 619 | + const u32 pclk_pre = pixel_rate / HZ_PER_MHZ; | |
| 620 | + u64 numerator = cycles * pclk_pre; | |
| 621 | + | |
| 622 | + do_div(numerator, iclk_pre); | |
| 623 | + | |
| 624 | + return numerator; | |
| 625 | +} | |
| 626 | + | |
| 627 | +/* Determine the exposure based on current hmax, vmax and a given SHR */ | |
| 628 | +static u32 imx283_exposure(struct imx283 *imx283, | |
| 629 | + const struct imx283_mode *mode, u64 shr) | |
| 630 | +{ | |
| 631 | + u32 svr = 0; /* SVR feature is not currently supported */ | |
| 632 | + u32 offset; | |
| 633 | + u64 numerator; | |
| 634 | + | |
| 635 | + /* Number of clocks per internal offset period */ | |
| 636 | + offset = mode->mode == IMX283_MODE_0 ? 209 : 157; | |
| 637 | + numerator = (imx283->vmax * (svr + 1) - shr) * imx283->hmax + offset; | |
| 638 | + | |
| 639 | + do_div(numerator, imx283->hmax); | |
| 640 | + | |
| 641 | + return clamp(numerator, 0, U32_MAX); | |
| 642 | +} | |
| 643 | + | |
| 644 | +static void imx283_exposure_limits(struct imx283 *imx283, | |
| 645 | + const struct imx283_mode *mode, | |
| 646 | + s64 *min_exposure, s64 *max_exposure) | |
| 647 | +{ | |
| 648 | + u32 svr = 0; /* SVR feature is not currently supported */ | |
| 649 | + u64 min_shr = mode->min_shr; | |
| 650 | + /* Global Shutter is not supported */ | |
| 651 | + u64 max_shr = (svr + 1) * imx283->vmax - 4; | |
| 652 | + | |
| 653 | + max_shr = min(max_shr, BIT(16) - 1); | |
| 654 | + | |
| 655 | + *min_exposure = imx283_exposure(imx283, mode, max_shr); | |
| 656 | + *max_exposure = imx283_exposure(imx283, mode, min_shr); | |
| 657 | +} | |
| 658 | + | |
| 659 | +/* | |
| 660 | + * Integration Time [s] = [ {VMAX x (SVR + 1) – (SHR)} x HMAX + offset ] | |
| 661 | + * / [ 72 x 10^6 ] | |
| 662 | + */ | |
| 663 | +static u32 imx283_shr(struct imx283 *imx283, const struct imx283_mode *mode, | |
| 664 | + u32 exposure) | |
| 665 | +{ | |
| 666 | + u32 svr = 0; /* SVR feature is not currently supported */ | |
| 667 | + u32 offset; | |
| 668 | + u64 temp; | |
| 669 | + | |
| 670 | + /* Number of clocks per internal offset period */ | |
| 671 | + offset = mode->mode == IMX283_MODE_0 ? 209 : 157; | |
| 672 | + temp = ((u64)exposure * imx283->hmax - offset); | |
| 673 | + do_div(temp, imx283->hmax); | |
| 674 | + | |
| 675 | + return (imx283->vmax * (svr + 1) - temp); | |
| 676 | +} | |
| 677 | + | |
| 678 | +static const char * const imx283_tpg_menu[] = { | |
| 679 | + "Disabled", | |
| 680 | + "All 000h", | |
| 681 | + "All FFFh", | |
| 682 | + "All 555h", | |
| 683 | + "All AAAh", | |
| 684 | + "Horizontal color bars", | |
| 685 | + "Vertical color bars", | |
| 686 | +}; | |
| 687 | + | |
| 688 | +static const int imx283_tpg_val[] = { | |
| 689 | + IMX283_TPG_PAT_ALL_000, | |
| 690 | + IMX283_TPG_PAT_ALL_000, | |
| 691 | + IMX283_TPG_PAT_ALL_FFF, | |
| 692 | + IMX283_TPG_PAT_ALL_555, | |
| 693 | + IMX283_TPG_PAT_ALL_AAA, | |
| 694 | + IMX283_TPG_PAT_H_COLOR_BARS, | |
| 695 | + IMX283_TPG_PAT_V_COLOR_BARS, | |
| 696 | +}; | |
| 697 | + | |
| 698 | +static int imx283_update_test_pattern(struct imx283 *imx283, u32 pattern_index) | |
| 699 | +{ | |
| 700 | + int ret; | |
| 701 | + | |
| 702 | + if (pattern_index >= ARRAY_SIZE(imx283_tpg_val)) | |
| 703 | + return -EINVAL; | |
| 704 | + | |
| 705 | + if (!pattern_index) | |
| 706 | + return cci_write(imx283->cci, IMX283_REG_TPG_CTRL, 0x00, NULL); | |
| 707 | + | |
| 708 | + ret = cci_write(imx283->cci, IMX283_REG_TPG_PAT, | |
| 709 | + imx283_tpg_val[pattern_index], NULL); | |
| 710 | + if (ret) | |
| 711 | + return ret; | |
| 712 | + | |
| 713 | + return cci_write(imx283->cci, IMX283_REG_TPG_CTRL, | |
| 714 | + IMX283_TPG_CTRL_CLKEN | IMX283_TPG_CTRL_PATEN, NULL); | |
| 715 | +} | |
| 716 | + | |
| 717 | +static int imx283_set_ctrl(struct v4l2_ctrl *ctrl) | |
| 718 | +{ | |
| 719 | + struct imx283 *imx283 = container_of(ctrl->handler, struct imx283, | |
| 720 | + ctrl_handler); | |
| 721 | + const struct imx283_mode *mode; | |
| 722 | + struct v4l2_mbus_framefmt *fmt; | |
| 723 | + const struct imx283_mode *mode_list; | |
| 724 | + struct v4l2_subdev_state *state; | |
| 725 | + unsigned int num_modes; | |
| 726 | + u64 shr, pixel_rate; | |
| 727 | + int ret = 0; | |
| 728 | + | |
| 729 | + state = v4l2_subdev_get_locked_active_state(&imx283->sd); | |
| 730 | + fmt = v4l2_subdev_state_get_format(state, 0); | |
| 731 | + | |
| 732 | + get_mode_table(fmt->code, &mode_list, &num_modes); | |
| 733 | + mode = v4l2_find_nearest_size(mode_list, num_modes, width, height, | |
| 734 | + fmt->width, fmt->height); | |
| 735 | + | |
| 736 | + /* | |
| 737 | + * The VBLANK control may change the limits of usable exposure, so check | |
| 738 | + * and adjust if necessary. | |
| 739 | + */ | |
| 740 | + if (ctrl->id == V4L2_CID_VBLANK) { | |
| 741 | + /* Honour the VBLANK limits when setting exposure. */ | |
| 742 | + s64 current_exposure, max_exposure, min_exposure; | |
| 743 | + | |
| 744 | + imx283->vmax = mode->height + ctrl->val; | |
| 745 | + | |
| 746 | + imx283_exposure_limits(imx283, mode, | |
| 747 | + &min_exposure, &max_exposure); | |
| 748 | + | |
| 749 | + current_exposure = imx283->exposure->val; | |
| 750 | + current_exposure = clamp(current_exposure, min_exposure, | |
| 751 | + max_exposure); | |
| 752 | + | |
| 753 | + __v4l2_ctrl_modify_range(imx283->exposure, min_exposure, | |
| 754 | + max_exposure, 1, current_exposure); | |
| 755 | + } | |
| 756 | + | |
| 757 | + /* | |
| 758 | + * Applying V4L2 control value only happens | |
| 759 | + * when power is up for streaming | |
| 760 | + */ | |
| 761 | + if (!pm_runtime_get_if_active(imx283->dev)) | |
| 762 | + return 0; | |
| 763 | + | |
| 764 | + switch (ctrl->id) { | |
| 765 | + case V4L2_CID_EXPOSURE: | |
| 766 | + shr = imx283_shr(imx283, mode, ctrl->val); | |
| 767 | + dev_dbg(imx283->dev, "V4L2_CID_EXPOSURE : %d - SHR: %lld\n", | |
| 768 | + ctrl->val, shr); | |
| 769 | + ret = cci_write(imx283->cci, IMX283_REG_SHR, shr, NULL); | |
| 770 | + break; | |
| 771 | + | |
| 772 | + case V4L2_CID_HBLANK: | |
| 773 | + pixel_rate = imx283_pixel_rate(imx283, mode); | |
| 774 | + imx283->hmax = imx283_internal_clock(pixel_rate, mode->width + ctrl->val); | |
| 775 | + dev_dbg(imx283->dev, "V4L2_CID_HBLANK : %d HMAX : %u\n", | |
| 776 | + ctrl->val, imx283->hmax); | |
| 777 | + ret = cci_write(imx283->cci, IMX283_REG_HMAX, imx283->hmax, NULL); | |
| 778 | + break; | |
| 779 | + | |
| 780 | + case V4L2_CID_VBLANK: | |
| 781 | + imx283->vmax = mode->height + ctrl->val; | |
| 782 | + dev_dbg(imx283->dev, "V4L2_CID_VBLANK : %d VMAX : %u\n", | |
| 783 | + ctrl->val, imx283->vmax); | |
| 784 | + ret = cci_write(imx283->cci, IMX283_REG_VMAX, imx283->vmax, NULL); | |
| 785 | + break; | |
| 786 | + | |
| 787 | + case V4L2_CID_ANALOGUE_GAIN: | |
| 788 | + ret = cci_write(imx283->cci, IMX283_REG_ANALOG_GAIN, ctrl->val, NULL); | |
| 789 | + break; | |
| 790 | + | |
| 791 | + case V4L2_CID_DIGITAL_GAIN: | |
| 792 | + ret = cci_write(imx283->cci, IMX283_REG_DIGITAL_GAIN, ctrl->val, NULL); | |
| 793 | + break; | |
| 794 | + | |
| 795 | + case V4L2_CID_VFLIP: | |
| 796 | + /* | |
| 797 | + * VFLIP is managed by BIT(0) of IMX283_REG_HTRIMMING address, hence | |
| 798 | + * both need to be set simultaneously. | |
| 799 | + */ | |
| 800 | + if (ctrl->val) { | |
| 801 | + cci_write(imx283->cci, IMX283_REG_HTRIMMING, | |
| 802 | + IMX283_HTRIMMING_EN | IMX283_MDVREV, &ret); | |
| 803 | + } else { | |
| 804 | + cci_write(imx283->cci, IMX283_REG_HTRIMMING, | |
| 805 | + IMX283_HTRIMMING_EN, &ret); | |
| 806 | + } | |
| 807 | + break; | |
| 808 | + | |
| 809 | + case V4L2_CID_TEST_PATTERN: | |
| 810 | + ret = imx283_update_test_pattern(imx283, ctrl->val); | |
| 811 | + break; | |
| 812 | + | |
| 813 | + default: | |
| 814 | + dev_err(imx283->dev, "ctrl(id:0x%x, val:0x%x) is not handled\n", | |
| 815 | + ctrl->id, ctrl->val); | |
| 816 | + break; | |
| 817 | + } | |
| 818 | + | |
| 819 | + pm_runtime_put(imx283->dev); | |
| 820 | + | |
| 821 | + return ret; | |
| 822 | +} | |
| 823 | + | |
| 824 | +static const struct v4l2_ctrl_ops imx283_ctrl_ops = { | |
| 825 | + .s_ctrl = imx283_set_ctrl, | |
| 826 | +}; | |
| 827 | + | |
| 828 | +static int imx283_enum_mbus_code(struct v4l2_subdev *sd, | |
| 829 | + struct v4l2_subdev_state *sd_state, | |
| 830 | + struct v4l2_subdev_mbus_code_enum *code) | |
| 831 | +{ | |
| 832 | + if (code->index >= ARRAY_SIZE(imx283_mbus_codes)) | |
| 833 | + return -EINVAL; | |
| 834 | + | |
| 835 | + code->code = imx283_mbus_codes[code->index]; | |
| 836 | + | |
| 837 | + return 0; | |
| 838 | +} | |
| 839 | + | |
| 840 | +static int imx283_enum_frame_size(struct v4l2_subdev *sd, | |
| 841 | + struct v4l2_subdev_state *sd_state, | |
| 842 | + struct v4l2_subdev_frame_size_enum *fse) | |
| 843 | +{ | |
| 844 | + const struct imx283_mode *mode_list; | |
| 845 | + unsigned int num_modes; | |
| 846 | + | |
| 847 | + get_mode_table(fse->code, &mode_list, &num_modes); | |
| 848 | + | |
| 849 | + if (fse->index >= num_modes) | |
| 850 | + return -EINVAL; | |
| 851 | + | |
| 852 | + fse->min_width = mode_list[fse->index].width; | |
| 853 | + fse->max_width = fse->min_width; | |
| 854 | + fse->min_height = mode_list[fse->index].height; | |
| 855 | + fse->max_height = fse->min_height; | |
| 856 | + | |
| 857 | + return 0; | |
| 858 | +} | |
| 859 | + | |
| 860 | +static void imx283_update_image_pad_format(struct imx283 *imx283, | |
| 861 | + const struct imx283_mode *mode, | |
| 862 | + struct v4l2_mbus_framefmt *format) | |
| 863 | +{ | |
| 864 | + format->width = mode->width; | |
| 865 | + format->height = mode->height; | |
| 866 | + format->field = V4L2_FIELD_NONE; | |
| 867 | + format->colorspace = V4L2_COLORSPACE_RAW; | |
| 868 | + format->ycbcr_enc = V4L2_YCBCR_ENC_601; | |
| 869 | + format->quantization = V4L2_QUANTIZATION_FULL_RANGE; | |
| 870 | + format->xfer_func = V4L2_XFER_FUNC_NONE; | |
| 871 | +} | |
| 872 | + | |
| 873 | +static int imx283_init_state(struct v4l2_subdev *sd, | |
| 874 | + struct v4l2_subdev_state *state) | |
| 875 | +{ | |
| 876 | + struct imx283 *imx283 = to_imx283(sd); | |
| 877 | + struct v4l2_mbus_framefmt *format; | |
| 878 | + const struct imx283_mode *mode; | |
| 879 | + struct v4l2_rect *crop; | |
| 880 | + | |
| 881 | + /* Initialize try_fmt */ | |
| 882 | + format = v4l2_subdev_state_get_format(state, IMAGE_PAD); | |
| 883 | + | |
| 884 | + mode = &supported_modes_12bit[0]; | |
| 885 | + format->code = MEDIA_BUS_FMT_SRGGB12_1X12; | |
| 886 | + imx283_update_image_pad_format(imx283, mode, format); | |
| 887 | + | |
| 888 | + /* Initialize crop rectangle to mode default */ | |
| 889 | + crop = v4l2_subdev_state_get_crop(state, IMAGE_PAD); | |
| 890 | + *crop = mode->crop; | |
| 891 | + | |
| 892 | + return 0; | |
| 893 | +} | |
| 894 | + | |
| 895 | +static void imx283_set_framing_limits(struct imx283 *imx283, | |
| 896 | + const struct imx283_mode *mode) | |
| 897 | +{ | |
| 898 | + u64 pixel_rate = imx283_pixel_rate(imx283, mode); | |
| 899 | + u64 min_hblank, max_hblank, def_hblank; | |
| 900 | + | |
| 901 | + /* Initialise hmax and vmax for exposure calculations */ | |
| 902 | + imx283->hmax = imx283_internal_clock(pixel_rate, mode->default_hmax); | |
| 903 | + imx283->vmax = mode->default_vmax; | |
| 904 | + | |
| 905 | + /* | |
| 906 | + * Horizontal Blanking | |
| 907 | + * Convert the HMAX_MAX (72MHz) to Pixel rate values for HBLANK_MAX | |
| 908 | + */ | |
| 909 | + min_hblank = mode->min_hmax - mode->width; | |
| 910 | + max_hblank = imx283_iclk_to_pix(pixel_rate, IMX283_HMAX_MAX) - mode->width; | |
| 911 | + def_hblank = mode->default_hmax - mode->width; | |
| 912 | + __v4l2_ctrl_modify_range(imx283->hblank, min_hblank, max_hblank, 1, | |
| 913 | + def_hblank); | |
| 914 | + __v4l2_ctrl_s_ctrl(imx283->hblank, def_hblank); | |
| 915 | + | |
| 916 | + /* Vertical Blanking */ | |
| 917 | + __v4l2_ctrl_modify_range(imx283->vblank, mode->min_vmax - mode->height, | |
| 918 | + IMX283_VMAX_MAX - mode->height, 1, | |
| 919 | + mode->default_vmax - mode->height); | |
| 920 | + __v4l2_ctrl_s_ctrl(imx283->vblank, mode->default_vmax - mode->height); | |
| 921 | +} | |
| 922 | + | |
| 923 | +static int imx283_set_pad_format(struct v4l2_subdev *sd, | |
| 924 | + struct v4l2_subdev_state *sd_state, | |
| 925 | + struct v4l2_subdev_format *fmt) | |
| 926 | +{ | |
| 927 | + struct v4l2_mbus_framefmt *format; | |
| 928 | + const struct imx283_mode *mode; | |
| 929 | + struct imx283 *imx283 = to_imx283(sd); | |
| 930 | + const struct imx283_mode *mode_list; | |
| 931 | + unsigned int num_modes; | |
| 932 | + | |
| 933 | + get_mode_table(fmt->format.code, &mode_list, &num_modes); | |
| 934 | + | |
| 935 | + mode = v4l2_find_nearest_size(mode_list, num_modes, width, height, | |
| 936 | + fmt->format.width, fmt->format.height); | |
| 937 | + | |
| 938 | + fmt->format.width = mode->width; | |
| 939 | + fmt->format.height = mode->height; | |
| 940 | + fmt->format.field = V4L2_FIELD_NONE; | |
| 941 | + fmt->format.colorspace = V4L2_COLORSPACE_RAW; | |
| 942 | + fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601; | |
| 943 | + fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE; | |
| 944 | + fmt->format.xfer_func = V4L2_XFER_FUNC_NONE; | |
| 945 | + | |
| 946 | + format = v4l2_subdev_state_get_format(sd_state, 0); | |
| 947 | + | |
| 948 | + if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 949 | + imx283_set_framing_limits(imx283, mode); | |
| 950 | + | |
| 951 | + *format = fmt->format; | |
| 952 | + | |
| 953 | + return 0; | |
| 954 | +} | |
| 955 | + | |
| 956 | +static int imx283_standby_cancel(struct imx283 *imx283) | |
| 957 | +{ | |
| 958 | + unsigned int link_freq_idx; | |
| 959 | + int ret = 0; | |
| 960 | + | |
| 961 | + cci_write(imx283->cci, IMX283_REG_STANDBY, | |
| 962 | + IMX283_STBLOGIC | IMX283_STBDV, &ret); | |
| 963 | + | |
| 964 | + /* Configure PLL clocks based on the xclk */ | |
| 965 | + cci_multi_reg_write(imx283->cci, imx283->freq->regs, | |
| 966 | + imx283->freq->reg_count, &ret); | |
| 967 | + | |
| 968 | + dev_dbg(imx283->dev, "Using clk freq %ld MHz", | |
| 969 | + imx283->freq->mhz / HZ_PER_MHZ); | |
| 970 | + | |
| 971 | + /* Initialise communication */ | |
| 972 | + cci_write(imx283->cci, IMX283_REG_PLSTMG08, IMX283_PLSTMG08_VAL, &ret); | |
| 973 | + cci_write(imx283->cci, IMX283_REG_PLSTMG02, IMX283_PLSTMG02_VAL, &ret); | |
| 974 | + | |
| 975 | + /* Enable PLL */ | |
| 976 | + cci_write(imx283->cci, IMX283_REG_STBPL, IMX283_STBPL_NORMAL, &ret); | |
| 977 | + | |
| 978 | + /* Configure the MIPI link speed */ | |
| 979 | + link_freq_idx = __ffs(imx283->link_freq_bitmap); | |
| 980 | + cci_multi_reg_write(imx283->cci, link_freq_reglist[link_freq_idx].regs, | |
| 981 | + link_freq_reglist[link_freq_idx].num_of_regs, | |
| 982 | + &ret); | |
| 983 | + | |
| 984 | + /* 1st Stabilisation period of 1 ms or more */ | |
| 985 | + usleep_range(1000, 2000); | |
| 986 | + | |
| 987 | + /* Activate */ | |
| 988 | + cci_write(imx283->cci, IMX283_REG_STANDBY, IMX283_ACTIVE, &ret); | |
| 989 | + | |
| 990 | + /* 2nd Stabilisation period of 19ms or more */ | |
| 991 | + usleep_range(19000, 20000); | |
| 992 | + | |
| 993 | + cci_write(imx283->cci, IMX283_REG_CLAMP, IMX283_CLPSQRST, &ret); | |
| 994 | + cci_write(imx283->cci, IMX283_REG_XMSTA, 0, &ret); | |
| 995 | + cci_write(imx283->cci, IMX283_REG_SYNCDRV, IMX283_SYNCDRV_XHS_XVS, &ret); | |
| 996 | + | |
| 997 | + return ret; | |
| 998 | +} | |
| 999 | + | |
| 1000 | +/* Start streaming */ | |
| 1001 | +static int imx283_start_streaming(struct imx283 *imx283, | |
| 1002 | + struct v4l2_subdev_state *state) | |
| 1003 | +{ | |
| 1004 | + const struct imx283_readout_mode *readout; | |
| 1005 | + const struct imx283_mode *mode; | |
| 1006 | + const struct v4l2_mbus_framefmt *fmt; | |
| 1007 | + const struct imx283_mode *mode_list; | |
| 1008 | + unsigned int num_modes; | |
| 1009 | + u32 v_widcut; | |
| 1010 | + s32 v_pos; | |
| 1011 | + u32 write_v_size; | |
| 1012 | + u32 y_out_size; | |
| 1013 | + int ret = 0; | |
| 1014 | + | |
| 1015 | + fmt = v4l2_subdev_state_get_format(state, 0); | |
| 1016 | + get_mode_table(fmt->code, &mode_list, &num_modes); | |
| 1017 | + mode = v4l2_find_nearest_size(mode_list, num_modes, width, height, | |
| 1018 | + fmt->width, fmt->height); | |
| 1019 | + | |
| 1020 | + ret = imx283_standby_cancel(imx283); | |
| 1021 | + if (ret) { | |
| 1022 | + dev_err(imx283->dev, "failed to cancel standby\n"); | |
| 1023 | + return ret; | |
| 1024 | + } | |
| 1025 | + | |
| 1026 | + /* | |
| 1027 | + * Set the readout mode registers. | |
| 1028 | + * MDSEL3 and MDSEL4 are updated to enable Arbitrary Vertical Cropping. | |
| 1029 | + */ | |
| 1030 | + readout = &imx283_readout_modes[mode->mode]; | |
| 1031 | + cci_write(imx283->cci, IMX283_REG_MDSEL1, readout->mdsel1, &ret); | |
| 1032 | + cci_write(imx283->cci, IMX283_REG_MDSEL2, readout->mdsel2, &ret); | |
| 1033 | + cci_write(imx283->cci, IMX283_REG_MDSEL3, | |
| 1034 | + readout->mdsel3 | IMX283_MDSEL3_VCROP_EN, &ret); | |
| 1035 | + cci_write(imx283->cci, IMX283_REG_MDSEL4, | |
| 1036 | + readout->mdsel4 | IMX283_MDSEL4_VCROP_EN, &ret); | |
| 1037 | + | |
| 1038 | + /* Mode 1S specific entries from the Readout Drive Mode Tables */ | |
| 1039 | + if (mode->mode == IMX283_MODE_1S) { | |
| 1040 | + cci_write(imx283->cci, IMX283_REG_MDSEL7, 0x01, &ret); | |
| 1041 | + cci_write(imx283->cci, IMX283_REG_MDSEL18, 0x1098, &ret); | |
| 1042 | + } | |
| 1043 | + | |
| 1044 | + if (ret) { | |
| 1045 | + dev_err(imx283->dev, "failed to set readout\n"); | |
| 1046 | + return ret; | |
| 1047 | + } | |
| 1048 | + | |
| 1049 | + /* Initialise SVR. Unsupported for now - Always 0 */ | |
| 1050 | + cci_write(imx283->cci, IMX283_REG_SVR, 0x00, &ret); | |
| 1051 | + | |
| 1052 | + dev_dbg(imx283->dev, "Mode: Size %d x %d\n", mode->width, mode->height); | |
| 1053 | + dev_dbg(imx283->dev, "Analogue Crop (in the mode) %d,%d %dx%d\n", | |
| 1054 | + mode->crop.left, | |
| 1055 | + mode->crop.top, | |
| 1056 | + mode->crop.width, | |
| 1057 | + mode->crop.height); | |
| 1058 | + | |
| 1059 | + y_out_size = mode->crop.height / mode->vbin_ratio; | |
| 1060 | + write_v_size = y_out_size + mode->vertical_ob; | |
| 1061 | + /* | |
| 1062 | + * cropping start position = (VWINPOS – Vst) × 2 | |
| 1063 | + * cropping width = Veff – (VWIDCUT – Vct) × 2 | |
| 1064 | + */ | |
| 1065 | + v_pos = imx283->vflip->val ? | |
| 1066 | + ((-mode->crop.top / mode->vbin_ratio) / 2) + mode->vst : | |
| 1067 | + ((mode->crop.top / mode->vbin_ratio) / 2) + mode->vst; | |
| 1068 | + v_widcut = ((mode->veff - y_out_size) / 2) + mode->vct; | |
| 1069 | + | |
| 1070 | + cci_write(imx283->cci, IMX283_REG_Y_OUT_SIZE, y_out_size, &ret); | |
| 1071 | + cci_write(imx283->cci, IMX283_REG_WRITE_VSIZE, write_v_size, &ret); | |
| 1072 | + cci_write(imx283->cci, IMX283_REG_VWIDCUT, v_widcut, &ret); | |
| 1073 | + cci_write(imx283->cci, IMX283_REG_VWINPOS, v_pos, &ret); | |
| 1074 | + | |
| 1075 | + cci_write(imx283->cci, IMX283_REG_OB_SIZE_V, mode->vertical_ob, &ret); | |
| 1076 | + | |
| 1077 | + /* TODO: Validate mode->crop is fully contained within imx283_native_area */ | |
| 1078 | + cci_write(imx283->cci, IMX283_REG_HTRIMMING_START, mode->crop.left, &ret); | |
| 1079 | + cci_write(imx283->cci, IMX283_REG_HTRIMMING_END, | |
| 1080 | + mode->crop.left + mode->crop.width, &ret); | |
| 1081 | + | |
| 1082 | + /* Disable embedded data */ | |
| 1083 | + cci_write(imx283->cci, IMX283_REG_EBD_X_OUT_SIZE, 0, &ret); | |
| 1084 | + | |
| 1085 | + /* Apply customized values from controls (HMAX/VMAX/SHR) */ | |
| 1086 | + ret = __v4l2_ctrl_handler_setup(imx283->sd.ctrl_handler); | |
| 1087 | + | |
| 1088 | + return ret; | |
| 1089 | +} | |
| 1090 | + | |
| 1091 | +static int imx283_enable_streams(struct v4l2_subdev *sd, | |
| 1092 | + struct v4l2_subdev_state *state, u32 pad, | |
| 1093 | + u64 streams_mask) | |
| 1094 | +{ | |
| 1095 | + struct imx283 *imx283 = to_imx283(sd); | |
| 1096 | + int ret; | |
| 1097 | + | |
| 1098 | + if (pad != IMAGE_PAD) | |
| 1099 | + return -EINVAL; | |
| 1100 | + | |
| 1101 | + ret = pm_runtime_get_sync(imx283->dev); | |
| 1102 | + if (ret < 0) { | |
| 1103 | + pm_runtime_put_noidle(imx283->dev); | |
| 1104 | + return ret; | |
| 1105 | + } | |
| 1106 | + | |
| 1107 | + ret = imx283_start_streaming(imx283, state); | |
| 1108 | + if (ret) | |
| 1109 | + goto err_rpm_put; | |
| 1110 | + | |
| 1111 | + return 0; | |
| 1112 | + | |
| 1113 | +err_rpm_put: | |
| 1114 | + pm_runtime_mark_last_busy(imx283->dev); | |
| 1115 | + pm_runtime_put_autosuspend(imx283->dev); | |
| 1116 | + | |
| 1117 | + return ret; | |
| 1118 | +} | |
| 1119 | + | |
| 1120 | +static int imx283_disable_streams(struct v4l2_subdev *sd, | |
| 1121 | + struct v4l2_subdev_state *state, u32 pad, | |
| 1122 | + u64 streams_mask) | |
| 1123 | +{ | |
| 1124 | + struct imx283 *imx283 = to_imx283(sd); | |
| 1125 | + int ret; | |
| 1126 | + | |
| 1127 | + if (pad != IMAGE_PAD) | |
| 1128 | + return -EINVAL; | |
| 1129 | + | |
| 1130 | + ret = cci_write(imx283->cci, IMX283_REG_STANDBY, IMX283_STBLOGIC, NULL); | |
| 1131 | + if (ret) | |
| 1132 | + dev_err(imx283->dev, "Failed to stop stream\n"); | |
| 1133 | + | |
| 1134 | + pm_runtime_mark_last_busy(imx283->dev); | |
| 1135 | + pm_runtime_put_autosuspend(imx283->dev); | |
| 1136 | + | |
| 1137 | + return ret; | |
| 1138 | +} | |
| 1139 | + | |
| 1140 | +/* Power/clock management functions */ | |
| 1141 | +static int imx283_power_on(struct imx283 *imx283) | |
| 1142 | +{ | |
| 1143 | + int ret; | |
| 1144 | + | |
| 1145 | + ret = regulator_bulk_enable(ARRAY_SIZE(imx283_supply_name), | |
| 1146 | + imx283->supplies); | |
| 1147 | + if (ret) { | |
| 1148 | + dev_err(imx283->dev, "failed to enable regulators\n"); | |
| 1149 | + return ret; | |
| 1150 | + } | |
| 1151 | + | |
| 1152 | + ret = clk_prepare_enable(imx283->xclk); | |
| 1153 | + if (ret) { | |
| 1154 | + dev_err(imx283->dev, "failed to enable clock\n"); | |
| 1155 | + goto reg_off; | |
| 1156 | + } | |
| 1157 | + | |
| 1158 | + gpiod_set_value_cansleep(imx283->reset_gpio, 0); | |
| 1159 | + | |
| 1160 | + usleep_range(IMX283_XCLR_MIN_DELAY_US, | |
| 1161 | + IMX283_XCLR_MIN_DELAY_US + IMX283_XCLR_DELAY_RANGE_US); | |
| 1162 | + | |
| 1163 | + return 0; | |
| 1164 | + | |
| 1165 | +reg_off: | |
| 1166 | + regulator_bulk_disable(ARRAY_SIZE(imx283_supply_name), imx283->supplies); | |
| 1167 | + return ret; | |
| 1168 | +} | |
| 1169 | + | |
| 1170 | +static int imx283_power_off(struct imx283 *imx283) | |
| 1171 | +{ | |
| 1172 | + gpiod_set_value_cansleep(imx283->reset_gpio, 1); | |
| 1173 | + regulator_bulk_disable(ARRAY_SIZE(imx283_supply_name), imx283->supplies); | |
| 1174 | + clk_disable_unprepare(imx283->xclk); | |
| 1175 | + | |
| 1176 | + return 0; | |
| 1177 | +} | |
| 1178 | + | |
| 1179 | +static int imx283_runtime_resume(struct device *dev) | |
| 1180 | +{ | |
| 1181 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 1182 | + struct imx283 *imx283 = to_imx283(sd); | |
| 1183 | + | |
| 1184 | + return imx283_power_on(imx283); | |
| 1185 | +} | |
| 1186 | + | |
| 1187 | +static int imx283_runtime_suspend(struct device *dev) | |
| 1188 | +{ | |
| 1189 | + struct v4l2_subdev *sd = dev_get_drvdata(dev); | |
| 1190 | + struct imx283 *imx283 = to_imx283(sd); | |
| 1191 | + | |
| 1192 | + imx283_power_off(imx283); | |
| 1193 | + | |
| 1194 | + return 0; | |
| 1195 | +} | |
| 1196 | + | |
| 1197 | +static int imx283_get_regulators(struct imx283 *imx283) | |
| 1198 | +{ | |
| 1199 | + unsigned int i; | |
| 1200 | + | |
| 1201 | + for (i = 0; i < ARRAY_SIZE(imx283_supply_name); i++) | |
| 1202 | + imx283->supplies[i].supply = imx283_supply_name[i]; | |
| 1203 | + | |
| 1204 | + return devm_regulator_bulk_get(imx283->dev, | |
| 1205 | + ARRAY_SIZE(imx283_supply_name), | |
| 1206 | + imx283->supplies); | |
| 1207 | +} | |
| 1208 | + | |
| 1209 | +/* Verify chip ID */ | |
| 1210 | +static int imx283_identify_module(struct imx283 *imx283) | |
| 1211 | +{ | |
| 1212 | + int ret; | |
| 1213 | + u64 val; | |
| 1214 | + | |
| 1215 | + ret = cci_read(imx283->cci, IMX283_REG_CHIP_ID, &val, NULL); | |
| 1216 | + if (ret) { | |
| 1217 | + dev_err(imx283->dev, "failed to read chip id %x, with error %d\n", | |
| 1218 | + IMX283_CHIP_ID, ret); | |
| 1219 | + return ret; | |
| 1220 | + } | |
| 1221 | + | |
| 1222 | + if (val != IMX283_CHIP_ID) { | |
| 1223 | + dev_err(imx283->dev, "chip id mismatch: %x!=%llx\n", | |
| 1224 | + IMX283_CHIP_ID, val); | |
| 1225 | + return -EIO; | |
| 1226 | + } | |
| 1227 | + | |
| 1228 | + return 0; | |
| 1229 | +} | |
| 1230 | + | |
| 1231 | +static int imx283_get_selection(struct v4l2_subdev *sd, | |
| 1232 | + struct v4l2_subdev_state *sd_state, | |
| 1233 | + struct v4l2_subdev_selection *sel) | |
| 1234 | +{ | |
| 1235 | + switch (sel->target) { | |
| 1236 | + case V4L2_SEL_TGT_CROP: { | |
| 1237 | + sel->r = *v4l2_subdev_state_get_crop(sd_state, 0); | |
| 1238 | + return 0; | |
| 1239 | + } | |
| 1240 | + | |
| 1241 | + case V4L2_SEL_TGT_NATIVE_SIZE: | |
| 1242 | + sel->r = imx283_native_area; | |
| 1243 | + return 0; | |
| 1244 | + | |
| 1245 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 1246 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 1247 | + sel->r = imx283_active_area; | |
| 1248 | + return 0; | |
| 1249 | + default: | |
| 1250 | + return -EINVAL; | |
| 1251 | + } | |
| 1252 | +} | |
| 1253 | + | |
| 1254 | +static const struct v4l2_subdev_core_ops imx283_core_ops = { | |
| 1255 | + .subscribe_event = v4l2_ctrl_subdev_subscribe_event, | |
| 1256 | + .unsubscribe_event = v4l2_event_subdev_unsubscribe, | |
| 1257 | +}; | |
| 1258 | + | |
| 1259 | +static const struct v4l2_subdev_video_ops imx283_video_ops = { | |
| 1260 | + .s_stream = v4l2_subdev_s_stream_helper, | |
| 1261 | +}; | |
| 1262 | + | |
| 1263 | +static const struct v4l2_subdev_pad_ops imx283_pad_ops = { | |
| 1264 | + .enum_mbus_code = imx283_enum_mbus_code, | |
| 1265 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 1266 | + .set_fmt = imx283_set_pad_format, | |
| 1267 | + .get_selection = imx283_get_selection, | |
| 1268 | + .enum_frame_size = imx283_enum_frame_size, | |
| 1269 | + .enable_streams = imx283_enable_streams, | |
| 1270 | + .disable_streams = imx283_disable_streams, | |
| 1271 | +}; | |
| 1272 | + | |
| 1273 | +static const struct v4l2_subdev_internal_ops imx283_internal_ops = { | |
| 1274 | + .init_state = imx283_init_state, | |
| 1275 | +}; | |
| 1276 | + | |
| 1277 | +static const struct v4l2_subdev_ops imx283_subdev_ops = { | |
| 1278 | + .core = &imx283_core_ops, | |
| 1279 | + .video = &imx283_video_ops, | |
| 1280 | + .pad = &imx283_pad_ops, | |
| 1281 | +}; | |
| 1282 | + | |
| 1283 | +/* Initialize control handlers */ | |
| 1284 | +static int imx283_init_controls(struct imx283 *imx283) | |
| 1285 | +{ | |
| 1286 | + struct v4l2_ctrl_handler *ctrl_hdlr; | |
| 1287 | + struct v4l2_fwnode_device_properties props; | |
| 1288 | + struct v4l2_ctrl *link_freq; | |
| 1289 | + const struct imx283_mode *mode = &supported_modes_12bit[0]; | |
| 1290 | + u64 min_hblank, max_hblank, def_hblank; | |
| 1291 | + u64 pixel_rate; | |
| 1292 | + int ret; | |
| 1293 | + | |
| 1294 | + ctrl_hdlr = &imx283->ctrl_handler; | |
| 1295 | + ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16); | |
| 1296 | + if (ret) | |
| 1297 | + return ret; | |
| 1298 | + | |
| 1299 | + /* | |
| 1300 | + * Create the controls here, but mode specific limits are setup | |
| 1301 | + * in the imx283_set_framing_limits() call below. | |
| 1302 | + */ | |
| 1303 | + | |
| 1304 | + /* By default, PIXEL_RATE is read only */ | |
| 1305 | + pixel_rate = imx283_pixel_rate(imx283, mode); | |
| 1306 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1307 | + V4L2_CID_PIXEL_RATE, pixel_rate, | |
| 1308 | + pixel_rate, 1, pixel_rate); | |
| 1309 | + | |
| 1310 | + link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1311 | + V4L2_CID_LINK_FREQ, | |
| 1312 | + __fls(imx283->link_freq_bitmap), | |
| 1313 | + __ffs(imx283->link_freq_bitmap), | |
| 1314 | + link_frequencies); | |
| 1315 | + if (link_freq) | |
| 1316 | + link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | |
| 1317 | + | |
| 1318 | + /* Initialise vblank/hblank/exposure based on the current mode. */ | |
| 1319 | + imx283->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1320 | + V4L2_CID_VBLANK, | |
| 1321 | + mode->min_vmax - mode->height, | |
| 1322 | + IMX283_VMAX_MAX, 1, | |
| 1323 | + mode->default_vmax - mode->height); | |
| 1324 | + | |
| 1325 | + min_hblank = mode->min_hmax - mode->width; | |
| 1326 | + max_hblank = imx283_iclk_to_pix(pixel_rate, IMX283_HMAX_MAX) - mode->width; | |
| 1327 | + def_hblank = mode->default_hmax - mode->width; | |
| 1328 | + imx283->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1329 | + V4L2_CID_HBLANK, min_hblank, max_hblank, | |
| 1330 | + 1, def_hblank); | |
| 1331 | + | |
| 1332 | + imx283->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1333 | + V4L2_CID_EXPOSURE, | |
| 1334 | + IMX283_EXPOSURE_MIN, | |
| 1335 | + IMX283_EXPOSURE_MAX, | |
| 1336 | + IMX283_EXPOSURE_STEP, | |
| 1337 | + IMX283_EXPOSURE_DEFAULT); | |
| 1338 | + | |
| 1339 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, V4L2_CID_ANALOGUE_GAIN, | |
| 1340 | + IMX283_ANA_GAIN_MIN, IMX283_ANA_GAIN_MAX, | |
| 1341 | + IMX283_ANA_GAIN_STEP, IMX283_ANA_GAIN_DEFAULT); | |
| 1342 | + | |
| 1343 | + v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, V4L2_CID_DIGITAL_GAIN, | |
| 1344 | + IMX283_DGTL_GAIN_MIN, IMX283_DGTL_GAIN_MAX, | |
| 1345 | + IMX283_DGTL_GAIN_STEP, IMX283_DGTL_GAIN_DEFAULT); | |
| 1346 | + | |
| 1347 | + imx283->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, V4L2_CID_VFLIP, | |
| 1348 | + 0, 1, 1, 0); | |
| 1349 | + if (imx283->vflip) | |
| 1350 | + imx283->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; | |
| 1351 | + | |
| 1352 | + v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1353 | + V4L2_CID_TEST_PATTERN, | |
| 1354 | + ARRAY_SIZE(imx283_tpg_menu) - 1, | |
| 1355 | + 0, 0, imx283_tpg_menu); | |
| 1356 | + | |
| 1357 | + if (ctrl_hdlr->error) { | |
| 1358 | + ret = ctrl_hdlr->error; | |
| 1359 | + dev_err(imx283->dev, "control init failed (%d)\n", ret); | |
| 1360 | + goto error; | |
| 1361 | + } | |
| 1362 | + | |
| 1363 | + ret = v4l2_fwnode_device_parse(imx283->dev, &props); | |
| 1364 | + if (ret) | |
| 1365 | + goto error; | |
| 1366 | + | |
| 1367 | + ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx283_ctrl_ops, | |
| 1368 | + &props); | |
| 1369 | + if (ret) | |
| 1370 | + goto error; | |
| 1371 | + | |
| 1372 | + imx283->sd.ctrl_handler = ctrl_hdlr; | |
| 1373 | + | |
| 1374 | + mutex_lock(imx283->ctrl_handler.lock); | |
| 1375 | + | |
| 1376 | + /* Setup exposure and frame/line length limits. */ | |
| 1377 | + imx283_set_framing_limits(imx283, mode); | |
| 1378 | + | |
| 1379 | + mutex_unlock(imx283->ctrl_handler.lock); | |
| 1380 | + | |
| 1381 | + return 0; | |
| 1382 | + | |
| 1383 | +error: | |
| 1384 | + v4l2_ctrl_handler_free(ctrl_hdlr); | |
| 1385 | + | |
| 1386 | + return ret; | |
| 1387 | +} | |
| 1388 | + | |
| 1389 | +static int imx283_parse_endpoint(struct imx283 *imx283) | |
| 1390 | +{ | |
| 1391 | + struct fwnode_handle *fwnode; | |
| 1392 | + struct v4l2_fwnode_endpoint bus_cfg = { | |
| 1393 | + .bus_type = V4L2_MBUS_CSI2_DPHY | |
| 1394 | + }; | |
| 1395 | + struct fwnode_handle *ep; | |
| 1396 | + int ret; | |
| 1397 | + | |
| 1398 | + fwnode = dev_fwnode(imx283->dev); | |
| 1399 | + ep = fwnode_graph_get_next_endpoint(fwnode, NULL); | |
| 1400 | + if (!ep) { | |
| 1401 | + dev_err(imx283->dev, "Failed to get next endpoint\n"); | |
| 1402 | + return -ENXIO; | |
| 1403 | + } | |
| 1404 | + | |
| 1405 | + ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg); | |
| 1406 | + fwnode_handle_put(ep); | |
| 1407 | + if (ret) | |
| 1408 | + return ret; | |
| 1409 | + | |
| 1410 | + if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) { | |
| 1411 | + dev_err(imx283->dev, | |
| 1412 | + "number of CSI2 data lanes %d is not supported\n", | |
| 1413 | + bus_cfg.bus.mipi_csi2.num_data_lanes); | |
| 1414 | + ret = -EINVAL; | |
| 1415 | + goto done_endpoint_free; | |
| 1416 | + } | |
| 1417 | + | |
| 1418 | + ret = v4l2_link_freq_to_bitmap(imx283->dev, bus_cfg.link_frequencies, | |
| 1419 | + bus_cfg.nr_of_link_frequencies, | |
| 1420 | + link_frequencies, ARRAY_SIZE(link_frequencies), | |
| 1421 | + &imx283->link_freq_bitmap); | |
| 1422 | + | |
| 1423 | +done_endpoint_free: | |
| 1424 | + v4l2_fwnode_endpoint_free(&bus_cfg); | |
| 1425 | + | |
| 1426 | + return ret; | |
| 1427 | +}; | |
| 1428 | + | |
| 1429 | +static int imx283_probe(struct i2c_client *client) | |
| 1430 | +{ | |
| 1431 | + struct imx283 *imx283; | |
| 1432 | + unsigned int i; | |
| 1433 | + unsigned int xclk_freq; | |
| 1434 | + int ret; | |
| 1435 | + | |
| 1436 | + imx283 = devm_kzalloc(&client->dev, sizeof(*imx283), GFP_KERNEL); | |
| 1437 | + if (!imx283) | |
| 1438 | + return -ENOMEM; | |
| 1439 | + | |
| 1440 | + imx283->dev = &client->dev; | |
| 1441 | + | |
| 1442 | + v4l2_i2c_subdev_init(&imx283->sd, client, &imx283_subdev_ops); | |
| 1443 | + | |
| 1444 | + imx283->cci = devm_cci_regmap_init_i2c(client, 16); | |
| 1445 | + if (IS_ERR(imx283->cci)) { | |
| 1446 | + ret = PTR_ERR(imx283->cci); | |
| 1447 | + dev_err(imx283->dev, "failed to initialize CCI: %d\n", ret); | |
| 1448 | + return ret; | |
| 1449 | + } | |
| 1450 | + | |
| 1451 | + /* Get system clock (xclk) */ | |
| 1452 | + imx283->xclk = devm_clk_get(imx283->dev, NULL); | |
| 1453 | + if (IS_ERR(imx283->xclk)) { | |
| 1454 | + return dev_err_probe(imx283->dev, PTR_ERR(imx283->xclk), | |
| 1455 | + "failed to get xclk\n"); | |
| 1456 | + } | |
| 1457 | + | |
| 1458 | + xclk_freq = clk_get_rate(imx283->xclk); | |
| 1459 | + for (i = 0; i < ARRAY_SIZE(imx283_frequencies); i++) { | |
| 1460 | + if (xclk_freq == imx283_frequencies[i].mhz) { | |
| 1461 | + imx283->freq = &imx283_frequencies[i]; | |
| 1462 | + break; | |
| 1463 | + } | |
| 1464 | + } | |
| 1465 | + if (!imx283->freq) { | |
| 1466 | + dev_err(imx283->dev, "xclk frequency unsupported: %d Hz\n", xclk_freq); | |
| 1467 | + return -EINVAL; | |
| 1468 | + } | |
| 1469 | + | |
| 1470 | + ret = imx283_get_regulators(imx283); | |
| 1471 | + if (ret) { | |
| 1472 | + return dev_err_probe(imx283->dev, ret, | |
| 1473 | + "failed to get regulators\n"); | |
| 1474 | + } | |
| 1475 | + | |
| 1476 | + ret = imx283_parse_endpoint(imx283); | |
| 1477 | + if (ret) { | |
| 1478 | + dev_err(imx283->dev, "failed to parse endpoint configuration\n"); | |
| 1479 | + return ret; | |
| 1480 | + } | |
| 1481 | + | |
| 1482 | + /* Request optional enable pin */ | |
| 1483 | + imx283->reset_gpio = devm_gpiod_get_optional(imx283->dev, "reset", | |
| 1484 | + GPIOD_OUT_LOW); | |
| 1485 | + if (IS_ERR(imx283->reset_gpio)) | |
| 1486 | + return dev_err_probe(imx283->dev, PTR_ERR(imx283->reset_gpio), | |
| 1487 | + "failed to get reset GPIO\n"); | |
| 1488 | + | |
| 1489 | + /* | |
| 1490 | + * The sensor must be powered for imx283_identify_module() | |
| 1491 | + * to be able to read the CHIP_ID register | |
| 1492 | + */ | |
| 1493 | + ret = imx283_power_on(imx283); | |
| 1494 | + if (ret) | |
| 1495 | + return ret; | |
| 1496 | + | |
| 1497 | + ret = imx283_identify_module(imx283); | |
| 1498 | + if (ret) | |
| 1499 | + goto error_power_off; | |
| 1500 | + | |
| 1501 | + /* | |
| 1502 | + * Enable runtime PM with autosuspend. As the device has been powered | |
| 1503 | + * manually, mark it as active, and increase the usage count without | |
| 1504 | + * resuming the device. | |
| 1505 | + */ | |
| 1506 | + pm_runtime_set_active(imx283->dev); | |
| 1507 | + pm_runtime_get_noresume(imx283->dev); | |
| 1508 | + pm_runtime_enable(imx283->dev); | |
| 1509 | + pm_runtime_set_autosuspend_delay(imx283->dev, 1000); | |
| 1510 | + pm_runtime_use_autosuspend(imx283->dev); | |
| 1511 | + | |
| 1512 | + /* This needs the pm runtime to be registered. */ | |
| 1513 | + ret = imx283_init_controls(imx283); | |
| 1514 | + if (ret) | |
| 1515 | + goto error_pm; | |
| 1516 | + | |
| 1517 | + /* Initialize subdev */ | |
| 1518 | + imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | | |
| 1519 | + V4L2_SUBDEV_FL_HAS_EVENTS; | |
| 1520 | + imx283->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR; | |
| 1521 | + imx283->sd.internal_ops = &imx283_internal_ops; | |
| 1522 | + | |
| 1523 | + /* Initialize source pads */ | |
| 1524 | + imx283->pad.flags = MEDIA_PAD_FL_SOURCE; | |
| 1525 | + | |
| 1526 | + ret = media_entity_pads_init(&imx283->sd.entity, 1, &imx283->pad); | |
| 1527 | + if (ret) { | |
| 1528 | + dev_err(imx283->dev, "failed to init entity pads: %d\n", ret); | |
| 1529 | + goto error_handler_free; | |
| 1530 | + } | |
| 1531 | + | |
| 1532 | + imx283->sd.state_lock = imx283->ctrl_handler.lock; | |
| 1533 | + ret = v4l2_subdev_init_finalize(&imx283->sd); | |
| 1534 | + if (ret < 0) { | |
| 1535 | + dev_err(imx283->dev, "subdev init error: %d\n", ret); | |
| 1536 | + goto error_media_entity; | |
| 1537 | + } | |
| 1538 | + | |
| 1539 | + ret = v4l2_async_register_subdev_sensor(&imx283->sd); | |
| 1540 | + if (ret < 0) { | |
| 1541 | + dev_err(imx283->dev, "failed to register sensor sub-device: %d\n", ret); | |
| 1542 | + goto error_subdev_cleanup; | |
| 1543 | + } | |
| 1544 | + | |
| 1545 | + /* | |
| 1546 | + * Decrease the PM usage count. The device will get suspended after the | |
| 1547 | + * autosuspend delay, turning the power off. | |
| 1548 | + */ | |
| 1549 | + pm_runtime_mark_last_busy(imx283->dev); | |
| 1550 | + pm_runtime_put_autosuspend(imx283->dev); | |
| 1551 | + | |
| 1552 | + return 0; | |
| 1553 | + | |
| 1554 | +error_subdev_cleanup: | |
| 1555 | + v4l2_subdev_cleanup(&imx283->sd); | |
| 1556 | + | |
| 1557 | +error_media_entity: | |
| 1558 | + media_entity_cleanup(&imx283->sd.entity); | |
| 1559 | + | |
| 1560 | +error_handler_free: | |
| 1561 | + v4l2_ctrl_handler_free(imx283->sd.ctrl_handler); | |
| 1562 | + | |
| 1563 | +error_pm: | |
| 1564 | + pm_runtime_disable(imx283->dev); | |
| 1565 | + pm_runtime_set_suspended(imx283->dev); | |
| 1566 | +error_power_off: | |
| 1567 | + imx283_power_off(imx283); | |
| 1568 | + | |
| 1569 | + return ret; | |
| 1570 | +} | |
| 1571 | + | |
| 1572 | +static void imx283_remove(struct i2c_client *client) | |
| 1573 | +{ | |
| 1574 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 1575 | + struct imx283 *imx283 = to_imx283(sd); | |
| 1576 | + | |
| 1577 | + v4l2_async_unregister_subdev(sd); | |
| 1578 | + v4l2_subdev_cleanup(&imx283->sd); | |
| 1579 | + media_entity_cleanup(&sd->entity); | |
| 1580 | + v4l2_ctrl_handler_free(imx283->sd.ctrl_handler); | |
| 1581 | + | |
| 1582 | + pm_runtime_disable(imx283->dev); | |
| 1583 | + if (!pm_runtime_status_suspended(imx283->dev)) | |
| 1584 | + imx283_power_off(imx283); | |
| 1585 | + pm_runtime_set_suspended(imx283->dev); | |
| 1586 | +} | |
| 1587 | + | |
| 1588 | +static DEFINE_RUNTIME_DEV_PM_OPS(imx283_pm_ops, imx283_runtime_suspend, | |
| 1589 | + imx283_runtime_resume, NULL); | |
| 1590 | + | |
| 1591 | +static const struct of_device_id imx283_dt_ids[] = { | |
| 1592 | + { .compatible = "sony,imx283" }, | |
| 1593 | + { /* sentinel */ } | |
| 1594 | +}; | |
| 1595 | +MODULE_DEVICE_TABLE(of, imx283_dt_ids); | |
| 1596 | + | |
| 1597 | +static struct i2c_driver imx283_i2c_driver = { | |
| 1598 | + .driver = { | |
| 1599 | + .name = "imx283", | |
| 1600 | + .pm = pm_ptr(&imx283_pm_ops), | |
| 1601 | + .of_match_table = imx283_dt_ids, | |
| 1602 | + }, | |
| 1603 | + .probe = imx283_probe, | |
| 1604 | + .remove = imx283_remove, | |
| 1605 | +}; | |
| 1606 | +module_i2c_driver(imx283_i2c_driver); | |
| 1607 | + | |
| 1608 | +MODULE_AUTHOR("Will Whang <will@willwhang.com>"); | |
| 1609 | +MODULE_AUTHOR("Kieran Bingham <kieran.bingham@ideasonboard.com>"); | |
| 1610 | +MODULE_AUTHOR("Umang Jain <umang.jain@ideasonboard.com>"); | |
| 1611 | +MODULE_DESCRIPTION("Sony IMX283 Sensor Driver"); | |
| 1612 | +MODULE_LICENSE("GPL"); | |
| @@ -542,14 +542,13 @@ static int imx412_update_controls(struct imx412 *imx412, · 541 unmodified lines | ||
| 542 | 542 | */ |
| 543 | 543 | static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) |
| 544 | 544 | { |
| 545 | − u32 lpfr, shutter; | |
| 545 | + u32 lpfr; | |
| 546 | 546 | int ret; |
| 547 | 547 | |
| 548 | 548 | lpfr = imx412->vblank + imx412->cur_mode->height; |
| 549 | − shutter = lpfr - exposure; | |
| 550 | 549 | |
| 551 | − dev_dbg(imx412->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u", | |
| 552 | − exposure, gain, shutter, lpfr); | |
| 550 | + dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u", | |
| 551 | + exposure, gain, lpfr); | |
| 553 | 552 | |
| 554 | 553 | ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); |
| 555 | 554 | if (ret) |
| @@ -559,7 +558,7 @@ static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) · 3 unmodified lines | ||
| 559 | 558 | if (ret) |
| 560 | 559 | goto error_release_group_hold; |
| 561 | 560 | |
| 562 | − ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, shutter); | |
| 561 | + ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure); | |
| 563 | 562 | if (ret) |
| 564 | 563 | goto error_release_group_hold; |
| 565 | 564 | |
| @@ -175,14 +175,6 @@ MODULE_LICENSE("GPL"); · 174 unmodified lines | ||
| 175 | 175 | * mga_dev : represents one ks0127 chip. |
| 176 | 176 | ****************************************************************************/ |
| 177 | 177 | |
| 178 | −struct adjust { | |
| 179 | − int contrast; | |
| 180 | − int bright; | |
| 181 | − int hue; | |
| 182 | − int ugain; | |
| 183 | − int vgain; | |
| 184 | −}; | |
| 185 | − | |
| 186 | 178 | struct ks0127 { |
| 187 | 179 | struct v4l2_subdev sd; |
| 188 | 180 | v4l2_std_id norm; |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/i2c.h> |
| 20 | 20 | #include <linux/i2c-mux.h> |
| 21 | 21 | #include <linux/module.h> |
| 22 | −#include <linux/mutex.h> | |
| 23 | 22 | #include <linux/of_graph.h> |
| 24 | 23 | #include <linux/regulator/consumer.h> |
| 25 | 24 | #include <linux/slab.h> |
| @@ -198,12 +197,6 @@ struct max9286_priv { · 172 unmodified lines | ||
| 198 | 197 | struct v4l2_ctrl *pixelrate_ctrl; |
| 199 | 198 | unsigned int pixelrate; |
| 200 | 199 | |
| 201 | − struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS]; | |
| 202 | − struct v4l2_fract interval; | |
| 203 | − | |
| 204 | − /* Protects controls and fmt structures */ | |
| 205 | − struct mutex mutex; | |
| 206 | − | |
| 207 | 200 | unsigned int nsources; |
| 208 | 201 | unsigned int source_mask; |
| 209 | 202 | unsigned int route_mask; |
| @@ -576,11 +569,14 @@ static void max9286_set_video_format(struct max9286_priv *priv, · 366 unmodified lines | ||
| 576 | 569 | MAX9286_INVVS | MAX9286_HVSRC_D14); |
| 577 | 570 | } |
| 578 | 571 | |
| 579 | −static void max9286_set_fsync_period(struct max9286_priv *priv) | |
| 572 | +static void max9286_set_fsync_period(struct max9286_priv *priv, | |
| 573 | + struct v4l2_subdev_state *state) | |
| 580 | 574 | { |
| 575 | + const struct v4l2_fract *interval; | |
| 581 | 576 | u32 fsync; |
| 582 | 577 | |
| 583 | − if (!priv->interval.numerator || !priv->interval.denominator) { | |
| 578 | + interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD); | |
| 579 | + if (!interval->numerator || !interval->denominator) { | |
| 584 | 580 | /* |
| 585 | 581 | * Special case, a null interval enables automatic FRAMESYNC |
| 586 | 582 | * mode. FRAMESYNC is taken from the slowest link. |
| @@ -596,8 +592,8 @@ static void max9286_set_fsync_period(struct max9286_priv *priv) · 9 unmodified lines | ||
| 596 | 592 | * The FRAMESYNC generator is configured with a period expressed as a |
| 597 | 593 | * number of PCLK periods. |
| 598 | 594 | */ |
| 599 | − fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator, | |
| 600 | − priv->interval.denominator); | |
| 595 | + fsync = div_u64((u64)priv->pixelrate * interval->numerator, | |
| 596 | + interval->denominator); | |
| 601 | 597 | |
| 602 | 598 | dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync, |
| 603 | 599 | priv->pixelrate); |
| @@ -788,22 +784,25 @@ static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv) · 184 unmodified lines | ||
| 788 | 784 | static int max9286_s_stream(struct v4l2_subdev *sd, int enable) |
| 789 | 785 | { |
| 790 | 786 | struct max9286_priv *priv = sd_to_max9286(sd); |
| 787 | + struct v4l2_subdev_state *state; | |
| 791 | 788 | struct max9286_source *source; |
| 792 | 789 | unsigned int i; |
| 793 | 790 | bool sync = false; |
| 794 | − int ret; | |
| 791 | + int ret = 0; | |
| 792 | + | |
| 793 | + state = v4l2_subdev_lock_and_get_active_state(sd); | |
| 795 | 794 | |
| 796 | 795 | if (enable) { |
| 797 | 796 | const struct v4l2_mbus_framefmt *format; |
| 798 | 797 | |
| 799 | 798 | /* |
| 800 | − * Get the format from the first used sink pad, as all sink | |
| 801 | − * formats must be identical. | |
| 799 | + * Get the format from the source pad, as all formats must be | |
| 800 | + * identical. | |
| 802 | 801 | */ |
| 803 | − format = &priv->fmt[__ffs(priv->bound_sources)]; | |
| 802 | + format = v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD); | |
| 804 | 803 | |
| 805 | 804 | max9286_set_video_format(priv, format); |
| 806 | − max9286_set_fsync_period(priv); | |
| 805 | + max9286_set_fsync_period(priv, state); | |
| 807 | 806 | |
| 808 | 807 | /* |
| 809 | 808 | * The frame sync between cameras is transmitted across the |
| @@ -816,12 +815,12 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) · 6 unmodified lines | ||
| 816 | 815 | for_each_source(priv, source) { |
| 817 | 816 | ret = v4l2_subdev_call(source->sd, video, s_stream, 1); |
| 818 | 817 | if (ret) |
| 819 | − return ret; | |
| 818 | + goto unlock; | |
| 820 | 819 | } |
| 821 | 820 | |
| 822 | 821 | ret = max9286_check_video_links(priv); |
| 823 | 822 | if (ret) |
| 824 | − return ret; | |
| 823 | + goto unlock; | |
| 825 | 824 | |
| 826 | 825 | /* |
| 827 | 826 | * Wait until frame synchronization is locked. |
| @@ -842,7 +841,8 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) · 14 unmodified lines | ||
| 842 | 841 | if (!sync) { |
| 843 | 842 | dev_err(&priv->client->dev, |
| 844 | 843 | "Failed to get frame synchronization\n"); |
| 845 | − return -EXDEV; /* Invalid cross-device link */ | |
| 844 | + ret = -EXDEV; /* Invalid cross-device link */ | |
| 845 | + goto unlock; | |
| 846 | 846 | } |
| 847 | 847 | |
| 848 | 848 | /* |
| @@ -865,26 +865,21 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable) · 16 unmodified lines | ||
| 865 | 865 | max9286_i2c_mux_close(priv); |
| 866 | 866 | } |
| 867 | 867 | |
| 868 | − return 0; | |
| 868 | +unlock: | |
| 869 | + v4l2_subdev_unlock_state(state); | |
| 870 | + | |
| 871 | + return ret; | |
| 869 | 872 | } |
| 870 | 873 | |
| 871 | 874 | static int max9286_get_frame_interval(struct v4l2_subdev *sd, |
| 872 | 875 | struct v4l2_subdev_state *sd_state, |
| 873 | 876 | struct v4l2_subdev_frame_interval *interval) |
| 874 | 877 | { |
| 875 | − struct max9286_priv *priv = sd_to_max9286(sd); | |
| 876 | − | |
| 877 | − /* | |
| 878 | − * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 | |
| 879 | − * subdev active state API. | |
| 880 | − */ | |
| 881 | − if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 882 | − return -EINVAL; | |
| 883 | − | |
| 884 | 878 | if (interval->pad != MAX9286_SRC_PAD) |
| 885 | 879 | return -EINVAL; |
| 886 | 880 | |
| 887 | − interval->interval = priv->interval; | |
| 881 | + interval->interval = *v4l2_subdev_state_get_interval(sd_state, | |
| 882 | + interval->pad); | |
| 888 | 883 | |
| 889 | 884 | return 0; |
| 890 | 885 | } |
| @@ -893,19 +888,11 @@ static int max9286_set_frame_interval(struct v4l2_subdev *sd, · 2 unmodified lines | ||
| 893 | 888 | struct v4l2_subdev_state *sd_state, |
| 894 | 889 | struct v4l2_subdev_frame_interval *interval) |
| 895 | 890 | { |
| 896 | − struct max9286_priv *priv = sd_to_max9286(sd); | |
| 897 | − | |
| 898 | − /* | |
| 899 | − * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2 | |
| 900 | − * subdev active state API. | |
| 901 | − */ | |
| 902 | − if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE) | |
| 903 | − return -EINVAL; | |
| 904 | − | |
| 905 | 891 | if (interval->pad != MAX9286_SRC_PAD) |
| 906 | 892 | return -EINVAL; |
| 907 | 893 | |
| 908 | − priv->interval = interval->interval; | |
| 894 | + *v4l2_subdev_state_get_interval(sd_state, | |
| 895 | + interval->pad) = interval->interval; | |
| 909 | 896 | |
| 910 | 897 | return 0; |
| 911 | 898 | } |
| @@ -914,39 +901,28 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd, · 2 unmodified lines | ||
| 914 | 901 | struct v4l2_subdev_state *sd_state, |
| 915 | 902 | struct v4l2_subdev_mbus_code_enum *code) |
| 916 | 903 | { |
| 917 | − if (code->pad || code->index > 0) | |
| 904 | + if (code->pad || code->index >= ARRAY_SIZE(max9286_formats)) | |
| 918 | 905 | return -EINVAL; |
| 919 | 906 | |
| 920 | − code->code = MEDIA_BUS_FMT_UYVY8_1X16; | |
| 907 | + code->code = max9286_formats[code->index].code; | |
| 921 | 908 | |
| 922 | 909 | return 0; |
| 923 | 910 | } |
| 924 | 911 | |
| 925 | −static struct v4l2_mbus_framefmt * | |
| 926 | −max9286_get_pad_format(struct max9286_priv *priv, | |
| 927 | − struct v4l2_subdev_state *sd_state, | |
| 928 | − unsigned int pad, u32 which) | |
| 929 | −{ | |
| 930 | − switch (which) { | |
| 931 | − case V4L2_SUBDEV_FORMAT_TRY: | |
| 932 | − return v4l2_subdev_state_get_format(sd_state, pad); | |
| 933 | − case V4L2_SUBDEV_FORMAT_ACTIVE: | |
| 934 | − return &priv->fmt[pad]; | |
| 935 | − default: | |
| 936 | − return NULL; | |
| 937 | − } | |
| 938 | −} | |
| 939 | − | |
| 940 | 912 | static int max9286_set_fmt(struct v4l2_subdev *sd, |
| 941 | − struct v4l2_subdev_state *sd_state, | |
| 913 | + struct v4l2_subdev_state *state, | |
| 942 | 914 | struct v4l2_subdev_format *format) |
| 943 | 915 | { |
| 944 | 916 | struct max9286_priv *priv = sd_to_max9286(sd); |
| 945 | − struct v4l2_mbus_framefmt *cfg_fmt; | |
| 917 | + struct max9286_source *source; | |
| 946 | 918 | unsigned int i; |
| 947 | 919 | |
| 920 | + /* | |
| 921 | + * Disable setting format on the source pad: format is propagated | |
| 922 | + * from the sinks. | |
| 923 | + */ | |
| 948 | 924 | if (format->pad == MAX9286_SRC_PAD) |
| 949 | − return -EINVAL; | |
| 925 | + return v4l2_subdev_get_fmt(sd, state, format); | |
| 950 | 926 | |
| 951 | 927 | /* Validate the format. */ |
| 952 | 928 | for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { |
| @@ -957,42 +933,17 @@ static int max9286_set_fmt(struct v4l2_subdev *sd, · 4 unmodified lines | ||
| 957 | 933 | if (i == ARRAY_SIZE(max9286_formats)) |
| 958 | 934 | format->format.code = max9286_formats[0].code; |
| 959 | 935 | |
| 960 | − cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad, | |
| 961 | − format->which); | |
| 962 | − if (!cfg_fmt) | |
| 963 | − return -EINVAL; | |
| 964 | − | |
| 965 | − mutex_lock(&priv->mutex); | |
| 966 | − *cfg_fmt = format->format; | |
| 967 | − mutex_unlock(&priv->mutex); | |
| 968 | − | |
| 969 | − return 0; | |
| 970 | −} | |
| 971 | − | |
| 972 | −static int max9286_get_fmt(struct v4l2_subdev *sd, | |
| 973 | − struct v4l2_subdev_state *sd_state, | |
| 974 | − struct v4l2_subdev_format *format) | |
| 975 | −{ | |
| 976 | − struct max9286_priv *priv = sd_to_max9286(sd); | |
| 977 | − struct v4l2_mbus_framefmt *cfg_fmt; | |
| 978 | − unsigned int pad = format->pad; | |
| 979 | − | |
| 980 | 936 | /* |
| 981 | − * Multiplexed Stream Support: Support link validation by returning the | |
| 982 | − * format of the first bound link. All links must have the same format, | |
| 983 | − * as we do not support mixing and matching of cameras connected to the | |
| 984 | − * max9286. | |
| 937 | + * Apply the same format on all the other pad as all links must have the | |
| 938 | + * same format. | |
| 985 | 939 | */ |
| 986 | − if (pad == MAX9286_SRC_PAD) | |
| 987 | − pad = __ffs(priv->bound_sources); | |
| 940 | + for_each_source(priv, source) { | |
| 941 | + unsigned int index = to_index(priv, source); | |
| 988 | 942 | |
| 989 | − cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which); | |
| 990 | − if (!cfg_fmt) | |
| 991 | − return -EINVAL; | |
| 943 | + *v4l2_subdev_state_get_format(state, index) = format->format; | |
| 944 | + } | |
| 992 | 945 | |
| 993 | − mutex_lock(&priv->mutex); | |
| 994 | − format->format = *cfg_fmt; | |
| 995 | − mutex_unlock(&priv->mutex); | |
| 946 | + *v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD) = format->format; | |
| 996 | 947 | |
| 997 | 948 | return 0; |
| 998 | 949 | } |
| @@ -1003,7 +954,7 @@ static const struct v4l2_subdev_video_ops max9286_video_ops = { · 4 unmodified lines | ||
| 1003 | 954 | |
| 1004 | 955 | static const struct v4l2_subdev_pad_ops max9286_pad_ops = { |
| 1005 | 956 | .enum_mbus_code = max9286_enum_mbus_code, |
| 1006 | − .get_fmt = max9286_get_fmt, | |
| 957 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 1007 | 958 | .set_fmt = max9286_set_fmt, |
| 1008 | 959 | .get_frame_interval = max9286_get_frame_interval, |
| 1009 | 960 | .set_frame_interval = max9286_set_frame_interval, |
| @@ -1025,26 +976,29 @@ static const struct v4l2_mbus_framefmt max9286_default_format = { · 15 unmodified lines | ||
| 1025 | 976 | .xfer_func = V4L2_XFER_FUNC_DEFAULT, |
| 1026 | 977 | }; |
| 1027 | 978 | |
| 1028 | −static void max9286_init_format(struct v4l2_mbus_framefmt *fmt) | |
| 979 | +static int max9286_init_state(struct v4l2_subdev *sd, | |
| 980 | + struct v4l2_subdev_state *state) | |
| 1029 | 981 | { |
| 1030 | − *fmt = max9286_default_format; | |
| 1031 | −} | |
| 982 | + struct v4l2_fract *interval; | |
| 1032 | 983 | |
| 1033 | −static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | |
| 1034 | −{ | |
| 1035 | − struct v4l2_mbus_framefmt *format; | |
| 1036 | − unsigned int i; | |
| 984 | + for (unsigned int i = 0; i < MAX9286_N_PADS; i++) | |
| 985 | + *v4l2_subdev_state_get_format(state, i) = max9286_default_format; | |
| 1037 | 986 | |
| 1038 | − for (i = 0; i < MAX9286_N_SINKS; i++) { | |
| 1039 | − format = v4l2_subdev_state_get_format(fh->state, i); | |
| 1040 | − max9286_init_format(format); | |
| 1041 | − } | |
| 987 | + /* | |
| 988 | + * Special case: a null interval enables automatic FRAMESYNC mode. | |
| 989 | + * | |
| 990 | + * FRAMESYNC is taken from the slowest link. See register 0x01 | |
| 991 | + * configuration. | |
| 992 | + */ | |
| 993 | + interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD); | |
| 994 | + interval->numerator = 0; | |
| 995 | + interval->denominator = 0; | |
| 1042 | 996 | |
| 1043 | 997 | return 0; |
| 1044 | 998 | } |
| 1045 | 999 | |
| 1046 | 1000 | static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = { |
| 1047 | − .open = max9286_open, | |
| 1001 | + .init_state = max9286_init_state, | |
| 1048 | 1002 | }; |
| 1049 | 1003 | |
| 1050 | 1004 | static const struct media_entity_operations max9286_media_ops = { |
| @@ -1079,10 +1033,6 @@ static int max9286_v4l2_register(struct max9286_priv *priv) · 28 unmodified lines | ||
| 1079 | 1033 | } |
| 1080 | 1034 | |
| 1081 | 1035 | /* Configure V4L2 for the MAX9286 itself */ |
| 1082 | − | |
| 1083 | − for (i = 0; i < MAX9286_N_SINKS; i++) | |
| 1084 | − max9286_init_format(&priv->fmt[i]); | |
| 1085 | − | |
| 1086 | 1036 | v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops); |
| 1087 | 1037 | priv->sd.internal_ops = &max9286_subdev_internal_ops; |
| 1088 | 1038 | priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; |
| @@ -1109,14 +1059,21 @@ static int max9286_v4l2_register(struct max9286_priv *priv) · 20 unmodified lines | ||
| 1109 | 1059 | if (ret) |
| 1110 | 1060 | goto err_async; |
| 1111 | 1061 | |
| 1062 | + priv->sd.state_lock = priv->ctrls.lock; | |
| 1063 | + ret = v4l2_subdev_init_finalize(&priv->sd); | |
| 1064 | + if (ret) | |
| 1065 | + goto err_async; | |
| 1066 | + | |
| 1112 | 1067 | ret = v4l2_async_register_subdev(&priv->sd); |
| 1113 | 1068 | if (ret < 0) { |
| 1114 | 1069 | dev_err(dev, "Unable to register subdevice\n"); |
| 1115 | − goto err_async; | |
| 1070 | + goto err_subdev; | |
| 1116 | 1071 | } |
| 1117 | 1072 | |
| 1118 | 1073 | return 0; |
| 1119 | 1074 | |
| 1075 | +err_subdev: | |
| 1076 | + v4l2_subdev_cleanup(&priv->sd); | |
| 1120 | 1077 | err_async: |
| 1121 | 1078 | v4l2_ctrl_handler_free(&priv->ctrls); |
| 1122 | 1079 | max9286_v4l2_notifier_unregister(priv); |
| @@ -1126,6 +1083,7 @@ err_async: · 3 unmodified lines | ||
| 1126 | 1083 | |
| 1127 | 1084 | static void max9286_v4l2_unregister(struct max9286_priv *priv) |
| 1128 | 1085 | { |
| 1086 | + v4l2_subdev_cleanup(&priv->sd); | |
| 1129 | 1087 | v4l2_ctrl_handler_free(&priv->ctrls); |
| 1130 | 1088 | v4l2_async_unregister_subdev(&priv->sd); |
| 1131 | 1089 | max9286_v4l2_notifier_unregister(priv); |
| @@ -1182,7 +1140,6 @@ static int max9286_setup(struct max9286_priv *priv) · 50 unmodified lines | ||
| 1182 | 1140 | max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); |
| 1183 | 1141 | |
| 1184 | 1142 | max9286_set_video_format(priv, &max9286_default_format); |
| 1185 | − max9286_set_fsync_period(priv); | |
| 1186 | 1143 | |
| 1187 | 1144 | cfg = max9286_read(priv, 0x1c); |
| 1188 | 1145 | if (cfg < 0) |
| @@ -1629,8 +1586,6 @@ static int max9286_probe(struct i2c_client *client) · 440 unmodified lines | ||
| 1629 | 1586 | if (!priv) |
| 1630 | 1587 | return -ENOMEM; |
| 1631 | 1588 | |
| 1632 | − mutex_init(&priv->mutex); | |
| 1633 | − | |
| 1634 | 1589 | priv->client = client; |
| 1635 | 1590 | |
| 1636 | 1591 | /* GPIO values default to high */ |
| @@ -0,0 +1,1024 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Maxim GMSL2 Deserializer Driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2024 Collabora Ltd. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/bitfield.h> | |
| 9 | +#include <linux/bitops.h> | |
| 10 | +#include <linux/fwnode.h> | |
| 11 | +#include <linux/gpio/consumer.h> | |
| 12 | +#include <linux/i2c.h> | |
| 13 | +#include <linux/i2c-mux.h> | |
| 14 | +#include <linux/module.h> | |
| 15 | +#include <linux/regmap.h> | |
| 16 | +#include <linux/regulator/consumer.h> | |
| 17 | + | |
| 18 | +#include <media/v4l2-cci.h> | |
| 19 | +#include <media/v4l2-ctrls.h> | |
| 20 | +#include <media/v4l2-fwnode.h> | |
| 21 | +#include <media/v4l2-subdev.h> | |
| 22 | + | |
| 23 | +#define MAX96714_DEVICE_ID 0xc9 | |
| 24 | +#define MAX96714F_DEVICE_ID 0xca | |
| 25 | +#define MAX96714_NPORTS 2 | |
| 26 | +#define MAX96714_PAD_SINK 0 | |
| 27 | +#define MAX96714_PAD_SOURCE 1 | |
| 28 | + | |
| 29 | +/* DEV */ | |
| 30 | +#define MAX96714_REG13 CCI_REG8(0x0d) | |
| 31 | +#define MAX96714_DEV_REV CCI_REG8(0x0e) | |
| 32 | +#define MAX96714_DEV_REV_MASK GENMASK(3, 0) | |
| 33 | +#define MAX96714_LINK_LOCK CCI_REG8(0x13) | |
| 34 | +#define MAX96714_LINK_LOCK_BIT BIT(3) | |
| 35 | +#define MAX96714_IO_CHK0 CCI_REG8(0x38) | |
| 36 | +#define MAX96714_PATTERN_CLK_FREQ GENMASK(1, 0) | |
| 37 | +/* VID_RX */ | |
| 38 | +#define MAX96714_VIDEO_RX8 CCI_REG8(0x11a) | |
| 39 | +#define MAX96714_VID_LOCK BIT(6) | |
| 40 | + | |
| 41 | +/* VRX_PATGEN_0 */ | |
| 42 | +#define MAX96714_PATGEN_0 CCI_REG8(0x240) | |
| 43 | +#define MAX96714_PATGEN_1 CCI_REG8(0x241) | |
| 44 | +#define MAX96714_PATGEN_MODE GENMASK(5, 4) | |
| 45 | +#define MAX96714_PATGEN_VS_DLY CCI_REG24(0x242) | |
| 46 | +#define MAX96714_PATGEN_VS_HIGH CCI_REG24(0x245) | |
| 47 | +#define MAX96714_PATGEN_VS_LOW CCI_REG24(0x248) | |
| 48 | +#define MAX96714_PATGEN_V2H CCI_REG24(0x24b) | |
| 49 | +#define MAX96714_PATGEN_HS_HIGH CCI_REG16(0x24e) | |
| 50 | +#define MAX96714_PATGEN_HS_LOW CCI_REG16(0x250) | |
| 51 | +#define MAX96714_PATGEN_HS_CNT CCI_REG16(0x252) | |
| 52 | +#define MAX96714_PATGEN_V2D CCI_REG24(0x254) | |
| 53 | +#define MAX96714_PATGEN_DE_HIGH CCI_REG16(0x257) | |
| 54 | +#define MAX96714_PATGEN_DE_LOW CCI_REG16(0x259) | |
| 55 | +#define MAX96714_PATGEN_DE_CNT CCI_REG16(0x25B) | |
| 56 | +#define MAX96714_PATGEN_GRAD_INC CCI_REG8(0x25d) | |
| 57 | +#define MAX96714_PATGEN_CHKB_COLOR_A CCI_REG24(0x25E) | |
| 58 | +#define MAX96714_PATGEN_CHKB_COLOR_B CCI_REG24(0x261) | |
| 59 | +#define MAX96714_PATGEN_CHKB_RPT_CNT_A CCI_REG8(0x264) | |
| 60 | +#define MAX96714_PATGEN_CHKB_RPT_CNT_B CCI_REG8(0x265) | |
| 61 | +#define MAX96714_PATGEN_CHKB_ALT CCI_REG8(0x266) | |
| 62 | +/* BACKTOP */ | |
| 63 | +#define MAX96714_BACKTOP25 CCI_REG8(0x320) | |
| 64 | +#define CSI_DPLL_FREQ_MASK GENMASK(4, 0) | |
| 65 | + | |
| 66 | +/* MIPI_PHY */ | |
| 67 | +#define MAX96714_MIPI_PHY0 CCI_REG8(0x330) | |
| 68 | +#define MAX96714_FORCE_CSI_OUT BIT(7) | |
| 69 | +#define MAX96714_MIPI_STDBY_N CCI_REG8(0x332) | |
| 70 | +#define MAX96714_MIPI_STDBY_MASK GENMASK(5, 4) | |
| 71 | +#define MAX96714_MIPI_LANE_MAP CCI_REG8(0x333) | |
| 72 | +#define MAX96714_MIPI_POLARITY CCI_REG8(0x335) | |
| 73 | +#define MAX96714_MIPI_POLARITY_MASK GENMASK(5, 0) | |
| 74 | + | |
| 75 | +/* MIPI_TX */ | |
| 76 | +#define MAX96714_MIPI_LANE_CNT CCI_REG8(0x44a) | |
| 77 | +#define MAX96714_CSI2_LANE_CNT_MASK GENMASK(7, 6) | |
| 78 | +#define MAX96714_MIPI_TX52 CCI_REG8(0x474) | |
| 79 | +#define MAX96714_TUN_EN BIT(0) | |
| 80 | + | |
| 81 | +#define MHZ(v) ((u32)((v) * 1000000U)) | |
| 82 | + | |
| 83 | +enum max96714_vpg_mode { | |
| 84 | + MAX96714_VPG_DISABLED = 0, | |
| 85 | + MAX96714_VPG_CHECKERBOARD = 1, | |
| 86 | + MAX96714_VPG_GRADIENT = 2, | |
| 87 | +}; | |
| 88 | + | |
| 89 | +struct max96714_rxport { | |
| 90 | + struct { | |
| 91 | + struct v4l2_subdev *sd; | |
| 92 | + u16 pad; | |
| 93 | + struct fwnode_handle *ep_fwnode; | |
| 94 | + } source; | |
| 95 | + struct regulator *poc; | |
| 96 | +}; | |
| 97 | + | |
| 98 | +struct max96714_txport { | |
| 99 | + struct v4l2_fwnode_endpoint vep; | |
| 100 | +}; | |
| 101 | + | |
| 102 | +struct max96714_priv { | |
| 103 | + struct i2c_client *client; | |
| 104 | + struct regmap *regmap; | |
| 105 | + struct gpio_desc *pd_gpio; | |
| 106 | + struct max96714_rxport rxport; | |
| 107 | + struct i2c_mux_core *mux; | |
| 108 | + u64 enabled_source_streams; | |
| 109 | + struct v4l2_subdev sd; | |
| 110 | + struct media_pad pads[MAX96714_NPORTS]; | |
| 111 | + struct v4l2_mbus_config_mipi_csi2 mipi_csi2; | |
| 112 | + struct v4l2_ctrl_handler ctrl_handler; | |
| 113 | + struct v4l2_async_notifier notifier; | |
| 114 | + s64 tx_link_freq; | |
| 115 | + enum max96714_vpg_mode pattern; | |
| 116 | +}; | |
| 117 | + | |
| 118 | +static inline struct max96714_priv *sd_to_max96714(struct v4l2_subdev *sd) | |
| 119 | +{ | |
| 120 | + return container_of(sd, struct max96714_priv, sd); | |
| 121 | +} | |
| 122 | + | |
| 123 | +static int max96714_enable_tx_port(struct max96714_priv *priv) | |
| 124 | +{ | |
| 125 | + return cci_update_bits(priv->regmap, MAX96714_MIPI_STDBY_N, | |
| 126 | + MAX96714_MIPI_STDBY_MASK, | |
| 127 | + MAX96714_MIPI_STDBY_MASK, NULL); | |
| 128 | +} | |
| 129 | + | |
| 130 | +static int max96714_disable_tx_port(struct max96714_priv *priv) | |
| 131 | +{ | |
| 132 | + return cci_update_bits(priv->regmap, MAX96714_MIPI_STDBY_N, | |
| 133 | + MAX96714_MIPI_STDBY_MASK, 0, NULL); | |
| 134 | +} | |
| 135 | + | |
| 136 | +static bool max96714_tx_port_enabled(struct max96714_priv *priv) | |
| 137 | +{ | |
| 138 | + u64 val; | |
| 139 | + | |
| 140 | + cci_read(priv->regmap, MAX96714_MIPI_STDBY_N, &val, NULL); | |
| 141 | + | |
| 142 | + return val & MAX96714_MIPI_STDBY_MASK; | |
| 143 | +} | |
| 144 | + | |
| 145 | +static int max96714_apply_patgen_timing(struct max96714_priv *priv, | |
| 146 | + struct v4l2_subdev_state *state) | |
| 147 | +{ | |
| 148 | + struct v4l2_mbus_framefmt *fmt = | |
| 149 | + v4l2_subdev_state_get_format(state, MAX96714_PAD_SOURCE); | |
| 150 | + const u32 h_active = fmt->width; | |
| 151 | + const u32 h_fp = 88; | |
| 152 | + const u32 h_sw = 44; | |
| 153 | + const u32 h_bp = 148; | |
| 154 | + u32 h_tot; | |
| 155 | + const u32 v_active = fmt->height; | |
| 156 | + const u32 v_fp = 4; | |
| 157 | + const u32 v_sw = 5; | |
| 158 | + const u32 v_bp = 36; | |
| 159 | + u32 v_tot; | |
| 160 | + int ret = 0; | |
| 161 | + | |
| 162 | + h_tot = h_active + h_fp + h_sw + h_bp; | |
| 163 | + v_tot = v_active + v_fp + v_sw + v_bp; | |
| 164 | + | |
| 165 | + /* 75 Mhz pixel clock */ | |
| 166 | + cci_update_bits(priv->regmap, MAX96714_IO_CHK0, | |
| 167 | + MAX96714_PATTERN_CLK_FREQ, 1, &ret); | |
| 168 | + | |
| 169 | + dev_info(&priv->client->dev, "height: %d width: %d\n", fmt->height, | |
| 170 | + fmt->width); | |
| 171 | + | |
| 172 | + cci_write(priv->regmap, MAX96714_PATGEN_VS_DLY, 0, &ret); | |
| 173 | + cci_write(priv->regmap, MAX96714_PATGEN_VS_HIGH, v_sw * h_tot, &ret); | |
| 174 | + cci_write(priv->regmap, MAX96714_PATGEN_VS_LOW, | |
| 175 | + (v_active + v_fp + v_bp) * h_tot, &ret); | |
| 176 | + cci_write(priv->regmap, MAX96714_PATGEN_HS_HIGH, h_sw, &ret); | |
| 177 | + cci_write(priv->regmap, MAX96714_PATGEN_HS_LOW, h_active + h_fp + h_bp, | |
| 178 | + &ret); | |
| 179 | + cci_write(priv->regmap, MAX96714_PATGEN_V2D, | |
| 180 | + h_tot * (v_sw + v_bp) + (h_sw + h_bp), &ret); | |
| 181 | + cci_write(priv->regmap, MAX96714_PATGEN_HS_CNT, v_tot, &ret); | |
| 182 | + cci_write(priv->regmap, MAX96714_PATGEN_DE_HIGH, h_active, &ret); | |
| 183 | + cci_write(priv->regmap, MAX96714_PATGEN_DE_LOW, h_fp + h_sw + h_bp, | |
| 184 | + &ret); | |
| 185 | + cci_write(priv->regmap, MAX96714_PATGEN_DE_CNT, v_active, &ret); | |
| 186 | + /* B G R */ | |
| 187 | + cci_write(priv->regmap, MAX96714_PATGEN_CHKB_COLOR_A, 0xfecc00, &ret); | |
| 188 | + /* B G R */ | |
| 189 | + cci_write(priv->regmap, MAX96714_PATGEN_CHKB_COLOR_B, 0x006aa7, &ret); | |
| 190 | + cci_write(priv->regmap, MAX96714_PATGEN_CHKB_RPT_CNT_A, 0x3c, &ret); | |
| 191 | + cci_write(priv->regmap, MAX96714_PATGEN_CHKB_RPT_CNT_B, 0x3c, &ret); | |
| 192 | + cci_write(priv->regmap, MAX96714_PATGEN_CHKB_ALT, 0x3c, &ret); | |
| 193 | + cci_write(priv->regmap, MAX96714_PATGEN_GRAD_INC, 0x10, &ret); | |
| 194 | + | |
| 195 | + return ret; | |
| 196 | +} | |
| 197 | + | |
| 198 | +static int max96714_apply_patgen(struct max96714_priv *priv, | |
| 199 | + struct v4l2_subdev_state *state) | |
| 200 | +{ | |
| 201 | + unsigned int val; | |
| 202 | + int ret = 0; | |
| 203 | + | |
| 204 | + if (priv->pattern) | |
| 205 | + ret = max96714_apply_patgen_timing(priv, state); | |
| 206 | + | |
| 207 | + cci_write(priv->regmap, MAX96714_PATGEN_0, priv->pattern ? 0xfb : 0, | |
| 208 | + &ret); | |
| 209 | + | |
| 210 | + val = FIELD_PREP(MAX96714_PATGEN_MODE, priv->pattern); | |
| 211 | + cci_update_bits(priv->regmap, MAX96714_PATGEN_1, MAX96714_PATGEN_MODE, | |
| 212 | + val, &ret); | |
| 213 | + return ret; | |
| 214 | +} | |
| 215 | + | |
| 216 | +static int max96714_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 217 | +{ | |
| 218 | + struct max96714_priv *priv = | |
| 219 | + container_of(ctrl->handler, struct max96714_priv, ctrl_handler); | |
| 220 | + int ret; | |
| 221 | + | |
| 222 | + switch (ctrl->id) { | |
| 223 | + case V4L2_CID_TEST_PATTERN: | |
| 224 | + if (priv->enabled_source_streams) | |
| 225 | + return -EBUSY; | |
| 226 | + priv->pattern = ctrl->val; | |
| 227 | + break; | |
| 228 | + default: | |
| 229 | + return -EINVAL; | |
| 230 | + } | |
| 231 | + | |
| 232 | + ret = cci_update_bits(priv->regmap, MAX96714_MIPI_PHY0, | |
| 233 | + MAX96714_FORCE_CSI_OUT, | |
| 234 | + priv->pattern ? MAX96714_FORCE_CSI_OUT : 0, NULL); | |
| 235 | + | |
| 236 | + /* Pattern generator doesn't work with tunnel mode */ | |
| 237 | + return cci_update_bits(priv->regmap, MAX96714_MIPI_TX52, | |
| 238 | + MAX96714_TUN_EN, | |
| 239 | + priv->pattern ? 0 : MAX96714_TUN_EN, &ret); | |
| 240 | +} | |
| 241 | + | |
| 242 | +static const char * const max96714_test_pattern[] = { | |
| 243 | + "Disabled", | |
| 244 | + "Checkerboard", | |
| 245 | + "Gradient" | |
| 246 | +}; | |
| 247 | + | |
| 248 | +static const struct v4l2_ctrl_ops max96714_ctrl_ops = { | |
| 249 | + .s_ctrl = max96714_s_ctrl, | |
| 250 | +}; | |
| 251 | + | |
| 252 | +static int max96714_enable_streams(struct v4l2_subdev *sd, | |
| 253 | + struct v4l2_subdev_state *state, | |
| 254 | + u32 source_pad, u64 streams_mask) | |
| 255 | +{ | |
| 256 | + struct max96714_priv *priv = sd_to_max96714(sd); | |
| 257 | + u64 sink_streams; | |
| 258 | + int ret; | |
| 259 | + | |
| 260 | + if (!priv->enabled_source_streams) | |
| 261 | + max96714_enable_tx_port(priv); | |
| 262 | + | |
| 263 | + ret = max96714_apply_patgen(priv, state); | |
| 264 | + if (ret) | |
| 265 | + goto err; | |
| 266 | + | |
| 267 | + if (!priv->pattern) { | |
| 268 | + if (!priv->rxport.source.sd) { | |
| 269 | + ret = -ENODEV; | |
| 270 | + goto err; | |
| 271 | + } | |
| 272 | + | |
| 273 | + sink_streams = | |
| 274 | + v4l2_subdev_state_xlate_streams(state, | |
| 275 | + MAX96714_PAD_SOURCE, | |
| 276 | + MAX96714_PAD_SINK, | |
| 277 | + &streams_mask); | |
| 278 | + | |
| 279 | + ret = v4l2_subdev_enable_streams(priv->rxport.source.sd, | |
| 280 | + priv->rxport.source.pad, | |
| 281 | + sink_streams); | |
| 282 | + if (ret) | |
| 283 | + goto err; | |
| 284 | + } | |
| 285 | + | |
| 286 | + priv->enabled_source_streams |= streams_mask; | |
| 287 | + | |
| 288 | + return 0; | |
| 289 | + | |
| 290 | +err: | |
| 291 | + if (!priv->enabled_source_streams) | |
| 292 | + max96714_disable_tx_port(priv); | |
| 293 | + | |
| 294 | + return ret; | |
| 295 | +} | |
| 296 | + | |
| 297 | +static int max96714_disable_streams(struct v4l2_subdev *sd, | |
| 298 | + struct v4l2_subdev_state *state, | |
| 299 | + u32 source_pad, u64 streams_mask) | |
| 300 | +{ | |
| 301 | + struct max96714_priv *priv = sd_to_max96714(sd); | |
| 302 | + u64 sink_streams; | |
| 303 | + | |
| 304 | + if (!priv->pattern) { | |
| 305 | + int ret; | |
| 306 | + | |
| 307 | + sink_streams = | |
| 308 | + v4l2_subdev_state_xlate_streams(state, | |
| 309 | + MAX96714_PAD_SOURCE, | |
| 310 | + MAX96714_PAD_SINK, | |
| 311 | + &streams_mask); | |
| 312 | + | |
| 313 | + ret = v4l2_subdev_disable_streams(priv->rxport.source.sd, | |
| 314 | + priv->rxport.source.pad, | |
| 315 | + sink_streams); | |
| 316 | + if (ret) | |
| 317 | + return ret; | |
| 318 | + } | |
| 319 | + | |
| 320 | + priv->enabled_source_streams &= ~streams_mask; | |
| 321 | + | |
| 322 | + if (!priv->enabled_source_streams) | |
| 323 | + max96714_disable_tx_port(priv); | |
| 324 | + | |
| 325 | + return 0; | |
| 326 | +} | |
| 327 | + | |
| 328 | +static int max96714_set_fmt(struct v4l2_subdev *sd, | |
| 329 | + struct v4l2_subdev_state *state, | |
| 330 | + struct v4l2_subdev_format *format) | |
| 331 | +{ | |
| 332 | + struct max96714_priv *priv = sd_to_max96714(sd); | |
| 333 | + struct v4l2_mbus_framefmt *fmt; | |
| 334 | + | |
| 335 | + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && | |
| 336 | + priv->enabled_source_streams) | |
| 337 | + return -EBUSY; | |
| 338 | + | |
| 339 | + /* No transcoding, source and sink formats must match. */ | |
| 340 | + if (format->pad == MAX96714_PAD_SOURCE) | |
| 341 | + return v4l2_subdev_get_fmt(sd, state, format); | |
| 342 | + | |
| 343 | + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); | |
| 344 | + if (!fmt) | |
| 345 | + return -EINVAL; | |
| 346 | + | |
| 347 | + *fmt = format->format; | |
| 348 | + | |
| 349 | + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, | |
| 350 | + format->stream); | |
| 351 | + if (!fmt) | |
| 352 | + return -EINVAL; | |
| 353 | + | |
| 354 | + *fmt = format->format; | |
| 355 | + | |
| 356 | + return 0; | |
| 357 | +} | |
| 358 | + | |
| 359 | +static int _max96714_set_routing(struct v4l2_subdev *sd, | |
| 360 | + struct v4l2_subdev_state *state, | |
| 361 | + enum v4l2_subdev_format_whence which, | |
| 362 | + struct v4l2_subdev_krouting *routing) | |
| 363 | +{ | |
| 364 | + static const struct v4l2_mbus_framefmt format = { | |
| 365 | + .width = 1280, | |
| 366 | + .height = 1080, | |
| 367 | + .code = MEDIA_BUS_FMT_Y8_1X8, | |
| 368 | + .field = V4L2_FIELD_NONE, | |
| 369 | + }; | |
| 370 | + int ret; | |
| 371 | + | |
| 372 | + /* | |
| 373 | + * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until | |
| 374 | + * frame desc is made dynamically allocated. | |
| 375 | + */ | |
| 376 | + if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX) | |
| 377 | + return -EINVAL; | |
| 378 | + | |
| 379 | + ret = v4l2_subdev_routing_validate(sd, routing, | |
| 380 | + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); | |
| 381 | + if (ret) | |
| 382 | + return ret; | |
| 383 | + | |
| 384 | + return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format); | |
| 385 | +} | |
| 386 | + | |
| 387 | +static int max96714_set_routing(struct v4l2_subdev *sd, | |
| 388 | + struct v4l2_subdev_state *state, | |
| 389 | + enum v4l2_subdev_format_whence which, | |
| 390 | + struct v4l2_subdev_krouting *routing) | |
| 391 | +{ | |
| 392 | + struct max96714_priv *priv = sd_to_max96714(sd); | |
| 393 | + | |
| 394 | + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams) | |
| 395 | + return -EBUSY; | |
| 396 | + | |
| 397 | + return _max96714_set_routing(sd, state, which, routing); | |
| 398 | +} | |
| 399 | + | |
| 400 | +static int max96714_init_state(struct v4l2_subdev *sd, | |
| 401 | + struct v4l2_subdev_state *state) | |
| 402 | +{ | |
| 403 | + struct v4l2_subdev_route routes[] = { | |
| 404 | + { | |
| 405 | + .sink_pad = MAX96714_PAD_SINK, | |
| 406 | + .sink_stream = 0, | |
| 407 | + .source_pad = MAX96714_PAD_SOURCE, | |
| 408 | + .source_stream = 0, | |
| 409 | + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, | |
| 410 | + } | |
| 411 | + }; | |
| 412 | + struct v4l2_subdev_krouting routing = { | |
| 413 | + .num_routes = ARRAY_SIZE(routes), | |
| 414 | + .routes = routes, | |
| 415 | + }; | |
| 416 | + | |
| 417 | + return _max96714_set_routing(sd, state, V4L2_SUBDEV_FORMAT_ACTIVE, | |
| 418 | + &routing); | |
| 419 | +} | |
| 420 | + | |
| 421 | +static const struct v4l2_subdev_pad_ops max96714_pad_ops = { | |
| 422 | + .enable_streams = max96714_enable_streams, | |
| 423 | + .disable_streams = max96714_disable_streams, | |
| 424 | + | |
| 425 | + .set_routing = max96714_set_routing, | |
| 426 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 427 | + .set_fmt = max96714_set_fmt, | |
| 428 | +}; | |
| 429 | + | |
| 430 | +static bool max96714_link_locked(struct max96714_priv *priv) | |
| 431 | +{ | |
| 432 | + u64 val = 0; | |
| 433 | + | |
| 434 | + cci_read(priv->regmap, MAX96714_LINK_LOCK, &val, NULL); | |
| 435 | + | |
| 436 | + return val & MAX96714_LINK_LOCK_BIT; | |
| 437 | +} | |
| 438 | + | |
| 439 | +static void max96714_link_status(struct max96714_priv *priv) | |
| 440 | +{ | |
| 441 | + struct device *dev = &priv->client->dev; | |
| 442 | + | |
| 443 | + dev_info(dev, "Link locked:%d\n", max96714_link_locked(priv)); | |
| 444 | +} | |
| 445 | + | |
| 446 | +static bool max96714_pipe_locked(struct max96714_priv *priv) | |
| 447 | +{ | |
| 448 | + u64 val; | |
| 449 | + | |
| 450 | + cci_read(priv->regmap, MAX96714_VIDEO_RX8, &val, NULL); | |
| 451 | + | |
| 452 | + return val & MAX96714_VID_LOCK; | |
| 453 | +} | |
| 454 | + | |
| 455 | +static void max96714_pipe_status(struct max96714_priv *priv) | |
| 456 | +{ | |
| 457 | + struct device *dev = &priv->client->dev; | |
| 458 | + | |
| 459 | + dev_info(dev, "Pipe vidlock:%d\n", max96714_pipe_locked(priv)); | |
| 460 | +} | |
| 461 | + | |
| 462 | +static void max96714_csi_status(struct max96714_priv *priv) | |
| 463 | +{ | |
| 464 | + struct device *dev = &priv->client->dev; | |
| 465 | + u64 freq = 0; | |
| 466 | + | |
| 467 | + cci_read(priv->regmap, MAX96714_BACKTOP25, &freq, NULL); | |
| 468 | + freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq); | |
| 469 | + | |
| 470 | + dev_info(dev, "CSI controller DPLL freq:%u00MHz CSIPHY enabled:%d\n", | |
| 471 | + (u8)freq, max96714_tx_port_enabled(priv)); | |
| 472 | +} | |
| 473 | + | |
| 474 | +static int max96714_log_status(struct v4l2_subdev *sd) | |
| 475 | +{ | |
| 476 | + struct max96714_priv *priv = sd_to_max96714(sd); | |
| 477 | + struct device *dev = &priv->client->dev; | |
| 478 | + | |
| 479 | + dev_info(dev, "Deserializer: max96714\n"); | |
| 480 | + | |
| 481 | + max96714_link_status(priv); | |
| 482 | + max96714_pipe_status(priv); | |
| 483 | + max96714_csi_status(priv); | |
| 484 | + | |
| 485 | + return 0; | |
| 486 | +} | |
| 487 | + | |
| 488 | +static const struct v4l2_subdev_core_ops max96714_subdev_core_ops = { | |
| 489 | + .log_status = max96714_log_status, | |
| 490 | +}; | |
| 491 | + | |
| 492 | +static const struct v4l2_subdev_video_ops max96714_video_ops = { | |
| 493 | + .s_stream = v4l2_subdev_s_stream_helper, | |
| 494 | +}; | |
| 495 | + | |
| 496 | +static const struct v4l2_subdev_internal_ops max96714_internal_ops = { | |
| 497 | + .init_state = max96714_init_state, | |
| 498 | +}; | |
| 499 | + | |
| 500 | +static const struct v4l2_subdev_ops max96714_subdev_ops = { | |
| 501 | + .video = &max96714_video_ops, | |
| 502 | + .core = &max96714_subdev_core_ops, | |
| 503 | + .pad = &max96714_pad_ops, | |
| 504 | +}; | |
| 505 | + | |
| 506 | +static const struct media_entity_operations max96714_entity_ops = { | |
| 507 | + .link_validate = v4l2_subdev_link_validate, | |
| 508 | +}; | |
| 509 | + | |
| 510 | +static int max96714_notify_bound(struct v4l2_async_notifier *notifier, | |
| 511 | + struct v4l2_subdev *subdev, | |
| 512 | + struct v4l2_async_connection *asd) | |
| 513 | +{ | |
| 514 | + struct max96714_priv *priv = sd_to_max96714(notifier->sd); | |
| 515 | + struct device *dev = &priv->client->dev; | |
| 516 | + int ret; | |
| 517 | + | |
| 518 | + ret = media_entity_get_fwnode_pad(&subdev->entity, | |
| 519 | + priv->rxport.source.ep_fwnode, | |
| 520 | + MEDIA_PAD_FL_SOURCE); | |
| 521 | + if (ret < 0) { | |
| 522 | + dev_err(dev, "Failed to find pad for %s\n", subdev->name); | |
| 523 | + return ret; | |
| 524 | + } | |
| 525 | + | |
| 526 | + priv->rxport.source.sd = subdev; | |
| 527 | + priv->rxport.source.pad = ret; | |
| 528 | + | |
| 529 | + ret = media_create_pad_link(&priv->rxport.source.sd->entity, | |
| 530 | + priv->rxport.source.pad, &priv->sd.entity, | |
| 531 | + MAX96714_PAD_SINK, | |
| 532 | + MEDIA_LNK_FL_ENABLED | | |
| 533 | + MEDIA_LNK_FL_IMMUTABLE); | |
| 534 | + if (ret) { | |
| 535 | + dev_err(dev, "Unable to link %s:%u -> %s:%u\n", | |
| 536 | + priv->rxport.source.sd->name, priv->rxport.source.pad, | |
| 537 | + priv->sd.name, MAX96714_PAD_SINK); | |
| 538 | + return ret; | |
| 539 | + } | |
| 540 | + | |
| 541 | + return 0; | |
| 542 | +} | |
| 543 | + | |
| 544 | +static const struct v4l2_async_notifier_operations max96714_notify_ops = { | |
| 545 | + .bound = max96714_notify_bound, | |
| 546 | +}; | |
| 547 | + | |
| 548 | +static int max96714_v4l2_notifier_register(struct max96714_priv *priv) | |
| 549 | +{ | |
| 550 | + struct device *dev = &priv->client->dev; | |
| 551 | + struct max96714_rxport *rxport = &priv->rxport; | |
| 552 | + struct v4l2_async_connection *asd; | |
| 553 | + int ret; | |
| 554 | + | |
| 555 | + if (!rxport->source.ep_fwnode) | |
| 556 | + return 0; | |
| 557 | + | |
| 558 | + v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd); | |
| 559 | + | |
| 560 | + asd = v4l2_async_nf_add_fwnode(&priv->notifier, | |
| 561 | + rxport->source.ep_fwnode, | |
| 562 | + struct v4l2_async_connection); | |
| 563 | + if (IS_ERR(asd)) { | |
| 564 | + dev_err(dev, "Failed to add subdev: %pe", asd); | |
| 565 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 566 | + return PTR_ERR(asd); | |
| 567 | + } | |
| 568 | + | |
| 569 | + priv->notifier.ops = &max96714_notify_ops; | |
| 570 | + | |
| 571 | + ret = v4l2_async_nf_register(&priv->notifier); | |
| 572 | + if (ret) { | |
| 573 | + dev_err(dev, "Failed to register subdev_notifier"); | |
| 574 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 575 | + return ret; | |
| 576 | + } | |
| 577 | + | |
| 578 | + return 0; | |
| 579 | +} | |
| 580 | + | |
| 581 | +static int max96714_create_subdev(struct max96714_priv *priv) | |
| 582 | +{ | |
| 583 | + struct device *dev = &priv->client->dev; | |
| 584 | + int ret; | |
| 585 | + | |
| 586 | + v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96714_subdev_ops); | |
| 587 | + priv->sd.internal_ops = &max96714_internal_ops; | |
| 588 | + | |
| 589 | + v4l2_ctrl_handler_init(&priv->ctrl_handler, 1); | |
| 590 | + priv->sd.ctrl_handler = &priv->ctrl_handler; | |
| 591 | + | |
| 592 | + v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ, | |
| 593 | + 0, 0, &priv->tx_link_freq); | |
| 594 | + v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, | |
| 595 | + &max96714_ctrl_ops, | |
| 596 | + V4L2_CID_TEST_PATTERN, | |
| 597 | + ARRAY_SIZE(max96714_test_pattern) - 1, | |
| 598 | + 0, 0, max96714_test_pattern); | |
| 599 | + if (priv->ctrl_handler.error) { | |
| 600 | + ret = priv->ctrl_handler.error; | |
| 601 | + goto err_free_ctrl; | |
| 602 | + } | |
| 603 | + | |
| 604 | + priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; | |
| 605 | + priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; | |
| 606 | + priv->sd.entity.ops = &max96714_entity_ops; | |
| 607 | + | |
| 608 | + priv->pads[MAX96714_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | |
| 609 | + priv->pads[MAX96714_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | |
| 610 | + | |
| 611 | + ret = media_entity_pads_init(&priv->sd.entity, | |
| 612 | + MAX96714_NPORTS, | |
| 613 | + priv->pads); | |
| 614 | + if (ret) | |
| 615 | + goto err_free_ctrl; | |
| 616 | + | |
| 617 | + priv->sd.state_lock = priv->sd.ctrl_handler->lock; | |
| 618 | + | |
| 619 | + ret = v4l2_subdev_init_finalize(&priv->sd); | |
| 620 | + if (ret) | |
| 621 | + goto err_entity_cleanup; | |
| 622 | + | |
| 623 | + ret = max96714_v4l2_notifier_register(priv); | |
| 624 | + if (ret) { | |
| 625 | + dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret); | |
| 626 | + goto err_subdev_cleanup; | |
| 627 | + } | |
| 628 | + | |
| 629 | + ret = v4l2_async_register_subdev(&priv->sd); | |
| 630 | + if (ret) { | |
| 631 | + dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret); | |
| 632 | + goto err_unreg_notif; | |
| 633 | + } | |
| 634 | + | |
| 635 | + return 0; | |
| 636 | + | |
| 637 | +err_unreg_notif: | |
| 638 | + v4l2_async_nf_unregister(&priv->notifier); | |
| 639 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 640 | +err_subdev_cleanup: | |
| 641 | + v4l2_subdev_cleanup(&priv->sd); | |
| 642 | +err_entity_cleanup: | |
| 643 | + media_entity_cleanup(&priv->sd.entity); | |
| 644 | +err_free_ctrl: | |
| 645 | + v4l2_ctrl_handler_free(&priv->ctrl_handler); | |
| 646 | + | |
| 647 | + return ret; | |
| 648 | +}; | |
| 649 | + | |
| 650 | +static void max96714_destroy_subdev(struct max96714_priv *priv) | |
| 651 | +{ | |
| 652 | + v4l2_async_nf_unregister(&priv->notifier); | |
| 653 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 654 | + v4l2_async_unregister_subdev(&priv->sd); | |
| 655 | + | |
| 656 | + v4l2_subdev_cleanup(&priv->sd); | |
| 657 | + | |
| 658 | + media_entity_cleanup(&priv->sd.entity); | |
| 659 | + v4l2_ctrl_handler_free(&priv->ctrl_handler); | |
| 660 | +} | |
| 661 | + | |
| 662 | +static int max96714_i2c_mux_select(struct i2c_mux_core *mux, u32 chan) | |
| 663 | +{ | |
| 664 | + return 0; | |
| 665 | +} | |
| 666 | + | |
| 667 | +static int max96714_i2c_mux_init(struct max96714_priv *priv) | |
| 668 | +{ | |
| 669 | + priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev, | |
| 670 | + 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, | |
| 671 | + max96714_i2c_mux_select, NULL); | |
| 672 | + if (!priv->mux) | |
| 673 | + return -ENOMEM; | |
| 674 | + | |
| 675 | + return i2c_mux_add_adapter(priv->mux, 0, 0); | |
| 676 | +} | |
| 677 | + | |
| 678 | +static int max96714_init_tx_port(struct max96714_priv *priv) | |
| 679 | +{ | |
| 680 | + struct v4l2_mbus_config_mipi_csi2 *mipi; | |
| 681 | + unsigned long lanes_used = 0; | |
| 682 | + unsigned int val, lane; | |
| 683 | + int ret; | |
| 684 | + | |
| 685 | + ret = max96714_disable_tx_port(priv); | |
| 686 | + | |
| 687 | + mipi = &priv->mipi_csi2; | |
| 688 | + val = div_u64(priv->tx_link_freq * 2, MHZ(100)); | |
| 689 | + | |
| 690 | + cci_update_bits(priv->regmap, MAX96714_BACKTOP25, | |
| 691 | + CSI_DPLL_FREQ_MASK, val, &ret); | |
| 692 | + | |
| 693 | + val = FIELD_PREP(MAX96714_CSI2_LANE_CNT_MASK, mipi->num_data_lanes - 1); | |
| 694 | + cci_update_bits(priv->regmap, MAX96714_MIPI_LANE_CNT, | |
| 695 | + MAX96714_CSI2_LANE_CNT_MASK, val, &ret); | |
| 696 | + | |
| 697 | + /* lanes polarity */ | |
| 698 | + val = 0; | |
| 699 | + for (lane = 0; lane < mipi->num_data_lanes + 1; lane++) { | |
| 700 | + if (!mipi->lane_polarities[lane]) | |
| 701 | + continue; | |
| 702 | + if (lane == 0) | |
| 703 | + /* clock lane */ | |
| 704 | + val |= BIT(5); | |
| 705 | + else if (lane < 3) | |
| 706 | + /* Lane D0 and D1 */ | |
| 707 | + val |= BIT(lane - 1); | |
| 708 | + else | |
| 709 | + /* D2 and D3 */ | |
| 710 | + val |= BIT(lane); | |
| 711 | + } | |
| 712 | + | |
| 713 | + cci_update_bits(priv->regmap, MAX96714_MIPI_POLARITY, | |
| 714 | + MAX96714_MIPI_POLARITY_MASK, val, &ret); | |
| 715 | + | |
| 716 | + /* lanes mapping */ | |
| 717 | + val = 0; | |
| 718 | + for (lane = 0; lane < mipi->num_data_lanes; lane++) { | |
| 719 | + val |= (mipi->data_lanes[lane] - 1) << (lane * 2); | |
| 720 | + lanes_used |= BIT(mipi->data_lanes[lane] - 1); | |
| 721 | + } | |
| 722 | + | |
| 723 | + /* | |
| 724 | + * Unused lanes need to be mapped as well to not have | |
| 725 | + * the same lanes mapped twice. | |
| 726 | + */ | |
| 727 | + for (; lane < 4; lane++) { | |
| 728 | + unsigned int idx = find_first_zero_bit(&lanes_used, 4); | |
| 729 | + | |
| 730 | + val |= idx << (lane * 2); | |
| 731 | + lanes_used |= BIT(idx); | |
| 732 | + } | |
| 733 | + | |
| 734 | + return cci_write(priv->regmap, MAX96714_MIPI_LANE_MAP, val, &ret); | |
| 735 | +} | |
| 736 | + | |
| 737 | +static int max96714_rxport_enable_poc(struct max96714_priv *priv) | |
| 738 | +{ | |
| 739 | + struct max96714_rxport *rxport = &priv->rxport; | |
| 740 | + | |
| 741 | + if (!rxport->poc) | |
| 742 | + return 0; | |
| 743 | + | |
| 744 | + return regulator_enable(rxport->poc); | |
| 745 | +} | |
| 746 | + | |
| 747 | +static int max96714_rxport_disable_poc(struct max96714_priv *priv) | |
| 748 | +{ | |
| 749 | + struct max96714_rxport *rxport = &priv->rxport; | |
| 750 | + | |
| 751 | + if (!rxport->poc) | |
| 752 | + return 0; | |
| 753 | + | |
| 754 | + return regulator_disable(rxport->poc); | |
| 755 | +} | |
| 756 | + | |
| 757 | +static int max96714_parse_dt_txport(struct max96714_priv *priv) | |
| 758 | +{ | |
| 759 | + struct device *dev = &priv->client->dev; | |
| 760 | + struct v4l2_fwnode_endpoint vep = { | |
| 761 | + .bus_type = V4L2_MBUS_CSI2_DPHY | |
| 762 | + }; | |
| 763 | + struct fwnode_handle *ep_fwnode; | |
| 764 | + u32 num_data_lanes; | |
| 765 | + int ret; | |
| 766 | + | |
| 767 | + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), | |
| 768 | + MAX96714_PAD_SOURCE, 0, 0); | |
| 769 | + if (!ep_fwnode) | |
| 770 | + return -EINVAL; | |
| 771 | + | |
| 772 | + ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &vep); | |
| 773 | + fwnode_handle_put(ep_fwnode); | |
| 774 | + if (ret) { | |
| 775 | + dev_err(dev, "tx: failed to parse endpoint data\n"); | |
| 776 | + return -EINVAL; | |
| 777 | + } | |
| 778 | + | |
| 779 | + if (vep.nr_of_link_frequencies != 1) { | |
| 780 | + ret = -EINVAL; | |
| 781 | + goto err_free_vep; | |
| 782 | + } | |
| 783 | + | |
| 784 | + priv->tx_link_freq = vep.link_frequencies[0]; | |
| 785 | + /* Min 50MHz, Max 1250MHz, 50MHz step */ | |
| 786 | + if (priv->tx_link_freq < MHZ(50) || priv->tx_link_freq > MHZ(1250) || | |
| 787 | + (u32)priv->tx_link_freq % MHZ(50)) { | |
| 788 | + dev_err(dev, "tx: invalid link frequency\n"); | |
| 789 | + ret = -EINVAL; | |
| 790 | + goto err_free_vep; | |
| 791 | + } | |
| 792 | + | |
| 793 | + num_data_lanes = vep.bus.mipi_csi2.num_data_lanes; | |
| 794 | + if (num_data_lanes < 1 || num_data_lanes > 4) { | |
| 795 | + dev_err(dev, | |
| 796 | + "tx: invalid number of data lanes must be 1 to 4\n"); | |
| 797 | + ret = -EINVAL; | |
| 798 | + goto err_free_vep; | |
| 799 | + } | |
| 800 | + | |
| 801 | + memcpy(&priv->mipi_csi2, &vep.bus.mipi_csi2, sizeof(priv->mipi_csi2)); | |
| 802 | + | |
| 803 | +err_free_vep: | |
| 804 | + v4l2_fwnode_endpoint_free(&vep); | |
| 805 | + | |
| 806 | + return ret; | |
| 807 | +} | |
| 808 | + | |
| 809 | +static int max96714_parse_dt_rxport(struct max96714_priv *priv) | |
| 810 | +{ | |
| 811 | + static const char *poc_name = "port0-poc"; | |
| 812 | + struct max96714_rxport *rxport = &priv->rxport; | |
| 813 | + struct device *dev = &priv->client->dev; | |
| 814 | + struct fwnode_handle *ep_fwnode; | |
| 815 | + int ret; | |
| 816 | + | |
| 817 | + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), | |
| 818 | + MAX96714_PAD_SINK, 0, 0); | |
| 819 | + if (!ep_fwnode) | |
| 820 | + return -ENOENT; | |
| 821 | + | |
| 822 | + rxport->source.ep_fwnode = fwnode_graph_get_remote_endpoint(ep_fwnode); | |
| 823 | + fwnode_handle_put(ep_fwnode); | |
| 824 | + | |
| 825 | + if (!rxport->source.ep_fwnode) { | |
| 826 | + dev_err(dev, "rx: no remote endpoint\n"); | |
| 827 | + return -EINVAL; | |
| 828 | + } | |
| 829 | + | |
| 830 | + rxport->poc = devm_regulator_get_optional(dev, poc_name); | |
| 831 | + if (IS_ERR(rxport->poc)) { | |
| 832 | + ret = PTR_ERR(rxport->poc); | |
| 833 | + if (ret == -ENODEV) { | |
| 834 | + rxport->poc = NULL; | |
| 835 | + } else { | |
| 836 | + dev_err(dev, "rx: failed to get POC supply: %d\n", ret); | |
| 837 | + goto err_put_source_ep_fwnode; | |
| 838 | + } | |
| 839 | + } | |
| 840 | + | |
| 841 | + return 0; | |
| 842 | + | |
| 843 | +err_put_source_ep_fwnode: | |
| 844 | + fwnode_handle_put(rxport->source.ep_fwnode); | |
| 845 | + return ret; | |
| 846 | +} | |
| 847 | + | |
| 848 | +static int max96714_parse_dt(struct max96714_priv *priv) | |
| 849 | +{ | |
| 850 | + int ret; | |
| 851 | + | |
| 852 | + ret = max96714_parse_dt_txport(priv); | |
| 853 | + if (ret) | |
| 854 | + return ret; | |
| 855 | + | |
| 856 | + ret = max96714_parse_dt_rxport(priv); | |
| 857 | + /* | |
| 858 | + * The deserializer can create a test pattern even if the | |
| 859 | + * rx port is not connected to a serializer. | |
| 860 | + */ | |
| 861 | + if (ret && ret == -ENOENT) | |
| 862 | + ret = 0; | |
| 863 | + | |
| 864 | + return ret; | |
| 865 | +} | |
| 866 | + | |
| 867 | +static int max96714_enable_core_hw(struct max96714_priv *priv) | |
| 868 | +{ | |
| 869 | + struct device *dev = &priv->client->dev; | |
| 870 | + u64 val; | |
| 871 | + int ret; | |
| 872 | + | |
| 873 | + if (priv->pd_gpio) { | |
| 874 | + /* wait min 2 ms for reset to complete */ | |
| 875 | + gpiod_set_value_cansleep(priv->pd_gpio, 1); | |
| 876 | + fsleep(2000); | |
| 877 | + gpiod_set_value_cansleep(priv->pd_gpio, 0); | |
| 878 | + /* wait min 2 ms for power up to finish */ | |
| 879 | + fsleep(2000); | |
| 880 | + } | |
| 881 | + | |
| 882 | + ret = cci_read(priv->regmap, MAX96714_REG13, &val, NULL); | |
| 883 | + if (ret) { | |
| 884 | + dev_err_probe(dev, ret, "Cannot read first register, abort\n"); | |
| 885 | + goto err_pd_gpio; | |
| 886 | + } | |
| 887 | + | |
| 888 | + if (val != MAX96714_DEVICE_ID && val != MAX96714F_DEVICE_ID) { | |
| 889 | + dev_err(dev, "Unsupported device id expected %x got %x\n", | |
| 890 | + MAX96714F_DEVICE_ID, (u8)val); | |
| 891 | + ret = -EOPNOTSUPP; | |
| 892 | + goto err_pd_gpio; | |
| 893 | + } | |
| 894 | + | |
| 895 | + ret = cci_read(priv->regmap, MAX96714_DEV_REV, &val, NULL); | |
| 896 | + if (ret) | |
| 897 | + goto err_pd_gpio; | |
| 898 | + | |
| 899 | + dev_dbg(dev, "Found %x (rev %lx)\n", MAX96714F_DEVICE_ID, | |
| 900 | + (u8)val & MAX96714_DEV_REV_MASK); | |
| 901 | + | |
| 902 | + ret = cci_read(priv->regmap, MAX96714_MIPI_TX52, &val, NULL); | |
| 903 | + if (ret) | |
| 904 | + goto err_pd_gpio; | |
| 905 | + | |
| 906 | + if (!(val & MAX96714_TUN_EN)) { | |
| 907 | + dev_err(dev, "Only supporting tunnel mode"); | |
| 908 | + ret = -EOPNOTSUPP; | |
| 909 | + goto err_pd_gpio; | |
| 910 | + } | |
| 911 | + | |
| 912 | + return 0; | |
| 913 | + | |
| 914 | +err_pd_gpio: | |
| 915 | + gpiod_set_value_cansleep(priv->pd_gpio, 1); | |
| 916 | + return ret; | |
| 917 | +} | |
| 918 | + | |
| 919 | +static void max96714_disable_core_hw(struct max96714_priv *priv) | |
| 920 | +{ | |
| 921 | + gpiod_set_value_cansleep(priv->pd_gpio, 1); | |
| 922 | +} | |
| 923 | + | |
| 924 | +static int max96714_get_hw_resources(struct max96714_priv *priv) | |
| 925 | +{ | |
| 926 | + struct device *dev = &priv->client->dev; | |
| 927 | + | |
| 928 | + priv->regmap = devm_cci_regmap_init_i2c(priv->client, 16); | |
| 929 | + if (IS_ERR(priv->regmap)) | |
| 930 | + return PTR_ERR(priv->regmap); | |
| 931 | + | |
| 932 | + priv->pd_gpio = | |
| 933 | + devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH); | |
| 934 | + if (IS_ERR(priv->pd_gpio)) | |
| 935 | + return dev_err_probe(dev, PTR_ERR(priv->pd_gpio), | |
| 936 | + "Cannot get powerdown GPIO\n"); | |
| 937 | + return 0; | |
| 938 | +} | |
| 939 | + | |
| 940 | +static int max96714_probe(struct i2c_client *client) | |
| 941 | +{ | |
| 942 | + struct device *dev = &client->dev; | |
| 943 | + struct max96714_priv *priv; | |
| 944 | + int ret; | |
| 945 | + | |
| 946 | + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
| 947 | + if (!priv) | |
| 948 | + return -ENOMEM; | |
| 949 | + | |
| 950 | + priv->client = client; | |
| 951 | + | |
| 952 | + ret = max96714_get_hw_resources(priv); | |
| 953 | + if (ret) | |
| 954 | + return ret; | |
| 955 | + | |
| 956 | + ret = max96714_enable_core_hw(priv); | |
| 957 | + if (ret) | |
| 958 | + return ret; | |
| 959 | + | |
| 960 | + ret = max96714_parse_dt(priv); | |
| 961 | + if (ret) | |
| 962 | + goto err_disable_core_hw; | |
| 963 | + | |
| 964 | + max96714_init_tx_port(priv); | |
| 965 | + | |
| 966 | + ret = max96714_rxport_enable_poc(priv); | |
| 967 | + if (ret) | |
| 968 | + goto err_free_ports; | |
| 969 | + | |
| 970 | + ret = max96714_i2c_mux_init(priv); | |
| 971 | + if (ret) | |
| 972 | + goto err_disable_poc; | |
| 973 | + | |
| 974 | + ret = max96714_create_subdev(priv); | |
| 975 | + if (ret) | |
| 976 | + goto err_del_mux; | |
| 977 | + | |
| 978 | + return 0; | |
| 979 | + | |
| 980 | +err_del_mux: | |
| 981 | + i2c_mux_del_adapters(priv->mux); | |
| 982 | +err_disable_poc: | |
| 983 | + max96714_rxport_disable_poc(priv); | |
| 984 | +err_free_ports: | |
| 985 | + fwnode_handle_put(priv->rxport.source.ep_fwnode); | |
| 986 | +err_disable_core_hw: | |
| 987 | + max96714_disable_core_hw(priv); | |
| 988 | + | |
| 989 | + return ret; | |
| 990 | +} | |
| 991 | + | |
| 992 | +static void max96714_remove(struct i2c_client *client) | |
| 993 | +{ | |
| 994 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 995 | + struct max96714_priv *priv = sd_to_max96714(sd); | |
| 996 | + | |
| 997 | + max96714_destroy_subdev(priv); | |
| 998 | + i2c_mux_del_adapters(priv->mux); | |
| 999 | + max96714_rxport_disable_poc(priv); | |
| 1000 | + fwnode_handle_put(priv->rxport.source.ep_fwnode); | |
| 1001 | + max96714_disable_core_hw(priv); | |
| 1002 | + gpiod_set_value_cansleep(priv->pd_gpio, 1); | |
| 1003 | +} | |
| 1004 | + | |
| 1005 | +static const struct of_device_id max96714_of_ids[] = { | |
| 1006 | + { .compatible = "maxim,max96714f" }, | |
| 1007 | + { } | |
| 1008 | +}; | |
| 1009 | +MODULE_DEVICE_TABLE(of, max96714_of_ids); | |
| 1010 | + | |
| 1011 | +static struct i2c_driver max96714_i2c_driver = { | |
| 1012 | + .driver = { | |
| 1013 | + .name = "max96714", | |
| 1014 | + .of_match_table = max96714_of_ids, | |
| 1015 | + }, | |
| 1016 | + .probe = max96714_probe, | |
| 1017 | + .remove = max96714_remove, | |
| 1018 | +}; | |
| 1019 | + | |
| 1020 | +module_i2c_driver(max96714_i2c_driver); | |
| 1021 | + | |
| 1022 | +MODULE_LICENSE("GPL"); | |
| 1023 | +MODULE_DESCRIPTION("Maxim Integrated GMSL2 Deserializers Driver"); | |
| 1024 | +MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>"); | |
| @@ -0,0 +1,927 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Maxim GMSL2 Serializer Driver | |
| 4 | + * | |
| 5 | + * Copyright (C) 2024 Collabora Ltd. | |
| 6 | + */ | |
| 7 | + | |
| 8 | +#include <linux/bitfield.h> | |
| 9 | +#include <linux/clk.h> | |
| 10 | +#include <linux/clk-provider.h> | |
| 11 | +#include <linux/delay.h> | |
| 12 | +#include <linux/fwnode.h> | |
| 13 | +#include <linux/gpio/driver.h> | |
| 14 | +#include <linux/i2c-mux.h> | |
| 15 | +#include <linux/i2c.h> | |
| 16 | +#include <linux/regmap.h> | |
| 17 | + | |
| 18 | +#include <media/v4l2-cci.h> | |
| 19 | +#include <media/v4l2-fwnode.h> | |
| 20 | +#include <media/v4l2-subdev.h> | |
| 21 | + | |
| 22 | +#define MAX96717_DEVICE_ID 0xbf | |
| 23 | +#define MAX96717F_DEVICE_ID 0xc8 | |
| 24 | +#define MAX96717_PORTS 2 | |
| 25 | +#define MAX96717_PAD_SINK 0 | |
| 26 | +#define MAX96717_PAD_SOURCE 1 | |
| 27 | + | |
| 28 | +#define MAX96717_DEFAULT_CLKOUT_RATE 24000000UL | |
| 29 | + | |
| 30 | +/* DEV */ | |
| 31 | +#define MAX96717_REG3 CCI_REG8(0x3) | |
| 32 | +#define MAX96717_RCLKSEL GENMASK(1, 0) | |
| 33 | +#define RCLKSEL_REF_PLL CCI_REG8(0x3) | |
| 34 | +#define MAX96717_REG6 CCI_REG8(0x6) | |
| 35 | +#define RCLKEN BIT(5) | |
| 36 | +#define MAX96717_DEV_ID CCI_REG8(0xd) | |
| 37 | +#define MAX96717_DEV_REV CCI_REG8(0xe) | |
| 38 | +#define MAX96717_DEV_REV_MASK GENMASK(3, 0) | |
| 39 | + | |
| 40 | +/* VID_TX Z */ | |
| 41 | +#define MAX96717_VIDEO_TX2 CCI_REG8(0x112) | |
| 42 | +#define MAX96717_VIDEO_PCLKDET BIT(7) | |
| 43 | + | |
| 44 | +/* GPIO */ | |
| 45 | +#define MAX96717_NUM_GPIO 11 | |
| 46 | +#define MAX96717_GPIO_REG_A(gpio) CCI_REG8(0x2be + (gpio) * 3) | |
| 47 | +#define MAX96717_GPIO_OUT BIT(4) | |
| 48 | +#define MAX96717_GPIO_IN BIT(3) | |
| 49 | +#define MAX96717_GPIO_RX_EN BIT(2) | |
| 50 | +#define MAX96717_GPIO_TX_EN BIT(1) | |
| 51 | +#define MAX96717_GPIO_OUT_DIS BIT(0) | |
| 52 | + | |
| 53 | +/* FRONTTOP */ | |
| 54 | +/* MAX96717 only have CSI port 'B' */ | |
| 55 | +#define MAX96717_FRONTOP0 CCI_REG8(0x308) | |
| 56 | +#define MAX96717_START_PORT_B BIT(5) | |
| 57 | + | |
| 58 | +/* MIPI_RX */ | |
| 59 | +#define MAX96717_MIPI_RX1 CCI_REG8(0x331) | |
| 60 | +#define MAX96717_MIPI_LANES_CNT GENMASK(5, 4) | |
| 61 | +#define MAX96717_MIPI_RX2 CCI_REG8(0x332) /* phy1 Lanes map */ | |
| 62 | +#define MAX96717_PHY2_LANES_MAP GENMASK(7, 4) | |
| 63 | +#define MAX96717_MIPI_RX3 CCI_REG8(0x333) /* phy2 Lanes map */ | |
| 64 | +#define MAX96717_PHY1_LANES_MAP GENMASK(3, 0) | |
| 65 | +#define MAX96717_MIPI_RX4 CCI_REG8(0x334) /* phy1 lane polarities */ | |
| 66 | +#define MAX96717_PHY1_LANES_POL GENMASK(6, 4) | |
| 67 | +#define MAX96717_MIPI_RX5 CCI_REG8(0x335) /* phy2 lane polarities */ | |
| 68 | +#define MAX96717_PHY2_LANES_POL GENMASK(2, 0) | |
| 69 | + | |
| 70 | +/* MIPI_RX_EXT */ | |
| 71 | +#define MAX96717_MIPI_RX_EXT11 CCI_REG8(0x383) | |
| 72 | +#define MAX96717_TUN_MODE BIT(7) | |
| 73 | + | |
| 74 | +/* REF_VTG */ | |
| 75 | +#define REF_VTG0 CCI_REG8(0x3f0) | |
| 76 | +#define REFGEN_PREDEF_EN BIT(6) | |
| 77 | +#define REFGEN_PREDEF_FREQ_MASK GENMASK(5, 4) | |
| 78 | +#define REFGEN_PREDEF_FREQ_ALT BIT(3) | |
| 79 | +#define REFGEN_RST BIT(1) | |
| 80 | +#define REFGEN_EN BIT(0) | |
| 81 | + | |
| 82 | +/* MISC */ | |
| 83 | +#define PIO_SLEW_1 CCI_REG8(0x570) | |
| 84 | + | |
| 85 | +struct max96717_priv { | |
| 86 | + struct i2c_client *client; | |
| 87 | + struct regmap *regmap; | |
| 88 | + struct i2c_mux_core *mux; | |
| 89 | + struct v4l2_mbus_config_mipi_csi2 mipi_csi2; | |
| 90 | + struct v4l2_subdev sd; | |
| 91 | + struct media_pad pads[MAX96717_PORTS]; | |
| 92 | + struct v4l2_async_notifier notifier; | |
| 93 | + struct v4l2_subdev *source_sd; | |
| 94 | + u16 source_sd_pad; | |
| 95 | + u64 enabled_source_streams; | |
| 96 | + u8 pll_predef_index; | |
| 97 | + struct clk_hw clk_hw; | |
| 98 | + struct gpio_chip gpio_chip; | |
| 99 | +}; | |
| 100 | + | |
| 101 | +static inline struct max96717_priv *sd_to_max96717(struct v4l2_subdev *sd) | |
| 102 | +{ | |
| 103 | + return container_of(sd, struct max96717_priv, sd); | |
| 104 | +} | |
| 105 | + | |
| 106 | +static inline struct max96717_priv *clk_hw_to_max96717(struct clk_hw *hw) | |
| 107 | +{ | |
| 108 | + return container_of(hw, struct max96717_priv, clk_hw); | |
| 109 | +} | |
| 110 | + | |
| 111 | +static int max96717_i2c_mux_select(struct i2c_mux_core *mux, u32 chan) | |
| 112 | +{ | |
| 113 | + return 0; | |
| 114 | +} | |
| 115 | + | |
| 116 | +static int max96717_i2c_mux_init(struct max96717_priv *priv) | |
| 117 | +{ | |
| 118 | + priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev, | |
| 119 | + 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE, | |
| 120 | + max96717_i2c_mux_select, NULL); | |
| 121 | + if (!priv->mux) | |
| 122 | + return -ENOMEM; | |
| 123 | + | |
| 124 | + return i2c_mux_add_adapter(priv->mux, 0, 0); | |
| 125 | +} | |
| 126 | + | |
| 127 | +static inline int max96717_start_csi(struct max96717_priv *priv, bool start) | |
| 128 | +{ | |
| 129 | + return cci_update_bits(priv->regmap, MAX96717_FRONTOP0, | |
| 130 | + MAX96717_START_PORT_B, | |
| 131 | + start ? MAX96717_START_PORT_B : 0, NULL); | |
| 132 | +} | |
| 133 | + | |
| 134 | +static int max96717_gpiochip_get(struct gpio_chip *gpiochip, | |
| 135 | + unsigned int offset) | |
| 136 | +{ | |
| 137 | + struct max96717_priv *priv = gpiochip_get_data(gpiochip); | |
| 138 | + u64 val; | |
| 139 | + int ret; | |
| 140 | + | |
| 141 | + ret = cci_read(priv->regmap, MAX96717_GPIO_REG_A(offset), | |
| 142 | + &val, NULL); | |
| 143 | + if (ret) | |
| 144 | + return ret; | |
| 145 | + | |
| 146 | + if (val & MAX96717_GPIO_OUT_DIS) | |
| 147 | + return !!(val & MAX96717_GPIO_IN); | |
| 148 | + else | |
| 149 | + return !!(val & MAX96717_GPIO_OUT); | |
| 150 | +} | |
| 151 | + | |
| 152 | +static void max96717_gpiochip_set(struct gpio_chip *gpiochip, | |
| 153 | + unsigned int offset, int value) | |
| 154 | +{ | |
| 155 | + struct max96717_priv *priv = gpiochip_get_data(gpiochip); | |
| 156 | + | |
| 157 | + cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), | |
| 158 | + MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL); | |
| 159 | +} | |
| 160 | + | |
| 161 | +static int max96717_gpio_get_direction(struct gpio_chip *gpiochip, | |
| 162 | + unsigned int offset) | |
| 163 | +{ | |
| 164 | + struct max96717_priv *priv = gpiochip_get_data(gpiochip); | |
| 165 | + u64 val; | |
| 166 | + int ret; | |
| 167 | + | |
| 168 | + ret = cci_read(priv->regmap, MAX96717_GPIO_REG_A(offset), &val, NULL); | |
| 169 | + if (ret < 0) | |
| 170 | + return ret; | |
| 171 | + | |
| 172 | + return !!(val & MAX96717_GPIO_OUT_DIS); | |
| 173 | +} | |
| 174 | + | |
| 175 | +static int max96717_gpio_direction_out(struct gpio_chip *gpiochip, | |
| 176 | + unsigned int offset, int value) | |
| 177 | +{ | |
| 178 | + struct max96717_priv *priv = gpiochip_get_data(gpiochip); | |
| 179 | + | |
| 180 | + return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), | |
| 181 | + MAX96717_GPIO_OUT_DIS | MAX96717_GPIO_OUT, | |
| 182 | + value ? MAX96717_GPIO_OUT : 0, NULL); | |
| 183 | +} | |
| 184 | + | |
| 185 | +static int max96717_gpio_direction_in(struct gpio_chip *gpiochip, | |
| 186 | + unsigned int offset) | |
| 187 | +{ | |
| 188 | + struct max96717_priv *priv = gpiochip_get_data(gpiochip); | |
| 189 | + | |
| 190 | + return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset), | |
| 191 | + MAX96717_GPIO_OUT_DIS, MAX96717_GPIO_OUT_DIS, | |
| 192 | + NULL); | |
| 193 | +} | |
| 194 | + | |
| 195 | +static int max96717_gpiochip_probe(struct max96717_priv *priv) | |
| 196 | +{ | |
| 197 | + struct device *dev = &priv->client->dev; | |
| 198 | + struct gpio_chip *gc = &priv->gpio_chip; | |
| 199 | + int i, ret = 0; | |
| 200 | + | |
| 201 | + gc->label = dev_name(dev); | |
| 202 | + gc->parent = dev; | |
| 203 | + gc->owner = THIS_MODULE; | |
| 204 | + gc->ngpio = MAX96717_NUM_GPIO; | |
| 205 | + gc->base = -1; | |
| 206 | + gc->can_sleep = true; | |
| 207 | + gc->get_direction = max96717_gpio_get_direction; | |
| 208 | + gc->direction_input = max96717_gpio_direction_in; | |
| 209 | + gc->direction_output = max96717_gpio_direction_out; | |
| 210 | + gc->set = max96717_gpiochip_set; | |
| 211 | + gc->get = max96717_gpiochip_get; | |
| 212 | + gc->of_gpio_n_cells = 2; | |
| 213 | + | |
| 214 | + /* Disable GPIO forwarding */ | |
| 215 | + for (i = 0; i < gc->ngpio; i++) | |
| 216 | + cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(i), | |
| 217 | + MAX96717_GPIO_RX_EN | MAX96717_GPIO_TX_EN, | |
| 218 | + 0, &ret); | |
| 219 | + | |
| 220 | + if (ret) | |
| 221 | + return ret; | |
| 222 | + | |
| 223 | + ret = devm_gpiochip_add_data(dev, gc, priv); | |
| 224 | + if (ret) { | |
| 225 | + dev_err(dev, "Unable to create gpio_chip\n"); | |
| 226 | + return ret; | |
| 227 | + } | |
| 228 | + | |
| 229 | + return 0; | |
| 230 | +} | |
| 231 | + | |
| 232 | +static int _max96717_set_routing(struct v4l2_subdev *sd, | |
| 233 | + struct v4l2_subdev_state *state, | |
| 234 | + struct v4l2_subdev_krouting *routing) | |
| 235 | +{ | |
| 236 | + static const struct v4l2_mbus_framefmt format = { | |
| 237 | + .width = 1280, | |
| 238 | + .height = 1080, | |
| 239 | + .code = MEDIA_BUS_FMT_Y8_1X8, | |
| 240 | + .field = V4L2_FIELD_NONE, | |
| 241 | + }; | |
| 242 | + int ret; | |
| 243 | + | |
| 244 | + ret = v4l2_subdev_routing_validate(sd, routing, | |
| 245 | + V4L2_SUBDEV_ROUTING_ONLY_1_TO_1); | |
| 246 | + if (ret) | |
| 247 | + return ret; | |
| 248 | + | |
| 249 | + ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format); | |
| 250 | + if (ret) | |
| 251 | + return ret; | |
| 252 | + | |
| 253 | + return 0; | |
| 254 | +} | |
| 255 | + | |
| 256 | +static int max96717_set_routing(struct v4l2_subdev *sd, | |
| 257 | + struct v4l2_subdev_state *state, | |
| 258 | + enum v4l2_subdev_format_whence which, | |
| 259 | + struct v4l2_subdev_krouting *routing) | |
| 260 | +{ | |
| 261 | + struct max96717_priv *priv = sd_to_max96717(sd); | |
| 262 | + | |
| 263 | + if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams) | |
| 264 | + return -EBUSY; | |
| 265 | + | |
| 266 | + return _max96717_set_routing(sd, state, routing); | |
| 267 | +} | |
| 268 | + | |
| 269 | +static int max96717_set_fmt(struct v4l2_subdev *sd, | |
| 270 | + struct v4l2_subdev_state *state, | |
| 271 | + struct v4l2_subdev_format *format) | |
| 272 | +{ | |
| 273 | + struct max96717_priv *priv = sd_to_max96717(sd); | |
| 274 | + struct v4l2_mbus_framefmt *fmt; | |
| 275 | + u64 stream_source_mask; | |
| 276 | + | |
| 277 | + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && | |
| 278 | + priv->enabled_source_streams) | |
| 279 | + return -EBUSY; | |
| 280 | + | |
| 281 | + /* No transcoding, source and sink formats must match. */ | |
| 282 | + if (format->pad == MAX96717_PAD_SOURCE) | |
| 283 | + return v4l2_subdev_get_fmt(sd, state, format); | |
| 284 | + | |
| 285 | + /* Set sink format */ | |
| 286 | + fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream); | |
| 287 | + if (!fmt) | |
| 288 | + return -EINVAL; | |
| 289 | + | |
| 290 | + *fmt = format->format; | |
| 291 | + | |
| 292 | + /* Propagate to source format */ | |
| 293 | + fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad, | |
| 294 | + format->stream); | |
| 295 | + if (!fmt) | |
| 296 | + return -EINVAL; | |
| 297 | + *fmt = format->format; | |
| 298 | + | |
| 299 | + stream_source_mask = BIT(format->stream); | |
| 300 | + | |
| 301 | + return v4l2_subdev_state_xlate_streams(state, MAX96717_PAD_SOURCE, | |
| 302 | + MAX96717_PAD_SINK, | |
| 303 | + &stream_source_mask); | |
| 304 | +} | |
| 305 | + | |
| 306 | +static int max96717_init_state(struct v4l2_subdev *sd, | |
| 307 | + struct v4l2_subdev_state *state) | |
| 308 | +{ | |
| 309 | + struct v4l2_subdev_route routes[] = { | |
| 310 | + { | |
| 311 | + .sink_pad = MAX96717_PAD_SINK, | |
| 312 | + .sink_stream = 0, | |
| 313 | + .source_pad = MAX96717_PAD_SOURCE, | |
| 314 | + .source_stream = 0, | |
| 315 | + .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE, | |
| 316 | + }, | |
| 317 | + }; | |
| 318 | + struct v4l2_subdev_krouting routing = { | |
| 319 | + .num_routes = ARRAY_SIZE(routes), | |
| 320 | + .routes = routes, | |
| 321 | + }; | |
| 322 | + | |
| 323 | + return _max96717_set_routing(sd, state, &routing); | |
| 324 | +} | |
| 325 | + | |
| 326 | +static bool max96717_pipe_pclkdet(struct max96717_priv *priv) | |
| 327 | +{ | |
| 328 | + u64 val = 0; | |
| 329 | + | |
| 330 | + cci_read(priv->regmap, MAX96717_VIDEO_TX2, &val, NULL); | |
| 331 | + | |
| 332 | + return val & MAX96717_VIDEO_PCLKDET; | |
| 333 | +} | |
| 334 | + | |
| 335 | +static int max96717_log_status(struct v4l2_subdev *sd) | |
| 336 | +{ | |
| 337 | + struct max96717_priv *priv = sd_to_max96717(sd); | |
| 338 | + struct device *dev = &priv->client->dev; | |
| 339 | + | |
| 340 | + dev_info(dev, "Serializer: max96717\n"); | |
| 341 | + dev_info(dev, "Pipe: pclkdet:%d\n", max96717_pipe_pclkdet(priv)); | |
| 342 | + | |
| 343 | + return 0; | |
| 344 | +} | |
| 345 | + | |
| 346 | +static int max96717_enable_streams(struct v4l2_subdev *sd, | |
| 347 | + struct v4l2_subdev_state *state, u32 pad, | |
| 348 | + u64 streams_mask) | |
| 349 | +{ | |
| 350 | + struct max96717_priv *priv = sd_to_max96717(sd); | |
| 351 | + struct device *dev = &priv->client->dev; | |
| 352 | + u64 sink_streams; | |
| 353 | + int ret; | |
| 354 | + | |
| 355 | + sink_streams = v4l2_subdev_state_xlate_streams(state, | |
| 356 | + MAX96717_PAD_SOURCE, | |
| 357 | + MAX96717_PAD_SINK, | |
| 358 | + &streams_mask); | |
| 359 | + | |
| 360 | + if (!priv->enabled_source_streams) | |
| 361 | + max96717_start_csi(priv, true); | |
| 362 | + | |
| 363 | + ret = v4l2_subdev_enable_streams(priv->source_sd, priv->source_sd_pad, | |
| 364 | + sink_streams); | |
| 365 | + if (ret) { | |
| 366 | + dev_err(dev, "Fail to start streams:%llu on remote subdev\n", | |
| 367 | + sink_streams); | |
| 368 | + goto stop_csi; | |
| 369 | + } | |
| 370 | + | |
| 371 | + priv->enabled_source_streams |= streams_mask; | |
| 372 | + | |
| 373 | + return 0; | |
| 374 | + | |
| 375 | +stop_csi: | |
| 376 | + if (!priv->enabled_source_streams) | |
| 377 | + max96717_start_csi(priv, false); | |
| 378 | + return ret; | |
| 379 | +} | |
| 380 | + | |
| 381 | +static int max96717_disable_streams(struct v4l2_subdev *sd, | |
| 382 | + struct v4l2_subdev_state *state, u32 pad, | |
| 383 | + u64 streams_mask) | |
| 384 | +{ | |
| 385 | + struct max96717_priv *priv = sd_to_max96717(sd); | |
| 386 | + u64 sink_streams; | |
| 387 | + | |
| 388 | + /* | |
| 389 | + * Stop the CSI receiver first then the source, | |
| 390 | + * otherwise the device may become unresponsive | |
| 391 | + * while holding the I2C bus low. | |
| 392 | + */ | |
| 393 | + priv->enabled_source_streams &= ~streams_mask; | |
| 394 | + if (!priv->enabled_source_streams) | |
| 395 | + max96717_start_csi(priv, false); | |
| 396 | + | |
| 397 | + sink_streams = v4l2_subdev_state_xlate_streams(state, | |
| 398 | + MAX96717_PAD_SOURCE, | |
| 399 | + MAX96717_PAD_SINK, | |
| 400 | + &streams_mask); | |
| 401 | + | |
| 402 | + return v4l2_subdev_disable_streams(priv->source_sd, priv->source_sd_pad, | |
| 403 | + sink_streams); | |
| 404 | +} | |
| 405 | + | |
| 406 | +static const struct v4l2_subdev_pad_ops max96717_pad_ops = { | |
| 407 | + .enable_streams = max96717_enable_streams, | |
| 408 | + .disable_streams = max96717_disable_streams, | |
| 409 | + .set_routing = max96717_set_routing, | |
| 410 | + .get_fmt = v4l2_subdev_get_fmt, | |
| 411 | + .set_fmt = max96717_set_fmt, | |
| 412 | +}; | |
| 413 | + | |
| 414 | +static const struct v4l2_subdev_core_ops max96717_subdev_core_ops = { | |
| 415 | + .log_status = max96717_log_status, | |
| 416 | +}; | |
| 417 | + | |
| 418 | +static const struct v4l2_subdev_internal_ops max96717_internal_ops = { | |
| 419 | + .init_state = max96717_init_state, | |
| 420 | +}; | |
| 421 | + | |
| 422 | +static const struct v4l2_subdev_ops max96717_subdev_ops = { | |
| 423 | + .core = &max96717_subdev_core_ops, | |
| 424 | + .pad = &max96717_pad_ops, | |
| 425 | +}; | |
| 426 | + | |
| 427 | +static const struct media_entity_operations max96717_entity_ops = { | |
| 428 | + .link_validate = v4l2_subdev_link_validate, | |
| 429 | +}; | |
| 430 | + | |
| 431 | +static int max96717_notify_bound(struct v4l2_async_notifier *notifier, | |
| 432 | + struct v4l2_subdev *source_subdev, | |
| 433 | + struct v4l2_async_connection *asd) | |
| 434 | +{ | |
| 435 | + struct max96717_priv *priv = sd_to_max96717(notifier->sd); | |
| 436 | + struct device *dev = &priv->client->dev; | |
| 437 | + int ret; | |
| 438 | + | |
| 439 | + ret = media_entity_get_fwnode_pad(&source_subdev->entity, | |
| 440 | + source_subdev->fwnode, | |
| 441 | + MEDIA_PAD_FL_SOURCE); | |
| 442 | + if (ret < 0) { | |
| 443 | + dev_err(dev, "Failed to find pad for %s\n", | |
| 444 | + source_subdev->name); | |
| 445 | + return ret; | |
| 446 | + } | |
| 447 | + | |
| 448 | + priv->source_sd = source_subdev; | |
| 449 | + priv->source_sd_pad = ret; | |
| 450 | + | |
| 451 | + ret = media_create_pad_link(&source_subdev->entity, priv->source_sd_pad, | |
| 452 | + &priv->sd.entity, 0, | |
| 453 | + MEDIA_LNK_FL_ENABLED | | |
| 454 | + MEDIA_LNK_FL_IMMUTABLE); | |
| 455 | + if (ret) { | |
| 456 | + dev_err(dev, "Unable to link %s:%u -> %s:0\n", | |
| 457 | + source_subdev->name, priv->source_sd_pad, | |
| 458 | + priv->sd.name); | |
| 459 | + return ret; | |
| 460 | + } | |
| 461 | + | |
| 462 | + return 0; | |
| 463 | +} | |
| 464 | + | |
| 465 | +static const struct v4l2_async_notifier_operations max96717_notify_ops = { | |
| 466 | + .bound = max96717_notify_bound, | |
| 467 | +}; | |
| 468 | + | |
| 469 | +static int max96717_v4l2_notifier_register(struct max96717_priv *priv) | |
| 470 | +{ | |
| 471 | + struct device *dev = &priv->client->dev; | |
| 472 | + struct v4l2_async_connection *asd; | |
| 473 | + struct fwnode_handle *ep_fwnode; | |
| 474 | + int ret; | |
| 475 | + | |
| 476 | + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), | |
| 477 | + MAX96717_PAD_SINK, 0, 0); | |
| 478 | + if (!ep_fwnode) { | |
| 479 | + dev_err(dev, "No graph endpoint\n"); | |
| 480 | + return -ENODEV; | |
| 481 | + } | |
| 482 | + | |
| 483 | + v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd); | |
| 484 | + | |
| 485 | + asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep_fwnode, | |
| 486 | + struct v4l2_async_connection); | |
| 487 | + | |
| 488 | + fwnode_handle_put(ep_fwnode); | |
| 489 | + | |
| 490 | + if (IS_ERR(asd)) { | |
| 491 | + dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd)); | |
| 492 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 493 | + return PTR_ERR(asd); | |
| 494 | + } | |
| 495 | + | |
| 496 | + priv->notifier.ops = &max96717_notify_ops; | |
| 497 | + | |
| 498 | + ret = v4l2_async_nf_register(&priv->notifier); | |
| 499 | + if (ret) { | |
| 500 | + dev_err(dev, "Failed to register subdev_notifier"); | |
| 501 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 502 | + return ret; | |
| 503 | + } | |
| 504 | + | |
| 505 | + return 0; | |
| 506 | +} | |
| 507 | + | |
| 508 | +static int max96717_subdev_init(struct max96717_priv *priv) | |
| 509 | +{ | |
| 510 | + struct device *dev = &priv->client->dev; | |
| 511 | + int ret; | |
| 512 | + | |
| 513 | + v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96717_subdev_ops); | |
| 514 | + priv->sd.internal_ops = &max96717_internal_ops; | |
| 515 | + | |
| 516 | + priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS; | |
| 517 | + priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE; | |
| 518 | + priv->sd.entity.ops = &max96717_entity_ops; | |
| 519 | + | |
| 520 | + priv->pads[MAX96717_PAD_SINK].flags = MEDIA_PAD_FL_SINK; | |
| 521 | + priv->pads[MAX96717_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE; | |
| 522 | + | |
| 523 | + ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads); | |
| 524 | + if (ret) | |
| 525 | + return dev_err_probe(dev, ret, "Failed to init pads\n"); | |
| 526 | + | |
| 527 | + ret = v4l2_subdev_init_finalize(&priv->sd); | |
| 528 | + if (ret) { | |
| 529 | + dev_err_probe(dev, ret, | |
| 530 | + "v4l2 subdev init finalized failed\n"); | |
| 531 | + goto err_entity_cleanup; | |
| 532 | + } | |
| 533 | + ret = max96717_v4l2_notifier_register(priv); | |
| 534 | + if (ret) { | |
| 535 | + dev_err_probe(dev, ret, | |
| 536 | + "v4l2 subdev notifier register failed\n"); | |
| 537 | + goto err_free_state; | |
| 538 | + } | |
| 539 | + | |
| 540 | + ret = v4l2_async_register_subdev(&priv->sd); | |
| 541 | + if (ret) { | |
| 542 | + dev_err_probe(dev, ret, "v4l2_async_register_subdev error\n"); | |
| 543 | + goto err_unreg_notif; | |
| 544 | + } | |
| 545 | + | |
| 546 | + return 0; | |
| 547 | + | |
| 548 | +err_unreg_notif: | |
| 549 | + v4l2_async_nf_unregister(&priv->notifier); | |
| 550 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 551 | +err_free_state: | |
| 552 | + v4l2_subdev_cleanup(&priv->sd); | |
| 553 | +err_entity_cleanup: | |
| 554 | + media_entity_cleanup(&priv->sd.entity); | |
| 555 | + | |
| 556 | + return ret; | |
| 557 | +} | |
| 558 | + | |
| 559 | +static void max96717_subdev_uninit(struct max96717_priv *priv) | |
| 560 | +{ | |
| 561 | + v4l2_async_unregister_subdev(&priv->sd); | |
| 562 | + v4l2_async_nf_unregister(&priv->notifier); | |
| 563 | + v4l2_async_nf_cleanup(&priv->notifier); | |
| 564 | + v4l2_subdev_cleanup(&priv->sd); | |
| 565 | + media_entity_cleanup(&priv->sd.entity); | |
| 566 | +} | |
| 567 | + | |
| 568 | +struct max96717_pll_predef_freq { | |
| 569 | + unsigned long freq; | |
| 570 | + bool is_alt; | |
| 571 | + u8 val; | |
| 572 | +}; | |
| 573 | + | |
| 574 | +static const struct max96717_pll_predef_freq max96717_predef_freqs[] = { | |
| 575 | + { 13500000, true, 0 }, { 19200000, false, 0 }, | |
| 576 | + { 24000000, true, 1 }, { 27000000, false, 1 }, | |
| 577 | + { 37125000, false, 2 }, { 74250000, false, 3 }, | |
| 578 | +}; | |
| 579 | + | |
| 580 | +static unsigned long | |
| 581 | +max96717_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate) | |
| 582 | +{ | |
| 583 | + struct max96717_priv *priv = clk_hw_to_max96717(hw); | |
| 584 | + | |
| 585 | + return max96717_predef_freqs[priv->pll_predef_index].freq; | |
| 586 | +} | |
| 587 | + | |
| 588 | +static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv, | |
| 589 | + unsigned long rate) | |
| 590 | +{ | |
| 591 | + unsigned int i, idx; | |
| 592 | + unsigned long diff_new, diff_old; | |
| 593 | + | |
| 594 | + diff_old = U32_MAX; | |
| 595 | + idx = 0; | |
| 596 | + | |
| 597 | + for (i = 0; i < ARRAY_SIZE(max96717_predef_freqs); i++) { | |
| 598 | + diff_new = abs(rate - max96717_predef_freqs[i].freq); | |
| 599 | + if (diff_new < diff_old) { | |
| 600 | + diff_old = diff_new; | |
| 601 | + idx = i; | |
| 602 | + } | |
| 603 | + } | |
| 604 | + | |
| 605 | + return idx; | |
| 606 | +} | |
| 607 | + | |
| 608 | +static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate, | |
| 609 | + unsigned long *parent_rate) | |
| 610 | +{ | |
| 611 | + struct max96717_priv *priv = clk_hw_to_max96717(hw); | |
| 612 | + struct device *dev = &priv->client->dev; | |
| 613 | + unsigned int idx; | |
| 614 | + | |
| 615 | + idx = max96717_clk_find_best_index(priv, rate); | |
| 616 | + | |
| 617 | + if (rate != max96717_predef_freqs[idx].freq) { | |
| 618 | + dev_warn(dev, "Request CLK freq:%lu, found CLK freq:%lu\n", | |
| 619 | + rate, max96717_predef_freqs[idx].freq); | |
| 620 | + } | |
| 621 | + | |
| 622 | + return max96717_predef_freqs[idx].freq; | |
| 623 | +} | |
| 624 | + | |
| 625 | +static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate, | |
| 626 | + unsigned long parent_rate) | |
| 627 | +{ | |
| 628 | + struct max96717_priv *priv = clk_hw_to_max96717(hw); | |
| 629 | + unsigned int val, idx; | |
| 630 | + int ret = 0; | |
| 631 | + | |
| 632 | + idx = max96717_clk_find_best_index(priv, rate); | |
| 633 | + | |
| 634 | + val = FIELD_PREP(REFGEN_PREDEF_FREQ_MASK, | |
| 635 | + max96717_predef_freqs[idx].val); | |
| 636 | + | |
| 637 | + if (max96717_predef_freqs[idx].is_alt) | |
| 638 | + val |= REFGEN_PREDEF_FREQ_ALT; | |
| 639 | + | |
| 640 | + val |= REFGEN_RST | REFGEN_PREDEF_EN; | |
| 641 | + | |
| 642 | + cci_write(priv->regmap, REF_VTG0, val, &ret); | |
| 643 | + cci_update_bits(priv->regmap, REF_VTG0, REFGEN_RST | REFGEN_EN, | |
| 644 | + REFGEN_EN, &ret); | |
| 645 | + if (ret) | |
| 646 | + return ret; | |
| 647 | + | |
| 648 | + priv->pll_predef_index = idx; | |
| 649 | + | |
| 650 | + return 0; | |
| 651 | +} | |
| 652 | + | |
| 653 | +static int max96717_clk_prepare(struct clk_hw *hw) | |
| 654 | +{ | |
| 655 | + struct max96717_priv *priv = clk_hw_to_max96717(hw); | |
| 656 | + | |
| 657 | + return cci_update_bits(priv->regmap, MAX96717_REG6, RCLKEN, | |
| 658 | + RCLKEN, NULL); | |
| 659 | +} | |
| 660 | + | |
| 661 | +static void max96717_clk_unprepare(struct clk_hw *hw) | |
| 662 | +{ | |
| 663 | + struct max96717_priv *priv = clk_hw_to_max96717(hw); | |
| 664 | + | |
| 665 | + cci_update_bits(priv->regmap, MAX96717_REG6, RCLKEN, 0, NULL); | |
| 666 | +} | |
| 667 | + | |
| 668 | +static const struct clk_ops max96717_clk_ops = { | |
| 669 | + .prepare = max96717_clk_prepare, | |
| 670 | + .unprepare = max96717_clk_unprepare, | |
| 671 | + .set_rate = max96717_clk_set_rate, | |
| 672 | + .recalc_rate = max96717_clk_recalc_rate, | |
| 673 | + .round_rate = max96717_clk_round_rate, | |
| 674 | +}; | |
| 675 | + | |
| 676 | +static int max96717_register_clkout(struct max96717_priv *priv) | |
| 677 | +{ | |
| 678 | + struct device *dev = &priv->client->dev; | |
| 679 | + struct clk_init_data init = { .ops = &max96717_clk_ops }; | |
| 680 | + int ret; | |
| 681 | + | |
| 682 | + init.name = kasprintf(GFP_KERNEL, "max96717.%s.clk_out", | |
| 683 | + dev_name(dev)); | |
| 684 | + if (!init.name) | |
| 685 | + return -ENOMEM; | |
| 686 | + | |
| 687 | + /* RCLKSEL Reference PLL output */ | |
| 688 | + ret = cci_update_bits(priv->regmap, MAX96717_REG3, MAX96717_RCLKSEL, | |
| 689 | + MAX96717_RCLKSEL, NULL); | |
| 690 | + /* MFP4 fastest slew rate */ | |
| 691 | + cci_update_bits(priv->regmap, PIO_SLEW_1, BIT(5) | BIT(4), 0, &ret); | |
| 692 | + if (ret) | |
| 693 | + goto free_init_name; | |
| 694 | + | |
| 695 | + priv->clk_hw.init = &init; | |
| 696 | + | |
| 697 | + /* Initialize to 24 MHz */ | |
| 698 | + ret = max96717_clk_set_rate(&priv->clk_hw, | |
| 699 | + MAX96717_DEFAULT_CLKOUT_RATE, 0); | |
| 700 | + if (ret < 0) | |
| 701 | + goto free_init_name; | |
| 702 | + | |
| 703 | + ret = devm_clk_hw_register(dev, &priv->clk_hw); | |
| 704 | + kfree(init.name); | |
| 705 | + if (ret) | |
| 706 | + return dev_err_probe(dev, ret, "Cannot register clock HW\n"); | |
| 707 | + | |
| 708 | + ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get, | |
| 709 | + &priv->clk_hw); | |
| 710 | + if (ret) | |
| 711 | + return dev_err_probe(dev, ret, | |
| 712 | + "Cannot add OF clock provider\n"); | |
| 713 | + | |
| 714 | + return 0; | |
| 715 | + | |
| 716 | +free_init_name: | |
| 717 | + kfree(init.name); | |
| 718 | + return ret; | |
| 719 | +} | |
| 720 | + | |
| 721 | +static int max96717_init_csi_lanes(struct max96717_priv *priv) | |
| 722 | +{ | |
| 723 | + struct v4l2_mbus_config_mipi_csi2 *mipi = &priv->mipi_csi2; | |
| 724 | + unsigned long lanes_used = 0; | |
| 725 | + unsigned int nlanes, lane, val = 0; | |
| 726 | + int ret; | |
| 727 | + | |
| 728 | + nlanes = mipi->num_data_lanes; | |
| 729 | + | |
| 730 | + ret = cci_update_bits(priv->regmap, MAX96717_MIPI_RX1, | |
| 731 | + MAX96717_MIPI_LANES_CNT, | |
| 732 | + FIELD_PREP(MAX96717_MIPI_LANES_CNT, | |
| 733 | + nlanes - 1), NULL); | |
| 734 | + | |
| 735 | + /* lanes polarity */ | |
| 736 | + for (lane = 0; lane < nlanes + 1; lane++) { | |
| 737 | + if (!mipi->lane_polarities[lane]) | |
| 738 | + continue; | |
| 739 | + /* Clock lane */ | |
| 740 | + if (lane == 0) | |
| 741 | + val |= BIT(2); | |
| 742 | + else if (lane < 3) | |
| 743 | + val |= BIT(lane - 1); | |
| 744 | + else | |
| 745 | + val |= BIT(lane); | |
| 746 | + } | |
| 747 | + | |
| 748 | + cci_update_bits(priv->regmap, MAX96717_MIPI_RX5, | |
| 749 | + MAX96717_PHY2_LANES_POL, | |
| 750 | + FIELD_PREP(MAX96717_PHY2_LANES_POL, val), &ret); | |
| 751 | + | |
| 752 | + cci_update_bits(priv->regmap, MAX96717_MIPI_RX4, | |
| 753 | + MAX96717_PHY1_LANES_POL, | |
| 754 | + FIELD_PREP(MAX96717_PHY1_LANES_POL, | |
| 755 | + val >> 3), &ret); | |
| 756 | + /* lanes mapping */ | |
| 757 | + for (lane = 0, val = 0; lane < nlanes; lane++) { | |
| 758 | + val |= (mipi->data_lanes[lane] - 1) << (lane * 2); | |
| 759 | + lanes_used |= BIT(mipi->data_lanes[lane] - 1); | |
| 760 | + } | |
| 761 | + | |
| 762 | + /* | |
| 763 | + * Unused lanes need to be mapped as well to not have | |
| 764 | + * the same lanes mapped twice. | |
| 765 | + */ | |
| 766 | + for (; lane < 4; lane++) { | |
| 767 | + unsigned int idx = find_first_zero_bit(&lanes_used, 4); | |
| 768 | + | |
| 769 | + val |= idx << (lane * 2); | |
| 770 | + lanes_used |= BIT(idx); | |
| 771 | + } | |
| 772 | + | |
| 773 | + cci_update_bits(priv->regmap, MAX96717_MIPI_RX3, | |
| 774 | + MAX96717_PHY1_LANES_MAP, | |
| 775 | + FIELD_PREP(MAX96717_PHY1_LANES_MAP, val), &ret); | |
| 776 | + | |
| 777 | + return cci_update_bits(priv->regmap, MAX96717_MIPI_RX2, | |
| 778 | + MAX96717_PHY2_LANES_MAP, | |
| 779 | + FIELD_PREP(MAX96717_PHY2_LANES_MAP, val >> 4), | |
| 780 | + &ret); | |
| 781 | +} | |
| 782 | + | |
| 783 | +static int max96717_hw_init(struct max96717_priv *priv) | |
| 784 | +{ | |
| 785 | + struct device *dev = &priv->client->dev; | |
| 786 | + u64 dev_id, val; | |
| 787 | + int ret; | |
| 788 | + | |
| 789 | + ret = cci_read(priv->regmap, MAX96717_DEV_ID, &dev_id, NULL); | |
| 790 | + if (ret) | |
| 791 | + return dev_err_probe(dev, ret, | |
| 792 | + "Fail to read the device id\n"); | |
| 793 | + | |
| 794 | + if (dev_id != MAX96717_DEVICE_ID && dev_id != MAX96717F_DEVICE_ID) | |
| 795 | + return dev_err_probe(dev, -EOPNOTSUPP, | |
| 796 | + "Unsupported device id got %x\n", (u8)dev_id); | |
| 797 | + | |
| 798 | + ret = cci_read(priv->regmap, MAX96717_DEV_REV, &val, NULL); | |
| 799 | + if (ret) | |
| 800 | + return dev_err_probe(dev, ret, | |
| 801 | + "Fail to read device revision"); | |
| 802 | + | |
| 803 | + dev_dbg(dev, "Found %x (rev %lx)\n", (u8)dev_id, | |
| 804 | + (u8)val & MAX96717_DEV_REV_MASK); | |
| 805 | + | |
| 806 | + ret = cci_read(priv->regmap, MAX96717_MIPI_RX_EXT11, &val, NULL); | |
| 807 | + if (ret) | |
| 808 | + return dev_err_probe(dev, ret, | |
| 809 | + "Fail to read mipi rx extension"); | |
| 810 | + | |
| 811 | + if (!(val & MAX96717_TUN_MODE)) | |
| 812 | + return dev_err_probe(dev, -EOPNOTSUPP, | |
| 813 | + "Only supporting tunnel mode"); | |
| 814 | + | |
| 815 | + return max96717_init_csi_lanes(priv); | |
| 816 | +} | |
| 817 | + | |
| 818 | +static int max96717_parse_dt(struct max96717_priv *priv) | |
| 819 | +{ | |
| 820 | + struct device *dev = &priv->client->dev; | |
| 821 | + struct v4l2_fwnode_endpoint vep = { | |
| 822 | + .bus_type = V4L2_MBUS_CSI2_DPHY | |
| 823 | + }; | |
| 824 | + struct fwnode_handle *ep_fwnode; | |
| 825 | + unsigned char num_data_lanes; | |
| 826 | + int ret; | |
| 827 | + | |
| 828 | + ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), | |
| 829 | + MAX96717_PAD_SINK, 0, 0); | |
| 830 | + if (!ep_fwnode) | |
| 831 | + return dev_err_probe(dev, -ENOENT, "no endpoint found\n"); | |
| 832 | + | |
| 833 | + ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &vep); | |
| 834 | + | |
| 835 | + fwnode_handle_put(ep_fwnode); | |
| 836 | + | |
| 837 | + if (ret < 0) | |
| 838 | + return dev_err_probe(dev, ret, "Failed to parse sink endpoint"); | |
| 839 | + | |
| 840 | + num_data_lanes = vep.bus.mipi_csi2.num_data_lanes; | |
| 841 | + if (num_data_lanes < 1 || num_data_lanes > 4) | |
| 842 | + return dev_err_probe(dev, -EINVAL, | |
| 843 | + "Invalid data lanes must be 1 to 4\n"); | |
| 844 | + | |
| 845 | + memcpy(&priv->mipi_csi2, &vep.bus.mipi_csi2, sizeof(priv->mipi_csi2)); | |
| 846 | + | |
| 847 | + return 0; | |
| 848 | +} | |
| 849 | + | |
| 850 | +static int max96717_probe(struct i2c_client *client) | |
| 851 | +{ | |
| 852 | + struct device *dev = &client->dev; | |
| 853 | + struct max96717_priv *priv; | |
| 854 | + int ret; | |
| 855 | + | |
| 856 | + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); | |
| 857 | + if (!priv) | |
| 858 | + return -ENOMEM; | |
| 859 | + | |
| 860 | + priv->client = client; | |
| 861 | + priv->regmap = devm_cci_regmap_init_i2c(client, 16); | |
| 862 | + if (IS_ERR(priv->regmap)) { | |
| 863 | + ret = PTR_ERR(priv->regmap); | |
| 864 | + return dev_err_probe(dev, ret, "Failed to init regmap\n"); | |
| 865 | + } | |
| 866 | + | |
| 867 | + ret = max96717_parse_dt(priv); | |
| 868 | + if (ret) | |
| 869 | + return dev_err_probe(dev, ret, "Failed to parse the dt\n"); | |
| 870 | + | |
| 871 | + ret = max96717_hw_init(priv); | |
| 872 | + if (ret) | |
| 873 | + return dev_err_probe(dev, ret, | |
| 874 | + "Failed to initialize the hardware\n"); | |
| 875 | + | |
| 876 | + ret = max96717_gpiochip_probe(priv); | |
| 877 | + if (ret) | |
| 878 | + return dev_err_probe(&client->dev, ret, | |
| 879 | + "Failed to init gpiochip\n"); | |
| 880 | + | |
| 881 | + ret = max96717_register_clkout(priv); | |
| 882 | + if (ret) | |
| 883 | + return dev_err_probe(dev, ret, "Failed to register clkout\n"); | |
| 884 | + | |
| 885 | + ret = max96717_subdev_init(priv); | |
| 886 | + if (ret) | |
| 887 | + return dev_err_probe(dev, ret, | |
| 888 | + "Failed to initialize v4l2 subdev\n"); | |
| 889 | + | |
| 890 | + ret = max96717_i2c_mux_init(priv); | |
| 891 | + if (ret) { | |
| 892 | + dev_err_probe(dev, ret, "failed to add remote i2c adapter\n"); | |
| 893 | + max96717_subdev_uninit(priv); | |
| 894 | + } | |
| 895 | + | |
| 896 | + return ret; | |
| 897 | +} | |
| 898 | + | |
| 899 | +static void max96717_remove(struct i2c_client *client) | |
| 900 | +{ | |
| 901 | + struct v4l2_subdev *sd = i2c_get_clientdata(client); | |
| 902 | + struct max96717_priv *priv = sd_to_max96717(sd); | |
| 903 | + | |
| 904 | + max96717_subdev_uninit(priv); | |
| 905 | + i2c_mux_del_adapters(priv->mux); | |
| 906 | +} | |
| 907 | + | |
| 908 | +static const struct of_device_id max96717_of_ids[] = { | |
| 909 | + { .compatible = "maxim,max96717f" }, | |
| 910 | + { } | |
| 911 | +}; | |
| 912 | +MODULE_DEVICE_TABLE(of, max96717_of_ids); | |
| 913 | + | |
| 914 | +static struct i2c_driver max96717_i2c_driver = { | |
| 915 | + .driver = { | |
| 916 | + .name = "max96717", | |
| 917 | + .of_match_table = max96717_of_ids, | |
| 918 | + }, | |
| 919 | + .probe = max96717_probe, | |
| 920 | + .remove = max96717_remove, | |
| 921 | +}; | |
| 922 | + | |
| 923 | +module_i2c_driver(max96717_i2c_driver); | |
| 924 | + | |
| 925 | +MODULE_DESCRIPTION("Maxim GMSL2 MAX96717 Serializer Driver"); | |
| 926 | +MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>"); | |
| 927 | +MODULE_LICENSE("GPL"); | |
| @@ -971,7 +971,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor) · 970 unmodified lines | ||
| 971 | 971 | if (ret < 0) |
| 972 | 972 | return ret; |
| 973 | 973 | |
| 974 | − v4l2_ctrl_handler_init(hdl, 5); | |
| 974 | + v4l2_ctrl_handler_init(hdl, 11); | |
| 975 | 975 | |
| 976 | 976 | hdl->lock = &sensor->lock; |
| 977 | 977 | |
| @@ -1360,24 +1360,21 @@ static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np) · 1359 unmodified lines | ||
| 1360 | 1360 | struct v4l2_fwnode_endpoint bus_cfg = { |
| 1361 | 1361 | .bus_type = V4L2_MBUS_CSI2_DPHY, |
| 1362 | 1362 | }; |
| 1363 | − struct device_node *ep; | |
| 1363 | + struct device_node *ep __free(device_node) = | |
| 1364 | + of_graph_get_endpoint_by_regs(np, 0, -1); | |
| 1364 | 1365 | int ret; |
| 1365 | 1366 | |
| 1366 | − ep = of_graph_get_endpoint_by_regs(np, 0, -1); | |
| 1367 | 1367 | if (!ep) |
| 1368 | 1368 | return -EINVAL; |
| 1369 | 1369 | |
| 1370 | 1370 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); |
| 1371 | 1371 | if (ret) |
| 1372 | − goto out; | |
| 1372 | + return ret; | |
| 1373 | 1373 | |
| 1374 | 1374 | sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags & |
| 1375 | 1375 | V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; |
| 1376 | 1376 | |
| 1377 | −out: | |
| 1378 | − of_node_put(ep); | |
| 1379 | − | |
| 1380 | − return ret; | |
| 1377 | + return 0; | |
| 1381 | 1378 | } |
| 1382 | 1379 | |
| 1383 | 1380 | static int ov5647_probe(struct i2c_client *client) |
| @@ -141,7 +141,6 @@ struct ov5693_device { · 140 unmodified lines | ||
| 141 | 141 | |
| 142 | 142 | struct gpio_desc *reset; |
| 143 | 143 | struct gpio_desc *powerdown; |
| 144 | − struct gpio_desc *privacy_led; | |
| 145 | 144 | struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; |
| 146 | 145 | struct clk *xvclk; |
| 147 | 146 | |
| @@ -657,7 +656,6 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693) · 509 unmodified lines | ||
| 657 | 656 | |
| 658 | 657 | static void ov5693_sensor_powerdown(struct ov5693_device *ov5693) |
| 659 | 658 | { |
| 660 | − gpiod_set_value_cansleep(ov5693->privacy_led, 0); | |
| 661 | 659 | gpiod_set_value_cansleep(ov5693->reset, 1); |
| 662 | 660 | gpiod_set_value_cansleep(ov5693->powerdown, 1); |
| 663 | 661 | |
| @@ -687,7 +685,6 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693) · 23 unmodified lines | ||
| 687 | 685 | |
| 688 | 686 | gpiod_set_value_cansleep(ov5693->powerdown, 0); |
| 689 | 687 | gpiod_set_value_cansleep(ov5693->reset, 0); |
| 690 | − gpiod_set_value_cansleep(ov5693->privacy_led, 1); | |
| 691 | 688 | |
| 692 | 689 | usleep_range(5000, 7500); |
| 693 | 690 | |
| @@ -1201,13 +1198,6 @@ static int ov5693_configure_gpios(struct ov5693_device *ov5693) · 507 unmodified lines | ||
| 1201 | 1198 | return PTR_ERR(ov5693->powerdown); |
| 1202 | 1199 | } |
| 1203 | 1200 | |
| 1204 | − ov5693->privacy_led = devm_gpiod_get_optional(ov5693->dev, "privacy-led", | |
| 1205 | − GPIOD_OUT_LOW); | |
| 1206 | − if (IS_ERR(ov5693->privacy_led)) { | |
| 1207 | − dev_err(ov5693->dev, "Error fetching privacy-led GPIO\n"); | |
| 1208 | − return PTR_ERR(ov5693->privacy_led); | |
| 1209 | − } | |
| 1210 | − | |
| 1211 | 1201 | return 0; |
| 1212 | 1202 | } |
| 1213 | 1203 | |
| @@ -212,11 +212,6 @@ · 211 unmodified lines | ||
| 212 | 212 | * structure |
| 213 | 213 | */ |
| 214 | 214 | |
| 215 | −struct regval_list { | |
| 216 | − unsigned char reg_num; | |
| 217 | − unsigned char value; | |
| 218 | −}; | |
| 219 | − | |
| 220 | 215 | struct tw9910_scale_ctrl { |
| 221 | 216 | char *name; |
| 222 | 217 | unsigned short width; |
| @@ -95,4 +95,5 @@ static struct i2c_driver uda1342_driver = { · 94 unmodified lines | ||
| 95 | 95 | |
| 96 | 96 | module_i2c_driver(uda1342_driver); |
| 97 | 97 | |
| 98 | +MODULE_DESCRIPTION("Philips UDA1342 audio codec driver"); | |
| 98 | 99 | MODULE_LICENSE("GPL v2"); |
| @@ -1878,7 +1878,7 @@ static const struct dev_pm_ops vgxy61_pm_ops = { · 1877 unmodified lines | ||
| 1878 | 1878 | |
| 1879 | 1879 | static struct i2c_driver vgxy61_i2c_driver = { |
| 1880 | 1880 | .driver = { |
| 1881 | − .name = "st-vgxy61", | |
| 1881 | + .name = "vgxy61", | |
| 1882 | 1882 | .of_match_table = vgxy61_dt_ids, |
| 1883 | 1883 | .pm = &vgxy61_pm_ops, |
| 1884 | 1884 | }, |
| @@ -300,8 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id) · 299 unmodified lines | ||
| 300 | 300 | } |
| 301 | 301 | if (astat & BT878_ARISCI) { |
| 302 | 302 | bt->finished_block = (stat & BT878_ARISCS) >> 28; |
| 303 | − if (bt->tasklet.callback) | |
| 304 | − tasklet_schedule(&bt->tasklet); | |
| 303 | + if (bt->bh_work.func) | |
| 304 | + queue_work(system_bh_wq, &bt->bh_work); | |
| 305 | 305 | break; |
| 306 | 306 | } |
| 307 | 307 | count++; |
| @@ -478,8 +478,8 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id) · 170 unmodified lines | ||
| 478 | 478 | btwrite(0, BT878_AINT_MASK); |
| 479 | 479 | bt878_num++; |
| 480 | 480 | |
| 481 | − if (!bt->tasklet.func) | |
| 482 | − tasklet_disable(&bt->tasklet); | |
| 481 | + if (!bt->bh_work.func) | |
| 482 | + disable_work_sync(&bt->bh_work); | |
| 483 | 483 | |
| 484 | 484 | return 0; |
| 485 | 485 | |
| @@ -563,4 +563,5 @@ static void __exit bt878_cleanup_module(void) · 77 unmodified lines | ||
| 563 | 563 | module_init(bt878_init_module); |
| 564 | 564 | module_exit(bt878_cleanup_module); |
| 565 | 565 | |
| 566 | +MODULE_DESCRIPTION("DVB/ATSC Support for bt878 based TV cards"); | |
| 566 | 567 | MODULE_LICENSE("GPL"); |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/sched.h> |
| 15 | 15 | #include <linux/spinlock.h> |
| 16 | 16 | #include <linux/mutex.h> |
| 17 | +#include <linux/workqueue.h> | |
| 17 | 18 | |
| 18 | 19 | #include "bt848.h" |
| 19 | 20 | #include "bttv.h" |
| @@ -120,7 +121,7 @@ struct bt878 { · 100 unmodified lines | ||
| 120 | 121 | dma_addr_t risc_dma; |
| 121 | 122 | u32 risc_pos; |
| 122 | 123 | |
| 123 | − struct tasklet_struct tasklet; | |
| 124 | + struct work_struct bh_work; | |
| 124 | 125 | int shutdown; |
| 125 | 126 | }; |
| 126 | 127 | |
| @@ -39,9 +39,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 38 unmodified lines | ||
| 39 | 39 | |
| 40 | 40 | #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ |
| 41 | 41 | |
| 42 | −static void dvb_bt8xx_task(struct tasklet_struct *t) | |
| 42 | +static void dvb_bt8xx_work(struct work_struct *t) | |
| 43 | 43 | { |
| 44 | − struct bt878 *bt = from_tasklet(bt, t, tasklet); | |
| 44 | + struct bt878 *bt = from_work(bt, t, bh_work); | |
| 45 | 45 | struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev); |
| 46 | 46 | |
| 47 | 47 | dprintk("%d\n", card->bt->finished_block); |
| @@ -782,7 +782,7 @@ static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) · 734 unmodified lines | ||
| 782 | 782 | goto err_disconnect_frontend; |
| 783 | 783 | } |
| 784 | 784 | |
| 785 | − tasklet_setup(&card->bt->tasklet, dvb_bt8xx_task); | |
| 785 | + INIT_WORK(&card->bt->bh_work, dvb_bt8xx_work); | |
| 786 | 786 | |
| 787 | 787 | frontend_init(card, type); |
| 788 | 788 | |
| @@ -922,7 +922,7 @@ static void dvb_bt8xx_remove(struct bttv_sub_device *sub) · 133 unmodified lines | ||
| 922 | 922 | dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); |
| 923 | 923 | |
| 924 | 924 | bt878_stop(card->bt); |
| 925 | − tasklet_kill(&card->bt->tasklet); | |
| 925 | + cancel_work_sync(&card->bt->bh_work); | |
| 926 | 926 | dvb_net_release(&card->dvbnet); |
| 927 | 927 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); |
| 928 | 928 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); |
| @@ -258,7 +258,7 @@ struct cx18_scb { · 257 unmodified lines | ||
| 258 | 258 | struct cx18_mailbox ppu2epu_mb; |
| 259 | 259 | |
| 260 | 260 | struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; |
| 261 | − struct cx18_mdl_ent cpu_mdl[1]; | |
| 261 | + struct cx18_mdl_ent cpu_mdl[]; | |
| 262 | 262 | }; |
| 263 | 263 | |
| 264 | 264 | void cx18_init_scb(struct cx18 *cx); |
| @@ -298,7 +298,7 @@ struct ddb_link { · 297 unmodified lines | ||
| 298 | 298 | spinlock_t lock; /* lock link access */ |
| 299 | 299 | struct mutex flash_mutex; /* lock flash access */ |
| 300 | 300 | struct ddb_lnb lnb; |
| 301 | − struct tasklet_struct tasklet; | |
| 301 | + struct work_struct bh_work; | |
| 302 | 302 | struct ddb_ids ids; |
| 303 | 303 | |
| 304 | 304 | spinlock_t temp_lock; /* lock temp chip access */ |
| @@ -43,28 +43,46 @@ · 42 unmodified lines | ||
| 43 | 43 | * becoming apparent in the future. |
| 44 | 44 | * |
| 45 | 45 | * Do not add an entry for a sensor that is not actually supported. |
| 46 | + * | |
| 47 | + * Please keep the list sorted by ACPI HID. | |
| 46 | 48 | */ |
| 47 | 49 | static const struct ipu_sensor_config ipu_supported_sensors[] = { |
| 50 | + /* Himax HM11B1 */ | |
| 51 | + IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000), | |
| 52 | + /* Himax HM2170 */ | |
| 53 | + IPU_SENSOR_CONFIG("HIMX2170", 1, 384000000), | |
| 54 | + /* Himax HM2172 */ | |
| 55 | + IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000), | |
| 56 | + /* GalaxyCore GC0310 */ | |
| 57 | + IPU_SENSOR_CONFIG("INT0310", 0), | |
| 48 | 58 | /* Omnivision OV5693 */ |
| 49 | 59 | IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), |
| 60 | + /* Omnivision OV2740 */ | |
| 61 | + IPU_SENSOR_CONFIG("INT3474", 1, 180000000), | |
| 50 | 62 | /* Omnivision OV8865 */ |
| 51 | 63 | IPU_SENSOR_CONFIG("INT347A", 1, 360000000), |
| 52 | 64 | /* Omnivision OV7251 */ |
| 53 | 65 | IPU_SENSOR_CONFIG("INT347E", 1, 319200000), |
| 66 | + /* Hynix Hi-556 */ | |
| 67 | + IPU_SENSOR_CONFIG("INT3537", 1, 437000000), | |
| 68 | + /* Omnivision OV01A10 / OV01A1S */ | |
| 69 | + IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000), | |
| 70 | + IPU_SENSOR_CONFIG("OVTI01AS", 1, 400000000), | |
| 71 | + /* Omnivision OV02C10 */ | |
| 72 | + IPU_SENSOR_CONFIG("OVTI02C1", 1, 400000000), | |
| 73 | + /* Omnivision OV02E10 */ | |
| 74 | + IPU_SENSOR_CONFIG("OVTI02E1", 1, 360000000), | |
| 75 | + /* Omnivision OV08A10 */ | |
| 76 | + IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000), | |
| 77 | + /* Omnivision OV08x40 */ | |
| 78 | + IPU_SENSOR_CONFIG("OVTI08F4", 1, 400000000), | |
| 79 | + /* Omnivision OV13B10 */ | |
| 80 | + IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000), | |
| 81 | + IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), | |
| 54 | 82 | /* Omnivision OV2680 */ |
| 55 | 83 | IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), |
| 56 | − /* Omnivision ov8856 */ | |
| 84 | + /* Omnivision OV8856 */ | |
| 57 | 85 | IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), |
| 58 | − /* Omnivision ov2740 */ | |
| 59 | − IPU_SENSOR_CONFIG("INT3474", 1, 180000000), | |
| 60 | − /* Hynix hi556 */ | |
| 61 | − IPU_SENSOR_CONFIG("INT3537", 1, 437000000), | |
| 62 | − /* Omnivision ov13b10 */ | |
| 63 | − IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000), | |
| 64 | − /* GalaxyCore GC0310 */ | |
| 65 | − IPU_SENSOR_CONFIG("INT0310", 0), | |
| 66 | − /* Omnivision ov01a10 */ | |
| 67 | − IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000), | |
| 68 | 86 | }; |
| 69 | 87 | |
| 70 | 88 | static const struct ipu_property_names prop_names = { |
| @@ -163,8 +163,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp, · 162 unmodified lines | ||
| 163 | 163 | writel(ENTRY, isp->base + ipc->csr_out); |
| 164 | 164 | break; |
| 165 | 165 | default: |
| 166 | − dev_warn_ratelimited(&isp->pdev->dev, | |
| 167 | − "Unexpected CSR 0x%x\n", val); | |
| 166 | + dev_dbg_ratelimited(&isp->pdev->dev, | |
| 167 | + "Unexpected CSR 0x%x\n", val); | |
| 168 | 168 | break; |
| 169 | 169 | } |
| 170 | 170 | } while (retries--); |
| @@ -345,42 +345,61 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd, · 344 unmodified lines | ||
| 345 | 345 | return ret; |
| 346 | 346 | } |
| 347 | 347 | |
| 348 | −static int set_stream(struct v4l2_subdev *sd, int enable) | |
| 348 | +static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd, | |
| 349 | + struct v4l2_subdev_state *state, | |
| 350 | + u32 pad, u64 streams_mask) | |
| 349 | 351 | { |
| 350 | 352 | struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd); |
| 351 | 353 | struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd); |
| 352 | − struct device *dev = &csi2->isys->adev->auxdev.dev; | |
| 353 | 354 | struct ipu6_isys_csi2_timing timing = { }; |
| 354 | − unsigned int nlanes; | |
| 355 | + struct v4l2_subdev *remote_sd; | |
| 356 | + struct media_pad *remote_pad; | |
| 357 | + u64 sink_streams; | |
| 355 | 358 | int ret; |
| 356 | 359 | |
| 357 | − dev_dbg(dev, "csi2 stream %s callback\n", enable ? "on" : "off"); | |
| 358 | − | |
| 359 | − if (!enable) { | |
| 360 | − csi2->stream_count--; | |
| 361 | − if (csi2->stream_count) | |
| 362 | − return 0; | |
| 363 | − | |
| 364 | − ipu6_isys_csi2_set_stream(sd, &timing, 0, enable); | |
| 365 | − return 0; | |
| 366 | − } | |
| 367 | − | |
| 368 | − if (csi2->stream_count) { | |
| 369 | − csi2->stream_count++; | |
| 370 | − return 0; | |
| 371 | − } | |
| 360 | + remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); | |
| 361 | + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); | |
| 372 | 362 | |
| 373 | − nlanes = csi2->nlanes; | |
| 363 | + sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC, | |
| 364 | + CSI2_PAD_SINK, | |
| 365 | + &streams_mask); | |
| 374 | 366 | |
| 375 | 367 | ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV); |
| 376 | 368 | if (ret) |
| 377 | 369 | return ret; |
| 378 | 370 | |
| 379 | − ret = ipu6_isys_csi2_set_stream(sd, &timing, nlanes, enable); | |
| 371 | + ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true); | |
| 380 | 372 | if (ret) |
| 381 | 373 | return ret; |
| 382 | 374 | |
| 383 | − csi2->stream_count++; | |
| 375 | + ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index, | |
| 376 | + sink_streams); | |
| 377 | + if (ret) { | |
| 378 | + ipu6_isys_csi2_set_stream(sd, NULL, 0, false); | |
| 379 | + return ret; | |
| 380 | + } | |
| 381 | + | |
| 382 | + return 0; | |
| 383 | +} | |
| 384 | + | |
| 385 | +static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd, | |
| 386 | + struct v4l2_subdev_state *state, | |
| 387 | + u32 pad, u64 streams_mask) | |
| 388 | +{ | |
| 389 | + struct v4l2_subdev *remote_sd; | |
| 390 | + struct media_pad *remote_pad; | |
| 391 | + u64 sink_streams; | |
| 392 | + | |
| 393 | + sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC, | |
| 394 | + CSI2_PAD_SINK, | |
| 395 | + &streams_mask); | |
| 396 | + | |
| 397 | + remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); | |
| 398 | + remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); | |
| 399 | + | |
| 400 | + ipu6_isys_csi2_set_stream(sd, NULL, 0, false); | |
| 401 | + | |
| 402 | + v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams); | |
| 384 | 403 | |
| 385 | 404 | return 0; |
| 386 | 405 | } |
| @@ -475,10 +494,6 @@ static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd, · 88 unmodified lines | ||
| 475 | 494 | return ret; |
| 476 | 495 | } |
| 477 | 496 | |
| 478 | −static const struct v4l2_subdev_video_ops csi2_sd_video_ops = { | |
| 479 | − .s_stream = set_stream, | |
| 480 | −}; | |
| 481 | − | |
| 482 | 497 | static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = { |
| 483 | 498 | .get_fmt = v4l2_subdev_get_fmt, |
| 484 | 499 | .set_fmt = ipu6_isys_subdev_set_fmt, |
| @@ -486,11 +501,12 @@ static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = { · 1 unmodified line | ||
| 486 | 501 | .set_selection = ipu6_isys_csi2_set_sel, |
| 487 | 502 | .enum_mbus_code = ipu6_isys_subdev_enum_mbus_code, |
| 488 | 503 | .set_routing = ipu6_isys_subdev_set_routing, |
| 504 | + .enable_streams = ipu6_isys_csi2_enable_streams, | |
| 505 | + .disable_streams = ipu6_isys_csi2_disable_streams, | |
| 489 | 506 | }; |
| 490 | 507 | |
| 491 | 508 | static const struct v4l2_subdev_ops csi2_sd_ops = { |
| 492 | 509 | .core = &csi2_sd_core_ops, |
| 493 | − .video = &csi2_sd_video_ops, | |
| 494 | 510 | .pad = &csi2_sd_pad_ops, |
| 495 | 511 | }; |
| 496 | 512 | |
| @@ -631,33 +647,3 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream, · 134 unmodified lines | ||
| 631 | 647 | |
| 632 | 648 | return 0; |
| 633 | 649 | } |
| 634 | − | |
| 635 | −void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status) | |
| 636 | −{ | |
| 637 | − struct ipu6_isys_stream *stream = av->stream; | |
| 638 | − struct v4l2_subdev *sd = &stream->asd->sd; | |
| 639 | − struct v4l2_subdev_state *state; | |
| 640 | − struct media_pad *r_pad; | |
| 641 | − unsigned int i; | |
| 642 | − u32 r_stream; | |
| 643 | − | |
| 644 | − r_pad = media_pad_remote_pad_first(&av->pad); | |
| 645 | − r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index); | |
| 646 | − | |
| 647 | − state = v4l2_subdev_lock_and_get_active_state(sd); | |
| 648 | − | |
| 649 | − for (i = 0; i < state->stream_configs.num_configs; i++) { | |
| 650 | − struct v4l2_subdev_stream_config *cfg = | |
| 651 | − &state->stream_configs.configs[i]; | |
| 652 | − | |
| 653 | − if (cfg->pad == r_pad->index && r_stream == cfg->stream) { | |
| 654 | − dev_dbg(&av->isys->adev->auxdev.dev, | |
| 655 | − "%s: pad:%u, stream:%u, status:%u\n", | |
| 656 | − sd->entity.name, r_pad->index, r_stream, | |
| 657 | − status); | |
| 658 | − cfg->enabled = status; | |
| 659 | − } | |
| 660 | − } | |
| 661 | − | |
| 662 | − v4l2_subdev_unlock_state(state); | |
| 663 | −} | |
| @@ -45,7 +45,6 @@ struct ipu6_isys_csi2 { · 44 unmodified lines | ||
| 45 | 45 | u32 receiver_errors; |
| 46 | 46 | unsigned int nlanes; |
| 47 | 47 | unsigned int port; |
| 48 | − unsigned int stream_count; | |
| 49 | 48 | }; |
| 50 | 49 | |
| 51 | 50 | struct ipu6_isys_csi2_timing { |
| @@ -77,6 +76,5 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream, · 25 unmodified lines | ||
| 77 | 76 | struct ipu6_isys_csi2 *csi2, |
| 78 | 77 | struct media_entity *source_entity, |
| 79 | 78 | struct v4l2_mbus_frame_desc_entry *entry); |
| 80 | −void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status); | |
| 81 | 79 | |
| 82 | 80 | #endif /* IPU6_ISYS_CSI2_H */ |
| @@ -551,7 +551,6 @@ static int start_streaming(struct vb2_queue *q, unsigned int count) · 550 unmodified lines | ||
| 551 | 551 | stream->nr_queues); |
| 552 | 552 | |
| 553 | 553 | list_add(&aq->node, &stream->queues); |
| 554 | − ipu6_isys_set_csi2_streams_status(av, true); | |
| 555 | 554 | ipu6_isys_configure_stream_watermark(av, true); |
| 556 | 555 | ipu6_isys_update_stream_watermark(av, true); |
| 557 | 556 | |
| @@ -598,8 +597,6 @@ static void stop_streaming(struct vb2_queue *q) · 40 unmodified lines | ||
| 598 | 597 | struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); |
| 599 | 598 | struct ipu6_isys_stream *stream = av->stream; |
| 600 | 599 | |
| 601 | − ipu6_isys_set_csi2_streams_status(av, false); | |
| 602 | − | |
| 603 | 600 | mutex_lock(&stream->mutex); |
| 604 | 601 | |
| 605 | 602 | ipu6_isys_update_stream_watermark(av, false); |
| @@ -990,9 +990,7 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state, · 989 unmodified lines | ||
| 990 | 990 | struct v4l2_subdev_state *subdev_state; |
| 991 | 991 | struct device *dev = &av->isys->adev->auxdev.dev; |
| 992 | 992 | struct v4l2_subdev *sd; |
| 993 | − struct v4l2_subdev *ssd; | |
| 994 | 993 | struct media_pad *r_pad; |
| 995 | − struct media_pad *s_pad; | |
| 996 | 994 | u32 sink_pad, sink_stream; |
| 997 | 995 | u64 r_stream; |
| 998 | 996 | u64 stream_mask = 0; |
| @@ -1003,7 +1001,6 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state, · 4 unmodified lines | ||
| 1003 | 1001 | if (WARN(!stream->source_entity, "No source entity for stream\n")) |
| 1004 | 1002 | return -ENODEV; |
| 1005 | 1003 | |
| 1006 | − ssd = media_entity_to_v4l2_subdev(stream->source_entity); | |
| 1007 | 1004 | sd = &stream->asd->sd; |
| 1008 | 1005 | r_pad = media_pad_remote_pad_first(&av->pad); |
| 1009 | 1006 | r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index); |
| @@ -1017,27 +1014,15 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state, · 7 unmodified lines | ||
| 1017 | 1014 | if (ret) |
| 1018 | 1015 | return ret; |
| 1019 | 1016 | |
| 1020 | − s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]); | |
| 1021 | − | |
| 1022 | 1017 | stream_mask = get_stream_mask_by_pipeline(av); |
| 1023 | 1018 | if (!state) { |
| 1024 | 1019 | stop_streaming_firmware(av); |
| 1025 | 1020 | |
| 1026 | − /* stop external sub-device now. */ | |
| 1027 | − dev_dbg(dev, "disable streams 0x%llx of %s\n", stream_mask, | |
| 1028 | − ssd->name); | |
| 1029 | − ret = v4l2_subdev_disable_streams(ssd, s_pad->index, | |
| 1030 | − stream_mask); | |
| 1031 | − if (ret) { | |
| 1032 | − dev_err(dev, "disable streams of %s failed with %d\n", | |
| 1033 | − ssd->name, ret); | |
| 1034 | − return ret; | |
| 1035 | − } | |
| 1036 | − | |
| 1037 | 1021 | /* stop sub-device which connects with video */ |
| 1038 | − dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name, | |
| 1039 | − r_pad->index); | |
| 1040 | − ret = v4l2_subdev_call(sd, video, s_stream, state); | |
| 1022 | + dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n", | |
| 1023 | + sd->name, r_pad->index, stream_mask); | |
| 1024 | + ret = v4l2_subdev_disable_streams(sd, r_pad->index, | |
| 1025 | + stream_mask); | |
| 1041 | 1026 | if (ret) { |
| 1042 | 1027 | dev_err(dev, "stream off %s failed with %d\n", sd->name, |
| 1043 | 1028 | ret); |
| @@ -1052,34 +1037,20 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state, · 8 unmodified lines | ||
| 1052 | 1037 | } |
| 1053 | 1038 | |
| 1054 | 1039 | /* start sub-device which connects with video */ |
| 1055 | − dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index); | |
| 1056 | − ret = v4l2_subdev_call(sd, video, s_stream, state); | |
| 1040 | + dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name, | |
| 1041 | + r_pad->index, stream_mask); | |
| 1042 | + ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask); | |
| 1057 | 1043 | if (ret) { |
| 1058 | 1044 | dev_err(dev, "stream on %s failed with %d\n", sd->name, |
| 1059 | 1045 | ret); |
| 1060 | 1046 | goto out_media_entity_stop_streaming_firmware; |
| 1061 | 1047 | } |
| 1062 | − | |
| 1063 | − /* start external sub-device now. */ | |
| 1064 | − dev_dbg(dev, "enable streams 0x%llx of %s\n", stream_mask, | |
| 1065 | − ssd->name); | |
| 1066 | − ret = v4l2_subdev_enable_streams(ssd, s_pad->index, | |
| 1067 | − stream_mask); | |
| 1068 | − if (ret) { | |
| 1069 | − dev_err(dev, | |
| 1070 | − "enable streams 0x%llx of %s failed with %d\n", | |
| 1071 | − stream_mask, stream->source_entity->name, ret); | |
| 1072 | − goto out_media_entity_stop_streaming; | |
| 1073 | − } | |
| 1074 | 1048 | } |
| 1075 | 1049 | |
| 1076 | 1050 | av->streaming = state; |
| 1077 | 1051 | |
| 1078 | 1052 | return 0; |
| 1079 | 1053 | |
| 1080 | −out_media_entity_stop_streaming: | |
| 1081 | − v4l2_subdev_disable_streams(sd, r_pad->index, BIT(r_stream)); | |
| 1082 | − | |
| 1083 | 1054 | out_media_entity_stop_streaming_firmware: |
| 1084 | 1055 | stop_streaming_firmware(av); |
| 1085 | 1056 | |
| @@ -126,6 +126,8 @@ struct mei_csi { · 125 unmodified lines | ||
| 126 | 126 | struct v4l2_ctrl_handler ctrl_handler; |
| 127 | 127 | struct v4l2_ctrl *freq_ctrl; |
| 128 | 128 | struct v4l2_ctrl *privacy_ctrl; |
| 129 | + /* lock for v4l2 controls */ | |
| 130 | + struct mutex ctrl_lock; | |
| 129 | 131 | unsigned int remote_pad; |
| 130 | 132 | /* start streaming or not */ |
| 131 | 133 | int streaming; |
| @@ -136,9 +138,6 @@ struct mei_csi { · 4 unmodified lines | ||
| 136 | 138 | u32 nr_of_lanes; |
| 137 | 139 | /* frequency of the CSI-2 link */ |
| 138 | 140 | u64 link_freq; |
| 139 | − | |
| 140 | − /* privacy status */ | |
| 141 | − enum ivsc_privacy_status status; | |
| 142 | 141 | }; |
| 143 | 142 | |
| 144 | 143 | static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = { |
| @@ -190,7 +189,11 @@ static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len) · 45 unmodified lines | ||
| 190 | 189 | |
| 191 | 190 | /* command response status */ |
| 192 | 191 | ret = csi->cmd_response.status; |
| 193 | − if (ret) { | |
| 192 | + if (ret == -1) { | |
| 193 | + /* notify privacy on instead of reporting error */ | |
| 194 | + ret = 0; | |
| 195 | + v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1); | |
| 196 | + } else if (ret) { | |
| 194 | 197 | ret = -EINVAL; |
| 195 | 198 | goto out; |
| 196 | 199 | } |
| @@ -265,10 +268,9 @@ static void mei_csi_rx(struct mei_cl_device *cldev) · 68 unmodified lines | ||
| 265 | 268 | |
| 266 | 269 | switch (notif.cmd_id) { |
| 267 | 270 | case CSI_PRIVACY_NOTIF: |
| 268 | − if (notif.cont.cont < CSI_PRIVACY_MAX) { | |
| 269 | − csi->status = notif.cont.cont; | |
| 270 | − v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status); | |
| 271 | − } | |
| 271 | + if (notif.cont.cont < CSI_PRIVACY_MAX) | |
| 272 | + v4l2_ctrl_s_ctrl(csi->privacy_ctrl, | |
| 273 | + notif.cont.cont == CSI_PRIVACY_ON); | |
| 272 | 274 | break; |
| 273 | 275 | case CSI_SET_OWNER: |
| 274 | 276 | case CSI_SET_CONF: |
| @@ -559,11 +561,13 @@ static int mei_csi_init_controls(struct mei_csi *csi) · 284 unmodified lines | ||
| 559 | 561 | u32 max; |
| 560 | 562 | int ret; |
| 561 | 563 | |
| 564 | + mutex_init(&csi->ctrl_lock); | |
| 565 | + | |
| 562 | 566 | ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2); |
| 563 | 567 | if (ret) |
| 564 | 568 | return ret; |
| 565 | 569 | |
| 566 | − csi->ctrl_handler.lock = &csi->lock; | |
| 570 | + csi->ctrl_handler.lock = &csi->ctrl_lock; | |
| 567 | 571 | |
| 568 | 572 | max = ARRAY_SIZE(link_freq_menu_items) - 1; |
| 569 | 573 | csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler, |
| @@ -755,6 +759,7 @@ err_entity: · 185 unmodified lines | ||
| 755 | 759 | |
| 756 | 760 | err_ctrl_handler: |
| 757 | 761 | v4l2_ctrl_handler_free(&csi->ctrl_handler); |
| 762 | + mutex_destroy(&csi->ctrl_lock); | |
| 758 | 763 | v4l2_async_nf_unregister(&csi->notifier); |
| 759 | 764 | v4l2_async_nf_cleanup(&csi->notifier); |
| 760 | 765 | |
| @@ -774,6 +779,7 @@ static void mei_csi_remove(struct mei_cl_device *cldev) · 13 unmodified lines | ||
| 774 | 779 | v4l2_async_nf_unregister(&csi->notifier); |
| 775 | 780 | v4l2_async_nf_cleanup(&csi->notifier); |
| 776 | 781 | v4l2_ctrl_handler_free(&csi->ctrl_handler); |
| 782 | + mutex_destroy(&csi->ctrl_lock); | |
| 777 | 783 | v4l2_async_unregister_subdev(&csi->subdev); |
| 778 | 784 | v4l2_subdev_cleanup(&csi->subdev); |
| 779 | 785 | media_entity_cleanup(&csi->subdev.entity); |
| @@ -371,33 +371,6 @@ int ivtv_msleep_timeout(unsigned int msecs, int intr) · 370 unmodified lines | ||
| 371 | 371 | return 0; |
| 372 | 372 | } |
| 373 | 373 | |
| 374 | −/* Release ioremapped memory */ | |
| 375 | −static void ivtv_iounmap(struct ivtv *itv) | |
| 376 | −{ | |
| 377 | − if (itv == NULL) | |
| 378 | − return; | |
| 379 | − | |
| 380 | − /* Release registers memory */ | |
| 381 | − if (itv->reg_mem != NULL) { | |
| 382 | − IVTV_DEBUG_INFO("releasing reg_mem\n"); | |
| 383 | − iounmap(itv->reg_mem); | |
| 384 | − itv->reg_mem = NULL; | |
| 385 | − } | |
| 386 | − /* Release io memory */ | |
| 387 | − if (itv->has_cx23415 && itv->dec_mem != NULL) { | |
| 388 | − IVTV_DEBUG_INFO("releasing dec_mem\n"); | |
| 389 | − iounmap(itv->dec_mem); | |
| 390 | − } | |
| 391 | − itv->dec_mem = NULL; | |
| 392 | − | |
| 393 | − /* Release io memory */ | |
| 394 | − if (itv->enc_mem != NULL) { | |
| 395 | − IVTV_DEBUG_INFO("releasing enc_mem\n"); | |
| 396 | − iounmap(itv->enc_mem); | |
| 397 | − itv->enc_mem = NULL; | |
| 398 | − } | |
| 399 | −} | |
| 400 | − | |
| 401 | 374 | /* Hauppauge card? get values from tveeprom */ |
| 402 | 375 | void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) |
| 403 | 376 | { |
| @@ -833,7 +806,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, · 429 unmodified lines | ||
| 833 | 806 | |
| 834 | 807 | IVTV_DEBUG_INFO("Enabling pci device\n"); |
| 835 | 808 | |
| 836 | − if (pci_enable_device(pdev)) { | |
| 809 | + if (pcim_enable_device(pdev)) { | |
| 837 | 810 | IVTV_ERR("Can't enable device!\n"); |
| 838 | 811 | return -EIO; |
| 839 | 812 | } |
| @@ -841,24 +814,24 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, · 1 unmodified line | ||
| 841 | 814 | IVTV_ERR("No suitable DMA available.\n"); |
| 842 | 815 | return -EIO; |
| 843 | 816 | } |
| 844 | − if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) { | |
| 817 | + if (!devm_request_mem_region(&pdev->dev, itv->base_addr, | |
| 818 | + IVTV_ENCODER_SIZE, "ivtv encoder")) { | |
| 845 | 819 | IVTV_ERR("Cannot request encoder memory region.\n"); |
| 846 | 820 | return -EIO; |
| 847 | 821 | } |
| 848 | 822 | |
| 849 | − if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, | |
| 850 | − IVTV_REG_SIZE, "ivtv registers")) { | |
| 823 | + if (!devm_request_mem_region(&pdev->dev, | |
| 824 | + itv->base_addr + IVTV_REG_OFFSET, | |
| 825 | + IVTV_REG_SIZE, "ivtv registers")) { | |
| 851 | 826 | IVTV_ERR("Cannot request register memory region.\n"); |
| 852 | − release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | |
| 853 | 827 | return -EIO; |
| 854 | 828 | } |
| 855 | 829 | |
| 856 | 830 | if (itv->has_cx23415 && |
| 857 | − !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, | |
| 858 | − IVTV_DECODER_SIZE, "ivtv decoder")) { | |
| 831 | + !devm_request_mem_region(&pdev->dev, | |
| 832 | + itv->base_addr + IVTV_DECODER_OFFSET, | |
| 833 | + IVTV_DECODER_SIZE, "ivtv decoder")) { | |
| 859 | 834 | IVTV_ERR("Cannot request decoder memory region.\n"); |
| 860 | − release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | |
| 861 | − release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | |
| 862 | 835 | return -EIO; |
| 863 | 836 | } |
| 864 | 837 | |
| @@ -870,11 +843,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev, · 5 unmodified lines | ||
| 870 | 843 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); |
| 871 | 844 | if (!(cmd & PCI_COMMAND_MASTER)) { |
| 872 | 845 | IVTV_ERR("Bus Mastering is not enabled\n"); |
| 873 | − if (itv->has_cx23415) | |
| 874 | − release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, | |
| 875 | − IVTV_DECODER_SIZE); | |
| 876 | − release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | |
| 877 | − release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | |
| 878 | 846 | return -ENXIO; |
| 879 | 847 | } |
| 880 | 848 | } |
| @@ -1033,37 +1001,37 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) · 152 unmodified lines | ||
| 1033 | 1001 | |
| 1034 | 1002 | /* PCI Device Setup */ |
| 1035 | 1003 | retval = ivtv_setup_pci(itv, pdev, pci_id); |
| 1036 | − if (retval == -EIO) | |
| 1004 | + if (retval == -EIO || retval == -ENXIO) | |
| 1037 | 1005 | goto free_worker; |
| 1038 | − if (retval == -ENXIO) | |
| 1039 | − goto free_mem; | |
| 1040 | 1006 | |
| 1041 | 1007 | /* map io memory */ |
| 1042 | 1008 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", |
| 1043 | 1009 | (u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); |
| 1044 | − itv->enc_mem = ioremap(itv->base_addr + IVTV_ENCODER_OFFSET, | |
| 1045 | − IVTV_ENCODER_SIZE); | |
| 1010 | + itv->enc_mem = devm_ioremap(&pdev->dev, | |
| 1011 | + itv->base_addr + IVTV_ENCODER_OFFSET, | |
| 1012 | + IVTV_ENCODER_SIZE); | |
| 1046 | 1013 | if (!itv->enc_mem) { |
| 1047 | 1014 | IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 encoder memory\n"); |
| 1048 | 1015 | IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of vmalloc address space for this window\n"); |
| 1049 | 1016 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); |
| 1050 | 1017 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); |
| 1051 | 1018 | retval = -ENOMEM; |
| 1052 | − goto free_mem; | |
| 1019 | + goto free_worker; | |
| 1053 | 1020 | } |
| 1054 | 1021 | |
| 1055 | 1022 | if (itv->has_cx23415) { |
| 1056 | 1023 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", |
| 1057 | 1024 | (u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); |
| 1058 | − itv->dec_mem = ioremap(itv->base_addr + IVTV_DECODER_OFFSET, | |
| 1059 | − IVTV_DECODER_SIZE); | |
| 1025 | + itv->dec_mem = devm_ioremap(&pdev->dev, | |
| 1026 | + itv->base_addr + IVTV_DECODER_OFFSET, | |
| 1027 | + IVTV_DECODER_SIZE); | |
| 1060 | 1028 | if (!itv->dec_mem) { |
| 1061 | 1029 | IVTV_ERR("ioremap failed. Can't get a window into CX23415 decoder memory\n"); |
| 1062 | 1030 | IVTV_ERR("Each capture card with a CX23415 needs 8 MB of vmalloc address space for this window\n"); |
| 1063 | 1031 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); |
| 1064 | 1032 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); |
| 1065 | 1033 | retval = -ENOMEM; |
| 1066 | − goto free_mem; | |
| 1034 | + goto free_worker; | |
| 1067 | 1035 | } |
| 1068 | 1036 | } |
| 1069 | 1037 | else { |
| @@ -1073,26 +1041,27 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) · 3 unmodified lines | ||
| 1073 | 1041 | /* map registers memory */ |
| 1074 | 1042 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", |
| 1075 | 1043 | (u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); |
| 1076 | − itv->reg_mem = | |
| 1077 | − ioremap(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | |
| 1044 | + itv->reg_mem = devm_ioremap(&pdev->dev, | |
| 1045 | + itv->base_addr + IVTV_REG_OFFSET, | |
| 1046 | + IVTV_REG_SIZE); | |
| 1078 | 1047 | if (!itv->reg_mem) { |
| 1079 | 1048 | IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 register space\n"); |
| 1080 | 1049 | IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of vmalloc address space for this window\n"); |
| 1081 | 1050 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); |
| 1082 | 1051 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); |
| 1083 | 1052 | retval = -ENOMEM; |
| 1084 | − goto free_io; | |
| 1053 | + goto free_worker; | |
| 1085 | 1054 | } |
| 1086 | 1055 | |
| 1087 | 1056 | retval = ivtv_gpio_init(itv); |
| 1088 | 1057 | if (retval) |
| 1089 | − goto free_io; | |
| 1058 | + goto free_worker; | |
| 1090 | 1059 | |
| 1091 | 1060 | /* active i2c */ |
| 1092 | 1061 | IVTV_DEBUG_INFO("activating i2c...\n"); |
| 1093 | 1062 | if (init_ivtv_i2c(itv)) { |
| 1094 | 1063 | IVTV_ERR("Could not initialize i2c\n"); |
| 1095 | − goto free_io; | |
| 1064 | + goto free_worker; | |
| 1096 | 1065 | } |
| 1097 | 1066 | |
| 1098 | 1067 | if (itv->card->hw_all & IVTV_HW_TVEEPROM) { |
| @@ -1277,13 +1246,6 @@ free_irq: · 178 unmodified lines | ||
| 1277 | 1246 | free_i2c: |
| 1278 | 1247 | v4l2_ctrl_handler_free(&itv->cxhdl.hdl); |
| 1279 | 1248 | exit_ivtv_i2c(itv); |
| 1280 | −free_io: | |
| 1281 | − ivtv_iounmap(itv); | |
| 1282 | −free_mem: | |
| 1283 | − release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | |
| 1284 | − release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | |
| 1285 | − if (itv->has_cx23415) | |
| 1286 | − release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | |
| 1287 | 1249 | free_worker: |
| 1288 | 1250 | kthread_stop(itv->irq_worker_task); |
| 1289 | 1251 | err: |
| @@ -1439,14 +1401,7 @@ static void ivtv_remove(struct pci_dev *pdev) · 149 unmodified lines | ||
| 1439 | 1401 | exit_ivtv_i2c(itv); |
| 1440 | 1402 | |
| 1441 | 1403 | free_irq(itv->pdev->irq, (void *)itv); |
| 1442 | − ivtv_iounmap(itv); | |
| 1443 | − | |
| 1444 | − release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | |
| 1445 | − release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | |
| 1446 | − if (itv->has_cx23415) | |
| 1447 | − release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | |
| 1448 | 1404 | |
| 1449 | − pci_disable_device(itv->pdev); | |
| 1450 | 1405 | for (i = 0; i < IVTV_VBI_FRAMES; i++) |
| 1451 | 1406 | kfree(itv->vbi.sliced_mpeg_data[i]); |
| 1452 | 1407 | |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | ||
| 21 | 21 | #include "ivtv-ioctl.h" |
| 22 | 22 | #include "ivtv-cards.h" |
| 23 | 23 | #include "ivtv-firmware.h" |
| 24 | +#include <linux/lockdep.h> | |
| 24 | 25 | #include <media/v4l2-event.h> |
| 25 | 26 | #include <media/i2c/saa7115.h> |
| 26 | 27 | |
| @@ -190,12 +191,27 @@ static void ivtv_update_pgm_info(struct ivtv *itv) · 163 unmodified lines | ||
| 190 | 191 | itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; |
| 191 | 192 | } |
| 192 | 193 | |
| 194 | +static void ivtv_schedule(struct ivtv_stream *s) | |
| 195 | +{ | |
| 196 | + struct ivtv *itv = s->itv; | |
| 197 | + DEFINE_WAIT(wait); | |
| 198 | + | |
| 199 | + lockdep_assert_held(&itv->serialize_lock); | |
| 200 | + | |
| 201 | + mutex_unlock(&itv->serialize_lock); | |
| 202 | + prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | |
| 203 | + /* New buffers might have become free before we were added to the waitqueue */ | |
| 204 | + if (!s->q_free.buffers) | |
| 205 | + schedule(); | |
| 206 | + finish_wait(&s->waitq, &wait); | |
| 207 | + mutex_lock(&itv->serialize_lock); | |
| 208 | +} | |
| 209 | + | |
| 193 | 210 | static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) |
| 194 | 211 | { |
| 195 | 212 | struct ivtv *itv = s->itv; |
| 196 | 213 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; |
| 197 | 214 | struct ivtv_buffer *buf; |
| 198 | − DEFINE_WAIT(wait); | |
| 199 | 215 | |
| 200 | 216 | *err = 0; |
| 201 | 217 | while (1) { |
| @@ -258,13 +274,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, · 56 unmodified lines | ||
| 258 | 274 | } |
| 259 | 275 | |
| 260 | 276 | /* wait for more data to arrive */ |
| 261 | − mutex_unlock(&itv->serialize_lock); | |
| 262 | − prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | |
| 263 | − /* New buffers might have become available before we were added to the waitqueue */ | |
| 264 | − if (!s->q_full.buffers) | |
| 265 | − schedule(); | |
| 266 | − finish_wait(&s->waitq, &wait); | |
| 267 | − mutex_lock(&itv->serialize_lock); | |
| 277 | + ivtv_schedule(s); | |
| 268 | 278 | if (signal_pending(current)) { |
| 269 | 279 | /* return if a signal was received */ |
| 270 | 280 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); |
| @@ -533,6 +543,25 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed) · 262 unmodified lines | ||
| 533 | 543 | return 0; |
| 534 | 544 | } |
| 535 | 545 | |
| 546 | +static int ivtv_schedule_dma(struct ivtv_stream *s) | |
| 547 | +{ | |
| 548 | + struct ivtv *itv = s->itv; | |
| 549 | + int got_sig; | |
| 550 | + DEFINE_WAIT(wait); | |
| 551 | + | |
| 552 | + lockdep_assert_held(&itv->serialize_lock); | |
| 553 | + | |
| 554 | + mutex_unlock(&itv->serialize_lock); | |
| 555 | + prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | |
| 556 | + while (!(got_sig = signal_pending(current)) && | |
| 557 | + test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) | |
| 558 | + schedule(); | |
| 559 | + finish_wait(&itv->dma_waitq, &wait); | |
| 560 | + mutex_lock(&itv->serialize_lock); | |
| 561 | + | |
| 562 | + return got_sig; | |
| 563 | +} | |
| 564 | + | |
| 536 | 565 | static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) |
| 537 | 566 | { |
| 538 | 567 | struct ivtv_open_id *id = fh2id(filp->private_data); |
| @@ -544,7 +573,6 @@ static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t · 5 unmodified lines | ||
| 544 | 573 | int bytes_written = 0; |
| 545 | 574 | int mode; |
| 546 | 575 | int rc; |
| 547 | − DEFINE_WAIT(wait); | |
| 548 | 576 | |
| 549 | 577 | IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); |
| 550 | 578 | |
| @@ -618,13 +646,7 @@ retry: · 67 unmodified lines | ||
| 618 | 646 | break; |
| 619 | 647 | if (filp->f_flags & O_NONBLOCK) |
| 620 | 648 | return -EAGAIN; |
| 621 | − mutex_unlock(&itv->serialize_lock); | |
| 622 | − prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE); | |
| 623 | − /* New buffers might have become free before we were added to the waitqueue */ | |
| 624 | − if (!s->q_free.buffers) | |
| 625 | − schedule(); | |
| 626 | − finish_wait(&s->waitq, &wait); | |
| 627 | − mutex_lock(&itv->serialize_lock); | |
| 649 | + ivtv_schedule(s); | |
| 628 | 650 | if (signal_pending(current)) { |
| 629 | 651 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); |
| 630 | 652 | return -EINTR; |
| @@ -674,20 +696,10 @@ retry: · 43 unmodified lines | ||
| 674 | 696 | |
| 675 | 697 | if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { |
| 676 | 698 | if (s->q_full.length >= itv->dma_data_req_size) { |
| 677 | − int got_sig; | |
| 678 | − | |
| 679 | 699 | if (mode == OUT_YUV) |
| 680 | 700 | ivtv_yuv_setup_stream_frame(itv); |
| 681 | 701 | |
| 682 | − mutex_unlock(&itv->serialize_lock); | |
| 683 | − prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE); | |
| 684 | − while (!(got_sig = signal_pending(current)) && | |
| 685 | − test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) { | |
| 686 | − schedule(); | |
| 687 | − } | |
| 688 | − finish_wait(&itv->dma_waitq, &wait); | |
| 689 | − mutex_lock(&itv->serialize_lock); | |
| 690 | − if (got_sig) { | |
| 702 | + if (ivtv_schedule_dma(s)) { | |
| 691 | 703 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); |
| 692 | 704 | return -EINTR; |
| 693 | 705 | } |
| @@ -131,6 +131,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, · 130 unmodified lines | ||
| 131 | 131 | |
| 132 | 132 | /* Fill SG List with new values */ |
| 133 | 133 | if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { |
| 134 | + IVTV_DEBUG_WARN("%s: could not allocate bounce buffers for highmem userspace buffers\n", | |
| 135 | + __func__); | |
| 134 | 136 | unpin_user_pages(dma->map, dma->page_count); |
| 135 | 137 | dma->page_count = 0; |
| 136 | 138 | return -ENOMEM; |
| @@ -139,6 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, · 2 unmodified lines | ||
| 139 | 141 | /* Map SG List */ |
| 140 | 142 | dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, |
| 141 | 143 | dma->page_count, DMA_TO_DEVICE); |
| 144 | + if (!dma->SG_length) { | |
| 145 | + IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__); | |
| 146 | + unpin_user_pages(dma->map, dma->page_count); | |
| 147 | + dma->page_count = 0; | |
| 148 | + return -EINVAL; | |
| 149 | + } | |
| 142 | 150 | |
| 143 | 151 | /* Fill SG Array with new values */ |
| 144 | 152 | ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); |
| @@ -114,6 +114,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma, · 113 unmodified lines | ||
| 114 | 114 | } |
| 115 | 115 | dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, |
| 116 | 116 | dma->page_count, DMA_TO_DEVICE); |
| 117 | + if (!dma->SG_length) { | |
| 118 | + IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__); | |
| 119 | + unpin_user_pages(dma->map, dma->page_count); | |
| 120 | + dma->page_count = 0; | |
| 121 | + return -EINVAL; | |
| 122 | + } | |
| 117 | 123 | |
| 118 | 124 | /* Fill SG Array with new values */ |
| 119 | 125 | ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); |
| @@ -104,6 +104,7 @@ MODULE_PARM_DESC(osd_xres, · 103 unmodified lines | ||
| 104 | 104 | "\t\t\tdefault 640"); |
| 105 | 105 | |
| 106 | 106 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); |
| 107 | +MODULE_DESCRIPTION("Conexant cx23415 framebuffer support"); | |
| 107 | 108 | MODULE_LICENSE("GPL"); |
| 108 | 109 | |
| 109 | 110 | /* --------------------------------------------------------------------- */ |
| @@ -281,10 +282,10 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv, · 171 unmodified lines | ||
| 281 | 282 | /* Map User DMA */ |
| 282 | 283 | if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { |
| 283 | 284 | mutex_unlock(&itv->udma.lock); |
| 284 | − IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, Error with pin_user_pages: %d bytes, %d pages returned\n", | |
| 285 | − size_in_bytes, itv->udma.page_count); | |
| 285 | + IVTVFB_WARN("%s, Error in ivtv_udma_setup: %d bytes, %d pages returned\n", | |
| 286 | + __func__, size_in_bytes, itv->udma.page_count); | |
| 286 | 287 | |
| 287 | − /* pin_user_pages must have failed completely */ | |
| 288 | + /* pin_user_pages or DMA must have failed completely */ | |
| 288 | 289 | return -EIO; |
| 289 | 290 | } |
| 290 | 291 | |
| @@ -116,7 +116,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id) · 115 unmodified lines | ||
| 116 | 116 | if (stat & MANTIS_INT_RISCI) { |
| 117 | 117 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); |
| 118 | 118 | mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; |
| 119 | − tasklet_schedule(&mantis->tasklet); | |
| 119 | + queue_work(system_bh_wq, &mantis->bh_work); | |
| 120 | 120 | } |
| 121 | 121 | if (stat & MANTIS_INT_I2CDONE) { |
| 122 | 122 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); |
| @@ -125,7 +125,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id) · 124 unmodified lines | ||
| 125 | 125 | if (stat & MANTIS_INT_RISCI) { |
| 126 | 126 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); |
| 127 | 127 | mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; |
| 128 | − tasklet_schedule(&mantis->tasklet); | |
| 128 | + queue_work(system_bh_wq, &mantis->bh_work); | |
| 129 | 129 | } |
| 130 | 130 | if (stat & MANTIS_INT_I2CDONE) { |
| 131 | 131 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); |
| @@ -125,7 +125,7 @@ struct mantis_pci { · 124 unmodified lines | ||
| 125 | 125 | __le32 *risc_cpu; |
| 126 | 126 | dma_addr_t risc_dma; |
| 127 | 127 | |
| 128 | − struct tasklet_struct tasklet; | |
| 128 | + struct work_struct bh_work; | |
| 129 | 129 | spinlock_t intmask_lock; |
| 130 | 130 | |
| 131 | 131 | struct i2c_adapter adapter; |
| @@ -200,9 +200,9 @@ void mantis_dma_stop(struct mantis_pci *mantis) · 199 unmodified lines | ||
| 200 | 200 | } |
| 201 | 201 | |
| 202 | 202 | |
| 203 | −void mantis_dma_xfer(struct tasklet_struct *t) | |
| 203 | +void mantis_dma_xfer(struct work_struct *t) | |
| 204 | 204 | { |
| 205 | − struct mantis_pci *mantis = from_tasklet(mantis, t, tasklet); | |
| 205 | + struct mantis_pci *mantis = from_work(mantis, t, bh_work); | |
| 206 | 206 | struct mantis_hwconfig *config = mantis->hwconfig; |
| 207 | 207 | |
| 208 | 208 | while (mantis->last_block != mantis->busy_block) { |
| @@ -13,6 +13,6 @@ extern int mantis_dma_init(struct mantis_pci *mantis); · 12 unmodified lines | ||
| 13 | 13 | extern int mantis_dma_exit(struct mantis_pci *mantis); |
| 14 | 14 | extern void mantis_dma_start(struct mantis_pci *mantis); |
| 15 | 15 | extern void mantis_dma_stop(struct mantis_pci *mantis); |
| 16 | −extern void mantis_dma_xfer(struct tasklet_struct *t); | |
| 16 | +extern void mantis_dma_xfer(struct work_struct *t); | |
| 17 | 17 | |
| 18 | 18 | #endif /* __MANTIS_DMA_H */ |
| @@ -105,7 +105,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) · 104 unmodified lines | ||
| 105 | 105 | if (mantis->feeds == 1) { |
| 106 | 106 | dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); |
| 107 | 107 | mantis_dma_start(mantis); |
| 108 | − tasklet_enable(&mantis->tasklet); | |
| 108 | + enable_and_queue_work(system_bh_wq, &mantis->bh_work); | |
| 109 | 109 | } |
| 110 | 110 | |
| 111 | 111 | return mantis->feeds; |
| @@ -125,7 +125,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) · 13 unmodified lines | ||
| 125 | 125 | mantis->feeds--; |
| 126 | 126 | if (mantis->feeds == 0) { |
| 127 | 127 | dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); |
| 128 | − tasklet_disable(&mantis->tasklet); | |
| 128 | + disable_work_sync(&mantis->bh_work); | |
| 129 | 129 | mantis_dma_stop(mantis); |
| 130 | 130 | } |
| 131 | 131 | |
| @@ -205,8 +205,8 @@ int mantis_dvb_init(struct mantis_pci *mantis) · 73 unmodified lines | ||
| 205 | 205 | } |
| 206 | 206 | |
| 207 | 207 | dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); |
| 208 | − tasklet_setup(&mantis->tasklet, mantis_dma_xfer); | |
| 209 | − tasklet_disable(&mantis->tasklet); | |
| 208 | + INIT_WORK(&mantis->bh_work, mantis_dma_xfer); | |
| 209 | + disable_work_sync(&mantis->bh_work); | |
| 210 | 210 | if (mantis->hwconfig) { |
| 211 | 211 | result = config->frontend_init(mantis, mantis->fe); |
| 212 | 212 | if (result < 0) { |
| @@ -235,7 +235,7 @@ int mantis_dvb_init(struct mantis_pci *mantis) · 22 unmodified lines | ||
| 235 | 235 | |
| 236 | 236 | /* Error conditions .. */ |
| 237 | 237 | err5: |
| 238 | − tasklet_kill(&mantis->tasklet); | |
| 238 | + cancel_work_sync(&mantis->bh_work); | |
| 239 | 239 | dvb_net_release(&mantis->dvbnet); |
| 240 | 240 | if (mantis->fe) { |
| 241 | 241 | dvb_unregister_frontend(mantis->fe); |
| @@ -273,7 +273,7 @@ int mantis_dvb_exit(struct mantis_pci *mantis) · 31 unmodified lines | ||
| 273 | 273 | dvb_frontend_detach(mantis->fe); |
| 274 | 274 | } |
| 275 | 275 | |
| 276 | − tasklet_kill(&mantis->tasklet); | |
| 276 | + cancel_work_sync(&mantis->bh_work); | |
| 277 | 277 | dvb_net_release(&mantis->dvbnet); |
| 278 | 278 | |
| 279 | 279 | mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); |
| @@ -50,9 +50,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 49 unmodified lines | ||
| 50 | 50 | /* nGene interrupt handler **************************************************/ |
| 51 | 51 | /****************************************************************************/ |
| 52 | 52 | |
| 53 | −static void event_tasklet(struct tasklet_struct *t) | |
| 53 | +static void event_bh_work(struct work_struct *t) | |
| 54 | 54 | { |
| 55 | − struct ngene *dev = from_tasklet(dev, t, event_tasklet); | |
| 55 | + struct ngene *dev = from_work(dev, t, event_bh_work); | |
| 56 | 56 | |
| 57 | 57 | while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { |
| 58 | 58 | struct EVENT_BUFFER Event = |
| @@ -68,9 +68,9 @@ static void event_tasklet(struct tasklet_struct *t) · 9 unmodified lines | ||
| 68 | 68 | } |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | −static void demux_tasklet(struct tasklet_struct *t) | |
| 71 | +static void demux_bh_work(struct work_struct *t) | |
| 72 | 72 | { |
| 73 | − struct ngene_channel *chan = from_tasklet(chan, t, demux_tasklet); | |
| 73 | + struct ngene_channel *chan = from_work(chan, t, demux_bh_work); | |
| 74 | 74 | struct device *pdev = &chan->dev->pci_dev->dev; |
| 75 | 75 | struct SBufferHeader *Cur = chan->nextBuffer; |
| 76 | 76 | |
| @@ -204,7 +204,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id) · 127 unmodified lines | ||
| 204 | 204 | dev->EventQueueOverflowFlag = 1; |
| 205 | 205 | } |
| 206 | 206 | dev->EventBuffer->EventStatus &= ~0x80; |
| 207 | − tasklet_schedule(&dev->event_tasklet); | |
| 207 | + queue_work(system_bh_wq, &dev->event_bh_work); | |
| 208 | 208 | rc = IRQ_HANDLED; |
| 209 | 209 | } |
| 210 | 210 | |
| @@ -217,8 +217,8 @@ static irqreturn_t irq_handler(int irq, void *dev_id) · 6 unmodified lines | ||
| 217 | 217 | ngeneBuffer.SR.Flags & 0xC0) == 0x80) { |
| 218 | 218 | dev->channel[i].nextBuffer-> |
| 219 | 219 | ngeneBuffer.SR.Flags |= 0x40; |
| 220 | − tasklet_schedule( | |
| 221 | − &dev->channel[i].demux_tasklet); | |
| 220 | + queue_work(system_bh_wq, | |
| 221 | + &dev->channel[i].demux_bh_work); | |
| 222 | 222 | rc = IRQ_HANDLED; |
| 223 | 223 | } |
| 224 | 224 | } |
| @@ -1181,7 +1181,7 @@ static void ngene_init(struct ngene *dev) · 956 unmodified lines | ||
| 1181 | 1181 | struct device *pdev = &dev->pci_dev->dev; |
| 1182 | 1182 | int i; |
| 1183 | 1183 | |
| 1184 | − tasklet_setup(&dev->event_tasklet, event_tasklet); | |
| 1184 | + INIT_WORK(&dev->event_bh_work, event_bh_work); | |
| 1185 | 1185 | |
| 1186 | 1186 | memset_io(dev->iomem + 0xc000, 0x00, 0x220); |
| 1187 | 1187 | memset_io(dev->iomem + 0xc400, 0x00, 0x100); |
| @@ -1395,7 +1395,7 @@ static void release_channel(struct ngene_channel *chan) · 207 unmodified lines | ||
| 1395 | 1395 | if (chan->running) |
| 1396 | 1396 | set_transfer(chan, 0); |
| 1397 | 1397 | |
| 1398 | − tasklet_kill(&chan->demux_tasklet); | |
| 1398 | + cancel_work_sync(&chan->demux_bh_work); | |
| 1399 | 1399 | |
| 1400 | 1400 | if (chan->ci_dev) { |
| 1401 | 1401 | dvb_unregister_device(chan->ci_dev); |
| @@ -1445,7 +1445,7 @@ static int init_channel(struct ngene_channel *chan) · 43 unmodified lines | ||
| 1445 | 1445 | struct ngene_info *ni = dev->card_info; |
| 1446 | 1446 | int io = ni->io_type[nr]; |
| 1447 | 1447 | |
| 1448 | − tasklet_setup(&chan->demux_tasklet, demux_tasklet); | |
| 1448 | + INIT_WORK(&chan->demux_bh_work, demux_bh_work); | |
| 1449 | 1449 | chan->users = 0; |
| 1450 | 1450 | chan->type = io; |
| 1451 | 1451 | chan->mode = chan->type; /* for now only one mode */ |
| @@ -1649,7 +1649,7 @@ void ngene_remove(struct pci_dev *pdev) · 197 unmodified lines | ||
| 1649 | 1649 | struct ngene *dev = pci_get_drvdata(pdev); |
| 1650 | 1650 | int i; |
| 1651 | 1651 | |
| 1652 | − tasklet_kill(&dev->event_tasklet); | |
| 1652 | + cancel_work_sync(&dev->event_bh_work); | |
| 1653 | 1653 | for (i = MAX_STREAM - 1; i >= 0; i--) |
| 1654 | 1654 | release_channel(&dev->channel[i]); |
| 1655 | 1655 | if (dev->ci.en) |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <linux/scatterlist.h> |
| 17 | 17 | |
| 18 | 18 | #include <linux/dvb/frontend.h> |
| 19 | +#include <linux/workqueue.h> | |
| 19 | 20 | |
| 20 | 21 | #include <media/dmxdev.h> |
| 21 | 22 | #include <media/dvbdev.h> |
| @@ -621,7 +622,7 @@ struct ngene_channel { · 599 unmodified lines | ||
| 621 | 622 | int users; |
| 622 | 623 | struct video_device *v4l_dev; |
| 623 | 624 | struct dvb_device *ci_dev; |
| 624 | − struct tasklet_struct demux_tasklet; | |
| 625 | + struct work_struct demux_bh_work; | |
| 625 | 626 | |
| 626 | 627 | struct SBufferHeader *nextBuffer; |
| 627 | 628 | enum KSSTATE State; |
| @@ -717,7 +718,7 @@ struct ngene { · 89 unmodified lines | ||
| 717 | 718 | struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; |
| 718 | 719 | int EventQueueOverflowCount; |
| 719 | 720 | int EventQueueOverflowFlag; |
| 720 | − struct tasklet_struct event_tasklet; | |
| 721 | + struct work_struct event_bh_work; | |
| 721 | 722 | struct EVENT_BUFFER *EventBuffer; |
| 722 | 723 | int EventQueueWriteIndex; |
| 723 | 724 | int EventQueueReadIndex; |
| @@ -1254,5 +1254,6 @@ static void saa7134_alsa_exit(void) · 1253 unmodified lines | ||
| 1254 | 1254 | /* We initialize this late, to make sure the sound system is up and running */ |
| 1255 | 1255 | late_initcall(saa7134_alsa_init); |
| 1256 | 1256 | module_exit(saa7134_alsa_exit); |
| 1257 | +MODULE_DESCRIPTION("Philips SAA7134 DMA audio support"); | |
| 1257 | 1258 | MODULE_LICENSE("GPL"); |
| 1258 | 1259 | MODULE_AUTHOR("Ricardo Cerqueira"); |
| @@ -52,6 +52,7 @@ · 51 unmodified lines | ||
| 52 | 52 | #include "s5h1411.h" |
| 53 | 53 | |
| 54 | 54 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
| 55 | +MODULE_DESCRIPTION("DVB/ATSC Support for saa7134 based TV cards"); | |
| 55 | 56 | MODULE_LICENSE("GPL"); |
| 56 | 57 | |
| 57 | 58 | static unsigned int antenna_pwr; |
| @@ -466,7 +467,9 @@ static int philips_europa_tuner_sleep(struct dvb_frontend *fe) · 408 unmodified lines | ||
| 466 | 467 | /* switch the board to analog mode */ |
| 467 | 468 | if (fe->ops.i2c_gate_ctrl) |
| 468 | 469 | fe->ops.i2c_gate_ctrl(fe, 1); |
| 469 | − i2c_transfer(&dev->i2c_adap, &analog_msg, 1); | |
| 470 | + if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1) | |
| 471 | + return -EIO; | |
| 472 | + | |
| 470 | 473 | return 0; |
| 471 | 474 | } |
| 472 | 475 | |
| @@ -1018,7 +1021,9 @@ static int md8800_set_voltage2(struct dvb_frontend *fe, · 545 unmodified lines | ||
| 1018 | 1021 | else |
| 1019 | 1022 | wbuf[1] = rbuf & 0xef; |
| 1020 | 1023 | msg[0].len = 2; |
| 1021 | − i2c_transfer(&dev->i2c_adap, msg, 1); | |
| 1024 | + if (i2c_transfer(&dev->i2c_adap, msg, 1) != 1) | |
| 1025 | + return -EIO; | |
| 1026 | + | |
| 1022 | 1027 | return 0; |
| 1023 | 1028 | } |
| 1024 | 1029 | |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | /* ------------------------------------------------------------------ */ |
| 20 | 20 | |
| 21 | 21 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
| 22 | +MODULE_DESCRIPTION("Philips SAA7134 empress support"); | |
| 22 | 23 | MODULE_LICENSE("GPL"); |
| 23 | 24 | |
| 24 | 25 | static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; |
| @@ -516,4 +516,5 @@ static void __exit saa7134_go7007_mod_cleanup(void) · 515 unmodified lines | ||
| 516 | 516 | module_init(saa7134_go7007_mod_init); |
| 517 | 517 | module_exit(saa7134_go7007_mod_cleanup); |
| 518 | 518 | |
| 519 | +MODULE_DESCRIPTION("go7007 support for saa7134 based TV cards"); | |
| 519 | 520 | MODULE_LICENSE("GPL v2"); |
| @@ -279,10 +279,10 @@ static void smi_port_clearInterrupt(struct smi_port *port) · 278 unmodified lines | ||
| 279 | 279 | (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); |
| 280 | 280 | } |
| 281 | 281 | |
| 282 | −/* tasklet handler: DMA data to dmx.*/ | |
| 283 | −static void smi_dma_xfer(struct tasklet_struct *t) | |
| 282 | +/* BH work handler: DMA data to dmx.*/ | |
| 283 | +static void smi_dma_xfer(struct work_struct *t) | |
| 284 | 284 | { |
| 285 | − struct smi_port *port = from_tasklet(port, t, tasklet); | |
| 285 | + struct smi_port *port = from_work(port, t, bh_work); | |
| 286 | 286 | struct smi_dev *dev = port->dev; |
| 287 | 287 | u32 intr_status, finishedData, dmaManagement; |
| 288 | 288 | u8 dmaChan0State, dmaChan1State; |
| @@ -426,8 +426,8 @@ static int smi_port_init(struct smi_port *port, int dmaChanUsed) · 137 unmodified lines | ||
| 426 | 426 | } |
| 427 | 427 | |
| 428 | 428 | smi_port_disableInterrupt(port); |
| 429 | − tasklet_setup(&port->tasklet, smi_dma_xfer); | |
| 430 | − tasklet_disable(&port->tasklet); | |
| 429 | + INIT_WORK(&port->bh_work, smi_dma_xfer); | |
| 430 | + disable_work_sync(&port->bh_work); | |
| 431 | 431 | port->enable = 1; |
| 432 | 432 | return 0; |
| 433 | 433 | err: |
| @@ -438,7 +438,7 @@ err: · 4 unmodified lines | ||
| 438 | 438 | static void smi_port_exit(struct smi_port *port) |
| 439 | 439 | { |
| 440 | 440 | smi_port_disableInterrupt(port); |
| 441 | − tasklet_kill(&port->tasklet); | |
| 441 | + cancel_work_sync(&port->bh_work); | |
| 442 | 442 | smi_port_dma_free(port); |
| 443 | 443 | port->enable = 0; |
| 444 | 444 | } |
| @@ -452,7 +452,7 @@ static int smi_port_irq(struct smi_port *port, u32 int_status) · 7 unmodified lines | ||
| 452 | 452 | smi_port_disableInterrupt(port); |
| 453 | 453 | port->_int_status = int_status; |
| 454 | 454 | smi_port_clearInterrupt(port); |
| 455 | − tasklet_schedule(&port->tasklet); | |
| 455 | + queue_work(system_bh_wq, &port->bh_work); | |
| 456 | 456 | handled = 1; |
| 457 | 457 | } |
| 458 | 458 | return handled; |
| @@ -823,7 +823,7 @@ static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) · 364 unmodified lines | ||
| 823 | 823 | smi_port_clearInterrupt(port); |
| 824 | 824 | smi_port_enableInterrupt(port); |
| 825 | 825 | smi_write(port->DMA_MANAGEMENT, dmaManagement); |
| 826 | − tasklet_enable(&port->tasklet); | |
| 826 | + enable_and_queue_work(system_bh_wq, &port->bh_work); | |
| 827 | 827 | } |
| 828 | 828 | return port->users; |
| 829 | 829 | } |
| @@ -837,7 +837,7 @@ static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) · 7 unmodified lines | ||
| 837 | 837 | if (--port->users) |
| 838 | 838 | return port->users; |
| 839 | 839 | |
| 840 | − tasklet_disable(&port->tasklet); | |
| 840 | + disable_work_sync(&port->bh_work); | |
| 841 | 841 | smi_port_disableInterrupt(port); |
| 842 | 842 | smi_clear(port->DMA_MANAGEMENT, 0x30003); |
| 843 | 843 | return 0; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/pci.h> |
| 18 | 18 | #include <linux/dma-mapping.h> |
| 19 | 19 | #include <linux/slab.h> |
| 20 | +#include <linux/workqueue.h> | |
| 20 | 21 | #include <media/rc-core.h> |
| 21 | 22 | |
| 22 | 23 | #include <media/demux.h> |
| @@ -257,7 +258,7 @@ struct smi_port { · 234 unmodified lines | ||
| 257 | 258 | u32 _dmaInterruptCH0; |
| 258 | 259 | u32 _dmaInterruptCH1; |
| 259 | 260 | u32 _int_status; |
| 260 | − struct tasklet_struct tasklet; | |
| 261 | + struct work_struct bh_work; | |
| 261 | 262 | /* dvb */ |
| 262 | 263 | struct dmx_frontend hw_frontend; |
| 263 | 264 | struct dmx_frontend mem_frontend; |
| @@ -36,6 +36,7 @@ · 35 unmodified lines | ||
| 36 | 36 | #include <linux/interrupt.h> |
| 37 | 37 | #include <linux/input.h> |
| 38 | 38 | #include <linux/spinlock.h> |
| 39 | +#include <linux/workqueue.h> | |
| 39 | 40 | |
| 40 | 41 | #include <media/dvb_ca_en50221.h> |
| 41 | 42 | |
| @@ -54,7 +55,7 @@ struct budget_av { · 12 unmodified lines | ||
| 54 | 55 | struct video_device vd; |
| 55 | 56 | int cur_input; |
| 56 | 57 | int has_saa7113; |
| 57 | − struct tasklet_struct ciintf_irq_tasklet; | |
| 58 | + struct work_struct ciintf_irq_bh_work; | |
| 58 | 59 | int slot_status; |
| 59 | 60 | struct dvb_ca_en50221 ca; |
| 60 | 61 | u8 reinitialise_demod:1; |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include <linux/slab.h> |
| 19 | 19 | #include <linux/interrupt.h> |
| 20 | 20 | #include <linux/spinlock.h> |
| 21 | +#include <linux/workqueue.h> | |
| 21 | 22 | #include <media/rc-core.h> |
| 22 | 23 | |
| 23 | 24 | #include "budget.h" |
| @@ -81,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 57 unmodified lines | ||
| 81 | 82 | |
| 82 | 83 | struct budget_ci_ir { |
| 83 | 84 | struct rc_dev *dev; |
| 84 | − struct tasklet_struct msp430_irq_tasklet; | |
| 85 | + struct work_struct msp430_irq_bh_work; | |
| 85 | 86 | char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ |
| 86 | 87 | char phys[32]; |
| 87 | 88 | int rc5_device; |
| @@ -92,7 +93,7 @@ struct budget_ci_ir { · 4 unmodified lines | ||
| 92 | 93 | |
| 93 | 94 | struct budget_ci { |
| 94 | 95 | struct budget budget; |
| 95 | − struct tasklet_struct ciintf_irq_tasklet; | |
| 96 | + struct work_struct ciintf_irq_bh_work; | |
| 96 | 97 | int slot_status; |
| 97 | 98 | int ci_irq; |
| 98 | 99 | struct dvb_ca_en50221 ca; |
| @@ -100,9 +101,9 @@ struct budget_ci { · 1 unmodified line | ||
| 100 | 101 | u8 tuner_pll_address; /* used for philips_tdm1316l configs */ |
| 101 | 102 | }; |
| 102 | 103 | |
| 103 | −static void msp430_ir_interrupt(struct tasklet_struct *t) | |
| 104 | +static void msp430_ir_interrupt(struct work_struct *t) | |
| 104 | 105 | { |
| 105 | − struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet); | |
| 106 | + struct budget_ci_ir *ir = from_work(ir, t, msp430_irq_bh_work); | |
| 106 | 107 | struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); |
| 107 | 108 | struct rc_dev *dev = budget_ci->ir.dev; |
| 108 | 109 | u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; |
| @@ -231,7 +232,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci) · 122 unmodified lines | ||
| 231 | 232 | |
| 232 | 233 | budget_ci->ir.dev = dev; |
| 233 | 234 | |
| 234 | − tasklet_setup(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt); | |
| 235 | + INIT_WORK(&budget_ci->ir.msp430_irq_bh_work, msp430_ir_interrupt); | |
| 235 | 236 | |
| 236 | 237 | SAA7146_IER_ENABLE(saa, MASK_06); |
| 237 | 238 | saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); |
| @@ -245,7 +246,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci) · 7 unmodified lines | ||
| 245 | 246 | |
| 246 | 247 | SAA7146_IER_DISABLE(saa, MASK_06); |
| 247 | 248 | saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); |
| 248 | − tasklet_kill(&budget_ci->ir.msp430_irq_tasklet); | |
| 249 | + cancel_work_sync(&budget_ci->ir.msp430_irq_bh_work); | |
| 249 | 250 | |
| 250 | 251 | rc_unregister_device(budget_ci->ir.dev); |
| 251 | 252 | } |
| @@ -349,10 +350,10 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) · 97 unmodified lines | ||
| 349 | 350 | return 0; |
| 350 | 351 | } |
| 351 | 352 | |
| 352 | −static void ciintf_interrupt(struct tasklet_struct *t) | |
| 353 | +static void ciintf_interrupt(struct work_struct *t) | |
| 353 | 354 | { |
| 354 | − struct budget_ci *budget_ci = from_tasklet(budget_ci, t, | |
| 355 | − ciintf_irq_tasklet); | |
| 355 | + struct budget_ci *budget_ci = from_work(budget_ci, t, | |
| 356 | + ciintf_irq_bh_work); | |
| 356 | 357 | struct saa7146_dev *saa = budget_ci->budget.dev; |
| 357 | 358 | unsigned int flags; |
| 358 | 359 | |
| @@ -491,7 +492,7 @@ static int ciintf_init(struct budget_ci *budget_ci) · 132 unmodified lines | ||
| 491 | 492 | |
| 492 | 493 | // Setup CI slot IRQ |
| 493 | 494 | if (budget_ci->ci_irq) { |
| 494 | − tasklet_setup(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt); | |
| 495 | + INIT_WORK(&budget_ci->ciintf_irq_bh_work, ciintf_interrupt); | |
| 495 | 496 | if (budget_ci->slot_status != SLOTSTATUS_NONE) |
| 496 | 497 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); |
| 497 | 498 | else |
| @@ -530,7 +531,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci) · 32 unmodified lines | ||
| 530 | 531 | if (budget_ci->ci_irq) { |
| 531 | 532 | SAA7146_IER_DISABLE(saa, MASK_03); |
| 532 | 533 | saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); |
| 533 | − tasklet_kill(&budget_ci->ciintf_irq_tasklet); | |
| 534 | + cancel_work_sync(&budget_ci->ciintf_irq_bh_work); | |
| 534 | 535 | } |
| 535 | 536 | |
| 536 | 537 | // reset interface |
| @@ -556,13 +557,13 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 *isr) · 19 unmodified lines | ||
| 556 | 557 | dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); |
| 557 | 558 | |
| 558 | 559 | if (*isr & MASK_06) |
| 559 | − tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet); | |
| 560 | + queue_work(system_bh_wq, &budget_ci->ir.msp430_irq_bh_work); | |
| 560 | 561 | |
| 561 | 562 | if (*isr & MASK_10) |
| 562 | 563 | ttpci_budget_irq10_handler(dev, isr); |
| 563 | 564 | |
| 564 | 565 | if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) |
| 565 | − tasklet_schedule(&budget_ci->ciintf_irq_tasklet); | |
| 566 | + queue_work(system_bh_wq, &budget_ci->ciintf_irq_bh_work); | |
| 566 | 567 | } |
| 567 | 568 | |
| 568 | 569 | static u8 philips_su1278_tt_inittab[] = { |
| @@ -172,9 +172,9 @@ static int budget_read_fe_status(struct dvb_frontend *fe, · 171 unmodified lines | ||
| 172 | 172 | return ret; |
| 173 | 173 | } |
| 174 | 174 | |
| 175 | −static void vpeirq(struct tasklet_struct *t) | |
| 175 | +static void vpeirq(struct work_struct *t) | |
| 176 | 176 | { |
| 177 | − struct budget *budget = from_tasklet(budget, t, vpe_tasklet); | |
| 177 | + struct budget *budget = from_work(budget, t, vpe_bh_work); | |
| 178 | 178 | u8 *mem = (u8 *) (budget->grabbing); |
| 179 | 179 | u32 olddma = budget->ttbp; |
| 180 | 180 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); |
| @@ -525,7 +525,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, · 344 unmodified lines | ||
| 525 | 525 | /* upload all */ |
| 526 | 526 | saa7146_write(dev, GPIO_CTRL, 0x000000); |
| 527 | 527 | |
| 528 | − tasklet_setup(&budget->vpe_tasklet, vpeirq); | |
| 528 | + INIT_WORK(&budget->vpe_bh_work, vpeirq); | |
| 529 | 529 | |
| 530 | 530 | /* frontend power on */ |
| 531 | 531 | if (bi->type != BUDGET_FS_ACTIVY) |
| @@ -565,7 +565,7 @@ int ttpci_budget_deinit(struct budget *budget) · 33 unmodified lines | ||
| 565 | 565 | |
| 566 | 566 | budget_unregister(budget); |
| 567 | 567 | |
| 568 | − tasklet_kill(&budget->vpe_tasklet); | |
| 568 | + cancel_work_sync(&budget->vpe_bh_work); | |
| 569 | 569 | |
| 570 | 570 | saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); |
| 571 | 571 | |
| @@ -584,7 +584,7 @@ void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 *isr) · 12 unmodified lines | ||
| 584 | 584 | dprintk(8, "dev: %p, budget: %p\n", dev, budget); |
| 585 | 585 | |
| 586 | 586 | if (*isr & MASK_10) |
| 587 | − tasklet_schedule(&budget->vpe_tasklet); | |
| 587 | + queue_work(system_bh_wq, &budget->vpe_bh_work); | |
| 588 | 588 | } |
| 589 | 589 | EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); |
| 590 | 590 | |
| @@ -602,4 +602,5 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port) · 11 unmodified lines | ||
| 602 | 602 | } |
| 603 | 603 | EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); |
| 604 | 604 | |
| 605 | +MODULE_DESCRIPTION("base driver for the SAA7146 based Budget DVB cards"); | |
| 605 | 606 | MODULE_LICENSE("GPL"); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | |
| 19 | 19 | #include <linux/module.h> |
| 20 | 20 | #include <linux/mutex.h> |
| 21 | +#include <linux/workqueue.h> | |
| 21 | 22 | |
| 22 | 23 | #include <media/drv-intf/saa7146.h> |
| 23 | 24 | |
| @@ -54,8 +55,8 @@ struct budget { · 30 unmodified lines | ||
| 54 | 55 | unsigned char *grabbing; |
| 55 | 56 | struct saa7146_pgtable pt; |
| 56 | 57 | |
| 57 | − struct tasklet_struct fidb_tasklet; | |
| 58 | − struct tasklet_struct vpe_tasklet; | |
| 58 | + struct work_struct fidb_bh_work; | |
| 59 | + struct work_struct vpe_bh_work; | |
| 59 | 60 | |
| 60 | 61 | struct dmxdev dmxdev; |
| 61 | 62 | struct dvb_demux demux; |
| @@ -144,7 +144,7 @@ static void tw5864_h264_isr(struct tw5864_dev *dev) · 143 unmodified lines | ||
| 144 | 144 | cur_frame->gop_seqno = input->frame_gop_seqno; |
| 145 | 145 | |
| 146 | 146 | dev->h264_buf_w_index = next_frame_index; |
| 147 | − tasklet_schedule(&dev->tasklet); | |
| 147 | + queue_work(system_bh_wq, &dev->bh_work); | |
| 148 | 148 | |
| 149 | 149 | cur_frame = next_frame; |
| 150 | 150 | |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | */ |
| 7 | 7 | |
| 8 | 8 | #include <linux/module.h> |
| 9 | +#include <linux/workqueue.h> | |
| 9 | 10 | #include <media/v4l2-common.h> |
| 10 | 11 | #include <media/v4l2-event.h> |
| 11 | 12 | #include <media/videobuf2-dma-contig.h> |
| @@ -175,7 +176,7 @@ static const unsigned int intra4x4_lambda3[] = { · 163 unmodified lines | ||
| 175 | 176 | static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std); |
| 176 | 177 | static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std); |
| 177 | 178 | |
| 178 | −static void tw5864_handle_frame_task(struct tasklet_struct *t); | |
| 179 | +static void tw5864_handle_frame_work(struct work_struct *t); | |
| 179 | 180 | static void tw5864_handle_frame(struct tw5864_h264_frame *frame); |
| 180 | 181 | static void tw5864_frame_interval_set(struct tw5864_input *input); |
| 181 | 182 | |
| @@ -1062,7 +1063,7 @@ int tw5864_video_init(struct tw5864_dev *dev, int *video_nr) · 880 unmodified lines | ||
| 1062 | 1063 | dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER; |
| 1063 | 1064 | tw5864_irqmask_apply(dev); |
| 1064 | 1065 | |
| 1065 | − tasklet_setup(&dev->tasklet, tw5864_handle_frame_task); | |
| 1066 | + INIT_WORK(&dev->bh_work, tw5864_handle_frame_work); | |
| 1066 | 1067 | |
| 1067 | 1068 | for (i = 0; i < TW5864_INPUTS; i++) { |
| 1068 | 1069 | dev->inputs[i].root = dev; |
| @@ -1079,7 +1080,7 @@ fini_video_inputs: · 10 unmodified lines | ||
| 1079 | 1080 | for (i = last_input_nr_registered; i >= 0; i--) |
| 1080 | 1081 | tw5864_video_input_fini(&dev->inputs[i]); |
| 1081 | 1082 | |
| 1082 | − tasklet_kill(&dev->tasklet); | |
| 1083 | + cancel_work_sync(&dev->bh_work); | |
| 1083 | 1084 | |
| 1084 | 1085 | free_dma: |
| 1085 | 1086 | for (i = last_dma_allocated; i >= 0; i--) { |
| @@ -1198,7 +1199,7 @@ void tw5864_video_fini(struct tw5864_dev *dev) · 112 unmodified lines | ||
| 1198 | 1199 | { |
| 1199 | 1200 | int i; |
| 1200 | 1201 | |
| 1201 | − tasklet_kill(&dev->tasklet); | |
| 1202 | + cancel_work_sync(&dev->bh_work); | |
| 1202 | 1203 | |
| 1203 | 1204 | for (i = 0; i < TW5864_INPUTS; i++) |
| 1204 | 1205 | tw5864_video_input_fini(&dev->inputs[i]); |
| @@ -1315,9 +1316,9 @@ static int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame) · 110 unmodified lines | ||
| 1315 | 1316 | return detected; |
| 1316 | 1317 | } |
| 1317 | 1318 | |
| 1318 | −static void tw5864_handle_frame_task(struct tasklet_struct *t) | |
| 1319 | +static void tw5864_handle_frame_work(struct work_struct *t) | |
| 1319 | 1320 | { |
| 1320 | − struct tw5864_dev *dev = from_tasklet(dev, t, tasklet); | |
| 1321 | + struct tw5864_dev *dev = from_work(dev, t, bh_work); | |
| 1321 | 1322 | unsigned long flags; |
| 1322 | 1323 | int batch_size = H264_BUF_CNT; |
| 1323 | 1324 | |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | ||
| 12 | 12 | #include <linux/mutex.h> |
| 13 | 13 | #include <linux/io.h> |
| 14 | 14 | #include <linux/interrupt.h> |
| 15 | +#include <linux/workqueue.h> | |
| 15 | 16 | |
| 16 | 17 | #include <media/v4l2-common.h> |
| 17 | 18 | #include <media/v4l2-ioctl.h> |
| @@ -85,7 +86,7 @@ struct tw5864_input { · 67 unmodified lines | ||
| 85 | 86 | int nr; /* input number */ |
| 86 | 87 | struct tw5864_dev *root; |
| 87 | 88 | struct mutex lock; /* used for vidq and vdev */ |
| 88 | − spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */ | |
| 89 | + spinlock_t slock; /* used for sync between ISR, bh_work & V4L2 API */ | |
| 89 | 90 | struct video_device vdev; |
| 90 | 91 | struct v4l2_ctrl_handler hdl; |
| 91 | 92 | struct vb2_queue vidq; |
| @@ -142,7 +143,7 @@ struct tw5864_h264_frame { · 50 unmodified lines | ||
| 142 | 143 | |
| 143 | 144 | /* global device status */ |
| 144 | 145 | struct tw5864_dev { |
| 145 | − spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */ | |
| 146 | + spinlock_t slock; /* used for sync between ISR, bh_work & V4L2 API */ | |
| 146 | 147 | struct v4l2_device v4l2_dev; |
| 147 | 148 | struct tw5864_input inputs[TW5864_INPUTS]; |
| 148 | 149 | #define H264_BUF_CNT 4 |
| @@ -150,7 +151,7 @@ struct tw5864_dev { · 1 unmodified line | ||
| 150 | 151 | int h264_buf_r_index; |
| 151 | 152 | int h264_buf_w_index; |
| 152 | 153 | |
| 153 | − struct tasklet_struct tasklet; | |
| 154 | + struct work_struct bh_work; | |
| 154 | 155 | |
| 155 | 156 | int encoder_busy; |
| 156 | 157 | /* Input number to check next for ready raw picture (in RR fashion) */ |
| @@ -70,6 +70,7 @@ source "drivers/media/platform/atmel/Kconfig" · 69 unmodified lines | ||
| 70 | 70 | source "drivers/media/platform/broadcom/Kconfig" |
| 71 | 71 | source "drivers/media/platform/cadence/Kconfig" |
| 72 | 72 | source "drivers/media/platform/chips-media/Kconfig" |
| 73 | +source "drivers/media/platform/imagination/Kconfig" | |
| 73 | 74 | source "drivers/media/platform/intel/Kconfig" |
| 74 | 75 | source "drivers/media/platform/marvell/Kconfig" |
| 75 | 76 | source "drivers/media/platform/mediatek/Kconfig" |
| @@ -78,6 +79,7 @@ source "drivers/media/platform/nuvoton/Kconfig" · 2 unmodified lines | ||
| 78 | 79 | source "drivers/media/platform/nvidia/Kconfig" |
| 79 | 80 | source "drivers/media/platform/nxp/Kconfig" |
| 80 | 81 | source "drivers/media/platform/qcom/Kconfig" |
| 82 | +source "drivers/media/platform/raspberrypi/Kconfig" | |
| 81 | 83 | source "drivers/media/platform/renesas/Kconfig" |
| 82 | 84 | source "drivers/media/platform/rockchip/Kconfig" |
| 83 | 85 | source "drivers/media/platform/samsung/Kconfig" |
| @@ -13,6 +13,7 @@ obj-y += atmel/ · 12 unmodified lines | ||
| 13 | 13 | obj-y += broadcom/ |
| 14 | 14 | obj-y += cadence/ |
| 15 | 15 | obj-y += chips-media/ |
| 16 | +obj-y += imagination/ | |
| 16 | 17 | obj-y += intel/ |
| 17 | 18 | obj-y += marvell/ |
| 18 | 19 | obj-y += mediatek/ |
| @@ -21,6 +22,7 @@ obj-y += nuvoton/ · 2 unmodified lines | ||
| 21 | 22 | obj-y += nvidia/ |
| 22 | 23 | obj-y += nxp/ |
| 23 | 24 | obj-y += qcom/ |
| 25 | +obj-y += raspberrypi/ | |
| 24 | 26 | obj-y += renesas/ |
| 25 | 27 | obj-y += rockchip/ |
| 26 | 28 | obj-y += samsung/ |
| @@ -96,10 +96,11 @@ struct nal_hevc_vps { · 95 unmodified lines | ||
| 96 | 96 | unsigned int extension_data_flag; |
| 97 | 97 | }; |
| 98 | 98 | |
| 99 | +#define N_HRD_PARAMS 1 | |
| 99 | 100 | struct nal_hevc_sub_layer_hrd_parameters { |
| 100 | − unsigned int bit_rate_value_minus1[1]; | |
| 101 | − unsigned int cpb_size_value_minus1[1]; | |
| 102 | − unsigned int cbr_flag[1]; | |
| 101 | + unsigned int bit_rate_value_minus1[N_HRD_PARAMS]; | |
| 102 | + unsigned int cpb_size_value_minus1[N_HRD_PARAMS]; | |
| 103 | + unsigned int cbr_flag[N_HRD_PARAMS]; | |
| 103 | 104 | }; |
| 104 | 105 | |
| 105 | 106 | struct nal_hevc_hrd_parameters { |
| @@ -195,7 +195,6 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) · 194 unmodified lines | ||
| 195 | 195 | struct vdec_t *vdec = inst->priv; |
| 196 | 196 | int ret = 0; |
| 197 | 197 | |
| 198 | − vpu_inst_lock(inst); | |
| 199 | 198 | switch (ctrl->id) { |
| 200 | 199 | case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: |
| 201 | 200 | vdec->params.display_delay_enable = ctrl->val; |
| @@ -207,7 +206,6 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) · 5 unmodified lines | ||
| 207 | 206 | ret = -EINVAL; |
| 208 | 207 | break; |
| 209 | 208 | } |
| 210 | − vpu_inst_unlock(inst); | |
| 211 | 209 | |
| 212 | 210 | return ret; |
| 213 | 211 | } |
| @@ -518,7 +518,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) · 517 unmodified lines | ||
| 518 | 518 | struct venc_t *venc = inst->priv; |
| 519 | 519 | int ret = 0; |
| 520 | 520 | |
| 521 | − vpu_inst_lock(inst); | |
| 522 | 521 | switch (ctrl->id) { |
| 523 | 522 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: |
| 524 | 523 | venc->params.profile = ctrl->val; |
| @@ -579,7 +578,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) · 54 unmodified lines | ||
| 579 | 578 | ret = -EINVAL; |
| 580 | 579 | break; |
| 581 | 580 | } |
| 582 | − vpu_inst_unlock(inst); | |
| 583 | 581 | |
| 584 | 582 | return ret; |
| 585 | 583 | } |
| @@ -680,6 +678,9 @@ static int venc_ctrl_init(struct vpu_inst *inst) · 94 unmodified lines | ||
| 680 | 678 | ~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), |
| 681 | 679 | V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); |
| 682 | 680 | |
| 681 | + v4l2_ctrl_new_std(&inst->ctrl_handler, NULL, | |
| 682 | + V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1, 0); | |
| 683 | + | |
| 683 | 684 | if (inst->ctrl_handler.error) { |
| 684 | 685 | ret = inst->ctrl_handler.error; |
| 685 | 686 | v4l2_ctrl_handler_free(&inst->ctrl_handler); |
| @@ -819,6 +820,7 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst, · 133 unmodified lines | ||
| 819 | 820 | vbuf->field = inst->cap_format.field; |
| 820 | 821 | vbuf->flags |= frame->info.pic_type; |
| 821 | 822 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); |
| 823 | + vpu_set_buffer_average_qp(vbuf, frame->info.average_qp); | |
| 822 | 824 | dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); |
| 823 | 825 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); |
| 824 | 826 | venc->ready_count++; |
| @@ -306,6 +306,7 @@ struct vpu_vb2_buffer { · 305 unmodified lines | ||
| 306 | 306 | dma_addr_t chroma_v; |
| 307 | 307 | unsigned int state; |
| 308 | 308 | u32 tag; |
| 309 | + u32 average_qp; | |
| 309 | 310 | }; |
| 310 | 311 | |
| 311 | 312 | void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val); |
| @@ -114,6 +114,7 @@ struct vpu_enc_pic_info { · 113 unmodified lines | ||
| 114 | 114 | u32 wptr; |
| 115 | 115 | u32 crc; |
| 116 | 116 | s64 timestamp; |
| 117 | + u32 average_qp; | |
| 117 | 118 | }; |
| 118 | 119 | |
| 119 | 120 | struct vpu_dec_codec_info { |
| @@ -207,11 +207,6 @@ struct vpu_malone_dbglog_desc { · 206 unmodified lines | ||
| 207 | 207 | u32 reserved; |
| 208 | 208 | }; |
| 209 | 209 | |
| 210 | −struct vpu_malone_frame_buffer { | |
| 211 | − u32 addr; | |
| 212 | − u32 size; | |
| 213 | −}; | |
| 214 | − | |
| 215 | 210 | struct vpu_malone_udata { |
| 216 | 211 | u32 base; |
| 217 | 212 | u32 total_size; |
| @@ -63,6 +63,13 @@ unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf) · 62 unmodified lines | ||
| 63 | 63 | return vpu_buf->state; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | +void vpu_set_buffer_average_qp(struct vb2_v4l2_buffer *vbuf, u32 qp) | |
| 67 | +{ | |
| 68 | + struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 69 | + | |
| 70 | + vpu_buf->average_qp = qp; | |
| 71 | +} | |
| 72 | + | |
| 66 | 73 | void vpu_v4l2_set_error(struct vpu_inst *inst) |
| 67 | 74 | { |
| 68 | 75 | vpu_inst_lock(inst); |
| @@ -539,6 +546,15 @@ static void vpu_vb2_buf_finish(struct vb2_buffer *vb) · 470 unmodified lines | ||
| 539 | 546 | struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue); |
| 540 | 547 | struct vb2_queue *q = vb->vb2_queue; |
| 541 | 548 | |
| 549 | + if (V4L2_TYPE_IS_CAPTURE(vb->type)) { | |
| 550 | + struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf); | |
| 551 | + struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&inst->ctrl_handler, | |
| 552 | + V4L2_CID_MPEG_VIDEO_AVERAGE_QP); | |
| 553 | + | |
| 554 | + if (ctrl) | |
| 555 | + v4l2_ctrl_s_ctrl(ctrl, vpu_buf->average_qp); | |
| 556 | + } | |
| 557 | + | |
| 542 | 558 | if (vbuf->flags & V4L2_BUF_FLAG_LAST) |
| 543 | 559 | vpu_notify_eos(inst); |
| 544 | 560 | |
| @@ -12,6 +12,7 @@ void vpu_inst_lock(struct vpu_inst *inst); · 11 unmodified lines | ||
| 12 | 12 | void vpu_inst_unlock(struct vpu_inst *inst); |
| 13 | 13 | void vpu_set_buffer_state(struct vb2_v4l2_buffer *vbuf, unsigned int state); |
| 14 | 14 | unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf); |
| 15 | +void vpu_set_buffer_average_qp(struct vb2_v4l2_buffer *vbuf, u32 qp); | |
| 15 | 16 | |
| 16 | 17 | int vpu_v4l2_open(struct file *file, struct vpu_inst *inst); |
| 17 | 18 | int vpu_v4l2_close(struct file *file); |
| @@ -499,6 +499,7 @@ struct windsor_pic_info { · 498 unmodified lines | ||
| 499 | 499 | u32 proc_dacc_rng_wr_cnt; |
| 500 | 500 | s32 tv_s; |
| 501 | 501 | u32 tv_ns; |
| 502 | + u32 average_qp; | |
| 502 | 503 | }; |
| 503 | 504 | |
| 504 | 505 | u32 vpu_windsor_get_data_size(void) |
| @@ -734,6 +735,7 @@ static void vpu_windsor_unpack_pic_info(struct vpu_rpc_event *pkt, void *data) · 229 unmodified lines | ||
| 734 | 735 | info->wptr = get_ptr(windsor->str_buff_wptr); |
| 735 | 736 | info->crc = windsor->frame_crc; |
| 736 | 737 | info->timestamp = timespec64_to_ns(&ts); |
| 738 | + info->average_qp = windsor->average_qp; | |
| 737 | 739 | } |
| 738 | 740 | |
| 739 | 741 | static void vpu_windsor_unpack_mem_req(struct vpu_rpc_event *pkt, void *data) |
| @@ -29,7 +29,13 @@ void wave5_cleanup_instance(struct vpu_instance *inst) · 28 unmodified lines | ||
| 29 | 29 | { |
| 30 | 30 | int i; |
| 31 | 31 | |
| 32 | − if (list_is_singular(&inst->list)) | |
| 32 | + /* | |
| 33 | + * For Wave515 SRAM memory is allocated at | |
| 34 | + * wave5_vpu_dec_register_device() and freed at | |
| 35 | + * wave5_vpu_dec_unregister_device(). | |
| 36 | + */ | |
| 37 | + if (list_is_singular(&inst->list) && | |
| 38 | + inst->dev->product_code != WAVE515_CODE) | |
| 33 | 39 | wave5_vdi_free_sram(inst->dev); |
| 34 | 40 | |
| 35 | 41 | for (i = 0; i < inst->fbc_buf_count; i++) |
| @@ -18,18 +18,20 @@ · 17 unmodified lines | ||
| 18 | 18 | #define QUEUE_REPORT_MASK 0xffff |
| 19 | 19 | |
| 20 | 20 | /* Encoder support fields */ |
| 21 | −#define FEATURE_HEVC10BIT_ENC BIT(3) | |
| 22 | −#define FEATURE_AVC10BIT_ENC BIT(11) | |
| 23 | −#define FEATURE_AVC_ENCODER BIT(1) | |
| 24 | −#define FEATURE_HEVC_ENCODER BIT(0) | |
| 21 | +#define W521_FEATURE_HEVC10BIT_ENC BIT(3) | |
| 22 | +#define W521_FEATURE_AVC10BIT_ENC BIT(11) | |
| 23 | +#define W521_FEATURE_AVC_ENCODER BIT(1) | |
| 24 | +#define W521_FEATURE_HEVC_ENCODER BIT(0) | |
| 25 | 25 | |
| 26 | 26 | /* Decoder support fields */ |
| 27 | −#define FEATURE_AVC_DECODER BIT(3) | |
| 28 | −#define FEATURE_HEVC_DECODER BIT(2) | |
| 27 | +#define W521_FEATURE_AVC_DECODER BIT(3) | |
| 28 | +#define W521_FEATURE_HEVC_DECODER BIT(2) | |
| 29 | +#define W515_FEATURE_HEVC10BIT_DEC BIT(1) | |
| 30 | +#define W515_FEATURE_HEVC_DECODER BIT(0) | |
| 29 | 31 | |
| 30 | −#define FEATURE_BACKBONE BIT(16) | |
| 31 | −#define FEATURE_VCORE_BACKBONE BIT(22) | |
| 32 | −#define FEATURE_VCPU_BACKBONE BIT(28) | |
| 32 | +#define W521_FEATURE_BACKBONE BIT(16) | |
| 33 | +#define W521_FEATURE_VCORE_BACKBONE BIT(22) | |
| 34 | +#define W521_FEATURE_VCPU_BACKBONE BIT(28) | |
| 33 | 35 | |
| 34 | 36 | #define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) |
| 35 | 37 | #define REMAP_CTRL_REGISTER_VALUE(index) ( \ |
| @@ -155,6 +157,8 @@ static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr) · 119 unmodified lines | ||
| 155 | 157 | { |
| 156 | 158 | u32 gdi_status_check_value = 0x3f; |
| 157 | 159 | |
| 160 | + if (vpu_dev->product_code == WAVE515_CODE) | |
| 161 | + gdi_status_check_value = 0x0738; | |
| 158 | 162 | if (vpu_dev->product_code == WAVE521C_CODE || |
| 159 | 163 | vpu_dev->product_code == WAVE521_CODE || |
| 160 | 164 | vpu_dev->product_code == WAVE521E1_CODE) |
| @@ -186,6 +190,8 @@ unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev) · 25 unmodified lines | ||
| 186 | 190 | u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER); |
| 187 | 191 | |
| 188 | 192 | switch (val) { |
| 193 | + case WAVE515_CODE: | |
| 194 | + return PRODUCT_ID_515; | |
| 189 | 195 | case WAVE521C_CODE: |
| 190 | 196 | return PRODUCT_ID_521; |
| 191 | 197 | case WAVE521_CODE: |
| @@ -299,6 +305,27 @@ static int wave5_send_query(struct vpu_device *vpu_dev, struct vpu_instance *ins · 107 unmodified lines | ||
| 299 | 305 | return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL); |
| 300 | 306 | } |
| 301 | 307 | |
| 308 | +static void setup_wave5_interrupts(struct vpu_device *vpu_dev) | |
| 309 | +{ | |
| 310 | + u32 reg_val = 0; | |
| 311 | + | |
| 312 | + if (vpu_dev->attr.support_encoders) { | |
| 313 | + /* Encoder interrupt */ | |
| 314 | + reg_val |= BIT(INT_WAVE5_ENC_SET_PARAM); | |
| 315 | + reg_val |= BIT(INT_WAVE5_ENC_PIC); | |
| 316 | + reg_val |= BIT(INT_WAVE5_BSBUF_FULL); | |
| 317 | + } | |
| 318 | + | |
| 319 | + if (vpu_dev->attr.support_decoders) { | |
| 320 | + /* Decoder interrupt */ | |
| 321 | + reg_val |= BIT(INT_WAVE5_INIT_SEQ); | |
| 322 | + reg_val |= BIT(INT_WAVE5_DEC_PIC); | |
| 323 | + reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); | |
| 324 | + } | |
| 325 | + | |
| 326 | + return vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); | |
| 327 | +} | |
| 328 | + | |
| 302 | 329 | static int setup_wave5_properties(struct device *dev) |
| 303 | 330 | { |
| 304 | 331 | struct vpu_device *vpu_dev = dev_get_drvdata(dev); |
| @@ -328,17 +355,35 @@ static int setup_wave5_properties(struct device *dev) · 23 unmodified lines | ||
| 328 | 355 | hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1); |
| 329 | 356 | hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE); |
| 330 | 357 | |
| 331 | − p_attr->support_hevc10bit_enc = FIELD_GET(FEATURE_HEVC10BIT_ENC, hw_config_feature); | |
| 332 | − p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature); | |
| 333 | − | |
| 334 | − p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC; | |
| 335 | − p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC; | |
| 336 | − p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC; | |
| 337 | − p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC; | |
| 338 | − | |
| 339 | − p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0); | |
| 340 | − p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0); | |
| 341 | − p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0); | |
| 358 | + if (vpu_dev->product_code == WAVE515_CODE) { | |
| 359 | + p_attr->support_hevc10bit_dec = FIELD_GET(W515_FEATURE_HEVC10BIT_DEC, | |
| 360 | + hw_config_feature); | |
| 361 | + p_attr->support_decoders = FIELD_GET(W515_FEATURE_HEVC_DECODER, | |
| 362 | + hw_config_def1) << STD_HEVC; | |
| 363 | + } else { | |
| 364 | + p_attr->support_hevc10bit_enc = FIELD_GET(W521_FEATURE_HEVC10BIT_ENC, | |
| 365 | + hw_config_feature); | |
| 366 | + p_attr->support_avc10bit_enc = FIELD_GET(W521_FEATURE_AVC10BIT_ENC, | |
| 367 | + hw_config_feature); | |
| 368 | + | |
| 369 | + p_attr->support_decoders = FIELD_GET(W521_FEATURE_AVC_DECODER, | |
| 370 | + hw_config_def1) << STD_AVC; | |
| 371 | + p_attr->support_decoders |= FIELD_GET(W521_FEATURE_HEVC_DECODER, | |
| 372 | + hw_config_def1) << STD_HEVC; | |
| 373 | + p_attr->support_encoders = FIELD_GET(W521_FEATURE_AVC_ENCODER, | |
| 374 | + hw_config_def1) << STD_AVC; | |
| 375 | + p_attr->support_encoders |= FIELD_GET(W521_FEATURE_HEVC_ENCODER, | |
| 376 | + hw_config_def1) << STD_HEVC; | |
| 377 | + | |
| 378 | + p_attr->support_backbone = FIELD_GET(W521_FEATURE_BACKBONE, | |
| 379 | + hw_config_def0); | |
| 380 | + p_attr->support_vcpu_backbone = FIELD_GET(W521_FEATURE_VCPU_BACKBONE, | |
| 381 | + hw_config_def0); | |
| 382 | + p_attr->support_vcore_backbone = FIELD_GET(W521_FEATURE_VCORE_BACKBONE, | |
| 383 | + hw_config_def0); | |
| 384 | + } | |
| 385 | + | |
| 386 | + setup_wave5_interrupts(vpu_dev); | |
| 342 | 387 | |
| 343 | 388 | return 0; |
| 344 | 389 | } |
| @@ -380,12 +425,18 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size) · 35 unmodified lines | ||
| 380 | 425 | common_vb = &vpu_dev->common_mem; |
| 381 | 426 | |
| 382 | 427 | code_base = common_vb->daddr; |
| 428 | + | |
| 429 | + if (vpu_dev->product_code == WAVE515_CODE) | |
| 430 | + code_size = WAVE515_MAX_CODE_BUF_SIZE; | |
| 431 | + else | |
| 432 | + code_size = WAVE521_MAX_CODE_BUF_SIZE; | |
| 433 | + | |
| 383 | 434 | /* ALIGN TO 4KB */ |
| 384 | − code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); | |
| 435 | + code_size &= ~0xfff; | |
| 385 | 436 | if (code_size < size * 2) |
| 386 | 437 | return -EINVAL; |
| 387 | 438 | |
| 388 | − temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; | |
| 439 | + temp_base = code_base + code_size; | |
| 389 | 440 | temp_size = WAVE5_TEMPBUF_SIZE; |
| 390 | 441 | |
| 391 | 442 | ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size); |
| @@ -413,22 +464,15 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size) · 21 unmodified lines | ||
| 413 | 464 | |
| 414 | 465 | /* These register must be reset explicitly */ |
| 415 | 466 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); |
| 416 | − wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | |
| 417 | − wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 418 | − vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | |
| 419 | − | |
| 420 | − /* Encoder interrupt */ | |
| 421 | − reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); | |
| 422 | − reg_val |= BIT(INT_WAVE5_ENC_PIC); | |
| 423 | − reg_val |= BIT(INT_WAVE5_BSBUF_FULL); | |
| 424 | − /* Decoder interrupt */ | |
| 425 | − reg_val |= BIT(INT_WAVE5_INIT_SEQ); | |
| 426 | − reg_val |= BIT(INT_WAVE5_DEC_PIC); | |
| 427 | − reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); | |
| 428 | − vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); | |
| 467 | + | |
| 468 | + if (vpu_dev->product_code != WAVE515_CODE) { | |
| 469 | + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | |
| 470 | + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 471 | + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | |
| 472 | + } | |
| 429 | 473 | |
| 430 | 474 | reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); |
| 431 | − if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { | |
| 475 | + if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) { | |
| 432 | 476 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | |
| 433 | 477 | (WAVE5_PRP_AXI_ID << 24) | |
| 434 | 478 | (WAVE5_FBD_Y_AXI_ID << 20) | |
| @@ -440,6 +484,24 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size) · 5 unmodified lines | ||
| 440 | 484 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); |
| 441 | 485 | } |
| 442 | 486 | |
| 487 | + if (vpu_dev->product_code == WAVE515_CODE) { | |
| 488 | + dma_addr_t task_buf_base; | |
| 489 | + | |
| 490 | + vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF, WAVE515_COMMAND_QUEUE_DEPTH); | |
| 491 | + vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE, WAVE515_ONE_TASKBUF_SIZE); | |
| 492 | + | |
| 493 | + for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) { | |
| 494 | + task_buf_base = temp_base + temp_size + | |
| 495 | + (i * WAVE515_ONE_TASKBUF_SIZE); | |
| 496 | + vpu_write_reg(vpu_dev, | |
| 497 | + W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4), | |
| 498 | + task_buf_base); | |
| 499 | + } | |
| 500 | + | |
| 501 | + vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); | |
| 502 | + vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); | |
| 503 | + } | |
| 504 | + | |
| 443 | 505 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); |
| 444 | 506 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); |
| 445 | 507 | vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); |
| @@ -480,29 +542,40 @@ int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, · 34 unmodified lines | ||
| 480 | 542 | return -EINVAL; |
| 481 | 543 | } |
| 482 | 544 | |
| 483 | − p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE; | |
| 545 | + if (vpu_dev->product == PRODUCT_ID_515) | |
| 546 | + p_dec_info->vb_work.size = WAVE515DEC_WORKBUF_SIZE; | |
| 547 | + else | |
| 548 | + p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE; | |
| 549 | + | |
| 484 | 550 | ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work); |
| 485 | 551 | if (ret) |
| 486 | 552 | return ret; |
| 487 | 553 | |
| 488 | − vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1); | |
| 554 | + if (inst->dev->product_code != WAVE515_CODE) | |
| 555 | + vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1); | |
| 489 | 556 | |
| 490 | 557 | wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work); |
| 491 | 558 | |
| 492 | 559 | vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr); |
| 493 | 560 | vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size); |
| 494 | 561 | |
| 495 | − vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); | |
| 496 | − vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); | |
| 562 | + if (inst->dev->product_code != WAVE515_CODE) { | |
| 563 | + vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr); | |
| 564 | + vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); | |
| 565 | + } | |
| 497 | 566 | |
| 498 | 567 | vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr); |
| 499 | 568 | vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size); |
| 500 | 569 | |
| 501 | 570 | /* NOTE: SDMA reads MSB first */ |
| 502 | 571 | vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN); |
| 503 | − /* This register must be reset explicitly */ | |
| 504 | − vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); | |
| 505 | − vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); | |
| 572 | + | |
| 573 | + if (inst->dev->product_code != WAVE515_CODE) { | |
| 574 | + /* This register must be reset explicitly */ | |
| 575 | + vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); | |
| 576 | + vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, | |
| 577 | + WAVE521_COMMAND_QUEUE_DEPTH - 1); | |
| 578 | + } | |
| 506 | 579 | |
| 507 | 580 | ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); |
| 508 | 581 | if (ret) { |
| @@ -553,7 +626,7 @@ static u32 get_bitstream_options(struct dec_info *info) · 44 unmodified lines | ||
| 553 | 626 | int wave5_vpu_dec_init_seq(struct vpu_instance *inst) |
| 554 | 627 | { |
| 555 | 628 | struct dec_info *p_dec_info = &inst->codec_info->dec_info; |
| 556 | − u32 cmd_option = INIT_SEQ_NORMAL; | |
| 629 | + u32 bs_option, cmd_option = INIT_SEQ_NORMAL; | |
| 557 | 630 | u32 reg_val, fail_res; |
| 558 | 631 | int ret; |
| 559 | 632 | |
| @@ -563,7 +636,13 @@ int wave5_vpu_dec_init_seq(struct vpu_instance *inst) · 3 unmodified lines | ||
| 563 | 636 | vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); |
| 564 | 637 | vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); |
| 565 | 638 | |
| 566 | − vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); | |
| 639 | + bs_option = get_bitstream_options(p_dec_info); | |
| 640 | + | |
| 641 | + /* Without RD_PTR_VALID_FLAG Wave515 ignores RD_PTR value */ | |
| 642 | + if (inst->dev->product_code == WAVE515_CODE) | |
| 643 | + bs_option |= BSOPTION_RD_PTR_VALID_FLAG; | |
| 644 | + | |
| 645 | + vpu_write_reg(inst->dev, W5_BS_OPTION, bs_option); | |
| 567 | 646 | |
| 568 | 647 | vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option); |
| 569 | 648 | vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable); |
| @@ -629,10 +708,12 @@ static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initi · 59 unmodified lines | ||
| 629 | 708 | info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val); |
| 630 | 709 | } |
| 631 | 710 | |
| 632 | − info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); | |
| 633 | − info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); | |
| 634 | − p_dec_info->vlc_buf_size = info->vlc_buf_size; | |
| 635 | − p_dec_info->param_buf_size = info->param_buf_size; | |
| 711 | + if (inst->dev->product_code != WAVE515_CODE) { | |
| 712 | + info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); | |
| 713 | + info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); | |
| 714 | + p_dec_info->vlc_buf_size = info->vlc_buf_size; | |
| 715 | + p_dec_info->param_buf_size = info->param_buf_size; | |
| 716 | + } | |
| 636 | 717 | } |
| 637 | 718 | |
| 638 | 719 | int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info) |
| @@ -734,22 +815,27 @@ int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, struct frame_b · 95 unmodified lines | ||
| 734 | 815 | |
| 735 | 816 | pic_size = (init_info->pic_width << 16) | (init_info->pic_height); |
| 736 | 817 | |
| 737 | − vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) + | |
| 738 | − (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH); | |
| 739 | − vb_buf.daddr = 0; | |
| 818 | + if (inst->dev->product_code != WAVE515_CODE) { | |
| 819 | + vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) + | |
| 820 | + (p_dec_info->param_buf_size * WAVE521_COMMAND_QUEUE_DEPTH); | |
| 821 | + vb_buf.daddr = 0; | |
| 740 | 822 | |
| 741 | − if (vb_buf.size != p_dec_info->vb_task.size) { | |
| 742 | − wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); | |
| 743 | − ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf); | |
| 744 | − if (ret) | |
| 745 | − goto free_fbc_c_tbl_buffers; | |
| 823 | + if (vb_buf.size != p_dec_info->vb_task.size) { | |
| 824 | + wave5_vdi_free_dma_memory(inst->dev, | |
| 825 | + &p_dec_info->vb_task); | |
| 826 | + ret = wave5_vdi_allocate_dma_memory(inst->dev, | |
| 827 | + &vb_buf); | |
| 828 | + if (ret) | |
| 829 | + goto free_fbc_c_tbl_buffers; | |
| 746 | 830 | |
| 747 | − p_dec_info->vb_task = vb_buf; | |
| 748 | − } | |
| 831 | + p_dec_info->vb_task = vb_buf; | |
| 832 | + } | |
| 749 | 833 | |
| 750 | − vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, | |
| 751 | − p_dec_info->vb_task.daddr); | |
| 752 | − vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size); | |
| 834 | + vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, | |
| 835 | + p_dec_info->vb_task.daddr); | |
| 836 | + vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, | |
| 837 | + vb_buf.size); | |
| 838 | + } | |
| 753 | 839 | } else { |
| 754 | 840 | pic_size = (init_info->pic_width << 16) | (init_info->pic_height); |
| 755 | 841 | |
| @@ -830,6 +916,43 @@ free_mv_buffers: · 74 unmodified lines | ||
| 830 | 916 | return ret; |
| 831 | 917 | } |
| 832 | 918 | |
| 919 | +static u32 wave5_vpu_dec_validate_sec_axi(struct vpu_instance *inst) | |
| 920 | +{ | |
| 921 | + u32 bitdepth = inst->codec_info->dec_info.initial_info.luma_bitdepth; | |
| 922 | + struct dec_info *p_dec_info = &inst->codec_info->dec_info; | |
| 923 | + u32 bit_size = 0, ip_size = 0, lf_size = 0, ret = 0; | |
| 924 | + u32 sram_size = inst->dev->sram_size; | |
| 925 | + u32 width = inst->src_fmt.width; | |
| 926 | + | |
| 927 | + if (!sram_size) | |
| 928 | + return 0; | |
| 929 | + | |
| 930 | + /* | |
| 931 | + * TODO: calculate bit_size, ip_size, lf_size from width and bitdepth | |
| 932 | + * for Wave521. | |
| 933 | + */ | |
| 934 | + if (inst->dev->product_code == WAVE515_CODE) { | |
| 935 | + bit_size = DIV_ROUND_UP(width, 16) * 5 * 8; | |
| 936 | + ip_size = ALIGN(width, 16) * 2 * bitdepth / 8; | |
| 937 | + lf_size = ALIGN(width, 16) * 10 * bitdepth / 8; | |
| 938 | + } | |
| 939 | + | |
| 940 | + if (p_dec_info->sec_axi_info.use_bit_enable && sram_size >= bit_size) { | |
| 941 | + ret |= BIT(0); | |
| 942 | + sram_size -= bit_size; | |
| 943 | + } | |
| 944 | + | |
| 945 | + if (p_dec_info->sec_axi_info.use_ip_enable && sram_size >= ip_size) { | |
| 946 | + ret |= BIT(9); | |
| 947 | + sram_size -= ip_size; | |
| 948 | + } | |
| 949 | + | |
| 950 | + if (p_dec_info->sec_axi_info.use_lf_row_enable && sram_size >= lf_size) | |
| 951 | + ret |= BIT(15); | |
| 952 | + | |
| 953 | + return ret; | |
| 954 | +} | |
| 955 | + | |
| 833 | 956 | int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) |
| 834 | 957 | { |
| 835 | 958 | u32 reg_val; |
| @@ -842,9 +965,7 @@ int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) · 6 unmodified lines | ||
| 842 | 965 | vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); |
| 843 | 966 | |
| 844 | 967 | /* secondary AXI */ |
| 845 | − reg_val = p_dec_info->sec_axi_info.use_bit_enable | | |
| 846 | − (p_dec_info->sec_axi_info.use_ip_enable << 9) | | |
| 847 | − (p_dec_info->sec_axi_info.use_lf_row_enable << 15); | |
| 968 | + reg_val = wave5_vpu_dec_validate_sec_axi(inst); | |
| 848 | 969 | vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val); |
| 849 | 970 | |
| 850 | 971 | /* set attributes of user buffer */ |
| @@ -992,11 +1113,18 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) · 141 unmodified lines | ||
| 992 | 1113 | common_vb = &vpu_dev->common_mem; |
| 993 | 1114 | |
| 994 | 1115 | code_base = common_vb->daddr; |
| 1116 | + | |
| 1117 | + if (vpu_dev->product_code == WAVE515_CODE) | |
| 1118 | + code_size = WAVE515_MAX_CODE_BUF_SIZE; | |
| 1119 | + else | |
| 1120 | + code_size = WAVE521_MAX_CODE_BUF_SIZE; | |
| 1121 | + | |
| 995 | 1122 | /* ALIGN TO 4KB */ |
| 996 | − code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); | |
| 1123 | + code_size &= ~0xfff; | |
| 997 | 1124 | if (code_size < size * 2) |
| 998 | 1125 | return -EINVAL; |
| 999 | − temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; | |
| 1126 | + | |
| 1127 | + temp_base = code_base + code_size; | |
| 1000 | 1128 | temp_size = WAVE5_TEMPBUF_SIZE; |
| 1001 | 1129 | |
| 1002 | 1130 | old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR); |
| @@ -1030,22 +1158,15 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) · 27 unmodified lines | ||
| 1030 | 1158 | |
| 1031 | 1159 | /* These register must be reset explicitly */ |
| 1032 | 1160 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); |
| 1033 | − wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | |
| 1034 | − wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 1035 | − vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | |
| 1036 | 1161 | |
| 1037 | − /* Encoder interrupt */ | |
| 1038 | − reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); | |
| 1039 | − reg_val |= BIT(INT_WAVE5_ENC_PIC); | |
| 1040 | − reg_val |= BIT(INT_WAVE5_BSBUF_FULL); | |
| 1041 | − /* Decoder interrupt */ | |
| 1042 | − reg_val |= BIT(INT_WAVE5_INIT_SEQ); | |
| 1043 | − reg_val |= BIT(INT_WAVE5_DEC_PIC); | |
| 1044 | − reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); | |
| 1045 | − vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); | |
| 1162 | + if (vpu_dev->product_code != WAVE515_CODE) { | |
| 1163 | + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | |
| 1164 | + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 1165 | + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | |
| 1166 | + } | |
| 1046 | 1167 | |
| 1047 | 1168 | reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); |
| 1048 | − if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { | |
| 1169 | + if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) { | |
| 1049 | 1170 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | |
| 1050 | 1171 | (WAVE5_PRP_AXI_ID << 24) | |
| 1051 | 1172 | (WAVE5_FBD_Y_AXI_ID << 20) | |
| @@ -1057,6 +1178,29 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size) · 5 unmodified lines | ||
| 1057 | 1178 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); |
| 1058 | 1179 | } |
| 1059 | 1180 | |
| 1181 | + if (vpu_dev->product_code == WAVE515_CODE) { | |
| 1182 | + dma_addr_t task_buf_base; | |
| 1183 | + u32 i; | |
| 1184 | + | |
| 1185 | + vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF, | |
| 1186 | + WAVE515_COMMAND_QUEUE_DEPTH); | |
| 1187 | + vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE, | |
| 1188 | + WAVE515_ONE_TASKBUF_SIZE); | |
| 1189 | + | |
| 1190 | + for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) { | |
| 1191 | + task_buf_base = temp_base + temp_size + | |
| 1192 | + (i * WAVE515_ONE_TASKBUF_SIZE); | |
| 1193 | + vpu_write_reg(vpu_dev, | |
| 1194 | + W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4), | |
| 1195 | + task_buf_base); | |
| 1196 | + } | |
| 1197 | + | |
| 1198 | + vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI, | |
| 1199 | + vpu_dev->sram_buf.daddr); | |
| 1200 | + vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE, | |
| 1201 | + vpu_dev->sram_buf.size); | |
| 1202 | + } | |
| 1203 | + | |
| 1060 | 1204 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); |
| 1061 | 1205 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); |
| 1062 | 1206 | vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); |
| @@ -1080,8 +1224,8 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin · 17 unmodified lines | ||
| 1080 | 1224 | { |
| 1081 | 1225 | u32 reg_val; |
| 1082 | 1226 | struct vpu_buf *common_vb; |
| 1083 | − dma_addr_t code_base; | |
| 1084 | − u32 code_size, reason_code; | |
| 1227 | + dma_addr_t code_base, temp_base; | |
| 1228 | + u32 code_size, temp_size, reason_code; | |
| 1085 | 1229 | struct vpu_device *vpu_dev = dev_get_drvdata(dev); |
| 1086 | 1230 | int ret; |
| 1087 | 1231 | |
| @@ -1111,13 +1255,22 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin · 23 unmodified lines | ||
| 1111 | 1255 | common_vb = &vpu_dev->common_mem; |
| 1112 | 1256 | |
| 1113 | 1257 | code_base = common_vb->daddr; |
| 1258 | + | |
| 1259 | + if (vpu_dev->product_code == WAVE515_CODE) | |
| 1260 | + code_size = WAVE515_MAX_CODE_BUF_SIZE; | |
| 1261 | + else | |
| 1262 | + code_size = WAVE521_MAX_CODE_BUF_SIZE; | |
| 1263 | + | |
| 1114 | 1264 | /* ALIGN TO 4KB */ |
| 1115 | − code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); | |
| 1265 | + code_size &= ~0xfff; | |
| 1116 | 1266 | if (code_size < size * 2) { |
| 1117 | 1267 | dev_err(dev, "size too small\n"); |
| 1118 | 1268 | return -EINVAL; |
| 1119 | 1269 | } |
| 1120 | 1270 | |
| 1271 | + temp_base = code_base + code_size; | |
| 1272 | + temp_size = WAVE5_TEMPBUF_SIZE; | |
| 1273 | + | |
| 1121 | 1274 | /* Power on without DEBUG mode */ |
| 1122 | 1275 | vpu_write_reg(vpu_dev, W5_PO_CONF, 0); |
| 1123 | 1276 | |
| @@ -1130,22 +1283,17 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin · 6 unmodified lines | ||
| 1130 | 1283 | |
| 1131 | 1284 | /* These register must be reset explicitly */ |
| 1132 | 1285 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); |
| 1133 | − wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | |
| 1134 | − wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 1135 | − vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | |
| 1136 | 1286 | |
| 1137 | − /* Encoder interrupt */ | |
| 1138 | − reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); | |
| 1139 | − reg_val |= BIT(INT_WAVE5_ENC_PIC); | |
| 1140 | − reg_val |= BIT(INT_WAVE5_BSBUF_FULL); | |
| 1141 | − /* Decoder interrupt */ | |
| 1142 | − reg_val |= BIT(INT_WAVE5_INIT_SEQ); | |
| 1143 | − reg_val |= BIT(INT_WAVE5_DEC_PIC); | |
| 1144 | − reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); | |
| 1145 | − vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); | |
| 1287 | + if (vpu_dev->product_code != WAVE515_CODE) { | |
| 1288 | + wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | |
| 1289 | + wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 1290 | + vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | |
| 1291 | + } | |
| 1292 | + | |
| 1293 | + setup_wave5_interrupts(vpu_dev); | |
| 1146 | 1294 | |
| 1147 | 1295 | reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); |
| 1148 | − if (FIELD_GET(FEATURE_BACKBONE, reg_val)) { | |
| 1296 | + if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) { | |
| 1149 | 1297 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | |
| 1150 | 1298 | (WAVE5_PRP_AXI_ID << 24) | |
| 1151 | 1299 | (WAVE5_FBD_Y_AXI_ID << 20) | |
| @@ -1157,6 +1305,29 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin · 5 unmodified lines | ||
| 1157 | 1305 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); |
| 1158 | 1306 | } |
| 1159 | 1307 | |
| 1308 | + if (vpu_dev->product_code == WAVE515_CODE) { | |
| 1309 | + dma_addr_t task_buf_base; | |
| 1310 | + u32 i; | |
| 1311 | + | |
| 1312 | + vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF, | |
| 1313 | + WAVE515_COMMAND_QUEUE_DEPTH); | |
| 1314 | + vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE, | |
| 1315 | + WAVE515_ONE_TASKBUF_SIZE); | |
| 1316 | + | |
| 1317 | + for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) { | |
| 1318 | + task_buf_base = temp_base + temp_size + | |
| 1319 | + (i * WAVE515_ONE_TASKBUF_SIZE); | |
| 1320 | + vpu_write_reg(vpu_dev, | |
| 1321 | + W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4), | |
| 1322 | + task_buf_base); | |
| 1323 | + } | |
| 1324 | + | |
| 1325 | + vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI, | |
| 1326 | + vpu_dev->sram_buf.daddr); | |
| 1327 | + vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE, | |
| 1328 | + vpu_dev->sram_buf.size); | |
| 1329 | + } | |
| 1330 | + | |
| 1160 | 1331 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); |
| 1161 | 1332 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU); |
| 1162 | 1333 | /* Start VPU after settings */ |
| @@ -1401,7 +1572,7 @@ int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst, · 238 unmodified lines | ||
| 1401 | 1572 | reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN; |
| 1402 | 1573 | vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val); |
| 1403 | 1574 | vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); |
| 1404 | − vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); | |
| 1575 | + vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, WAVE521_COMMAND_QUEUE_DEPTH - 1); | |
| 1405 | 1576 | |
| 1406 | 1577 | /* This register must be reset explicitly */ |
| 1407 | 1578 | vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0); |
| @@ -1855,7 +2026,7 @@ int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance * · 447 unmodified lines | ||
| 1855 | 2026 | p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf; |
| 1856 | 2027 | |
| 1857 | 2028 | vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) + |
| 1858 | − (p_enc_info->param_buf_size * COMMAND_QUEUE_DEPTH); | |
| 2029 | + (p_enc_info->param_buf_size * WAVE521_COMMAND_QUEUE_DEPTH); | |
| 1859 | 2030 | vb_task.daddr = 0; |
| 1860 | 2031 | if (p_enc_info->vb_task.size == 0) { |
| 1861 | 2032 | ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task); |
| @@ -1943,6 +2114,31 @@ free_vb_fbc_y_tbl: · 81 unmodified lines | ||
| 1943 | 2114 | return ret; |
| 1944 | 2115 | } |
| 1945 | 2116 | |
| 2117 | +static u32 wave5_vpu_enc_validate_sec_axi(struct vpu_instance *inst) | |
| 2118 | +{ | |
| 2119 | + struct enc_info *p_enc_info = &inst->codec_info->enc_info; | |
| 2120 | + u32 rdo_size = 0, lf_size = 0, ret = 0; | |
| 2121 | + u32 sram_size = inst->dev->sram_size; | |
| 2122 | + | |
| 2123 | + if (!sram_size) | |
| 2124 | + return 0; | |
| 2125 | + | |
| 2126 | + /* | |
| 2127 | + * TODO: calculate rdo_size and lf_size from inst->src_fmt.width and | |
| 2128 | + * inst->codec_info->enc_info.open_param.wave_param.internal_bit_depth | |
| 2129 | + */ | |
| 2130 | + | |
| 2131 | + if (p_enc_info->sec_axi_info.use_enc_rdo_enable && sram_size >= rdo_size) { | |
| 2132 | + ret |= BIT(11); | |
| 2133 | + sram_size -= rdo_size; | |
| 2134 | + } | |
| 2135 | + | |
| 2136 | + if (p_enc_info->sec_axi_info.use_enc_lf_enable && sram_size >= lf_size) | |
| 2137 | + ret |= BIT(15); | |
| 2138 | + | |
| 2139 | + return ret; | |
| 2140 | +} | |
| 2141 | + | |
| 1946 | 2142 | int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res) |
| 1947 | 2143 | { |
| 1948 | 2144 | u32 src_frame_format; |
| @@ -1964,8 +2160,7 @@ int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *f · 15 unmodified lines | ||
| 1964 | 2160 | |
| 1965 | 2161 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI); |
| 1966 | 2162 | /* secondary AXI */ |
| 1967 | − reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) | | |
| 1968 | − (p_enc_info->sec_axi_info.use_enc_lf_enable << 15); | |
| 2163 | + reg_val = wave5_vpu_enc_validate_sec_axi(inst); | |
| 1969 | 2164 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val); |
| 1970 | 2165 | |
| 1971 | 2166 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0); |
| @@ -205,6 +205,9 @@ enum query_opt { · 204 unmodified lines | ||
| 205 | 205 | #define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C) |
| 206 | 206 | #define W5_TEMP_SIZE (W5_REG_BASE + 0x0120) |
| 207 | 207 | #define W5_HW_OPTION (W5_REG_BASE + 0x012C) |
| 208 | +#define W5_CMD_INIT_NUM_TASK_BUF (W5_REG_BASE + 0x0134) | |
| 209 | +#define W5_CMD_INIT_ADDR_TASK_BUF0 (W5_REG_BASE + 0x0138) | |
| 210 | +#define W5_CMD_INIT_TASK_BUF_SIZE (W5_REG_BASE + 0x0178) | |
| 208 | 211 | #define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180) |
| 209 | 212 | |
| 210 | 213 | /************************************************************************/ |
| @@ -216,7 +219,9 @@ enum query_opt { · 5 unmodified lines | ||
| 216 | 219 | #define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120) |
| 217 | 220 | #define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124) |
| 218 | 221 | #define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130) |
| 222 | +#define W515_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0124) | |
| 219 | 223 | #define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134) |
| 224 | +#define W515_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0128) | |
| 220 | 225 | #define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138) |
| 221 | 226 | #define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C) |
| 222 | 227 | #define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140) |
| @@ -18,7 +18,11 @@ static int wave5_vdi_allocate_common_memory(struct device *dev) · 17 unmodified lines | ||
| 18 | 18 | if (!vpu_dev->common_mem.vaddr) { |
| 19 | 19 | int ret; |
| 20 | 20 | |
| 21 | − vpu_dev->common_mem.size = SIZE_COMMON; | |
| 21 | + if (vpu_dev->product_code == WAVE515_CODE) | |
| 22 | + vpu_dev->common_mem.size = WAVE515_SIZE_COMMON; | |
| 23 | + else | |
| 24 | + vpu_dev->common_mem.size = WAVE521_SIZE_COMMON; | |
| 25 | + | |
| 22 | 26 | ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem); |
| 23 | 27 | if (ret) { |
| 24 | 28 | dev_err(dev, "unable to allocate common buffer\n"); |
| @@ -174,16 +178,19 @@ int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array, · 149 unmodified lines | ||
| 174 | 178 | void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev) |
| 175 | 179 | { |
| 176 | 180 | struct vpu_buf *vb = &vpu_dev->sram_buf; |
| 181 | + dma_addr_t daddr; | |
| 182 | + void *vaddr; | |
| 183 | + size_t size; | |
| 177 | 184 | |
| 178 | − if (!vpu_dev->sram_pool || !vpu_dev->sram_size) | |
| 185 | + if (!vpu_dev->sram_pool || vb->vaddr) | |
| 179 | 186 | return; |
| 180 | 187 | |
| 181 | − if (!vb->vaddr) { | |
| 182 | − vb->size = vpu_dev->sram_size; | |
| 183 | − vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size, | |
| 184 | − &vb->daddr); | |
| 185 | − if (!vb->vaddr) | |
| 186 | − vb->size = 0; | |
| 188 | + size = min_t(size_t, vpu_dev->sram_size, gen_pool_avail(vpu_dev->sram_pool)); | |
| 189 | + vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, size, &daddr); | |
| 190 | + if (vaddr) { | |
| 191 | + vb->vaddr = vaddr; | |
| 192 | + vb->daddr = daddr; | |
| 193 | + vb->size = size; | |
| 187 | 194 | } |
| 188 | 195 | |
| 189 | 196 | dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n", |
| @@ -197,9 +204,7 @@ void wave5_vdi_free_sram(struct vpu_device *vpu_dev) · 7 unmodified lines | ||
| 197 | 204 | if (!vb->size || !vb->vaddr) |
| 198 | 205 | return; |
| 199 | 206 | |
| 200 | − if (vb->vaddr) | |
| 201 | − gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, | |
| 202 | − vb->size); | |
| 207 | + gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, vb->size); | |
| 203 | 208 | |
| 204 | 209 | memset(vb, 0, sizeof(*vb)); |
| 205 | 210 | } |
| @@ -1055,6 +1055,22 @@ static int wave5_prepare_fb(struct vpu_instance *inst) · 1054 unmodified lines | ||
| 1055 | 1055 | int ret, i; |
| 1056 | 1056 | struct v4l2_m2m_buffer *buf, *n; |
| 1057 | 1057 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; |
| 1058 | + u32 bitdepth = inst->codec_info->dec_info.initial_info.luma_bitdepth; | |
| 1059 | + | |
| 1060 | + switch (bitdepth) { | |
| 1061 | + case 8: | |
| 1062 | + break; | |
| 1063 | + case 10: | |
| 1064 | + if (inst->std == W_HEVC_DEC && | |
| 1065 | + inst->dev->attr.support_hevc10bit_dec) | |
| 1066 | + break; | |
| 1067 | + | |
| 1068 | + fallthrough; | |
| 1069 | + default: | |
| 1070 | + dev_err(inst->dev->dev, "no support for %d bit depth\n", bitdepth); | |
| 1071 | + | |
| 1072 | + return -EINVAL; | |
| 1073 | + } | |
| 1058 | 1074 | |
| 1059 | 1075 | linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx); |
| 1060 | 1076 | non_linear_num = inst->fbc_buf_count; |
| @@ -1063,7 +1079,7 @@ static int wave5_prepare_fb(struct vpu_instance *inst) · 2 unmodified lines | ||
| 1063 | 1079 | struct frame_buffer *frame = &inst->frame_buf[i]; |
| 1064 | 1080 | struct vpu_buf *vframe = &inst->frame_vbuf[i]; |
| 1065 | 1081 | |
| 1066 | − fb_stride = inst->dst_fmt.width; | |
| 1082 | + fb_stride = ALIGN(inst->dst_fmt.width * bitdepth / 8, 32); | |
| 1067 | 1083 | fb_height = ALIGN(inst->dst_fmt.height, 32); |
| 1068 | 1084 | luma_size = fb_stride * fb_height; |
| 1069 | 1085 | |
| @@ -1408,22 +1424,10 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count · 338 unmodified lines | ||
| 1408 | 1424 | if (ret) |
| 1409 | 1425 | goto free_bitstream_vbuf; |
| 1410 | 1426 | } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { |
| 1411 | − struct dec_initial_info *initial_info = | |
| 1412 | − &inst->codec_info->dec_info.initial_info; | |
| 1413 | − | |
| 1414 | 1427 | if (inst->state == VPU_INST_STATE_STOP) |
| 1415 | 1428 | ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); |
| 1416 | 1429 | if (ret) |
| 1417 | 1430 | goto return_buffers; |
| 1418 | − | |
| 1419 | − if (inst->state == VPU_INST_STATE_INIT_SEQ) { | |
| 1420 | − if (initial_info->luma_bitdepth != 8) { | |
| 1421 | − dev_info(inst->dev->dev, "%s: no support for %d bit depth", | |
| 1422 | − __func__, initial_info->luma_bitdepth); | |
| 1423 | − ret = -EINVAL; | |
| 1424 | − goto return_buffers; | |
| 1425 | − } | |
| 1426 | − } | |
| 1427 | 1431 | } |
| 1428 | 1432 | |
| 1429 | 1433 | return ret; |
| @@ -1864,7 +1868,12 @@ static int wave5_vpu_open_dec(struct file *filp) · 434 unmodified lines | ||
| 1864 | 1868 | goto cleanup_inst; |
| 1865 | 1869 | } |
| 1866 | 1870 | |
| 1867 | − wave5_vdi_allocate_sram(inst->dev); | |
| 1871 | + /* | |
| 1872 | + * For Wave515 SRAM memory was already allocated | |
| 1873 | + * at wave5_vpu_dec_register_device() | |
| 1874 | + */ | |
| 1875 | + if (inst->dev->product_code != WAVE515_CODE) | |
| 1876 | + wave5_vdi_allocate_sram(inst->dev); | |
| 1868 | 1877 | |
| 1869 | 1878 | ret = mutex_lock_interruptible(&dev->dev_lock); |
| 1870 | 1879 | if (ret) |
| @@ -1904,6 +1913,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev) · 33 unmodified lines | ||
| 1904 | 1913 | struct video_device *vdev_dec; |
| 1905 | 1914 | int ret; |
| 1906 | 1915 | |
| 1916 | + /* | |
| 1917 | + * Secondary AXI setup for Wave515 is done by INIT_VPU command, | |
| 1918 | + * i.e. wave5_vpu_init(), that's why we allocate SRAM memory early. | |
| 1919 | + */ | |
| 1920 | + if (dev->product_code == WAVE515_CODE) | |
| 1921 | + wave5_vdi_allocate_sram(dev); | |
| 1922 | + | |
| 1907 | 1923 | vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL); |
| 1908 | 1924 | if (!vdev_dec) |
| 1909 | 1925 | return -ENOMEM; |
| @@ -1937,6 +1953,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev) · 27 unmodified lines | ||
| 1937 | 1953 | |
| 1938 | 1954 | void wave5_vpu_dec_unregister_device(struct vpu_device *dev) |
| 1939 | 1955 | { |
| 1956 | + /* | |
| 1957 | + * Here is a freeing pair for Wave515 SRAM memory allocation | |
| 1958 | + * happened at wave5_vpu_dec_register_device(). | |
| 1959 | + */ | |
| 1960 | + if (dev->product_code == WAVE515_CODE) | |
| 1961 | + wave5_vdi_free_sram(dev); | |
| 1962 | + | |
| 1940 | 1963 | video_unregister_device(dev->video_dev_dec); |
| 1941 | 1964 | if (dev->v4l2_m2m_dec_dev) |
| 1942 | 1965 | v4l2_m2m_release(dev->v4l2_m2m_dec_dev); |
| @@ -1247,7 +1247,7 @@ static int initialize_sequence(struct vpu_instance *inst) · 1246 unmodified lines | ||
| 1247 | 1247 | __func__, initial_info.min_frame_buffer_count, |
| 1248 | 1248 | initial_info.min_src_frame_count); |
| 1249 | 1249 | inst->min_src_buf_count = initial_info.min_src_frame_count + |
| 1250 | − COMMAND_QUEUE_DEPTH; | |
| 1250 | + WAVE521_COMMAND_QUEUE_DEPTH; | |
| 1251 | 1251 | |
| 1252 | 1252 | ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, |
| 1253 | 1253 | V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/clk.h> |
| 11 | 11 | #include <linux/firmware.h> |
| 12 | 12 | #include <linux/interrupt.h> |
| 13 | +#include <linux/reset.h> | |
| 13 | 14 | #include "wave5-vpu.h" |
| 14 | 15 | #include "wave5-regdefine.h" |
| 15 | 16 | #include "wave5-vpuconfig.h" |
| @@ -24,6 +25,7 @@ · 8 unmodified lines | ||
| 24 | 25 | struct wave5_match_data { |
| 25 | 26 | int flags; |
| 26 | 27 | const char *fw_name; |
| 28 | + u32 sram_size; | |
| 27 | 29 | }; |
| 28 | 30 | |
| 29 | 31 | static int vpu_poll_interval = 5; |
| @@ -61,7 +63,13 @@ static void wave5_vpu_handle_irq(void *dev_id) · 31 unmodified lines | ||
| 61 | 63 | |
| 62 | 64 | if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || |
| 63 | 65 | irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) { |
| 64 | − if (seq_done & BIT(inst->id)) { | |
| 66 | + if (dev->product_code == WAVE515_CODE && | |
| 67 | + (cmd_done & BIT(inst->id))) { | |
| 68 | + cmd_done &= ~BIT(inst->id); | |
| 69 | + wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST, | |
| 70 | + cmd_done); | |
| 71 | + complete(&inst->irq_done); | |
| 72 | + } else if (seq_done & BIT(inst->id)) { | |
| 65 | 73 | seq_done &= ~BIT(inst->id); |
| 66 | 74 | wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, |
| 67 | 75 | seq_done); |
| @@ -179,6 +187,16 @@ static int wave5_vpu_probe(struct platform_device *pdev) · 111 unmodified lines | ||
| 179 | 187 | dev_set_drvdata(&pdev->dev, dev); |
| 180 | 188 | dev->dev = &pdev->dev; |
| 181 | 189 | |
| 190 | + dev->resets = devm_reset_control_array_get_optional_exclusive(&pdev->dev); | |
| 191 | + if (IS_ERR(dev->resets)) { | |
| 192 | + return dev_err_probe(&pdev->dev, PTR_ERR(dev->resets), | |
| 193 | + "Failed to get reset control\n"); | |
| 194 | + } | |
| 195 | + | |
| 196 | + ret = reset_control_deassert(dev->resets); | |
| 197 | + if (ret) | |
| 198 | + return dev_err_probe(&pdev->dev, ret, "Failed to deassert resets\n"); | |
| 199 | + | |
| 182 | 200 | ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks); |
| 183 | 201 | |
| 184 | 202 | /* continue without clock, assume externally managed */ |
| @@ -191,20 +209,15 @@ static int wave5_vpu_probe(struct platform_device *pdev) · 6 unmodified lines | ||
| 191 | 209 | ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks); |
| 192 | 210 | if (ret) { |
| 193 | 211 | dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret); |
| 194 | − return ret; | |
| 195 | − } | |
| 196 | − | |
| 197 | − ret = of_property_read_u32(pdev->dev.of_node, "sram-size", | |
| 198 | − &dev->sram_size); | |
| 199 | − if (ret) { | |
| 200 | − dev_warn(&pdev->dev, "sram-size not found\n"); | |
| 201 | − dev->sram_size = 0; | |
| 212 | + goto err_reset_assert; | |
| 202 | 213 | } |
| 203 | 214 | |
| 204 | 215 | dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); |
| 205 | 216 | if (!dev->sram_pool) |
| 206 | 217 | dev_warn(&pdev->dev, "sram node not found\n"); |
| 207 | 218 | |
| 219 | + dev->sram_size = match_data->sram_size; | |
| 220 | + | |
| 208 | 221 | dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER); |
| 209 | 222 | ret = wave5_vdi_init(&pdev->dev); |
| 210 | 223 | if (ret < 0) { |
| @@ -282,6 +295,8 @@ err_vdi_release: · 71 unmodified lines | ||
| 282 | 295 | wave5_vdi_release(&pdev->dev); |
| 283 | 296 | err_clk_dis: |
| 284 | 297 | clk_bulk_disable_unprepare(dev->num_clks, dev->clks); |
| 298 | +err_reset_assert: | |
| 299 | + reset_control_assert(dev->resets); | |
| 285 | 300 | |
| 286 | 301 | return ret; |
| 287 | 302 | } |
| @@ -297,6 +312,7 @@ static void wave5_vpu_remove(struct platform_device *pdev) · 9 unmodified lines | ||
| 297 | 312 | |
| 298 | 313 | mutex_destroy(&dev->dev_lock); |
| 299 | 314 | mutex_destroy(&dev->hw_lock); |
| 315 | + reset_control_assert(dev->resets); | |
| 300 | 316 | clk_bulk_disable_unprepare(dev->num_clks, dev->clks); |
| 301 | 317 | wave5_vpu_enc_unregister_device(dev); |
| 302 | 318 | wave5_vpu_dec_unregister_device(dev); |
| @@ -308,6 +324,7 @@ static void wave5_vpu_remove(struct platform_device *pdev) · 5 unmodified lines | ||
| 308 | 324 | static const struct wave5_match_data ti_wave521c_data = { |
| 309 | 325 | .flags = WAVE5_IS_ENC | WAVE5_IS_DEC, |
| 310 | 326 | .fw_name = "cnm/wave521c_k3_codec_fw.bin", |
| 327 | + .sram_size = (64 * 1024), | |
| 311 | 328 | }; |
| 312 | 329 | |
| 313 | 330 | static const struct of_device_id wave5_dt_ids[] = { |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | ||
| 18 | 18 | #include "wave5-vdi.h" |
| 19 | 19 | |
| 20 | 20 | enum product_id { |
| 21 | + PRODUCT_ID_515, | |
| 21 | 22 | PRODUCT_ID_521, |
| 22 | 23 | PRODUCT_ID_511, |
| 23 | 24 | PRODUCT_ID_517, |
| @@ -327,6 +328,7 @@ struct vpu_attr { · 303 unmodified lines | ||
| 327 | 328 | u32 support_backbone: 1; |
| 328 | 329 | u32 support_avc10bit_enc: 1; |
| 329 | 330 | u32 support_hevc10bit_enc: 1; |
| 331 | + u32 support_hevc10bit_dec: 1; | |
| 330 | 332 | u32 support_vcore_backbone: 1; |
| 331 | 333 | u32 support_vcpu_backbone: 1; |
| 332 | 334 | }; |
| @@ -761,6 +763,7 @@ struct vpu_device { · 428 unmodified lines | ||
| 761 | 763 | struct kthread_worker *worker; |
| 762 | 764 | int vpu_poll_interval; |
| 763 | 765 | int num_clks; |
| 766 | + struct reset_control *resets; | |
| 764 | 767 | }; |
| 765 | 768 | |
| 766 | 769 | struct vpu_instance; |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #ifndef _VPU_CONFIG_H_ |
| 9 | 9 | #define _VPU_CONFIG_H_ |
| 10 | 10 | |
| 11 | +#define WAVE515_CODE 0x5150 | |
| 11 | 12 | #define WAVE517_CODE 0x5170 |
| 12 | 13 | #define WAVE537_CODE 0x5370 |
| 13 | 14 | #define WAVE511_CODE 0x5110 |
| @@ -21,12 +22,13 @@ · 7 unmodified lines | ||
| 21 | 22 | ((c) == WAVE517_CODE || (c) == WAVE537_CODE || \ |
| 22 | 23 | (c) == WAVE511_CODE || (c) == WAVE521_CODE || \ |
| 23 | 24 | (c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \ |
| 24 | − (c) == WAVE521C_DUAL_CODE); \ | |
| 25 | + (c) == WAVE521C_DUAL_CODE) || (c) == WAVE515_CODE; \ | |
| 25 | 26 | }) |
| 26 | 27 | |
| 27 | 28 | #define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024) |
| 28 | 29 | #define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K |
| 29 | 30 | #define WAVE521DEC_WORKBUF_SIZE (1784 * 1024) |
| 31 | +#define WAVE515DEC_WORKBUF_SIZE (2 * 1024 * 1024) | |
| 30 | 32 | |
| 31 | 33 | #define MAX_NUM_INSTANCE 32 |
| 32 | 34 | |
| @@ -49,17 +51,21 @@ · 16 unmodified lines | ||
| 49 | 51 | /************************************************************************/ |
| 50 | 52 | #define VLC_BUF_NUM (2) |
| 51 | 53 | |
| 52 | −#define COMMAND_QUEUE_DEPTH (2) | |
| 54 | +#define WAVE521_COMMAND_QUEUE_DEPTH (2) | |
| 55 | +#define WAVE515_COMMAND_QUEUE_DEPTH (4) | |
| 53 | 56 | |
| 54 | 57 | #define W5_REMAP_INDEX0 0 |
| 55 | 58 | #define W5_REMAP_INDEX1 1 |
| 56 | 59 | #define W5_REMAP_MAX_SIZE (1024 * 1024) |
| 57 | 60 | |
| 58 | −#define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024) | |
| 59 | −#define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE | |
| 61 | +#define WAVE521_MAX_CODE_BUF_SIZE (2 * 1024 * 1024) | |
| 62 | +#define WAVE515_MAX_CODE_BUF_SIZE (1024 * 1024) | |
| 60 | 63 | #define WAVE5_TEMPBUF_SIZE (1024 * 1024) |
| 61 | 64 | |
| 62 | −#define SIZE_COMMON (WAVE5_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE) | |
| 65 | +#define WAVE521_SIZE_COMMON (WAVE521_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE) | |
| 66 | +#define WAVE515_ONE_TASKBUF_SIZE (8 * 1024 * 1024) | |
| 67 | +#define WAVE515_SIZE_COMMON (WAVE515_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE + \ | |
| 68 | + WAVE515_COMMAND_QUEUE_DEPTH * WAVE515_ONE_TASKBUF_SIZE) | |
| 63 | 69 | |
| 64 | 70 | //=====4. VPU REPORT MEMORY ======================// |
| 65 | 71 | |
| @@ -22,6 +22,12 @@ · 21 unmodified lines | ||
| 22 | 22 | */ |
| 23 | 23 | #define BSOPTION_ENABLE_EXPLICIT_END BIT(0) |
| 24 | 24 | #define BSOPTION_HIGHLIGHT_STREAM_END BIT(1) |
| 25 | +/* | |
| 26 | + * When RD_PTR_VALID_FLAG is 0 Wave515 ignores RD_PTR value and starts to | |
| 27 | + * decode from the access unit end position of the last decoded picture in | |
| 28 | + * bitstream buffer. | |
| 29 | + */ | |
| 30 | +#define BSOPTION_RD_PTR_VALID_FLAG BIT(31) | |
| 25 | 31 | |
| 26 | 32 | /* |
| 27 | 33 | * Currently the driver only supports hardware with little endian but for source |
| @@ -0,0 +1,13 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +config VIDEO_E5010_JPEG_ENC | |
| 3 | + tristate "Imagination E5010 JPEG Encoder Driver" | |
| 4 | + depends on VIDEO_DEV | |
| 5 | + select VIDEOBUF2_DMA_CONTIG | |
| 6 | + select VIDEOBUF2_VMALLOC | |
| 7 | + select V4L2_MEM2MEM_DEV | |
| 8 | + select V4L2_JPEG_HELPER | |
| 9 | + help | |
| 10 | + This is a video4linux2 M2M driver for Imagination E5010 JPEG encoder, | |
| 11 | + which supports JPEG and MJPEG baseline encoding of YUV422 and YUV420 | |
| 12 | + semiplanar video formats, with resolution ranging from 64x64 to 8K x 8K | |
| 13 | + pixels. The module will be named as e5010_jpeg_enc. | |
| @@ -0,0 +1,3 @@ | ||
| 1 | +# SPDX-License-Identifier: GPL-2.0 | |
| 2 | +e5010_jpeg_enc-objs := e5010-jpeg-enc-hw.o e5010-jpeg-enc.o | |
| 3 | +obj-$(CONFIG_VIDEO_E5010_JPEG_ENC) += e5010_jpeg_enc.o | |
| @@ -0,0 +1,585 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Imagination E5010 JPEG Encoder driver. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ | |
| 6 | + * | |
| 7 | + * Author: David Huang <d-huang@ti.com> | |
| 8 | + * Author: Devarsh Thakkar <devarsht@ti.com> | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#ifndef _E5010_CORE_REGS_H | |
| 12 | +#define _E5010_CORE_REGS_H | |
| 13 | + | |
| 14 | +#define JASPER_CORE_ID_OFFSET (0x0000) | |
| 15 | +#define JASPER_CORE_ID_CR_GROUP_ID_MASK (0xFF000000) | |
| 16 | +#define JASPER_CORE_ID_CR_GROUP_ID_SHIFT (24) | |
| 17 | +#define JASPER_CORE_ID_CR_CORE_ID_MASK (0x00FF0000) | |
| 18 | +#define JASPER_CORE_ID_CR_CORE_ID_SHIFT (16) | |
| 19 | +#define JASPER_CORE_ID_CR_UNIQUE_NUM_MASK (0x0000FFF8) | |
| 20 | +#define JASPER_CORE_ID_CR_UNIQUE_NUM_SHIFT (3) | |
| 21 | +#define JASPER_CORE_ID_CR_PELS_PER_CYCLE_MASK (0x00000007) | |
| 22 | +#define JASPER_CORE_ID_CR_PELS_PER_CYCLE_SHIFT (0) | |
| 23 | + | |
| 24 | +#define JASPER_CORE_REV_OFFSET (0x0004) | |
| 25 | +#define JASPER_CORE_REV_CR_JASPER_DESIGNER_MASK (0xFF000000) | |
| 26 | +#define JASPER_CORE_REV_CR_JASPER_DESIGNER_SHIFT (24) | |
| 27 | +#define JASPER_CORE_REV_CR_JASPER_MAJOR_REV_MASK (0x00FF0000) | |
| 28 | +#define JASPER_CORE_REV_CR_JASPER_MAJOR_REV_SHIFT (16) | |
| 29 | +#define JASPER_CORE_REV_CR_JASPER_MINOR_REV_MASK (0x0000FF00) | |
| 30 | +#define JASPER_CORE_REV_CR_JASPER_MINOR_REV_SHIFT (8) | |
| 31 | +#define JASPER_CORE_REV_CR_JASPER_MAINT_REV_MASK (0x000000FF) | |
| 32 | +#define JASPER_CORE_REV_CR_JASPER_MAINT_REV_SHIFT (0) | |
| 33 | + | |
| 34 | +#define JASPER_INTERRUPT_MASK_OFFSET (0x0008) | |
| 35 | +#define JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_MASK (0x00000002) | |
| 36 | +#define JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_SHIFT (1) | |
| 37 | +#define JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_MASK (0x00000001) | |
| 38 | +#define JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_SHIFT (0) | |
| 39 | + | |
| 40 | +#define JASPER_INTERRUPT_STATUS_OFFSET (0x000C) | |
| 41 | +#define JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_MASK (0x00000002) | |
| 42 | +#define JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_SHIFT (1) | |
| 43 | +#define JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_MASK (0x00000001) | |
| 44 | +#define JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_SHIFT (0) | |
| 45 | + | |
| 46 | +#define JASPER_INTERRUPT_CLEAR_OFFSET (0x0010) | |
| 47 | +#define JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_MASK (0x00000002) | |
| 48 | +#define JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_SHIFT (1) | |
| 49 | +#define JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_MASK (0x00000001) | |
| 50 | +#define JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_SHIFT (0) | |
| 51 | + | |
| 52 | +#define JASPER_CLK_CONTROL_OFFSET (0x0014) | |
| 53 | +#define JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_MASK (0x00000002) | |
| 54 | +#define JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_SHIFT (1) | |
| 55 | +#define JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_MASK (0x00000001) | |
| 56 | +#define JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_SHIFT (0) | |
| 57 | + | |
| 58 | +#define JASPER_CLK_STATUS_OFFSET (0x0018) | |
| 59 | +#define JASPER_CLK_STATUS_CR_JASPER_CLKG_STATUS_MASK (0x00000001) | |
| 60 | +#define JASPER_CLK_STATUS_CR_JASPER_CLKG_STATUS_SHIFT (0) | |
| 61 | + | |
| 62 | +#define JASPER_RESET_OFFSET (0x001C) | |
| 63 | +#define JASPER_RESET_CR_SYS_RESET_MASK (0x00000002) | |
| 64 | +#define JASPER_RESET_CR_SYS_RESET_SHIFT (1) | |
| 65 | +#define JASPER_RESET_CR_CORE_RESET_MASK (0x00000001) | |
| 66 | +#define JASPER_RESET_CR_CORE_RESET_SHIFT (0) | |
| 67 | + | |
| 68 | +#define JASPER_CORE_CTRL_OFFSET (0x0020) | |
| 69 | +#define JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_MASK (0x00000001) | |
| 70 | +#define JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_SHIFT (0) | |
| 71 | + | |
| 72 | +#define JASPER_STATUS_OFFSET (0x0024) | |
| 73 | +#define JASPER_STATUS_CR_FLUSH_MODE_MASK (0x00000002) | |
| 74 | +#define JASPER_STATUS_CR_FLUSH_MODE_SHIFT (1) | |
| 75 | +#define JASPER_STATUS_CR_JASPER_BUSY_MASK (0x00000001) | |
| 76 | +#define JASPER_STATUS_CR_JASPER_BUSY_SHIFT (0) | |
| 77 | + | |
| 78 | +#define JASPER_CRC_CLEAR_OFFSET (0x0028) | |
| 79 | +#define JASPER_CRC_CLEAR_CR_FRONT_END_CRC_CLEAR_MASK (0x00000001) | |
| 80 | +#define JASPER_CRC_CLEAR_CR_FRONT_END_CRC_CLEAR_SHIFT (0) | |
| 81 | +#define JASPER_CRC_CLEAR_CR_DCT_CRC_CLEAR_MASK (0x00000002) | |
| 82 | +#define JASPER_CRC_CLEAR_CR_DCT_CRC_CLEAR_SHIFT (1) | |
| 83 | +#define JASPER_CRC_CLEAR_CR_ZZ_CRC_CLEAR_MASK (0x00000004) | |
| 84 | +#define JASPER_CRC_CLEAR_CR_ZZ_CRC_CLEAR_SHIFT (2) | |
| 85 | +#define JASPER_CRC_CLEAR_CR_QUANT_CRC_CLEAR_MASK (0x00000008) | |
| 86 | +#define JASPER_CRC_CLEAR_CR_QUANT_CRC_CLEAR_SHIFT (3) | |
| 87 | +#define JASPER_CRC_CLEAR_CR_ENTROPY_ENCODER_CRC_CLEAR_MASK (0x00000010) | |
| 88 | +#define JASPER_CRC_CLEAR_CR_ENTROPY_ENCODER_CRC_CLEAR_SHIFT (4) | |
| 89 | +#define JASPER_CRC_CLEAR_CR_PACKING_BUFFER_CRC_CLEAR_MASK (0x00000020) | |
| 90 | +#define JASPER_CRC_CLEAR_CR_PACKING_BUFFER_CRC_CLEAR_SHIFT (5) | |
| 91 | + | |
| 92 | +#define JASPER_INPUT_CTRL0_OFFSET (0x002C) | |
| 93 | +#define JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_MASK (0x01000000) | |
| 94 | +#define JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_SHIFT (24) | |
| 95 | +#define JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_MASK (0x00030000) | |
| 96 | +#define JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_SHIFT (16) | |
| 97 | +#define JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_MASK (0x00000004) | |
| 98 | +#define JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_SHIFT (2) | |
| 99 | + | |
| 100 | +#define JASPER_INPUT_CTRL1_OFFSET (0x0030) | |
| 101 | +#define JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_MASK (0x1FC00000) | |
| 102 | +#define JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_SHIFT (22) | |
| 103 | +#define JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_MASK (0x00001FC0) | |
| 104 | +#define JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_SHIFT (6) | |
| 105 | + | |
| 106 | +#define JASPER_MMU_CTRL_OFFSET (0x0034) | |
| 107 | +#define JASPER_MMU_CTRL_CR_JASPER_TILING_SCHEME_MASK (0x00000002) | |
| 108 | +#define JASPER_MMU_CTRL_CR_JASPER_TILING_SCHEME_SHIFT (1) | |
| 109 | +#define JASPER_MMU_CTRL_CR_JASPER_TILING_ENABLE_MASK (0x00000001) | |
| 110 | +#define JASPER_MMU_CTRL_CR_JASPER_TILING_ENABLE_SHIFT (0) | |
| 111 | + | |
| 112 | +#define JASPER_IMAGE_SIZE_OFFSET (0x0038) | |
| 113 | +#define JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_MASK (0x1FFF0000) | |
| 114 | +#define JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_SHIFT (16) | |
| 115 | +#define JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_MASK (0x00001FFF) | |
| 116 | +#define JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_SHIFT (0) | |
| 117 | + | |
| 118 | +#define INPUT_LUMA_BASE_OFFSET (0x003C) | |
| 119 | +#define INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_MASK (0xFFFFFFC0) | |
| 120 | +#define INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_SHIFT (6) | |
| 121 | + | |
| 122 | +#define INPUT_CHROMA_BASE_OFFSET (0x0040) | |
| 123 | +#define INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_MASK (0xFFFFFFC0) | |
| 124 | +#define INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_SHIFT (6) | |
| 125 | + | |
| 126 | +#define JASPER_OUTPUT_BASE_OFFSET (0x0044) | |
| 127 | +#define JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_MASK (0xFFFFFFFF) | |
| 128 | +#define JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_SHIFT (0) | |
| 129 | + | |
| 130 | +#define JASPER_OUTPUT_SIZE_OFFSET (0x0048) | |
| 131 | +#define JASPER_OUTPUT_SIZE_CR_OUTPUT_SIZE_MASK (0xFFFFFFFF) | |
| 132 | +#define JASPER_OUTPUT_SIZE_CR_OUTPUT_SIZE_SHIFT (0) | |
| 133 | +#define JASPER_OUTPUT_MAX_SIZE_OFFSET (0x004C) | |
| 134 | +#define JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_MASK (0xFFFFFFFF) | |
| 135 | +#define JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_SHIFT (0) | |
| 136 | + | |
| 137 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET (0x0050) | |
| 138 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_03_MASK (0xFF000000) | |
| 139 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_03_SHIFT (24) | |
| 140 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_02_MASK (0x00FF0000) | |
| 141 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_02_SHIFT (16) | |
| 142 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_01_MASK (0x0000FF00) | |
| 143 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_01_SHIFT (8) | |
| 144 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_00_MASK (0x000000FF) | |
| 145 | +#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_00_SHIFT (0) | |
| 146 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_OFFSET (0x0054) | |
| 147 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_07_MASK (0xFF000000) | |
| 148 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_07_SHIFT (24) | |
| 149 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_06_MASK (0x00FF0000) | |
| 150 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_06_SHIFT (16) | |
| 151 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_05_MASK (0x0000FF00) | |
| 152 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_05_SHIFT (8) | |
| 153 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_04_MASK (0x000000FF) | |
| 154 | +#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_04_SHIFT (0) | |
| 155 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_OFFSET (0x0058) | |
| 156 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_13_MASK (0xFF000000) | |
| 157 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_13_SHIFT (24) | |
| 158 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_12_MASK (0x00FF0000) | |
| 159 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_12_SHIFT (16) | |
| 160 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_11_MASK (0x0000FF00) | |
| 161 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_11_SHIFT (8) | |
| 162 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_10_MASK (0x000000FF) | |
| 163 | +#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_10_SHIFT (0) | |
| 164 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_OFFSET (0x005C) | |
| 165 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_17_MASK (0xFF000000) | |
| 166 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_17_SHIFT (24) | |
| 167 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_16_MASK (0x00FF0000) | |
| 168 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_16_SHIFT (16) | |
| 169 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_15_MASK (0x0000FF00) | |
| 170 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_15_SHIFT (8) | |
| 171 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_14_MASK (0x000000FF) | |
| 172 | +#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_14_SHIFT (0) | |
| 173 | +#define JASPER_LUMA_QUANTIZATION_TABLE4_OFFSET (0x0060) | |
| 174 | +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_21_MASK (0x0000FF00) | |
| 175 | +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_21_SHIFT (8) | |
| 176 | +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_20_MASK (0x000000FF) | |
| 177 | +#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_20_SHIFT (0) | |
| 178 | + | |
| 179 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_OFFSET (0x0064) | |
| 180 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_27_MASK (0xFF000000) | |
| 181 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_27_SHIFT (24) | |
| 182 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_26_MASK (0x00FF0000) | |
| 183 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_26_SHIFT (16) | |
| 184 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_25_MASK (0x0000FF00) | |
| 185 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_25_SHIFT (8) | |
| 186 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_24_MASK (0x000000FF) | |
| 187 | +#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_24_SHIFT (0) | |
| 188 | + | |
| 189 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_OFFSET (0x0068) | |
| 190 | + | |
| 191 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_33_MASK (0xFF000000) | |
| 192 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_33_SHIFT (24) | |
| 193 | + | |
| 194 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_32_MASK (0x00FF0000) | |
| 195 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_32_SHIFT (16) | |
| 196 | + | |
| 197 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_31_MASK (0x0000FF00) | |
| 198 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_31_SHIFT (8) | |
| 199 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_30_MASK (0x000000FF) | |
| 200 | +#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_30_SHIFT (0) | |
| 201 | + | |
| 202 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_OFFSET (0x006C) | |
| 203 | + | |
| 204 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_37_MASK (0xFF000000) | |
| 205 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_37_SHIFT (24) | |
| 206 | + | |
| 207 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_36_MASK (0x00FF0000) | |
| 208 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_36_SHIFT (16) | |
| 209 | + | |
| 210 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_35_MASK (0x0000FF00) | |
| 211 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_35_SHIFT (8) | |
| 212 | + | |
| 213 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_34_MASK (0x000000FF) | |
| 214 | +#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_34_SHIFT (0) | |
| 215 | + | |
| 216 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_OFFSET (0x0070) | |
| 217 | + | |
| 218 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_43_MASK (0xFF000000) | |
| 219 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_43_SHIFT (24) | |
| 220 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_42_MASK (0x00FF0000) | |
| 221 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_42_SHIFT (16) | |
| 222 | + | |
| 223 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_41_MASK (0x0000FF00) | |
| 224 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_41_SHIFT (8) | |
| 225 | + | |
| 226 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_40_MASK (0x000000FF) | |
| 227 | +#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_40_SHIFT (0) | |
| 228 | + | |
| 229 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_OFFSET (0x0074) | |
| 230 | + | |
| 231 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_47_MASK (0xFF000000) | |
| 232 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_47_SHIFT (24) | |
| 233 | + | |
| 234 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_46_MASK (0x00FF0000) | |
| 235 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_46_SHIFT (16) | |
| 236 | + | |
| 237 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_45_MASK (0x0000FF00) | |
| 238 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_45_SHIFT (8) | |
| 239 | + | |
| 240 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_44_MASK (0x000000FF) | |
| 241 | +#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_44_SHIFT (0) | |
| 242 | + | |
| 243 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_OFFSET (0x0078) | |
| 244 | + | |
| 245 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_53_MASK (0xFF000000) | |
| 246 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_53_SHIFT (24) | |
| 247 | + | |
| 248 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_52_MASK (0x00FF0000) | |
| 249 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_52_SHIFT (16) | |
| 250 | + | |
| 251 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_51_MASK (0x0000FF00) | |
| 252 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_51_SHIFT (8) | |
| 253 | + | |
| 254 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_50_MASK (0x000000FF) | |
| 255 | +#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_50_SHIFT (0) | |
| 256 | + | |
| 257 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_OFFSET (0x007C) | |
| 258 | + | |
| 259 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_57_MASK (0xFF000000) | |
| 260 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_57_SHIFT (24) | |
| 261 | + | |
| 262 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_56_MASK (0x00FF0000) | |
| 263 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_56_SHIFT (16) | |
| 264 | + | |
| 265 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_55_MASK (0x0000FF00) | |
| 266 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_55_SHIFT (8) | |
| 267 | + | |
| 268 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_54_MASK (0x000000FF) | |
| 269 | +#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_54_SHIFT (0) | |
| 270 | + | |
| 271 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_OFFSET (0x0080) | |
| 272 | + | |
| 273 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_63_MASK (0xFF000000) | |
| 274 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_63_SHIFT (24) | |
| 275 | + | |
| 276 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_62_MASK (0x00FF0000) | |
| 277 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_62_SHIFT (16) | |
| 278 | + | |
| 279 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_61_MASK (0x0000FF00) | |
| 280 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_61_SHIFT (8) | |
| 281 | + | |
| 282 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_60_MASK (0x000000FF) | |
| 283 | +#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_60_SHIFT (0) | |
| 284 | + | |
| 285 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_OFFSET (0x0084) | |
| 286 | + | |
| 287 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_67_MASK (0xFF000000) | |
| 288 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_67_SHIFT (24) | |
| 289 | + | |
| 290 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_66_MASK (0x00FF0000) | |
| 291 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_66_SHIFT (16) | |
| 292 | + | |
| 293 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_65_MASK (0x0000FF00) | |
| 294 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_65_SHIFT (8) | |
| 295 | + | |
| 296 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_64_MASK (0x000000FF) | |
| 297 | +#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_64_SHIFT (0) | |
| 298 | + | |
| 299 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_OFFSET (0x0088) | |
| 300 | + | |
| 301 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_73_MASK (0xFF000000) | |
| 302 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_73_SHIFT (24) | |
| 303 | + | |
| 304 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_72_MASK (0x00FF0000) | |
| 305 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_72_SHIFT (16) | |
| 306 | + | |
| 307 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_71_MASK (0x0000FF00) | |
| 308 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_71_SHIFT (8) | |
| 309 | + | |
| 310 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_70_MASK (0x000000FF) | |
| 311 | +#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_70_SHIFT (0) | |
| 312 | + | |
| 313 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_OFFSET (0x008C) | |
| 314 | + | |
| 315 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_77_MASK (0xFF000000) | |
| 316 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_77_SHIFT (24) | |
| 317 | + | |
| 318 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_76_MASK (0x00FF0000) | |
| 319 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_76_SHIFT (16) | |
| 320 | + | |
| 321 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_75_MASK (0x0000FF00) | |
| 322 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_75_SHIFT (8) | |
| 323 | + | |
| 324 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_74_MASK (0x000000FF) | |
| 325 | +#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_74_SHIFT (0) | |
| 326 | + | |
| 327 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET (0x0090) | |
| 328 | + | |
| 329 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_03_MASK (0xFF000000) | |
| 330 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_03_SHIFT (24) | |
| 331 | + | |
| 332 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_02_MASK (0x00FF0000) | |
| 333 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_02_SHIFT (16) | |
| 334 | + | |
| 335 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_01_MASK (0x0000FF00) | |
| 336 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_01_SHIFT (8) | |
| 337 | + | |
| 338 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_00_MASK (0x000000FF) | |
| 339 | +#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_00_SHIFT (0) | |
| 340 | + | |
| 341 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_OFFSET (0x0094) | |
| 342 | + | |
| 343 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_07_MASK (0xFF000000) | |
| 344 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_07_SHIFT (24) | |
| 345 | + | |
| 346 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_06_MASK (0x00FF0000) | |
| 347 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_06_SHIFT (16) | |
| 348 | + | |
| 349 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_05_MASK (0x0000FF00) | |
| 350 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_05_SHIFT (8) | |
| 351 | + | |
| 352 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_04_MASK (0x000000FF) | |
| 353 | +#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_04_SHIFT (0) | |
| 354 | + | |
| 355 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_OFFSET (0x0098) | |
| 356 | + | |
| 357 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_13_MASK (0xFF000000) | |
| 358 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_13_SHIFT (24) | |
| 359 | + | |
| 360 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_12_MASK (0x00FF0000) | |
| 361 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_12_SHIFT (16) | |
| 362 | + | |
| 363 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_11_MASK (0x0000FF00) | |
| 364 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_11_SHIFT (8) | |
| 365 | + | |
| 366 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_10_MASK (0x000000FF) | |
| 367 | +#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_10_SHIFT (0) | |
| 368 | + | |
| 369 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_OFFSET (0x009C) | |
| 370 | + | |
| 371 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_17_MASK (0xFF000000) | |
| 372 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_17_SHIFT (24) | |
| 373 | + | |
| 374 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_16_MASK (0x00FF0000) | |
| 375 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_16_SHIFT (16) | |
| 376 | + | |
| 377 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_15_MASK (0x0000FF00) | |
| 378 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_15_SHIFT (8) | |
| 379 | + | |
| 380 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_14_MASK (0x000000FF) | |
| 381 | +#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_14_SHIFT (0) | |
| 382 | + | |
| 383 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_OFFSET (0x00A0) | |
| 384 | + | |
| 385 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_23_MASK (0xFF000000) | |
| 386 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_23_SHIFT (24) | |
| 387 | + | |
| 388 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_22_MASK (0x00FF0000) | |
| 389 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_22_SHIFT (16) | |
| 390 | + | |
| 391 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_21_MASK (0x0000FF00) | |
| 392 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_21_SHIFT (8) | |
| 393 | + | |
| 394 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_20_MASK (0x000000FF) | |
| 395 | +#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_20_SHIFT (0) | |
| 396 | + | |
| 397 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_OFFSET (0x00A4) | |
| 398 | + | |
| 399 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_27_MASK (0xFF000000) | |
| 400 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_27_SHIFT (24) | |
| 401 | + | |
| 402 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_26_MASK (0x00FF0000) | |
| 403 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_26_SHIFT (16) | |
| 404 | + | |
| 405 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_25_MASK (0x0000FF00) | |
| 406 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_25_SHIFT (8) | |
| 407 | + | |
| 408 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_24_MASK (0x000000FF) | |
| 409 | +#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_24_SHIFT (0) | |
| 410 | + | |
| 411 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_OFFSET (0x00A8) | |
| 412 | + | |
| 413 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_33_MASK (0xFF000000) | |
| 414 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_33_SHIFT (24) | |
| 415 | + | |
| 416 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_32_MASK (0x00FF0000) | |
| 417 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_32_SHIFT (16) | |
| 418 | + | |
| 419 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_31_MASK (0x0000FF00) | |
| 420 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_31_SHIFT (8) | |
| 421 | + | |
| 422 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_30_MASK (0x000000FF) | |
| 423 | +#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_30_SHIFT (0) | |
| 424 | + | |
| 425 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_OFFSET (0x00AC) | |
| 426 | + | |
| 427 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_37_MASK (0xFF000000) | |
| 428 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_37_SHIFT (24) | |
| 429 | + | |
| 430 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_36_MASK (0x00FF0000) | |
| 431 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_36_SHIFT (16) | |
| 432 | + | |
| 433 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_35_MASK (0x0000FF00) | |
| 434 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_35_SHIFT (8) | |
| 435 | + | |
| 436 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_34_MASK (0x000000FF) | |
| 437 | +#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_34_SHIFT (0) | |
| 438 | + | |
| 439 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_OFFSET (0x00B0) | |
| 440 | + | |
| 441 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_43_MASK (0xFF000000) | |
| 442 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_43_SHIFT (24) | |
| 443 | + | |
| 444 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_42_MASK (0x00FF0000) | |
| 445 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_42_SHIFT (16) | |
| 446 | + | |
| 447 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_41_MASK (0x0000FF00) | |
| 448 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_41_SHIFT (8) | |
| 449 | + | |
| 450 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_40_MASK (0x000000FF) | |
| 451 | +#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_40_SHIFT (0) | |
| 452 | + | |
| 453 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_OFFSET (0x00B4) | |
| 454 | + | |
| 455 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_47_MASK (0xFF000000) | |
| 456 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_47_SHIFT (24) | |
| 457 | + | |
| 458 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_46_MASK (0x00FF0000) | |
| 459 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_46_SHIFT (16) | |
| 460 | + | |
| 461 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_45_MASK (0x0000FF00) | |
| 462 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_45_SHIFT (8) | |
| 463 | + | |
| 464 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_44_MASK (0x000000FF) | |
| 465 | +#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_44_SHIFT (0) | |
| 466 | + | |
| 467 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_OFFSET (0x00B8) | |
| 468 | + | |
| 469 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_53_MASK (0xFF000000) | |
| 470 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_53_SHIFT (24) | |
| 471 | + | |
| 472 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_52_MASK (0x00FF0000) | |
| 473 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_52_SHIFT (16) | |
| 474 | + | |
| 475 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_51_MASK (0x0000FF00) | |
| 476 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_51_SHIFT (8) | |
| 477 | + | |
| 478 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_50_MASK (0x000000FF) | |
| 479 | +#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_50_SHIFT (0) | |
| 480 | + | |
| 481 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_OFFSET (0x00BC) | |
| 482 | + | |
| 483 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_57_MASK (0xFF000000) | |
| 484 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_57_SHIFT (24) | |
| 485 | + | |
| 486 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_56_MASK (0x00FF0000) | |
| 487 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_56_SHIFT (16) | |
| 488 | + | |
| 489 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_55_MASK (0x0000FF00) | |
| 490 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_55_SHIFT (8) | |
| 491 | + | |
| 492 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_54_MASK (0x000000FF) | |
| 493 | +#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_54_SHIFT (0) | |
| 494 | + | |
| 495 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_OFFSET (0x00C0) | |
| 496 | + | |
| 497 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_63_MASK (0xFF000000) | |
| 498 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_63_SHIFT (24) | |
| 499 | + | |
| 500 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_62_MASK (0x00FF0000) | |
| 501 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_62_SHIFT (16) | |
| 502 | + | |
| 503 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_61_MASK (0x0000FF00) | |
| 504 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_61_SHIFT (8) | |
| 505 | + | |
| 506 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_60_MASK (0x000000FF) | |
| 507 | +#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_60_SHIFT (0) | |
| 508 | + | |
| 509 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_OFFSET (0x00C4) | |
| 510 | + | |
| 511 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_67_MASK (0xFF000000) | |
| 512 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_67_SHIFT (24) | |
| 513 | + | |
| 514 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_66_MASK (0x00FF0000) | |
| 515 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_66_SHIFT (16) | |
| 516 | + | |
| 517 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_65_MASK (0x0000FF00) | |
| 518 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_65_SHIFT (8) | |
| 519 | + | |
| 520 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_64_MASK (0x000000FF) | |
| 521 | +#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_64_SHIFT (0) | |
| 522 | + | |
| 523 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_OFFSET (0x00C8) | |
| 524 | + | |
| 525 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_73_MASK (0xFF000000) | |
| 526 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_73_SHIFT (24) | |
| 527 | + | |
| 528 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_72_MASK (0x00FF0000) | |
| 529 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_72_SHIFT (16) | |
| 530 | + | |
| 531 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_71_MASK (0x0000FF00) | |
| 532 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_71_SHIFT (8) | |
| 533 | + | |
| 534 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_70_MASK (0x000000FF) | |
| 535 | +#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_70_SHIFT (0) | |
| 536 | + | |
| 537 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_OFFSET (0x00CC) | |
| 538 | + | |
| 539 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_77_MASK (0xFF000000) | |
| 540 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_77_SHIFT (24) | |
| 541 | + | |
| 542 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_76_MASK (0x00FF0000) | |
| 543 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_76_SHIFT (16) | |
| 544 | + | |
| 545 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_75_MASK (0x0000FF00) | |
| 546 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_75_SHIFT (8) | |
| 547 | + | |
| 548 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_74_MASK (0x000000FF) | |
| 549 | +#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_74_SHIFT (0) | |
| 550 | + | |
| 551 | +#define JASPER_CRC_CTRL_OFFSET (0x00D0) | |
| 552 | +#define JASPER_CRC_CTRL_JASPER_CRC_ENABLE_MASK (0x00000001) | |
| 553 | +#define JASPER_CRC_CTRL_JASPER_CRC_ENABLE_SHIFT (0) | |
| 554 | + | |
| 555 | +#define JASPER_FRONT_END_CRC_OFFSET (0x00D4) | |
| 556 | +#define JASPER_FRONT_END_CRC_CR_JASPER_FRONT_END_CRC_OUT_MASK (0xFFFFFFFF) | |
| 557 | +#define JASPER_FRONT_END_CRC_CR_JASPER_FRONT_END_CRC_OUT_SHIFT (0) | |
| 558 | + | |
| 559 | +#define JASPER_DCT_CRC_OFFSET (0x00D8) | |
| 560 | +#define JASPER_DCT_CRC_CR_JASPER_DCT_CRC_OUT_MASK (0xFFFFFFFF) | |
| 561 | +#define JASPER_DCT_CRC_CR_JASPER_DCT_CRC_OUT_SHIFT (0) | |
| 562 | + | |
| 563 | +#define JASPER_ZZ_CRC_OFFSET (0x00DC) | |
| 564 | +#define JASPER_ZZ_CRC_CR_JASPER_ZZ_CRC_OUT_MASK (0xFFFFFFFF) | |
| 565 | +#define JASPER_ZZ_CRC_CR_JASPER_ZZ_CRC_OUT_SHIFT (0) | |
| 566 | + | |
| 567 | +#define JASPER_QUANT_CRC_OFFSET (0x00E0) | |
| 568 | +#define JASPER_QUANT_CRC_CR_JASPER_QUANT_CRC_OUT_MASK (0xFFFFFFFF) | |
| 569 | +#define JASPER_QUANT_CRC_CR_JASPER_QUANT_CRC_OUT_SHIFT (0) | |
| 570 | + | |
| 571 | +#define JASPER_ENTROPY_ENCODER_CRC_OFFSET (0x00E4) | |
| 572 | +#define JASPER_ENTROPY_ENCODER_CRC_CR_JASPER_ENTROPY_CRC_OUT_MASK (0xFFFFFFFF) | |
| 573 | +#define JASPER_ENTROPY_ENCODER_CRC_CR_JASPER_ENTROPY_CRC_OUT_SHIFT (0) | |
| 574 | + | |
| 575 | +#define JASPER_PACKING_BUFFER_DATA_CRC_OFFSET (0x00E8) | |
| 576 | +#define JASPER_PACKING_BUFFER_DATA_CRC_CR_JASPER_PACKING_DATA_CRC_OUT_MASK (0xFFFFFFFF) | |
| 577 | +#define JASPER_PACKING_BUFFER_DATA_CRC_CR_JASPER_PACKING_DATA_CRC_OUT_SHIFT (0) | |
| 578 | + | |
| 579 | +#define JASPER_PACKING_BUFFER_ADDR_CRC_OFFSET (0x00EC) | |
| 580 | +#define JASPER_PACKING_BUFFER_ADDR_CRC_CR_JASPER_PACKING_ADDR_OUT_CRC_MASK (0xFFFFFFFF) | |
| 581 | +#define JASPER_PACKING_BUFFER_ADDR_CRC_CR_JASPER_PACKING_ADDR_OUT_CRC_SHIFT (0) | |
| 582 | + | |
| 583 | +#define JASPER_CORE_BYTE_SIZE (0x00F0) | |
| 584 | + | |
| 585 | +#endif | |
| @@ -0,0 +1,267 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Imagination E5010 JPEG Encoder driver. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ | |
| 6 | + * | |
| 7 | + * Author: David Huang <d-huang@ti.com> | |
| 8 | + * Author: Devarsh Thakkar <devarsht@ti.com> | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include <linux/io.h> | |
| 12 | +#include <linux/iopoll.h> | |
| 13 | +#include <linux/dev_printk.h> | |
| 14 | +#include "e5010-jpeg-enc-hw.h" | |
| 15 | + | |
| 16 | +static void write_reg_field(void __iomem *base, unsigned int offset, u32 mask, | |
| 17 | + unsigned int shift, u32 value) | |
| 18 | +{ | |
| 19 | + u32 reg; | |
| 20 | + | |
| 21 | + value <<= shift; | |
| 22 | + if (mask != 0xffffffff) { | |
| 23 | + reg = readl(base + offset); | |
| 24 | + value = (value & mask) | (reg & ~mask); | |
| 25 | + } | |
| 26 | + writel(value, (base + offset)); | |
| 27 | +} | |
| 28 | + | |
| 29 | +static int write_reg_field_not_busy(void __iomem *jasper_base, void __iomem *wr_base, | |
| 30 | + unsigned int offset, u32 mask, unsigned int shift, | |
| 31 | + u32 value) | |
| 32 | +{ | |
| 33 | + int ret; | |
| 34 | + u32 val; | |
| 35 | + | |
| 36 | + ret = readl_poll_timeout_atomic(jasper_base + JASPER_STATUS_OFFSET, val, | |
| 37 | + (val & JASPER_STATUS_CR_JASPER_BUSY_MASK) == 0, | |
| 38 | + 2000, 50000); | |
| 39 | + if (ret) | |
| 40 | + return ret; | |
| 41 | + | |
| 42 | + write_reg_field(wr_base, offset, mask, shift, value); | |
| 43 | + | |
| 44 | + return 0; | |
| 45 | +} | |
| 46 | + | |
| 47 | +void e5010_reset(struct device *dev, void __iomem *core_base, void __iomem *mmu_base) | |
| 48 | +{ | |
| 49 | + int ret = 0; | |
| 50 | + u32 val; | |
| 51 | + | |
| 52 | + write_reg_field(core_base, JASPER_RESET_OFFSET, | |
| 53 | + JASPER_RESET_CR_CORE_RESET_MASK, | |
| 54 | + JASPER_RESET_CR_CORE_RESET_SHIFT, 1); | |
| 55 | + | |
| 56 | + write_reg_field(mmu_base, MMU_MMU_CONTROL1_OFFSET, | |
| 57 | + MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK, | |
| 58 | + MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT, 1); | |
| 59 | + | |
| 60 | + ret = readl_poll_timeout_atomic(mmu_base + MMU_MMU_CONTROL1_OFFSET, val, | |
| 61 | + (val & MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK) == 0, | |
| 62 | + 2000, 50000); | |
| 63 | + if (ret) | |
| 64 | + dev_warn(dev, "MMU soft reset timed out, forcing system soft reset\n"); | |
| 65 | + | |
| 66 | + write_reg_field(core_base, JASPER_RESET_OFFSET, | |
| 67 | + JASPER_RESET_CR_SYS_RESET_MASK, | |
| 68 | + JASPER_RESET_CR_SYS_RESET_SHIFT, 1); | |
| 69 | +} | |
| 70 | + | |
| 71 | +void e5010_hw_bypass_mmu(void __iomem *mmu_base, u32 enable) | |
| 72 | +{ | |
| 73 | + /* Bypass MMU */ | |
| 74 | + write_reg_field(mmu_base, | |
| 75 | + MMU_MMU_ADDRESS_CONTROL_OFFSET, | |
| 76 | + MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK, | |
| 77 | + MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT, | |
| 78 | + enable); | |
| 79 | +} | |
| 80 | + | |
| 81 | +int e5010_hw_enable_output_address_error_irq(void __iomem *core_base, u32 enable) | |
| 82 | +{ | |
| 83 | + return write_reg_field_not_busy(core_base, core_base, | |
| 84 | + JASPER_INTERRUPT_MASK_OFFSET, | |
| 85 | + JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_MASK, | |
| 86 | + JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_SHIFT, | |
| 87 | + enable); | |
| 88 | +} | |
| 89 | + | |
| 90 | +bool e5010_hw_pic_done_irq(void __iomem *core_base) | |
| 91 | +{ | |
| 92 | + u32 reg; | |
| 93 | + | |
| 94 | + reg = readl(core_base + JASPER_INTERRUPT_STATUS_OFFSET); | |
| 95 | + return reg & JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_MASK; | |
| 96 | +} | |
| 97 | + | |
| 98 | +bool e5010_hw_output_address_irq(void __iomem *core_base) | |
| 99 | +{ | |
| 100 | + u32 reg; | |
| 101 | + | |
| 102 | + reg = readl(core_base + JASPER_INTERRUPT_STATUS_OFFSET); | |
| 103 | + return reg & JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_MASK; | |
| 104 | +} | |
| 105 | + | |
| 106 | +int e5010_hw_enable_picture_done_irq(void __iomem *core_base, u32 enable) | |
| 107 | +{ | |
| 108 | + return write_reg_field_not_busy(core_base, core_base, | |
| 109 | + JASPER_INTERRUPT_MASK_OFFSET, | |
| 110 | + JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_MASK, | |
| 111 | + JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_SHIFT, | |
| 112 | + enable); | |
| 113 | +} | |
| 114 | + | |
| 115 | +int e5010_hw_enable_auto_clock_gating(void __iomem *core_base, u32 enable) | |
| 116 | +{ | |
| 117 | + return write_reg_field_not_busy(core_base, core_base, | |
| 118 | + JASPER_CLK_CONTROL_OFFSET, | |
| 119 | + JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_MASK, | |
| 120 | + JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_SHIFT, | |
| 121 | + enable); | |
| 122 | +} | |
| 123 | + | |
| 124 | +int e5010_hw_enable_manual_clock_gating(void __iomem *core_base, u32 enable) | |
| 125 | +{ | |
| 126 | + return write_reg_field_not_busy(core_base, core_base, | |
| 127 | + JASPER_CLK_CONTROL_OFFSET, | |
| 128 | + JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_MASK, | |
| 129 | + JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_SHIFT, 0); | |
| 130 | +} | |
| 131 | + | |
| 132 | +int e5010_hw_enable_crc_check(void __iomem *core_base, u32 enable) | |
| 133 | +{ | |
| 134 | + return write_reg_field_not_busy(core_base, core_base, | |
| 135 | + JASPER_CRC_CTRL_OFFSET, | |
| 136 | + JASPER_CRC_CTRL_JASPER_CRC_ENABLE_MASK, | |
| 137 | + JASPER_CRC_CTRL_JASPER_CRC_ENABLE_SHIFT, enable); | |
| 138 | +} | |
| 139 | + | |
| 140 | +int e5010_hw_set_input_source_to_memory(void __iomem *core_base, u32 set) | |
| 141 | +{ | |
| 142 | + return write_reg_field_not_busy(core_base, core_base, | |
| 143 | + JASPER_INPUT_CTRL0_OFFSET, | |
| 144 | + JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_MASK, | |
| 145 | + JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_SHIFT, set); | |
| 146 | +} | |
| 147 | + | |
| 148 | +int e5010_hw_set_input_luma_addr(void __iomem *core_base, u32 val) | |
| 149 | +{ | |
| 150 | + return write_reg_field_not_busy(core_base, core_base, | |
| 151 | + INPUT_LUMA_BASE_OFFSET, | |
| 152 | + INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_MASK, 0, val); | |
| 153 | +} | |
| 154 | + | |
| 155 | +int e5010_hw_set_input_chroma_addr(void __iomem *core_base, u32 val) | |
| 156 | +{ | |
| 157 | + return write_reg_field_not_busy(core_base, core_base, | |
| 158 | + INPUT_CHROMA_BASE_OFFSET, | |
| 159 | + INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_MASK, 0, val); | |
| 160 | +} | |
| 161 | + | |
| 162 | +int e5010_hw_set_output_base_addr(void __iomem *core_base, u32 val) | |
| 163 | +{ | |
| 164 | + return write_reg_field_not_busy(core_base, core_base, | |
| 165 | + JASPER_OUTPUT_BASE_OFFSET, | |
| 166 | + JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_MASK, | |
| 167 | + JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_SHIFT, val); | |
| 168 | +} | |
| 169 | + | |
| 170 | +int e5010_hw_set_horizontal_size(void __iomem *core_base, u32 val) | |
| 171 | +{ | |
| 172 | + return write_reg_field_not_busy(core_base, core_base, | |
| 173 | + JASPER_IMAGE_SIZE_OFFSET, | |
| 174 | + JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_MASK, | |
| 175 | + JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_SHIFT, | |
| 176 | + val); | |
| 177 | +} | |
| 178 | + | |
| 179 | +int e5010_hw_set_vertical_size(void __iomem *core_base, u32 val) | |
| 180 | +{ | |
| 181 | + return write_reg_field_not_busy(core_base, core_base, | |
| 182 | + JASPER_IMAGE_SIZE_OFFSET, | |
| 183 | + JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_MASK, | |
| 184 | + JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_SHIFT, | |
| 185 | + val); | |
| 186 | +} | |
| 187 | + | |
| 188 | +int e5010_hw_set_luma_stride(void __iomem *core_base, u32 bytesperline) | |
| 189 | +{ | |
| 190 | + u32 val = bytesperline / 64; | |
| 191 | + | |
| 192 | + return write_reg_field_not_busy(core_base, core_base, | |
| 193 | + JASPER_INPUT_CTRL1_OFFSET, | |
| 194 | + JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_MASK, | |
| 195 | + JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_SHIFT, | |
| 196 | + val); | |
| 197 | +} | |
| 198 | + | |
| 199 | +int e5010_hw_set_chroma_stride(void __iomem *core_base, u32 bytesperline) | |
| 200 | +{ | |
| 201 | + u32 val = bytesperline / 64; | |
| 202 | + | |
| 203 | + return write_reg_field_not_busy(core_base, core_base, | |
| 204 | + JASPER_INPUT_CTRL1_OFFSET, | |
| 205 | + JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_MASK, | |
| 206 | + JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_SHIFT, | |
| 207 | + val); | |
| 208 | +} | |
| 209 | + | |
| 210 | +int e5010_hw_set_input_subsampling(void __iomem *core_base, u32 val) | |
| 211 | +{ | |
| 212 | + return write_reg_field_not_busy(core_base, core_base, | |
| 213 | + JASPER_INPUT_CTRL0_OFFSET, | |
| 214 | + JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_MASK, | |
| 215 | + JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_SHIFT, | |
| 216 | + val); | |
| 217 | +} | |
| 218 | + | |
| 219 | +int e5010_hw_set_chroma_order(void __iomem *core_base, u32 val) | |
| 220 | +{ | |
| 221 | + return write_reg_field_not_busy(core_base, core_base, | |
| 222 | + JASPER_INPUT_CTRL0_OFFSET, | |
| 223 | + JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_MASK, | |
| 224 | + JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_SHIFT, | |
| 225 | + val); | |
| 226 | +} | |
| 227 | + | |
| 228 | +void e5010_hw_set_output_max_size(void __iomem *core_base, u32 val) | |
| 229 | +{ | |
| 230 | + write_reg_field(core_base, JASPER_OUTPUT_MAX_SIZE_OFFSET, | |
| 231 | + JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_MASK, | |
| 232 | + JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_SHIFT, | |
| 233 | + val); | |
| 234 | +} | |
| 235 | + | |
| 236 | +int e5010_hw_set_qpvalue(void __iomem *core_base, u32 offset, u32 val) | |
| 237 | +{ | |
| 238 | + return write_reg_field_not_busy(core_base, core_base, offset, 0xffffffff, 0, val); | |
| 239 | +} | |
| 240 | + | |
| 241 | +void e5010_hw_clear_output_error(void __iomem *core_base, u32 clear) | |
| 242 | +{ | |
| 243 | + /* Make sure interrupts are clear */ | |
| 244 | + write_reg_field(core_base, JASPER_INTERRUPT_CLEAR_OFFSET, | |
| 245 | + JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_MASK, | |
| 246 | + JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_SHIFT, clear); | |
| 247 | +} | |
| 248 | + | |
| 249 | +void e5010_hw_clear_picture_done(void __iomem *core_base, u32 clear) | |
| 250 | +{ | |
| 251 | + write_reg_field(core_base, | |
| 252 | + JASPER_INTERRUPT_CLEAR_OFFSET, | |
| 253 | + JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_MASK, | |
| 254 | + JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_SHIFT, clear); | |
| 255 | +} | |
| 256 | + | |
| 257 | +int e5010_hw_get_output_size(void __iomem *core_base) | |
| 258 | +{ | |
| 259 | + return readl(core_base + JASPER_OUTPUT_SIZE_OFFSET); | |
| 260 | +} | |
| 261 | + | |
| 262 | +void e5010_hw_encode_start(void __iomem *core_base, u32 start) | |
| 263 | +{ | |
| 264 | + write_reg_field(core_base, JASPER_CORE_CTRL_OFFSET, | |
| 265 | + JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_MASK, | |
| 266 | + JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_SHIFT, start); | |
| 267 | +} | |
| @@ -0,0 +1,42 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Imagination E5010 JPEG Encoder driver. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ | |
| 6 | + * | |
| 7 | + * Author: David Huang <d-huang@ti.com> | |
| 8 | + * Author: Devarsh Thakkar <devarsht@ti.com> | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#ifndef _E5010_JPEG_ENC_HW_H | |
| 12 | +#define _E5010_JPEG_ENC_HW_H | |
| 13 | + | |
| 14 | +#include "e5010-core-regs.h" | |
| 15 | +#include "e5010-mmu-regs.h" | |
| 16 | + | |
| 17 | +int e5010_hw_enable_output_address_error_irq(void __iomem *core_offset, u32 enable); | |
| 18 | +int e5010_hw_enable_picture_done_irq(void __iomem *core_offset, u32 enable); | |
| 19 | +int e5010_hw_enable_auto_clock_gating(void __iomem *core_offset, u32 enable); | |
| 20 | +int e5010_hw_enable_manual_clock_gating(void __iomem *core_offset, u32 enable); | |
| 21 | +int e5010_hw_enable_crc_check(void __iomem *core_offset, u32 enable); | |
| 22 | +int e5010_hw_set_input_source_to_memory(void __iomem *core_offset, u32 set); | |
| 23 | +int e5010_hw_set_input_luma_addr(void __iomem *core_offset, u32 val); | |
| 24 | +int e5010_hw_set_input_chroma_addr(void __iomem *core_offset, u32 val); | |
| 25 | +int e5010_hw_set_output_base_addr(void __iomem *core_offset, u32 val); | |
| 26 | +int e5010_hw_get_output_size(void __iomem *core_offset); | |
| 27 | +int e5010_hw_set_horizontal_size(void __iomem *core_offset, u32 val); | |
| 28 | +int e5010_hw_set_vertical_size(void __iomem *core_offset, u32 val); | |
| 29 | +int e5010_hw_set_luma_stride(void __iomem *core_offset, u32 bytesperline); | |
| 30 | +int e5010_hw_set_chroma_stride(void __iomem *core_offset, u32 bytesperline); | |
| 31 | +int e5010_hw_set_input_subsampling(void __iomem *core_offset, u32 val); | |
| 32 | +int e5010_hw_set_chroma_order(void __iomem *core_offset, u32 val); | |
| 33 | +int e5010_hw_set_qpvalue(void __iomem *core_offset, u32 offset, u32 value); | |
| 34 | +void e5010_reset(struct device *dev, void __iomem *core_offset, void __iomem *mmu_offset); | |
| 35 | +void e5010_hw_set_output_max_size(void __iomem *core_offset, u32 val); | |
| 36 | +void e5010_hw_clear_picture_done(void __iomem *core_offset, u32 clear); | |
| 37 | +void e5010_hw_encode_start(void __iomem *core_offset, u32 start); | |
| 38 | +void e5010_hw_clear_output_error(void __iomem *core_offset, u32 clear); | |
| 39 | +void e5010_hw_bypass_mmu(void __iomem *mmu_base, u32 enable); | |
| 40 | +bool e5010_hw_pic_done_irq(void __iomem *core_base); | |
| 41 | +bool e5010_hw_output_address_irq(void __iomem *core_base); | |
| 42 | +#endif | |
| @@ -0,0 +1,1632 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * Imagination E5010 JPEG Encoder driver. | |
| 4 | + * | |
| 5 | + * TODO: Add MMU and memory tiling support | |
| 6 | + * | |
| 7 | + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ | |
| 8 | + * | |
| 9 | + * Author: David Huang <d-huang@ti.com> | |
| 10 | + * Author: Devarsh Thakkar <devarsht@ti.com> | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/clk.h> | |
| 14 | +#include <linux/dma-mapping.h> | |
| 15 | +#include <linux/err.h> | |
| 16 | +#include <linux/interrupt.h> | |
| 17 | +#include <linux/ioctl.h> | |
| 18 | +#include <linux/module.h> | |
| 19 | +#include <linux/of_device.h> | |
| 20 | +#include <linux/pm_runtime.h> | |
| 21 | +#include <media/jpeg.h> | |
| 22 | +#include <media/v4l2-common.h> | |
| 23 | +#include <media/v4l2-ctrls.h> | |
| 24 | +#include <media/v4l2-device.h> | |
| 25 | +#include <media/v4l2-event.h> | |
| 26 | +#include <media/v4l2-ioctl.h> | |
| 27 | +#include <media/v4l2-jpeg.h> | |
| 28 | +#include <media/v4l2-rect.h> | |
| 29 | +#include <media/v4l2-mem2mem.h> | |
| 30 | +#include <media/videobuf2-dma-contig.h> | |
| 31 | +#include <media/videobuf2-v4l2.h> | |
| 32 | +#include "e5010-jpeg-enc.h" | |
| 33 | +#include "e5010-jpeg-enc-hw.h" | |
| 34 | + | |
| 35 | +/* forward declarations */ | |
| 36 | +static const struct of_device_id e5010_of_match[]; | |
| 37 | + | |
| 38 | +static const struct v4l2_file_operations e5010_fops; | |
| 39 | + | |
| 40 | +static const struct v4l2_ioctl_ops e5010_ioctl_ops; | |
| 41 | + | |
| 42 | +static const struct vb2_ops e5010_video_ops; | |
| 43 | + | |
| 44 | +static const struct v4l2_m2m_ops e5010_m2m_ops; | |
| 45 | + | |
| 46 | +static struct e5010_fmt e5010_formats[] = { | |
| 47 | + { | |
| 48 | + .fourcc = V4L2_PIX_FMT_NV12, | |
| 49 | + .num_planes = 1, | |
| 50 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 51 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | |
| 52 | + .chroma_order = CHROMA_ORDER_CB_CR, | |
| 53 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 54 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 55 | + }, | |
| 56 | + { | |
| 57 | + .fourcc = V4L2_PIX_FMT_NV12M, | |
| 58 | + .num_planes = 2, | |
| 59 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 60 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | |
| 61 | + .chroma_order = CHROMA_ORDER_CB_CR, | |
| 62 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 63 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 64 | + }, | |
| 65 | + { | |
| 66 | + .fourcc = V4L2_PIX_FMT_NV21, | |
| 67 | + .num_planes = 1, | |
| 68 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 69 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | |
| 70 | + .chroma_order = CHROMA_ORDER_CR_CB, | |
| 71 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 72 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 73 | + }, | |
| 74 | + { | |
| 75 | + .fourcc = V4L2_PIX_FMT_NV21M, | |
| 76 | + .num_planes = 2, | |
| 77 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 78 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, | |
| 79 | + .chroma_order = CHROMA_ORDER_CR_CB, | |
| 80 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 81 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + .fourcc = V4L2_PIX_FMT_NV16, | |
| 85 | + .num_planes = 1, | |
| 86 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 87 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | |
| 88 | + .chroma_order = CHROMA_ORDER_CB_CR, | |
| 89 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 90 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 91 | + }, | |
| 92 | + { | |
| 93 | + .fourcc = V4L2_PIX_FMT_NV16M, | |
| 94 | + .num_planes = 2, | |
| 95 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 96 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | |
| 97 | + .chroma_order = CHROMA_ORDER_CB_CR, | |
| 98 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 99 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 100 | + | |
| 101 | + }, | |
| 102 | + { | |
| 103 | + .fourcc = V4L2_PIX_FMT_NV61, | |
| 104 | + .num_planes = 1, | |
| 105 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 106 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | |
| 107 | + .chroma_order = CHROMA_ORDER_CR_CB, | |
| 108 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 109 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 110 | + }, | |
| 111 | + { | |
| 112 | + .fourcc = V4L2_PIX_FMT_NV61M, | |
| 113 | + .num_planes = 2, | |
| 114 | + .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE, | |
| 115 | + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, | |
| 116 | + .chroma_order = CHROMA_ORDER_CR_CB, | |
| 117 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64, | |
| 118 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 119 | + }, | |
| 120 | + { | |
| 121 | + .fourcc = V4L2_PIX_FMT_JPEG, | |
| 122 | + .num_planes = 1, | |
| 123 | + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, | |
| 124 | + .subsampling = 0, | |
| 125 | + .chroma_order = 0, | |
| 126 | + .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 16, | |
| 127 | + MIN_DIMENSION, MAX_DIMENSION, 8 }, | |
| 128 | + }, | |
| 129 | +}; | |
| 130 | + | |
| 131 | +static unsigned int debug; | |
| 132 | +module_param(debug, uint, 0644); | |
| 133 | +MODULE_PARM_DESC(debug, "debug level"); | |
| 134 | + | |
| 135 | +#define dprintk(dev, lvl, fmt, arg...) \ | |
| 136 | + v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg) | |
| 137 | + | |
| 138 | +static const struct v4l2_event e5010_eos_event = { | |
| 139 | + .type = V4L2_EVENT_EOS | |
| 140 | +}; | |
| 141 | + | |
| 142 | +static const char *type_name(enum v4l2_buf_type type) | |
| 143 | +{ | |
| 144 | + switch (type) { | |
| 145 | + case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE: | |
| 146 | + return "Output"; | |
| 147 | + case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE: | |
| 148 | + return "Capture"; | |
| 149 | + default: | |
| 150 | + return "Invalid"; | |
| 151 | + } | |
| 152 | +} | |
| 153 | + | |
| 154 | +static struct e5010_q_data *get_queue(struct e5010_context *ctx, enum v4l2_buf_type type) | |
| 155 | +{ | |
| 156 | + return (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->out_queue : &ctx->cap_queue; | |
| 157 | +} | |
| 158 | + | |
| 159 | +static void calculate_qp_tables(struct e5010_context *ctx) | |
| 160 | +{ | |
| 161 | + long long luminosity, contrast; | |
| 162 | + int quality, i; | |
| 163 | + | |
| 164 | + quality = 50 - ctx->quality; | |
| 165 | + | |
| 166 | + luminosity = LUMINOSITY * quality / 50; | |
| 167 | + contrast = CONTRAST * quality / 50; | |
| 168 | + | |
| 169 | + if (quality > 0) { | |
| 170 | + luminosity *= INCREASE; | |
| 171 | + contrast *= INCREASE; | |
| 172 | + } | |
| 173 | + | |
| 174 | + for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) { | |
| 175 | + long long delta = v4l2_jpeg_ref_table_chroma_qt[i] * contrast + luminosity; | |
| 176 | + int val = (int)(v4l2_jpeg_ref_table_chroma_qt[i] + delta); | |
| 177 | + | |
| 178 | + clamp(val, 1, 255); | |
| 179 | + ctx->chroma_qp[i] = quality == -50 ? 1 : val; | |
| 180 | + | |
| 181 | + delta = v4l2_jpeg_ref_table_luma_qt[i] * contrast + luminosity; | |
| 182 | + val = (int)(v4l2_jpeg_ref_table_luma_qt[i] + delta); | |
| 183 | + clamp(val, 1, 255); | |
| 184 | + ctx->luma_qp[i] = quality == -50 ? 1 : val; | |
| 185 | + } | |
| 186 | + | |
| 187 | + ctx->update_qp = true; | |
| 188 | +} | |
| 189 | + | |
| 190 | +static int update_qp_tables(struct e5010_context *ctx) | |
| 191 | +{ | |
| 192 | + struct e5010_dev *e5010 = ctx->e5010; | |
| 193 | + int i, ret = 0; | |
| 194 | + u32 lvalue, cvalue; | |
| 195 | + | |
| 196 | + lvalue = 0; | |
| 197 | + cvalue = 0; | |
| 198 | + | |
| 199 | + for (i = 0; i < QP_TABLE_SIZE; i++) { | |
| 200 | + lvalue |= ctx->luma_qp[i] << (8 * (i % 4)); | |
| 201 | + cvalue |= ctx->chroma_qp[i] << (8 * (i % 4)); | |
| 202 | + if (i % 4 == 3) { | |
| 203 | + ret |= e5010_hw_set_qpvalue(e5010->core_base, | |
| 204 | + JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET | |
| 205 | + + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4), | |
| 206 | + lvalue); | |
| 207 | + ret |= e5010_hw_set_qpvalue(e5010->core_base, | |
| 208 | + JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET | |
| 209 | + + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4), | |
| 210 | + cvalue); | |
| 211 | + lvalue = 0; | |
| 212 | + cvalue = 0; | |
| 213 | + } | |
| 214 | + } | |
| 215 | + | |
| 216 | + return ret; | |
| 217 | +} | |
| 218 | + | |
| 219 | +static int e5010_set_input_subsampling(void __iomem *core_base, int subsampling) | |
| 220 | +{ | |
| 221 | + switch (subsampling) { | |
| 222 | + case V4L2_JPEG_CHROMA_SUBSAMPLING_420: | |
| 223 | + return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_420); | |
| 224 | + case V4L2_JPEG_CHROMA_SUBSAMPLING_422: | |
| 225 | + return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_422); | |
| 226 | + default: | |
| 227 | + return -EINVAL; | |
| 228 | + }; | |
| 229 | +} | |
| 230 | + | |
| 231 | +static int e5010_querycap(struct file *file, void *priv, struct v4l2_capability *cap) | |
| 232 | +{ | |
| 233 | + strscpy(cap->driver, E5010_MODULE_NAME, sizeof(cap->driver)); | |
| 234 | + strscpy(cap->card, E5010_MODULE_NAME, sizeof(cap->card)); | |
| 235 | + | |
| 236 | + return 0; | |
| 237 | +} | |
| 238 | + | |
| 239 | +static struct e5010_fmt *find_format(struct v4l2_format *f) | |
| 240 | +{ | |
| 241 | + int i; | |
| 242 | + | |
| 243 | + for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) { | |
| 244 | + if (e5010_formats[i].fourcc == f->fmt.pix_mp.pixelformat && | |
| 245 | + e5010_formats[i].type == f->type) | |
| 246 | + return &e5010_formats[i]; | |
| 247 | + } | |
| 248 | + | |
| 249 | + return NULL; | |
| 250 | +} | |
| 251 | + | |
| 252 | +static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) | |
| 253 | +{ | |
| 254 | + int i, index = 0; | |
| 255 | + struct e5010_fmt *fmt = NULL; | |
| 256 | + struct e5010_context *ctx = file->private_data; | |
| 257 | + | |
| 258 | + if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) { | |
| 259 | + v4l2_err(&ctx->e5010->v4l2_dev, "ENUMFMT with Invalid type: %d\n", f->type); | |
| 260 | + return -EINVAL; | |
| 261 | + } | |
| 262 | + | |
| 263 | + for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) { | |
| 264 | + if (e5010_formats[i].type == f->type) { | |
| 265 | + if (index == f->index) { | |
| 266 | + fmt = &e5010_formats[i]; | |
| 267 | + break; | |
| 268 | + } | |
| 269 | + index++; | |
| 270 | + } | |
| 271 | + } | |
| 272 | + | |
| 273 | + if (!fmt) | |
| 274 | + return -EINVAL; | |
| 275 | + | |
| 276 | + f->pixelformat = fmt->fourcc; | |
| 277 | + return 0; | |
| 278 | +} | |
| 279 | + | |
| 280 | +static int e5010_g_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
| 281 | +{ | |
| 282 | + struct e5010_context *ctx = file->private_data; | |
| 283 | + struct e5010_q_data *queue; | |
| 284 | + int i; | |
| 285 | + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | |
| 286 | + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; | |
| 287 | + | |
| 288 | + queue = get_queue(ctx, f->type); | |
| 289 | + | |
| 290 | + pix_mp->flags = 0; | |
| 291 | + pix_mp->field = V4L2_FIELD_NONE; | |
| 292 | + pix_mp->pixelformat = queue->fmt->fourcc; | |
| 293 | + pix_mp->width = queue->width_adjusted; | |
| 294 | + pix_mp->height = queue->height_adjusted; | |
| 295 | + pix_mp->num_planes = queue->fmt->num_planes; | |
| 296 | + | |
| 297 | + if (V4L2_TYPE_IS_OUTPUT(f->type)) { | |
| 298 | + if (!pix_mp->colorspace) | |
| 299 | + pix_mp->colorspace = V4L2_COLORSPACE_SRGB; | |
| 300 | + | |
| 301 | + for (i = 0; i < queue->fmt->num_planes; i++) { | |
| 302 | + plane_fmt[i].sizeimage = queue->sizeimage[i]; | |
| 303 | + plane_fmt[i].bytesperline = queue->bytesperline[i]; | |
| 304 | + } | |
| 305 | + | |
| 306 | + } else { | |
| 307 | + pix_mp->colorspace = V4L2_COLORSPACE_JPEG; | |
| 308 | + plane_fmt[0].bytesperline = 0; | |
| 309 | + plane_fmt[0].sizeimage = queue->sizeimage[0]; | |
| 310 | + } | |
| 311 | + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
| 312 | + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
| 313 | + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; | |
| 314 | + | |
| 315 | + return 0; | |
| 316 | +} | |
| 317 | + | |
| 318 | +static int e5010_jpeg_try_fmt(struct v4l2_format *f, struct e5010_context *ctx) | |
| 319 | +{ | |
| 320 | + struct e5010_fmt *fmt; | |
| 321 | + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | |
| 322 | + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; | |
| 323 | + | |
| 324 | + fmt = find_format(f); | |
| 325 | + if (!fmt) { | |
| 326 | + if (V4L2_TYPE_IS_OUTPUT(f->type)) | |
| 327 | + pix_mp->pixelformat = V4L2_PIX_FMT_NV12; | |
| 328 | + else | |
| 329 | + pix_mp->pixelformat = V4L2_PIX_FMT_JPEG; | |
| 330 | + fmt = find_format(f); | |
| 331 | + if (!fmt) | |
| 332 | + return -EINVAL; | |
| 333 | + } | |
| 334 | + | |
| 335 | + if (V4L2_TYPE_IS_OUTPUT(f->type)) { | |
| 336 | + if (!pix_mp->colorspace) | |
| 337 | + pix_mp->colorspace = V4L2_COLORSPACE_JPEG; | |
| 338 | + if (!pix_mp->ycbcr_enc) | |
| 339 | + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
| 340 | + if (!pix_mp->quantization) | |
| 341 | + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; | |
| 342 | + if (!pix_mp->xfer_func) | |
| 343 | + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
| 344 | + | |
| 345 | + v4l2_apply_frmsize_constraints(&pix_mp->width, | |
| 346 | + &pix_mp->height, | |
| 347 | + &fmt->frmsize); | |
| 348 | + | |
| 349 | + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, | |
| 350 | + pix_mp->width, pix_mp->height); | |
| 351 | + | |
| 352 | + } else { | |
| 353 | + pix_mp->colorspace = V4L2_COLORSPACE_JPEG; | |
| 354 | + pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; | |
| 355 | + pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT; | |
| 356 | + pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT; | |
| 357 | + v4l2_apply_frmsize_constraints(&pix_mp->width, | |
| 358 | + &pix_mp->height, | |
| 359 | + &fmt->frmsize); | |
| 360 | + plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL; | |
| 361 | + plane_fmt[0].sizeimage += HEADER_SIZE; | |
| 362 | + plane_fmt[0].bytesperline = 0; | |
| 363 | + pix_mp->pixelformat = fmt->fourcc; | |
| 364 | + pix_mp->num_planes = fmt->num_planes; | |
| 365 | + } | |
| 366 | + pix_mp->flags = 0; | |
| 367 | + pix_mp->field = V4L2_FIELD_NONE; | |
| 368 | + | |
| 369 | + dprintk(ctx->e5010, 2, | |
| 370 | + "ctx: 0x%p: format type %s:, wxh: %dx%d (plane0 : %d bytes, plane1 : %d bytes),fmt: %c%c%c%c\n", | |
| 371 | + ctx, type_name(f->type), pix_mp->width, pix_mp->height, | |
| 372 | + plane_fmt[0].sizeimage, plane_fmt[1].sizeimage, | |
| 373 | + (fmt->fourcc & 0xff), | |
| 374 | + (fmt->fourcc >> 8) & 0xff, | |
| 375 | + (fmt->fourcc >> 16) & 0xff, | |
| 376 | + (fmt->fourcc >> 24) & 0xff); | |
| 377 | + | |
| 378 | + return 0; | |
| 379 | +} | |
| 380 | + | |
| 381 | +static int e5010_try_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
| 382 | +{ | |
| 383 | + struct e5010_context *ctx = file->private_data; | |
| 384 | + | |
| 385 | + return e5010_jpeg_try_fmt(f, ctx); | |
| 386 | +} | |
| 387 | + | |
| 388 | +static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f) | |
| 389 | +{ | |
| 390 | + struct e5010_context *ctx = file->private_data; | |
| 391 | + struct vb2_queue *vq; | |
| 392 | + int ret = 0, i = 0; | |
| 393 | + struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp; | |
| 394 | + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; | |
| 395 | + struct e5010_q_data *queue; | |
| 396 | + struct e5010_fmt *fmt; | |
| 397 | + | |
| 398 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type); | |
| 399 | + if (!vq) | |
| 400 | + return -EINVAL; | |
| 401 | + | |
| 402 | + if (vb2_is_busy(vq)) { | |
| 403 | + v4l2_err(&ctx->e5010->v4l2_dev, "queue busy\n"); | |
| 404 | + return -EBUSY; | |
| 405 | + } | |
| 406 | + | |
| 407 | + ret = e5010_jpeg_try_fmt(f, ctx); | |
| 408 | + if (ret) | |
| 409 | + return ret; | |
| 410 | + | |
| 411 | + fmt = find_format(f); | |
| 412 | + queue = get_queue(ctx, f->type); | |
| 413 | + | |
| 414 | + queue->fmt = fmt; | |
| 415 | + queue->width = pix_mp->width; | |
| 416 | + queue->height = pix_mp->height; | |
| 417 | + | |
| 418 | + if (V4L2_TYPE_IS_OUTPUT(f->type)) { | |
| 419 | + for (i = 0; i < fmt->num_planes; i++) { | |
| 420 | + queue->bytesperline[i] = plane_fmt[i].bytesperline; | |
| 421 | + queue->sizeimage[i] = plane_fmt[i].sizeimage; | |
| 422 | + } | |
| 423 | + queue->crop.left = 0; | |
| 424 | + queue->crop.top = 0; | |
| 425 | + queue->crop.width = queue->width; | |
| 426 | + queue->crop.height = queue->height; | |
| 427 | + } else { | |
| 428 | + queue->sizeimage[0] = plane_fmt[0].sizeimage; | |
| 429 | + queue->sizeimage[1] = 0; | |
| 430 | + queue->bytesperline[0] = 0; | |
| 431 | + queue->bytesperline[1] = 0; | |
| 432 | + } | |
| 433 | + | |
| 434 | + return 0; | |
| 435 | +} | |
| 436 | + | |
| 437 | +static int e5010_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize) | |
| 438 | +{ | |
| 439 | + struct v4l2_format f; | |
| 440 | + struct e5010_fmt *fmt; | |
| 441 | + | |
| 442 | + if (fsize->index != 0) | |
| 443 | + return -EINVAL; | |
| 444 | + | |
| 445 | + f.fmt.pix_mp.pixelformat = fsize->pixel_format; | |
| 446 | + if (f.fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG) | |
| 447 | + f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 448 | + else | |
| 449 | + f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
| 450 | + | |
| 451 | + fmt = find_format(&f); | |
| 452 | + if (!fmt) | |
| 453 | + return -EINVAL; | |
| 454 | + | |
| 455 | + fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE; | |
| 456 | + fsize->stepwise = fmt->frmsize; | |
| 457 | + fsize->reserved[0] = 0; | |
| 458 | + fsize->reserved[1] = 0; | |
| 459 | + | |
| 460 | + return 0; | |
| 461 | +} | |
| 462 | + | |
| 463 | +static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection *s) | |
| 464 | +{ | |
| 465 | + struct e5010_context *ctx = file->private_data; | |
| 466 | + struct e5010_q_data *queue; | |
| 467 | + | |
| 468 | + if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
| 469 | + return -EINVAL; | |
| 470 | + | |
| 471 | + queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 472 | + | |
| 473 | + switch (s->target) { | |
| 474 | + case V4L2_SEL_TGT_CROP_DEFAULT: | |
| 475 | + case V4L2_SEL_TGT_CROP_BOUNDS: | |
| 476 | + s->r.left = 0; | |
| 477 | + s->r.top = 0; | |
| 478 | + s->r.width = queue->width; | |
| 479 | + s->r.height = queue->height; | |
| 480 | + break; | |
| 481 | + case V4L2_SEL_TGT_CROP: | |
| 482 | + memcpy(&s->r, &queue->crop, sizeof(s->r)); | |
| 483 | + break; | |
| 484 | + default: | |
| 485 | + return -EINVAL; | |
| 486 | + } | |
| 487 | + | |
| 488 | + return 0; | |
| 489 | +} | |
| 490 | + | |
| 491 | +static int e5010_s_selection(struct file *file, void *fh, struct v4l2_selection *s) | |
| 492 | +{ | |
| 493 | + struct e5010_context *ctx = file->private_data; | |
| 494 | + struct e5010_q_data *queue; | |
| 495 | + struct vb2_queue *vq; | |
| 496 | + struct v4l2_rect base_rect; | |
| 497 | + | |
| 498 | + vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, s->type); | |
| 499 | + if (!vq) | |
| 500 | + return -EINVAL; | |
| 501 | + | |
| 502 | + if (vb2_is_streaming(vq)) | |
| 503 | + return -EBUSY; | |
| 504 | + | |
| 505 | + if (s->target != V4L2_SEL_TGT_CROP || | |
| 506 | + s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) | |
| 507 | + return -EINVAL; | |
| 508 | + | |
| 509 | + queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | |
| 510 | + base_rect.top = 0; | |
| 511 | + base_rect.left = 0; | |
| 512 | + base_rect.width = queue->width; | |
| 513 | + base_rect.height = queue->height; | |
| 514 | + | |
| 515 | + switch (s->flags) { | |
| 516 | + case 0: | |
| 517 | + s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width); | |
| 518 | + s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height); | |
| 519 | + s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width); | |
| 520 | + s->r.top = round_down(s->r.top, 2); | |
| 521 | + | |
| 522 | + if (s->r.left + s->r.width > queue->width) | |
| 523 | + s->r.width = round_down(s->r.width + s->r.left - queue->width, | |
| 524 | + queue->fmt->frmsize.step_width); | |
| 525 | + if (s->r.top + s->r.height > queue->height) | |
| 526 | + s->r.top = round_down(s->r.top + s->r.height - queue->height, 2); | |
| 527 | + break; | |
| 528 | + case V4L2_SEL_FLAG_GE: | |
| 529 | + s->r.width = round_up(s->r.width, queue->fmt->frmsize.step_width); | |
| 530 | + s->r.height = round_up(s->r.height, queue->fmt->frmsize.step_height); | |
| 531 | + s->r.left = round_up(s->r.left, queue->fmt->frmsize.step_width); | |
| 532 | + s->r.top = round_up(s->r.top, 2); | |
| 533 | + break; | |
| 534 | + case V4L2_SEL_FLAG_LE: | |
| 535 | + s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width); | |
| 536 | + s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height); | |
| 537 | + s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width); | |
| 538 | + s->r.top = round_down(s->r.top, 2); | |
| 539 | + break; | |
| 540 | + case V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE: | |
| 541 | + if (!IS_ALIGNED(s->r.width, queue->fmt->frmsize.step_width) || | |
| 542 | + !IS_ALIGNED(s->r.height, queue->fmt->frmsize.step_height) || | |
| 543 | + !IS_ALIGNED(s->r.left, queue->fmt->frmsize.step_width) || | |
| 544 | + !IS_ALIGNED(s->r.top, 2)) | |
| 545 | + return -ERANGE; | |
| 546 | + break; | |
| 547 | + default: | |
| 548 | + return -EINVAL; | |
| 549 | + } | |
| 550 | + | |
| 551 | + if (!v4l2_rect_enclosed(&s->r, &base_rect)) | |
| 552 | + return -ERANGE; | |
| 553 | + | |
| 554 | + memcpy(&queue->crop, &s->r, sizeof(s->r)); | |
| 555 | + | |
| 556 | + if (!v4l2_rect_equal(&s->r, &base_rect)) | |
| 557 | + queue->crop_set = true; | |
| 558 | + | |
| 559 | + dprintk(ctx->e5010, 2, "ctx: 0x%p: crop rectangle: w: %d, h : %d, l : %d, t : %d\n", | |
| 560 | + ctx, queue->crop.width, queue->crop.height, queue->crop.left, queue->crop.top); | |
| 561 | + | |
| 562 | + return 0; | |
| 563 | +} | |
| 564 | + | |
| 565 | +static int e5010_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub) | |
| 566 | +{ | |
| 567 | + switch (sub->type) { | |
| 568 | + case V4L2_EVENT_EOS: | |
| 569 | + return v4l2_event_subscribe(fh, sub, 0, NULL); | |
| 570 | + case V4L2_EVENT_CTRL: | |
| 571 | + return v4l2_ctrl_subscribe_event(fh, sub); | |
| 572 | + default: | |
| 573 | + return -EINVAL; | |
| 574 | + } | |
| 575 | + | |
| 576 | + return 0; | |
| 577 | +} | |
| 578 | + | |
| 579 | +static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq) | |
| 580 | +{ | |
| 581 | + struct e5010_context *ctx = priv; | |
| 582 | + struct e5010_dev *e5010 = ctx->e5010; | |
| 583 | + int ret = 0; | |
| 584 | + | |
| 585 | + /* src_vq */ | |
| 586 | + memset(src_vq, 0, sizeof(*src_vq)); | |
| 587 | + src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
| 588 | + src_vq->io_modes = VB2_MMAP | VB2_DMABUF; | |
| 589 | + src_vq->drv_priv = ctx; | |
| 590 | + src_vq->buf_struct_size = sizeof(struct e5010_buffer); | |
| 591 | + src_vq->ops = &e5010_video_ops; | |
| 592 | + src_vq->mem_ops = &vb2_dma_contig_memops; | |
| 593 | + src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
| 594 | + src_vq->lock = &e5010->mutex; | |
| 595 | + src_vq->dev = e5010->v4l2_dev.dev; | |
| 596 | + | |
| 597 | + ret = vb2_queue_init(src_vq); | |
| 598 | + if (ret) | |
| 599 | + return ret; | |
| 600 | + | |
| 601 | + /* dst_vq */ | |
| 602 | + memset(dst_vq, 0, sizeof(*dst_vq)); | |
| 603 | + dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 604 | + dst_vq->io_modes = VB2_MMAP | VB2_DMABUF; | |
| 605 | + dst_vq->drv_priv = ctx; | |
| 606 | + dst_vq->buf_struct_size = sizeof(struct e5010_buffer); | |
| 607 | + dst_vq->ops = &e5010_video_ops; | |
| 608 | + dst_vq->mem_ops = &vb2_dma_contig_memops; | |
| 609 | + dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY; | |
| 610 | + dst_vq->lock = &e5010->mutex; | |
| 611 | + dst_vq->dev = e5010->v4l2_dev.dev; | |
| 612 | + | |
| 613 | + ret = vb2_queue_init(dst_vq); | |
| 614 | + if (ret) { | |
| 615 | + vb2_queue_release(src_vq); | |
| 616 | + return ret; | |
| 617 | + } | |
| 618 | + | |
| 619 | + return 0; | |
| 620 | +} | |
| 621 | + | |
| 622 | +static int e5010_s_ctrl(struct v4l2_ctrl *ctrl) | |
| 623 | +{ | |
| 624 | + struct e5010_context *ctx = | |
| 625 | + container_of(ctrl->handler, struct e5010_context, ctrl_handler); | |
| 626 | + | |
| 627 | + switch (ctrl->id) { | |
| 628 | + case V4L2_CID_JPEG_COMPRESSION_QUALITY: | |
| 629 | + ctx->quality = ctrl->val; | |
| 630 | + calculate_qp_tables(ctx); | |
| 631 | + dprintk(ctx->e5010, 2, "ctx: 0x%p compression quality set to : %d\n", ctx, | |
| 632 | + ctx->quality); | |
| 633 | + break; | |
| 634 | + default: | |
| 635 | + return -EINVAL; | |
| 636 | + } | |
| 637 | + | |
| 638 | + return 0; | |
| 639 | +} | |
| 640 | + | |
| 641 | +static const struct v4l2_ctrl_ops e5010_ctrl_ops = { | |
| 642 | + .s_ctrl = e5010_s_ctrl, | |
| 643 | +}; | |
| 644 | + | |
| 645 | +static void e5010_encode_ctrls(struct e5010_context *ctx) | |
| 646 | +{ | |
| 647 | + v4l2_ctrl_new_std(&ctx->ctrl_handler, &e5010_ctrl_ops, | |
| 648 | + V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75); | |
| 649 | +} | |
| 650 | + | |
| 651 | +static int e5010_ctrls_setup(struct e5010_context *ctx) | |
| 652 | +{ | |
| 653 | + int err; | |
| 654 | + | |
| 655 | + v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1); | |
| 656 | + | |
| 657 | + e5010_encode_ctrls(ctx); | |
| 658 | + | |
| 659 | + if (ctx->ctrl_handler.error) { | |
| 660 | + err = ctx->ctrl_handler.error; | |
| 661 | + v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
| 662 | + | |
| 663 | + return err; | |
| 664 | + } | |
| 665 | + | |
| 666 | + err = v4l2_ctrl_handler_setup(&ctx->ctrl_handler); | |
| 667 | + if (err) | |
| 668 | + v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
| 669 | + | |
| 670 | + return err; | |
| 671 | +} | |
| 672 | + | |
| 673 | +static void e5010_jpeg_set_default_params(struct e5010_context *ctx) | |
| 674 | +{ | |
| 675 | + struct e5010_q_data *queue; | |
| 676 | + struct v4l2_format f; | |
| 677 | + struct e5010_fmt *fmt; | |
| 678 | + struct v4l2_pix_format_mplane *pix_mp = &f.fmt.pix_mp; | |
| 679 | + struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt; | |
| 680 | + int i = 0; | |
| 681 | + | |
| 682 | + f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE; | |
| 683 | + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12; | |
| 684 | + fmt = find_format(&f); | |
| 685 | + queue = &ctx->out_queue; | |
| 686 | + queue->fmt = fmt; | |
| 687 | + queue->width = DEFAULT_WIDTH; | |
| 688 | + queue->height = DEFAULT_HEIGHT; | |
| 689 | + pix_mp->width = queue->width; | |
| 690 | + pix_mp->height = queue->height; | |
| 691 | + queue->crop.left = 0; | |
| 692 | + queue->crop.top = 0; | |
| 693 | + queue->crop.width = queue->width; | |
| 694 | + queue->crop.height = queue->height; | |
| 695 | + v4l2_apply_frmsize_constraints(&pix_mp->width, | |
| 696 | + &pix_mp->height, | |
| 697 | + &fmt->frmsize); | |
| 698 | + v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, | |
| 699 | + pix_mp->width, pix_mp->height); | |
| 700 | + for (i = 0; i < fmt->num_planes; i++) { | |
| 701 | + queue->bytesperline[i] = plane_fmt[i].bytesperline; | |
| 702 | + queue->sizeimage[i] = plane_fmt[i].sizeimage; | |
| 703 | + } | |
| 704 | + queue->width_adjusted = pix_mp->width; | |
| 705 | + queue->height_adjusted = pix_mp->height; | |
| 706 | + | |
| 707 | + f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE; | |
| 708 | + f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_JPEG; | |
| 709 | + fmt = find_format(&f); | |
| 710 | + queue = &ctx->cap_queue; | |
| 711 | + queue->fmt = fmt; | |
| 712 | + queue->width = DEFAULT_WIDTH; | |
| 713 | + queue->height = DEFAULT_HEIGHT; | |
| 714 | + pix_mp->width = queue->width; | |
| 715 | + pix_mp->height = queue->height; | |
| 716 | + v4l2_apply_frmsize_constraints(&pix_mp->width, | |
| 717 | + &pix_mp->height, | |
| 718 | + &fmt->frmsize); | |
| 719 | + queue->sizeimage[0] = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL; | |
| 720 | + queue->sizeimage[0] += HEADER_SIZE; | |
| 721 | + queue->sizeimage[1] = 0; | |
| 722 | + queue->bytesperline[0] = 0; | |
| 723 | + queue->bytesperline[1] = 0; | |
| 724 | + queue->width_adjusted = pix_mp->width; | |
| 725 | + queue->height_adjusted = pix_mp->height; | |
| 726 | +} | |
| 727 | + | |
| 728 | +static int e5010_open(struct file *file) | |
| 729 | +{ | |
| 730 | + struct e5010_dev *e5010 = video_drvdata(file); | |
| 731 | + struct video_device *vdev = video_devdata(file); | |
| 732 | + struct e5010_context *ctx; | |
| 733 | + int ret = 0; | |
| 734 | + | |
| 735 | + ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); | |
| 736 | + if (!ctx) | |
| 737 | + return -ENOMEM; | |
| 738 | + | |
| 739 | + if (mutex_lock_interruptible(&e5010->mutex)) { | |
| 740 | + ret = -ERESTARTSYS; | |
| 741 | + goto free; | |
| 742 | + } | |
| 743 | + | |
| 744 | + v4l2_fh_init(&ctx->fh, vdev); | |
| 745 | + file->private_data = ctx; | |
| 746 | + v4l2_fh_add(&ctx->fh); | |
| 747 | + | |
| 748 | + ctx->e5010 = e5010; | |
| 749 | + ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(e5010->m2m_dev, ctx, queue_init); | |
| 750 | + if (IS_ERR(ctx->fh.m2m_ctx)) { | |
| 751 | + v4l2_err(&e5010->v4l2_dev, "failed to init m2m ctx\n"); | |
| 752 | + ret = PTR_ERR(ctx->fh.m2m_ctx); | |
| 753 | + goto exit; | |
| 754 | + } | |
| 755 | + | |
| 756 | + ret = e5010_ctrls_setup(ctx); | |
| 757 | + if (ret) { | |
| 758 | + v4l2_err(&e5010->v4l2_dev, "failed to setup e5010 jpeg controls\n"); | |
| 759 | + goto err_ctrls_setup; | |
| 760 | + } | |
| 761 | + ctx->fh.ctrl_handler = &ctx->ctrl_handler; | |
| 762 | + | |
| 763 | + e5010_jpeg_set_default_params(ctx); | |
| 764 | + | |
| 765 | + dprintk(e5010, 1, "Created instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx); | |
| 766 | + | |
| 767 | + mutex_unlock(&e5010->mutex); | |
| 768 | + return 0; | |
| 769 | + | |
| 770 | +err_ctrls_setup: | |
| 771 | + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | |
| 772 | +exit: | |
| 773 | + v4l2_fh_del(&ctx->fh); | |
| 774 | + v4l2_fh_exit(&ctx->fh); | |
| 775 | + mutex_unlock(&e5010->mutex); | |
| 776 | +free: | |
| 777 | + kfree(ctx); | |
| 778 | + return ret; | |
| 779 | +} | |
| 780 | + | |
| 781 | +static int e5010_release(struct file *file) | |
| 782 | +{ | |
| 783 | + struct e5010_dev *e5010 = video_drvdata(file); | |
| 784 | + struct e5010_context *ctx = file->private_data; | |
| 785 | + | |
| 786 | + dprintk(e5010, 1, "Releasing instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx); | |
| 787 | + mutex_lock(&e5010->mutex); | |
| 788 | + v4l2_ctrl_handler_free(&ctx->ctrl_handler); | |
| 789 | + v4l2_m2m_ctx_release(ctx->fh.m2m_ctx); | |
| 790 | + v4l2_fh_del(&ctx->fh); | |
| 791 | + v4l2_fh_exit(&ctx->fh); | |
| 792 | + kfree(ctx); | |
| 793 | + mutex_unlock(&e5010->mutex); | |
| 794 | + | |
| 795 | + return 0; | |
| 796 | +} | |
| 797 | + | |
| 798 | +static void header_write(struct e5010_context *ctx, u8 *addr, unsigned int *offset, | |
| 799 | + unsigned int no_bytes, unsigned long bits) | |
| 800 | +{ | |
| 801 | + u8 *w_addr = addr + *offset; | |
| 802 | + int i; | |
| 803 | + | |
| 804 | + if ((*offset + no_bytes) > HEADER_SIZE) { | |
| 805 | + v4l2_warn(&ctx->e5010->v4l2_dev, "%s: %s: %d: Problem writing header. %d > HEADER_SIZE %d\n", | |
| 806 | + __FILE__, __func__, __LINE__, *offset + no_bytes, HEADER_SIZE); | |
| 807 | + return; | |
| 808 | + } | |
| 809 | + | |
| 810 | + for (i = no_bytes - 1; i >= 0; i--) | |
| 811 | + *(w_addr++) = ((u8 *)&bits)[i]; | |
| 812 | + | |
| 813 | + *offset += no_bytes; | |
| 814 | +} | |
| 815 | + | |
| 816 | +static void encode_marker_segment(struct e5010_context *ctx, void *addr, unsigned int *offset) | |
| 817 | +{ | |
| 818 | + u8 *buffer = (u8 *)addr; | |
| 819 | + int i; | |
| 820 | + | |
| 821 | + header_write(ctx, buffer, offset, 2, START_OF_IMAGE); | |
| 822 | + header_write(ctx, buffer, offset, 2, DQT_MARKER); | |
| 823 | + header_write(ctx, buffer, offset, 3, LQPQ << 4); | |
| 824 | + for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) | |
| 825 | + header_write(ctx, buffer, offset, 1, ctx->luma_qp[v4l2_jpeg_zigzag_scan_index[i]]); | |
| 826 | + | |
| 827 | + header_write(ctx, buffer, offset, 2, DQT_MARKER); | |
| 828 | + header_write(ctx, buffer, offset, 3, (LQPQ << 4) | 1); | |
| 829 | + for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) | |
| 830 | + header_write(ctx, buffer, offset, 1, | |
| 831 | + ctx->chroma_qp[v4l2_jpeg_zigzag_scan_index[i]]); | |
| 832 | + | |
| 833 | + /* Huffman tables */ | |
| 834 | + header_write(ctx, buffer, offset, 2, DHT_MARKER); | |
| 835 | + header_write(ctx, buffer, offset, 2, LH_DC); | |
| 836 | + header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_DC_HT); | |
| 837 | + for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++) | |
| 838 | + header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_luma_dc_ht[i]); | |
| 839 | + | |
| 840 | + header_write(ctx, buffer, offset, 2, DHT_MARKER); | |
| 841 | + header_write(ctx, buffer, offset, 2, LH_AC); | |
| 842 | + header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_AC_HT); | |
| 843 | + for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++) | |
| 844 | + header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_luma_ac_ht[i]); | |
| 845 | + | |
| 846 | + header_write(ctx, buffer, offset, 2, DHT_MARKER); | |
| 847 | + header_write(ctx, buffer, offset, 2, LH_DC); | |
| 848 | + header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_DC_HT); | |
| 849 | + for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++) | |
| 850 | + header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_chroma_dc_ht[i]); | |
| 851 | + | |
| 852 | + header_write(ctx, buffer, offset, 2, DHT_MARKER); | |
| 853 | + header_write(ctx, buffer, offset, 2, LH_AC); | |
| 854 | + header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_AC_HT); | |
| 855 | + for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++) | |
| 856 | + header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_chroma_ac_ht[i]); | |
| 857 | +} | |
| 858 | + | |
| 859 | +static void encode_frame_header(struct e5010_context *ctx, void *addr, unsigned int *offset) | |
| 860 | +{ | |
| 861 | + u8 *buffer = (u8 *)addr; | |
| 862 | + | |
| 863 | + header_write(ctx, buffer, offset, 2, SOF_BASELINE_DCT); | |
| 864 | + header_write(ctx, buffer, offset, 2, 8 + (3 * UC_NUM_COMP)); | |
| 865 | + header_write(ctx, buffer, offset, 1, PRECISION); | |
| 866 | + header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.height); | |
| 867 | + header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.width); | |
| 868 | + header_write(ctx, buffer, offset, 1, UC_NUM_COMP); | |
| 869 | + | |
| 870 | + /* Luma details */ | |
| 871 | + header_write(ctx, buffer, offset, 1, 1); | |
| 872 | + if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) | |
| 873 | + header_write(ctx, buffer, offset, 1, | |
| 874 | + HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_422)); | |
| 875 | + else | |
| 876 | + header_write(ctx, buffer, offset, 1, | |
| 877 | + HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_420)); | |
| 878 | + header_write(ctx, buffer, offset, 1, 0); | |
| 879 | + /* Chroma details */ | |
| 880 | + header_write(ctx, buffer, offset, 1, 2); | |
| 881 | + header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1); | |
| 882 | + header_write(ctx, buffer, offset, 1, 1); | |
| 883 | + header_write(ctx, buffer, offset, 1, 3); | |
| 884 | + header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1); | |
| 885 | + header_write(ctx, buffer, offset, 1, 1); | |
| 886 | +} | |
| 887 | + | |
| 888 | +static void jpg_encode_sos_header(struct e5010_context *ctx, void *addr, unsigned int *offset) | |
| 889 | +{ | |
| 890 | + u8 *buffer = (u8 *)addr; | |
| 891 | + int i; | |
| 892 | + | |
| 893 | + header_write(ctx, buffer, offset, 2, START_OF_SCAN); | |
| 894 | + header_write(ctx, buffer, offset, 2, 6 + (COMPONENTS_IN_SCAN << 1)); | |
| 895 | + header_write(ctx, buffer, offset, 1, COMPONENTS_IN_SCAN); | |
| 896 | + | |
| 897 | + for (i = 0; i < COMPONENTS_IN_SCAN; i++) { | |
| 898 | + header_write(ctx, buffer, offset, 1, i + 1); | |
| 899 | + if (i == 0) | |
| 900 | + header_write(ctx, buffer, offset, 1, 0); | |
| 901 | + else | |
| 902 | + header_write(ctx, buffer, offset, 1, 17); | |
| 903 | + } | |
| 904 | + | |
| 905 | + header_write(ctx, buffer, offset, 1, 0); | |
| 906 | + header_write(ctx, buffer, offset, 1, 63); | |
| 907 | + header_write(ctx, buffer, offset, 1, 0); | |
| 908 | +} | |
| 909 | + | |
| 910 | +static void write_header(struct e5010_context *ctx, void *addr) | |
| 911 | +{ | |
| 912 | + unsigned int offset = 0; | |
| 913 | + | |
| 914 | + encode_marker_segment(ctx, addr, &offset); | |
| 915 | + encode_frame_header(ctx, addr, &offset); | |
| 916 | + jpg_encode_sos_header(ctx, addr, &offset); | |
| 917 | +} | |
| 918 | + | |
| 919 | +static irqreturn_t e5010_irq(int irq, void *data) | |
| 920 | +{ | |
| 921 | + struct e5010_dev *e5010 = data; | |
| 922 | + struct e5010_context *ctx; | |
| 923 | + int output_size; | |
| 924 | + struct vb2_v4l2_buffer *src_buf, *dst_buf; | |
| 925 | + bool pic_done, out_addr_err; | |
| 926 | + | |
| 927 | + spin_lock(&e5010->hw_lock); | |
| 928 | + pic_done = e5010_hw_pic_done_irq(e5010->core_base); | |
| 929 | + out_addr_err = e5010_hw_output_address_irq(e5010->core_base); | |
| 930 | + | |
| 931 | + if (!pic_done && !out_addr_err) { | |
| 932 | + spin_unlock(&e5010->hw_lock); | |
| 933 | + return IRQ_NONE; | |
| 934 | + } | |
| 935 | + | |
| 936 | + ctx = v4l2_m2m_get_curr_priv(e5010->m2m_dev); | |
| 937 | + if (WARN_ON(!ctx)) | |
| 938 | + goto job_unlock; | |
| 939 | + | |
| 940 | + dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx); | |
| 941 | + src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx); | |
| 942 | + if (!dst_buf || !src_buf) { | |
| 943 | + v4l2_err(&e5010->v4l2_dev, "ctx: 0x%p No source or destination buffer\n", ctx); | |
| 944 | + goto job_unlock; | |
| 945 | + } | |
| 946 | + | |
| 947 | + if (out_addr_err) { | |
| 948 | + e5010_hw_clear_output_error(e5010->core_base, 1); | |
| 949 | + v4l2_warn(&e5010->v4l2_dev, | |
| 950 | + "ctx: 0x%p Output bitstream size exceeded max size\n", ctx); | |
| 951 | + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR); | |
| 952 | + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, dst_buf->planes[0].length); | |
| 953 | + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR); | |
| 954 | + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { | |
| 955 | + dst_buf->flags |= V4L2_BUF_FLAG_LAST; | |
| 956 | + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); | |
| 957 | + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); | |
| 958 | + dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx); | |
| 959 | + } | |
| 960 | + } | |
| 961 | + | |
| 962 | + if (pic_done) { | |
| 963 | + e5010_hw_clear_picture_done(e5010->core_base, 1); | |
| 964 | + dprintk(e5010, 3, "ctx: 0x%p Got output bitstream of size %d bytes\n", | |
| 965 | + ctx, readl(e5010->core_base + JASPER_OUTPUT_SIZE_OFFSET)); | |
| 966 | + | |
| 967 | + if (v4l2_m2m_is_last_draining_src_buf(ctx->fh.m2m_ctx, src_buf)) { | |
| 968 | + dst_buf->flags |= V4L2_BUF_FLAG_LAST; | |
| 969 | + v4l2_m2m_mark_stopped(ctx->fh.m2m_ctx); | |
| 970 | + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); | |
| 971 | + dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx); | |
| 972 | + } | |
| 973 | + v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE); | |
| 974 | + output_size = e5010_hw_get_output_size(e5010->core_base); | |
| 975 | + vb2_set_plane_payload(&dst_buf->vb2_buf, 0, output_size + HEADER_SIZE); | |
| 976 | + v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE); | |
| 977 | + dprintk(e5010, 3, | |
| 978 | + "ctx: 0x%p frame done for dst_buf->sequence: %d src_buf->sequence: %d\n", | |
| 979 | + ctx, dst_buf->sequence, src_buf->sequence); | |
| 980 | + } | |
| 981 | + | |
| 982 | + v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx); | |
| 983 | + dprintk(e5010, 3, "ctx: 0x%p Finish job\n", ctx); | |
| 984 | + | |
| 985 | +job_unlock: | |
| 986 | + spin_unlock(&e5010->hw_lock); | |
| 987 | + return IRQ_HANDLED; | |
| 988 | +} | |
| 989 | + | |
| 990 | +static int e5010_init_device(struct e5010_dev *e5010) | |
| 991 | +{ | |
| 992 | + int ret = 0; | |
| 993 | + | |
| 994 | + /*TODO: Set MMU in bypass mode until support for the same is added in driver*/ | |
| 995 | + e5010_hw_bypass_mmu(e5010->mmu_base, 1); | |
| 996 | + | |
| 997 | + if (e5010_hw_enable_auto_clock_gating(e5010->core_base, 1)) | |
| 998 | + v4l2_warn(&e5010->v4l2_dev, "failed to enable auto clock gating\n"); | |
| 999 | + | |
| 1000 | + if (e5010_hw_enable_manual_clock_gating(e5010->core_base, 0)) | |
| 1001 | + v4l2_warn(&e5010->v4l2_dev, "failed to disable manual clock gating\n"); | |
| 1002 | + | |
| 1003 | + if (e5010_hw_enable_crc_check(e5010->core_base, 0)) | |
| 1004 | + v4l2_warn(&e5010->v4l2_dev, "failed to disable CRC check\n"); | |
| 1005 | + | |
| 1006 | + if (e5010_hw_enable_output_address_error_irq(e5010->core_base, 1)) | |
| 1007 | + v4l2_err(&e5010->v4l2_dev, "failed to enable Output Address Error interrupts\n"); | |
| 1008 | + | |
| 1009 | + ret = e5010_hw_set_input_source_to_memory(e5010->core_base, 1); | |
| 1010 | + if (ret) { | |
| 1011 | + v4l2_err(&e5010->v4l2_dev, "failed to set input source to memory\n"); | |
| 1012 | + return ret; | |
| 1013 | + } | |
| 1014 | + | |
| 1015 | + ret = e5010_hw_enable_picture_done_irq(e5010->core_base, 1); | |
| 1016 | + if (ret) | |
| 1017 | + v4l2_err(&e5010->v4l2_dev, "failed to enable Picture Done interrupts\n"); | |
| 1018 | + | |
| 1019 | + return ret; | |
| 1020 | +} | |
| 1021 | + | |
| 1022 | +static int e5010_probe(struct platform_device *pdev) | |
| 1023 | +{ | |
| 1024 | + struct e5010_dev *e5010; | |
| 1025 | + int irq, ret = 0; | |
| 1026 | + struct device *dev = &pdev->dev; | |
| 1027 | + | |
| 1028 | + ret = dma_set_mask(dev, DMA_BIT_MASK(32)); | |
| 1029 | + if (ret) | |
| 1030 | + return dev_err_probe(dev, ret, "32-bit consistent DMA enable failed\n"); | |
| 1031 | + | |
| 1032 | + e5010 = devm_kzalloc(dev, sizeof(*e5010), GFP_KERNEL); | |
| 1033 | + if (!e5010) | |
| 1034 | + return -ENOMEM; | |
| 1035 | + | |
| 1036 | + platform_set_drvdata(pdev, e5010); | |
| 1037 | + | |
| 1038 | + e5010->dev = dev; | |
| 1039 | + | |
| 1040 | + mutex_init(&e5010->mutex); | |
| 1041 | + spin_lock_init(&e5010->hw_lock); | |
| 1042 | + | |
| 1043 | + e5010->vdev = video_device_alloc(); | |
| 1044 | + if (!e5010->vdev) { | |
| 1045 | + dev_err(dev, "failed to allocate video device\n"); | |
| 1046 | + return -ENOMEM; | |
| 1047 | + } | |
| 1048 | + | |
| 1049 | + snprintf(e5010->vdev->name, sizeof(e5010->vdev->name), "%s", E5010_MODULE_NAME); | |
| 1050 | + e5010->vdev->fops = &e5010_fops; | |
| 1051 | + e5010->vdev->ioctl_ops = &e5010_ioctl_ops; | |
| 1052 | + e5010->vdev->minor = -1; | |
| 1053 | + e5010->vdev->release = video_device_release; | |
| 1054 | + e5010->vdev->vfl_dir = VFL_DIR_M2M; | |
| 1055 | + e5010->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING; | |
| 1056 | + e5010->vdev->v4l2_dev = &e5010->v4l2_dev; | |
| 1057 | + e5010->vdev->lock = &e5010->mutex; | |
| 1058 | + | |
| 1059 | + ret = v4l2_device_register(dev, &e5010->v4l2_dev); | |
| 1060 | + if (ret) | |
| 1061 | + return dev_err_probe(dev, ret, "failed to register v4l2 device\n"); | |
| 1062 | + | |
| 1063 | + e5010->m2m_dev = v4l2_m2m_init(&e5010_m2m_ops); | |
| 1064 | + if (IS_ERR(e5010->m2m_dev)) { | |
| 1065 | + ret = PTR_ERR(e5010->m2m_dev); | |
| 1066 | + e5010->m2m_dev = NULL; | |
| 1067 | + dev_err_probe(dev, ret, "failed to init mem2mem device\n"); | |
| 1068 | + goto fail_after_v4l2_register; | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + video_set_drvdata(e5010->vdev, e5010); | |
| 1072 | + | |
| 1073 | + e5010->core_base = devm_platform_ioremap_resource_byname(pdev, "core"); | |
| 1074 | + if (IS_ERR(e5010->core_base)) { | |
| 1075 | + ret = PTR_ERR(e5010->core_base); | |
| 1076 | + dev_err_probe(dev, ret, "Missing 'core' resources area\n"); | |
| 1077 | + goto fail_after_v4l2_register; | |
| 1078 | + } | |
| 1079 | + | |
| 1080 | + e5010->mmu_base = devm_platform_ioremap_resource_byname(pdev, "mmu"); | |
| 1081 | + if (IS_ERR(e5010->mmu_base)) { | |
| 1082 | + ret = PTR_ERR(e5010->mmu_base); | |
| 1083 | + dev_err_probe(dev, ret, "Missing 'mmu' resources area\n"); | |
| 1084 | + goto fail_after_v4l2_register; | |
| 1085 | + } | |
| 1086 | + | |
| 1087 | + e5010->last_context_run = NULL; | |
| 1088 | + | |
| 1089 | + irq = platform_get_irq(pdev, 0); | |
| 1090 | + ret = devm_request_irq(dev, irq, e5010_irq, 0, | |
| 1091 | + E5010_MODULE_NAME, e5010); | |
| 1092 | + if (ret) { | |
| 1093 | + dev_err_probe(dev, ret, "failed to register IRQ %d\n", irq); | |
| 1094 | + goto fail_after_v4l2_register; | |
| 1095 | + } | |
| 1096 | + | |
| 1097 | + e5010->clk = devm_clk_get(dev, NULL); | |
| 1098 | + if (IS_ERR(e5010->clk)) { | |
| 1099 | + ret = PTR_ERR(e5010->clk); | |
| 1100 | + dev_err_probe(dev, ret, "failed to get clock\n"); | |
| 1101 | + goto fail_after_v4l2_register; | |
| 1102 | + } | |
| 1103 | + | |
| 1104 | + pm_runtime_enable(dev); | |
| 1105 | + | |
| 1106 | + ret = video_register_device(e5010->vdev, VFL_TYPE_VIDEO, 0); | |
| 1107 | + if (ret) { | |
| 1108 | + dev_err_probe(dev, ret, "failed to register video device\n"); | |
| 1109 | + goto fail_after_video_register_device; | |
| 1110 | + } | |
| 1111 | + | |
| 1112 | + v4l2_info(&e5010->v4l2_dev, "Device registered as /dev/video%d\n", | |
| 1113 | + e5010->vdev->num); | |
| 1114 | + | |
| 1115 | + return 0; | |
| 1116 | + | |
| 1117 | +fail_after_video_register_device: | |
| 1118 | + v4l2_m2m_release(e5010->m2m_dev); | |
| 1119 | +fail_after_v4l2_register: | |
| 1120 | + v4l2_device_unregister(&e5010->v4l2_dev); | |
| 1121 | + return ret; | |
| 1122 | +} | |
| 1123 | + | |
| 1124 | +static void e5010_remove(struct platform_device *pdev) | |
| 1125 | +{ | |
| 1126 | + struct e5010_dev *e5010 = platform_get_drvdata(pdev); | |
| 1127 | + | |
| 1128 | + pm_runtime_disable(e5010->dev); | |
| 1129 | + video_unregister_device(e5010->vdev); | |
| 1130 | + v4l2_m2m_release(e5010->m2m_dev); | |
| 1131 | + v4l2_device_unregister(&e5010->v4l2_dev); | |
| 1132 | +} | |
| 1133 | + | |
| 1134 | +static void e5010_vb2_buffers_return(struct vb2_queue *q, enum vb2_buffer_state state) | |
| 1135 | +{ | |
| 1136 | + struct vb2_v4l2_buffer *vbuf; | |
| 1137 | + struct e5010_context *ctx = vb2_get_drv_priv(q); | |
| 1138 | + | |
| 1139 | + if (V4L2_TYPE_IS_OUTPUT(q->type)) { | |
| 1140 | + while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) { | |
| 1141 | + dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n", | |
| 1142 | + ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index); | |
| 1143 | + v4l2_m2m_buf_done(vbuf, state); | |
| 1144 | + } | |
| 1145 | + } else { | |
| 1146 | + while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) { | |
| 1147 | + dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n", | |
| 1148 | + ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index); | |
| 1149 | + vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0); | |
| 1150 | + v4l2_m2m_buf_done(vbuf, state); | |
| 1151 | + } | |
| 1152 | + } | |
| 1153 | +} | |
| 1154 | + | |
| 1155 | +static int e5010_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes, | |
| 1156 | + unsigned int sizes[], struct device *alloc_devs[]) | |
| 1157 | +{ | |
| 1158 | + struct e5010_context *ctx = vb2_get_drv_priv(vq); | |
| 1159 | + struct e5010_q_data *queue; | |
| 1160 | + int i; | |
| 1161 | + | |
| 1162 | + queue = get_queue(ctx, vq->type); | |
| 1163 | + | |
| 1164 | + if (*nplanes) { | |
| 1165 | + if (*nplanes != queue->fmt->num_planes) | |
| 1166 | + return -EINVAL; | |
| 1167 | + for (i = 0; i < *nplanes; i++) { | |
| 1168 | + if (sizes[i] < queue->sizeimage[i]) | |
| 1169 | + return -EINVAL; | |
| 1170 | + } | |
| 1171 | + return 0; | |
| 1172 | + } | |
| 1173 | + | |
| 1174 | + *nplanes = queue->fmt->num_planes; | |
| 1175 | + for (i = 0; i < *nplanes; i++) | |
| 1176 | + sizes[i] = queue->sizeimage[i]; | |
| 1177 | + | |
| 1178 | + dprintk(ctx->e5010, 2, | |
| 1179 | + "ctx: 0x%p, type %s, buffer(s): %d, planes %d, plane1: bytes %d plane2: %d bytes\n", | |
| 1180 | + ctx, type_name(vq->type), *nbuffers, *nplanes, sizes[0], sizes[1]); | |
| 1181 | + | |
| 1182 | + return 0; | |
| 1183 | +} | |
| 1184 | + | |
| 1185 | +static void e5010_buf_finish(struct vb2_buffer *vb) | |
| 1186 | +{ | |
| 1187 | + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 1188 | + void *d_addr; | |
| 1189 | + | |
| 1190 | + if (vb->state != VB2_BUF_STATE_DONE || V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type)) | |
| 1191 | + return; | |
| 1192 | + | |
| 1193 | + d_addr = vb2_plane_vaddr(vb, 0); | |
| 1194 | + write_header(ctx, d_addr); | |
| 1195 | +} | |
| 1196 | + | |
| 1197 | +static int e5010_buf_out_validate(struct vb2_buffer *vb) | |
| 1198 | +{ | |
| 1199 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 1200 | + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 1201 | + | |
| 1202 | + if (vbuf->field != V4L2_FIELD_NONE) | |
| 1203 | + dprintk(ctx->e5010, 1, "ctx: 0x%p, field isn't supported\n", ctx); | |
| 1204 | + | |
| 1205 | + vbuf->field = V4L2_FIELD_NONE; | |
| 1206 | + | |
| 1207 | + return 0; | |
| 1208 | +} | |
| 1209 | + | |
| 1210 | +static int e5010_buf_prepare(struct vb2_buffer *vb) | |
| 1211 | +{ | |
| 1212 | + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 1213 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 1214 | + struct e5010_q_data *queue; | |
| 1215 | + int i; | |
| 1216 | + | |
| 1217 | + vbuf->field = V4L2_FIELD_NONE; | |
| 1218 | + | |
| 1219 | + queue = get_queue(ctx, vb->vb2_queue->type); | |
| 1220 | + | |
| 1221 | + for (i = 0; i < queue->fmt->num_planes; i++) { | |
| 1222 | + if (vb2_plane_size(vb, i) < (unsigned long)queue->sizeimage[i]) { | |
| 1223 | + v4l2_err(&ctx->e5010->v4l2_dev, "plane %d too small (%lu < %lu)", i, | |
| 1224 | + vb2_plane_size(vb, i), (unsigned long)queue->sizeimage[i]); | |
| 1225 | + | |
| 1226 | + return -EINVAL; | |
| 1227 | + } | |
| 1228 | + } | |
| 1229 | + | |
| 1230 | + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type)) { | |
| 1231 | + vb2_set_plane_payload(vb, 0, 0); | |
| 1232 | + vb2_set_plane_payload(vb, 1, 0); | |
| 1233 | + } | |
| 1234 | + | |
| 1235 | + return 0; | |
| 1236 | +} | |
| 1237 | + | |
| 1238 | +static void e5010_buf_queue(struct vb2_buffer *vb) | |
| 1239 | +{ | |
| 1240 | + struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue); | |
| 1241 | + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); | |
| 1242 | + | |
| 1243 | + if (V4L2_TYPE_IS_CAPTURE(vb->vb2_queue->type) && | |
| 1244 | + vb2_is_streaming(vb->vb2_queue) && | |
| 1245 | + v4l2_m2m_dst_buf_is_last(ctx->fh.m2m_ctx)) { | |
| 1246 | + struct e5010_q_data *queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 1247 | + | |
| 1248 | + vbuf->sequence = queue->sequence++; | |
| 1249 | + v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf); | |
| 1250 | + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); | |
| 1251 | + return; | |
| 1252 | + } | |
| 1253 | + | |
| 1254 | + v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf); | |
| 1255 | +} | |
| 1256 | + | |
| 1257 | +static int e5010_encoder_cmd(struct file *file, void *priv, | |
| 1258 | + struct v4l2_encoder_cmd *cmd) | |
| 1259 | +{ | |
| 1260 | + struct e5010_context *ctx = file->private_data; | |
| 1261 | + int ret; | |
| 1262 | + struct vb2_queue *cap_vq; | |
| 1263 | + | |
| 1264 | + cap_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); | |
| 1265 | + | |
| 1266 | + ret = v4l2_m2m_ioctl_try_encoder_cmd(file, &ctx->fh, cmd); | |
| 1267 | + if (ret < 0) | |
| 1268 | + return ret; | |
| 1269 | + | |
| 1270 | + if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) || | |
| 1271 | + !vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx))) | |
| 1272 | + return 0; | |
| 1273 | + | |
| 1274 | + ret = v4l2_m2m_ioctl_encoder_cmd(file, &ctx->fh, cmd); | |
| 1275 | + if (ret < 0) | |
| 1276 | + return ret; | |
| 1277 | + | |
| 1278 | + if (cmd->cmd == V4L2_ENC_CMD_STOP && | |
| 1279 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1280 | + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); | |
| 1281 | + | |
| 1282 | + if (cmd->cmd == V4L2_ENC_CMD_START && | |
| 1283 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) | |
| 1284 | + vb2_clear_last_buffer_dequeued(cap_vq); | |
| 1285 | + | |
| 1286 | + return 0; | |
| 1287 | +} | |
| 1288 | + | |
| 1289 | +static int e5010_start_streaming(struct vb2_queue *q, unsigned int count) | |
| 1290 | +{ | |
| 1291 | + struct e5010_context *ctx = vb2_get_drv_priv(q); | |
| 1292 | + int ret; | |
| 1293 | + | |
| 1294 | + struct e5010_q_data *queue = get_queue(ctx, q->type); | |
| 1295 | + | |
| 1296 | + v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q); | |
| 1297 | + queue->sequence = 0; | |
| 1298 | + | |
| 1299 | + ret = pm_runtime_resume_and_get(ctx->e5010->dev); | |
| 1300 | + if (ret < 0) { | |
| 1301 | + v4l2_err(&ctx->e5010->v4l2_dev, "failed to power up jpeg\n"); | |
| 1302 | + goto fail; | |
| 1303 | + } | |
| 1304 | + | |
| 1305 | + ret = e5010_init_device(ctx->e5010); | |
| 1306 | + if (ret) { | |
| 1307 | + v4l2_err(&ctx->e5010->v4l2_dev, "failed to Enable e5010 device\n"); | |
| 1308 | + goto fail; | |
| 1309 | + } | |
| 1310 | + | |
| 1311 | + return 0; | |
| 1312 | + | |
| 1313 | +fail: | |
| 1314 | + e5010_vb2_buffers_return(q, VB2_BUF_STATE_QUEUED); | |
| 1315 | + | |
| 1316 | + return ret; | |
| 1317 | +} | |
| 1318 | + | |
| 1319 | +static void e5010_stop_streaming(struct vb2_queue *q) | |
| 1320 | +{ | |
| 1321 | + struct e5010_context *ctx = vb2_get_drv_priv(q); | |
| 1322 | + | |
| 1323 | + e5010_vb2_buffers_return(q, VB2_BUF_STATE_ERROR); | |
| 1324 | + | |
| 1325 | + if (V4L2_TYPE_IS_OUTPUT(q->type)) | |
| 1326 | + v4l2_m2m_update_stop_streaming_state(ctx->fh.m2m_ctx, q); | |
| 1327 | + | |
| 1328 | + if (V4L2_TYPE_IS_OUTPUT(q->type) && | |
| 1329 | + v4l2_m2m_has_stopped(ctx->fh.m2m_ctx)) { | |
| 1330 | + v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event); | |
| 1331 | + } | |
| 1332 | + | |
| 1333 | + pm_runtime_put_sync(ctx->e5010->dev); | |
| 1334 | +} | |
| 1335 | + | |
| 1336 | +static void e5010_device_run(void *priv) | |
| 1337 | +{ | |
| 1338 | + struct e5010_context *ctx = priv; | |
| 1339 | + struct e5010_dev *e5010 = ctx->e5010; | |
| 1340 | + struct vb2_v4l2_buffer *s_vb, *d_vb; | |
| 1341 | + u32 reg = 0; | |
| 1342 | + int ret = 0, luma_crop_offset = 0, chroma_crop_offset = 0; | |
| 1343 | + unsigned long flags; | |
| 1344 | + int num_planes = ctx->out_queue.fmt->num_planes; | |
| 1345 | + | |
| 1346 | + spin_lock_irqsave(&e5010->hw_lock, flags); | |
| 1347 | + s_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); | |
| 1348 | + WARN_ON(!s_vb); | |
| 1349 | + d_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); | |
| 1350 | + WARN_ON(!d_vb); | |
| 1351 | + if (!s_vb || !d_vb) | |
| 1352 | + goto no_ready_buf_err; | |
| 1353 | + | |
| 1354 | + s_vb->sequence = ctx->out_queue.sequence++; | |
| 1355 | + d_vb->sequence = ctx->cap_queue.sequence++; | |
| 1356 | + | |
| 1357 | + v4l2_m2m_buf_copy_metadata(s_vb, d_vb, false); | |
| 1358 | + | |
| 1359 | + if (ctx != e5010->last_context_run || ctx->update_qp) { | |
| 1360 | + dprintk(e5010, 1, "ctx updated: 0x%p -> 0x%p, updating qp tables\n", | |
| 1361 | + e5010->last_context_run, ctx); | |
| 1362 | + ret = update_qp_tables(ctx); | |
| 1363 | + } | |
| 1364 | + | |
| 1365 | + if (ret) { | |
| 1366 | + ctx->update_qp = true; | |
| 1367 | + v4l2_err(&e5010->v4l2_dev, "failed to update QP tables\n"); | |
| 1368 | + goto device_busy_err; | |
| 1369 | + } else { | |
| 1370 | + e5010->last_context_run = ctx; | |
| 1371 | + ctx->update_qp = false; | |
| 1372 | + } | |
| 1373 | + | |
| 1374 | + /* Set I/O Buffer addresses */ | |
| 1375 | + reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0); | |
| 1376 | + | |
| 1377 | + if (ctx->out_queue.crop_set) { | |
| 1378 | + luma_crop_offset = ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top + | |
| 1379 | + ctx->out_queue.crop.left; | |
| 1380 | + | |
| 1381 | + if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) { | |
| 1382 | + chroma_crop_offset = | |
| 1383 | + ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top | |
| 1384 | + + ctx->out_queue.crop.left; | |
| 1385 | + } else { | |
| 1386 | + chroma_crop_offset = | |
| 1387 | + ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top / 2 | |
| 1388 | + + ctx->out_queue.crop.left; | |
| 1389 | + } | |
| 1390 | + | |
| 1391 | + dprintk(e5010, 1, "Luma crop offset : %x, chroma crop offset : %x\n", | |
| 1392 | + luma_crop_offset, chroma_crop_offset); | |
| 1393 | + } | |
| 1394 | + | |
| 1395 | + ret = e5010_hw_set_input_luma_addr(e5010->core_base, reg + luma_crop_offset); | |
| 1396 | + if (ret || !reg) { | |
| 1397 | + v4l2_err(&e5010->v4l2_dev, "failed to set input luma address\n"); | |
| 1398 | + goto device_busy_err; | |
| 1399 | + } | |
| 1400 | + | |
| 1401 | + if (num_planes == 1) | |
| 1402 | + reg += (ctx->out_queue.bytesperline[0]) * (ctx->out_queue.height); | |
| 1403 | + else | |
| 1404 | + reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 1); | |
| 1405 | + | |
| 1406 | + dprintk(e5010, 3, | |
| 1407 | + "ctx: 0x%p, luma_addr: 0x%x, chroma_addr: 0x%x, out_addr: 0x%x\n", | |
| 1408 | + ctx, (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0) + luma_crop_offset, | |
| 1409 | + reg + chroma_crop_offset, (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0)); | |
| 1410 | + | |
| 1411 | + dprintk(e5010, 3, | |
| 1412 | + "ctx: 0x%p, buf indices: src_index: %d, dst_index: %d\n", | |
| 1413 | + ctx, s_vb->vb2_buf.index, d_vb->vb2_buf.index); | |
| 1414 | + | |
| 1415 | + ret = e5010_hw_set_input_chroma_addr(e5010->core_base, reg + chroma_crop_offset); | |
| 1416 | + if (ret || !reg) { | |
| 1417 | + v4l2_err(&e5010->v4l2_dev, "failed to set input chroma address\n"); | |
| 1418 | + goto device_busy_err; | |
| 1419 | + } | |
| 1420 | + | |
| 1421 | + reg = (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0); | |
| 1422 | + reg += HEADER_SIZE; | |
| 1423 | + ret = e5010_hw_set_output_base_addr(e5010->core_base, reg); | |
| 1424 | + if (ret || !reg) { | |
| 1425 | + v4l2_err(&e5010->v4l2_dev, "failed to set output base address\n"); | |
| 1426 | + goto device_busy_err; | |
| 1427 | + } | |
| 1428 | + | |
| 1429 | + /* Set input settings */ | |
| 1430 | + ret = e5010_hw_set_horizontal_size(e5010->core_base, ctx->out_queue.crop.width - 1); | |
| 1431 | + if (ret) { | |
| 1432 | + v4l2_err(&e5010->v4l2_dev, "failed to set input width\n"); | |
| 1433 | + goto device_busy_err; | |
| 1434 | + } | |
| 1435 | + | |
| 1436 | + ret = e5010_hw_set_vertical_size(e5010->core_base, ctx->out_queue.crop.height - 1); | |
| 1437 | + if (ret) { | |
| 1438 | + v4l2_err(&e5010->v4l2_dev, "failed to set input width\n"); | |
| 1439 | + goto device_busy_err; | |
| 1440 | + } | |
| 1441 | + | |
| 1442 | + ret = e5010_hw_set_luma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]); | |
| 1443 | + if (ret) { | |
| 1444 | + v4l2_err(&e5010->v4l2_dev, "failed to set luma stride\n"); | |
| 1445 | + goto device_busy_err; | |
| 1446 | + } | |
| 1447 | + | |
| 1448 | + ret = e5010_hw_set_chroma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]); | |
| 1449 | + if (ret) { | |
| 1450 | + v4l2_err(&e5010->v4l2_dev, "failed to set chroma stride\n"); | |
| 1451 | + goto device_busy_err; | |
| 1452 | + } | |
| 1453 | + | |
| 1454 | + ret = e5010_set_input_subsampling(e5010->core_base, ctx->out_queue.fmt->subsampling); | |
| 1455 | + if (ret) { | |
| 1456 | + v4l2_err(&e5010->v4l2_dev, "failed to set input subsampling\n"); | |
| 1457 | + goto device_busy_err; | |
| 1458 | + } | |
| 1459 | + | |
| 1460 | + ret = e5010_hw_set_chroma_order(e5010->core_base, ctx->out_queue.fmt->chroma_order); | |
| 1461 | + if (ret) { | |
| 1462 | + v4l2_err(&e5010->v4l2_dev, "failed to set chroma order\n"); | |
| 1463 | + goto device_busy_err; | |
| 1464 | + } | |
| 1465 | + | |
| 1466 | + e5010_hw_set_output_max_size(e5010->core_base, d_vb->planes[0].length); | |
| 1467 | + e5010_hw_encode_start(e5010->core_base, 1); | |
| 1468 | + | |
| 1469 | + spin_unlock_irqrestore(&e5010->hw_lock, flags); | |
| 1470 | + | |
| 1471 | + return; | |
| 1472 | + | |
| 1473 | +device_busy_err: | |
| 1474 | + e5010_reset(e5010->dev, e5010->core_base, e5010->mmu_base); | |
| 1475 | + | |
| 1476 | +no_ready_buf_err: | |
| 1477 | + if (s_vb) { | |
| 1478 | + v4l2_m2m_src_buf_remove_by_buf(ctx->fh.m2m_ctx, s_vb); | |
| 1479 | + v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_ERROR); | |
| 1480 | + } | |
| 1481 | + | |
| 1482 | + if (d_vb) { | |
| 1483 | + v4l2_m2m_dst_buf_remove_by_buf(ctx->fh.m2m_ctx, d_vb); | |
| 1484 | + /* Payload set to 1 since 0 payload can trigger EOS */ | |
| 1485 | + vb2_set_plane_payload(&d_vb->vb2_buf, 0, 1); | |
| 1486 | + v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_ERROR); | |
| 1487 | + } | |
| 1488 | + v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx); | |
| 1489 | + spin_unlock_irqrestore(&e5010->hw_lock, flags); | |
| 1490 | +} | |
| 1491 | + | |
| 1492 | +#ifdef CONFIG_PM | |
| 1493 | +static int e5010_runtime_resume(struct device *dev) | |
| 1494 | +{ | |
| 1495 | + struct e5010_dev *e5010 = dev_get_drvdata(dev); | |
| 1496 | + int ret; | |
| 1497 | + | |
| 1498 | + ret = clk_prepare_enable(e5010->clk); | |
| 1499 | + if (ret < 0) { | |
| 1500 | + v4l2_err(&e5010->v4l2_dev, "failed to enable clock\n"); | |
| 1501 | + return ret; | |
| 1502 | + } | |
| 1503 | + | |
| 1504 | + return 0; | |
| 1505 | +} | |
| 1506 | + | |
| 1507 | +static int e5010_runtime_suspend(struct device *dev) | |
| 1508 | +{ | |
| 1509 | + struct e5010_dev *e5010 = dev_get_drvdata(dev); | |
| 1510 | + | |
| 1511 | + clk_disable_unprepare(e5010->clk); | |
| 1512 | + | |
| 1513 | + return 0; | |
| 1514 | +} | |
| 1515 | +#endif | |
| 1516 | + | |
| 1517 | +#ifdef CONFIG_PM_SLEEP | |
| 1518 | +static int e5010_suspend(struct device *dev) | |
| 1519 | +{ | |
| 1520 | + struct e5010_dev *e5010 = dev_get_drvdata(dev); | |
| 1521 | + | |
| 1522 | + v4l2_m2m_suspend(e5010->m2m_dev); | |
| 1523 | + | |
| 1524 | + return pm_runtime_force_suspend(dev); | |
| 1525 | +} | |
| 1526 | + | |
| 1527 | +static int e5010_resume(struct device *dev) | |
| 1528 | +{ | |
| 1529 | + struct e5010_dev *e5010 = dev_get_drvdata(dev); | |
| 1530 | + int ret; | |
| 1531 | + | |
| 1532 | + ret = pm_runtime_force_resume(dev); | |
| 1533 | + if (ret < 0) | |
| 1534 | + return ret; | |
| 1535 | + | |
| 1536 | + ret = e5010_init_device(e5010); | |
| 1537 | + if (ret) { | |
| 1538 | + dev_err(dev, "Failed to re-enable e5010 device\n"); | |
| 1539 | + return ret; | |
| 1540 | + } | |
| 1541 | + | |
| 1542 | + v4l2_m2m_resume(e5010->m2m_dev); | |
| 1543 | + | |
| 1544 | + return ret; | |
| 1545 | +} | |
| 1546 | +#endif | |
| 1547 | + | |
| 1548 | +static const struct dev_pm_ops e5010_pm_ops = { | |
| 1549 | + SET_RUNTIME_PM_OPS(e5010_runtime_suspend, | |
| 1550 | + e5010_runtime_resume, NULL) | |
| 1551 | + SET_SYSTEM_SLEEP_PM_OPS(e5010_suspend, e5010_resume) | |
| 1552 | +}; | |
| 1553 | + | |
| 1554 | +static const struct v4l2_ioctl_ops e5010_ioctl_ops = { | |
| 1555 | + .vidioc_querycap = e5010_querycap, | |
| 1556 | + | |
| 1557 | + .vidioc_enum_fmt_vid_cap = e5010_enum_fmt, | |
| 1558 | + .vidioc_g_fmt_vid_cap_mplane = e5010_g_fmt, | |
| 1559 | + .vidioc_try_fmt_vid_cap_mplane = e5010_try_fmt, | |
| 1560 | + .vidioc_s_fmt_vid_cap_mplane = e5010_s_fmt, | |
| 1561 | + | |
| 1562 | + .vidioc_enum_fmt_vid_out = e5010_enum_fmt, | |
| 1563 | + .vidioc_g_fmt_vid_out_mplane = e5010_g_fmt, | |
| 1564 | + .vidioc_try_fmt_vid_out_mplane = e5010_try_fmt, | |
| 1565 | + .vidioc_s_fmt_vid_out_mplane = e5010_s_fmt, | |
| 1566 | + | |
| 1567 | + .vidioc_g_selection = e5010_g_selection, | |
| 1568 | + .vidioc_s_selection = e5010_s_selection, | |
| 1569 | + | |
| 1570 | + .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs, | |
| 1571 | + .vidioc_querybuf = v4l2_m2m_ioctl_querybuf, | |
| 1572 | + .vidioc_qbuf = v4l2_m2m_ioctl_qbuf, | |
| 1573 | + .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf, | |
| 1574 | + .vidioc_expbuf = v4l2_m2m_ioctl_expbuf, | |
| 1575 | + .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs, | |
| 1576 | + .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf, | |
| 1577 | + | |
| 1578 | + .vidioc_streamon = v4l2_m2m_ioctl_streamon, | |
| 1579 | + .vidioc_streamoff = v4l2_m2m_ioctl_streamoff, | |
| 1580 | + .vidioc_log_status = v4l2_ctrl_log_status, | |
| 1581 | + | |
| 1582 | + .vidioc_subscribe_event = e5010_subscribe_event, | |
| 1583 | + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, | |
| 1584 | + .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd, | |
| 1585 | + .vidioc_encoder_cmd = e5010_encoder_cmd, | |
| 1586 | + | |
| 1587 | + .vidioc_enum_framesizes = e5010_enum_framesizes, | |
| 1588 | +}; | |
| 1589 | + | |
| 1590 | +static const struct vb2_ops e5010_video_ops = { | |
| 1591 | + .queue_setup = e5010_queue_setup, | |
| 1592 | + .buf_queue = e5010_buf_queue, | |
| 1593 | + .buf_finish = e5010_buf_finish, | |
| 1594 | + .buf_prepare = e5010_buf_prepare, | |
| 1595 | + .buf_out_validate = e5010_buf_out_validate, | |
| 1596 | + .wait_prepare = vb2_ops_wait_prepare, | |
| 1597 | + .wait_finish = vb2_ops_wait_finish, | |
| 1598 | + .start_streaming = e5010_start_streaming, | |
| 1599 | + .stop_streaming = e5010_stop_streaming, | |
| 1600 | +}; | |
| 1601 | + | |
| 1602 | +static const struct v4l2_file_operations e5010_fops = { | |
| 1603 | + .owner = THIS_MODULE, | |
| 1604 | + .open = e5010_open, | |
| 1605 | + .release = e5010_release, | |
| 1606 | + .poll = v4l2_m2m_fop_poll, | |
| 1607 | + .unlocked_ioctl = video_ioctl2, | |
| 1608 | + .mmap = v4l2_m2m_fop_mmap, | |
| 1609 | +}; | |
| 1610 | + | |
| 1611 | +static const struct v4l2_m2m_ops e5010_m2m_ops = { | |
| 1612 | + .device_run = e5010_device_run, | |
| 1613 | +}; | |
| 1614 | + | |
| 1615 | +static const struct of_device_id e5010_of_match[] = { | |
| 1616 | + {.compatible = "img,e5010-jpeg-enc"}, { /* end */}, | |
| 1617 | +}; | |
| 1618 | +MODULE_DEVICE_TABLE(of, e5010_of_match); | |
| 1619 | + | |
| 1620 | +static struct platform_driver e5010_driver = { | |
| 1621 | + .probe = e5010_probe, | |
| 1622 | + .remove_new = e5010_remove, | |
| 1623 | + .driver = { | |
| 1624 | + .name = E5010_MODULE_NAME, | |
| 1625 | + .of_match_table = e5010_of_match, | |
| 1626 | + .pm = &e5010_pm_ops, | |
| 1627 | + }, | |
| 1628 | +}; | |
| 1629 | +module_platform_driver(e5010_driver); | |
| 1630 | + | |
| 1631 | +MODULE_LICENSE("GPL"); | |
| 1632 | +MODULE_DESCRIPTION("Imagination E5010 JPEG encoder driver"); | |
| @@ -0,0 +1,168 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Imagination E5010 JPEG Encoder driver. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ | |
| 6 | + * | |
| 7 | + * Author: David Huang <d-huang@ti.com> | |
| 8 | + * Author: Devarsh Thakkar <devarsht@ti.com> | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include <media/v4l2-ctrls.h> | |
| 12 | +#include <media/v4l2-device.h> | |
| 13 | +#include <media/v4l2-fh.h> | |
| 14 | + | |
| 15 | +#ifndef _E5010_JPEG_ENC_H | |
| 16 | +#define _E5010_JPEG_ENC_H | |
| 17 | + | |
| 18 | +#define MAX_PLANES 2 | |
| 19 | +#define HEADER_SIZE 0x025D | |
| 20 | +#define MIN_DIMENSION 64 | |
| 21 | +#define MAX_DIMENSION 8192 | |
| 22 | +#define DEFAULT_WIDTH 640 | |
| 23 | +#define DEFAULT_HEIGHT 480 | |
| 24 | +#define E5010_MODULE_NAME "e5010" | |
| 25 | +#define JPEG_MAX_BYTES_PER_PIXEL 2 | |
| 26 | + | |
| 27 | +/* JPEG marker definitions */ | |
| 28 | +#define START_OF_IMAGE 0xFFD8 | |
| 29 | +#define SOF_BASELINE_DCT 0xFFC0 | |
| 30 | +#define END_OF_IMAGE 0xFFD9 | |
| 31 | +#define START_OF_SCAN 0xFFDA | |
| 32 | + | |
| 33 | +/* Definitions for the huffman table specification in the Marker segment */ | |
| 34 | +#define DHT_MARKER 0xFFC4 | |
| 35 | +#define LH_DC 0x001F | |
| 36 | +#define LH_AC 0x00B5 | |
| 37 | + | |
| 38 | +/* Definitions for the quantization table specification in the Marker segment */ | |
| 39 | +#define DQT_MARKER 0xFFDB | |
| 40 | +#define ACMAX 0x03FF | |
| 41 | +#define DCMAX 0x07FF | |
| 42 | + | |
| 43 | +/* Length and precision of the quantization table parameters */ | |
| 44 | +#define LQPQ 0x00430 | |
| 45 | +#define QMAX 255 | |
| 46 | + | |
| 47 | +/* Misc JPEG header definitions */ | |
| 48 | +#define UC_NUM_COMP 3 | |
| 49 | +#define PRECISION 8 | |
| 50 | +#define HORZ_SAMPLING_FACTOR (2 << 4) | |
| 51 | +#define VERT_SAMPLING_FACTOR_422 1 | |
| 52 | +#define VERT_SAMPLING_FACTOR_420 2 | |
| 53 | +#define COMPONENTS_IN_SCAN 3 | |
| 54 | +#define PELS_IN_BLOCK 64 | |
| 55 | + | |
| 56 | +/* Used for Qp table generation */ | |
| 57 | +#define LUMINOSITY 10 | |
| 58 | +#define CONTRAST 1 | |
| 59 | +#define INCREASE 2 | |
| 60 | +#define QP_TABLE_SIZE (8 * 8) | |
| 61 | +#define QP_TABLE_FIELD_OFFSET 0x04 | |
| 62 | + | |
| 63 | +/* | |
| 64 | + * vb2 queue structure | |
| 65 | + * contains queue data information | |
| 66 | + * | |
| 67 | + * @fmt: format info | |
| 68 | + * @width: frame width | |
| 69 | + * @height: frame height | |
| 70 | + * @bytesperline: bytes per line in memory | |
| 71 | + * @size_image: image size in memory | |
| 72 | + */ | |
| 73 | +struct e5010_q_data { | |
| 74 | + struct e5010_fmt *fmt; | |
| 75 | + u32 width; | |
| 76 | + u32 height; | |
| 77 | + u32 width_adjusted; | |
| 78 | + u32 height_adjusted; | |
| 79 | + u32 sizeimage[MAX_PLANES]; | |
| 80 | + u32 bytesperline[MAX_PLANES]; | |
| 81 | + u32 sequence; | |
| 82 | + struct v4l2_rect crop; | |
| 83 | + bool crop_set; | |
| 84 | +}; | |
| 85 | + | |
| 86 | +/* | |
| 87 | + * Driver device structure | |
| 88 | + * Holds all memory handles and global parameters | |
| 89 | + * Shared by all instances | |
| 90 | + */ | |
| 91 | +struct e5010_dev { | |
| 92 | + struct device *dev; | |
| 93 | + struct v4l2_device v4l2_dev; | |
| 94 | + struct v4l2_m2m_dev *m2m_dev; | |
| 95 | + struct video_device *vdev; | |
| 96 | + void __iomem *core_base; | |
| 97 | + void __iomem *mmu_base; | |
| 98 | + struct clk *clk; | |
| 99 | + struct e5010_context *last_context_run; | |
| 100 | + /* Protect access to device data */ | |
| 101 | + struct mutex mutex; | |
| 102 | + /* Protect access to hardware*/ | |
| 103 | + spinlock_t hw_lock; | |
| 104 | +}; | |
| 105 | + | |
| 106 | +/* | |
| 107 | + * Driver context structure | |
| 108 | + * One of these exists for every m2m context | |
| 109 | + * Holds context specific data | |
| 110 | + */ | |
| 111 | +struct e5010_context { | |
| 112 | + struct v4l2_fh fh; | |
| 113 | + struct e5010_dev *e5010; | |
| 114 | + struct e5010_q_data out_queue; | |
| 115 | + struct e5010_q_data cap_queue; | |
| 116 | + int quality; | |
| 117 | + bool update_qp; | |
| 118 | + struct v4l2_ctrl_handler ctrl_handler; | |
| 119 | + u8 luma_qp[QP_TABLE_SIZE]; | |
| 120 | + u8 chroma_qp[QP_TABLE_SIZE]; | |
| 121 | +}; | |
| 122 | + | |
| 123 | +/* | |
| 124 | + * Buffer structure | |
| 125 | + * Contains info for all buffers | |
| 126 | + */ | |
| 127 | +struct e5010_buffer { | |
| 128 | + struct v4l2_m2m_buffer buffer; | |
| 129 | +}; | |
| 130 | + | |
| 131 | +enum { | |
| 132 | + CHROMA_ORDER_CB_CR = 0, //UV ordering | |
| 133 | + CHROMA_ORDER_CR_CB = 1, //VU ordering | |
| 134 | +}; | |
| 135 | + | |
| 136 | +enum { | |
| 137 | + SUBSAMPLING_420 = 1, | |
| 138 | + SUBSAMPLING_422 = 2, | |
| 139 | +}; | |
| 140 | + | |
| 141 | +/* | |
| 142 | + * e5010 format structure | |
| 143 | + * contains format information | |
| 144 | + */ | |
| 145 | +struct e5010_fmt { | |
| 146 | + u32 fourcc; | |
| 147 | + unsigned int num_planes; | |
| 148 | + unsigned int type; | |
| 149 | + u32 subsampling; | |
| 150 | + u32 chroma_order; | |
| 151 | + const struct v4l2_frmsize_stepwise frmsize; | |
| 152 | +}; | |
| 153 | + | |
| 154 | +/* | |
| 155 | + * struct e5010_ctrl - contains info for each supported v4l2 control | |
| 156 | + */ | |
| 157 | +struct e5010_ctrl { | |
| 158 | + unsigned int cid; | |
| 159 | + enum v4l2_ctrl_type type; | |
| 160 | + unsigned char name[32]; | |
| 161 | + int minimum; | |
| 162 | + int maximum; | |
| 163 | + int step; | |
| 164 | + int default_value; | |
| 165 | + unsigned char compound; | |
| 166 | +}; | |
| 167 | + | |
| 168 | +#endif | |
| @@ -0,0 +1,311 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * Imagination E5010 JPEG Encoder driver. | |
| 4 | + * | |
| 5 | + * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/ | |
| 6 | + * | |
| 7 | + * Author: David Huang <d-huang@ti.com> | |
| 8 | + * Author: Devarsh Thakkar <devarsht@ti.com> | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#ifndef _E5010_MMU_REGS_H | |
| 12 | +#define _E5010_MMU_REGS_H | |
| 13 | + | |
| 14 | +#define MMU_MMU_DIR_BASE_ADDR_OFFSET (0x0020) | |
| 15 | +#define MMU_MMU_DIR_BASE_ADDR_STRIDE (4) | |
| 16 | +#define MMU_MMU_DIR_BASE_ADDR_NO_ENTRIES (4) | |
| 17 | + | |
| 18 | +#define MMU_MMU_DIR_BASE_ADDR_MMU_DIR_BASE_ADDR_MASK (0xFFFFFFFF) | |
| 19 | +#define MMU_MMU_DIR_BASE_ADDR_MMU_DIR_BASE_ADDR_SHIFT (0) | |
| 20 | + | |
| 21 | +#define MMU_MMU_TILE_CFG_OFFSET (0x0040) | |
| 22 | +#define MMU_MMU_TILE_CFG_STRIDE (4) | |
| 23 | +#define MMU_MMU_TILE_CFG_NO_ENTRIES (4) | |
| 24 | + | |
| 25 | +#define MMU_MMU_TILE_CFG_TILE_128INTERLEAVE_MASK (0x00000010) | |
| 26 | +#define MMU_MMU_TILE_CFG_TILE_128INTERLEAVE_SHIFT (4) | |
| 27 | + | |
| 28 | +#define MMU_MMU_TILE_CFG_TILE_ENABLE_MASK (0x00000008) | |
| 29 | +#define MMU_MMU_TILE_CFG_TILE_ENABLE_SHIFT (3) | |
| 30 | + | |
| 31 | +#define MMU_MMU_TILE_CFG_TILE_STRIDE_MASK (0x00000007) | |
| 32 | +#define MMU_MMU_TILE_CFG_TILE_STRIDE_SHIFT (0) | |
| 33 | + | |
| 34 | +#define MMU_MMU_TILE_MIN_ADDR_OFFSET (0x0050) | |
| 35 | +#define MMU_MMU_TILE_MIN_ADDR_STRIDE (4) | |
| 36 | +#define MMU_MMU_TILE_MIN_ADDR_NO_ENTRIES (4) | |
| 37 | + | |
| 38 | +#define MMU_MMU_TILE_MIN_ADDR_TILE_MIN_ADDR_MASK (0xFFFFFFFF) | |
| 39 | +#define MMU_MMU_TILE_MIN_ADDR_TILE_MIN_ADDR_SHIFT (0) | |
| 40 | + | |
| 41 | +#define MMU_MMU_TILE_MAX_ADDR_OFFSET (0x0060) | |
| 42 | +#define MMU_MMU_TILE_MAX_ADDR_STRIDE (4) | |
| 43 | +#define MMU_MMU_TILE_MAX_ADDR_NO_ENTRIES (4) | |
| 44 | + | |
| 45 | +#define MMU_MMU_TILE_MAX_ADDR_TILE_MAX_ADDR_MASK (0xFFFFFFFF) | |
| 46 | +#define MMU_MMU_TILE_MAX_ADDR_TILE_MAX_ADDR_SHIFT (0) | |
| 47 | + | |
| 48 | +#define MMU_MMU_CONTROL0_OFFSET (0x0000) | |
| 49 | + | |
| 50 | +#define MMU_MMU_CONTROL0_MMU_TILING_SCHEME_MASK (0x00000001) | |
| 51 | +#define MMU_MMU_CONTROL0_MMU_TILING_SCHEME_SHIFT (0) | |
| 52 | + | |
| 53 | +#define MMU_MMU_CONTROL0_MMU_CACHE_POLICY_MASK (0x00000100) | |
| 54 | +#define MMU_MMU_CONTROL0_MMU_CACHE_POLICY_SHIFT (8) | |
| 55 | + | |
| 56 | +#define MMU_MMU_CONTROL0_FORCE_CACHE_POLICY_BYPASS_MASK (0x00000200) | |
| 57 | +#define MMU_MMU_CONTROL0_FORCE_CACHE_POLICY_BYPASS_SHIFT (9) | |
| 58 | + | |
| 59 | +#define MMU_MMU_CONTROL0_STALL_ON_PROTOCOL_FAULT_MASK (0x00001000) | |
| 60 | +#define MMU_MMU_CONTROL0_STALL_ON_PROTOCOL_FAULT_SHIFT (12) | |
| 61 | + | |
| 62 | +#define MMU_MMU_CONTROL1_OFFSET (0x0008) | |
| 63 | + | |
| 64 | +#define MMU_MMU_CONTROL1_MMU_FLUSH_MASK (0x00000008) | |
| 65 | +#define MMU_MMU_CONTROL1_MMU_FLUSH_SHIFT (3) | |
| 66 | +#define MMU_MMU_CONTROL1_MMU_FLUSH_NO_REPS (4) | |
| 67 | +#define MMU_MMU_CONTROL1_MMU_FLUSH_SIZE (1) | |
| 68 | + | |
| 69 | +#define MMU_MMU_CONTROL1_MMU_INVALDC_MASK (0x00000800) | |
| 70 | +#define MMU_MMU_CONTROL1_MMU_INVALDC_SHIFT (11) | |
| 71 | +#define MMU_MMU_CONTROL1_MMU_INVALDC_NO_REPS (4) | |
| 72 | +#define MMU_MMU_CONTROL1_MMU_INVALDC_SIZE (1) | |
| 73 | + | |
| 74 | +#define MMU_MMU_CONTROL1_MMU_FAULT_CLEAR_MASK (0x00010000) | |
| 75 | +#define MMU_MMU_CONTROL1_MMU_FAULT_CLEAR_SHIFT (16) | |
| 76 | + | |
| 77 | +#define MMU_MMU_CONTROL1_PROTOCOL_FAULT_CLEAR_MASK (0x00100000) | |
| 78 | +#define MMU_MMU_CONTROL1_PROTOCOL_FAULT_CLEAR_SHIFT (20) | |
| 79 | + | |
| 80 | +#define MMU_MMU_CONTROL1_MMU_PAUSE_SET_MASK (0x01000000) | |
| 81 | +#define MMU_MMU_CONTROL1_MMU_PAUSE_SET_SHIFT (24) | |
| 82 | + | |
| 83 | +#define MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_MASK (0x02000000) | |
| 84 | +#define MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_SHIFT (25) | |
| 85 | + | |
| 86 | +#define MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK (0x10000000) | |
| 87 | +#define MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT (28) | |
| 88 | + | |
| 89 | +#define MMU_MMU_BANK_INDEX_OFFSET (0x0010) | |
| 90 | + | |
| 91 | +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_MASK (0xC0000000) | |
| 92 | +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_SHIFT (30) | |
| 93 | +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_NO_REPS (16) | |
| 94 | +#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_SIZE (2) | |
| 95 | + | |
| 96 | +#define MMU_REQUEST_PRIORITY_ENABLE_OFFSET (0x0018) | |
| 97 | + | |
| 98 | +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_MASK (0x00008000) | |
| 99 | +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_SHIFT (15) | |
| 100 | +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_NO_REPS (16) | |
| 101 | +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_SIZE (1) | |
| 102 | + | |
| 103 | +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_MMU_PRIORITY_ENABLE_MASK (0x00010000) | |
| 104 | +#define MMU_REQUEST_PRIORITY_ENABLE_CMD_MMU_PRIORITY_ENABLE_SHIFT (16) | |
| 105 | + | |
| 106 | +#define MMU_REQUEST_LIMITED_THROUGHPUT_OFFSET (0x001C) | |
| 107 | + | |
| 108 | +#define MMU_REQUEST_LIMITED_THROUGHPUT_LIMITED_WORDS_MASK (0x000003FF) | |
| 109 | +#define MMU_REQUEST_LIMITED_THROUGHPUT_LIMITED_WORDS_SHIFT (0) | |
| 110 | + | |
| 111 | +#define MMU_REQUEST_LIMITED_THROUGHPUT_REQUEST_GAP_MASK (0x0FFF0000) | |
| 112 | +#define MMU_REQUEST_LIMITED_THROUGHPUT_REQUEST_GAP_SHIFT (16) | |
| 113 | + | |
| 114 | +#define MMU_MMU_ADDRESS_CONTROL_OFFSET (0x0070) | |
| 115 | +#define MMU_MMU_ADDRESS_CONTROL_TRUSTED (IMG_TRUE) | |
| 116 | + | |
| 117 | +#define MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK (0x00000001) | |
| 118 | +#define MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT (0) | |
| 119 | + | |
| 120 | +#define MMU_MMU_ADDRESS_CONTROL_MMU_ENABLE_EXT_ADDRESSING_MASK (0x00000010) | |
| 121 | +#define MMU_MMU_ADDRESS_CONTROL_MMU_ENABLE_EXT_ADDRESSING_SHIFT (4) | |
| 122 | + | |
| 123 | +#define MMU_MMU_ADDRESS_CONTROL_UPPER_ADDRESS_FIXED_MASK (0x00FF0000) | |
| 124 | +#define MMU_MMU_ADDRESS_CONTROL_UPPER_ADDRESS_FIXED_SHIFT (16) | |
| 125 | + | |
| 126 | +#define MMU_MMU_CONFIG0_OFFSET (0x0080) | |
| 127 | + | |
| 128 | +#define MMU_MMU_CONFIG0_NUM_REQUESTORS_MASK (0x0000000F) | |
| 129 | +#define MMU_MMU_CONFIG0_NUM_REQUESTORS_SHIFT (0) | |
| 130 | + | |
| 131 | +#define MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_MASK (0x000000F0) | |
| 132 | +#define MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_SHIFT (4) | |
| 133 | + | |
| 134 | +#define MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_MASK (0x00000700) | |
| 135 | +#define MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_SHIFT (8) | |
| 136 | + | |
| 137 | +#define MMU_MMU_CONFIG0_ADDR_COHERENCY_SUPPORTED_MASK (0x00001000) | |
| 138 | +#define MMU_MMU_CONFIG0_ADDR_COHERENCY_SUPPORTED_SHIFT (12) | |
| 139 | + | |
| 140 | +#define MMU_MMU_CONFIG0_MMU_SUPPORTED_MASK (0x00002000) | |
| 141 | +#define MMU_MMU_CONFIG0_MMU_SUPPORTED_SHIFT (13) | |
| 142 | + | |
| 143 | +#define MMU_MMU_CONFIG0_TILE_ADDR_GRANULARITY_MASK (0x001F0000) | |
| 144 | +#define MMU_MMU_CONFIG0_TILE_ADDR_GRANULARITY_SHIFT (16) | |
| 145 | + | |
| 146 | +#define MMU_MMU_CONFIG0_NO_READ_REORDER_MASK (0x00200000) | |
| 147 | +#define MMU_MMU_CONFIG0_NO_READ_REORDER_SHIFT (21) | |
| 148 | + | |
| 149 | +#define MMU_MMU_CONFIG0_TAGS_SUPPORTED_MASK (0xFFC00000) | |
| 150 | +#define MMU_MMU_CONFIG0_TAGS_SUPPORTED_SHIFT (22) | |
| 151 | + | |
| 152 | +#define MMU_MMU_CONFIG1_OFFSET (0x0084) | |
| 153 | + | |
| 154 | +#define MMU_MMU_CONFIG1_PAGE_SIZE_MASK (0x0000000F) | |
| 155 | +#define MMU_MMU_CONFIG1_PAGE_SIZE_SHIFT (0) | |
| 156 | + | |
| 157 | +#define MMU_MMU_CONFIG1_PAGE_CACHE_ENTRIES_MASK (0x0000FF00) | |
| 158 | +#define MMU_MMU_CONFIG1_PAGE_CACHE_ENTRIES_SHIFT (8) | |
| 159 | + | |
| 160 | +#define MMU_MMU_CONFIG1_DIR_CACHE_ENTRIES_MASK (0x001F0000) | |
| 161 | +#define MMU_MMU_CONFIG1_DIR_CACHE_ENTRIES_SHIFT (16) | |
| 162 | + | |
| 163 | +#define MMU_MMU_CONFIG1_BANDWIDTH_COUNT_SUPPORTED_MASK (0x01000000) | |
| 164 | +#define MMU_MMU_CONFIG1_BANDWIDTH_COUNT_SUPPORTED_SHIFT (24) | |
| 165 | + | |
| 166 | +#define MMU_MMU_CONFIG1_STALL_COUNT_SUPPORTED_MASK (0x02000000) | |
| 167 | +#define MMU_MMU_CONFIG1_STALL_COUNT_SUPPORTED_SHIFT (25) | |
| 168 | + | |
| 169 | +#define MMU_MMU_CONFIG1_LATENCY_COUNT_SUPPORTED_MASK (0x04000000) | |
| 170 | +#define MMU_MMU_CONFIG1_LATENCY_COUNT_SUPPORTED_SHIFT (26) | |
| 171 | + | |
| 172 | +#define MMU_MMU_STATUS0_OFFSET (0x0088) | |
| 173 | + | |
| 174 | +#define MMU_MMU_STATUS0_MMU_PF_N_RW_MASK (0x00000001) | |
| 175 | +#define MMU_MMU_STATUS0_MMU_PF_N_RW_SHIFT (0) | |
| 176 | + | |
| 177 | +#define MMU_MMU_STATUS0_MMU_FAULT_ADDR_MASK (0xFFFFF000) | |
| 178 | +#define MMU_MMU_STATUS0_MMU_FAULT_ADDR_SHIFT (12) | |
| 179 | + | |
| 180 | +#define MMU_MMU_STATUS1_OFFSET (0x008C) | |
| 181 | + | |
| 182 | +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_STAT_MASK (0x0000FFFF) | |
| 183 | +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_STAT_SHIFT (0) | |
| 184 | + | |
| 185 | +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_MASK (0x000F0000) | |
| 186 | +#define MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_SHIFT (16) | |
| 187 | + | |
| 188 | +#define MMU_MMU_STATUS1_MMU_FAULT_INDEX_MASK (0x03000000) | |
| 189 | +#define MMU_MMU_STATUS1_MMU_FAULT_INDEX_SHIFT (24) | |
| 190 | + | |
| 191 | +#define MMU_MMU_STATUS1_MMU_FAULT_RNW_MASK (0x10000000) | |
| 192 | +#define MMU_MMU_STATUS1_MMU_FAULT_RNW_SHIFT (28) | |
| 193 | + | |
| 194 | +#define MMU_MMU_MEM_REQ_OFFSET (0x0090) | |
| 195 | + | |
| 196 | +#define MMU_MMU_MEM_REQ_TAG_OUTSTANDING_MASK (0x000003FF) | |
| 197 | +#define MMU_MMU_MEM_REQ_TAG_OUTSTANDING_SHIFT (0) | |
| 198 | + | |
| 199 | +#define MMU_MMU_MEM_REQ_EXT_WRRESP_FAULT_MASK (0x00001000) | |
| 200 | +#define MMU_MMU_MEM_REQ_EXT_WRRESP_FAULT_SHIFT (12) | |
| 201 | + | |
| 202 | +#define MMU_MMU_MEM_REQ_EXT_RDRESP_FAULT_MASK (0x00002000) | |
| 203 | +#define MMU_MMU_MEM_REQ_EXT_RDRESP_FAULT_SHIFT (13) | |
| 204 | + | |
| 205 | +#define MMU_MMU_MEM_REQ_EXT_READ_BURST_FAULT_MASK (0x00004000) | |
| 206 | +#define MMU_MMU_MEM_REQ_EXT_READ_BURST_FAULT_SHIFT (14) | |
| 207 | + | |
| 208 | +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_MASK (0x80000000) | |
| 209 | +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_SHIFT (31) | |
| 210 | +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_NO_REPS (16) | |
| 211 | +#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_SIZE (1) | |
| 212 | + | |
| 213 | +#define MMU_MMU_FAULT_SELECT_OFFSET (0x00A0) | |
| 214 | + | |
| 215 | +#define MMU_MMU_FAULT_SELECT_MMU_FAULT_SELECT_MASK (0x0000000F) | |
| 216 | +#define MMU_MMU_FAULT_SELECT_MMU_FAULT_SELECT_SHIFT (0) | |
| 217 | + | |
| 218 | +#define MMU_PROTOCOL_FAULT_OFFSET (0x00A8) | |
| 219 | + | |
| 220 | +#define MMU_PROTOCOL_FAULT_FAULT_PAGE_BREAK_MASK (0x00000001) | |
| 221 | +#define MMU_PROTOCOL_FAULT_FAULT_PAGE_BREAK_SHIFT (0) | |
| 222 | + | |
| 223 | +#define MMU_PROTOCOL_FAULT_FAULT_WRITE_MASK (0x00000010) | |
| 224 | +#define MMU_PROTOCOL_FAULT_FAULT_WRITE_SHIFT (4) | |
| 225 | + | |
| 226 | +#define MMU_PROTOCOL_FAULT_FAULT_READ_MASK (0x00000020) | |
| 227 | +#define MMU_PROTOCOL_FAULT_FAULT_READ_SHIFT (5) | |
| 228 | + | |
| 229 | +#define MMU_TOTAL_READ_REQ_OFFSET (0x0100) | |
| 230 | + | |
| 231 | +#define MMU_TOTAL_READ_REQ_TOTAL_READ_REQ_MASK (0xFFFFFFFF) | |
| 232 | +#define MMU_TOTAL_READ_REQ_TOTAL_READ_REQ_SHIFT (0) | |
| 233 | + | |
| 234 | +#define MMU_TOTAL_WRITE_REQ_OFFSET (0x0104) | |
| 235 | + | |
| 236 | +#define MMU_TOTAL_WRITE_REQ_TOTAL_WRITE_REQ_MASK (0xFFFFFFFF) | |
| 237 | +#define MMU_TOTAL_WRITE_REQ_TOTAL_WRITE_REQ_SHIFT (0) | |
| 238 | + | |
| 239 | +#define MMU_READS_LESS_64_REQ_OFFSET (0x0108) | |
| 240 | + | |
| 241 | +#define MMU_READS_LESS_64_REQ_READS_LESS_64_REQ_MASK (0xFFFFFFFF) | |
| 242 | +#define MMU_READS_LESS_64_REQ_READS_LESS_64_REQ_SHIFT (0) | |
| 243 | + | |
| 244 | +#define MMU_WRITES_LESS_64_REQ_OFFSET (0x010C) | |
| 245 | + | |
| 246 | +#define MMU_WRITES_LESS_64_REQ_WRITES_LESS_64_REQ_MASK (0xFFFFFFFF) | |
| 247 | +#define MMU_WRITES_LESS_64_REQ_WRITES_LESS_64_REQ_SHIFT (0) | |
| 248 | + | |
| 249 | +#define MMU_EXT_CMD_STALL_OFFSET (0x0120) | |
| 250 | + | |
| 251 | +#define MMU_EXT_CMD_STALL_EXT_CMD_STALL_MASK (0xFFFFFFFF) | |
| 252 | +#define MMU_EXT_CMD_STALL_EXT_CMD_STALL_SHIFT (0) | |
| 253 | + | |
| 254 | +#define MMU_WRITE_REQ_STALL_OFFSET (0x0124) | |
| 255 | + | |
| 256 | +#define MMU_WRITE_REQ_STALL_WRITE_REQ_STALL_MASK (0xFFFFFFFF) | |
| 257 | +#define MMU_WRITE_REQ_STALL_WRITE_REQ_STALL_SHIFT (0) | |
| 258 | + | |
| 259 | +#define MMU_MMU_MISS_STALL_OFFSET (0x0128) | |
| 260 | + | |
| 261 | +#define MMU_MMU_MISS_STALL_MMU_MISS_STALL_MASK (0xFFFFFFFF) | |
| 262 | +#define MMU_MMU_MISS_STALL_MMU_MISS_STALL_SHIFT (0) | |
| 263 | + | |
| 264 | +#define MMU_ADDRESS_STALL_OFFSET (0x012C) | |
| 265 | + | |
| 266 | +#define MMU_ADDRESS_STALL_ADDRESS_STALL_MASK (0xFFFFFFFF) | |
| 267 | +#define MMU_ADDRESS_STALL_ADDRESS_STALL_SHIFT (0) | |
| 268 | + | |
| 269 | +#define MMU_TAG_STALL_OFFSET (0x0130) | |
| 270 | + | |
| 271 | +#define MMU_TAG_STALL_TAG_STALL_MASK (0xFFFFFFFF) | |
| 272 | +#define MMU_TAG_STALL_TAG_STALL_SHIFT (0) | |
| 273 | + | |
| 274 | +#define MMU_PEAK_READ_OUTSTANDING_OFFSET (0x0140) | |
| 275 | + | |
| 276 | +#define MMU_PEAK_READ_OUTSTANDING_PEAK_TAG_OUTSTANDING_MASK (0x000003FF) | |
| 277 | +#define MMU_PEAK_READ_OUTSTANDING_PEAK_TAG_OUTSTANDING_SHIFT (0) | |
| 278 | + | |
| 279 | +#define MMU_PEAK_READ_OUTSTANDING_PEAK_READ_LATENCY_MASK (0xFFFF0000) | |
| 280 | +#define MMU_PEAK_READ_OUTSTANDING_PEAK_READ_LATENCY_SHIFT (16) | |
| 281 | + | |
| 282 | +#define MMU_AVERAGE_READ_LATENCY_OFFSET (0x0144) | |
| 283 | + | |
| 284 | +#define MMU_AVERAGE_READ_LATENCY_AVERAGE_READ_LATENCY_MASK (0xFFFFFFFF) | |
| 285 | +#define MMU_AVERAGE_READ_LATENCY_AVERAGE_READ_LATENCY_SHIFT (0) | |
| 286 | + | |
| 287 | +#define MMU_STATISTICS_CONTROL_OFFSET (0x0160) | |
| 288 | + | |
| 289 | +#define MMU_STATISTICS_CONTROL_BANDWIDTH_STATS_INIT_MASK (0x00000001) | |
| 290 | +#define MMU_STATISTICS_CONTROL_BANDWIDTH_STATS_INIT_SHIFT (0) | |
| 291 | + | |
| 292 | +#define MMU_STATISTICS_CONTROL_STALL_STATS_INIT_MASK (0x00000002) | |
| 293 | +#define MMU_STATISTICS_CONTROL_STALL_STATS_INIT_SHIFT (1) | |
| 294 | + | |
| 295 | +#define MMU_STATISTICS_CONTROL_LATENCY_STATS_INIT_MASK (0x00000004) | |
| 296 | +#define MMU_STATISTICS_CONTROL_LATENCY_STATS_INIT_SHIFT (2) | |
| 297 | + | |
| 298 | +#define MMU_MMU_VERSION_OFFSET (0x01D0) | |
| 299 | + | |
| 300 | +#define MMU_MMU_VERSION_MMU_MAJOR_REV_MASK (0x00FF0000) | |
| 301 | +#define MMU_MMU_VERSION_MMU_MAJOR_REV_SHIFT (16) | |
| 302 | + | |
| 303 | +#define MMU_MMU_VERSION_MMU_MINOR_REV_MASK (0x0000FF00) | |
| 304 | +#define MMU_MMU_VERSION_MMU_MINOR_REV_SHIFT (8) | |
| 305 | + | |
| 306 | +#define MMU_MMU_VERSION_MMU_MAINT_REV_MASK (0x000000FF) | |
| 307 | +#define MMU_MMU_VERSION_MMU_MAINT_REV_SHIFT (0) | |
| 308 | + | |
| 309 | +#define MMU_BYTE_SIZE (0x01D4) | |
| 310 | + | |
| 311 | +#endif | |
| @@ -43,6 +43,7 @@ · 42 unmodified lines | ||
| 43 | 43 | #include <linux/videodev2.h> |
| 44 | 44 | |
| 45 | 45 | #include <linux/platform_data/media/camera-pxa.h> |
| 46 | +#include <linux/workqueue.h> | |
| 46 | 47 | |
| 47 | 48 | #define PXA_CAM_VERSION "0.0.6" |
| 48 | 49 | #define PXA_CAM_DRV_NAME "pxa27x-camera" |
| @@ -683,7 +684,7 @@ struct pxa_camera_dev { · 634 unmodified lines | ||
| 683 | 684 | unsigned int buf_sequence; |
| 684 | 685 | |
| 685 | 686 | struct pxa_buffer *active; |
| 686 | − struct tasklet_struct task_eof; | |
| 687 | + struct work_struct eof_bh_work; | |
| 687 | 688 | |
| 688 | 689 | u32 save_cicr[5]; |
| 689 | 690 | }; |
| @@ -1146,9 +1147,9 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev) · 456 unmodified lines | ||
| 1146 | 1147 | clk_disable_unprepare(pcdev->clk); |
| 1147 | 1148 | } |
| 1148 | 1149 | |
| 1149 | −static void pxa_camera_eof(struct tasklet_struct *t) | |
| 1150 | +static void pxa_camera_eof_bh_work(struct work_struct *t) | |
| 1150 | 1151 | { |
| 1151 | − struct pxa_camera_dev *pcdev = from_tasklet(pcdev, t, task_eof); | |
| 1152 | + struct pxa_camera_dev *pcdev = from_work(pcdev, t, eof_bh_work); | |
| 1152 | 1153 | unsigned long cifr; |
| 1153 | 1154 | struct pxa_buffer *buf; |
| 1154 | 1155 | |
| @@ -1185,7 +1186,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data) · 30 unmodified lines | ||
| 1185 | 1186 | if (status & CISR_EOF) { |
| 1186 | 1187 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; |
| 1187 | 1188 | __raw_writel(cicr0, pcdev->base + CICR0); |
| 1188 | − tasklet_schedule(&pcdev->task_eof); | |
| 1189 | + queue_work(system_bh_wq, &pcdev->eof_bh_work); | |
| 1189 | 1190 | } |
| 1190 | 1191 | |
| 1191 | 1192 | return IRQ_HANDLED; |
| @@ -2383,7 +2384,7 @@ static int pxa_camera_probe(struct platform_device *pdev) · 1191 unmodified lines | ||
| 2383 | 2384 | } |
| 2384 | 2385 | } |
| 2385 | 2386 | |
| 2386 | − tasklet_setup(&pcdev->task_eof, pxa_camera_eof); | |
| 2387 | + INIT_WORK(&pcdev->eof_bh_work, pxa_camera_eof_bh_work); | |
| 2387 | 2388 | |
| 2388 | 2389 | pxa_camera_activate(pcdev); |
| 2389 | 2390 | |
| @@ -2409,7 +2410,7 @@ static int pxa_camera_probe(struct platform_device *pdev) · 19 unmodified lines | ||
| 2409 | 2410 | return 0; |
| 2410 | 2411 | exit_deactivate: |
| 2411 | 2412 | pxa_camera_deactivate(pcdev); |
| 2412 | − tasklet_kill(&pcdev->task_eof); | |
| 2413 | + cancel_work_sync(&pcdev->eof_bh_work); | |
| 2413 | 2414 | exit_free_dma: |
| 2414 | 2415 | dma_release_channel(pcdev->dma_chans[2]); |
| 2415 | 2416 | exit_free_dma_u: |
| @@ -2428,7 +2429,7 @@ static void pxa_camera_remove(struct platform_device *pdev) · 12 unmodified lines | ||
| 2428 | 2429 | struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); |
| 2429 | 2430 | |
| 2430 | 2431 | pxa_camera_deactivate(pcdev); |
| 2431 | − tasklet_kill(&pcdev->task_eof); | |
| 2432 | + cancel_work_sync(&pcdev->eof_bh_work); | |
| 2432 | 2433 | dma_release_channel(pcdev->dma_chans[0]); |
| 2433 | 2434 | dma_release_channel(pcdev->dma_chans[1]); |
| 2434 | 2435 | dma_release_channel(pcdev->dma_chans[2]); |
| @@ -724,10 +724,6 @@ static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = { · 723 unmodified lines | ||
| 724 | 724 | /* |
| 725 | 725 | * Queue operations |
| 726 | 726 | */ |
| 727 | −struct vb2_dc_conf { | |
| 728 | − struct device *dev; | |
| 729 | −}; | |
| 730 | − | |
| 731 | 727 | static int deinterlace_queue_setup(struct vb2_queue *vq, |
| 732 | 728 | unsigned int *nbuffers, unsigned int *nplanes, |
| 733 | 729 | unsigned int sizes[], struct device *alloc_devs[]) |
| @@ -439,9 +439,9 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam) · 438 unmodified lines | ||
| 439 | 439 | /* |
| 440 | 440 | * Copy data out to user space in the vmalloc case |
| 441 | 441 | */ |
| 442 | −static void mcam_frame_tasklet(struct tasklet_struct *t) | |
| 442 | +static void mcam_frame_work(struct work_struct *t) | |
| 443 | 443 | { |
| 444 | − struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet); | |
| 444 | + struct mcam_camera *cam = from_work(cam, t, s_bh_work); | |
| 445 | 445 | int i; |
| 446 | 446 | unsigned long flags; |
| 447 | 447 | struct mcam_vb_buffer *buf; |
| @@ -493,7 +493,7 @@ static int mcam_check_dma_buffers(struct mcam_camera *cam) · 45 unmodified lines | ||
| 493 | 493 | |
| 494 | 494 | static void mcam_vmalloc_done(struct mcam_camera *cam, int frame) |
| 495 | 495 | { |
| 496 | − tasklet_schedule(&cam->s_tasklet); | |
| 496 | + queue_work(system_bh_wq, &cam->s_bh_work); | |
| 497 | 497 | } |
| 498 | 498 | |
| 499 | 499 | #else /* MCAM_MODE_VMALLOC */ |
| @@ -1305,7 +1305,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 805 unmodified lines | ||
| 1305 | 1305 | break; |
| 1306 | 1306 | case B_vmalloc: |
| 1307 | 1307 | #ifdef MCAM_MODE_VMALLOC |
| 1308 | − tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet); | |
| 1308 | + INIT_WORK(&cam->s_bh_work, mcam_frame_work); | |
| 1309 | 1309 | vq->ops = &mcam_vb2_ops; |
| 1310 | 1310 | vq->mem_ops = &vb2_vmalloc_memops; |
| 1311 | 1311 | cam->dma_setup = mcam_ctlr_dma_vmalloc; |
| @@ -1981,5 +1981,6 @@ int mccic_resume(struct mcam_camera *cam) · 669 unmodified lines | ||
| 1981 | 1981 | } |
| 1982 | 1982 | EXPORT_SYMBOL_GPL(mccic_resume); |
| 1983 | 1983 | |
| 1984 | +MODULE_DESCRIPTION("Marvell camera core driver"); | |
| 1984 | 1985 | MODULE_LICENSE("GPL v2"); |
| 1985 | 1986 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <linux/list.h> |
| 11 | 11 | #include <linux/clk-provider.h> |
| 12 | +#include <linux/workqueue.h> | |
| 12 | 13 | #include <media/v4l2-common.h> |
| 13 | 14 | #include <media/v4l2-ctrls.h> |
| 14 | 15 | #include <media/v4l2-dev.h> |
| @@ -167,7 +168,7 @@ struct mcam_camera { · 152 unmodified lines | ||
| 167 | 168 | unsigned int dma_buf_size; /* allocated size */ |
| 168 | 169 | void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ |
| 169 | 170 | dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ |
| 170 | − struct tasklet_struct s_tasklet; | |
| 171 | + struct work_struct s_bh_work; | |
| 171 | 172 | #endif |
| 172 | 173 | unsigned int sequence; /* Frame sequence number */ |
| 173 | 174 | unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */ |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | MODULE_ALIAS("platform:mmp-camera"); |
| 32 | 32 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
| 33 | +MODULE_DESCRIPTION("Support for the camera device found on Marvell MMP processors"); | |
| 33 | 34 | MODULE_LICENSE("GPL"); |
| 34 | 35 | |
| 35 | 36 | static char *mcam_clks[] = {"axi", "func", "phy"}; |
| @@ -46,6 +46,53 @@ enum mt8183_mdp_comp_id { · 45 unmodified lines | ||
| 46 | 46 | MT8183_MDP_COMP_WROT1, /* 25 */ |
| 47 | 47 | }; |
| 48 | 48 | |
| 49 | +enum mt8188_mdp_comp_id { | |
| 50 | + /* MT8188 Comp id */ | |
| 51 | + /* ISP */ | |
| 52 | + MT8188_MDP_COMP_WPEI = 0, | |
| 53 | + MT8188_MDP_COMP_WPEO, /* 1 */ | |
| 54 | + | |
| 55 | + /* MDP */ | |
| 56 | + MT8188_MDP_COMP_CAMIN, /* 2 */ | |
| 57 | + MT8188_MDP_COMP_RDMA0, /* 3 */ | |
| 58 | + MT8188_MDP_COMP_RDMA2, /* 4 */ | |
| 59 | + MT8188_MDP_COMP_RDMA3, /* 5 */ | |
| 60 | + MT8188_MDP_COMP_FG0, /* 6 */ | |
| 61 | + MT8188_MDP_COMP_FG2, /* 7 */ | |
| 62 | + MT8188_MDP_COMP_FG3, /* 8 */ | |
| 63 | + MT8188_MDP_COMP_TO_SVPP2MOUT, /* 9 */ | |
| 64 | + MT8188_MDP_COMP_TO_SVPP3MOUT, /* 10 */ | |
| 65 | + MT8188_MDP_COMP_TO_WARP0MOUT, /* 11 */ | |
| 66 | + MT8188_MDP_COMP_VPP0_SOUT, /* 12 */ | |
| 67 | + MT8188_MDP_COMP_VPP1_SOUT, /* 13 */ | |
| 68 | + MT8188_MDP_COMP_PQ0_SOUT, /* 14 */ | |
| 69 | + MT8188_MDP_COMP_HDR0, /* 15 */ | |
| 70 | + MT8188_MDP_COMP_HDR2, /* 16 */ | |
| 71 | + MT8188_MDP_COMP_HDR3, /* 17 */ | |
| 72 | + MT8188_MDP_COMP_AAL0, /* 18 */ | |
| 73 | + MT8188_MDP_COMP_AAL2, /* 19 */ | |
| 74 | + MT8188_MDP_COMP_AAL3, /* 20 */ | |
| 75 | + MT8188_MDP_COMP_RSZ0, /* 21 */ | |
| 76 | + MT8188_MDP_COMP_RSZ2, /* 22 */ | |
| 77 | + MT8188_MDP_COMP_RSZ3, /* 23 */ | |
| 78 | + MT8188_MDP_COMP_TDSHP0, /* 24 */ | |
| 79 | + MT8188_MDP_COMP_TDSHP2, /* 25 */ | |
| 80 | + MT8188_MDP_COMP_TDSHP3, /* 26 */ | |
| 81 | + MT8188_MDP_COMP_COLOR0, /* 27 */ | |
| 82 | + MT8188_MDP_COMP_COLOR2, /* 28 */ | |
| 83 | + MT8188_MDP_COMP_COLOR3, /* 29 */ | |
| 84 | + MT8188_MDP_COMP_OVL0, /* 30 */ | |
| 85 | + MT8188_MDP_COMP_PAD0, /* 31 */ | |
| 86 | + MT8188_MDP_COMP_PAD2, /* 32 */ | |
| 87 | + MT8188_MDP_COMP_PAD3, /* 33 */ | |
| 88 | + MT8188_MDP_COMP_TCC0, /* 34 */ | |
| 89 | + MT8188_MDP_COMP_WROT0, /* 35 */ | |
| 90 | + MT8188_MDP_COMP_WROT2, /* 36 */ | |
| 91 | + MT8188_MDP_COMP_WROT3, /* 37 */ | |
| 92 | + MT8188_MDP_COMP_MERGE2, /* 38 */ | |
| 93 | + MT8188_MDP_COMP_MERGE3, /* 39 */ | |
| 94 | +}; | |
| 95 | + | |
| 49 | 96 | enum mt8195_mdp_comp_id { |
| 50 | 97 | /* MT8195 Comp id */ |
| 51 | 98 | /* ISP */ |
| @@ -123,6 +170,13 @@ static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = { · 71 unmodified lines | ||
| 123 | 170 | [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" } |
| 124 | 171 | }; |
| 125 | 172 | |
| 173 | +static const struct of_device_id mt8188_mdp_probe_infra[MDP_INFRA_MAX] = { | |
| 174 | + [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8188-vppsys0" }, | |
| 175 | + [MDP_INFRA_MMSYS2] = { .compatible = "mediatek,mt8188-vppsys1" }, | |
| 176 | + [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8188-vpp-mutex" }, | |
| 177 | + [MDP_INFRA_MUTEX2] = { .compatible = "mediatek,mt8188-vpp-mutex" }, | |
| 178 | +}; | |
| 179 | + | |
| 126 | 180 | static const struct of_device_id mt8195_mdp_probe_infra[MDP_INFRA_MAX] = { |
| 127 | 181 | [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8195-vppsys0" }, |
| 128 | 182 | [MDP_INFRA_MMSYS2] = { .compatible = "mediatek,mt8195-vppsys1" }, |
| @@ -167,6 +221,40 @@ static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = { · 38 unmodified lines | ||
| 167 | 221 | [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0, |
| 168 | 222 | }; |
| 169 | 223 | |
| 224 | +static const u32 mt8188_mutex_idx[MDP_MAX_COMP_COUNT] = { | |
| 225 | + [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, | |
| 226 | + [MDP_COMP_RDMA2] = MUTEX_MOD_IDX_MDP_RDMA2, | |
| 227 | + [MDP_COMP_RDMA3] = MUTEX_MOD_IDX_MDP_RDMA3, | |
| 228 | + [MDP_COMP_FG0] = MUTEX_MOD_IDX_MDP_FG0, | |
| 229 | + [MDP_COMP_FG2] = MUTEX_MOD_IDX_MDP_FG2, | |
| 230 | + [MDP_COMP_FG3] = MUTEX_MOD_IDX_MDP_FG3, | |
| 231 | + [MDP_COMP_HDR0] = MUTEX_MOD_IDX_MDP_HDR0, | |
| 232 | + [MDP_COMP_HDR2] = MUTEX_MOD_IDX_MDP_HDR2, | |
| 233 | + [MDP_COMP_HDR3] = MUTEX_MOD_IDX_MDP_HDR3, | |
| 234 | + [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0, | |
| 235 | + [MDP_COMP_AAL2] = MUTEX_MOD_IDX_MDP_AAL2, | |
| 236 | + [MDP_COMP_AAL3] = MUTEX_MOD_IDX_MDP_AAL3, | |
| 237 | + [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0, | |
| 238 | + [MDP_COMP_RSZ2] = MUTEX_MOD_IDX_MDP_RSZ2, | |
| 239 | + [MDP_COMP_RSZ3] = MUTEX_MOD_IDX_MDP_RSZ3, | |
| 240 | + [MDP_COMP_MERGE2] = MUTEX_MOD_IDX_MDP_MERGE2, | |
| 241 | + [MDP_COMP_MERGE3] = MUTEX_MOD_IDX_MDP_MERGE3, | |
| 242 | + [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0, | |
| 243 | + [MDP_COMP_TDSHP2] = MUTEX_MOD_IDX_MDP_TDSHP2, | |
| 244 | + [MDP_COMP_TDSHP3] = MUTEX_MOD_IDX_MDP_TDSHP3, | |
| 245 | + [MDP_COMP_COLOR0] = MUTEX_MOD_IDX_MDP_COLOR0, | |
| 246 | + [MDP_COMP_COLOR2] = MUTEX_MOD_IDX_MDP_COLOR2, | |
| 247 | + [MDP_COMP_COLOR3] = MUTEX_MOD_IDX_MDP_COLOR3, | |
| 248 | + [MDP_COMP_OVL0] = MUTEX_MOD_IDX_MDP_OVL0, | |
| 249 | + [MDP_COMP_PAD0] = MUTEX_MOD_IDX_MDP_PAD0, | |
| 250 | + [MDP_COMP_PAD2] = MUTEX_MOD_IDX_MDP_PAD2, | |
| 251 | + [MDP_COMP_PAD3] = MUTEX_MOD_IDX_MDP_PAD3, | |
| 252 | + [MDP_COMP_TCC0] = MUTEX_MOD_IDX_MDP_TCC0, | |
| 253 | + [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0, | |
| 254 | + [MDP_COMP_WROT2] = MUTEX_MOD_IDX_MDP_WROT2, | |
| 255 | + [MDP_COMP_WROT3] = MUTEX_MOD_IDX_MDP_WROT3, | |
| 256 | +}; | |
| 257 | + | |
| 170 | 258 | static const u32 mt8195_mutex_idx[MDP_MAX_COMP_COUNT] = { |
| 171 | 259 | [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, |
| 172 | 260 | [MDP_COMP_RDMA1] = MUTEX_MOD_IDX_MDP_RDMA1, |
| @@ -288,6 +376,171 @@ static const struct mdp_comp_data mt8183_mdp_comp_data[MDP_MAX_COMP_COUNT] = { · 115 unmodified lines | ||
| 288 | 376 | }, |
| 289 | 377 | }; |
| 290 | 378 | |
| 379 | +static const struct mdp_comp_data mt8188_mdp_comp_data[MDP_MAX_COMP_COUNT] = { | |
| 380 | + [MDP_COMP_WPEI] = { | |
| 381 | + {MDP_COMP_TYPE_WPEI, 0, MT8188_MDP_COMP_WPEI, MDP_MM_SUBSYS_0}, | |
| 382 | + {0, 0, 0} | |
| 383 | + }, | |
| 384 | + [MDP_COMP_WPEO] = { | |
| 385 | + {MDP_COMP_TYPE_EXTO, 0, MT8188_MDP_COMP_WPEO, MDP_MM_SUBSYS_0}, | |
| 386 | + {0, 0, 0} | |
| 387 | + }, | |
| 388 | + [MDP_COMP_CAMIN] = { | |
| 389 | + {MDP_COMP_TYPE_DL_PATH, 0, MT8188_MDP_COMP_CAMIN, MDP_MM_SUBSYS_0}, | |
| 390 | + {3, 3, 0} | |
| 391 | + }, | |
| 392 | + [MDP_COMP_RDMA0] = { | |
| 393 | + {MDP_COMP_TYPE_RDMA, 0, MT8188_MDP_COMP_RDMA0, MDP_MM_SUBSYS_0}, | |
| 394 | + {3, 0, 0} | |
| 395 | + }, | |
| 396 | + [MDP_COMP_RDMA2] = { | |
| 397 | + {MDP_COMP_TYPE_RDMA, 1, MT8188_MDP_COMP_RDMA2, MDP_MM_SUBSYS_1}, | |
| 398 | + {3, 0, 0} | |
| 399 | + }, | |
| 400 | + [MDP_COMP_RDMA3] = { | |
| 401 | + {MDP_COMP_TYPE_RDMA, 2, MT8188_MDP_COMP_RDMA3, MDP_MM_SUBSYS_1}, | |
| 402 | + {3, 0, 0} | |
| 403 | + }, | |
| 404 | + [MDP_COMP_FG0] = { | |
| 405 | + {MDP_COMP_TYPE_FG, 0, MT8188_MDP_COMP_FG0, MDP_MM_SUBSYS_0}, | |
| 406 | + {1, 0, 0} | |
| 407 | + }, | |
| 408 | + [MDP_COMP_FG2] = { | |
| 409 | + {MDP_COMP_TYPE_FG, 1, MT8188_MDP_COMP_FG2, MDP_MM_SUBSYS_1}, | |
| 410 | + {1, 0, 0} | |
| 411 | + }, | |
| 412 | + [MDP_COMP_FG3] = { | |
| 413 | + {MDP_COMP_TYPE_FG, 2, MT8188_MDP_COMP_FG3, MDP_MM_SUBSYS_1}, | |
| 414 | + {1, 0, 0} | |
| 415 | + }, | |
| 416 | + [MDP_COMP_HDR0] = { | |
| 417 | + {MDP_COMP_TYPE_HDR, 0, MT8188_MDP_COMP_HDR0, MDP_MM_SUBSYS_0}, | |
| 418 | + {1, 0, 0} | |
| 419 | + }, | |
| 420 | + [MDP_COMP_HDR2] = { | |
| 421 | + {MDP_COMP_TYPE_HDR, 1, MT8188_MDP_COMP_HDR2, MDP_MM_SUBSYS_1}, | |
| 422 | + {1, 0, 0} | |
| 423 | + }, | |
| 424 | + [MDP_COMP_HDR3] = { | |
| 425 | + {MDP_COMP_TYPE_HDR, 2, MT8188_MDP_COMP_HDR3, MDP_MM_SUBSYS_1}, | |
| 426 | + {1, 0, 0} | |
| 427 | + }, | |
| 428 | + [MDP_COMP_AAL0] = { | |
| 429 | + {MDP_COMP_TYPE_AAL, 0, MT8188_MDP_COMP_AAL0, MDP_MM_SUBSYS_0}, | |
| 430 | + {1, 0, 0} | |
| 431 | + }, | |
| 432 | + [MDP_COMP_AAL2] = { | |
| 433 | + {MDP_COMP_TYPE_AAL, 1, MT8188_MDP_COMP_AAL2, MDP_MM_SUBSYS_1}, | |
| 434 | + {1, 0, 0} | |
| 435 | + }, | |
| 436 | + [MDP_COMP_AAL3] = { | |
| 437 | + {MDP_COMP_TYPE_AAL, 2, MT8188_MDP_COMP_AAL3, MDP_MM_SUBSYS_1}, | |
| 438 | + {1, 0, 0} | |
| 439 | + }, | |
| 440 | + [MDP_COMP_RSZ0] = { | |
| 441 | + {MDP_COMP_TYPE_RSZ, 0, MT8188_MDP_COMP_RSZ0, MDP_MM_SUBSYS_0}, | |
| 442 | + {1, 0, 0} | |
| 443 | + }, | |
| 444 | + [MDP_COMP_RSZ2] = { | |
| 445 | + {MDP_COMP_TYPE_RSZ, 1, MT8188_MDP_COMP_RSZ2, MDP_MM_SUBSYS_1}, | |
| 446 | + {2, 0, 0}, | |
| 447 | + {MDP_COMP_MERGE2, true, true} | |
| 448 | + }, | |
| 449 | + [MDP_COMP_RSZ3] = { | |
| 450 | + {MDP_COMP_TYPE_RSZ, 2, MT8188_MDP_COMP_RSZ3, MDP_MM_SUBSYS_1}, | |
| 451 | + {2, 0, 0}, | |
| 452 | + {MDP_COMP_MERGE3, true, true} | |
| 453 | + }, | |
| 454 | + [MDP_COMP_TDSHP0] = { | |
| 455 | + {MDP_COMP_TYPE_TDSHP, 0, MT8188_MDP_COMP_TDSHP0, MDP_MM_SUBSYS_0}, | |
| 456 | + {1, 0, 0} | |
| 457 | + }, | |
| 458 | + [MDP_COMP_TDSHP2] = { | |
| 459 | + {MDP_COMP_TYPE_TDSHP, 1, MT8188_MDP_COMP_TDSHP2, MDP_MM_SUBSYS_1}, | |
| 460 | + {1, 0, 0} | |
| 461 | + }, | |
| 462 | + [MDP_COMP_TDSHP3] = { | |
| 463 | + {MDP_COMP_TYPE_TDSHP, 2, MT8188_MDP_COMP_TDSHP3, MDP_MM_SUBSYS_1}, | |
| 464 | + {1, 0, 0} | |
| 465 | + }, | |
| 466 | + [MDP_COMP_COLOR0] = { | |
| 467 | + {MDP_COMP_TYPE_COLOR, 0, MT8188_MDP_COMP_COLOR0, MDP_MM_SUBSYS_0}, | |
| 468 | + {1, 0, 0} | |
| 469 | + }, | |
| 470 | + [MDP_COMP_COLOR2] = { | |
| 471 | + {MDP_COMP_TYPE_COLOR, 1, MT8188_MDP_COMP_COLOR2, MDP_MM_SUBSYS_1}, | |
| 472 | + {1, 0, 0} | |
| 473 | + }, | |
| 474 | + [MDP_COMP_COLOR3] = { | |
| 475 | + {MDP_COMP_TYPE_COLOR, 2, MT8188_MDP_COMP_COLOR3, MDP_MM_SUBSYS_1}, | |
| 476 | + {1, 0, 0} | |
| 477 | + }, | |
| 478 | + [MDP_COMP_OVL0] = { | |
| 479 | + {MDP_COMP_TYPE_OVL, 0, MT8188_MDP_COMP_OVL0, MDP_MM_SUBSYS_0}, | |
| 480 | + {1, 0, 0} | |
| 481 | + }, | |
| 482 | + [MDP_COMP_PAD0] = { | |
| 483 | + {MDP_COMP_TYPE_PAD, 0, MT8188_MDP_COMP_PAD0, MDP_MM_SUBSYS_0}, | |
| 484 | + {1, 0, 0} | |
| 485 | + }, | |
| 486 | + [MDP_COMP_PAD2] = { | |
| 487 | + {MDP_COMP_TYPE_PAD, 1, MT8188_MDP_COMP_PAD2, MDP_MM_SUBSYS_1}, | |
| 488 | + {1, 0, 0} | |
| 489 | + }, | |
| 490 | + [MDP_COMP_PAD3] = { | |
| 491 | + {MDP_COMP_TYPE_PAD, 2, MT8188_MDP_COMP_PAD3, MDP_MM_SUBSYS_1}, | |
| 492 | + {1, 0, 0} | |
| 493 | + }, | |
| 494 | + [MDP_COMP_TCC0] = { | |
| 495 | + {MDP_COMP_TYPE_TCC, 0, MT8188_MDP_COMP_TCC0, MDP_MM_SUBSYS_0}, | |
| 496 | + {1, 0, 0} | |
| 497 | + }, | |
| 498 | + [MDP_COMP_WROT0] = { | |
| 499 | + {MDP_COMP_TYPE_WROT, 0, MT8188_MDP_COMP_WROT0, MDP_MM_SUBSYS_0}, | |
| 500 | + {1, 0, 0} | |
| 501 | + }, | |
| 502 | + [MDP_COMP_WROT2] = { | |
| 503 | + {MDP_COMP_TYPE_WROT, 1, MT8188_MDP_COMP_WROT2, MDP_MM_SUBSYS_1}, | |
| 504 | + {1, 0, 0} | |
| 505 | + }, | |
| 506 | + [MDP_COMP_WROT3] = { | |
| 507 | + {MDP_COMP_TYPE_WROT, 2, MT8188_MDP_COMP_WROT3, MDP_MM_SUBSYS_1}, | |
| 508 | + {1, 0, 0} | |
| 509 | + }, | |
| 510 | + [MDP_COMP_MERGE2] = { | |
| 511 | + {MDP_COMP_TYPE_MERGE, 0, MT8188_MDP_COMP_MERGE2, MDP_MM_SUBSYS_1}, | |
| 512 | + {1, 0, 0} | |
| 513 | + }, | |
| 514 | + [MDP_COMP_MERGE3] = { | |
| 515 | + {MDP_COMP_TYPE_MERGE, 1, MT8188_MDP_COMP_MERGE3, MDP_MM_SUBSYS_1}, | |
| 516 | + {1, 0, 0} | |
| 517 | + }, | |
| 518 | + [MDP_COMP_PQ0_SOUT] = { | |
| 519 | + {MDP_COMP_TYPE_DUMMY, 0, MT8188_MDP_COMP_PQ0_SOUT, MDP_MM_SUBSYS_0}, | |
| 520 | + {0, 0, 0} | |
| 521 | + }, | |
| 522 | + [MDP_COMP_TO_WARP0MOUT] = { | |
| 523 | + {MDP_COMP_TYPE_DUMMY, 1, MT8188_MDP_COMP_TO_WARP0MOUT, MDP_MM_SUBSYS_0}, | |
| 524 | + {0, 0, 0} | |
| 525 | + }, | |
| 526 | + [MDP_COMP_TO_SVPP2MOUT] = { | |
| 527 | + {MDP_COMP_TYPE_DUMMY, 2, MT8188_MDP_COMP_TO_SVPP2MOUT, MDP_MM_SUBSYS_1}, | |
| 528 | + {0, 0, 0} | |
| 529 | + }, | |
| 530 | + [MDP_COMP_TO_SVPP3MOUT] = { | |
| 531 | + {MDP_COMP_TYPE_DUMMY, 3, MT8188_MDP_COMP_TO_SVPP3MOUT, MDP_MM_SUBSYS_1}, | |
| 532 | + {0, 0, 0} | |
| 533 | + }, | |
| 534 | + [MDP_COMP_VPP0_SOUT] = { | |
| 535 | + {MDP_COMP_TYPE_PATH, 0, MT8188_MDP_COMP_VPP0_SOUT, MDP_MM_SUBSYS_1}, | |
| 536 | + {2, 6, 0} | |
| 537 | + }, | |
| 538 | + [MDP_COMP_VPP1_SOUT] = { | |
| 539 | + {MDP_COMP_TYPE_PATH, 1, MT8188_MDP_COMP_VPP1_SOUT, MDP_MM_SUBSYS_0}, | |
| 540 | + {2, 8, 0} | |
| 541 | + }, | |
| 542 | +}; | |
| 543 | + | |
| 291 | 544 | static const struct mdp_comp_data mt8195_mdp_comp_data[MDP_MAX_COMP_COUNT] = { |
| 292 | 545 | [MDP_COMP_WPEI] = { |
| 293 | 546 | {MDP_COMP_TYPE_WPEI, 0, MT8195_MDP_COMP_WPEI, MDP_MM_SUBSYS_0}, |
| @@ -1046,6 +1299,15 @@ static const struct mdp_pipe_info mt8183_pipe_info[] = { · 752 unmodified lines | ||
| 1046 | 1299 | [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 3} |
| 1047 | 1300 | }; |
| 1048 | 1301 | |
| 1302 | +static const struct mdp_pipe_info mt8188_pipe_info[] = { | |
| 1303 | + [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0}, | |
| 1304 | + [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 1}, | |
| 1305 | + [MDP_PIPE_RDMA2] = {MDP_PIPE_RDMA2, MDP_MM_SUBSYS_1, 0}, | |
| 1306 | + [MDP_PIPE_RDMA3] = {MDP_PIPE_RDMA3, MDP_MM_SUBSYS_1, 1}, | |
| 1307 | + [MDP_PIPE_VPP1_SOUT] = {MDP_PIPE_VPP1_SOUT, MDP_MM_SUBSYS_0, 2}, | |
| 1308 | + [MDP_PIPE_VPP0_SOUT] = {MDP_PIPE_VPP0_SOUT, MDP_MM_SUBSYS_1, 2}, | |
| 1309 | +}; | |
| 1310 | + | |
| 1049 | 1311 | static const struct mdp_pipe_info mt8195_pipe_info[] = { |
| 1050 | 1312 | [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0}, |
| 1051 | 1313 | [MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, MDP_MM_SUBSYS_0, 1}, |
| @@ -1082,6 +1344,24 @@ const struct mtk_mdp_driver_data mt8183_mdp_driver_data = { · 30 unmodified lines | ||
| 1082 | 1344 | .pp_used = MDP_PP_USED_1, |
| 1083 | 1345 | }; |
| 1084 | 1346 | |
| 1347 | +const struct mtk_mdp_driver_data mt8188_mdp_driver_data = { | |
| 1348 | + .mdp_plat_id = MT8188, | |
| 1349 | + .mdp_con_res = 0x14001000, | |
| 1350 | + .mdp_probe_infra = mt8188_mdp_probe_infra, | |
| 1351 | + .mdp_sub_comp_dt_ids = mt8195_sub_comp_dt_ids, | |
| 1352 | + .mdp_cfg = &mt8195_plat_cfg, | |
| 1353 | + .mdp_mutex_table_idx = mt8188_mutex_idx, | |
| 1354 | + .comp_data = mt8188_mdp_comp_data, | |
| 1355 | + .comp_data_len = ARRAY_SIZE(mt8188_mdp_comp_data), | |
| 1356 | + .format = mt8195_formats, | |
| 1357 | + .format_len = ARRAY_SIZE(mt8195_formats), | |
| 1358 | + .def_limit = &mt8195_mdp_def_limit, | |
| 1359 | + .pipe_info = mt8188_pipe_info, | |
| 1360 | + .pipe_info_len = ARRAY_SIZE(mt8188_pipe_info), | |
| 1361 | + .pp_criteria = &mt8195_mdp_pp_criteria, | |
| 1362 | + .pp_used = MDP_PP_USED_2, | |
| 1363 | +}; | |
| 1364 | + | |
| 1085 | 1365 | const struct mtk_mdp_driver_data mt8195_mdp_driver_data = { |
| 1086 | 1366 | .mdp_plat_id = MT8195, |
| 1087 | 1367 | .mdp_con_res = 0x14001000, |
| @@ -116,6 +116,7 @@ struct img_frameparam { · 115 unmodified lines | ||
| 116 | 116 | |
| 117 | 117 | /* Platform config indicator */ |
| 118 | 118 | #define MT8183 8183 |
| 119 | +#define MT8188 8195 | |
| 119 | 120 | #define MT8195 8195 |
| 120 | 121 | |
| 121 | 122 | #define CFG_CHECK(plat, p_id) ((plat) == (p_id)) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/types.h> |
| 11 | 11 | |
| 12 | 12 | extern const struct mtk_mdp_driver_data mt8183_mdp_driver_data; |
| 13 | +extern const struct mtk_mdp_driver_data mt8188_mdp_driver_data; | |
| 13 | 14 | extern const struct mtk_mdp_driver_data mt8195_mdp_driver_data; |
| 14 | 15 | |
| 15 | 16 | struct mdp_dev; |
| @@ -21,6 +21,9 @@ static const struct of_device_id mdp_of_ids[] = { · 20 unmodified lines | ||
| 21 | 21 | { .compatible = "mediatek,mt8183-mdp3-rdma", |
| 22 | 22 | .data = &mt8183_mdp_driver_data, |
| 23 | 23 | }, |
| 24 | + { .compatible = "mediatek,mt8188-mdp3-rdma", | |
| 25 | + .data = &mt8188_mdp_driver_data, | |
| 26 | + }, | |
| 24 | 27 | { .compatible = "mediatek,mt8195-mdp3-rdma", |
| 25 | 28 | .data = &mt8195_mdp_driver_data, |
| 26 | 29 | }, |
| @@ -63,7 +63,8 @@ int mtk_vcodec_mem_alloc(void *priv, struct mtk_vcodec_mem *mem) · 62 unmodified lines | ||
| 63 | 63 | id = dec_ctx->id; |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | − mem->va = dma_alloc_coherent(&plat_dev->dev, mem->size, &mem->dma_addr, GFP_KERNEL); | |
| 66 | + mem->va = dma_alloc_attrs(&plat_dev->dev, mem->size, &mem->dma_addr, | |
| 67 | + GFP_KERNEL, DMA_ATTR_ALLOC_SINGLE_PAGES); | |
| 67 | 68 | if (!mem->va) { |
| 68 | 69 | mtk_v4l2_err(plat_dev, "%s dma_alloc size=0x%zx failed!", |
| 69 | 70 | __func__, mem->size); |
| @@ -80,21 +80,18 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_dec_ctx *ctx, · 79 unmodified lines | ||
| 80 | 80 | return &ctx->q_data[MTK_Q_DATA_DST]; |
| 81 | 81 | } |
| 82 | 82 | |
| 83 | −static int vidioc_try_decoder_cmd(struct file *file, void *priv, | |
| 84 | − struct v4l2_decoder_cmd *cmd) | |
| 83 | +static int stateful_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 85 | 84 | { |
| 86 | 85 | return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); |
| 87 | 86 | } |
| 88 | 87 | |
| 89 | − | |
| 90 | −static int vidioc_decoder_cmd(struct file *file, void *priv, | |
| 91 | − struct v4l2_decoder_cmd *cmd) | |
| 88 | +static int stateful_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 92 | 89 | { |
| 93 | 90 | struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); |
| 94 | 91 | struct vb2_queue *src_vq, *dst_vq; |
| 95 | 92 | int ret; |
| 96 | 93 | |
| 97 | − ret = vidioc_try_decoder_cmd(file, priv, cmd); | |
| 94 | + ret = stateful_try_decoder_cmd(file, priv, cmd); | |
| 98 | 95 | if (ret) |
| 99 | 96 | return ret; |
| 100 | 97 | |
| @@ -128,6 +125,57 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, · 27 unmodified lines | ||
| 128 | 125 | return 0; |
| 129 | 126 | } |
| 130 | 127 | |
| 128 | +static int stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 129 | +{ | |
| 130 | + return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd); | |
| 131 | +} | |
| 132 | + | |
| 133 | +static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 134 | +{ | |
| 135 | + struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); | |
| 136 | + int ret; | |
| 137 | + | |
| 138 | + ret = v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd); | |
| 139 | + if (ret) | |
| 140 | + return ret; | |
| 141 | + | |
| 142 | + mtk_v4l2_vdec_dbg(3, ctx, "decoder cmd=%u", cmd->cmd); | |
| 143 | + switch (cmd->cmd) { | |
| 144 | + case V4L2_DEC_CMD_FLUSH: | |
| 145 | + /* | |
| 146 | + * If the flag of the output buffer is equals V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF, | |
| 147 | + * this command will prevent dequeueing the capture buffer containing the last | |
| 148 | + * decoded frame. Or do nothing | |
| 149 | + */ | |
| 150 | + break; | |
| 151 | + default: | |
| 152 | + mtk_v4l2_vdec_err(ctx, "invalid stateless decoder cmd=%u", cmd->cmd); | |
| 153 | + return -EINVAL; | |
| 154 | + } | |
| 155 | + | |
| 156 | + return 0; | |
| 157 | +} | |
| 158 | + | |
| 159 | +static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 160 | +{ | |
| 161 | + struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); | |
| 162 | + | |
| 163 | + if (ctx->dev->vdec_pdata->uses_stateless_api) | |
| 164 | + return stateless_try_decoder_cmd(file, priv, cmd); | |
| 165 | + | |
| 166 | + return stateful_try_decoder_cmd(file, priv, cmd); | |
| 167 | +} | |
| 168 | + | |
| 169 | +static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 170 | +{ | |
| 171 | + struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); | |
| 172 | + | |
| 173 | + if (ctx->dev->vdec_pdata->uses_stateless_api) | |
| 174 | + return stateless_decoder_cmd(file, priv, cmd); | |
| 175 | + | |
| 176 | + return stateful_decoder_cmd(file, priv, cmd); | |
| 177 | +} | |
| 178 | + | |
| 131 | 179 | void mtk_vdec_unlock(struct mtk_vcodec_dec_ctx *ctx) |
| 132 | 180 | { |
| 133 | 181 | mutex_unlock(&ctx->dev->dec_mutex[ctx->hw_id]); |
| @@ -449,7 +449,7 @@ static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs, · 448 unmodified lines | ||
| 449 | 449 | inst->frm_cnt, y_fb_dma, c_fb_dma, fb); |
| 450 | 450 | |
| 451 | 451 | inst->cur_fb = fb; |
| 452 | − dec->bs_dma = (uint64_t)bs->dma_addr; | |
| 452 | + dec->bs_dma = bs->dma_addr; | |
| 453 | 453 | dec->bs_sz = bs->size; |
| 454 | 454 | dec->cur_y_fb_dma = y_fb_dma; |
| 455 | 455 | dec->cur_c_fb_dma = c_fb_dma; |
| @@ -233,6 +233,12 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu) · 232 unmodified lines | ||
| 233 | 233 | mtk_vdec_debug(vpu->ctx, "vdec_inst=%p", vpu); |
| 234 | 234 | |
| 235 | 235 | err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg)); |
| 236 | + | |
| 237 | + if (IS_ERR_OR_NULL(vpu->vsi)) { | |
| 238 | + mtk_vdec_err(vpu->ctx, "invalid vdec vsi, status=%d", err); | |
| 239 | + return -EINVAL; | |
| 240 | + } | |
| 241 | + | |
| 236 | 242 | mtk_vdec_debug(vpu->ctx, "- ret=%d", err); |
| 237 | 243 | return err; |
| 238 | 244 | } |
| @@ -19,11 +19,6 @@ · 18 unmodified lines | ||
| 19 | 19 | #define FLAG_B_FRAME 0x1 |
| 20 | 20 | #define FLAG_REFERENCE 0x2 |
| 21 | 21 | |
| 22 | −struct tegra_vde_h264_frame { | |
| 23 | − unsigned int frame_num; | |
| 24 | − unsigned int flags; | |
| 25 | −}; | |
| 26 | − | |
| 27 | 22 | struct tegra_vde_h264_decoder_ctx { |
| 28 | 23 | unsigned int dpb_frames_nb; |
| 29 | 24 | unsigned int dpb_ref_frames_with_earlier_poc_nb; |
| @@ -47,7 +47,6 @@ struct iommu_group; · 46 unmodified lines | ||
| 47 | 47 | struct iommu_domain; |
| 48 | 48 | struct reset_control; |
| 49 | 49 | struct dma_buf_attachment; |
| 50 | −struct tegra_vde_h264_frame; | |
| 51 | 50 | struct tegra_vde_h264_decoder_ctx; |
| 52 | 51 | |
| 53 | 52 | struct tegra_video_frame { |
| @@ -1634,6 +1634,9 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count) · 1633 unmodified lines | ||
| 1634 | 1634 | dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); |
| 1635 | 1635 | q_data->sequence = 0; |
| 1636 | 1636 | |
| 1637 | + if (V4L2_TYPE_IS_CAPTURE(q->type)) | |
| 1638 | + ctx->need_initial_source_change_evt = false; | |
| 1639 | + | |
| 1637 | 1640 | ret = pm_runtime_resume_and_get(ctx->mxc_jpeg->dev); |
| 1638 | 1641 | if (ret < 0) { |
| 1639 | 1642 | dev_err(ctx->mxc_jpeg->dev, "Failed to power up jpeg\n"); |
| @@ -1840,17 +1843,6 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) · 200 unmodified lines | ||
| 1840 | 1843 | |
| 1841 | 1844 | q_data_out = mxc_jpeg_get_q_data(ctx, |
| 1842 | 1845 | V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); |
| 1843 | − if (q_data_out->w == 0 && q_data_out->h == 0) { | |
| 1844 | − dev_warn(dev, "Invalid user resolution 0x0"); | |
| 1845 | − dev_warn(dev, "Keeping resolution from JPEG: %dx%d", | |
| 1846 | − header.frame.width, header.frame.height); | |
| 1847 | − } else if (header.frame.width != q_data_out->w || | |
| 1848 | − header.frame.height != q_data_out->h) { | |
| 1849 | − dev_err(dev, | |
| 1850 | − "Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)", | |
| 1851 | − header.frame.width, header.frame.height, | |
| 1852 | − q_data_out->w, q_data_out->h); | |
| 1853 | − } | |
| 1854 | 1846 | q_data_out->w = header.frame.width; |
| 1855 | 1847 | q_data_out->h = header.frame.height; |
| 1856 | 1848 | if (header.frame.width > MXC_JPEG_MAX_WIDTH || |
| @@ -320,7 +320,11 @@ struct mipi_csis_device { · 319 unmodified lines | ||
| 320 | 320 | struct v4l2_subdev sd; |
| 321 | 321 | struct media_pad pads[CSIS_PADS_NUM]; |
| 322 | 322 | struct v4l2_async_notifier notifier; |
| 323 | − struct v4l2_subdev *src_sd; | |
| 323 | + | |
| 324 | + struct { | |
| 325 | + struct v4l2_subdev *sd; | |
| 326 | + const struct media_pad *pad; | |
| 327 | + } source; | |
| 324 | 328 | |
| 325 | 329 | struct v4l2_mbus_config_mipi_csi2 bus; |
| 326 | 330 | u32 clk_frequency; |
| @@ -597,7 +601,7 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis, · 270 unmodified lines | ||
| 597 | 601 | u32 lane_rate; |
| 598 | 602 | |
| 599 | 603 | /* Calculate the line rate from the pixel rate. */ |
| 600 | − link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler, | |
| 604 | + link_freq = v4l2_get_link_freq(csis->source.sd->ctrl_handler, | |
| 601 | 605 | csis_fmt->width, |
| 602 | 606 | csis->bus.num_data_lanes * 2); |
| 603 | 607 | if (link_freq < 0) { |
| @@ -958,7 +962,8 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) · 354 unmodified lines | ||
| 958 | 962 | int ret; |
| 959 | 963 | |
| 960 | 964 | if (!enable) { |
| 961 | − v4l2_subdev_call(csis->src_sd, video, s_stream, 0); | |
| 965 | + v4l2_subdev_disable_streams(csis->source.sd, | |
| 966 | + csis->source.pad->index, BIT(0)); | |
| 962 | 967 | |
| 963 | 968 | mipi_csis_stop_stream(csis); |
| 964 | 969 | if (csis->debug.enable) |
| @@ -986,7 +991,8 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable) · 21 unmodified lines | ||
| 986 | 991 | |
| 987 | 992 | mipi_csis_start_stream(csis, format, csis_fmt); |
| 988 | 993 | |
| 989 | − ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1); | |
| 994 | + ret = v4l2_subdev_enable_streams(csis->source.sd, | |
| 995 | + csis->source.pad->index, BIT(0)); | |
| 990 | 996 | if (ret < 0) |
| 991 | 997 | goto err_stop; |
| 992 | 998 | |
| @@ -1233,12 +1239,14 @@ static int mipi_csis_link_setup(struct media_entity *entity, · 240 unmodified lines | ||
| 1233 | 1239 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); |
| 1234 | 1240 | |
| 1235 | 1241 | if (flags & MEDIA_LNK_FL_ENABLED) { |
| 1236 | − if (csis->src_sd) | |
| 1242 | + if (csis->source.sd) | |
| 1237 | 1243 | return -EBUSY; |
| 1238 | 1244 | |
| 1239 | − csis->src_sd = remote_sd; | |
| 1245 | + csis->source.sd = remote_sd; | |
| 1246 | + csis->source.pad = remote_pad; | |
| 1240 | 1247 | } else { |
| 1241 | − csis->src_sd = NULL; | |
| 1248 | + csis->source.sd = NULL; | |
| 1249 | + csis->source.pad = NULL; | |
| 1242 | 1250 | } |
| 1243 | 1251 | |
| 1244 | 1252 | return 0; |
| @@ -1805,6 +1805,9 @@ static int pxp_probe(struct platform_device *pdev) · 1804 unmodified lines | ||
| 1805 | 1805 | return PTR_ERR(mmio); |
| 1806 | 1806 | dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, |
| 1807 | 1807 | &pxp_regmap_config); |
| 1808 | + if (IS_ERR(dev->regmap)) | |
| 1809 | + return dev_err_probe(&pdev->dev, PTR_ERR(dev->regmap), | |
| 1810 | + "Failed to init regmap\n"); | |
| 1808 | 1811 | |
| 1809 | 1812 | irq = platform_get_irq(pdev, 0); |
| 1810 | 1813 | if (irq < 0) |
| @@ -19,5 +19,6 @@ qcom-camss-objs += \ · 18 unmodified lines | ||
| 19 | 19 | camss-vfe-gen1.o \ |
| 20 | 20 | camss-vfe.o \ |
| 21 | 21 | camss-video.o \ |
| 22 | + camss-format.o \ | |
| 22 | 23 | |
| 23 | 24 | obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o |
| @@ -45,128 +45,6 @@ · 44 unmodified lines | ||
| 45 | 45 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n)) |
| 46 | 46 | #define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n)) |
| 47 | 47 | |
| 48 | −static const struct csid_format csid_formats[] = { | |
| 49 | − { | |
| 50 | − MEDIA_BUS_FMT_UYVY8_1X16, | |
| 51 | − DATA_TYPE_YUV422_8BIT, | |
| 52 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 53 | − 8, | |
| 54 | − 2, | |
| 55 | − }, | |
| 56 | − { | |
| 57 | − MEDIA_BUS_FMT_VYUY8_1X16, | |
| 58 | − DATA_TYPE_YUV422_8BIT, | |
| 59 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 60 | − 8, | |
| 61 | − 2, | |
| 62 | − }, | |
| 63 | − { | |
| 64 | − MEDIA_BUS_FMT_YUYV8_1X16, | |
| 65 | − DATA_TYPE_YUV422_8BIT, | |
| 66 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 67 | − 8, | |
| 68 | − 2, | |
| 69 | − }, | |
| 70 | − { | |
| 71 | − MEDIA_BUS_FMT_YVYU8_1X16, | |
| 72 | − DATA_TYPE_YUV422_8BIT, | |
| 73 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 74 | − 8, | |
| 75 | − 2, | |
| 76 | − }, | |
| 77 | − { | |
| 78 | − MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 79 | − DATA_TYPE_RAW_8BIT, | |
| 80 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 81 | − 8, | |
| 82 | − 1, | |
| 83 | − }, | |
| 84 | − { | |
| 85 | − MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 86 | − DATA_TYPE_RAW_8BIT, | |
| 87 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 88 | − 8, | |
| 89 | − 1, | |
| 90 | − }, | |
| 91 | − { | |
| 92 | − MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 93 | − DATA_TYPE_RAW_8BIT, | |
| 94 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 95 | − 8, | |
| 96 | − 1, | |
| 97 | − }, | |
| 98 | − { | |
| 99 | − MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 100 | − DATA_TYPE_RAW_8BIT, | |
| 101 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 102 | − 8, | |
| 103 | − 1, | |
| 104 | − }, | |
| 105 | − { | |
| 106 | − MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 107 | − DATA_TYPE_RAW_10BIT, | |
| 108 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 109 | − 10, | |
| 110 | − 1, | |
| 111 | − }, | |
| 112 | − { | |
| 113 | − MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 114 | − DATA_TYPE_RAW_10BIT, | |
| 115 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 116 | − 10, | |
| 117 | − 1, | |
| 118 | − }, | |
| 119 | − { | |
| 120 | − MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 121 | − DATA_TYPE_RAW_10BIT, | |
| 122 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 123 | − 10, | |
| 124 | − 1, | |
| 125 | − }, | |
| 126 | − { | |
| 127 | − MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 128 | − DATA_TYPE_RAW_10BIT, | |
| 129 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 130 | − 10, | |
| 131 | − 1, | |
| 132 | − }, | |
| 133 | − { | |
| 134 | − MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 135 | − DATA_TYPE_RAW_12BIT, | |
| 136 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 137 | − 12, | |
| 138 | − 1, | |
| 139 | − }, | |
| 140 | − { | |
| 141 | − MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 142 | − DATA_TYPE_RAW_12BIT, | |
| 143 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 144 | − 12, | |
| 145 | − 1, | |
| 146 | − }, | |
| 147 | − { | |
| 148 | − MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 149 | − DATA_TYPE_RAW_12BIT, | |
| 150 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 151 | − 12, | |
| 152 | − 1, | |
| 153 | − }, | |
| 154 | − { | |
| 155 | − MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 156 | − DATA_TYPE_RAW_12BIT, | |
| 157 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 158 | − 12, | |
| 159 | − 1, | |
| 160 | − }, | |
| 161 | − { | |
| 162 | − MEDIA_BUS_FMT_Y10_1X10, | |
| 163 | − DATA_TYPE_RAW_10BIT, | |
| 164 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 165 | − 10, | |
| 166 | − 1, | |
| 167 | − }, | |
| 168 | −}; | |
| 169 | − | |
| 170 | 48 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
| 171 | 49 | { |
| 172 | 50 | struct csid_testgen_config *tg = &csid->testgen; |
| @@ -174,7 +52,7 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 1 unmodified line | ||
| 174 | 52 | |
| 175 | 53 | if (enable) { |
| 176 | 54 | struct v4l2_mbus_framefmt *input_format; |
| 177 | − const struct csid_format *format; | |
| 55 | + const struct csid_format_info *format; | |
| 178 | 56 | u8 vc = 0; /* Virtual Channel 0 */ |
| 179 | 57 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ |
| 180 | 58 | u8 dt_shift; |
| @@ -184,7 +62,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 3 unmodified lines | ||
| 184 | 62 | u32 num_lines, num_bytes_per_line; |
| 185 | 63 | |
| 186 | 64 | input_format = &csid->fmt[MSM_CSID_PAD_SRC]; |
| 187 | − format = csid_get_fmt_entry(csid->formats, csid->nformats, | |
| 65 | + format = csid_get_fmt_entry(csid->res->formats->formats, | |
| 66 | + csid->res->formats->nformats, | |
| 188 | 67 | input_format->code); |
| 189 | 68 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; |
| 190 | 69 | num_lines = input_format->height; |
| @@ -211,7 +90,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 20 unmodified lines | ||
| 211 | 90 | struct csid_phy_config *phy = &csid->phy; |
| 212 | 91 | |
| 213 | 92 | input_format = &csid->fmt[MSM_CSID_PAD_SINK]; |
| 214 | − format = csid_get_fmt_entry(csid->formats, csid->nformats, | |
| 93 | + format = csid_get_fmt_entry(csid->res->formats->formats, | |
| 94 | + csid->res->formats->nformats, | |
| 215 | 95 | input_format->code); |
| 216 | 96 | |
| 217 | 97 | val = phy->lane_cnt - 1; |
| @@ -311,8 +191,6 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, · 93 unmodified lines | ||
| 311 | 191 | |
| 312 | 192 | static void csid_subdev_init(struct csid_device *csid) |
| 313 | 193 | { |
| 314 | − csid->formats = csid_formats; | |
| 315 | − csid->nformats = ARRAY_SIZE(csid_formats); | |
| 316 | 194 | csid->testgen.modes = csid_testgen_modes; |
| 317 | 195 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; |
| 318 | 196 | } |
| @@ -44,156 +44,6 @@ · 43 unmodified lines | ||
| 44 | 44 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n)) |
| 45 | 45 | #define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0bc + 0xc * (n)) |
| 46 | 46 | |
| 47 | −static const struct csid_format csid_formats[] = { | |
| 48 | − { | |
| 49 | − MEDIA_BUS_FMT_UYVY8_1X16, | |
| 50 | − DATA_TYPE_YUV422_8BIT, | |
| 51 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 52 | − 8, | |
| 53 | − 2, | |
| 54 | − }, | |
| 55 | − { | |
| 56 | − MEDIA_BUS_FMT_VYUY8_1X16, | |
| 57 | − DATA_TYPE_YUV422_8BIT, | |
| 58 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 59 | − 8, | |
| 60 | − 2, | |
| 61 | − }, | |
| 62 | − { | |
| 63 | − MEDIA_BUS_FMT_YUYV8_1X16, | |
| 64 | − DATA_TYPE_YUV422_8BIT, | |
| 65 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 66 | − 8, | |
| 67 | − 2, | |
| 68 | − }, | |
| 69 | − { | |
| 70 | − MEDIA_BUS_FMT_YVYU8_1X16, | |
| 71 | − DATA_TYPE_YUV422_8BIT, | |
| 72 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 73 | − 8, | |
| 74 | − 2, | |
| 75 | − }, | |
| 76 | − { | |
| 77 | − MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 78 | − DATA_TYPE_RAW_8BIT, | |
| 79 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 80 | − 8, | |
| 81 | − 1, | |
| 82 | − }, | |
| 83 | − { | |
| 84 | − MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 85 | − DATA_TYPE_RAW_8BIT, | |
| 86 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 87 | − 8, | |
| 88 | − 1, | |
| 89 | − }, | |
| 90 | − { | |
| 91 | − MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 92 | − DATA_TYPE_RAW_8BIT, | |
| 93 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 94 | − 8, | |
| 95 | − 1, | |
| 96 | − }, | |
| 97 | − { | |
| 98 | − MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 99 | − DATA_TYPE_RAW_8BIT, | |
| 100 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 101 | − 8, | |
| 102 | − 1, | |
| 103 | − }, | |
| 104 | − { | |
| 105 | − MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 106 | − DATA_TYPE_RAW_10BIT, | |
| 107 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 108 | − 10, | |
| 109 | − 1, | |
| 110 | − }, | |
| 111 | − { | |
| 112 | − MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 113 | − DATA_TYPE_RAW_10BIT, | |
| 114 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 115 | − 10, | |
| 116 | − 1, | |
| 117 | − }, | |
| 118 | − { | |
| 119 | − MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 120 | − DATA_TYPE_RAW_10BIT, | |
| 121 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 122 | − 10, | |
| 123 | − 1, | |
| 124 | − }, | |
| 125 | − { | |
| 126 | − MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 127 | − DATA_TYPE_RAW_10BIT, | |
| 128 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 129 | − 10, | |
| 130 | − 1, | |
| 131 | − }, | |
| 132 | − { | |
| 133 | − MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 134 | − DATA_TYPE_RAW_12BIT, | |
| 135 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 136 | − 12, | |
| 137 | − 1, | |
| 138 | − }, | |
| 139 | − { | |
| 140 | − MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 141 | − DATA_TYPE_RAW_12BIT, | |
| 142 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 143 | − 12, | |
| 144 | − 1, | |
| 145 | − }, | |
| 146 | − { | |
| 147 | − MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 148 | − DATA_TYPE_RAW_12BIT, | |
| 149 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 150 | − 12, | |
| 151 | − 1, | |
| 152 | − }, | |
| 153 | − { | |
| 154 | − MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 155 | − DATA_TYPE_RAW_12BIT, | |
| 156 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 157 | − 12, | |
| 158 | − 1, | |
| 159 | − }, | |
| 160 | − { | |
| 161 | − MEDIA_BUS_FMT_SBGGR14_1X14, | |
| 162 | − DATA_TYPE_RAW_14BIT, | |
| 163 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 164 | − 14, | |
| 165 | − 1, | |
| 166 | − }, | |
| 167 | − { | |
| 168 | − MEDIA_BUS_FMT_SGBRG14_1X14, | |
| 169 | − DATA_TYPE_RAW_14BIT, | |
| 170 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 171 | − 14, | |
| 172 | − 1, | |
| 173 | − }, | |
| 174 | − { | |
| 175 | − MEDIA_BUS_FMT_SGRBG14_1X14, | |
| 176 | − DATA_TYPE_RAW_14BIT, | |
| 177 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 178 | − 14, | |
| 179 | − 1, | |
| 180 | − }, | |
| 181 | − { | |
| 182 | − MEDIA_BUS_FMT_SRGGB14_1X14, | |
| 183 | − DATA_TYPE_RAW_14BIT, | |
| 184 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 185 | − 14, | |
| 186 | − 1, | |
| 187 | − }, | |
| 188 | − { | |
| 189 | − MEDIA_BUS_FMT_Y10_1X10, | |
| 190 | − DATA_TYPE_RAW_10BIT, | |
| 191 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 192 | − 10, | |
| 193 | − 1, | |
| 194 | − }, | |
| 195 | −}; | |
| 196 | − | |
| 197 | 47 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
| 198 | 48 | { |
| 199 | 49 | struct csid_testgen_config *tg = &csid->testgen; |
| @@ -203,7 +53,7 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 3 unmodified lines | ||
| 203 | 53 | |
| 204 | 54 | if (enable) { |
| 205 | 55 | struct v4l2_mbus_framefmt *input_format; |
| 206 | − const struct csid_format *format; | |
| 56 | + const struct csid_format_info *format; | |
| 207 | 57 | u8 vc = 0; /* Virtual Channel 0 */ |
| 208 | 58 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ |
| 209 | 59 | u8 dt_shift; |
| @@ -213,7 +63,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 3 unmodified lines | ||
| 213 | 63 | u32 num_bytes_per_line, num_lines; |
| 214 | 64 | |
| 215 | 65 | input_format = &csid->fmt[MSM_CSID_PAD_SRC]; |
| 216 | − format = csid_get_fmt_entry(csid->formats, csid->nformats, | |
| 66 | + format = csid_get_fmt_entry(csid->res->formats->formats, | |
| 67 | + csid->res->formats->nformats, | |
| 217 | 68 | input_format->code); |
| 218 | 69 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; |
| 219 | 70 | num_lines = input_format->height; |
| @@ -240,7 +91,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 20 unmodified lines | ||
| 240 | 91 | struct csid_phy_config *phy = &csid->phy; |
| 241 | 92 | |
| 242 | 93 | input_format = &csid->fmt[MSM_CSID_PAD_SINK]; |
| 243 | − format = csid_get_fmt_entry(csid->formats, csid->nformats, | |
| 94 | + format = csid_get_fmt_entry(csid->res->formats->formats, | |
| 95 | + csid->res->formats->nformats, | |
| 244 | 96 | input_format->code); |
| 245 | 97 | |
| 246 | 98 | val = phy->lane_cnt - 1; |
| @@ -387,8 +239,6 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, · 140 unmodified lines | ||
| 387 | 239 | |
| 388 | 240 | static void csid_subdev_init(struct csid_device *csid) |
| 389 | 241 | { |
| 390 | − csid->formats = csid_formats; | |
| 391 | − csid->nformats = ARRAY_SIZE(csid_formats); | |
| 392 | 242 | csid->testgen.modes = csid_testgen_modes; |
| 393 | 243 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; |
| 394 | 244 | } |
| @@ -176,306 +176,171 @@ · 175 unmodified lines | ||
| 176 | 176 | #define TPG_COLOR_BOX_CFG_MODE 0 |
| 177 | 177 | #define TPG_COLOR_BOX_PATTERN_SEL 2 |
| 178 | 178 | |
| 179 | −static const struct csid_format csid_formats[] = { | |
| 180 | − { | |
| 181 | − MEDIA_BUS_FMT_UYVY8_1X16, | |
| 182 | − DATA_TYPE_YUV422_8BIT, | |
| 183 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 184 | − 8, | |
| 185 | − 2, | |
| 186 | − }, | |
| 187 | − { | |
| 188 | − MEDIA_BUS_FMT_VYUY8_1X16, | |
| 189 | − DATA_TYPE_YUV422_8BIT, | |
| 190 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 191 | − 8, | |
| 192 | − 2, | |
| 193 | − }, | |
| 194 | − { | |
| 195 | − MEDIA_BUS_FMT_YUYV8_1X16, | |
| 196 | − DATA_TYPE_YUV422_8BIT, | |
| 197 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 198 | − 8, | |
| 199 | − 2, | |
| 200 | − }, | |
| 201 | − { | |
| 202 | − MEDIA_BUS_FMT_YVYU8_1X16, | |
| 203 | − DATA_TYPE_YUV422_8BIT, | |
| 204 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 205 | − 8, | |
| 206 | − 2, | |
| 207 | − }, | |
| 208 | − { | |
| 209 | − MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 210 | − DATA_TYPE_RAW_8BIT, | |
| 211 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 212 | − 8, | |
| 213 | − 1, | |
| 214 | − }, | |
| 215 | − { | |
| 216 | − MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 217 | − DATA_TYPE_RAW_8BIT, | |
| 218 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 219 | − 8, | |
| 220 | − 1, | |
| 221 | − }, | |
| 222 | − { | |
| 223 | − MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 224 | − DATA_TYPE_RAW_8BIT, | |
| 225 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 226 | − 8, | |
| 227 | − 1, | |
| 228 | − }, | |
| 229 | − { | |
| 230 | − MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 231 | − DATA_TYPE_RAW_8BIT, | |
| 232 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 233 | − 8, | |
| 234 | − 1, | |
| 235 | − }, | |
| 236 | − { | |
| 237 | − MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 238 | − DATA_TYPE_RAW_10BIT, | |
| 239 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 240 | − 10, | |
| 241 | − 1, | |
| 242 | − }, | |
| 243 | − { | |
| 244 | − MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 245 | − DATA_TYPE_RAW_10BIT, | |
| 246 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 247 | − 10, | |
| 248 | − 1, | |
| 249 | − }, | |
| 250 | − { | |
| 251 | − MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 252 | − DATA_TYPE_RAW_10BIT, | |
| 253 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 254 | − 10, | |
| 255 | − 1, | |
| 256 | − }, | |
| 257 | − { | |
| 258 | − MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 259 | − DATA_TYPE_RAW_10BIT, | |
| 260 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 261 | − 10, | |
| 262 | − 1, | |
| 263 | − }, | |
| 264 | − { | |
| 265 | − MEDIA_BUS_FMT_Y8_1X8, | |
| 266 | − DATA_TYPE_RAW_8BIT, | |
| 267 | − DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 268 | − 8, | |
| 269 | − 1, | |
| 270 | − }, | |
| 271 | − { | |
| 272 | − MEDIA_BUS_FMT_Y10_1X10, | |
| 273 | − DATA_TYPE_RAW_10BIT, | |
| 274 | − DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 275 | − 10, | |
| 276 | − 1, | |
| 277 | − }, | |
| 278 | − { | |
| 279 | − MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 280 | − DATA_TYPE_RAW_12BIT, | |
| 281 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 282 | − 12, | |
| 283 | − 1, | |
| 284 | − }, | |
| 285 | − { | |
| 286 | − MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 287 | − DATA_TYPE_RAW_12BIT, | |
| 288 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 289 | − 12, | |
| 290 | − 1, | |
| 291 | − }, | |
| 292 | − { | |
| 293 | − MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 294 | − DATA_TYPE_RAW_12BIT, | |
| 295 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 296 | − 12, | |
| 297 | − 1, | |
| 298 | − }, | |
| 299 | − { | |
| 300 | − MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 301 | − DATA_TYPE_RAW_12BIT, | |
| 302 | − DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 303 | − 12, | |
| 304 | − 1, | |
| 305 | − }, | |
| 306 | − { | |
| 307 | − MEDIA_BUS_FMT_SBGGR14_1X14, | |
| 308 | − DATA_TYPE_RAW_14BIT, | |
| 309 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 310 | − 14, | |
| 311 | − 1, | |
| 312 | − }, | |
| 313 | − { | |
| 314 | − MEDIA_BUS_FMT_SGBRG14_1X14, | |
| 315 | − DATA_TYPE_RAW_14BIT, | |
| 316 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 317 | − 14, | |
| 318 | − 1, | |
| 319 | − }, | |
| 320 | − { | |
| 321 | − MEDIA_BUS_FMT_SGRBG14_1X14, | |
| 322 | − DATA_TYPE_RAW_14BIT, | |
| 323 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 324 | − 14, | |
| 325 | − 1, | |
| 326 | − }, | |
| 327 | − { | |
| 328 | − MEDIA_BUS_FMT_SRGGB14_1X14, | |
| 329 | − DATA_TYPE_RAW_14BIT, | |
| 330 | − DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 331 | − 14, | |
| 332 | − 1, | |
| 333 | − }, | |
| 334 | −}; | |
| 335 | − | |
| 336 | −static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc) | |
| 179 | +static void __csid_configure_rx(struct csid_device *csid, | |
| 180 | + struct csid_phy_config *phy, int vc) | |
| 337 | 181 | { |
| 338 | − struct csid_testgen_config *tg = &csid->testgen; | |
| 339 | − u32 val; | |
| 340 | − u32 phy_sel = 0; | |
| 341 | 182 | u8 lane_cnt = csid->phy.lane_cnt; |
| 342 | − /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ | |
| 343 | − struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; | |
| 344 | − const struct csid_format *format = csid_get_fmt_entry(csid->formats, csid->nformats, | |
| 345 | − input_format->code); | |
| 183 | + int val; | |
| 346 | 184 | |
| 347 | 185 | if (!lane_cnt) |
| 348 | 186 | lane_cnt = 4; |
| 349 | 187 | |
| 350 | − if (!tg->enabled) | |
| 351 | − phy_sel = csid->phy.csiphy_id; | |
| 352 | − | |
| 353 | − if (enable) { | |
| 354 | − /* | |
| 355 | − * DT_ID is a two bit bitfield that is concatenated with | |
| 356 | − * the four least significant bits of the five bit VC | |
| 357 | − * bitfield to generate an internal CID value. | |
| 358 | − * | |
| 359 | − * CSID_RDI_CFG0(vc) | |
| 360 | − * DT_ID : 28:27 | |
| 361 | − * VC : 26:22 | |
| 362 | − * DT : 21:16 | |
| 363 | − * | |
| 364 | − * CID : VC 3:0 << 2 | DT_ID 1:0 | |
| 365 | − */ | |
| 366 | − u8 dt_id = vc & 0x03; | |
| 367 | − | |
| 368 | − if (tg->enabled) { | |
| 369 | − /* configure one DT, infinite frames */ | |
| 370 | − val = vc << TPG_VC_CFG0_VC_NUM; | |
| 371 | − val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE; | |
| 372 | − val |= 0 << TPG_VC_CFG0_NUM_FRAMES; | |
| 373 | − writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0); | |
| 374 | − | |
| 375 | − val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT; | |
| 376 | − val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT; | |
| 377 | − writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1); | |
| 378 | − | |
| 379 | − writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED); | |
| 380 | − | |
| 381 | − val = (input_format->height & 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT; | |
| 382 | − val |= (input_format->width & 0x1fff) << TPG_DT_n_CFG_0_FRAME_WIDTH; | |
| 383 | − writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0)); | |
| 384 | − | |
| 385 | − val = format->data_type << TPG_DT_n_CFG_1_DATA_TYPE; | |
| 386 | − writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0)); | |
| 387 | − | |
| 388 | − val = (tg->mode - 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE; | |
| 389 | − val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD; | |
| 390 | − val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT; | |
| 391 | − writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0)); | |
| 392 | − | |
| 393 | − writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG); | |
| 394 | − | |
| 395 | − writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG); | |
| 396 | − } | |
| 188 | + val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; | |
| 189 | + val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; | |
| 190 | + val |= phy->csiphy_id << CSI2_RX_CFG0_PHY_NUM_SEL; | |
| 191 | + writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); | |
| 397 | 192 | |
| 398 | − val = 1 << RDI_CFG0_BYTE_CNTR_EN; | |
| 399 | − val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN; | |
| 400 | − val |= 1 << RDI_CFG0_TIMESTAMP_EN; | |
| 401 | − /* note: for non-RDI path, this should be format->decode_format */ | |
| 402 | − val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; | |
| 403 | − val |= format->data_type << RDI_CFG0_DATA_TYPE; | |
| 404 | − val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; | |
| 405 | − val |= dt_id << RDI_CFG0_DT_ID; | |
| 406 | − writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); | |
| 193 | + val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; | |
| 194 | + if (vc > 3) | |
| 195 | + val |= 1 << CSI2_RX_CFG1_VC_MODE; | |
| 196 | + val |= 1 << CSI2_RX_CFG1_MISR_EN; | |
| 197 | + writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); | |
| 198 | +} | |
| 407 | 199 | |
| 408 | − /* CSID_TIMESTAMP_STB_POST_IRQ */ | |
| 409 | − val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL; | |
| 410 | − writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc)); | |
| 200 | +static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi) | |
| 201 | +{ | |
| 202 | + int val; | |
| 411 | 203 | |
| 412 | − val = 1; | |
| 413 | − writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); | |
| 204 | + if (enable) | |
| 205 | + val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; | |
| 206 | + else | |
| 207 | + val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; | |
| 208 | + writel_relaxed(val, csid->base + CSID_RDI_CTRL(rdi)); | |
| 209 | +} | |
| 414 | 210 | |
| 415 | − val = 0; | |
| 416 | − writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc)); | |
| 211 | +static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc) | |
| 212 | +{ | |
| 213 | + struct csid_testgen_config *tg = &csid->testgen; | |
| 214 | + struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; | |
| 215 | + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, | |
| 216 | + csid->res->formats->nformats, | |
| 217 | + input_format->code); | |
| 218 | + u8 lane_cnt = csid->phy.lane_cnt; | |
| 219 | + u32 val; | |
| 417 | 220 | |
| 418 | − val = 1; | |
| 419 | − writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); | |
| 221 | + if (!lane_cnt) | |
| 222 | + lane_cnt = 4; | |
| 420 | 223 | |
| 421 | − val = 0; | |
| 422 | − writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); | |
| 224 | + /* configure one DT, infinite frames */ | |
| 225 | + val = vc << TPG_VC_CFG0_VC_NUM; | |
| 226 | + val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE; | |
| 227 | + val |= 0 << TPG_VC_CFG0_NUM_FRAMES; | |
| 228 | + writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0); | |
| 423 | 229 | |
| 424 | − val = 1; | |
| 425 | − writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc)); | |
| 230 | + val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT; | |
| 231 | + val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT; | |
| 232 | + writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1); | |
| 426 | 233 | |
| 427 | − val = 0; | |
| 428 | − writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc)); | |
| 234 | + writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED); | |
| 429 | 235 | |
| 430 | − val = 1; | |
| 431 | − writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc)); | |
| 236 | + val = (input_format->height & 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT; | |
| 237 | + val |= (input_format->width & 0x1fff) << TPG_DT_n_CFG_0_FRAME_WIDTH; | |
| 238 | + writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0)); | |
| 432 | 239 | |
| 433 | − val = 0; | |
| 434 | − writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc)); | |
| 240 | + val = format->data_type << TPG_DT_n_CFG_1_DATA_TYPE; | |
| 241 | + writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0)); | |
| 435 | 242 | |
| 436 | − val = 0; | |
| 437 | − writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc)); | |
| 243 | + val = (tg->mode - 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE; | |
| 244 | + val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD; | |
| 245 | + val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT; | |
| 246 | + writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0)); | |
| 438 | 247 | |
| 439 | − val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc)); | |
| 440 | − val |= 1 << RDI_CFG0_ENABLE; | |
| 441 | − writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); | |
| 442 | − } | |
| 248 | + writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG); | |
| 443 | 249 | |
| 444 | − if (tg->enabled) { | |
| 445 | − val = enable << TPG_CTRL_TEST_EN; | |
| 446 | − val |= 1 << TPG_CTRL_FS_PKT_EN; | |
| 447 | − val |= 1 << TPG_CTRL_FE_PKT_EN; | |
| 448 | − val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES; | |
| 449 | − val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS; | |
| 450 | − val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES; | |
| 451 | − writel_relaxed(val, csid->base + CSID_TPG_CTRL); | |
| 452 | − } | |
| 250 | + writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG); | |
| 453 | 251 | |
| 454 | − val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; | |
| 455 | − val |= csid->phy.lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; | |
| 456 | − val |= phy_sel << CSI2_RX_CFG0_PHY_NUM_SEL; | |
| 457 | − writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); | |
| 252 | + val = enable << TPG_CTRL_TEST_EN; | |
| 253 | + val |= 1 << TPG_CTRL_FS_PKT_EN; | |
| 254 | + val |= 1 << TPG_CTRL_FE_PKT_EN; | |
| 255 | + val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES; | |
| 256 | + val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS; | |
| 257 | + val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES; | |
| 258 | + writel_relaxed(val, csid->base + CSID_TPG_CTRL); | |
| 259 | +} | |
| 458 | 260 | |
| 459 | − val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; | |
| 460 | − if (vc > 3) | |
| 461 | − val |= 1 << CSI2_RX_CFG1_VC_MODE; | |
| 462 | − val |= 1 << CSI2_RX_CFG1_MISR_EN; | |
| 463 | − writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); | |
| 261 | +static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) | |
| 262 | +{ | |
| 263 | + /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ | |
| 264 | + struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; | |
| 265 | + const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats, | |
| 266 | + csid->res->formats->nformats, | |
| 267 | + input_format->code); | |
| 268 | + u32 val; | |
| 464 | 269 | |
| 465 | − if (enable) | |
| 466 | − val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; | |
| 467 | − else | |
| 468 | − val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; | |
| 270 | + /* | |
| 271 | + * DT_ID is a two bit bitfield that is concatenated with | |
| 272 | + * the four least significant bits of the five bit VC | |
| 273 | + * bitfield to generate an internal CID value. | |
| 274 | + * | |
| 275 | + * CSID_RDI_CFG0(vc) | |
| 276 | + * DT_ID : 28:27 | |
| 277 | + * VC : 26:22 | |
| 278 | + * DT : 21:16 | |
| 279 | + * | |
| 280 | + * CID : VC 3:0 << 2 | DT_ID 1:0 | |
| 281 | + */ | |
| 282 | + u8 dt_id = vc & 0x03; | |
| 283 | + | |
| 284 | + val = 1 << RDI_CFG0_BYTE_CNTR_EN; | |
| 285 | + val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN; | |
| 286 | + val |= 1 << RDI_CFG0_TIMESTAMP_EN; | |
| 287 | + /* note: for non-RDI path, this should be format->decode_format */ | |
| 288 | + val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; | |
| 289 | + val |= format->data_type << RDI_CFG0_DATA_TYPE; | |
| 290 | + val |= vc << RDI_CFG0_VIRTUAL_CHANNEL; | |
| 291 | + val |= dt_id << RDI_CFG0_DT_ID; | |
| 292 | + writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); | |
| 293 | + | |
| 294 | + /* CSID_TIMESTAMP_STB_POST_IRQ */ | |
| 295 | + val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL; | |
| 296 | + writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc)); | |
| 297 | + | |
| 298 | + val = 1; | |
| 299 | + writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); | |
| 300 | + | |
| 301 | + val = 0; | |
| 302 | + writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc)); | |
| 303 | + | |
| 304 | + val = 1; | |
| 305 | + writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); | |
| 306 | + | |
| 307 | + val = 0; | |
| 308 | + writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); | |
| 309 | + | |
| 310 | + val = 1; | |
| 311 | + writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc)); | |
| 312 | + | |
| 313 | + val = 0; | |
| 314 | + writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc)); | |
| 315 | + | |
| 316 | + val = 1; | |
| 317 | + writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc)); | |
| 318 | + | |
| 319 | + val = 0; | |
| 320 | + writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc)); | |
| 321 | + | |
| 322 | + val = 0; | |
| 469 | 323 | writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc)); |
| 324 | + | |
| 325 | + val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc)); | |
| 326 | + val |= enable << RDI_CFG0_ENABLE; | |
| 327 | + writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); | |
| 470 | 328 | } |
| 471 | 329 | |
| 472 | 330 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
| 473 | 331 | { |
| 332 | + struct csid_testgen_config *tg = &csid->testgen; | |
| 474 | 333 | u8 i; |
| 475 | 334 | /* Loop through all enabled VCs and configure stream for each */ |
| 476 | 335 | for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) |
| 477 | − if (csid->phy.en_vc & BIT(i)) | |
| 478 | − __csid_configure_stream(csid, enable, i); | |
| 336 | + if (csid->phy.en_vc & BIT(i)) { | |
| 337 | + if (tg->enabled) | |
| 338 | + __csid_configure_testgen(csid, enable, i); | |
| 339 | + | |
| 340 | + __csid_configure_rdi_stream(csid, enable, i); | |
| 341 | + __csid_configure_rx(csid, &csid->phy, i); | |
| 342 | + __csid_ctrl_rdi(csid, enable, i); | |
| 343 | + } | |
| 479 | 344 | } |
| 480 | 345 | |
| 481 | 346 | static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) |
| @@ -612,8 +477,6 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code, · 130 unmodified lines | ||
| 612 | 477 | |
| 613 | 478 | static void csid_subdev_init(struct csid_device *csid) |
| 614 | 479 | { |
| 615 | − csid->formats = csid_formats; | |
| 616 | − csid->nformats = ARRAY_SIZE(csid_formats); | |
| 617 | 480 | csid->testgen.modes = csid_testgen_modes; |
| 618 | 481 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2; |
| 619 | 482 | } |
| @@ -45,6 +45,450 @@ const char * const csid_testgen_modes[] = { · 44 unmodified lines | ||
| 45 | 45 | NULL |
| 46 | 46 | }; |
| 47 | 47 | |
| 48 | +static const struct csid_format_info formats_4_1[] = { | |
| 49 | + { | |
| 50 | + MEDIA_BUS_FMT_UYVY8_1X16, | |
| 51 | + DATA_TYPE_YUV422_8BIT, | |
| 52 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 53 | + 8, | |
| 54 | + 2, | |
| 55 | + }, | |
| 56 | + { | |
| 57 | + MEDIA_BUS_FMT_VYUY8_1X16, | |
| 58 | + DATA_TYPE_YUV422_8BIT, | |
| 59 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 60 | + 8, | |
| 61 | + 2, | |
| 62 | + }, | |
| 63 | + { | |
| 64 | + MEDIA_BUS_FMT_YUYV8_1X16, | |
| 65 | + DATA_TYPE_YUV422_8BIT, | |
| 66 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 67 | + 8, | |
| 68 | + 2, | |
| 69 | + }, | |
| 70 | + { | |
| 71 | + MEDIA_BUS_FMT_YVYU8_1X16, | |
| 72 | + DATA_TYPE_YUV422_8BIT, | |
| 73 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 74 | + 8, | |
| 75 | + 2, | |
| 76 | + }, | |
| 77 | + { | |
| 78 | + MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 79 | + DATA_TYPE_RAW_8BIT, | |
| 80 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 81 | + 8, | |
| 82 | + 1, | |
| 83 | + }, | |
| 84 | + { | |
| 85 | + MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 86 | + DATA_TYPE_RAW_8BIT, | |
| 87 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 88 | + 8, | |
| 89 | + 1, | |
| 90 | + }, | |
| 91 | + { | |
| 92 | + MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 93 | + DATA_TYPE_RAW_8BIT, | |
| 94 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 95 | + 8, | |
| 96 | + 1, | |
| 97 | + }, | |
| 98 | + { | |
| 99 | + MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 100 | + DATA_TYPE_RAW_8BIT, | |
| 101 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 102 | + 8, | |
| 103 | + 1, | |
| 104 | + }, | |
| 105 | + { | |
| 106 | + MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 107 | + DATA_TYPE_RAW_10BIT, | |
| 108 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 109 | + 10, | |
| 110 | + 1, | |
| 111 | + }, | |
| 112 | + { | |
| 113 | + MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 114 | + DATA_TYPE_RAW_10BIT, | |
| 115 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 116 | + 10, | |
| 117 | + 1, | |
| 118 | + }, | |
| 119 | + { | |
| 120 | + MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 121 | + DATA_TYPE_RAW_10BIT, | |
| 122 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 123 | + 10, | |
| 124 | + 1, | |
| 125 | + }, | |
| 126 | + { | |
| 127 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 128 | + DATA_TYPE_RAW_10BIT, | |
| 129 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 130 | + 10, | |
| 131 | + 1, | |
| 132 | + }, | |
| 133 | + { | |
| 134 | + MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 135 | + DATA_TYPE_RAW_12BIT, | |
| 136 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 137 | + 12, | |
| 138 | + 1, | |
| 139 | + }, | |
| 140 | + { | |
| 141 | + MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 142 | + DATA_TYPE_RAW_12BIT, | |
| 143 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 144 | + 12, | |
| 145 | + 1, | |
| 146 | + }, | |
| 147 | + { | |
| 148 | + MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 149 | + DATA_TYPE_RAW_12BIT, | |
| 150 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 151 | + 12, | |
| 152 | + 1, | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 156 | + DATA_TYPE_RAW_12BIT, | |
| 157 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 158 | + 12, | |
| 159 | + 1, | |
| 160 | + }, | |
| 161 | + { | |
| 162 | + MEDIA_BUS_FMT_Y10_1X10, | |
| 163 | + DATA_TYPE_RAW_10BIT, | |
| 164 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 165 | + 10, | |
| 166 | + 1, | |
| 167 | + }, | |
| 168 | +}; | |
| 169 | + | |
| 170 | +static const struct csid_format_info formats_4_7[] = { | |
| 171 | + { | |
| 172 | + MEDIA_BUS_FMT_UYVY8_1X16, | |
| 173 | + DATA_TYPE_YUV422_8BIT, | |
| 174 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 175 | + 8, | |
| 176 | + 2, | |
| 177 | + }, | |
| 178 | + { | |
| 179 | + MEDIA_BUS_FMT_VYUY8_1X16, | |
| 180 | + DATA_TYPE_YUV422_8BIT, | |
| 181 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 182 | + 8, | |
| 183 | + 2, | |
| 184 | + }, | |
| 185 | + { | |
| 186 | + MEDIA_BUS_FMT_YUYV8_1X16, | |
| 187 | + DATA_TYPE_YUV422_8BIT, | |
| 188 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 189 | + 8, | |
| 190 | + 2, | |
| 191 | + }, | |
| 192 | + { | |
| 193 | + MEDIA_BUS_FMT_YVYU8_1X16, | |
| 194 | + DATA_TYPE_YUV422_8BIT, | |
| 195 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 196 | + 8, | |
| 197 | + 2, | |
| 198 | + }, | |
| 199 | + { | |
| 200 | + MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 201 | + DATA_TYPE_RAW_8BIT, | |
| 202 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 203 | + 8, | |
| 204 | + 1, | |
| 205 | + }, | |
| 206 | + { | |
| 207 | + MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 208 | + DATA_TYPE_RAW_8BIT, | |
| 209 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 210 | + 8, | |
| 211 | + 1, | |
| 212 | + }, | |
| 213 | + { | |
| 214 | + MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 215 | + DATA_TYPE_RAW_8BIT, | |
| 216 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 217 | + 8, | |
| 218 | + 1, | |
| 219 | + }, | |
| 220 | + { | |
| 221 | + MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 222 | + DATA_TYPE_RAW_8BIT, | |
| 223 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 224 | + 8, | |
| 225 | + 1, | |
| 226 | + }, | |
| 227 | + { | |
| 228 | + MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 229 | + DATA_TYPE_RAW_10BIT, | |
| 230 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 231 | + 10, | |
| 232 | + 1, | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 236 | + DATA_TYPE_RAW_10BIT, | |
| 237 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 238 | + 10, | |
| 239 | + 1, | |
| 240 | + }, | |
| 241 | + { | |
| 242 | + MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 243 | + DATA_TYPE_RAW_10BIT, | |
| 244 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 245 | + 10, | |
| 246 | + 1, | |
| 247 | + }, | |
| 248 | + { | |
| 249 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 250 | + DATA_TYPE_RAW_10BIT, | |
| 251 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 252 | + 10, | |
| 253 | + 1, | |
| 254 | + }, | |
| 255 | + { | |
| 256 | + MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 257 | + DATA_TYPE_RAW_12BIT, | |
| 258 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 259 | + 12, | |
| 260 | + 1, | |
| 261 | + }, | |
| 262 | + { | |
| 263 | + MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 264 | + DATA_TYPE_RAW_12BIT, | |
| 265 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 266 | + 12, | |
| 267 | + 1, | |
| 268 | + }, | |
| 269 | + { | |
| 270 | + MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 271 | + DATA_TYPE_RAW_12BIT, | |
| 272 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 273 | + 12, | |
| 274 | + 1, | |
| 275 | + }, | |
| 276 | + { | |
| 277 | + MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 278 | + DATA_TYPE_RAW_12BIT, | |
| 279 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 280 | + 12, | |
| 281 | + 1, | |
| 282 | + }, | |
| 283 | + { | |
| 284 | + MEDIA_BUS_FMT_SBGGR14_1X14, | |
| 285 | + DATA_TYPE_RAW_14BIT, | |
| 286 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 287 | + 14, | |
| 288 | + 1, | |
| 289 | + }, | |
| 290 | + { | |
| 291 | + MEDIA_BUS_FMT_SGBRG14_1X14, | |
| 292 | + DATA_TYPE_RAW_14BIT, | |
| 293 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 294 | + 14, | |
| 295 | + 1, | |
| 296 | + }, | |
| 297 | + { | |
| 298 | + MEDIA_BUS_FMT_SGRBG14_1X14, | |
| 299 | + DATA_TYPE_RAW_14BIT, | |
| 300 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 301 | + 14, | |
| 302 | + 1, | |
| 303 | + }, | |
| 304 | + { | |
| 305 | + MEDIA_BUS_FMT_SRGGB14_1X14, | |
| 306 | + DATA_TYPE_RAW_14BIT, | |
| 307 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 308 | + 14, | |
| 309 | + 1, | |
| 310 | + }, | |
| 311 | + { | |
| 312 | + MEDIA_BUS_FMT_Y10_1X10, | |
| 313 | + DATA_TYPE_RAW_10BIT, | |
| 314 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 315 | + 10, | |
| 316 | + 1, | |
| 317 | + }, | |
| 318 | +}; | |
| 319 | + | |
| 320 | +static const struct csid_format_info formats_gen2[] = { | |
| 321 | + { | |
| 322 | + MEDIA_BUS_FMT_UYVY8_1X16, | |
| 323 | + DATA_TYPE_YUV422_8BIT, | |
| 324 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 325 | + 8, | |
| 326 | + 2, | |
| 327 | + }, | |
| 328 | + { | |
| 329 | + MEDIA_BUS_FMT_VYUY8_1X16, | |
| 330 | + DATA_TYPE_YUV422_8BIT, | |
| 331 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 332 | + 8, | |
| 333 | + 2, | |
| 334 | + }, | |
| 335 | + { | |
| 336 | + MEDIA_BUS_FMT_YUYV8_1X16, | |
| 337 | + DATA_TYPE_YUV422_8BIT, | |
| 338 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 339 | + 8, | |
| 340 | + 2, | |
| 341 | + }, | |
| 342 | + { | |
| 343 | + MEDIA_BUS_FMT_YVYU8_1X16, | |
| 344 | + DATA_TYPE_YUV422_8BIT, | |
| 345 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 346 | + 8, | |
| 347 | + 2, | |
| 348 | + }, | |
| 349 | + { | |
| 350 | + MEDIA_BUS_FMT_SBGGR8_1X8, | |
| 351 | + DATA_TYPE_RAW_8BIT, | |
| 352 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 353 | + 8, | |
| 354 | + 1, | |
| 355 | + }, | |
| 356 | + { | |
| 357 | + MEDIA_BUS_FMT_SGBRG8_1X8, | |
| 358 | + DATA_TYPE_RAW_8BIT, | |
| 359 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 360 | + 8, | |
| 361 | + 1, | |
| 362 | + }, | |
| 363 | + { | |
| 364 | + MEDIA_BUS_FMT_SGRBG8_1X8, | |
| 365 | + DATA_TYPE_RAW_8BIT, | |
| 366 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 367 | + 8, | |
| 368 | + 1, | |
| 369 | + }, | |
| 370 | + { | |
| 371 | + MEDIA_BUS_FMT_SRGGB8_1X8, | |
| 372 | + DATA_TYPE_RAW_8BIT, | |
| 373 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 374 | + 8, | |
| 375 | + 1, | |
| 376 | + }, | |
| 377 | + { | |
| 378 | + MEDIA_BUS_FMT_SBGGR10_1X10, | |
| 379 | + DATA_TYPE_RAW_10BIT, | |
| 380 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 381 | + 10, | |
| 382 | + 1, | |
| 383 | + }, | |
| 384 | + { | |
| 385 | + MEDIA_BUS_FMT_SGBRG10_1X10, | |
| 386 | + DATA_TYPE_RAW_10BIT, | |
| 387 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 388 | + 10, | |
| 389 | + 1, | |
| 390 | + }, | |
| 391 | + { | |
| 392 | + MEDIA_BUS_FMT_SGRBG10_1X10, | |
| 393 | + DATA_TYPE_RAW_10BIT, | |
| 394 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 395 | + 10, | |
| 396 | + 1, | |
| 397 | + }, | |
| 398 | + { | |
| 399 | + MEDIA_BUS_FMT_SRGGB10_1X10, | |
| 400 | + DATA_TYPE_RAW_10BIT, | |
| 401 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 402 | + 10, | |
| 403 | + 1, | |
| 404 | + }, | |
| 405 | + { | |
| 406 | + MEDIA_BUS_FMT_Y8_1X8, | |
| 407 | + DATA_TYPE_RAW_8BIT, | |
| 408 | + DECODE_FORMAT_UNCOMPRESSED_8_BIT, | |
| 409 | + 8, | |
| 410 | + 1, | |
| 411 | + }, | |
| 412 | + { | |
| 413 | + MEDIA_BUS_FMT_Y10_1X10, | |
| 414 | + DATA_TYPE_RAW_10BIT, | |
| 415 | + DECODE_FORMAT_UNCOMPRESSED_10_BIT, | |
| 416 | + 10, | |
| 417 | + 1, | |
| 418 | + }, | |
| 419 | + { | |
| 420 | + MEDIA_BUS_FMT_SBGGR12_1X12, | |
| 421 | + DATA_TYPE_RAW_12BIT, | |
| 422 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 423 | + 12, | |
| 424 | + 1, | |
| 425 | + }, | |
| 426 | + { | |
| 427 | + MEDIA_BUS_FMT_SGBRG12_1X12, | |
| 428 | + DATA_TYPE_RAW_12BIT, | |
| 429 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 430 | + 12, | |
| 431 | + 1, | |
| 432 | + }, | |
| 433 | + { | |
| 434 | + MEDIA_BUS_FMT_SGRBG12_1X12, | |
| 435 | + DATA_TYPE_RAW_12BIT, | |
| 436 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 437 | + 12, | |
| 438 | + 1, | |
| 439 | + }, | |
| 440 | + { | |
| 441 | + MEDIA_BUS_FMT_SRGGB12_1X12, | |
| 442 | + DATA_TYPE_RAW_12BIT, | |
| 443 | + DECODE_FORMAT_UNCOMPRESSED_12_BIT, | |
| 444 | + 12, | |
| 445 | + 1, | |
| 446 | + }, | |
| 447 | + { | |
| 448 | + MEDIA_BUS_FMT_SBGGR14_1X14, | |
| 449 | + DATA_TYPE_RAW_14BIT, | |
| 450 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 451 | + 14, | |
| 452 | + 1, | |
| 453 | + }, | |
| 454 | + { | |
| 455 | + MEDIA_BUS_FMT_SGBRG14_1X14, | |
| 456 | + DATA_TYPE_RAW_14BIT, | |
| 457 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 458 | + 14, | |
| 459 | + 1, | |
| 460 | + }, | |
| 461 | + { | |
| 462 | + MEDIA_BUS_FMT_SGRBG14_1X14, | |
| 463 | + DATA_TYPE_RAW_14BIT, | |
| 464 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 465 | + 14, | |
| 466 | + 1, | |
| 467 | + }, | |
| 468 | + { | |
| 469 | + MEDIA_BUS_FMT_SRGGB14_1X14, | |
| 470 | + DATA_TYPE_RAW_14BIT, | |
| 471 | + DECODE_FORMAT_UNCOMPRESSED_14_BIT, | |
| 472 | + 14, | |
| 473 | + 1, | |
| 474 | + }, | |
| 475 | +}; | |
| 476 | + | |
| 477 | +const struct csid_formats csid_formats_4_1 = { | |
| 478 | + .nformats = ARRAY_SIZE(formats_4_1), | |
| 479 | + .formats = formats_4_1 | |
| 480 | +}; | |
| 481 | + | |
| 482 | +const struct csid_formats csid_formats_4_7 = { | |
| 483 | + .nformats = ARRAY_SIZE(formats_4_7), | |
| 484 | + .formats = formats_4_7 | |
| 485 | +}; | |
| 486 | + | |
| 487 | +const struct csid_formats csid_formats_gen2 = { | |
| 488 | + .nformats = ARRAY_SIZE(formats_gen2), | |
| 489 | + .formats = formats_gen2 | |
| 490 | +}; | |
| 491 | + | |
| 48 | 492 | u32 csid_find_code(u32 *codes, unsigned int ncodes, |
| 49 | 493 | unsigned int match_format_idx, u32 match_code) |
| 50 | 494 | { |
| @@ -65,9 +509,9 @@ u32 csid_find_code(u32 *codes, unsigned int ncodes, · 14 unmodified lines | ||
| 65 | 509 | return codes[0]; |
| 66 | 510 | } |
| 67 | 511 | |
| 68 | −const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, | |
| 69 | − unsigned int nformats, | |
| 70 | − u32 code) | |
| 512 | +const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats, | |
| 513 | + unsigned int nformats, | |
| 514 | + u32 code) | |
| 71 | 515 | { |
| 72 | 516 | unsigned int i; |
| 73 | 517 | |
| @@ -87,12 +531,12 @@ const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, · 13 unmodified lines | ||
| 87 | 531 | static int csid_set_clock_rates(struct csid_device *csid) |
| 88 | 532 | { |
| 89 | 533 | struct device *dev = csid->camss->dev; |
| 90 | − const struct csid_format *fmt; | |
| 534 | + const struct csid_format_info *fmt; | |
| 91 | 535 | s64 link_freq; |
| 92 | 536 | int i, j; |
| 93 | 537 | int ret; |
| 94 | 538 | |
| 95 | − fmt = csid_get_fmt_entry(csid->formats, csid->nformats, | |
| 539 | + fmt = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats, | |
| 96 | 540 | csid->fmt[MSM_CSIPHY_PAD_SINK].code); |
| 97 | 541 | link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, |
| 98 | 542 | csid->phy.lane_cnt); |
| @@ -158,7 +602,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 59 unmodified lines | ||
| 158 | 602 | struct csid_device *csid = v4l2_get_subdevdata(sd); |
| 159 | 603 | struct camss *camss = csid->camss; |
| 160 | 604 | struct device *dev = camss->dev; |
| 161 | − struct vfe_device *vfe = &camss->vfe[csid->id]; | |
| 162 | 605 | int ret = 0; |
| 163 | 606 | |
| 164 | 607 | if (on) { |
| @@ -167,7 +610,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 2 unmodified lines | ||
| 167 | 610 | * switching on the CSID. Do so unconditionally, as there is no |
| 168 | 611 | * drawback in following the same powering order on older SoCs. |
| 169 | 612 | */ |
| 170 | − ret = vfe_get(vfe); | |
| 613 | + ret = csid->res->parent_dev_ops->get(camss, csid->id); | |
| 171 | 614 | if (ret < 0) |
| 172 | 615 | return ret; |
| 173 | 616 | |
| @@ -202,7 +645,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 28 unmodified lines | ||
| 202 | 645 | |
| 203 | 646 | enable_irq(csid->irq); |
| 204 | 647 | |
| 205 | − ret = csid->ops->reset(csid); | |
| 648 | + ret = csid->res->hw_ops->reset(csid); | |
| 206 | 649 | if (ret < 0) { |
| 207 | 650 | disable_irq(csid->irq); |
| 208 | 651 | camss_disable_clocks(csid->nclocks, csid->clock); |
| @@ -212,14 +655,14 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 3 unmodified lines | ||
| 212 | 655 | return ret; |
| 213 | 656 | } |
| 214 | 657 | |
| 215 | − csid->ops->hw_version(csid); | |
| 658 | + csid->res->hw_ops->hw_version(csid); | |
| 216 | 659 | } else { |
| 217 | 660 | disable_irq(csid->irq); |
| 218 | 661 | camss_disable_clocks(csid->nclocks, csid->clock); |
| 219 | 662 | regulator_bulk_disable(csid->num_supplies, |
| 220 | 663 | csid->supplies); |
| 221 | 664 | pm_runtime_put_sync(dev); |
| 222 | − vfe_put(vfe); | |
| 665 | + csid->res->parent_dev_ops->put(camss, csid->id); | |
| 223 | 666 | } |
| 224 | 667 | |
| 225 | 668 | return ret; |
| @@ -253,7 +696,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable) · 27 unmodified lines | ||
| 253 | 696 | } |
| 254 | 697 | |
| 255 | 698 | if (csid->phy.need_vc_update) { |
| 256 | − csid->ops->configure_stream(csid, enable); | |
| 699 | + csid->res->hw_ops->configure_stream(csid, enable); | |
| 257 | 700 | csid->phy.need_vc_update = false; |
| 258 | 701 | } |
| 259 | 702 | |
| @@ -301,12 +744,12 @@ static void csid_try_format(struct csid_device *csid, · 41 unmodified lines | ||
| 301 | 744 | case MSM_CSID_PAD_SINK: |
| 302 | 745 | /* Set format on sink pad */ |
| 303 | 746 | |
| 304 | − for (i = 0; i < csid->nformats; i++) | |
| 305 | − if (fmt->code == csid->formats[i].code) | |
| 747 | + for (i = 0; i < csid->res->formats->nformats; i++) | |
| 748 | + if (fmt->code == csid->res->formats->formats[i].code) | |
| 306 | 749 | break; |
| 307 | 750 | |
| 308 | 751 | /* If not found, use UYVY as default */ |
| 309 | − if (i >= csid->nformats) | |
| 752 | + if (i >= csid->res->formats->nformats) | |
| 310 | 753 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 311 | 754 | |
| 312 | 755 | fmt->width = clamp_t(u32, fmt->width, 1, 8191); |
| @@ -325,17 +768,17 @@ static void csid_try_format(struct csid_device *csid, · 12 unmodified lines | ||
| 325 | 768 | |
| 326 | 769 | *fmt = *__csid_get_format(csid, sd_state, |
| 327 | 770 | MSM_CSID_PAD_SINK, which); |
| 328 | − fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code); | |
| 771 | + fmt->code = csid->res->hw_ops->src_pad_code(csid, fmt->code, 0, code); | |
| 329 | 772 | } else { |
| 330 | 773 | /* Test generator is enabled, set format on source */ |
| 331 | 774 | /* pad to allow test generator usage */ |
| 332 | 775 | |
| 333 | − for (i = 0; i < csid->nformats; i++) | |
| 334 | − if (csid->formats[i].code == fmt->code) | |
| 776 | + for (i = 0; i < csid->res->formats->nformats; i++) | |
| 777 | + if (csid->res->formats->formats[i].code == fmt->code) | |
| 335 | 778 | break; |
| 336 | 779 | |
| 337 | 780 | /* If not found, use UYVY as default */ |
| 338 | − if (i >= csid->nformats) | |
| 781 | + if (i >= csid->res->formats->nformats) | |
| 339 | 782 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 340 | 783 | |
| 341 | 784 | fmt->width = clamp_t(u32, fmt->width, 1, 8191); |
| @@ -363,10 +806,10 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, · 21 unmodified lines | ||
| 363 | 806 | struct csid_device *csid = v4l2_get_subdevdata(sd); |
| 364 | 807 | |
| 365 | 808 | if (code->pad == MSM_CSID_PAD_SINK) { |
| 366 | − if (code->index >= csid->nformats) | |
| 809 | + if (code->index >= csid->res->formats->nformats) | |
| 367 | 810 | return -EINVAL; |
| 368 | 811 | |
| 369 | − code->code = csid->formats[code->index].code; | |
| 812 | + code->code = csid->res->formats->formats[code->index].code; | |
| 370 | 813 | } else { |
| 371 | 814 | if (csid->testgen_mode->cur.val == 0) { |
| 372 | 815 | struct v4l2_mbus_framefmt *sink_fmt; |
| @@ -375,15 +818,15 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd, · 2 unmodified lines | ||
| 375 | 818 | MSM_CSID_PAD_SINK, |
| 376 | 819 | code->which); |
| 377 | 820 | |
| 378 | − code->code = csid->ops->src_pad_code(csid, sink_fmt->code, | |
| 379 | − code->index, 0); | |
| 821 | + code->code = csid->res->hw_ops->src_pad_code(csid, sink_fmt->code, | |
| 822 | + code->index, 0); | |
| 380 | 823 | if (!code->code) |
| 381 | 824 | return -EINVAL; |
| 382 | 825 | } else { |
| 383 | − if (code->index >= csid->nformats) | |
| 826 | + if (code->index >= csid->res->formats->nformats) | |
| 384 | 827 | return -EINVAL; |
| 385 | 828 | |
| 386 | − code->code = csid->formats[code->index].code; | |
| 829 | + code->code = csid->res->formats->formats[code->index].code; | |
| 387 | 830 | } |
| 388 | 831 | } |
| 389 | 832 | |
| @@ -529,7 +972,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value) · 139 unmodified lines | ||
| 529 | 972 | |
| 530 | 973 | tg->enabled = !!value; |
| 531 | 974 | |
| 532 | − return csid->ops->configure_testgen_pattern(csid, value); | |
| 975 | + return csid->res->hw_ops->configure_testgen_pattern(csid, value); | |
| 533 | 976 | } |
| 534 | 977 | |
| 535 | 978 | /* |
| @@ -575,9 +1018,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, · 39 unmodified lines | ||
| 575 | 1018 | |
| 576 | 1019 | csid->camss = camss; |
| 577 | 1020 | csid->id = id; |
| 578 | − csid->ops = res->ops; | |
| 1021 | + csid->res = &res->csid; | |
| 1022 | + | |
| 1023 | + if (dev_WARN_ONCE(dev, !csid->res->parent_dev_ops, | |
| 1024 | + "Error: CSID depends on VFE/IFE device ops!\n")) { | |
| 1025 | + return -EINVAL; | |
| 1026 | + } | |
| 579 | 1027 | |
| 580 | − csid->ops->subdev_init(csid); | |
| 1028 | + csid->res->hw_ops->subdev_init(csid); | |
| 581 | 1029 | |
| 582 | 1030 | /* Memory */ |
| 583 | 1031 | |
| @@ -587,9 +1035,11 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, · 3 unmodified lines | ||
| 587 | 1035 | * VFE to be initialized before CSID |
| 588 | 1036 | */ |
| 589 | 1037 | if (id >= 2) /* VFE/CSID lite */ |
| 590 | − csid->base = camss->vfe[id].base + VFE_480_LITE_CSID_OFFSET; | |
| 1038 | + csid->base = csid->res->parent_dev_ops->get_base_address(camss, id) | |
| 1039 | + + VFE_480_LITE_CSID_OFFSET; | |
| 591 | 1040 | else |
| 592 | − csid->base = camss->vfe[id].base + VFE_480_CSID_OFFSET; | |
| 1041 | + csid->base = csid->res->parent_dev_ops->get_base_address(camss, id) | |
| 1042 | + + VFE_480_CSID_OFFSET; | |
| 593 | 1043 | } else { |
| 594 | 1044 | csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]); |
| 595 | 1045 | if (IS_ERR(csid->base)) |
| @@ -605,7 +1055,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, · 9 unmodified lines | ||
| 605 | 1055 | csid->irq = ret; |
| 606 | 1056 | snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d", |
| 607 | 1057 | dev_name(dev), MSM_CSID_NAME, csid->id); |
| 608 | − ret = devm_request_irq(dev, csid->irq, csid->ops->isr, | |
| 1058 | + ret = devm_request_irq(dev, csid->irq, csid->res->hw_ops->isr, | |
| 609 | 1059 | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, |
| 610 | 1060 | csid->irq_name, csid); |
| 611 | 1061 | if (ret < 0) { |
| @@ -899,5 +1349,5 @@ void msm_csid_unregister_entity(struct csid_device *csid) · 287 unmodified lines | ||
| 899 | 1349 | |
| 900 | 1350 | inline bool csid_is_lite(struct csid_device *csid) |
| 901 | 1351 | { |
| 902 | − return csid->camss->res->csid_res[csid->id].is_lite; | |
| 1352 | + return csid->camss->res->csid_res[csid->id].csid.is_lite; | |
| 903 | 1353 | } |
| @@ -67,7 +67,7 @@ enum csid_testgen_mode { · 66 unmodified lines | ||
| 67 | 67 | CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */ |
| 68 | 68 | }; |
| 69 | 69 | |
| 70 | −struct csid_format { | |
| 70 | +struct csid_format_info { | |
| 71 | 71 | u32 code; |
| 72 | 72 | u8 data_type; |
| 73 | 73 | u8 decode_format; |
| @@ -75,6 +75,11 @@ struct csid_format { · 1 unmodified line | ||
| 75 | 75 | u8 spp; /* bus samples per pixel */ |
| 76 | 76 | }; |
| 77 | 77 | |
| 78 | +struct csid_formats { | |
| 79 | + unsigned int nformats; | |
| 80 | + const struct csid_format_info *formats; | |
| 81 | +}; | |
| 82 | + | |
| 78 | 83 | struct csid_testgen_config { |
| 79 | 84 | enum csid_testgen_mode mode; |
| 80 | 85 | const char * const*modes; |
| @@ -149,6 +154,13 @@ struct csid_hw_ops { · 68 unmodified lines | ||
| 149 | 154 | void (*subdev_init)(struct csid_device *csid); |
| 150 | 155 | }; |
| 151 | 156 | |
| 157 | +struct csid_subdev_resources { | |
| 158 | + bool is_lite; | |
| 159 | + const struct csid_hw_ops *hw_ops; | |
| 160 | + const struct parent_dev_ops *parent_dev_ops; | |
| 161 | + const struct csid_formats *formats; | |
| 162 | +}; | |
| 163 | + | |
| 152 | 164 | struct csid_device { |
| 153 | 165 | struct camss *camss; |
| 154 | 166 | u8 id; |
| @@ -167,9 +179,7 @@ struct csid_device { · 12 unmodified lines | ||
| 167 | 179 | struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM]; |
| 168 | 180 | struct v4l2_ctrl_handler ctrls; |
| 169 | 181 | struct v4l2_ctrl *testgen_mode; |
| 170 | − const struct csid_format *formats; | |
| 171 | − unsigned int nformats; | |
| 172 | − const struct csid_hw_ops *ops; | |
| 182 | + const struct csid_subdev_resources *res; | |
| 173 | 183 | }; |
| 174 | 184 | |
| 175 | 185 | struct camss_subdev_resources; |
| @@ -188,16 +198,16 @@ u32 csid_find_code(u32 *codes, unsigned int ncode, · 12 unmodified lines | ||
| 188 | 198 | unsigned int match_format_idx, u32 match_code); |
| 189 | 199 | |
| 190 | 200 | /* |
| 191 | − * csid_get_fmt_entry - Find csid_format entry with matching format code | |
| 192 | − * @formats: Array of format csid_format entries | |
| 201 | + * csid_get_fmt_entry - Find csid_format_info entry with matching format code | |
| 202 | + * @formats: Array of format csid_format_info entries | |
| 193 | 203 | * @nformats: Length of @nformats array |
| 194 | 204 | * @code: Desired format code |
| 195 | 205 | * |
| 196 | 206 | * Return formats[0] on failure to find code |
| 197 | 207 | */ |
| 198 | −const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, | |
| 199 | − unsigned int nformats, | |
| 200 | − u32 code); | |
| 208 | +const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats, | |
| 209 | + unsigned int nformats, | |
| 210 | + u32 code); | |
| 201 | 211 | |
| 202 | 212 | int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, |
| 203 | 213 | const struct camss_subdev_resources *res, u8 id); |
| @@ -211,6 +221,10 @@ void msm_csid_get_csid_id(struct media_entity *entity, u8 *id); · 7 unmodified lines | ||
| 211 | 221 | |
| 212 | 222 | extern const char * const csid_testgen_modes[]; |
| 213 | 223 | |
| 224 | +extern const struct csid_formats csid_formats_4_1; | |
| 225 | +extern const struct csid_formats csid_formats_4_7; | |
| 226 | +extern const struct csid_formats csid_formats_gen2; | |
| 227 | + | |
| 214 | 228 | extern const struct csid_hw_ops csid_ops_4_1; |
| 215 | 229 | extern const struct csid_hw_ops csid_ops_4_7; |
| 216 | 230 | extern const struct csid_hw_ops csid_ops_gen2; |
| @@ -24,12 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | |
| 25 | 25 | #define MSM_CSIPHY_NAME "msm_csiphy" |
| 26 | 26 | |
| 27 | −struct csiphy_format { | |
| 28 | − u32 code; | |
| 29 | − u8 bpp; | |
| 30 | −}; | |
| 31 | − | |
| 32 | −static const struct csiphy_format csiphy_formats_8x16[] = { | |
| 27 | +static const struct csiphy_format_info formats_8x16[] = { | |
| 33 | 28 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, |
| 34 | 29 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, |
| 35 | 30 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, |
| @@ -49,7 +44,7 @@ static const struct csiphy_format csiphy_formats_8x16[] = { · 13 unmodified lines | ||
| 49 | 44 | { MEDIA_BUS_FMT_Y10_1X10, 10 }, |
| 50 | 45 | }; |
| 51 | 46 | |
| 52 | −static const struct csiphy_format csiphy_formats_8x96[] = { | |
| 47 | +static const struct csiphy_format_info formats_8x96[] = { | |
| 53 | 48 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, |
| 54 | 49 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, |
| 55 | 50 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, |
| @@ -73,7 +68,7 @@ static const struct csiphy_format csiphy_formats_8x96[] = { · 17 unmodified lines | ||
| 73 | 68 | { MEDIA_BUS_FMT_Y10_1X10, 10 }, |
| 74 | 69 | }; |
| 75 | 70 | |
| 76 | −static const struct csiphy_format csiphy_formats_sdm845[] = { | |
| 71 | +static const struct csiphy_format_info formats_sdm845[] = { | |
| 77 | 72 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, |
| 78 | 73 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, |
| 79 | 74 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, |
| @@ -98,6 +93,21 @@ static const struct csiphy_format csiphy_formats_sdm845[] = { · 18 unmodified lines | ||
| 98 | 93 | { MEDIA_BUS_FMT_Y10_1X10, 10 }, |
| 99 | 94 | }; |
| 100 | 95 | |
| 96 | +const struct csiphy_formats csiphy_formats_8x16 = { | |
| 97 | + .nformats = ARRAY_SIZE(formats_8x16), | |
| 98 | + .formats = formats_8x16 | |
| 99 | +}; | |
| 100 | + | |
| 101 | +const struct csiphy_formats csiphy_formats_8x96 = { | |
| 102 | + .nformats = ARRAY_SIZE(formats_8x96), | |
| 103 | + .formats = formats_8x96 | |
| 104 | +}; | |
| 105 | + | |
| 106 | +const struct csiphy_formats csiphy_formats_sdm845 = { | |
| 107 | + .nformats = ARRAY_SIZE(formats_sdm845), | |
| 108 | + .formats = formats_sdm845 | |
| 109 | +}; | |
| 110 | + | |
| 101 | 111 | /* |
| 102 | 112 | * csiphy_get_bpp - map media bus format to bits per pixel |
| 103 | 113 | * @formats: supported media bus formats array |
| @@ -106,7 +116,7 @@ static const struct csiphy_format csiphy_formats_sdm845[] = { · 2 unmodified lines | ||
| 106 | 116 | * |
| 107 | 117 | * Return number of bits per pixel |
| 108 | 118 | */ |
| 109 | −static u8 csiphy_get_bpp(const struct csiphy_format *formats, | |
| 119 | +static u8 csiphy_get_bpp(const struct csiphy_format_info *formats, | |
| 110 | 120 | unsigned int nformats, u32 code) |
| 111 | 121 | { |
| 112 | 122 | unsigned int i; |
| @@ -131,7 +141,7 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy) · 18 unmodified lines | ||
| 131 | 141 | int i, j; |
| 132 | 142 | int ret; |
| 133 | 143 | |
| 134 | − u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, | |
| 144 | + u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats, | |
| 135 | 145 | csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); |
| 136 | 146 | u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; |
| 137 | 147 | |
| @@ -216,9 +226,9 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on) · 78 unmodified lines | ||
| 216 | 226 | |
| 217 | 227 | enable_irq(csiphy->irq); |
| 218 | 228 | |
| 219 | − csiphy->ops->reset(csiphy); | |
| 229 | + csiphy->res->hw_ops->reset(csiphy); | |
| 220 | 230 | |
| 221 | − csiphy->ops->hw_version_read(csiphy, dev); | |
| 231 | + csiphy->res->hw_ops->hw_version_read(csiphy, dev); | |
| 222 | 232 | } else { |
| 223 | 233 | disable_irq(csiphy->irq); |
| 224 | 234 | |
| @@ -243,8 +253,8 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) · 18 unmodified lines | ||
| 243 | 253 | { |
| 244 | 254 | struct csiphy_config *cfg = &csiphy->cfg; |
| 245 | 255 | s64 link_freq; |
| 246 | − u8 lane_mask = csiphy->ops->get_lane_mask(&cfg->csi2->lane_cfg); | |
| 247 | − u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, | |
| 256 | + u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg); | |
| 257 | + u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats, | |
| 248 | 258 | csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); |
| 249 | 259 | u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; |
| 250 | 260 | u8 val; |
| @@ -272,7 +282,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) · 21 unmodified lines | ||
| 272 | 282 | wmb(); |
| 273 | 283 | } |
| 274 | 284 | |
| 275 | − csiphy->ops->lanes_enable(csiphy, cfg, link_freq, lane_mask); | |
| 285 | + csiphy->res->hw_ops->lanes_enable(csiphy, cfg, link_freq, lane_mask); | |
| 276 | 286 | |
| 277 | 287 | return 0; |
| 278 | 288 | } |
| @@ -285,7 +295,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) · 6 unmodified lines | ||
| 285 | 295 | */ |
| 286 | 296 | static void csiphy_stream_off(struct csiphy_device *csiphy) |
| 287 | 297 | { |
| 288 | − csiphy->ops->lanes_disable(csiphy, &csiphy->cfg); | |
| 298 | + csiphy->res->hw_ops->lanes_disable(csiphy, &csiphy->cfg); | |
| 289 | 299 | } |
| 290 | 300 | |
| 291 | 301 | |
| @@ -350,12 +360,12 @@ static void csiphy_try_format(struct csiphy_device *csiphy, · 58 unmodified lines | ||
| 350 | 360 | case MSM_CSIPHY_PAD_SINK: |
| 351 | 361 | /* Set format on sink pad */ |
| 352 | 362 | |
| 353 | − for (i = 0; i < csiphy->nformats; i++) | |
| 354 | − if (fmt->code == csiphy->formats[i].code) | |
| 363 | + for (i = 0; i < csiphy->res->formats->nformats; i++) | |
| 364 | + if (fmt->code == csiphy->res->formats->formats[i].code) | |
| 355 | 365 | break; |
| 356 | 366 | |
| 357 | 367 | /* If not found, use UYVY as default */ |
| 358 | − if (i >= csiphy->nformats) | |
| 368 | + if (i >= csiphy->res->formats->nformats) | |
| 359 | 369 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 360 | 370 | |
| 361 | 371 | fmt->width = clamp_t(u32, fmt->width, 1, 8191); |
| @@ -392,10 +402,10 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd, · 30 unmodified lines | ||
| 392 | 402 | struct v4l2_mbus_framefmt *format; |
| 393 | 403 | |
| 394 | 404 | if (code->pad == MSM_CSIPHY_PAD_SINK) { |
| 395 | − if (code->index >= csiphy->nformats) | |
| 405 | + if (code->index >= csiphy->res->formats->nformats) | |
| 396 | 406 | return -EINVAL; |
| 397 | 407 | |
| 398 | − code->code = csiphy->formats[code->index].code; | |
| 408 | + code->code = csiphy->res->formats->formats[code->index].code; | |
| 399 | 409 | } else { |
| 400 | 410 | if (code->index > 0) |
| 401 | 411 | return -EINVAL; |
| @@ -564,25 +574,7 @@ int msm_csiphy_subdev_init(struct camss *camss, · 162 unmodified lines | ||
| 564 | 574 | csiphy->camss = camss; |
| 565 | 575 | csiphy->id = id; |
| 566 | 576 | csiphy->cfg.combo_mode = 0; |
| 567 | − csiphy->ops = res->ops; | |
| 568 | − | |
| 569 | − switch (camss->res->version) { | |
| 570 | − case CAMSS_8x16: | |
| 571 | − csiphy->formats = csiphy_formats_8x16; | |
| 572 | − csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16); | |
| 573 | − break; | |
| 574 | − case CAMSS_8x96: | |
| 575 | − case CAMSS_660: | |
| 576 | − csiphy->formats = csiphy_formats_8x96; | |
| 577 | − csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96); | |
| 578 | − break; | |
| 579 | − case CAMSS_845: | |
| 580 | − case CAMSS_8250: | |
| 581 | − case CAMSS_8280XP: | |
| 582 | − csiphy->formats = csiphy_formats_sdm845; | |
| 583 | − csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845); | |
| 584 | − break; | |
| 585 | − } | |
| 577 | + csiphy->res = &res->csiphy; | |
| 586 | 578 | |
| 587 | 579 | /* Memory */ |
| 588 | 580 | |
| @@ -610,7 +602,7 @@ int msm_csiphy_subdev_init(struct camss *camss, · 21 unmodified lines | ||
| 610 | 602 | snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d", |
| 611 | 603 | dev_name(dev), MSM_CSIPHY_NAME, csiphy->id); |
| 612 | 604 | |
| 613 | − ret = devm_request_irq(dev, csiphy->irq, csiphy->ops->isr, | |
| 605 | + ret = devm_request_irq(dev, csiphy->irq, csiphy->res->hw_ops->isr, | |
| 614 | 606 | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, |
| 615 | 607 | csiphy->irq_name, csiphy); |
| 616 | 608 | if (ret < 0) { |
| @@ -42,6 +42,16 @@ struct csiphy_config { · 41 unmodified lines | ||
| 42 | 42 | struct csiphy_csi2_cfg *csi2; |
| 43 | 43 | }; |
| 44 | 44 | |
| 45 | +struct csiphy_format_info { | |
| 46 | + u32 code; | |
| 47 | + u8 bpp; | |
| 48 | +}; | |
| 49 | + | |
| 50 | +struct csiphy_formats { | |
| 51 | + unsigned int nformats; | |
| 52 | + const struct csiphy_format_info *formats; | |
| 53 | +}; | |
| 54 | + | |
| 45 | 55 | struct csiphy_device; |
| 46 | 56 | |
| 47 | 57 | struct csiphy_hw_ops { |
| @@ -63,6 +73,11 @@ struct csiphy_hw_ops { · 15 unmodified lines | ||
| 63 | 73 | irqreturn_t (*isr)(int irq, void *dev); |
| 64 | 74 | }; |
| 65 | 75 | |
| 76 | +struct csiphy_subdev_resources { | |
| 77 | + const struct csiphy_hw_ops *hw_ops; | |
| 78 | + const struct csiphy_formats *formats; | |
| 79 | +}; | |
| 80 | + | |
| 66 | 81 | struct csiphy_device { |
| 67 | 82 | struct camss *camss; |
| 68 | 83 | u8 id; |
| @@ -78,9 +93,7 @@ struct csiphy_device { · 9 unmodified lines | ||
| 78 | 93 | u32 timer_clk_rate; |
| 79 | 94 | struct csiphy_config cfg; |
| 80 | 95 | struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; |
| 81 | − const struct csiphy_hw_ops *ops; | |
| 82 | − const struct csiphy_format *formats; | |
| 83 | − unsigned int nformats; | |
| 96 | + const struct csiphy_subdev_resources *res; | |
| 84 | 97 | }; |
| 85 | 98 | |
| 86 | 99 | struct camss_subdev_resources; |
| @@ -94,6 +107,10 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy, · 7 unmodified lines | ||
| 94 | 107 | |
| 95 | 108 | void msm_csiphy_unregister_entity(struct csiphy_device *csiphy); |
| 96 | 109 | |
| 110 | +extern const struct csiphy_formats csiphy_formats_8x16; | |
| 111 | +extern const struct csiphy_formats csiphy_formats_8x96; | |
| 112 | +extern const struct csiphy_formats csiphy_formats_sdm845; | |
| 113 | + | |
| 97 | 114 | extern const struct csiphy_hw_ops csiphy_ops_2ph_1_0; |
| 98 | 115 | extern const struct csiphy_hw_ops csiphy_ops_3ph_1_0; |
| 99 | 116 | |
| @@ -0,0 +1,91 @@ | ||
| 1 | +// SPDX-License-Identifier: GPL-2.0 | |
| 2 | +/* | |
| 3 | + * camss-format.c | |
| 4 | + * | |
| 5 | + * Qualcomm MSM Camera Subsystem - Format helpers | |
| 6 | + * | |
| 7 | + * Copyright (c) 2023, The Linux Foundation. All rights reserved. | |
| 8 | + * Copyright (c) 2023 Qualcomm Technologies, Inc. | |
| 9 | + */ | |
| 10 | +#include <linux/bug.h> | |
| 11 | +#include <linux/errno.h> | |
| 12 | + | |
| 13 | +#include "camss-format.h" | |
| 14 | + | |
| 15 | +/* | |
| 16 | + * camss_format_get_bpp - Map media bus format to bits per pixel | |
| 17 | + * @formats: supported media bus formats array | |
| 18 | + * @nformats: size of @formats array | |
| 19 | + * @code: media bus format code | |
| 20 | + * | |
| 21 | + * Return number of bits per pixel | |
| 22 | + */ | |
| 23 | +u8 camss_format_get_bpp(const struct camss_format_info *formats, unsigned int nformats, u32 code) | |
| 24 | +{ | |
| 25 | + unsigned int i; | |
| 26 | + | |
| 27 | + for (i = 0; i < nformats; i++) | |
| 28 | + if (code == formats[i].code) | |
| 29 | + return formats[i].mbus_bpp; | |
| 30 | + | |
| 31 | + WARN(1, "Unknown format\n"); | |
| 32 | + | |
| 33 | + return formats[0].mbus_bpp; | |
| 34 | +} | |
| 35 | + | |
| 36 | +/* | |
| 37 | + * camss_format_find_code - Find a format code in an array | |
| 38 | + * @code: a pointer to media bus format codes array | |
| 39 | + * @n_code: size of @code array | |
| 40 | + * @index: index of code in the array | |
| 41 | + * @req_code: required code | |
| 42 | + * | |
| 43 | + * Return media bus format code | |
| 44 | + */ | |
| 45 | +u32 camss_format_find_code(u32 *code, unsigned int n_code, unsigned int index, u32 req_code) | |
| 46 | +{ | |
| 47 | + unsigned int i; | |
| 48 | + | |
| 49 | + if (!req_code && index >= n_code) | |
| 50 | + return 0; | |
| 51 | + | |
| 52 | + for (i = 0; i < n_code; i++) { | |
| 53 | + if (req_code) { | |
| 54 | + if (req_code == code[i]) | |
| 55 | + return req_code; | |
| 56 | + } else { | |
| 57 | + if (i == index) | |
| 58 | + return code[i]; | |
| 59 | + } | |
| 60 | + } | |
| 61 | + | |
| 62 | + return code[0]; | |
| 63 | +} | |
| 64 | + | |
| 65 | +/* | |
| 66 | + * camss_format_find_format - Find a format in an array | |
| 67 | + * @code: media bus format code | |
| 68 | + * @pixelformat: V4L2 pixel format FCC identifier | |
| 69 | + * @formats: a pointer to formats array | |
| 70 | + * @nformats: size of @formats array | |
| 71 | + * | |
| 72 | + * Return index of a format or a negative error code otherwise | |
| 73 | + */ | |
| 74 | +int camss_format_find_format(u32 code, u32 pixelformat, const struct camss_format_info *formats, | |
| 75 | + unsigned int nformats) | |
| 76 | +{ | |
| 77 | + unsigned int i; | |
| 78 | + | |
| 79 | + for (i = 0; i < nformats; i++) { | |
| 80 | + if (formats[i].code == code && | |
| 81 | + formats[i].pixelformat == pixelformat) | |
| 82 | + return i; | |
| 83 | + } | |
| 84 | + | |
| 85 | + for (i = 0; i < nformats; i++) { | |
| 86 | + if (formats[i].code == code) | |
| 87 | + return i; | |
| 88 | + } | |
| 89 | + | |
| 90 | + return -EINVAL; | |
| 91 | +} | |
| @@ -0,0 +1,62 @@ | ||
| 1 | +/* SPDX-License-Identifier: GPL-2.0 */ | |
| 2 | +/* | |
| 3 | + * camss-format.h | |
| 4 | + * | |
| 5 | + * Qualcomm MSM Camera Subsystem - Format helpers | |
| 6 | + * | |
| 7 | + * Copyright (c) 2023, The Linux Foundation. All rights reserved. | |
| 8 | + * Copyright (c) 2023 Qualcomm Technologies, Inc. | |
| 9 | + */ | |
| 10 | +#ifndef __CAMSS_FORMAT_H__ | |
| 11 | +#define __CAMSS_FORMAT_H__ | |
| 12 | + | |
| 13 | +#include <linux/types.h> | |
| 14 | + | |
| 15 | +#define PER_PLANE_DATA(plane, h_fract_num, h_fract_den, v_fract_num, v_fract_den, _bpp) \ | |
| 16 | + .hsub[(plane)].numerator = (h_fract_num), \ | |
| 17 | + .hsub[(plane)].denominator = (h_fract_den), \ | |
| 18 | + .vsub[(plane)].numerator = (v_fract_num), \ | |
| 19 | + .vsub[(plane)].denominator = (v_fract_den), \ | |
| 20 | + .bpp[(plane)] = (_bpp) | |
| 21 | + | |
| 22 | +/* | |
| 23 | + * struct fract - Represents a fraction | |
| 24 | + * @numerator: Store the numerator part of the fraction | |
| 25 | + * @denominator: Store the denominator part of the fraction | |
| 26 | + */ | |
| 27 | +struct fract { | |
| 28 | + u8 numerator; | |
| 29 | + u8 denominator; | |
| 30 | +}; | |
| 31 | + | |
| 32 | +/* | |
| 33 | + * struct camss_format_info - ISP media bus format information | |
| 34 | + * @code: V4L2 media bus format code | |
| 35 | + * @mbus_bpp: Media bus bits per pixel | |
| 36 | + * @pixelformat: V4L2 pixel format FCC identifier | |
| 37 | + * @planes: Number of planes | |
| 38 | + * @hsub: Horizontal subsampling (for each plane) | |
| 39 | + * @vsub: Vertical subsampling (for each plane) | |
| 40 | + * @bpp: Bits per pixel when stored in memory (for each plane) | |
| 41 | + */ | |
| 42 | +struct camss_format_info { | |
| 43 | + u32 code; | |
| 44 | + u32 mbus_bpp; | |
| 45 | + u32 pixelformat; | |
| 46 | + u8 planes; | |
| 47 | + struct fract hsub[3]; | |
| 48 | + struct fract vsub[3]; | |
| 49 | + unsigned int bpp[3]; | |
| 50 | +}; | |
| 51 | + | |
| 52 | +struct camss_formats { | |
| 53 | + unsigned int nformats; | |
| 54 | + const struct camss_format_info *formats; | |
| 55 | +}; | |
| 56 | + | |
| 57 | +u8 camss_format_get_bpp(const struct camss_format_info *formats, unsigned int nformats, u32 code); | |
| 58 | +u32 camss_format_find_code(u32 *code, unsigned int n_code, unsigned int index, u32 req_code); | |
| 59 | +int camss_format_find_format(u32 code, u32 pixelformat, const struct camss_format_info *formats, | |
| 60 | + unsigned int nformats); | |
| 61 | + | |
| 62 | +#endif /* __CAMSS_FORMAT_H__ */ | |
| @@ -353,7 +353,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 352 unmodified lines | ||
| 353 | 353 | writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0); |
| 354 | 354 | writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1); |
| 355 | 355 | |
| 356 | − for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) { | |
| 356 | + for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) { | |
| 357 | 357 | vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i)); |
| 358 | 358 | writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i)); |
| 359 | 359 | } |
| @@ -367,11 +367,11 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 7 unmodified lines | ||
| 367 | 367 | if (status0 & STATUS_0_RESET_ACK) |
| 368 | 368 | vfe->isr_ops.reset_ack(vfe); |
| 369 | 369 | |
| 370 | − for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) | |
| 370 | + for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) | |
| 371 | 371 | if (status0 & STATUS_0_RDI_REG_UPDATE(i)) |
| 372 | 372 | vfe->isr_ops.reg_update(vfe, i); |
| 373 | 373 | |
| 374 | − for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) | |
| 374 | + for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) | |
| 375 | 375 | if (status0 & STATUS_1_RDI_SOF(i)) |
| 376 | 376 | vfe->isr_ops.sof(vfe, i); |
| 377 | 377 | |
| @@ -442,7 +442,7 @@ static int vfe_enable_output(struct vfe_line *line) · 64 unmodified lines | ||
| 442 | 442 | { |
| 443 | 443 | struct vfe_device *vfe = to_vfe(line); |
| 444 | 444 | struct vfe_output *output = &line->output; |
| 445 | − const struct vfe_hw_ops *ops = vfe->ops; | |
| 445 | + const struct vfe_hw_ops *ops = vfe->res->hw_ops; | |
| 446 | 446 | struct media_entity *sensor; |
| 447 | 447 | unsigned long flags; |
| 448 | 448 | unsigned int frame_skip = 0; |
| @@ -560,7 +560,7 @@ static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id) · 111 unmodified lines | ||
| 560 | 560 | unsigned long flags; |
| 561 | 561 | |
| 562 | 562 | spin_lock_irqsave(&vfe->output_lock, flags); |
| 563 | − vfe->ops->reg_update_clear(vfe, line_id); | |
| 563 | + vfe->res->hw_ops->reg_update_clear(vfe, line_id); | |
| 564 | 564 | |
| 565 | 565 | output = &vfe->line[line_id].output; |
| 566 | 566 | |
| @@ -892,7 +892,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 891 unmodified lines | ||
| 892 | 892 | u32 value0, value1; |
| 893 | 893 | int i, j; |
| 894 | 894 | |
| 895 | − vfe->ops->isr_read(vfe, &value0, &value1); | |
| 895 | + vfe->res->hw_ops->isr_read(vfe, &value0, &value1); | |
| 896 | 896 | |
| 897 | 897 | dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", |
| 898 | 898 | value0, value1); |
| @@ -901,7 +901,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 2 unmodified lines | ||
| 901 | 901 | vfe->isr_ops.reset_ack(vfe); |
| 902 | 902 | |
| 903 | 903 | if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) |
| 904 | − vfe->ops->violation_read(vfe); | |
| 904 | + vfe->res->hw_ops->violation_read(vfe); | |
| 905 | 905 | |
| 906 | 906 | if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) |
| 907 | 907 | vfe->isr_ops.halt_ack(vfe); |
| @@ -1050,7 +1050,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 1049 unmodified lines | ||
| 1050 | 1050 | u32 value0, value1; |
| 1051 | 1051 | int i, j; |
| 1052 | 1052 | |
| 1053 | − vfe->ops->isr_read(vfe, &value0, &value1); | |
| 1053 | + vfe->res->hw_ops->isr_read(vfe, &value0, &value1); | |
| 1054 | 1054 | |
| 1055 | 1055 | dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", |
| 1056 | 1056 | value0, value1); |
| @@ -1059,12 +1059,12 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 2 unmodified lines | ||
| 1059 | 1059 | vfe->isr_ops.reset_ack(vfe); |
| 1060 | 1060 | |
| 1061 | 1061 | if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) |
| 1062 | − vfe->ops->violation_read(vfe); | |
| 1062 | + vfe->res->hw_ops->violation_read(vfe); | |
| 1063 | 1063 | |
| 1064 | 1064 | if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) |
| 1065 | 1065 | vfe->isr_ops.halt_ack(vfe); |
| 1066 | 1066 | |
| 1067 | − for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) | |
| 1067 | + for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) | |
| 1068 | 1068 | if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i)) |
| 1069 | 1069 | vfe->isr_ops.reg_update(vfe, i); |
1 more lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 741 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 326 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 1328 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 1798 lines aren’t shown here.
This diff is large: its 520 lines aren’t shown here.
This diff is large: its 343 lines aren’t shown here.
This diff is large: its 26 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 84 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 139 lines aren’t shown here.
This diff is large: its 82 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 217 lines aren’t shown here.
This diff is large: its 27 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 129 lines aren’t shown here.
This diff is large: its 98 lines aren’t shown here.
This diff is large: its 109 lines aren’t shown here.
This diff is large: its 81 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 137 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 250 lines aren’t shown here.
This diff is large: its 103 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 24 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 7 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 186 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 21 lines aren’t shown here.
This diff is large: its 133 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 371 lines aren’t shown here.
This diff is large: its 23 lines aren’t shown here.
This diff is large: its 268 lines aren’t shown here.
This diff is large: its 247 lines aren’t shown here.
This diff is large: its 130 lines aren’t shown here.
This diff is large: its 432 lines aren’t shown here.
This diff is large: its 196 lines aren’t shown here.
This diff is large: its 363 lines aren’t shown here.
This diff is large: its 188 lines aren’t shown here.
This diff is large: its 15 lines aren’t shown here.
This diff is large: its 17 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 229 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 187 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 107 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 35 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 51 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 12 lines aren’t shown here.
This diff is large: its 85 lines aren’t shown here.
This diff is large: its 238 lines aren’t shown here.
This diff is large: its 221 lines aren’t shown here.
This diff is large: its 312 lines aren’t shown here.
This diff is large: its 53 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 34 lines aren’t shown here.
This diff is large: its 123 lines aren’t shown here.
This diff is large: its 549 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 6 lines aren’t shown here.
This diff is large: its 42 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 40 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 32 lines aren’t shown here.
This diff is large: its 22 lines aren’t shown here.
This diff is large: its 25 lines aren’t shown here.
This diff is large: its 30 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 47 lines aren’t shown here.
This diff is large: its 136 lines aren’t shown here.
This diff is large: its 13 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 20 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 18 lines aren’t shown here.
This diff is large: its 16 lines aren’t shown here.
This diff is large: its 72 lines aren’t shown here.
This diff is large: its 11 lines aren’t shown here.
This diff is large: its 86 lines aren’t shown here.
This diff is large: its 94 lines aren’t shown here.
This diff is large: its 29 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 4 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 104 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 50 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 57 lines aren’t shown here.
This diff is large: its 59 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 60 lines aren’t shown here.
This diff is large: its 54 lines aren’t shown here.
This diff is large: its 63 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 49 lines aren’t shown here.
This diff is large: its 28 lines aren’t shown here.
This diff is large: its 117 lines aren’t shown here.
This diff is large: its 31 lines aren’t shown here.
This diff is large: its 1553 lines aren’t shown here.
This diff is large: its 156 lines aren’t shown here.
This diff is large: its 826 lines aren’t shown here.
This diff is large: its 48 lines aren’t shown here.
This diff is large: its 159 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 738 lines aren’t shown here.
This diff is large: its 194 lines aren’t shown here.
This diff is large: its 415 lines aren’t shown here.
This diff is large: its 19 lines aren’t shown here.
This diff is large: its 10 lines aren’t shown here.
This diff is large: its 353 lines aren’t shown here.
This diff is large: its 666 lines aren’t shown here.
This diff is large: its 167 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 495 lines aren’t shown here.
This diff is large: its 46 lines aren’t shown here.
This diff is large: its 55 lines aren’t shown here.
This diff is large: its 97 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 52 lines aren’t shown here.
This diff is large: its 112 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 80 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 106 lines aren’t shown here.
This diff is large: its 66 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 70 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 58 lines aren’t shown here.
This diff is large: its 77 lines aren’t shown here.
This diff is large: its 65 lines aren’t shown here.
This diff is large: its 61 lines aren’t shown here.
This diff is large: its 83 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 73 lines aren’t shown here.
This diff is large: its 62 lines aren’t shown here.
This diff is large: its 75 lines aren’t shown here.
This diff is large: its 67 lines aren’t shown here.
This diff is large: its 37 lines aren’t shown here.
This diff is large: its 36 lines aren’t shown here.
This diff is large: its 249 lines aren’t shown here.
This diff is large: its 64 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 8 lines aren’t shown here.
This diff is large: its 44 lines aren’t shown here.
This diff is large: its 160 lines aren’t shown here.
This diff is large: its 969 lines aren’t shown here.
This diff is large: its 203 lines aren’t shown here.
This diff is large: its 9 lines aren’t shown here.
This diff is large: its 38 lines aren’t shown here.