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 | - MyGica iGrabber | 438 | - MyGica iGrabber |
| 439 | - em2860 | 439 | - em2860 |
| 440 | - 1f4d:1abe | 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 | .. code-block:: none | 135 | .. code-block:: none |
| 136 | 136 | ||
| 137 | media-ctl -l "\"ov2740 14-0036\":0 -> \"Intel IPU6 CSI2 1\":0[1]" | 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]" | 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[5]" | 139 | media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[1]" |
| 140 | 140 | ||
| 141 | # set routing | 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]" | 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]" | 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]" | 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]" | 147 | media-ctl -V "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]" |
| 148 | 148 | ||
| 149 | CAPTURE_DEV=$(media-ctl -e "Intel IPU6 ISYS Capture 0") | 149 | CAPTURE_DEV=$(media-ctl -e "Intel IPU6 ISYS Capture 0") |
| 150 | ./yavta --data-prefix -c100 -n5 -I -s1932x1092 --file=/tmp/frame-#.bin \ | 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 | 89 Sony BTF-PG472Z PAL/SECAM | 97 | 89 Sony BTF-PG472Z PAL/SECAM |
| 98 | 90 Sony BTF-PK467Z NTSC-M-JP | 98 | 90 Sony BTF-PK467Z NTSC-M-JP |
| 99 | 91 Sony BTF-PB463Z NTSC-M | 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 | omap4_camera | 23 | omap4_camera |
| 24 | philips | 24 | philips |
| 25 | qcom_camss | 25 | qcom_camss |
| 26 | raspberrypi-pisp-be | ||
| 26 | rcar-fdp1 | 27 | rcar-fdp1 |
| 27 | rkisp1 | 28 | rkisp1 |
| 28 | saa7134 | 29 | saa7134 |
| @@ -302,6 +302,15 @@ all configurable using the following module options: · 301 unmodified lines | |||
| 302 | - 0: forbid hints | 302 | - 0: forbid hints |
| 303 | - 1: allow hints | 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 | Taken together, all these module options allow you to precisely customize | 314 | Taken together, all these module options allow you to precisely customize |
| 306 | the driver behavior and test your application with all sorts of permutations. | 315 | the driver behavior and test your application with all sorts of permutations. |
| 307 | It is also very suitable to emulate hardware that is not yet available, e.g. | 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 | This is probably the most frequently used feature. The video capture device | 323 | This is probably the most frequently used feature. The video capture device |
| 315 | can be configured by using the module options num_inputs, input_types and | 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 | 325 | ccs_cap_mode (see "Configuring the driver" for more detailed information), |
| 317 | four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI | 326 | but by default four inputs are configured: a webcam, a TV tuner, an S-Video |
| 318 | input, one input for each input type. Those are described in more detail | 327 | and an HDMI input, one input for each input type. Those are described in more |
| 319 | below. | 328 | detail below. |
| 320 | 329 | ||
| 321 | Special attention has been given to the rate at which new frames become | 330 | Special attention has been given to the rate at which new frames become |
| 322 | available. The jitter will be around 1 jiffie (that depends on the HZ | 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 | The video output device can be configured by using the module options | 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 | 446 | num_outputs, output_types and ccs_out_mode (see "Configuring the driver" |
| 438 | information), but by default two outputs are configured: an S-Video and an | 447 | for more detailed information), but by default two outputs are configured: |
| 439 | HDMI input, one output for each output type. Those are described in more detail | 448 | an S-Video and an HDMI input, one output for each output type. Those are |
| 440 | below. | 449 | described in more detail below. |
| 441 | 450 | ||
| 442 | Like with video capture the framerate is also exact in the long term. | 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 | affects the reported colorspace since DVI_D outputs will always use | 1020 | affects the reported colorspace since DVI_D outputs will always use |
| 1012 | sRGB. | 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 | FM Radio Receiver Controls | 1024 | FM Radio Receiver Controls |
| 1021 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ | 1025 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| @@ -1130,35 +1134,34 @@ Metadata Capture Controls · 108 unmodified lines | |||
| 1130 | 1134 | ||
| 1131 | if set, then the generated metadata stream contains Source Clock information. | 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 | 1138 | Video, Sliced VBI and HDMI CEC Looping |
| 1137 | to VBI input and RDS output to RDS input. For video/VBI looping this emulates | 1139 | -------------------------------------- |
| 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. | ||
| 1141 | 1140 | ||
| 1142 | Since radio is wireless this looping always happens if the radio receiver | 1141 | Video Looping functionality is supported for devices created by the same |
| 1143 | frequency is close to the radio transmitter frequency. In that case the radio | 1142 | vivid driver instance, as well as across multiple instances of the vivid driver. |
| 1144 | transmitter will 'override' the emulated radio stations. | 1143 | The vivid driver supports looping of video and Sliced VBI data between an S-Video output |
| 1145 | 1144 | and an S-Video input. It also supports looping of video and HDMI CEC data between an | |
| 1146 | Looping is currently supported only between devices created by the same | 1145 | HDMI output and an HDMI input. |
| 1147 | vivid driver instance. | ||
| 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 | 1158 | If an 'HDMI/S-Video XXX-N Is Connected To' control selected an output, then the video |
| 1151 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 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' | 1161 | - the currently selected input matches the input indicated by the control name. |
| 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: | ||
| 1159 | 1162 | ||
| 1160 | - the input type matches the output type. So the HDMI input cannot receive | 1163 | - in the vivid instance of the output connector, the currently selected output matches |
| 1161 | video from the S-Video output. | 1164 | the output indicated by the control's value. |
| 1162 | 1165 | ||
| 1163 | - the video resolution of the video input must match that of the video output. | 1166 | - the video resolution of the video input must match that of the video output. |
| 1164 | So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz | 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 | "DV Timings Signal Mode" for the HDMI input should be configured so that a | 1188 | "DV Timings Signal Mode" for the HDMI input should be configured so that a |
| 1186 | valid signal is passed to the video input. | 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 | The framerates do not have to match, although this might change in the future. | 1193 | The framerates do not have to match, although this might change in the future. |
| 1189 | 1194 | ||
| 1190 | By default you will see the OSD text superimposed on top of the looped video. | 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 | Radio & RDS Looping | 1205 | Radio & RDS Looping |
| 1201 | ~~~~~~~~~~~~~~~~~~~ | 1206 | ------------------- |
| 1202 | 1207 | ||
| 1203 | As mentioned in section 6 the radio receiver emulates stations are regular | 1208 | The vivid driver supports looping of RDS output to RDS input. |
| 1204 | frequency intervals. Depending on the frequency of the radio receiver a | 1209 | |
| 1205 | signal strength value is calculated (this is returned by VIDIOC_G_TUNER). | 1210 | Since radio is wireless this looping always happens if the radio receiver |
| 1206 | However, it will also look at the frequency set by the radio transmitter and | 1211 | frequency is close to the radio transmitter frequency. In that case the radio |
| 1207 | if that results in a higher signal strength than the settings of the radio | 1212 | transmitter will 'override' the emulated radio stations. |
| 1208 | transmitter will be used as if it was a valid station. This also includes | 1213 | |
| 1209 | the RDS data (if any) that the transmitter 'transmits'. This is received | 1214 | RDS looping is currently supported only between devices created by the same |
| 1210 | faithfully on the receiver side. Note that when the driver is loaded the | 1215 | vivid driver instance. |
| 1211 | frequencies of the radio receiver and transmitter are not identical, so | 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 | initially no looping takes place. | 1226 | initially no looping takes place. |
| 1213 | 1227 | ||
| 1214 | 1228 | ||
| @@ -1218,8 +1232,8 @@ Cropping, Composing, Scaling · 3 unmodified lines | |||
| 1218 | This driver supports cropping, composing and scaling in any combination. Normally | 1232 | This driver supports cropping, composing and scaling in any combination. Normally |
| 1219 | which features are supported can be selected through the Vivid controls, | 1233 | which features are supported can be selected through the Vivid controls, |
| 1220 | but it is also possible to hardcode it when the module is loaded through the | 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 | 1235 | ccs_cap_mode and ccs_out_mode module options. See "Configuring the driver" on |
| 1222 | these module options. | 1236 | the details of these module options. |
| 1223 | 1237 | ||
| 1224 | This allows you to test your application for all these variations. | 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 | The driver has to be configured to support the multiplanar formats. By default | 1275 | The driver has to be configured to support the multiplanar formats. By default |
| 1262 | the driver instances are single-planar. This can be changed by setting the | 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 | If the driver instance is using the multiplanar formats/API, then the first | 1280 | If the driver instance is using the multiplanar formats/API, then the first |
| 1266 | single planar format (YUYV) and the multiplanar NV16M and NV61M formats the | 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 | Video output will also honor any data_offset that the application set. | 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 | Output Overlay | 1288 | Output Overlay |
| 1342 | -------------- | 1289 | -------------- |
| 1343 | 1290 | ||
| @@ -1405,8 +1352,6 @@ Just as a reminder and in no particular order: · 61 unmodified lines | |||
| 1405 | - Add ARGB888 overlay support: better testing of the alpha channel | 1352 | - Add ARGB888 overlay support: better testing of the alpha channel |
| 1406 | - Improve pixel aspect support in the tpg code by passing a real v4l2_fract | 1353 | - Improve pixel aspect support in the tpg code by passing a real v4l2_fract |
| 1407 | - Use per-queue locks and/or per-device locks to improve throughput | 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 | - The SDR radio should use the same 'frequencies' for stations as the normal | 1355 | - The SDR radio should use the same 'frequencies' for stations as the normal |
| 1411 | radio receiver, and give back noise if the frequency doesn't match up with | 1356 | radio receiver, and give back noise if the frequency doesn't match up with |
| 1412 | a station frequency | 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 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) | 1 | # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) |
| 2 | %YAML 1.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 | $schema: http://devicetree.org/meta-schemas/core.yaml# | 5 | $schema: http://devicetree.org/meta-schemas/core.yaml# |
| 6 | 6 | ||
| 7 | title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor | 7 | title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor |
| @@ -13,11 +13,16 @@ description: |- · 5 unmodified lines | |||
| 13 | IMX258 is a diagonal 5.867mm (Type 1/3.06) 13 Mega-pixel CMOS active pixel | 13 | IMX258 is a diagonal 5.867mm (Type 1/3.06) 13 Mega-pixel CMOS active pixel |
| 14 | type stacked image sensor with a square pixel array of size 4208 x 3120. It | 14 | type stacked image sensor with a square pixel array of size 4208 x 3120. It |
| 15 | is programmable through I2C interface. Image data is sent through MIPI | 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 | properties: | 21 | properties: |
| 19 | compatible: | 22 | compatible: |
| 20 | const: sony,imx258 | 23 | enum: |
| 24 | - sony,imx258 | ||
| 25 | - sony,imx258-pdaf | ||
| 21 | 26 | ||
| 22 | assigned-clocks: true | 27 | assigned-clocks: true |
| 23 | assigned-clock-parents: true | 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 | oneOf: | 23 | oneOf: |
| 24 | - enum: | 24 | - enum: |
| 25 | - mediatek,mt8183-mdp3-rdma | 25 | - mediatek,mt8183-mdp3-rdma |
| 26 | - mediatek,mt8188-mdp3-rdma | ||
| 26 | - mediatek,mt8195-mdp3-rdma | 27 | - mediatek,mt8195-mdp3-rdma |
| 27 | - mediatek,mt8195-vdo1-rdma | 28 | - mediatek,mt8195-vdo1-rdma |
| 28 | - items: | 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 | properties: | 19 | properties: |
| 20 | compatible: | 20 | compatible: |
| 21 | const: qcom,msm8996-venus | 21 | enum: |
| 22 | - qcom,msm8996-venus | ||
| 23 | - qcom,msm8998-venus | ||
| 22 | 24 | ||
| 23 | power-domains: | 25 | power-domains: |
| 24 | maxItems: 1 | 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 | - rc-msi-digivox-iii | 103 | - rc-msi-digivox-iii |
| 104 | - rc-msi-tvanywhere | 104 | - rc-msi-tvanywhere |
| 105 | - rc-msi-tvanywhere-plus | 105 | - rc-msi-tvanywhere-plus |
| 106 | - rc-mygica-utv3 | ||
| 106 | - rc-nebula | 107 | - rc-nebula |
| 107 | - rc-nec-terratec-cinergy-xs | 108 | - rc-nec-terratec-cinergy-xs |
| 108 | - rc-norwood | 109 | - rc-norwood |
| @@ -24,6 +24,7 @@ properties: · 23 unmodified lines | |||
| 24 | - enum: | 24 | - enum: |
| 25 | - rockchip,rk3228-rga | 25 | - rockchip,rk3228-rga |
| 26 | - rockchip,rk3568-rga | 26 | - rockchip,rk3568-rga |
| 27 | - rockchip,rk3588-rga | ||
| 27 | - const: rockchip,rk3288-rga | 28 | - const: rockchip,rk3288-rga |
| 28 | 29 | ||
| 29 | reg: | 30 | reg: |
| @@ -26,3 +26,4 @@ Video4Linux devices · 25 unmodified lines | |||
| 26 | v4l2-tuner | 26 | v4l2-tuner |
| 27 | v4l2-common | 27 | v4l2-common |
| 28 | v4l2-tveeprom | 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 | max2175 | 35 | max2175 |
| 36 | npcm-video | 36 | npcm-video |
| 37 | omap3isp-uapi | 37 | omap3isp-uapi |
| 38 | st-vgxy61 | ||
| 39 | thp7312 | 38 | thp7312 |
| 40 | uvcvideo | 39 | uvcvideo |
| 40 | vgxy61 | ||
File renamed without changes.
| @@ -971,8 +971,8 @@ FWHT Flags · 970 unmodified lines | |||
| 971 | - ``horizontal_scale`` | 971 | - ``horizontal_scale`` |
| 972 | - Horizontal scaling factor. | 972 | - Horizontal scaling factor. |
| 973 | * - __u8 | 973 | * - __u8 |
| 974 | - ``vertical_scaling factor`` | 974 | - ``vertical_scale`` |
| 975 | - Vertical scale. | 975 | - Vertical scaling factor. |
| 976 | * - __u8 | 976 | * - __u8 |
| 977 | - ``version`` | 977 | - ``version`` |
| 978 | - Bitstream version. | 978 | - Bitstream version. |
| @@ -1653,6 +1653,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type - · 1652 unmodified lines | |||
| 1653 | Quantization parameter for a P frame for FWHT. Valid range: from 1 | 1653 | Quantization parameter for a P frame for FWHT. Valid range: from 1 |
| 1654 | to 31. | 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 | .. raw:: latex | 1670 | .. raw:: latex |
| 1657 | 1671 | ||
| 1658 | \normalsize | 1672 | \normalsize |
| @@ -15,6 +15,7 @@ These formats are used for the :ref:`metadata` interface only. · 14 unmodified lines | |||
| 15 | metafmt-d4xx | 15 | metafmt-d4xx |
| 16 | metafmt-generic | 16 | metafmt-generic |
| 17 | metafmt-intel-ipu3 | 17 | metafmt-intel-ipu3 |
| 18 | metafmt-pisp-be | ||
| 18 | metafmt-rkisp1 | 19 | metafmt-rkisp1 |
| 19 | metafmt-uvc | 20 | metafmt-uvc |
| 20 | metafmt-vivid | 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 | :maxdepth: 1 | 20 | :maxdepth: 1 |
| 21 | 21 | ||
| 22 | pixfmt-srggb8 | 22 | pixfmt-srggb8 |
| 23 | pixfmt-srggb8-pisp-comp | ||
| 23 | pixfmt-srggb10 | 24 | pixfmt-srggb10 |
| 24 | pixfmt-srggb10p | 25 | pixfmt-srggb10p |
| 25 | pixfmt-srggb10alaw8 | 26 | pixfmt-srggb10alaw8 |
| @@ -996,6 +996,60 @@ arranged in little endian order. · 995 unmodified lines | |||
| 996 | 996 | ||
| 997 | \normalsize | 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 | Deprecated RGB Formats | 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 | For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with | 209 | For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with |
| 210 | padding zeros in the 4 low bits, in contrast to the Y12 format, which has | 210 | padding zeros in the 4 low bits, in contrast to the Y12 format, which has |
| 211 | its padding located in the most significant bits of the 16 bit word. | 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 | F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml | 9190 | F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml |
| 9191 | F: drivers/media/i2c/gc0308.c | 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 | GALAXYCORE GC2145 SENSOR DRIVER | 9207 | GALAXYCORE GC2145 SENSOR DRIVER |
| 9194 | M: Alain Volmat <alain.volmat@foss.st.com> | 9208 | M: Alain Volmat <alain.volmat@foss.st.com> |
| 9195 | L: linux-media@vger.kernel.org | 9209 | L: linux-media@vger.kernel.org |
| @@ -10872,6 +10886,13 @@ S: Maintained · 1676 unmodified lines | |||
| 10872 | F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml | 10886 | F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml |
| 10873 | F: drivers/auxdisplay/img-ascii-lcd.c | 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 | IMGTEC IR DECODER DRIVER | 10896 | IMGTEC IR DECODER DRIVER |
| 10876 | S: Orphan | 10897 | S: Orphan |
| 10877 | F: drivers/media/rc/img-ir/ | 10898 | F: drivers/media/rc/img-ir/ |
| @@ -13632,6 +13653,20 @@ S: Maintained · 2754 unmodified lines | |||
| 13632 | F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml | 13653 | F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml |
| 13633 | F: drivers/staging/media/max96712/max96712.c | 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 | MAX9860 MONO AUDIO VOICE CODEC DRIVER | 13670 | MAX9860 MONO AUDIO VOICE CODEC DRIVER |
| 13636 | M: Peter Rosin <peda@axentia.se> | 13671 | M: Peter Rosin <peda@axentia.se> |
| 13637 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | 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 | S: Maintained | 18983 | S: Maintained |
| 18949 | F: drivers/ras/amd/fmpm.c | 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 | RC-CORE / LIRC FRAMEWORK | 18995 | RC-CORE / LIRC FRAMEWORK |
| 18952 | M: Sean Young <sean@mess.org> | 18996 | M: Sean Young <sean@mess.org> |
| 18953 | L: linux-media@vger.kernel.org | 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 | SOFTLOGIC 6x10 MPEG CODEC | 20943 | SOFTLOGIC 6x10 MPEG CODEC |
| 20900 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> | 20944 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> |
| 20901 | M: Anton Sviridenko <anton@corp.bluecherry.net> | ||
| 20902 | M: Andrey Utkin <andrey_utkin@fastmail.com> | 20945 | M: Andrey Utkin <andrey_utkin@fastmail.com> |
| 20903 | M: Ismael Luceno <ismael@iodev.co.uk> | 20946 | M: Ismael Luceno <ismael@iodev.co.uk> |
| 20904 | L: linux-media@vger.kernel.org | 20947 | L: linux-media@vger.kernel.org |
| @@ -20994,7 +21037,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com> · 89 unmodified lines | |||
| 20994 | L: linux-media@vger.kernel.org | 21037 | L: linux-media@vger.kernel.org |
| 20995 | S: Maintained | 21038 | S: Maintained |
| 20996 | T: git git://linuxtv.org/media_tree.git | 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 | F: drivers/media/i2c/imx258.c | 21041 | F: drivers/media/i2c/imx258.c |
| 20999 | 21042 | ||
| 21000 | SONY IMX274 SENSOR DRIVER | 21043 | SONY IMX274 SENSOR DRIVER |
| @@ -21005,6 +21048,15 @@ T: git git://linuxtv.org/media_tree.git · 4 unmodified lines | |||
| 21005 | F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml | 21048 | F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml |
| 21006 | F: drivers/media/i2c/imx274.c | 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 | SONY IMX290 SENSOR DRIVER | 21060 | SONY IMX290 SENSOR DRIVER |
| 21009 | M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> | 21061 | M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org> |
| 21010 | L: linux-media@vger.kernel.org | 21062 | L: linux-media@vger.kernel.org |
| @@ -21381,8 +21433,8 @@ L: linux-media@vger.kernel.org · 370 unmodified lines | |||
| 21381 | S: Maintained | 21433 | S: Maintained |
| 21382 | T: git git://linuxtv.org/media_tree.git | 21434 | T: git git://linuxtv.org/media_tree.git |
| 21383 | F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml | 21435 | F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml |
| 21384 | F: Documentation/userspace-api/media/drivers/st-vgxy61.rst | 21436 | F: Documentation/userspace-api/media/drivers/vgxy61.rst |
| 21385 | F: drivers/media/i2c/st-vgxy61.c | 21437 | F: drivers/media/i2c/vgxy61.c |
| 21386 | 21438 | ||
| 21387 | ST VL53L0X ToF RANGER(I2C) IIO DRIVER | 21439 | ST VL53L0X ToF RANGER(I2C) IIO DRIVER |
| 21388 | M: Song Qiang <songqiang1304521@gmail.com> | 21440 | M: Song Qiang <songqiang1304521@gmail.com> |
| @@ -23108,7 +23160,6 @@ F: tools/testing/selftests/turbostat/ · 1719 unmodified lines | |||
| 23108 | 23160 | ||
| 23109 | TW5864 VIDEO4LINUX DRIVER | 23161 | TW5864 VIDEO4LINUX DRIVER |
| 23110 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> | 23162 | M: Bluecherry Maintainers <maintainers@bluecherrydvr.com> |
| 23111 | M: Anton Sviridenko <anton@corp.bluecherry.net> | ||
| 23112 | M: Andrey Utkin <andrey.utkin@corp.bluecherry.net> | 23163 | M: Andrey Utkin <andrey.utkin@corp.bluecherry.net> |
| 23113 | M: Andrey Utkin <andrey_utkin@fastmail.com> | 23164 | M: Andrey Utkin <andrey_utkin@fastmail.com> |
| 23114 | L: linux-media@vger.kernel.org | 23165 | L: linux-media@vger.kernel.org |
| @@ -23725,7 +23776,7 @@ F: drivers/media/i2c/mt* · 610 unmodified lines | |||
| 23725 | F: drivers/media/i2c/og* | 23776 | F: drivers/media/i2c/og* |
| 23726 | F: drivers/media/i2c/ov* | 23777 | F: drivers/media/i2c/ov* |
| 23727 | F: drivers/media/i2c/s5* | 23778 | F: drivers/media/i2c/s5* |
| 23728 | F: drivers/media/i2c/st-vgxy61.c | 23779 | F: drivers/media/i2c/vgxy61.c |
| 23729 | 23780 | ||
| 23730 | VF610 NAND DRIVER | 23781 | VF610 NAND DRIVER |
| 23731 | M: Stefan Agner <stefan@agner.ch> | 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 | mtu_msg.x_msg_header.msg_flags = 0; | 839 | mtu_msg.x_msg_header.msg_flags = 0; |
| 840 | mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; | 840 | mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ; |
| 841 | mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg); | 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 | coredev->sendrequest_handler(coredev->context, &mtu_msg, | 844 | coredev->sendrequest_handler(coredev->context, &mtu_msg, |
| 845 | sizeof(mtu_msg)); | 845 | sizeof(mtu_msg)); |
| @@ -852,7 +852,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev) · 6 unmodified lines | |||
| 852 | SMS_INIT_MSG(&crys_msg.x_msg_header, | 852 | SMS_INIT_MSG(&crys_msg.x_msg_header, |
| 853 | MSG_SMS_NEW_CRYSTAL_REQ, | 853 | MSG_SMS_NEW_CRYSTAL_REQ, |
| 854 | sizeof(crys_msg)); | 854 | sizeof(crys_msg)); |
| 855 | crys_msg.msg_data[0] = board->crystal; | 855 | crys_msg.msg_data = board->crystal; |
| 856 | 856 | ||
| 857 | coredev->sendrequest_handler(coredev->context, &crys_msg, | 857 | coredev->sendrequest_handler(coredev->context, &crys_msg, |
| 858 | sizeof(crys_msg)); | 858 | sizeof(crys_msg)); |
| @@ -1306,7 +1306,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode) · 447 unmodified lines | |||
| 1306 | msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); | 1306 | msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer); |
| 1307 | SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, | 1307 | SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, |
| 1308 | sizeof(struct sms_msg_data)); | 1308 | sizeof(struct sms_msg_data)); |
| 1309 | msg->msg_data[0] = mode; | 1309 | msg->msg_data = mode; |
| 1310 | 1310 | ||
| 1311 | rc = smscore_sendrequest_and_wait(coredev, msg, | 1311 | rc = smscore_sendrequest_and_wait(coredev, msg, |
| 1312 | msg->x_msg_header. msg_length, | 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 | SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, | 1395 | SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ, |
| 1396 | sizeof(struct sms_msg_data)); | 1396 | sizeof(struct sms_msg_data)); |
| 1397 | msg->msg_data[0] = mode; | 1397 | msg->msg_data = mode; |
| 1398 | 1398 | ||
| 1399 | rc = smscore_sendrequest_and_wait( | 1399 | rc = smscore_sendrequest_and_wait( |
| 1400 | coredev, msg, msg->x_msg_header.msg_length, | 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 | struct sms_msg_data *validity = (struct sms_msg_data *) phdr; | 1554 | struct sms_msg_data *validity = (struct sms_msg_data *) phdr; |
| 1555 | 1555 | ||
| 1556 | pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n", | 1556 | pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n", |
| 1557 | validity->msg_data[0]); | 1557 | validity->msg_data); |
| 1558 | complete(&coredev->data_validity_done); | 1558 | complete(&coredev->data_validity_done); |
| 1559 | break; | 1559 | break; |
| 1560 | } | 1560 | } |
| @@ -616,7 +616,7 @@ struct sms_msg_hdr { · 615 unmodified lines | |||
| 616 | 616 | ||
| 617 | struct sms_msg_data { | 617 | struct sms_msg_data { |
| 618 | struct sms_msg_hdr x_msg_header; | 618 | struct sms_msg_hdr x_msg_header; |
| 619 | u32 msg_data[1]; | 619 | u32 msg_data; |
| 620 | }; | 620 | }; |
| 621 | 621 | ||
| 622 | struct sms_msg_data2 { | 622 | struct sms_msg_data2 { |
| @@ -666,7 +666,7 @@ struct sms_firmware { · 43 unmodified lines | |||
| 666 | u32 check_sum; | 666 | u32 check_sum; |
| 667 | u32 length; | 667 | u32 length; |
| 668 | u32 start_address; | 668 | u32 start_address; |
| 669 | u8 payload[1]; | 669 | u8 payload[]; |
| 670 | }; | 670 | }; |
| 671 | 671 | ||
| 672 | /* statistics information returned as response for | 672 | /* statistics information returned as response for |
| @@ -1042,20 +1042,6 @@ struct sms_srvm_signal_status { · 369 unmodified lines | |||
| 1042 | u32 request_id; | 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 | struct smscore_config_gpio { | 1045 | struct smscore_config_gpio { |
| 1060 | #define SMS_GPIO_DIRECTION_INPUT 0 | 1046 | #define SMS_GPIO_DIRECTION_INPUT 0 |
| 1061 | #define SMS_GPIO_DIRECTION_OUTPUT 1 | 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 | pid_msg.x_msg_header.msg_flags = 0; | 689 | pid_msg.x_msg_header.msg_flags = 0; |
| 690 | pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; | 690 | pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ; |
| 691 | pid_msg.x_msg_header.msg_length = sizeof(pid_msg); | 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 | return smsclient_sendrequest(client->smsclient, | 694 | return smsclient_sendrequest(client->smsclient, |
| 695 | &pid_msg, sizeof(pid_msg)); | 695 | &pid_msg, sizeof(pid_msg)); |
| @@ -711,7 +711,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed) · 15 unmodified lines | |||
| 711 | pid_msg.x_msg_header.msg_flags = 0; | 711 | pid_msg.x_msg_header.msg_flags = 0; |
| 712 | pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; | 712 | pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ; |
| 713 | pid_msg.x_msg_header.msg_length = sizeof(pid_msg); | 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 | return smsclient_sendrequest(client->smsclient, | 716 | return smsclient_sendrequest(client->smsclient, |
| 717 | &pid_msg, sizeof(pid_msg)); | 717 | &pid_msg, sizeof(pid_msg)); |
| @@ -20,11 +20,12 @@ void smsendian_handle_tx_message(void *buffer) · 19 unmodified lines | |||
| 20 | struct sms_msg_data *msg = buffer; | 20 | struct sms_msg_data *msg = buffer; |
| 21 | int i; | 21 | int i; |
| 22 | int msg_words; | 22 | int msg_words; |
| 23 | u32 *msg_data = &msg->msg_data; | ||
| 23 | 24 | ||
| 24 | switch (msg->x_msg_header.msg_type) { | 25 | switch (msg->x_msg_header.msg_type) { |
| 25 | case MSG_SMS_DATA_DOWNLOAD_REQ: | 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 | break; | 29 | break; |
| 29 | } | 30 | } |
| 30 | 31 | ||
| @@ -33,7 +34,7 @@ void smsendian_handle_tx_message(void *buffer) · 2 unmodified lines | |||
| 33 | sizeof(struct sms_msg_hdr))/4; | 34 | sizeof(struct sms_msg_hdr))/4; |
| 34 | 35 | ||
| 35 | for (i = 0; i < msg_words; i++) | 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 | break; | 39 | break; |
| 39 | } | 40 | } |
| @@ -66,11 +67,12 @@ void smsendian_handle_rx_message(void *buffer) · 26 unmodified lines | |||
| 66 | 67 | ||
| 67 | default: | 68 | default: |
| 68 | { | 69 | { |
| 70 | u32 *msg_data = &msg->msg_data; | ||
| 69 | msg_words = (msg->x_msg_header.msg_length - | 71 | msg_words = (msg->x_msg_header.msg_length - |
| 70 | sizeof(struct sms_msg_hdr))/4; | 72 | sizeof(struct sms_msg_hdr))/4; |
| 71 | 73 | ||
| 72 | for (i = 0; i < msg_words; i++) | 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 | break; | 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 | EXPORT_SYMBOL_GPL(uvc_format_by_guid); | 181 | EXPORT_SYMBOL_GPL(uvc_format_by_guid); |
| 182 | 182 | ||
| 183 | MODULE_DESCRIPTION("USB Video Class common code"); | ||
| 183 | MODULE_LICENSE("GPL"); | 184 | MODULE_LICENSE("GPL"); |
| @@ -199,7 +199,6 @@ module_param(debug, int, 0644); · 198 unmodified lines | |||
| 199 | }) | 199 | }) |
| 200 | 200 | ||
| 201 | static void __vb2_queue_cancel(struct vb2_queue *q); | 201 | static void __vb2_queue_cancel(struct vb2_queue *q); |
| 202 | static void __enqueue_in_driver(struct vb2_buffer *vb); | ||
| 203 | 202 | ||
| 204 | static const char *vb2_state_name(enum vb2_buffer_state s) | 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 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 21 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
| 22 | MODULE_DESCRIPTION("Videobuf2 helper library for simple DVB cards"); | ||
| 22 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
| 23 | 24 | ||
| 24 | /* ------------------------------------------------------------------ */ | 25 | /* ------------------------------------------------------------------ */ |
| @@ -25,6 +25,7 @@ · 24 unmodified lines | |||
| 25 | #include "au8522_priv.h" | 25 | #include "au8522_priv.h" |
| 26 | 26 | ||
| 27 | MODULE_AUTHOR("Devin Heitmueller"); | 27 | MODULE_AUTHOR("Devin Heitmueller"); |
| 28 | MODULE_DESCRIPTION("Auvitek AU8522 QAM/8VSB demodulator driver and video decoder"); | ||
| 28 | MODULE_LICENSE("GPL"); | 29 | MODULE_LICENSE("GPL"); |
| 29 | 30 | ||
| 30 | static int au8522_analog_debug; | 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 | __func__, ##arg); \ | 32 | __func__, ##arg); \ |
| 33 | } while (0) | 33 | } while (0) |
| 34 | 34 | ||
| 35 | struct i2c_device { | ||
| 36 | struct i2c_adapter *i2c_adap; | ||
| 37 | u8 i2c_addr; | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct dib7000p_state { | 35 | struct dib7000p_state { |
| 41 | struct dvb_frontend demod; | 36 | struct dvb_frontend demod; |
| 42 | struct dib7000p_config cfg; | 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 | STRUCTURES | 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 | /* HI command */ | 979 | /* HI command */ |
| 987 | struct drxj_hi_cmd { | 980 | struct drxj_hi_cmd { |
| 988 | u16 cmd; | 981 | u16 cmd; |
| @@ -1854,5 +1854,6 @@ error: · 1853 unmodified lines | |||
| 1854 | return NULL; | 1854 | return NULL; |
| 1855 | } | 1855 | } |
| 1856 | EXPORT_SYMBOL_GPL(mb86a16_attach); | 1856 | EXPORT_SYMBOL_GPL(mb86a16_attach); |
| 1857 | MODULE_DESCRIPTION("Fujitsu MB86A16 DVB-S/DSS DC Receiver driver"); | ||
| 1857 | MODULE_LICENSE("GPL"); | 1858 | MODULE_LICENSE("GPL"); |
| 1858 | MODULE_AUTHOR("Manu Abraham"); | 1859 | MODULE_AUTHOR("Manu Abraham"); |
| @@ -168,7 +168,7 @@ struct MBIN_FILE_HEADER_T { · 167 unmodified lines | |||
| 168 | 168 | ||
| 169 | struct MBIN_FILE_T { | 169 | struct MBIN_FILE_T { |
| 170 | struct MBIN_FILE_HEADER_T header; | 170 | struct MBIN_FILE_HEADER_T header; |
| 171 | u8 data[1]; | 171 | u8 data[]; |
| 172 | }; | 172 | }; |
| 173 | 173 | ||
| 174 | struct MBIN_SEGMENT_HEADER_T { | 174 | struct MBIN_SEGMENT_HEADER_T { |
| @@ -179,7 +179,7 @@ struct MBIN_SEGMENT_HEADER_T { · 4 unmodified lines | |||
| 179 | 179 | ||
| 180 | struct MBIN_SEGMENT_T { | 180 | struct MBIN_SEGMENT_T { |
| 181 | struct MBIN_SEGMENT_HEADER_T header; | 181 | struct MBIN_SEGMENT_HEADER_T header; |
| 182 | u8 data[1]; | 182 | u8 data[]; |
| 183 | }; | 183 | }; |
| 184 | 184 | ||
| 185 | enum MXL_CMD_TYPE_E { MXL_CMD_WRITE = 0, MXL_CMD_READ }; | 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 | return stv090x_write_regs(state, reg, &tmp, 1); | 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 | static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) | 767 | static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) |
| 752 | { | 768 | { |
| 753 | u32 reg; | 769 | u32 reg; |
| @@ -761,12 +777,8 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) · 7 unmodified lines | |||
| 761 | * In case of any error, the lock is unlocked and exit within the | 777 | * In case of any error, the lock is unlocked and exit within the |
| 762 | * relevant operations themselves. | 778 | * relevant operations themselves. |
| 763 | */ | 779 | */ |
| 764 | if (enable) { | 780 | if (enable) |
| 765 | if (state->config->tuner_i2c_lock) | 781 | stv090x_tuner_i2c_lock(state); |
| 766 | state->config->tuner_i2c_lock(&state->frontend, 1); | ||
| 767 | else | ||
| 768 | mutex_lock(&state->internal->tuner_lock); | ||
| 769 | } | ||
| 770 | 782 | ||
| 771 | reg = STV090x_READ_DEMOD(state, I2CRPT); | 783 | reg = STV090x_READ_DEMOD(state, I2CRPT); |
| 772 | if (enable) { | 784 | if (enable) { |
| @@ -782,20 +794,13 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable) · 9 unmodified lines | |||
| 782 | goto err; | 794 | goto err; |
| 783 | } | 795 | } |
| 784 | 796 | ||
| 785 | if (!enable) { | 797 | if (!enable) |
| 786 | if (state->config->tuner_i2c_lock) | 798 | stv090x_tuner_i2c_unlock(state); |
| 787 | state->config->tuner_i2c_lock(&state->frontend, 0); | ||
| 788 | else | ||
| 789 | mutex_unlock(&state->internal->tuner_lock); | ||
| 790 | } | ||
| 791 | 799 | ||
| 792 | return 0; | 800 | return 0; |
| 793 | err: | 801 | err: |
| 794 | dprintk(FE_ERROR, 1, "I/O error"); | 802 | dprintk(FE_ERROR, 1, "I/O error"); |
| 795 | if (state->config->tuner_i2c_lock) | 803 | stv090x_tuner_i2c_unlock(state); |
| 796 | state->config->tuner_i2c_lock(&state->frontend, 0); | ||
| 797 | else | ||
| 798 | mutex_unlock(&state->internal->tuner_lock); | ||
| 799 | return -1; | 804 | return -1; |
| 800 | } | 805 | } |
| 801 | 806 | ||
| @@ -119,11 +119,6 @@ struct stv { · 118 unmodified lines | |||
| 119 | u8 vth[6]; | 119 | u8 vth[6]; |
| 120 | }; | 120 | }; |
| 121 | 121 | ||
| 122 | struct sinit_table { | ||
| 123 | u16 address; | ||
| 124 | u8 data; | ||
| 125 | }; | ||
| 126 | |||
| 127 | struct slookup { | 122 | struct slookup { |
| 128 | s16 value; | 123 | s16 value; |
| 129 | u32 reg_value; | 124 | u32 reg_value; |
| @@ -70,6 +70,26 @@ config VIDEO_GC0308 · 69 unmodified lines | |||
| 70 | To compile this driver as a module, choose M here: the | 70 | To compile this driver as a module, choose M here: the |
| 71 | module will be called gc0308. | 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 | config VIDEO_GC2145 | 93 | config VIDEO_GC2145 |
| 74 | select V4L2_CCI_I2C | 94 | select V4L2_CCI_I2C |
| 75 | tristate "GalaxyCore GC2145 sensor support" | 95 | tristate "GalaxyCore GC2145 sensor support" |
| @@ -139,6 +159,7 @@ config VIDEO_IMX219 · 63 unmodified lines | |||
| 139 | 159 | ||
| 140 | config VIDEO_IMX258 | 160 | config VIDEO_IMX258 |
| 141 | tristate "Sony IMX258 sensor support" | 161 | tristate "Sony IMX258 sensor support" |
| 162 | select V4L2_CCI_I2C | ||
| 142 | help | 163 | help |
| 143 | This is a Video4Linux2 sensor driver for the Sony | 164 | This is a Video4Linux2 sensor driver for the Sony |
| 144 | IMX258 camera. | 165 | IMX258 camera. |
| @@ -153,6 +174,16 @@ config VIDEO_IMX274 · 8 unmodified lines | |||
| 153 | This is a V4L2 sensor driver for the Sony IMX274 | 174 | This is a V4L2 sensor driver for the Sony IMX274 |
| 154 | CMOS image sensor. | 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 | config VIDEO_IMX290 | 187 | config VIDEO_IMX290 |
| 157 | tristate "Sony IMX290 sensor support" | 188 | tristate "Sony IMX290 sensor support" |
| 158 | select REGMAP_I2C | 189 | select REGMAP_I2C |
| @@ -659,7 +690,7 @@ config VIDEO_S5K6A3 · 500 unmodified lines | |||
| 659 | This is a V4L2 sensor driver for Samsung S5K6A3 raw | 690 | This is a V4L2 sensor driver for Samsung S5K6A3 raw |
| 660 | camera sensor. | 691 | camera sensor. |
| 661 | 692 | ||
| 662 | config VIDEO_ST_VGXY61 | 693 | config VIDEO_VGXY61 |
| 663 | tristate "ST VGXY61 sensor support" | 694 | tristate "ST VGXY61 sensor support" |
| 664 | select V4L2_CCI_I2C | 695 | select V4L2_CCI_I2C |
| 665 | depends on OF && GPIOLIB | 696 | depends on OF && GPIOLIB |
| @@ -679,6 +710,7 @@ config VIDEO_THP7312 · 13 unmodified lines | |||
| 679 | tristate "THine THP7312 support" | 710 | tristate "THine THP7312 support" |
| 680 | depends on I2C | 711 | depends on I2C |
| 681 | select FW_LOADER | 712 | select FW_LOADER |
| 713 | select FW_UPLOAD | ||
| 682 | select MEDIA_CONTROLLER | 714 | select MEDIA_CONTROLLER |
| 683 | select V4L2_CCI_I2C | 715 | select V4L2_CCI_I2C |
| 684 | select V4L2_FWNODE | 716 | select V4L2_FWNODE |
| @@ -1575,6 +1607,40 @@ config VIDEO_DS90UB960 · 890 unmodified lines | |||
| 1575 | Device driver for the Texas Instruments DS90UB960 | 1607 | Device driver for the Texas Instruments DS90UB960 |
| 1576 | FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer. | 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 | endmenu | 1644 | endmenu |
| 1579 | 1645 | ||
| 1580 | endif # VIDEO_DEV | 1646 | endif # VIDEO_DEV |
| @@ -38,6 +38,8 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o · 37 unmodified lines | |||
| 38 | obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o | 38 | obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o |
| 39 | obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ | 39 | obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/ |
| 40 | obj-$(CONFIG_VIDEO_GC0308) += gc0308.o | 40 | obj-$(CONFIG_VIDEO_GC0308) += gc0308.o |
| 41 | obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o | ||
| 42 | obj-$(CONFIG_VIDEO_GC08A3) += gc08a3.o | ||
| 41 | obj-$(CONFIG_VIDEO_GC2145) += gc2145.o | 43 | obj-$(CONFIG_VIDEO_GC2145) += gc2145.o |
| 42 | obj-$(CONFIG_VIDEO_HI556) += hi556.o | 44 | obj-$(CONFIG_VIDEO_HI556) += hi556.o |
| 43 | obj-$(CONFIG_VIDEO_HI846) += hi846.o | 45 | obj-$(CONFIG_VIDEO_HI846) += hi846.o |
| @@ -48,6 +50,7 @@ obj-$(CONFIG_VIDEO_IMX214) += imx214.o · 4 unmodified lines | |||
| 48 | obj-$(CONFIG_VIDEO_IMX219) += imx219.o | 50 | obj-$(CONFIG_VIDEO_IMX219) += imx219.o |
| 49 | obj-$(CONFIG_VIDEO_IMX258) += imx258.o | 51 | obj-$(CONFIG_VIDEO_IMX258) += imx258.o |
| 50 | obj-$(CONFIG_VIDEO_IMX274) += imx274.o | 52 | obj-$(CONFIG_VIDEO_IMX274) += imx274.o |
| 53 | obj-$(CONFIG_VIDEO_IMX283) += imx283.o | ||
| 51 | obj-$(CONFIG_VIDEO_IMX290) += imx290.o | 54 | obj-$(CONFIG_VIDEO_IMX290) += imx290.o |
| 52 | obj-$(CONFIG_VIDEO_IMX296) += imx296.o | 55 | obj-$(CONFIG_VIDEO_IMX296) += imx296.o |
| 53 | obj-$(CONFIG_VIDEO_IMX319) += imx319.o | 56 | obj-$(CONFIG_VIDEO_IMX319) += imx319.o |
| @@ -64,6 +67,8 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o · 10 unmodified lines | |||
| 64 | obj-$(CONFIG_VIDEO_M52790) += m52790.o | 67 | obj-$(CONFIG_VIDEO_M52790) += m52790.o |
| 65 | obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o | 68 | obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o |
| 66 | obj-$(CONFIG_VIDEO_MAX9286) += max9286.o | 69 | obj-$(CONFIG_VIDEO_MAX9286) += max9286.o |
| 70 | obj-$(CONFIG_VIDEO_MAX96714) += max96714.o | ||
| 71 | obj-$(CONFIG_VIDEO_MAX96717) += max96717.o | ||
| 67 | obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o | 72 | obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o |
| 68 | obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o | 73 | obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o |
| 69 | obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o | 74 | obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o |
| @@ -124,7 +129,6 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o · 54 unmodified lines | |||
| 124 | obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o | 129 | obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o |
| 125 | obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o | 130 | obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o |
| 126 | obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o | 131 | obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o |
| 127 | obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o | ||
| 128 | obj-$(CONFIG_VIDEO_TC358743) += tc358743.o | 132 | obj-$(CONFIG_VIDEO_TC358743) += tc358743.o |
| 129 | obj-$(CONFIG_VIDEO_TC358746) += tc358746.o | 133 | obj-$(CONFIG_VIDEO_TC358746) += tc358746.o |
| 130 | obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o | 134 | obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o |
| @@ -148,6 +152,7 @@ obj-$(CONFIG_VIDEO_TW9910) += tw9910.o · 17 unmodified lines | |||
| 148 | obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o | 152 | obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o |
| 149 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o | 153 | obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o |
| 150 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o | 154 | obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o |
| 155 | obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o | ||
| 151 | obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o | 156 | obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o |
| 152 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o | 157 | obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o |
| 153 | obj-$(CONFIG_VIDEO_WM8739) += wm8739.o | 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 | memset(fmt, 0, sizeof(*fmt)); | 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 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; | 118 | fmt->colorspace = V4L2_COLORSPACE_SMPTE170M; |
| 119 | fmt->field = V4L2_FIELD_ALTERNATE; | 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 | if (code->index != 0) | 337 | if (code->index != 0) |
| 338 | return -EINVAL; | 338 | return -EINVAL; |
| 339 | 339 | ||
| 340 | code->code = MEDIA_BUS_FMT_UYVY8_2X8; | 340 | code->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 341 | 341 | ||
| 342 | return 0; | 342 | return 0; |
| 343 | } | 343 | } |
| @@ -6,7 +6,6 @@ · 5 unmodified lines | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/mutex.h> | ||
| 10 | 9 | ||
| 11 | #include <media/v4l2-ctrls.h> | 10 | #include <media/v4l2-ctrls.h> |
| 12 | #include <media/v4l2-device.h> | 11 | #include <media/v4l2-device.h> |
| @@ -14,6 +13,15 @@ · 1 unmodified line | |||
| 14 | 13 | ||
| 15 | #include "adv748x.h" | 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 | int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc) | 25 | int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc) |
| 18 | { | 26 | { |
| 19 | return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT); | 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 | * v4l2_subdev_internal_ops | 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 | * We use the internal registered operation to be able to ensure that our | 97 | * We use the internal registered operation to be able to ensure that our |
| 64 | * incremental subdevices (not connected in the forward path) can be registered | 98 | * incremental subdevices (not connected in the forward path) can be registered |
| 65 | * against the resulting video path and media device. | 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 | static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = { | 145 | static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = { |
| 146 | .init_state = adv748x_csi2_init_state, | ||
| 112 | .registered = adv748x_csi2_registered, | 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 | * But we must support setting the pad formats for format propagation. | 174 | * But we must support setting the pad formats for format propagation. |
| 140 | */ | 175 | */ |
| 141 | 176 | ||
| 142 | static struct v4l2_mbus_framefmt * | 177 | static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd, |
| 143 | adv748x_csi2_get_pad_format(struct v4l2_subdev *sd, | 178 | struct v4l2_subdev_state *sd_state, |
| 144 | struct v4l2_subdev_state *sd_state, | 179 | struct v4l2_subdev_mbus_code_enum *code) |
| 145 | unsigned int pad, u32 which) | ||
| 146 | { | 180 | { |
| 147 | struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); | 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) | 188 | /* |
| 150 | return v4l2_subdev_state_get_format(sd_state, pad); | 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; | 195 | if (code->index) |
| 153 | } | 196 | return -EINVAL; |
| 154 | 197 | ||
| 155 | static int adv748x_csi2_get_format(struct v4l2_subdev *sd, | 198 | fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK); |
| 156 | struct v4l2_subdev_state *sd_state, | 199 | code->code = fmt->code; |
| 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; | ||
| 162 | 200 | ||
| 163 | mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad, | 201 | return 0; |
| 164 | sdformat->which); | 202 | } |
| 165 | if (!mbusformat) | 203 | |
| 204 | if (code->index >= num_fmts) | ||
| 166 | return -EINVAL; | 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 | static int adv748x_csi2_set_format(struct v4l2_subdev *sd, | 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 | struct v4l2_subdev_format *sdformat) | 230 | struct v4l2_subdev_format *sdformat) |
| 180 | { | 231 | { |
| 181 | struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); | 232 | struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd); |
| 182 | struct adv748x_state *state = tx->state; | ||
| 183 | struct v4l2_mbus_framefmt *mbusformat; | 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) { | 235 | if (sdformat->pad == ADV748X_CSI2_SOURCE) |
| 194 | const struct v4l2_mbus_framefmt *sink_fmt; | 236 | return v4l2_subdev_get_fmt(sd, sd_state, sdformat); |
| 195 | 237 | ||
| 196 | sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state, | 238 | /* |
| 197 | ADV748X_CSI2_SINK, | 239 | * Make sure the format is supported, if not default it to |
| 198 | sdformat->which); | 240 | * UYVY8 as it's supported by both TXes. |
| 199 | 241 | */ | |
| 200 | if (!sink_fmt) { | 242 | if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code)) |
| 201 | ret = -EINVAL; | 243 | sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 202 | goto unlock; | ||
| 203 | } | ||
| 204 | |||
| 205 | sdformat->format = *sink_fmt; | ||
| 206 | } | ||
| 207 | 244 | ||
| 245 | mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad); | ||
| 208 | *mbusformat = sdformat->format; | 246 | *mbusformat = sdformat->format; |
| 209 | 247 | ||
| 210 | unlock: | 248 | /* Propagate format to the source pad. */ |
| 211 | mutex_unlock(&state->mutex); | 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 | static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad, | 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 | static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = { | 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 | .set_fmt = adv748x_csi2_set_format, | 272 | .set_fmt = adv748x_csi2_set_format, |
| 233 | .get_mbus_config = adv748x_csi2_get_mbus_config, | 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 | if (ret) | 360 | if (ret) |
| 321 | goto err_cleanup_subdev; | 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 | ret = v4l2_async_register_subdev(&tx->sd); | 368 | ret = v4l2_async_register_subdev(&tx->sd); |
| 324 | if (ret) | 369 | if (ret) |
| 325 | goto err_free_ctrl; | 370 | goto err_free_ctrl; |
| @@ -75,7 +75,6 @@ enum adv748x_csi2_pads { · 74 unmodified lines | |||
| 75 | 75 | ||
| 76 | struct adv748x_csi2 { | 76 | struct adv748x_csi2 { |
| 77 | struct adv748x_state *state; | 77 | struct adv748x_state *state; |
| 78 | struct v4l2_mbus_framefmt format; | ||
| 79 | unsigned int page; | 78 | unsigned int page; |
| 80 | unsigned int port; | 79 | unsigned int port; |
| 81 | unsigned int num_lanes; | 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 | struct adv7511_state_edid { | 65 | struct adv7511_state_edid { |
| 71 | /* total number of blocks */ | 66 | /* total number of blocks */ |
| 72 | u32 blocks; | 67 | u32 blocks; |
| @@ -403,21 +403,22 @@ static int alvium_get_bcrm_vers(struct alvium_dev *alvium) · 402 unmodified lines | |||
| 403 | static int alvium_get_fw_version(struct alvium_dev *alvium) | 403 | static int alvium_get_fw_version(struct alvium_dev *alvium) |
| 404 | { | 404 | { |
| 405 | struct device *dev = &alvium->i2c_client->dev; | 405 | struct device *dev = &alvium->i2c_client->dev; |
| 406 | u64 spec, maj, min, pat; | 406 | u64 val; |
| 407 | int ret = 0; | 407 | int ret; |
| 408 | 408 | ||
| 409 | ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_SPEC_VERSION_R, | 409 | ret = alvium_read(alvium, REG_BCRM_DEVICE_FW, &val, NULL); |
| 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); | ||
| 417 | if (ret) | 410 | if (ret) |
| 418 | return ret; | 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 | return 0; | 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 | struct device *dev = &alvium->i2c_client->dev; | 1189 | struct device *dev = &alvium->i2c_client->dev; |
| 1189 | int ret; | 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 | ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW, | 1206 | ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW, |
| 1192 | fr); | 1207 | fr); |
| 1193 | if (ret) { | 1208 | if (ret) { |
| @@ -1707,6 +1722,27 @@ alvium_code_to_pixfmt(struct alvium_dev *alvium, u32 code) · 513 unmodified lines | |||
| 1707 | return &alvium->alvium_csi2_fmt[0]; | 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 | static int alvium_set_mode(struct alvium_dev *alvium, | 1746 | static int alvium_set_mode(struct alvium_dev *alvium, |
| 1711 | struct v4l2_subdev_state *state) | 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 | int val; | 1998 | int val; |
| 1963 | 1999 | ||
| 1964 | switch (ctrl->id) { | 2000 | switch (ctrl->id) { |
| 1965 | case V4L2_CID_GAIN: | 2001 | case V4L2_CID_ANALOGUE_GAIN: |
| 1966 | val = alvium_get_gain(alvium); | 2002 | val = alvium_get_gain(alvium); |
| 1967 | if (val < 0) | 2003 | if (val < 0) |
| 1968 | return val; | 2004 | return val; |
| @@ -1994,7 +2030,7 @@ static int alvium_s_ctrl(struct v4l2_ctrl *ctrl) · 25 unmodified lines | |||
| 1994 | return 0; | 2030 | return 0; |
| 1995 | 2031 | ||
| 1996 | switch (ctrl->id) { | 2032 | switch (ctrl->id) { |
| 1997 | case V4L2_CID_GAIN: | 2033 | case V4L2_CID_ANALOGUE_GAIN: |
| 1998 | ret = alvium_set_ctrl_gain(alvium, ctrl->val); | 2034 | ret = alvium_set_ctrl_gain(alvium, ctrl->val); |
| 1999 | break; | 2035 | break; |
| 2000 | case V4L2_CID_AUTOGAIN: | 2036 | case V4L2_CID_AUTOGAIN: |
| @@ -2123,7 +2159,7 @@ static int alvium_ctrl_init(struct alvium_dev *alvium) · 122 unmodified lines | |||
| 2123 | 2159 | ||
| 2124 | if (alvium->avail_ft.gain) { | 2160 | if (alvium->avail_ft.gain) { |
| 2125 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, | 2161 | ctrls->gain = v4l2_ctrl_new_std(hdl, ops, |
| 2126 | V4L2_CID_GAIN, | 2162 | V4L2_CID_ANALOGUE_GAIN, |
| 2127 | alvium->min_gain, | 2163 | alvium->min_gain, |
| 2128 | alvium->max_gain, | 2164 | alvium->max_gain, |
| 2129 | alvium->inc_gain, | 2165 | alvium->inc_gain, |
| @@ -2214,6 +2250,7 @@ static const struct v4l2_subdev_video_ops alvium_video_ops = { · 84 unmodified lines | |||
| 2214 | 2250 | ||
| 2215 | static const struct v4l2_subdev_pad_ops alvium_pad_ops = { | 2251 | static const struct v4l2_subdev_pad_ops alvium_pad_ops = { |
| 2216 | .enum_mbus_code = alvium_enum_mbus_code, | 2252 | .enum_mbus_code = alvium_enum_mbus_code, |
| 2253 | .enum_frame_size = alvium_enum_frame_size, | ||
| 2217 | .get_fmt = v4l2_subdev_get_fmt, | 2254 | .get_fmt = v4l2_subdev_get_fmt, |
| 2218 | .set_fmt = alvium_set_fmt, | 2255 | .set_fmt = alvium_set_fmt, |
| 2219 | .get_selection = alvium_get_selection, | 2256 | .get_selection = alvium_get_selection, |
| @@ -31,10 +31,7 @@ · 30 unmodified lines | |||
| 31 | #define REG_BCRM_REG_ADDR_R CCI_REG16(0x0014) | 31 | #define REG_BCRM_REG_ADDR_R CCI_REG16(0x0014) |
| 32 | 32 | ||
| 33 | #define REG_BCRM_FEATURE_INQUIRY_R REG_BCRM_V4L2_64BIT(0x0008) | 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) | 34 | #define REG_BCRM_DEVICE_FW REG_BCRM_V4L2_64BIT(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) | ||
| 38 | #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0018) | 35 | #define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0018) |
| 39 | 36 | ||
| 40 | /* Streaming Control Registers */ | 37 | /* Streaming Control Registers */ |
| @@ -66,7 +63,7 @@ · 25 unmodified lines | |||
| 66 | #define REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R REG_BCRM_V4L2_64BIT(0x0098) | 63 | #define REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R REG_BCRM_V4L2_64BIT(0x0098) |
| 67 | #define REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R REG_BCRM_V4L2_64BIT(0x00a0) | 64 | #define REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R REG_BCRM_V4L2_64BIT(0x00a0) |
| 68 | #define REG_BCRM_ACQUISITION_FRAME_RATE_INC_R REG_BCRM_V4L2_64BIT(0x00a8) | 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 | #define REG_BCRM_FRAME_START_TRIGGER_MODE_RW REG_BCRM_V4L2_8BIT(0x00b4) | 68 | #define REG_BCRM_FRAME_START_TRIGGER_MODE_RW REG_BCRM_V4L2_8BIT(0x00b4) |
| 72 | #define REG_BCRM_FRAME_START_TRIGGER_SOURCE_RW REG_BCRM_V4L2_8BIT(0x00b8) | 69 | #define REG_BCRM_FRAME_START_TRIGGER_SOURCE_RW REG_BCRM_V4L2_8BIT(0x00b8) |
| @@ -205,6 +202,15 @@ · 132 unmodified lines | |||
| 205 | 202 | ||
| 206 | #define ALVIUM_LP2HS_DELAY_MS 100 | 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 | enum alvium_bcrm_mode { | 214 | enum alvium_bcrm_mode { |
| 209 | ALVIUM_BCM_MODE, | 215 | ALVIUM_BCM_MODE, |
| 210 | ALVIUM_GENCP_MODE, | 216 | ALVIUM_GENCP_MODE, |
| @@ -115,11 +115,6 @@ static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev) · 114 unmodified lines | |||
| 115 | return container_of(subdev, struct dw9768, sd); | 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 | struct dw9768_aac_mode_ot_multi { | 118 | struct dw9768_aac_mode_ot_multi { |
| 124 | u32 aac_mode_enum; | 119 | u32 aac_mode_enum; |
| 125 | u32 ot_multi_base100; | 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 | #define GC2145_DPHY_CLK_DELAY BIT(4) | 68 | #define GC2145_DPHY_CLK_DELAY BIT(4) |
| 69 | #define GC2145_DPHY_LANE0_DELAY BIT(5) | 69 | #define GC2145_DPHY_LANE0_DELAY BIT(5) |
| 70 | #define GC2145_DPHY_LANE1_DELAY BIT(6) | 70 | #define GC2145_DPHY_LANE1_DELAY BIT(6) |
| 71 | #define GC2145_REG_FIFO_FULL_LVL_LOW CCI_REG8(0x04) | 71 | #define GC2145_REG_FIFO_FULL_LVL CCI_REG16_LE(0x04) |
| 72 | #define GC2145_REG_FIFO_FULL_LVL_HIGH CCI_REG8(0x05) | ||
| 73 | #define GC2145_REG_FIFO_MODE CCI_REG8(0x06) | 72 | #define GC2145_REG_FIFO_MODE CCI_REG8(0x06) |
| 74 | #define GC2145_FIFO_MODE_READ_GATE BIT(3) | 73 | #define GC2145_FIFO_MODE_READ_GATE BIT(3) |
| 75 | #define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7) | 74 | #define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7) |
| @@ -79,8 +78,7 @@ · 3 unmodified lines | |||
| 79 | #define GC2145_CSI2_MODE_MIPI_EN BIT(4) | 78 | #define GC2145_CSI2_MODE_MIPI_EN BIT(4) |
| 80 | #define GC2145_CSI2_MODE_EN BIT(7) | 79 | #define GC2145_CSI2_MODE_EN BIT(7) |
| 81 | #define GC2145_REG_MIPI_DT CCI_REG8(0x11) | 80 | #define GC2145_REG_MIPI_DT CCI_REG8(0x11) |
| 82 | #define GC2145_REG_LWC_LOW CCI_REG8(0x12) | 81 | #define GC2145_REG_LWC CCI_REG16_LE(0x12) |
| 83 | #define GC2145_REG_LWC_HIGH CCI_REG8(0x13) | ||
| 84 | #define GC2145_REG_DPHY_MODE CCI_REG8(0x15) | 82 | #define GC2145_REG_DPHY_MODE CCI_REG8(0x15) |
| 85 | #define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4) | 83 | #define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4) |
| 86 | #define GC2145_REG_FIFO_GATE_MODE CCI_REG8(0x17) | 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 | * struct gc2145_format - GC2145 pixel format description | 541 | * struct gc2145_format - GC2145 pixel format description |
| 544 | * @code: media bus (MBUS) associated code | 542 | * @code: media bus (MBUS) associated code |
| 543 | * @colorspace: V4L2 colorspace | ||
| 545 | * @datatype: MIPI CSI2 data type | 544 | * @datatype: MIPI CSI2 data type |
| 546 | * @output_fmt: GC2145 output format | 545 | * @output_fmt: GC2145 output format |
| 547 | * @switch_bit: GC2145 first/second switch | 546 | * @switch_bit: GC2145 first/second switch |
| 547 | * @row_col_switch: GC2145 switch row and/or column | ||
| 548 | */ | 548 | */ |
| 549 | struct gc2145_format { | 549 | struct gc2145_format { |
| 550 | unsigned int code; | 550 | unsigned int code; |
| 551 | unsigned int colorspace; | ||
| 551 | unsigned char datatype; | 552 | unsigned char datatype; |
| 552 | unsigned char output_fmt; | 553 | unsigned char output_fmt; |
| 553 | bool switch_bit; | 554 | bool switch_bit; |
| 555 | unsigned char row_col_switch; | ||
| 554 | }; | 556 | }; |
| 555 | 557 | ||
| 556 | /* All supported formats */ | 558 | /* All supported formats */ |
| 557 | static const struct gc2145_format supported_formats[] = { | 559 | static const struct gc2145_format supported_formats[] = { |
| 558 | { | 560 | { |
| 559 | .code = MEDIA_BUS_FMT_UYVY8_1X16, | 561 | .code = MEDIA_BUS_FMT_UYVY8_1X16, |
| 562 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
| 560 | .datatype = MIPI_CSI2_DT_YUV422_8B, | 563 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 561 | .output_fmt = 0x00, | 564 | .output_fmt = 0x00, |
| 562 | }, | 565 | }, |
| 563 | { | 566 | { |
| 564 | .code = MEDIA_BUS_FMT_VYUY8_1X16, | 567 | .code = MEDIA_BUS_FMT_VYUY8_1X16, |
| 568 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
| 565 | .datatype = MIPI_CSI2_DT_YUV422_8B, | 569 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 566 | .output_fmt = 0x01, | 570 | .output_fmt = 0x01, |
| 567 | }, | 571 | }, |
| 568 | { | 572 | { |
| 569 | .code = MEDIA_BUS_FMT_YUYV8_1X16, | 573 | .code = MEDIA_BUS_FMT_YUYV8_1X16, |
| 574 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
| 570 | .datatype = MIPI_CSI2_DT_YUV422_8B, | 575 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 571 | .output_fmt = 0x02, | 576 | .output_fmt = 0x02, |
| 572 | }, | 577 | }, |
| 573 | { | 578 | { |
| 574 | .code = MEDIA_BUS_FMT_YVYU8_1X16, | 579 | .code = MEDIA_BUS_FMT_YVYU8_1X16, |
| 580 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
| 575 | .datatype = MIPI_CSI2_DT_YUV422_8B, | 581 | .datatype = MIPI_CSI2_DT_YUV422_8B, |
| 576 | .output_fmt = 0x03, | 582 | .output_fmt = 0x03, |
| 577 | }, | 583 | }, |
| 578 | { | 584 | { |
| 579 | .code = MEDIA_BUS_FMT_RGB565_1X16, | 585 | .code = MEDIA_BUS_FMT_RGB565_1X16, |
| 586 | .colorspace = V4L2_COLORSPACE_SRGB, | ||
| 580 | .datatype = MIPI_CSI2_DT_RGB565, | 587 | .datatype = MIPI_CSI2_DT_RGB565, |
| 581 | .output_fmt = 0x06, | 588 | .output_fmt = 0x06, |
| 582 | .switch_bit = true, | 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 | struct gc2145_ctrls { | 621 | struct gc2145_ctrls { |
| @@ -641,7 +676,8 @@ gc2145_get_format_code(struct gc2145 *gc2145, u32 code) · 54 unmodified lines | |||
| 641 | 676 | ||
| 642 | static void gc2145_update_pad_format(struct gc2145 *gc2145, | 677 | static void gc2145_update_pad_format(struct gc2145 *gc2145, |
| 643 | const struct gc2145_mode *mode, | 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 | fmt->code = code; | 682 | fmt->code = code; |
| 647 | fmt->width = mode->width; | 683 | fmt->width = mode->width; |
| @@ -663,7 +699,8 @@ static int gc2145_init_state(struct v4l2_subdev *sd, · 15 unmodified lines | |||
| 663 | /* Initialize pad format */ | 699 | /* Initialize pad format */ |
| 664 | format = v4l2_subdev_state_get_format(state, 0); | 700 | format = v4l2_subdev_state_get_format(state, 0); |
| 665 | gc2145_update_pad_format(gc2145, &supported_modes[0], format, | 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 | /* Initialize crop rectangle. */ | 705 | /* Initialize crop rectangle. */ |
| 669 | crop = v4l2_subdev_state_get_crop(state, 0); | 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 | width, height, | 791 | width, height, |
| 755 | fmt->format.width, fmt->format.height); | 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 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); | 801 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
| 759 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { | 802 | if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) { |
| 760 | gc2145->mode = mode; | 803 | gc2145->mode = mode; |
| @@ -811,9 +854,12 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145, · 50 unmodified lines | |||
| 811 | * For RAW8, LWC = image width | 854 | * For RAW8, LWC = image width |
| 812 | * For RAW10, LWC = image width * 1.25 | 855 | * For RAW10, LWC = image width * 1.25 |
| 813 | */ | 856 | */ |
| 814 | lwc = gc2145->mode->width * 2; | 857 | if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW) |
| 815 | cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret); | 858 | lwc = gc2145->mode->width * 2; |
| 816 | cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret); | 859 | else |
| 860 | lwc = gc2145->mode->width; | ||
| 861 | |||
| 862 | cci_write(gc2145->regmap, GC2145_REG_LWC, lwc, &ret); | ||
| 817 | 863 | ||
| 818 | /* | 864 | /* |
| 819 | * Adjust the MIPI FIFO Full Level | 865 | * Adjust the MIPI FIFO Full Level |
| @@ -821,21 +867,25 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145, · 1 unmodified line | |||
| 821 | * 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001 | 867 | * 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001 |
| 822 | * 1600x1200 RAW: 0x0190 | 868 | * 1600x1200 RAW: 0x0190 |
| 823 | */ | 869 | */ |
| 824 | if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600) | 870 | if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW) { |
| 825 | fifo_full_lvl = 0x0001; | 871 | if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600) |
| 826 | else | 872 | fifo_full_lvl = 0x0001; |
| 873 | else | ||
| 874 | fifo_full_lvl = 0x0190; | ||
| 875 | } else { | ||
| 827 | fifo_full_lvl = 0x0190; | 876 | fifo_full_lvl = 0x0190; |
| 877 | } | ||
| 828 | 878 | ||
| 829 | cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH, | 879 | cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL, |
| 830 | fifo_full_lvl >> 8, &ret); | 880 | fifo_full_lvl, &ret); |
| 831 | cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW, | ||
| 832 | fifo_full_lvl & 0xff, &ret); | ||
| 833 | 881 | ||
| 834 | /* | 882 | /* |
| 835 | * Set the FIFO gate mode / MIPI wdiv set: | 883 | * Set the FIFO gate mode / MIPI wdiv set: |
| 836 | * 0xf1 in case of RAW mode and 0xf0 otherwise | 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 | /* Set the MIPI data type */ | 890 | /* Set the MIPI data type */ |
| 841 | cci_write(gc2145->regmap, GC2145_REG_MIPI_DT, | 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 | GC2145_BYPASS_MODE_SWITCH, | 933 | GC2145_BYPASS_MODE_SWITCH, |
| 884 | gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH | 934 | gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH |
| 885 | : 0, &ret); | 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 | if (ret) { | 940 | if (ret) { |
| 887 | dev_err(&client->dev, "%s failed to write regs\n", __func__); | 941 | dev_err(&client->dev, "%s failed to write regs\n", __func__); |
| 888 | goto err_rpm_put; | 942 | goto err_rpm_put; |
| @@ -1851,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd, · 1850 unmodified lines | |||
| 1851 | mutex_lock(&hi846->mutex); | 1851 | mutex_lock(&hi846->mutex); |
| 1852 | switch (sel->which) { | 1852 | switch (sel->which) { |
| 1853 | case V4L2_SUBDEV_FORMAT_TRY: | 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 | break; | 1855 | break; |
| 1856 | case V4L2_SUBDEV_FORMAT_ACTIVE: | 1856 | case V4L2_SUBDEV_FORMAT_ACTIVE: |
| 1857 | sel->r = hi846->cur_mode->crop; | 1857 | sel->r = hi846->cur_mode->crop; |
| @@ -162,8 +162,8 @@ static const struct cci_reg_sequence imx219_common_regs[] = { · 161 unmodified lines | |||
| 162 | { IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */ | 162 | { IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */ |
| 163 | 163 | ||
| 164 | /* To Access Addresses 3000-5fff, send the following commands */ | 164 | /* To Access Addresses 3000-5fff, send the following commands */ |
| 165 | { CCI_REG8(0x30eb), 0x0c }, | ||
| 166 | { CCI_REG8(0x30eb), 0x05 }, | 165 | { CCI_REG8(0x30eb), 0x05 }, |
| 166 | { CCI_REG8(0x30eb), 0x0c }, | ||
| 167 | { CCI_REG8(0x300a), 0xff }, | 167 | { CCI_REG8(0x300a), 0xff }, |
| 168 | { CCI_REG8(0x300b), 0xff }, | 168 | { CCI_REG8(0x300b), 0xff }, |
| 169 | { CCI_REG8(0x30eb), 0x05 }, | 169 | { CCI_REG8(0x30eb), 0x05 }, |
| @@ -7,97 +7,150 @@ · 6 unmodified lines | |||
| 7 | #include <linux/i2c.h> | 7 | #include <linux/i2c.h> |
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/pm_runtime.h> | 9 | #include <linux/pm_runtime.h> |
| 10 | #include <linux/regulator/consumer.h> | ||
| 11 | #include <media/v4l2-cci.h> | ||
| 10 | #include <media/v4l2-ctrls.h> | 12 | #include <media/v4l2-ctrls.h> |
| 11 | #include <media/v4l2-device.h> | 13 | #include <media/v4l2-device.h> |
| 12 | #include <media/v4l2-fwnode.h> | 14 | #include <media/v4l2-fwnode.h> |
| 13 | #include <asm/unaligned.h> | 15 | #include <asm/unaligned.h> |
| 14 | 16 | ||
| 15 | #define IMX258_REG_VALUE_08BIT 1 | 17 | #define IMX258_REG_MODE_SELECT CCI_REG8(0x0100) |
| 16 | #define IMX258_REG_VALUE_16BIT 2 | ||
| 17 | |||
| 18 | #define IMX258_REG_MODE_SELECT 0x0100 | ||
| 19 | #define IMX258_MODE_STANDBY 0x00 | 18 | #define IMX258_MODE_STANDBY 0x00 |
| 20 | #define IMX258_MODE_STREAMING 0x01 | 19 | #define IMX258_MODE_STREAMING 0x01 |
| 21 | 20 | ||
| 21 | #define IMX258_REG_RESET CCI_REG8(0x0103) | ||
| 22 | |||
| 22 | /* Chip ID */ | 23 | /* Chip ID */ |
| 23 | #define IMX258_REG_CHIP_ID 0x0016 | 24 | #define IMX258_REG_CHIP_ID CCI_REG16(0x0016) |
| 24 | #define IMX258_CHIP_ID 0x0258 | 25 | #define IMX258_CHIP_ID 0x0258 |
| 25 | 26 | ||
| 26 | /* V_TIMING internal */ | 27 | /* V_TIMING internal */ |
| 27 | #define IMX258_VTS_30FPS 0x0c50 | 28 | #define IMX258_VTS_30FPS 0x0c50 |
| 28 | #define IMX258_VTS_30FPS_2K 0x0638 | 29 | #define IMX258_VTS_30FPS_2K 0x0638 |
| 29 | #define IMX258_VTS_30FPS_VGA 0x034c | 30 | #define IMX258_VTS_30FPS_VGA 0x034c |
| 30 | #define IMX258_VTS_MAX 0xffff | 31 | #define IMX258_VTS_MAX 65525 |
| 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 | ||
| 37 | 32 | ||
| 38 | /* HBLANK control - read only */ | 33 | /* HBLANK control - read only */ |
| 39 | #define IMX258_PPL_DEFAULT 5352 | 34 | #define IMX258_PPL_DEFAULT 5352 |
| 40 | 35 | ||
| 41 | /* Exposure control */ | 36 | /* Exposure control */ |
| 42 | #define IMX258_REG_EXPOSURE 0x0202 | 37 | #define IMX258_REG_EXPOSURE CCI_REG16(0x0202) |
| 38 | #define IMX258_EXPOSURE_OFFSET 10 | ||
| 43 | #define IMX258_EXPOSURE_MIN 4 | 39 | #define IMX258_EXPOSURE_MIN 4 |
| 44 | #define IMX258_EXPOSURE_STEP 1 | 40 | #define IMX258_EXPOSURE_STEP 1 |
| 45 | #define IMX258_EXPOSURE_DEFAULT 0x640 | 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 | /* Analog gain control */ | 44 | /* Analog gain control */ |
| 49 | #define IMX258_REG_ANALOG_GAIN 0x0204 | 45 | #define IMX258_REG_ANALOG_GAIN CCI_REG16(0x0204) |
| 50 | #define IMX258_ANA_GAIN_MIN 0 | 46 | #define IMX258_ANA_GAIN_MIN 0 |
| 51 | #define IMX258_ANA_GAIN_MAX 480 | 47 | #define IMX258_ANA_GAIN_MAX 480 |
| 52 | #define IMX258_ANA_GAIN_STEP 1 | 48 | #define IMX258_ANA_GAIN_STEP 1 |
| 53 | #define IMX258_ANA_GAIN_DEFAULT 0x0 | 49 | #define IMX258_ANA_GAIN_DEFAULT 0x0 |
| 54 | 50 | ||
| 55 | /* Digital gain control */ | 51 | /* Digital gain control */ |
| 56 | #define IMX258_REG_GR_DIGITAL_GAIN 0x020e | 52 | #define IMX258_REG_GR_DIGITAL_GAIN CCI_REG16(0x020e) |
| 57 | #define IMX258_REG_R_DIGITAL_GAIN 0x0210 | 53 | #define IMX258_REG_R_DIGITAL_GAIN CCI_REG16(0x0210) |
| 58 | #define IMX258_REG_B_DIGITAL_GAIN 0x0212 | 54 | #define IMX258_REG_B_DIGITAL_GAIN CCI_REG16(0x0212) |
| 59 | #define IMX258_REG_GB_DIGITAL_GAIN 0x0214 | 55 | #define IMX258_REG_GB_DIGITAL_GAIN CCI_REG16(0x0214) |
| 60 | #define IMX258_DGTL_GAIN_MIN 0 | 56 | #define IMX258_DGTL_GAIN_MIN 0 |
| 61 | #define IMX258_DGTL_GAIN_MAX 4096 /* Max = 0xFFF */ | 57 | #define IMX258_DGTL_GAIN_MAX 4096 /* Max = 0xFFF */ |
| 62 | #define IMX258_DGTL_GAIN_DEFAULT 1024 | 58 | #define IMX258_DGTL_GAIN_DEFAULT 1024 |
| 63 | #define IMX258_DGTL_GAIN_STEP 1 | 59 | #define IMX258_DGTL_GAIN_STEP 1 |
| 64 | 60 | ||
| 65 | /* HDR control */ | 61 | /* HDR control */ |
| 66 | #define IMX258_REG_HDR 0x0220 | 62 | #define IMX258_REG_HDR CCI_REG8(0x0220) |
| 67 | #define IMX258_HDR_ON BIT(0) | 63 | #define IMX258_HDR_ON BIT(0) |
| 68 | #define IMX258_REG_HDR_RATIO 0x0222 | 64 | #define IMX258_REG_HDR_RATIO CCI_REG8(0x0222) |
| 69 | #define IMX258_HDR_RATIO_MIN 0 | 65 | #define IMX258_HDR_RATIO_MIN 0 |
| 70 | #define IMX258_HDR_RATIO_MAX 5 | 66 | #define IMX258_HDR_RATIO_MAX 5 |
| 71 | #define IMX258_HDR_RATIO_STEP 1 | 67 | #define IMX258_HDR_RATIO_STEP 1 |
| 72 | #define IMX258_HDR_RATIO_DEFAULT 0x0 | 68 | #define IMX258_HDR_RATIO_DEFAULT 0x0 |
| 73 | 69 | ||
| 74 | /* Test Pattern Control */ | 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 | /* Orientation */ | 75 | /* Orientation */ |
| 78 | #define REG_MIRROR_FLIP_CONTROL 0x0101 | 76 | #define REG_MIRROR_FLIP_CONTROL CCI_REG8(0x0101) |
| 79 | #define REG_CONFIG_MIRROR_FLIP 0x03 | 77 | #define REG_CONFIG_MIRROR_HFLIP 0x01 |
| 80 | #define REG_CONFIG_FLIP_TEST_PATTERN 0x02 | 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 */ | 132 | struct imx258_reg_list { |
| 83 | #define IMX258_INPUT_CLOCK_FREQ 19200000 | 133 | u32 num_of_regs; |
| 134 | const struct cci_reg_sequence *regs; | ||
| 135 | }; | ||
| 84 | 136 | ||
| 85 | struct imx258_reg { | 137 | struct imx258_link_cfg { |
| 86 | u16 address; | 138 | unsigned int lf_to_pix_rate_factor; |
| 87 | u8 val; | 139 | struct imx258_reg_list reg_list; |
| 88 | }; | 140 | }; |
| 89 | 141 | ||
| 90 | struct imx258_reg_list { | 142 | enum { |
| 91 | u32 num_of_regs; | 143 | IMX258_2_LANE_MODE, |
| 92 | const struct imx258_reg *regs; | 144 | IMX258_4_LANE_MODE, |
| 145 | IMX258_LANE_CONFIGS, | ||
| 93 | }; | 146 | }; |
| 94 | 147 | ||
| 95 | /* Link frequency config */ | 148 | /* Link frequency config */ |
| 96 | struct imx258_link_freq_config { | 149 | struct imx258_link_freq_config { |
| 97 | u32 pixels_per_line; | 150 | u32 pixels_per_line; |
| 98 | 151 | ||
| 99 | /* PLL registers for this link frequency */ | 152 | /* Configuration for this link frequency / num lanes selection */ |
| 100 | struct imx258_reg_list reg_list; | 153 | struct imx258_link_cfg link_cfg[IMX258_LANE_CONFIGS]; |
| 101 | }; | 154 | }; |
| 102 | 155 | ||
| 103 | /* Mode : resolution and related config&values */ | 156 | /* Mode : resolution and related config&values */ |
| @@ -115,400 +168,307 @@ struct imx258_mode { · 11 unmodified lines | |||
| 115 | u32 link_freq_index; | 168 | u32 link_freq_index; |
| 116 | /* Default register values */ | 169 | /* Default register values */ |
| 117 | struct imx258_reg_list reg_list; | 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 */ | 283 | static const struct cci_reg_sequence mipi_642mbps_24mhz_2l[] = { |
| 121 | static const struct imx258_reg mipi_data_rate_1267mbps[] = { | 284 | { IMX258_REG_EXCK_FREQ, 0x1800 }, |
| 122 | { 0x0301, 0x05 }, | 285 | { IMX258_REG_IVTPXCK_DIV, 5 }, |
| 123 | { 0x0303, 0x02 }, | 286 | { IMX258_REG_IVTSYCK_DIV, 2 }, |
| 124 | { 0x0305, 0x03 }, | 287 | { IMX258_REG_PREPLLCK_VT_DIV, 4 }, |
| 125 | { 0x0306, 0x00 }, | 288 | { IMX258_REG_PLL_IVT_MPY, 107 }, |
| 126 | { 0x0307, 0xC6 }, | 289 | { IMX258_REG_IOPPXCK_DIV, 10 }, |
| 127 | { 0x0309, 0x0A }, | 290 | { IMX258_REG_IOPSYCK_DIV, 1 }, |
| 128 | { 0x030B, 0x01 }, | 291 | { IMX258_REG_PREPLLCK_OP_DIV, 2 }, |
| 129 | { 0x030D, 0x02 }, | 292 | { IMX258_REG_PLL_IOP_MPY, 216 }, |
| 130 | { 0x030E, 0x00 }, | 293 | { IMX258_REG_PLL_MULT_DRIV, 0 }, |
| 131 | { 0x030F, 0xD8 }, | 294 | |
| 132 | { 0x0310, 0x00 }, | 295 | { IMX258_REG_CSI_LANE_MODE, 1 }, |
| 133 | { 0x0820, 0x13 }, | 296 | { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 642 * 2 }, |
| 134 | { 0x0821, 0x4C }, | 297 | { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, |
| 135 | { 0x0822, 0xCC }, | ||
| 136 | { 0x0823, 0xCC }, | ||
| 137 | }; | 298 | }; |
| 138 | 299 | ||
| 139 | static const struct imx258_reg mipi_data_rate_640mbps[] = { | 300 | static const struct cci_reg_sequence mipi_642mbps_24mhz_4l[] = { |
| 140 | { 0x0301, 0x05 }, | 301 | { IMX258_REG_EXCK_FREQ, 0x1800 }, |
| 141 | { 0x0303, 0x02 }, | 302 | { IMX258_REG_IVTPXCK_DIV, 5 }, |
| 142 | { 0x0305, 0x03 }, | 303 | { IMX258_REG_IVTSYCK_DIV, 2 }, |
| 143 | { 0x0306, 0x00 }, | 304 | { IMX258_REG_PREPLLCK_VT_DIV, 4 }, |
| 144 | { 0x0307, 0x64 }, | 305 | { IMX258_REG_PLL_IVT_MPY, 107 }, |
| 145 | { 0x0309, 0x0A }, | 306 | { IMX258_REG_IOPPXCK_DIV, 10 }, |
| 146 | { 0x030B, 0x01 }, | 307 | { IMX258_REG_IOPSYCK_DIV, 1 }, |
| 147 | { 0x030D, 0x02 }, | 308 | { IMX258_REG_PREPLLCK_OP_DIV, 2 }, |
| 148 | { 0x030E, 0x00 }, | 309 | { IMX258_REG_PLL_IOP_MPY, 216 }, |
| 149 | { 0x030F, 0xD8 }, | 310 | { IMX258_REG_PLL_MULT_DRIV, 0 }, |
| 150 | { 0x0310, 0x00 }, | 311 | |
| 151 | { 0x0820, 0x0A }, | 312 | { IMX258_REG_CSI_LANE_MODE, 3 }, |
| 152 | { 0x0821, 0x00 }, | 313 | { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 642 * 4 }, |
| 153 | { 0x0822, 0x00 }, | 314 | { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 }, |
| 154 | { 0x0823, 0x00 }, | ||
| 155 | }; | 315 | }; |
| 156 | 316 | ||
| 157 | static const struct imx258_reg mode_4208x3118_regs[] = { | 317 | static const struct cci_reg_sequence mode_common_regs[] = { |
| 158 | { 0x0136, 0x13 }, | 318 | { CCI_REG8(0x3051), 0x00 }, |
| 159 | { 0x0137, 0x33 }, | 319 | { CCI_REG8(0x6B11), 0xCF }, |
| 160 | { 0x3051, 0x00 }, | 320 | { CCI_REG8(0x7FF0), 0x08 }, |
| 161 | { 0x3052, 0x00 }, | 321 | { CCI_REG8(0x7FF1), 0x0F }, |
| 162 | { 0x4E21, 0x14 }, | 322 | { CCI_REG8(0x7FF2), 0x08 }, |
| 163 | { 0x6B11, 0xCF }, | 323 | { CCI_REG8(0x7FF3), 0x1B }, |
| 164 | { 0x7FF0, 0x08 }, | 324 | { CCI_REG8(0x7FF4), 0x23 }, |
| 165 | { 0x7FF1, 0x0F }, | 325 | { CCI_REG8(0x7FF5), 0x60 }, |
| 166 | { 0x7FF2, 0x08 }, | 326 | { CCI_REG8(0x7FF6), 0x00 }, |
| 167 | { 0x7FF3, 0x1B }, | 327 | { CCI_REG8(0x7FF7), 0x01 }, |
| 168 | { 0x7FF4, 0x23 }, | 328 | { CCI_REG8(0x7FF8), 0x00 }, |
| 169 | { 0x7FF5, 0x60 }, | 329 | { CCI_REG8(0x7FF9), 0x78 }, |
| 170 | { 0x7FF6, 0x00 }, | 330 | { CCI_REG8(0x7FFA), 0x00 }, |
| 171 | { 0x7FF7, 0x01 }, | 331 | { CCI_REG8(0x7FFB), 0x00 }, |
| 172 | { 0x7FF8, 0x00 }, | 332 | { CCI_REG8(0x7FFC), 0x00 }, |
| 173 | { 0x7FF9, 0x78 }, | 333 | { CCI_REG8(0x7FFD), 0x00 }, |
| 174 | { 0x7FFA, 0x00 }, | 334 | { CCI_REG8(0x7FFE), 0x00 }, |
| 175 | { 0x7FFB, 0x00 }, | 335 | { CCI_REG8(0x7FFF), 0x03 }, |
| 176 | { 0x7FFC, 0x00 }, | 336 | { CCI_REG8(0x7F76), 0x03 }, |
| 177 | { 0x7FFD, 0x00 }, | 337 | { CCI_REG8(0x7F77), 0xFE }, |
| 178 | { 0x7FFE, 0x00 }, | 338 | { CCI_REG8(0x7FA8), 0x03 }, |
| 179 | { 0x7FFF, 0x03 }, | 339 | { CCI_REG8(0x7FA9), 0xFE }, |
| 180 | { 0x7F76, 0x03 }, | 340 | { CCI_REG8(0x7B24), 0x81 }, |
| 181 | { 0x7F77, 0xFE }, | 341 | { CCI_REG8(0x6564), 0x07 }, |
| 182 | { 0x7FA8, 0x03 }, | 342 | { CCI_REG8(0x6B0D), 0x41 }, |
| 183 | { 0x7FA9, 0xFE }, | 343 | { CCI_REG8(0x653D), 0x04 }, |
| 184 | { 0x7B24, 0x81 }, | 344 | { CCI_REG8(0x6B05), 0x8C }, |
| 185 | { 0x7B25, 0x00 }, | 345 | { CCI_REG8(0x6B06), 0xF9 }, |
| 186 | { 0x6564, 0x07 }, | 346 | { CCI_REG8(0x6B08), 0x65 }, |
| 187 | { 0x6B0D, 0x41 }, | 347 | { CCI_REG8(0x6B09), 0xFC }, |
| 188 | { 0x653D, 0x04 }, | 348 | { CCI_REG8(0x6B0A), 0xCF }, |
| 189 | { 0x6B05, 0x8C }, | 349 | { CCI_REG8(0x6B0B), 0xD2 }, |
| 190 | { 0x6B06, 0xF9 }, | 350 | { CCI_REG8(0x6700), 0x0E }, |
| 191 | { 0x6B08, 0x65 }, | 351 | { CCI_REG8(0x6707), 0x0E }, |
| 192 | { 0x6B09, 0xFC }, | 352 | { CCI_REG8(0x9104), 0x00 }, |
| 193 | { 0x6B0A, 0xCF }, | 353 | { CCI_REG8(0x4648), 0x7F }, |
| 194 | { 0x6B0B, 0xD2 }, | 354 | { CCI_REG8(0x7420), 0x00 }, |
| 195 | { 0x6700, 0x0E }, | 355 | { CCI_REG8(0x7421), 0x1C }, |
| 196 | { 0x6707, 0x0E }, | 356 | { CCI_REG8(0x7422), 0x00 }, |
| 197 | { 0x9104, 0x00 }, | 357 | { CCI_REG8(0x7423), 0xD7 }, |
| 198 | { 0x4648, 0x7F }, | 358 | { CCI_REG8(0x5F04), 0x00 }, |
| 199 | { 0x7420, 0x00 }, | 359 | { CCI_REG8(0x5F05), 0xED }, |
| 200 | { 0x7421, 0x1C }, | 360 | {IMX258_REG_CSI_DT_FMT, 0x0a0a}, |
| 201 | { 0x7422, 0x00 }, | 361 | {IMX258_REG_LINE_LENGTH_PCK, 5352}, |
| 202 | { 0x7423, 0xD7 }, | 362 | {IMX258_REG_X_ADD_STA, 0}, |
| 203 | { 0x5F04, 0x00 }, | 363 | {IMX258_REG_Y_ADD_STA, 0}, |
| 204 | { 0x5F05, 0xED }, | 364 | {IMX258_REG_X_ADD_END, 4207}, |
| 205 | { 0x0112, 0x0A }, | 365 | {IMX258_REG_Y_ADD_END, 3119}, |
| 206 | { 0x0113, 0x0A }, | 366 | {IMX258_REG_X_EVN_INC, 1}, |
| 207 | { 0x0114, 0x03 }, | 367 | {IMX258_REG_X_ODD_INC, 1}, |
| 208 | { 0x0342, 0x14 }, | 368 | {IMX258_REG_Y_EVN_INC, 1}, |
| 209 | { 0x0343, 0xE8 }, | 369 | {IMX258_REG_Y_ODD_INC, 1}, |
| 210 | { 0x0340, 0x0C }, | 370 | {IMX258_REG_DIG_CROP_X_OFFSET, 0}, |
| 211 | { 0x0341, 0x50 }, | 371 | {IMX258_REG_DIG_CROP_Y_OFFSET, 0}, |
| 212 | { 0x0344, 0x00 }, | 372 | {IMX258_REG_DIG_CROP_IMAGE_WIDTH, 4208}, |
| 213 | { 0x0345, 0x00 }, | 373 | {IMX258_REG_SCALE_MODE_EXT, 0}, |
| 214 | { 0x0346, 0x00 }, | 374 | {IMX258_REG_SCALE_M_EXT, 16}, |
| 215 | { 0x0347, 0x00 }, | 375 | {IMX258_REG_FORCE_FD_SUM, 0}, |
| 216 | { 0x0348, 0x10 }, | 376 | {IMX258_REG_FRM_LENGTH_CTL, 0}, |
| 217 | { 0x0349, 0x6F }, | 377 | {IMX258_REG_ANALOG_GAIN, 0}, |
| 218 | { 0x034A, 0x0C }, | 378 | {IMX258_REG_GR_DIGITAL_GAIN, 256}, |
| 219 | { 0x034B, 0x2E }, | 379 | {IMX258_REG_R_DIGITAL_GAIN, 256}, |
| 220 | { 0x0381, 0x01 }, | 380 | {IMX258_REG_B_DIGITAL_GAIN, 256}, |
| 221 | { 0x0383, 0x01 }, | 381 | {IMX258_REG_GB_DIGITAL_GAIN, 256}, |
| 222 | { 0x0385, 0x01 }, | 382 | {IMX258_REG_AF_WINDOW_MODE, 0}, |
| 223 | { 0x0387, 0x01 }, | 383 | { CCI_REG8(0x94DC), 0x20 }, |
| 224 | { 0x0900, 0x00 }, | 384 | { CCI_REG8(0x94DD), 0x20 }, |
| 225 | { 0x0901, 0x11 }, | 385 | { CCI_REG8(0x94DE), 0x20 }, |
| 226 | { 0x0401, 0x00 }, | 386 | { CCI_REG8(0x95DC), 0x20 }, |
| 227 | { 0x0404, 0x00 }, | 387 | { CCI_REG8(0x95DD), 0x20 }, |
| 228 | { 0x0405, 0x10 }, | 388 | { CCI_REG8(0x95DE), 0x20 }, |
| 229 | { 0x0408, 0x00 }, | 389 | { CCI_REG8(0x7FB0), 0x00 }, |
| 230 | { 0x0409, 0x00 }, | 390 | { CCI_REG8(0x9010), 0x3E }, |
| 231 | { 0x040A, 0x00 }, | 391 | { CCI_REG8(0x9419), 0x50 }, |
| 232 | { 0x040B, 0x00 }, | 392 | { CCI_REG8(0x941B), 0x50 }, |
| 233 | { 0x040C, 0x10 }, | 393 | { CCI_REG8(0x9519), 0x50 }, |
| 234 | { 0x040D, 0x70 }, | 394 | { CCI_REG8(0x951B), 0x50 }, |
| 235 | { 0x040E, 0x0C }, | 395 | {IMX258_REG_PHASE_PIX_OUTEN, 0}, |
| 236 | { 0x040F, 0x30 }, | 396 | {IMX258_REG_PDPIX_DATA_RATE, 0}, |
| 237 | { 0x3038, 0x00 }, | 397 | {IMX258_REG_HDR, 0}, |
| 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 }, | ||
| 274 | }; | 398 | }; |
| 275 | 399 | ||
| 276 | static const struct imx258_reg mode_2104_1560_regs[] = { | 400 | static const struct cci_reg_sequence mode_4208x3120_regs[] = { |
| 277 | { 0x0136, 0x13 }, | 401 | {IMX258_REG_BINNING_MODE, 0}, |
| 278 | { 0x0137, 0x33 }, | 402 | {IMX258_REG_BINNING_TYPE_V, 0x11}, |
| 279 | { 0x3051, 0x00 }, | 403 | {IMX258_REG_SCALE_MODE, 0}, |
| 280 | { 0x3052, 0x00 }, | 404 | {IMX258_REG_SCALE_M, 16}, |
| 281 | { 0x4E21, 0x14 }, | 405 | {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 3120}, |
| 282 | { 0x6B11, 0xCF }, | 406 | {IMX258_REG_X_OUT_SIZE, 4208}, |
| 283 | { 0x7FF0, 0x08 }, | 407 | {IMX258_REG_Y_OUT_SIZE, 3120}, |
| 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 }, | ||
| 393 | }; | 408 | }; |
| 394 | 409 | ||
| 395 | static const struct imx258_reg mode_1048_780_regs[] = { | 410 | static const struct cci_reg_sequence mode_2104_1560_regs[] = { |
| 396 | { 0x0136, 0x13 }, | 411 | {IMX258_REG_BINNING_MODE, 1}, |
| 397 | { 0x0137, 0x33 }, | 412 | {IMX258_REG_BINNING_TYPE_V, 0x12}, |
| 398 | { 0x3051, 0x00 }, | 413 | {IMX258_REG_SCALE_MODE, 1}, |
| 399 | { 0x3052, 0x00 }, | 414 | {IMX258_REG_SCALE_M, 32}, |
| 400 | { 0x4E21, 0x14 }, | 415 | {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 1560}, |
| 401 | { 0x6B11, 0xCF }, | 416 | {IMX258_REG_X_OUT_SIZE, 2104}, |
| 402 | { 0x7FF0, 0x08 }, | 417 | {IMX258_REG_Y_OUT_SIZE, 1560}, |
| 403 | { 0x7FF1, 0x0F }, | 418 | }; |
| 404 | { 0x7FF2, 0x08 }, | 419 | |
| 405 | { 0x7FF3, 0x1B }, | 420 | static const struct cci_reg_sequence mode_1048_780_regs[] = { |
| 406 | { 0x7FF4, 0x23 }, | 421 | {IMX258_REG_BINNING_MODE, 1}, |
| 407 | { 0x7FF5, 0x60 }, | 422 | {IMX258_REG_BINNING_TYPE_V, 0x14}, |
| 408 | { 0x7FF6, 0x00 }, | 423 | {IMX258_REG_SCALE_MODE, 1}, |
| 409 | { 0x7FF7, 0x01 }, | 424 | {IMX258_REG_SCALE_M, 64}, |
| 410 | { 0x7FF8, 0x00 }, | 425 | {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 780}, |
| 411 | { 0x7FF9, 0x78 }, | 426 | {IMX258_REG_X_OUT_SIZE, 1048}, |
| 412 | { 0x7FFA, 0x00 }, | 427 | {IMX258_REG_Y_OUT_SIZE, 780}, |
| 413 | { 0x7FFB, 0x00 }, | 428 | }; |
| 414 | { 0x7FFC, 0x00 }, | 429 | |
| 415 | { 0x7FFD, 0x00 }, | 430 | struct imx258_variant_cfg { |
| 416 | { 0x7FFE, 0x00 }, | 431 | const struct cci_reg_sequence *regs; |
| 417 | { 0x7FFF, 0x03 }, | 432 | unsigned int num_regs; |
| 418 | { 0x7F76, 0x03 }, | 433 | }; |
| 419 | { 0x7F77, 0xFE }, | 434 | |
| 420 | { 0x7FA8, 0x03 }, | 435 | static const struct cci_reg_sequence imx258_cfg_regs[] = { |
| 421 | { 0x7FA9, 0xFE }, | 436 | { CCI_REG8(0x3052), 0x00 }, |
| 422 | { 0x7B24, 0x81 }, | 437 | { CCI_REG8(0x4E21), 0x14 }, |
| 423 | { 0x7B25, 0x00 }, | 438 | { CCI_REG8(0x7B25), 0x00 }, |
| 424 | { 0x6564, 0x07 }, | 439 | }; |
| 425 | { 0x6B0D, 0x41 }, | 440 | |
| 426 | { 0x653D, 0x04 }, | 441 | static const struct imx258_variant_cfg imx258_cfg = { |
| 427 | { 0x6B05, 0x8C }, | 442 | .regs = imx258_cfg_regs, |
| 428 | { 0x6B06, 0xF9 }, | 443 | .num_regs = ARRAY_SIZE(imx258_cfg_regs), |
| 429 | { 0x6B08, 0x65 }, | 444 | }; |
| 430 | { 0x6B09, 0xFC }, | 445 | |
| 431 | { 0x6B0A, 0xCF }, | 446 | static const struct cci_reg_sequence imx258_pdaf_cfg_regs[] = { |
| 432 | { 0x6B0B, 0xD2 }, | 447 | { CCI_REG8(0x3052), 0x01 }, |
| 433 | { 0x6700, 0x0E }, | 448 | { CCI_REG8(0x4E21), 0x10 }, |
| 434 | { 0x6707, 0x0E }, | 449 | { CCI_REG8(0x7B25), 0x01 }, |
| 435 | { 0x9104, 0x00 }, | 450 | }; |
| 436 | { 0x4648, 0x7F }, | 451 | |
| 437 | { 0x7420, 0x00 }, | 452 | static const struct imx258_variant_cfg imx258_pdaf_cfg = { |
| 438 | { 0x7421, 0x1C }, | 453 | .regs = imx258_pdaf_cfg_regs, |
| 439 | { 0x7422, 0x00 }, | 454 | .num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs), |
| 440 | { 0x7423, 0xD7 }, | 455 | }; |
| 441 | { 0x5F04, 0x00 }, | 456 | |
| 442 | { 0x5F05, 0xED }, | 457 | /* |
| 443 | { 0x0112, 0x0A }, | 458 | * The supported formats. |
| 444 | { 0x0113, 0x0A }, | 459 | * This table MUST contain 4 entries per format, to cover the various flip |
| 445 | { 0x0114, 0x03 }, | 460 | * combinations in the order |
| 446 | { 0x0342, 0x14 }, | 461 | * - no flip |
| 447 | { 0x0343, 0xE8 }, | 462 | * - h flip |
| 448 | { 0x0340, 0x03 }, | 463 | * - v flip |
| 449 | { 0x0341, 0x4C }, | 464 | * - h&v flips |
| 450 | { 0x0344, 0x00 }, | 465 | */ |
| 451 | { 0x0345, 0x00 }, | 466 | static const u32 codes[] = { |
| 452 | { 0x0346, 0x00 }, | 467 | /* 10-bit modes. */ |
| 453 | { 0x0347, 0x00 }, | 468 | MEDIA_BUS_FMT_SRGGB10_1X10, |
| 454 | { 0x0348, 0x10 }, | 469 | MEDIA_BUS_FMT_SGRBG10_1X10, |
| 455 | { 0x0349, 0x6F }, | 470 | MEDIA_BUS_FMT_SGBRG10_1X10, |
| 456 | { 0x034A, 0x0C }, | 471 | MEDIA_BUS_FMT_SBGGR10_1X10 |
| 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 }, | ||
| 512 | }; | 472 | }; |
| 513 | 473 | ||
| 514 | static const char * const imx258_test_pattern_menu[] = { | 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 | "Pseudorandom Sequence (PN9)", | 479 | "Pseudorandom Sequence (PN9)", |
| 520 | }; | 480 | }; |
| 521 | 481 | ||
| 522 | /* Configurations for supported link frequencies */ | 482 | /* regulator supplies */ |
| 523 | #define IMX258_LINK_FREQ_634MHZ 633600000ULL | 483 | static const char * const imx258_supply_name[] = { |
| 524 | #define IMX258_LINK_FREQ_320MHZ 320000000ULL | 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 | enum { | 492 | enum { |
| 527 | IMX258_LINK_FREQ_1267MBPS, | 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 | 498 | * Pixel rate does not necessarily relate to link frequency on this sensor as |
| 533 | * data rate => double data rate; number of lanes => 4; bits per pixel => 10 | 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 | do_div(f, 10); | 514 | do_div(f, 10); |
| 539 | 515 | ||
| 540 | return f; | 516 | return f; |
| 541 | } | 517 | } |
| 542 | 518 | ||
| 543 | /* Menu items for LINK_FREQ V4L2 control */ | 519 | /* Menu items for LINK_FREQ V4L2 control */ |
| 544 | static const s64 link_freq_menu_items[] = { | 520 | /* Configurations for supported link frequencies */ |
| 545 | IMX258_LINK_FREQ_634MHZ, | 521 | static const s64 link_freq_menu_items_19_2[] = { |
| 546 | IMX258_LINK_FREQ_320MHZ, | 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 | /* Link frequency configs */ | 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 | [IMX258_LINK_FREQ_1267MBPS] = { | 535 | [IMX258_LINK_FREQ_1267MBPS] = { |
| 552 | .pixels_per_line = IMX258_PPL_DEFAULT, | 536 | .pixels_per_line = IMX258_PPL_DEFAULT, |
| 553 | .reg_list = { | 537 | .link_cfg = { |
| 554 | .num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps), | 538 | [IMX258_2_LANE_MODE] = { |
| 555 | .regs = mipi_data_rate_1267mbps, | 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 | [IMX258_LINK_FREQ_640MBPS] = { | 548 | [IMX258_LINK_FREQ_640MBPS] = { |
| 559 | .pixels_per_line = IMX258_PPL_DEFAULT, | 549 | .pixels_per_line = IMX258_PPL_DEFAULT, |
| 560 | .reg_list = { | 550 | .link_cfg = { |
| 561 | .num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps), | 551 | [IMX258_2_LANE_MODE] = { |
| 562 | .regs = mipi_data_rate_640mbps, | 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 | static const struct imx258_mode supported_modes[] = { | 593 | static const struct imx258_mode supported_modes[] = { |
| 569 | { | 594 | { |
| 570 | .width = 4208, | 595 | .width = 4208, |
| 571 | .height = 3118, | 596 | .height = 3120, |
| 572 | .vts_def = IMX258_VTS_30FPS, | 597 | .vts_def = IMX258_VTS_30FPS, |
| 573 | .vts_min = IMX258_VTS_30FPS, | 598 | .vts_min = IMX258_VTS_30FPS, |
| 574 | .reg_list = { | 599 | .reg_list = { |
| 575 | .num_of_regs = ARRAY_SIZE(mode_4208x3118_regs), | 600 | .num_of_regs = ARRAY_SIZE(mode_4208x3120_regs), |
| 576 | .regs = mode_4208x3118_regs, | 601 | .regs = mode_4208x3120_regs, |
| 577 | }, | 602 | }, |
| 578 | .link_freq_index = IMX258_LINK_FREQ_1267MBPS, | 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 | .width = 2104, | 612 | .width = 2104, |
| @@ -587,6 +618,12 @@ static const struct imx258_mode supported_modes[] = { · 5 unmodified lines | |||
| 587 | .regs = mode_2104_1560_regs, | 618 | .regs = mode_2104_1560_regs, |
| 588 | }, | 619 | }, |
| 589 | .link_freq_index = IMX258_LINK_FREQ_640MBPS, | 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 | .width = 1048, | 629 | .width = 1048, |
| @@ -598,12 +635,21 @@ static const struct imx258_mode supported_modes[] = { · 5 unmodified lines | |||
| 598 | .regs = mode_1048_780_regs, | 635 | .regs = mode_1048_780_regs, |
| 599 | }, | 636 | }, |
| 600 | .link_freq_index = IMX258_LINK_FREQ_640MBPS, | 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 | struct imx258 { | 647 | struct imx258 { |
| 605 | struct v4l2_subdev sd; | 648 | struct v4l2_subdev sd; |
| 606 | struct media_pad pad; | 649 | struct media_pad pad; |
| 650 | struct regmap *regmap; | ||
| 651 | |||
| 652 | const struct imx258_variant_cfg *variant_cfg; | ||
| 607 | 653 | ||
| 608 | struct v4l2_ctrl_handler ctrl_handler; | 654 | struct v4l2_ctrl_handler ctrl_handler; |
| 609 | /* V4L2 Controls */ | 655 | /* V4L2 Controls */ |
| @@ -612,10 +658,18 @@ struct imx258 { · 2 unmodified lines | |||
| 612 | struct v4l2_ctrl *vblank; | 658 | struct v4l2_ctrl *vblank; |
| 613 | struct v4l2_ctrl *hblank; | 659 | struct v4l2_ctrl *hblank; |
| 614 | struct v4l2_ctrl *exposure; | 660 | struct v4l2_ctrl *exposure; |
| 661 | struct v4l2_ctrl *hflip; | ||
| 662 | struct v4l2_ctrl *vflip; | ||
| 615 | 663 | ||
| 616 | /* Current mode */ | 664 | /* Current mode */ |
| 617 | const struct imx258_mode *cur_mode; | 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 | * Mutex for serialized access: | 674 | * Mutex for serialized access: |
| 621 | * Protect sensor module set pad format and start/stop streaming safely. | 675 | * Protect sensor module set pad format and start/stop streaming safely. |
| @@ -623,6 +677,7 @@ struct imx258 { · 1 unmodified line | |||
| 623 | struct mutex mutex; | 677 | struct mutex mutex; |
| 624 | 678 | ||
| 625 | struct clk *clk; | 679 | struct clk *clk; |
| 680 | struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES]; | ||
| 626 | }; | 681 | }; |
| 627 | 682 | ||
| 628 | static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd) | 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 | return container_of(_sd, struct imx258, sd); | 685 | return container_of(_sd, struct imx258, sd); |
| 631 | } | 686 | } |
| 632 | 687 | ||
| 633 | /* Read registers up to 2 at a time */ | 688 | /* Get bayer order based on flip setting. */ |
| 634 | static int imx258_read_reg(struct imx258 *imx258, u16 reg, u32 len, u32 *val) | 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 | unsigned int i; | 691 | unsigned int i; |
| 689 | int ret; | ||
| 690 | 692 | ||
| 691 | for (i = 0; i < len; i++) { | 693 | lockdep_assert_held(&imx258->mutex); |
| 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); | ||
| 699 | 694 | ||
| 700 | return ret; | 695 | i = (imx258->vflip->val ? 2 : 0) | |
| 701 | } | 696 | (imx258->hflip->val ? 1 : 0); |
| 702 | } | ||
| 703 | 697 | ||
| 704 | return 0; | 698 | return codes[i]; |
| 705 | } | 699 | } |
| 706 | 700 | ||
| 707 | /* Open sub-device */ | 701 | /* Open sub-device */ |
| 708 | static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) | 702 | static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) |
| 709 | { | 703 | { |
| 704 | struct imx258 *imx258 = to_imx258(sd); | ||
| 710 | struct v4l2_mbus_framefmt *try_fmt = | 705 | struct v4l2_mbus_framefmt *try_fmt = |
| 711 | v4l2_subdev_state_get_format(fh->state, 0); | 706 | v4l2_subdev_state_get_format(fh->state, 0); |
| 707 | struct v4l2_rect *try_crop; | ||
| 712 | 708 | ||
| 713 | /* Initialize try_fmt */ | 709 | /* Initialize try_fmt */ |
| 714 | try_fmt->width = supported_modes[0].width; | 710 | try_fmt->width = supported_modes[0].width; |
| 715 | try_fmt->height = supported_modes[0].height; | 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 | try_fmt->field = V4L2_FIELD_NONE; | 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 | return 0; | 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, | 729 | cci_write(imx258->regmap, IMX258_REG_GR_DIGITAL_GAIN, val, &ret); |
| 727 | IMX258_REG_VALUE_16BIT, | 730 | cci_write(imx258->regmap, IMX258_REG_GB_DIGITAL_GAIN, val, &ret); |
| 728 | val); | 731 | cci_write(imx258->regmap, IMX258_REG_R_DIGITAL_GAIN, val, &ret); |
| 729 | if (ret) | 732 | cci_write(imx258->regmap, IMX258_REG_B_DIGITAL_GAIN, val, &ret); |
| 730 | return ret; | 733 | |
| 731 | ret = imx258_write_reg(imx258, IMX258_REG_GB_DIGITAL_GAIN, | 734 | return ret; |
| 732 | IMX258_REG_VALUE_16BIT, | 735 | } |
| 733 | val); | 736 | |
| 734 | if (ret) | 737 | static void imx258_adjust_exposure_range(struct imx258 *imx258) |
| 735 | return ret; | 738 | { |
| 736 | ret = imx258_write_reg(imx258, IMX258_REG_R_DIGITAL_GAIN, | 739 | int exposure_max, exposure_def; |
| 737 | IMX258_REG_VALUE_16BIT, | 740 | |
| 738 | val); | 741 | /* Honour the VBLANK limits when setting exposure. */ |
| 739 | if (ret) | 742 | exposure_max = imx258->cur_mode->height + imx258->vblank->val - |
| 740 | return ret; | 743 | IMX258_EXPOSURE_OFFSET; |
| 741 | ret = imx258_write_reg(imx258, IMX258_REG_B_DIGITAL_GAIN, | 744 | exposure_def = min(exposure_max, imx258->exposure->val); |
| 742 | IMX258_REG_VALUE_16BIT, | 745 | __v4l2_ctrl_modify_range(imx258->exposure, imx258->exposure->minimum, |
| 743 | val); | 746 | exposure_max, imx258->exposure->step, |
| 744 | if (ret) | 747 | exposure_def); |
| 745 | return ret; | ||
| 746 | return 0; | ||
| 747 | } | 748 | } |
| 748 | 749 | ||
| 749 | static int imx258_set_ctrl(struct v4l2_ctrl *ctrl) | 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 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | 754 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 754 | int ret = 0; | 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 | * Applying V4L2 control value only happens | 765 | * Applying V4L2 control value only happens |
| 758 | * when power is up for streaming | 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 | switch (ctrl->id) { | 771 | switch (ctrl->id) { |
| 764 | case V4L2_CID_ANALOGUE_GAIN: | 772 | case V4L2_CID_ANALOGUE_GAIN: |
| 765 | ret = imx258_write_reg(imx258, IMX258_REG_ANALOG_GAIN, | 773 | ret = cci_write(imx258->regmap, IMX258_REG_ANALOG_GAIN, |
| 766 | IMX258_REG_VALUE_16BIT, | 774 | ctrl->val, NULL); |
| 767 | ctrl->val); | ||
| 768 | break; | 775 | break; |
| 769 | case V4L2_CID_EXPOSURE: | 776 | case V4L2_CID_EXPOSURE: |
| 770 | ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE, | 777 | ret = cci_write(imx258->regmap, IMX258_REG_EXPOSURE, |
| 771 | IMX258_REG_VALUE_16BIT, | 778 | ctrl->val, NULL); |
| 772 | ctrl->val); | ||
| 773 | break; | 779 | break; |
| 774 | case V4L2_CID_DIGITAL_GAIN: | 780 | case V4L2_CID_DIGITAL_GAIN: |
| 775 | ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT, | 781 | ret = imx258_update_digital_gain(imx258, ctrl->val); |
| 776 | ctrl->val); | ||
| 777 | break; | 782 | break; |
| 778 | case V4L2_CID_TEST_PATTERN: | 783 | case V4L2_CID_TEST_PATTERN: |
| 779 | ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN, | 784 | ret = cci_write(imx258->regmap, IMX258_REG_TEST_PATTERN, |
| 780 | IMX258_REG_VALUE_16BIT, | 785 | ctrl->val, NULL); |
| 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); | ||
| 786 | break; | 786 | break; |
| 787 | case V4L2_CID_WIDE_DYNAMIC_RANGE: | 787 | case V4L2_CID_WIDE_DYNAMIC_RANGE: |
| 788 | if (!ctrl->val) { | 788 | if (!ctrl->val) { |
| 789 | ret = imx258_write_reg(imx258, IMX258_REG_HDR, | 789 | ret = cci_write(imx258->regmap, IMX258_REG_HDR, |
| 790 | IMX258_REG_VALUE_08BIT, | 790 | IMX258_HDR_RATIO_MIN, NULL); |
| 791 | IMX258_HDR_RATIO_MIN); | ||
| 792 | } else { | 791 | } else { |
| 793 | ret = imx258_write_reg(imx258, IMX258_REG_HDR, | 792 | ret = cci_write(imx258->regmap, IMX258_REG_HDR, |
| 794 | IMX258_REG_VALUE_08BIT, | 793 | IMX258_HDR_ON, NULL); |
| 795 | IMX258_HDR_ON); | ||
| 796 | if (ret) | 794 | if (ret) |
| 797 | break; | 795 | break; |
| 798 | ret = imx258_write_reg(imx258, IMX258_REG_HDR_RATIO, | 796 | ret = cci_write(imx258->regmap, IMX258_REG_HDR_RATIO, |
| 799 | IMX258_REG_VALUE_08BIT, | 797 | BIT(IMX258_HDR_RATIO_MAX), NULL); |
| 800 | BIT(IMX258_HDR_RATIO_MAX)); | ||
| 801 | } | 798 | } |
| 802 | break; | 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 | default: | 813 | default: |
| 804 | dev_info(&client->dev, | 814 | dev_info(&client->dev, |
| 805 | "ctrl(id:0x%x,val:0x%x) is not handled\n", | 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 | struct v4l2_subdev_state *sd_state, | 831 | struct v4l2_subdev_state *sd_state, |
| 822 | struct v4l2_subdev_mbus_code_enum *code) | 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 | if (code->index > 0) | 837 | if (code->index > 0) |
| 826 | return -EINVAL; | 838 | return -EINVAL; |
| 827 | 839 | ||
| 828 | code->code = MEDIA_BUS_FMT_SGRBG10_1X10; | 840 | code->code = imx258_get_format_code(imx258); |
| 829 | 841 | ||
| 830 | return 0; | 842 | return 0; |
| 831 | } | 843 | } |
| @@ -834,10 +846,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd, · 2 unmodified lines | |||
| 834 | struct v4l2_subdev_state *sd_state, | 846 | struct v4l2_subdev_state *sd_state, |
| 835 | struct v4l2_subdev_frame_size_enum *fse) | 847 | struct v4l2_subdev_frame_size_enum *fse) |
| 836 | { | 848 | { |
| 849 | struct imx258 *imx258 = to_imx258(sd); | ||
| 837 | if (fse->index >= ARRAY_SIZE(supported_modes)) | 850 | if (fse->index >= ARRAY_SIZE(supported_modes)) |
| 838 | return -EINVAL; | 851 | return -EINVAL; |
| 839 | 852 | ||
| 840 | if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10) | 853 | if (fse->code != imx258_get_format_code(imx258)) |
| 841 | return -EINVAL; | 854 | return -EINVAL; |
| 842 | 855 | ||
| 843 | fse->min_width = supported_modes[fse->index].width; | 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 | return 0; | 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 | struct v4l2_subdev_format *fmt) | 866 | struct v4l2_subdev_format *fmt) |
| 853 | { | 867 | { |
| 854 | fmt->format.width = mode->width; | 868 | fmt->format.width = mode->width; |
| 855 | fmt->format.height = mode->height; | 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 | fmt->format.field = V4L2_FIELD_NONE; | 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 | fmt->format = *v4l2_subdev_state_get_format(sd_state, | 879 | fmt->format = *v4l2_subdev_state_get_format(sd_state, |
| 866 | fmt->pad); | 880 | fmt->pad); |
| 867 | else | 881 | else |
| 868 | imx258_update_pad_format(imx258->cur_mode, fmt); | 882 | imx258_update_pad_format(imx258, imx258->cur_mode, fmt); |
| 869 | 883 | ||
| 870 | return 0; | 884 | return 0; |
| 871 | } | 885 | } |
| @@ -889,8 +903,10 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 17 unmodified lines | |||
| 889 | struct v4l2_subdev_format *fmt) | 903 | struct v4l2_subdev_format *fmt) |
| 890 | { | 904 | { |
| 891 | struct imx258 *imx258 = to_imx258(sd); | 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 | struct v4l2_mbus_framefmt *framefmt; | 908 | struct v4l2_mbus_framefmt *framefmt; |
| 909 | const struct imx258_mode *mode; | ||
| 894 | s32 vblank_def; | 910 | s32 vblank_def; |
| 895 | s32 vblank_min; | 911 | s32 vblank_min; |
| 896 | s64 h_blank; | 912 | s64 h_blank; |
| @@ -899,13 +915,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 2 unmodified lines | |||
| 899 | 915 | ||
| 900 | mutex_lock(&imx258->mutex); | 916 | mutex_lock(&imx258->mutex); |
| 901 | 917 | ||
| 902 | /* Only one raw bayer(GBRG) order is supported */ | 918 | fmt->format.code = imx258_get_format_code(imx258); |
| 903 | fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10; | ||
| 904 | 919 | ||
| 905 | mode = v4l2_find_nearest_size(supported_modes, | 920 | mode = v4l2_find_nearest_size(supported_modes, |
| 906 | ARRAY_SIZE(supported_modes), width, height, | 921 | ARRAY_SIZE(supported_modes), width, height, |
| 907 | fmt->format.width, fmt->format.height); | 922 | fmt->format.width, fmt->format.height); |
| 908 | imx258_update_pad_format(mode, fmt); | 923 | imx258_update_pad_format(imx258, mode, fmt); |
| 909 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { | 924 | if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { |
| 910 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); | 925 | framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad); |
| 911 | *framefmt = fmt->format; | 926 | *framefmt = fmt->format; |
| @@ -913,9 +928,14 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 1 unmodified line | |||
| 913 | imx258->cur_mode = mode; | 928 | imx258->cur_mode = mode; |
| 914 | __v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index); | 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]; | 931 | link_freq = imx258->link_freq_menu_items[mode->link_freq_index]; |
| 917 | pixel_rate = link_freq_to_pixel_rate(link_freq); | 932 | link_freq_cfgs = |
| 918 | __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate); | 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 | /* Update limits and set FPS to default */ | 939 | /* Update limits and set FPS to default */ |
| 920 | vblank_def = imx258->cur_mode->vts_def - | 940 | vblank_def = imx258->cur_mode->vts_def - |
| 921 | imx258->cur_mode->height; | 941 | imx258->cur_mode->height; |
| @@ -927,7 +947,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 5 unmodified lines | |||
| 927 | vblank_def); | 947 | vblank_def); |
| 928 | __v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def); | 948 | __v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def); |
| 929 | h_blank = | 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 | - imx258->cur_mode->width; | 951 | - imx258->cur_mode->width; |
| 932 | __v4l2_ctrl_modify_range(imx258->hblank, h_blank, | 952 | __v4l2_ctrl_modify_range(imx258->hblank, h_blank, |
| 933 | h_blank, 1, h_blank); | 953 | h_blank, 1, h_blank); |
| @@ -938,48 +958,125 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd, · 4 unmodified lines | |||
| 938 | return 0; | 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 | /* Start streaming */ | 1013 | /* Start streaming */ |
| 942 | static int imx258_start_streaming(struct imx258 *imx258) | 1014 | static int imx258_start_streaming(struct imx258 *imx258) |
| 943 | { | 1015 | { |
| 944 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | 1016 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 945 | const struct imx258_reg_list *reg_list; | 1017 | const struct imx258_reg_list *reg_list; |
| 1018 | const struct imx258_link_freq_config *link_freq_cfg; | ||
| 946 | int ret, link_freq_index; | 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 | /* Setup PLL */ | 1030 | /* Setup PLL */ |
| 949 | link_freq_index = imx258->cur_mode->link_freq_index; | 1031 | link_freq_index = imx258->cur_mode->link_freq_index; |
| 950 | reg_list = &link_freq_configs[link_freq_index].reg_list; | 1032 | link_freq_cfg = &imx258->link_freq_configs[link_freq_index]; |
| 951 | ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); | 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 | if (ret) { | 1036 | if (ret) { |
| 953 | dev_err(&client->dev, "%s failed to set plls\n", __func__); | 1037 | dev_err(&client->dev, "%s failed to set plls\n", __func__); |
| 954 | return ret; | 1038 | return ret; |
| 955 | } | 1039 | } |
| 956 | 1040 | ||
| 957 | /* Apply default values of current mode */ | 1041 | ret = cci_multi_reg_write(imx258->regmap, mode_common_regs, |
| 958 | reg_list = &imx258->cur_mode->reg_list; | 1042 | ARRAY_SIZE(mode_common_regs), NULL); |
| 959 | ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs); | ||
| 960 | if (ret) { | 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 | return ret; | 1045 | return ret; |
| 963 | } | 1046 | } |
| 964 | 1047 | ||
| 965 | /* Set Orientation be 180 degree */ | 1048 | ret = cci_multi_reg_write(imx258->regmap, imx258->variant_cfg->regs, |
| 966 | ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL, | 1049 | imx258->variant_cfg->num_regs, NULL); |
| 967 | IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP); | ||
| 968 | if (ret) { | 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 | __func__); | 1052 | __func__); |
| 971 | return ret; | 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 | /* Apply customized values from user */ | 1072 | /* Apply customized values from user */ |
| 975 | ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler); | 1073 | ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler); |
| 976 | if (ret) | 1074 | if (ret) |
| 977 | return ret; | 1075 | return ret; |
| 978 | 1076 | ||
| 979 | /* set stream on register */ | 1077 | /* set stream on register */ |
| 980 | return imx258_write_reg(imx258, IMX258_REG_MODE_SELECT, | 1078 | return cci_write(imx258->regmap, IMX258_REG_MODE_SELECT, |
| 981 | IMX258_REG_VALUE_08BIT, | 1079 | IMX258_MODE_STREAMING, NULL); |
| 982 | IMX258_MODE_STREAMING); | ||
| 983 | } | 1080 | } |
| 984 | 1081 | ||
| 985 | /* Stop streaming */ | 1082 | /* Stop streaming */ |
| @@ -989,8 +1086,8 @@ static int imx258_stop_streaming(struct imx258 *imx258) · 3 unmodified lines | |||
| 989 | int ret; | 1086 | int ret; |
| 990 | 1087 | ||
| 991 | /* set stream off register */ | 1088 | /* set stream off register */ |
| 992 | ret = imx258_write_reg(imx258, IMX258_REG_MODE_SELECT, | 1089 | ret = cci_write(imx258->regmap, IMX258_REG_MODE_SELECT, |
| 993 | IMX258_REG_VALUE_08BIT, IMX258_MODE_STANDBY); | 1090 | IMX258_MODE_STANDBY, NULL); |
| 994 | if (ret) | 1091 | if (ret) |
| 995 | dev_err(&client->dev, "%s failed to set stream\n", __func__); | 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 | struct imx258 *imx258 = to_imx258(sd); | 1104 | struct imx258 *imx258 = to_imx258(sd); |
| 1008 | int ret; | 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 | ret = clk_prepare_enable(imx258->clk); | 1115 | ret = clk_prepare_enable(imx258->clk); |
| 1011 | if (ret) | 1116 | if (ret) { |
| 1012 | dev_err(dev, "failed to enable clock\n"); | 1117 | dev_err(dev, "failed to enable clock\n"); |
| 1118 | regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); | ||
| 1119 | } | ||
| 1013 | 1120 | ||
| 1014 | return ret; | 1121 | return ret; |
| 1015 | } | 1122 | } |
| @@ -1020,6 +1127,7 @@ static int imx258_power_off(struct device *dev) · 4 unmodified lines | |||
| 1020 | struct imx258 *imx258 = to_imx258(sd); | 1127 | struct imx258 *imx258 = to_imx258(sd); |
| 1021 | 1128 | ||
| 1022 | clk_disable_unprepare(imx258->clk); | 1129 | clk_disable_unprepare(imx258->clk); |
| 1130 | regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies); | ||
| 1023 | 1131 | ||
| 1024 | return 0; | 1132 | return 0; |
| 1025 | } | 1133 | } |
| @@ -1066,10 +1174,10 @@ static int imx258_identify_module(struct imx258 *imx258) · 40 unmodified lines | |||
| 1066 | { | 1174 | { |
| 1067 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | 1175 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 1068 | int ret; | 1176 | int ret; |
| 1069 | u32 val; | 1177 | u64 val; |
| 1070 | 1178 | ||
| 1071 | ret = imx258_read_reg(imx258, IMX258_REG_CHIP_ID, | 1179 | ret = cci_read(imx258->regmap, IMX258_REG_CHIP_ID, |
| 1072 | IMX258_REG_VALUE_16BIT, &val); | 1180 | &val, NULL); |
| 1073 | if (ret) { | 1181 | if (ret) { |
| 1074 | dev_err(&client->dev, "failed to read chip id %x\n", | 1182 | dev_err(&client->dev, "failed to read chip id %x\n", |
| 1075 | IMX258_CHIP_ID); | 1183 | IMX258_CHIP_ID); |
| @@ -1077,7 +1185,7 @@ static int imx258_identify_module(struct imx258 *imx258) · 1 unmodified line | |||
| 1077 | } | 1185 | } |
| 1078 | 1186 | ||
| 1079 | if (val != IMX258_CHIP_ID) { | 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 | IMX258_CHIP_ID, val); | 1189 | IMX258_CHIP_ID, val); |
| 1082 | return -EIO; | 1190 | return -EIO; |
| 1083 | } | 1191 | } |
| @@ -1094,6 +1202,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = { · 10 unmodified lines | |||
| 1094 | .get_fmt = imx258_get_pad_format, | 1202 | .get_fmt = imx258_get_pad_format, |
| 1095 | .set_fmt = imx258_set_pad_format, | 1203 | .set_fmt = imx258_set_pad_format, |
| 1096 | .enum_frame_size = imx258_enum_frame_size, | 1204 | .enum_frame_size = imx258_enum_frame_size, |
| 1205 | .get_selection = imx258_get_selection, | ||
| 1097 | }; | 1206 | }; |
| 1098 | 1207 | ||
| 1099 | static const struct v4l2_subdev_ops imx258_subdev_ops = { | 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 | static int imx258_init_controls(struct imx258 *imx258) | 1218 | static int imx258_init_controls(struct imx258 *imx258) |
| 1110 | { | 1219 | { |
| 1111 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); | 1220 | struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd); |
| 1221 | const struct imx258_link_freq_config *link_freq_cfgs; | ||
| 1112 | struct v4l2_fwnode_device_properties props; | 1222 | struct v4l2_fwnode_device_properties props; |
| 1113 | struct v4l2_ctrl_handler *ctrl_hdlr; | 1223 | struct v4l2_ctrl_handler *ctrl_hdlr; |
| 1114 | struct v4l2_ctrl *vflip, *hflip; | 1224 | const struct imx258_link_cfg *link_cfg; |
| 1115 | s64 vblank_def; | 1225 | s64 vblank_def; |
| 1116 | s64 vblank_min; | 1226 | s64 vblank_min; |
| 1117 | s64 pixel_rate_min; | 1227 | s64 pixel_rate; |
| 1118 | s64 pixel_rate_max; | ||
| 1119 | int ret; | 1228 | int ret; |
| 1120 | 1229 | ||
| 1121 | ctrl_hdlr = &imx258->ctrl_handler; | 1230 | ctrl_hdlr = &imx258->ctrl_handler; |
| @@ -1128,32 +1237,33 @@ static int imx258_init_controls(struct imx258 *imx258) · 6 unmodified lines | |||
| 1128 | imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, | 1237 | imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, |
| 1129 | &imx258_ctrl_ops, | 1238 | &imx258_ctrl_ops, |
| 1130 | V4L2_CID_LINK_FREQ, | 1239 | V4L2_CID_LINK_FREQ, |
| 1131 | ARRAY_SIZE(link_freq_menu_items) - 1, | 1240 | ARRAY_SIZE(link_freq_menu_items_19_2) - 1, |
| 1132 | 0, | 1241 | 0, |
| 1133 | link_freq_menu_items); | 1242 | imx258->link_freq_menu_items); |
| 1134 | 1243 | ||
| 1135 | if (imx258->link_freq) | 1244 | if (imx258->link_freq) |
| 1136 | imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 1245 | imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY; |
| 1137 | 1246 | ||
| 1138 | /* The driver only supports one bayer order and flips by default. */ | 1247 | imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, |
| 1139 | hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | 1248 | V4L2_CID_HFLIP, 0, 1, 1, 1); |
| 1140 | V4L2_CID_HFLIP, 1, 1, 1, 1); | 1249 | if (imx258->hflip) |
| 1141 | if (hflip) | 1250 | imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT; |
| 1142 | hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 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, | 1257 | link_freq_cfgs = &imx258->link_freq_configs[0]; |
| 1145 | V4L2_CID_VFLIP, 1, 1, 1, 1); | 1258 | link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg; |
| 1146 | if (vflip) | 1259 | pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items[0], |
| 1147 | vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY; | 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 | /* By default, PIXEL_RATE is read only */ | 1262 | /* By default, PIXEL_RATE is read only */ |
| 1152 | imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, | 1263 | imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops, |
| 1153 | V4L2_CID_PIXEL_RATE, | 1264 | V4L2_CID_PIXEL_RATE, |
| 1154 | pixel_rate_min, pixel_rate_max, | 1265 | pixel_rate, pixel_rate, |
| 1155 | 1, pixel_rate_max); | 1266 | 1, pixel_rate); |
| 1156 | |||
| 1157 | 1267 | ||
| 1158 | vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height; | 1268 | vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height; |
| 1159 | vblank_min = imx258->cur_mode->vts_min - imx258->cur_mode->height; | 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 | IMX258_VTS_MAX - imx258->cur_mode->height, 1, | 1273 | IMX258_VTS_MAX - imx258->cur_mode->height, 1, |
| 1164 | vblank_def); | 1274 | vblank_def); |
| 1165 | 1275 | ||
| 1166 | if (imx258->vblank) | ||
| 1167 | imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY; | ||
| 1168 | |||
| 1169 | imx258->hblank = v4l2_ctrl_new_std( | 1276 | imx258->hblank = v4l2_ctrl_new_std( |
| 1170 | ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK, | 1277 | ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK, |
| 1171 | IMX258_PPL_DEFAULT - imx258->cur_mode->width, | 1278 | IMX258_PPL_DEFAULT - imx258->cur_mode->width, |
| @@ -1232,9 +1339,25 @@ static void imx258_free_controls(struct imx258 *imx258) · 60 unmodified lines | |||
| 1232 | mutex_destroy(&imx258->mutex); | 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 | static int imx258_probe(struct i2c_client *client) | 1354 | static int imx258_probe(struct i2c_client *client) |
| 1236 | { | 1355 | { |
| 1237 | struct imx258 *imx258; | 1356 | struct imx258 *imx258; |
| 1357 | struct fwnode_handle *endpoint; | ||
| 1358 | struct v4l2_fwnode_endpoint ep = { | ||
| 1359 | .bus_type = V4L2_MBUS_CSI2_DPHY | ||
| 1360 | }; | ||
| 1238 | int ret; | 1361 | int ret; |
| 1239 | u32 val = 0; | 1362 | u32 val = 0; |
| 1240 | 1363 | ||
| @@ -1242,6 +1365,18 @@ static int imx258_probe(struct i2c_client *client) · 1 unmodified line | |||
| 1242 | if (!imx258) | 1365 | if (!imx258) |
| 1243 | return -ENOMEM; | 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 | imx258->clk = devm_clk_get_optional(&client->dev, NULL); | 1380 | imx258->clk = devm_clk_get_optional(&client->dev, NULL); |
| 1246 | if (IS_ERR(imx258->clk)) | 1381 | if (IS_ERR(imx258->clk)) |
| 1247 | return dev_err_probe(&client->dev, PTR_ERR(imx258->clk), | 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 | } else { | 1389 | } else { |
| 1255 | val = clk_get_rate(imx258->clk); | 1390 | val = clk_get_rate(imx258->clk); |
| 1256 | } | 1391 | } |
| 1257 | if (val != IMX258_INPUT_CLOCK_FREQ) { | 1392 | |
| 1258 | dev_err(&client->dev, "input clock frequency not supported\n"); | 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 | return -EINVAL; | 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 | /* Initialize subdev */ | 1453 | /* Initialize subdev */ |
| 1263 | v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); | 1454 | v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops); |
| 1264 | 1455 | ||
| 1265 | /* Will be powered off via pm_runtime_idle */ | 1456 | /* Will be powered off via pm_runtime_idle */ |
| 1266 | ret = imx258_power_on(&client->dev); | 1457 | ret = imx258_power_on(&client->dev); |
| 1267 | if (ret) | 1458 | if (ret) |
| 1268 | return ret; | 1459 | goto error_endpoint_free; |
| 1269 | 1460 | ||
| 1270 | /* Check module identity */ | 1461 | /* Check module identity */ |
| 1271 | ret = imx258_identify_module(imx258); | 1462 | ret = imx258_identify_module(imx258); |
| @@ -1298,6 +1489,7 @@ static int imx258_probe(struct i2c_client *client) · 26 unmodified lines | |||
| 1298 | pm_runtime_set_active(&client->dev); | 1489 | pm_runtime_set_active(&client->dev); |
| 1299 | pm_runtime_enable(&client->dev); | 1490 | pm_runtime_enable(&client->dev); |
| 1300 | pm_runtime_idle(&client->dev); | 1491 | pm_runtime_idle(&client->dev); |
| 1492 | v4l2_fwnode_endpoint_free(&ep); | ||
| 1301 | 1493 | ||
| 1302 | return 0; | 1494 | return 0; |
| 1303 | 1495 | ||
| @@ -1310,6 +1502,9 @@ error_handler_free: · 6 unmodified lines | |||
| 1310 | error_identify: | 1502 | error_identify: |
| 1311 | imx258_power_off(&client->dev); | 1503 | imx258_power_off(&client->dev); |
| 1312 | 1504 | ||
| 1505 | error_endpoint_free: | ||
| 1506 | v4l2_fwnode_endpoint_free(&ep); | ||
| 1507 | |||
| 1313 | return ret; | 1508 | return ret; |
| 1314 | } | 1509 | } |
| 1315 | 1510 | ||
| @@ -1342,7 +1537,8 @@ MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids); · 26 unmodified lines | |||
| 1342 | #endif | 1537 | #endif |
| 1343 | 1538 | ||
| 1344 | static const struct of_device_id imx258_dt_ids[] = { | 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 | { /* sentinel */ } | 1542 | { /* sentinel */ } |
| 1347 | }; | 1543 | }; |
| 1348 | MODULE_DEVICE_TABLE(of, imx258_dt_ids); | 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 | static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) | 543 | static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) |
| 544 | { | 544 | { |
| 545 | u32 lpfr, shutter; | 545 | u32 lpfr; |
| 546 | int ret; | 546 | int ret; |
| 547 | 547 | ||
| 548 | lpfr = imx412->vblank + imx412->cur_mode->height; | 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", | 550 | dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u", |
| 552 | exposure, gain, shutter, lpfr); | 551 | exposure, gain, lpfr); |
| 553 | 552 | ||
| 554 | ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); | 553 | ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1); |
| 555 | if (ret) | 554 | if (ret) |
| @@ -559,7 +558,7 @@ static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain) · 3 unmodified lines | |||
| 559 | if (ret) | 558 | if (ret) |
| 560 | goto error_release_group_hold; | 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 | if (ret) | 562 | if (ret) |
| 564 | goto error_release_group_hold; | 563 | goto error_release_group_hold; |
| 565 | 564 | ||
| @@ -175,14 +175,6 @@ MODULE_LICENSE("GPL"); · 174 unmodified lines | |||
| 175 | * mga_dev : represents one ks0127 chip. | 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 | struct ks0127 { | 178 | struct ks0127 { |
| 187 | struct v4l2_subdev sd; | 179 | struct v4l2_subdev sd; |
| 188 | v4l2_std_id norm; | 180 | v4l2_std_id norm; |
| @@ -19,7 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <linux/i2c.h> | 19 | #include <linux/i2c.h> |
| 20 | #include <linux/i2c-mux.h> | 20 | #include <linux/i2c-mux.h> |
| 21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
| 22 | #include <linux/mutex.h> | ||
| 23 | #include <linux/of_graph.h> | 22 | #include <linux/of_graph.h> |
| 24 | #include <linux/regulator/consumer.h> | 23 | #include <linux/regulator/consumer.h> |
| 25 | #include <linux/slab.h> | 24 | #include <linux/slab.h> |
| @@ -198,12 +197,6 @@ struct max9286_priv { · 172 unmodified lines | |||
| 198 | struct v4l2_ctrl *pixelrate_ctrl; | 197 | struct v4l2_ctrl *pixelrate_ctrl; |
| 199 | unsigned int pixelrate; | 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 | unsigned int nsources; | 200 | unsigned int nsources; |
| 208 | unsigned int source_mask; | 201 | unsigned int source_mask; |
| 209 | unsigned int route_mask; | 202 | unsigned int route_mask; |
| @@ -576,11 +569,14 @@ static void max9286_set_video_format(struct max9286_priv *priv, · 366 unmodified lines | |||
| 576 | MAX9286_INVVS | MAX9286_HVSRC_D14); | 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 | u32 fsync; | 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 | * Special case, a null interval enables automatic FRAMESYNC | 581 | * Special case, a null interval enables automatic FRAMESYNC |
| 586 | * mode. FRAMESYNC is taken from the slowest link. | 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 | * The FRAMESYNC generator is configured with a period expressed as a | 592 | * The FRAMESYNC generator is configured with a period expressed as a |
| 597 | * number of PCLK periods. | 593 | * number of PCLK periods. |
| 598 | */ | 594 | */ |
| 599 | fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator, | 595 | fsync = div_u64((u64)priv->pixelrate * interval->numerator, |
| 600 | priv->interval.denominator); | 596 | interval->denominator); |
| 601 | 597 | ||
| 602 | dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync, | 598 | dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync, |
| 603 | priv->pixelrate); | 599 | priv->pixelrate); |
| @@ -788,22 +784,25 @@ static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv) · 184 unmodified lines | |||
| 788 | static int max9286_s_stream(struct v4l2_subdev *sd, int enable) | 784 | static int max9286_s_stream(struct v4l2_subdev *sd, int enable) |
| 789 | { | 785 | { |
| 790 | struct max9286_priv *priv = sd_to_max9286(sd); | 786 | struct max9286_priv *priv = sd_to_max9286(sd); |
| 787 | struct v4l2_subdev_state *state; | ||
| 791 | struct max9286_source *source; | 788 | struct max9286_source *source; |
| 792 | unsigned int i; | 789 | unsigned int i; |
| 793 | bool sync = false; | 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 | if (enable) { | 795 | if (enable) { |
| 797 | const struct v4l2_mbus_framefmt *format; | 796 | const struct v4l2_mbus_framefmt *format; |
| 798 | 797 | ||
| 799 | /* | 798 | /* |
| 800 | * Get the format from the first used sink pad, as all sink | 799 | * Get the format from the source pad, as all formats must be |
| 801 | * formats must be identical. | 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 | max9286_set_video_format(priv, format); | 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 | * The frame sync between cameras is transmitted across the | 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 | for_each_source(priv, source) { | 815 | for_each_source(priv, source) { |
| 817 | ret = v4l2_subdev_call(source->sd, video, s_stream, 1); | 816 | ret = v4l2_subdev_call(source->sd, video, s_stream, 1); |
| 818 | if (ret) | 817 | if (ret) |
| 819 | return ret; | 818 | goto unlock; |
| 820 | } | 819 | } |
| 821 | 820 | ||
| 822 | ret = max9286_check_video_links(priv); | 821 | ret = max9286_check_video_links(priv); |
| 823 | if (ret) | 822 | if (ret) |
| 824 | return ret; | 823 | goto unlock; |
| 825 | 824 | ||
| 826 | /* | 825 | /* |
| 827 | * Wait until frame synchronization is locked. | 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 | if (!sync) { | 841 | if (!sync) { |
| 843 | dev_err(&priv->client->dev, | 842 | dev_err(&priv->client->dev, |
| 844 | "Failed to get frame synchronization\n"); | 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 | max9286_i2c_mux_close(priv); | 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 | static int max9286_get_frame_interval(struct v4l2_subdev *sd, | 874 | static int max9286_get_frame_interval(struct v4l2_subdev *sd, |
| 872 | struct v4l2_subdev_state *sd_state, | 875 | struct v4l2_subdev_state *sd_state, |
| 873 | struct v4l2_subdev_frame_interval *interval) | 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 | if (interval->pad != MAX9286_SRC_PAD) | 878 | if (interval->pad != MAX9286_SRC_PAD) |
| 885 | return -EINVAL; | 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 | return 0; | 884 | return 0; |
| 890 | } | 885 | } |
| @@ -893,19 +888,11 @@ static int max9286_set_frame_interval(struct v4l2_subdev *sd, · 2 unmodified lines | |||
| 893 | struct v4l2_subdev_state *sd_state, | 888 | struct v4l2_subdev_state *sd_state, |
| 894 | struct v4l2_subdev_frame_interval *interval) | 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 | if (interval->pad != MAX9286_SRC_PAD) | 891 | if (interval->pad != MAX9286_SRC_PAD) |
| 906 | return -EINVAL; | 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 | return 0; | 897 | return 0; |
| 911 | } | 898 | } |
| @@ -914,39 +901,28 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd, · 2 unmodified lines | |||
| 914 | struct v4l2_subdev_state *sd_state, | 901 | struct v4l2_subdev_state *sd_state, |
| 915 | struct v4l2_subdev_mbus_code_enum *code) | 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 | return -EINVAL; | 905 | return -EINVAL; |
| 919 | 906 | ||
| 920 | code->code = MEDIA_BUS_FMT_UYVY8_1X16; | 907 | code->code = max9286_formats[code->index].code; |
| 921 | 908 | ||
| 922 | return 0; | 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 | static int max9286_set_fmt(struct v4l2_subdev *sd, | 912 | static int max9286_set_fmt(struct v4l2_subdev *sd, |
| 941 | struct v4l2_subdev_state *sd_state, | 913 | struct v4l2_subdev_state *state, |
| 942 | struct v4l2_subdev_format *format) | 914 | struct v4l2_subdev_format *format) |
| 943 | { | 915 | { |
| 944 | struct max9286_priv *priv = sd_to_max9286(sd); | 916 | struct max9286_priv *priv = sd_to_max9286(sd); |
| 945 | struct v4l2_mbus_framefmt *cfg_fmt; | 917 | struct max9286_source *source; |
| 946 | unsigned int i; | 918 | unsigned int i; |
| 947 | 919 | ||
| 920 | /* | ||
| 921 | * Disable setting format on the source pad: format is propagated | ||
| 922 | * from the sinks. | ||
| 923 | */ | ||
| 948 | if (format->pad == MAX9286_SRC_PAD) | 924 | if (format->pad == MAX9286_SRC_PAD) |
| 949 | return -EINVAL; | 925 | return v4l2_subdev_get_fmt(sd, state, format); |
| 950 | 926 | ||
| 951 | /* Validate the format. */ | 927 | /* Validate the format. */ |
| 952 | for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) { | 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 | if (i == ARRAY_SIZE(max9286_formats)) | 933 | if (i == ARRAY_SIZE(max9286_formats)) |
| 958 | format->format.code = max9286_formats[0].code; | 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 | 937 | * Apply the same format on all the other pad as all links must have the |
| 982 | * format of the first bound link. All links must have the same format, | 938 | * same format. |
| 983 | * as we do not support mixing and matching of cameras connected to the | ||
| 984 | * max9286. | ||
| 985 | */ | 939 | */ |
| 986 | if (pad == MAX9286_SRC_PAD) | 940 | for_each_source(priv, source) { |
| 987 | pad = __ffs(priv->bound_sources); | 941 | unsigned int index = to_index(priv, source); |
| 988 | 942 | ||
| 989 | cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which); | 943 | *v4l2_subdev_state_get_format(state, index) = format->format; |
| 990 | if (!cfg_fmt) | 944 | } |
| 991 | return -EINVAL; | ||
| 992 | 945 | ||
| 993 | mutex_lock(&priv->mutex); | 946 | *v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD) = format->format; |
| 994 | format->format = *cfg_fmt; | ||
| 995 | mutex_unlock(&priv->mutex); | ||
| 996 | 947 | ||
| 997 | return 0; | 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 | static const struct v4l2_subdev_pad_ops max9286_pad_ops = { | 955 | static const struct v4l2_subdev_pad_ops max9286_pad_ops = { |
| 1005 | .enum_mbus_code = max9286_enum_mbus_code, | 956 | .enum_mbus_code = max9286_enum_mbus_code, |
| 1006 | .get_fmt = max9286_get_fmt, | 957 | .get_fmt = v4l2_subdev_get_fmt, |
| 1007 | .set_fmt = max9286_set_fmt, | 958 | .set_fmt = max9286_set_fmt, |
| 1008 | .get_frame_interval = max9286_get_frame_interval, | 959 | .get_frame_interval = max9286_get_frame_interval, |
| 1009 | .set_frame_interval = max9286_set_frame_interval, | 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 | .xfer_func = V4L2_XFER_FUNC_DEFAULT, | 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; | 982 | struct v4l2_fract *interval; |
| 1031 | } | ||
| 1032 | 983 | ||
| 1033 | static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh) | 984 | for (unsigned int i = 0; i < MAX9286_N_PADS; i++) |
| 1034 | { | 985 | *v4l2_subdev_state_get_format(state, i) = max9286_default_format; |
| 1035 | struct v4l2_mbus_framefmt *format; | ||
| 1036 | unsigned int i; | ||
| 1037 | 986 | ||
| 1038 | for (i = 0; i < MAX9286_N_SINKS; i++) { | 987 | /* |
| 1039 | format = v4l2_subdev_state_get_format(fh->state, i); | 988 | * Special case: a null interval enables automatic FRAMESYNC mode. |
| 1040 | max9286_init_format(format); | 989 | * |
| 1041 | } | 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 | return 0; | 997 | return 0; |
| 1044 | } | 998 | } |
| 1045 | 999 | ||
| 1046 | static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = { | 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 | static const struct media_entity_operations max9286_media_ops = { | 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 | /* Configure V4L2 for the MAX9286 itself */ | 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 | v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops); | 1036 | v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops); |
| 1087 | priv->sd.internal_ops = &max9286_subdev_internal_ops; | 1037 | priv->sd.internal_ops = &max9286_subdev_internal_ops; |
| 1088 | priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE; | 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 | if (ret) | 1059 | if (ret) |
| 1110 | goto err_async; | 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 | ret = v4l2_async_register_subdev(&priv->sd); | 1067 | ret = v4l2_async_register_subdev(&priv->sd); |
| 1113 | if (ret < 0) { | 1068 | if (ret < 0) { |
| 1114 | dev_err(dev, "Unable to register subdevice\n"); | 1069 | dev_err(dev, "Unable to register subdevice\n"); |
| 1115 | goto err_async; | 1070 | goto err_subdev; |
| 1116 | } | 1071 | } |
| 1117 | 1072 | ||
| 1118 | return 0; | 1073 | return 0; |
| 1119 | 1074 | ||
| 1075 | err_subdev: | ||
| 1076 | v4l2_subdev_cleanup(&priv->sd); | ||
| 1120 | err_async: | 1077 | err_async: |
| 1121 | v4l2_ctrl_handler_free(&priv->ctrls); | 1078 | v4l2_ctrl_handler_free(&priv->ctrls); |
| 1122 | max9286_v4l2_notifier_unregister(priv); | 1079 | max9286_v4l2_notifier_unregister(priv); |
| @@ -1126,6 +1083,7 @@ err_async: · 3 unmodified lines | |||
| 1126 | 1083 | ||
| 1127 | static void max9286_v4l2_unregister(struct max9286_priv *priv) | 1084 | static void max9286_v4l2_unregister(struct max9286_priv *priv) |
| 1128 | { | 1085 | { |
| 1086 | v4l2_subdev_cleanup(&priv->sd); | ||
| 1129 | v4l2_ctrl_handler_free(&priv->ctrls); | 1087 | v4l2_ctrl_handler_free(&priv->ctrls); |
| 1130 | v4l2_async_unregister_subdev(&priv->sd); | 1088 | v4l2_async_unregister_subdev(&priv->sd); |
| 1131 | max9286_v4l2_notifier_unregister(priv); | 1089 | max9286_v4l2_notifier_unregister(priv); |
| @@ -1182,7 +1140,6 @@ static int max9286_setup(struct max9286_priv *priv) · 50 unmodified lines | |||
| 1182 | max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); | 1140 | max9286_write(priv, 0x69, (0xf & ~priv->route_mask)); |
| 1183 | 1141 | ||
| 1184 | max9286_set_video_format(priv, &max9286_default_format); | 1142 | max9286_set_video_format(priv, &max9286_default_format); |
| 1185 | max9286_set_fsync_period(priv); | ||
| 1186 | 1143 | ||
| 1187 | cfg = max9286_read(priv, 0x1c); | 1144 | cfg = max9286_read(priv, 0x1c); |
| 1188 | if (cfg < 0) | 1145 | if (cfg < 0) |
| @@ -1629,8 +1586,6 @@ static int max9286_probe(struct i2c_client *client) · 440 unmodified lines | |||
| 1629 | if (!priv) | 1586 | if (!priv) |
| 1630 | return -ENOMEM; | 1587 | return -ENOMEM; |
| 1631 | 1588 | ||
| 1632 | mutex_init(&priv->mutex); | ||
| 1633 | |||
| 1634 | priv->client = client; | 1589 | priv->client = client; |
| 1635 | 1590 | ||
| 1636 | /* GPIO values default to high */ | 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 | if (ret < 0) | 971 | if (ret < 0) |
| 972 | return ret; | 972 | return ret; |
| 973 | 973 | ||
| 974 | v4l2_ctrl_handler_init(hdl, 5); | 974 | v4l2_ctrl_handler_init(hdl, 11); |
| 975 | 975 | ||
| 976 | hdl->lock = &sensor->lock; | 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 | struct v4l2_fwnode_endpoint bus_cfg = { | 1360 | struct v4l2_fwnode_endpoint bus_cfg = { |
| 1361 | .bus_type = V4L2_MBUS_CSI2_DPHY, | 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 | int ret; | 1365 | int ret; |
| 1365 | 1366 | ||
| 1366 | ep = of_graph_get_endpoint_by_regs(np, 0, -1); | ||
| 1367 | if (!ep) | 1367 | if (!ep) |
| 1368 | return -EINVAL; | 1368 | return -EINVAL; |
| 1369 | 1369 | ||
| 1370 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); | 1370 | ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg); |
| 1371 | if (ret) | 1371 | if (ret) |
| 1372 | goto out; | 1372 | return ret; |
| 1373 | 1373 | ||
| 1374 | sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags & | 1374 | sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags & |
| 1375 | V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; | 1375 | V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK; |
| 1376 | 1376 | ||
| 1377 | out: | 1377 | return 0; |
| 1378 | of_node_put(ep); | ||
| 1379 | |||
| 1380 | return ret; | ||
| 1381 | } | 1378 | } |
| 1382 | 1379 | ||
| 1383 | static int ov5647_probe(struct i2c_client *client) | 1380 | static int ov5647_probe(struct i2c_client *client) |
| @@ -141,7 +141,6 @@ struct ov5693_device { · 140 unmodified lines | |||
| 141 | 141 | ||
| 142 | struct gpio_desc *reset; | 142 | struct gpio_desc *reset; |
| 143 | struct gpio_desc *powerdown; | 143 | struct gpio_desc *powerdown; |
| 144 | struct gpio_desc *privacy_led; | ||
| 145 | struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; | 144 | struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES]; |
| 146 | struct clk *xvclk; | 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 | static void ov5693_sensor_powerdown(struct ov5693_device *ov5693) | 657 | static void ov5693_sensor_powerdown(struct ov5693_device *ov5693) |
| 659 | { | 658 | { |
| 660 | gpiod_set_value_cansleep(ov5693->privacy_led, 0); | ||
| 661 | gpiod_set_value_cansleep(ov5693->reset, 1); | 659 | gpiod_set_value_cansleep(ov5693->reset, 1); |
| 662 | gpiod_set_value_cansleep(ov5693->powerdown, 1); | 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 | gpiod_set_value_cansleep(ov5693->powerdown, 0); | 686 | gpiod_set_value_cansleep(ov5693->powerdown, 0); |
| 689 | gpiod_set_value_cansleep(ov5693->reset, 0); | 687 | gpiod_set_value_cansleep(ov5693->reset, 0); |
| 690 | gpiod_set_value_cansleep(ov5693->privacy_led, 1); | ||
| 691 | 688 | ||
| 692 | usleep_range(5000, 7500); | 689 | usleep_range(5000, 7500); |
| 693 | 690 | ||
| @@ -1201,13 +1198,6 @@ static int ov5693_configure_gpios(struct ov5693_device *ov5693) · 507 unmodified lines | |||
| 1201 | return PTR_ERR(ov5693->powerdown); | 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 | return 0; | 1201 | return 0; |
| 1212 | } | 1202 | } |
| 1213 | 1203 | ||
| @@ -212,11 +212,6 @@ · 211 unmodified lines | |||
| 212 | * structure | 212 | * structure |
| 213 | */ | 213 | */ |
| 214 | 214 | ||
| 215 | struct regval_list { | ||
| 216 | unsigned char reg_num; | ||
| 217 | unsigned char value; | ||
| 218 | }; | ||
| 219 | |||
| 220 | struct tw9910_scale_ctrl { | 215 | struct tw9910_scale_ctrl { |
| 221 | char *name; | 216 | char *name; |
| 222 | unsigned short width; | 217 | unsigned short width; |
| @@ -95,4 +95,5 @@ static struct i2c_driver uda1342_driver = { · 94 unmodified lines | |||
| 95 | 95 | ||
| 96 | module_i2c_driver(uda1342_driver); | 96 | module_i2c_driver(uda1342_driver); |
| 97 | 97 | ||
| 98 | MODULE_DESCRIPTION("Philips UDA1342 audio codec driver"); | ||
| 98 | MODULE_LICENSE("GPL v2"); | 99 | MODULE_LICENSE("GPL v2"); |
| @@ -1878,7 +1878,7 @@ static const struct dev_pm_ops vgxy61_pm_ops = { · 1877 unmodified lines | |||
| 1878 | 1878 | ||
| 1879 | static struct i2c_driver vgxy61_i2c_driver = { | 1879 | static struct i2c_driver vgxy61_i2c_driver = { |
| 1880 | .driver = { | 1880 | .driver = { |
| 1881 | .name = "st-vgxy61", | 1881 | .name = "vgxy61", |
| 1882 | .of_match_table = vgxy61_dt_ids, | 1882 | .of_match_table = vgxy61_dt_ids, |
| 1883 | .pm = &vgxy61_pm_ops, | 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 | if (astat & BT878_ARISCI) { | 301 | if (astat & BT878_ARISCI) { |
| 302 | bt->finished_block = (stat & BT878_ARISCS) >> 28; | 302 | bt->finished_block = (stat & BT878_ARISCS) >> 28; |
| 303 | if (bt->tasklet.callback) | 303 | if (bt->bh_work.func) |
| 304 | tasklet_schedule(&bt->tasklet); | 304 | queue_work(system_bh_wq, &bt->bh_work); |
| 305 | break; | 305 | break; |
| 306 | } | 306 | } |
| 307 | count++; | 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 | btwrite(0, BT878_AINT_MASK); | 478 | btwrite(0, BT878_AINT_MASK); |
| 479 | bt878_num++; | 479 | bt878_num++; |
| 480 | 480 | ||
| 481 | if (!bt->tasklet.func) | 481 | if (!bt->bh_work.func) |
| 482 | tasklet_disable(&bt->tasklet); | 482 | disable_work_sync(&bt->bh_work); |
| 483 | 483 | ||
| 484 | return 0; | 484 | return 0; |
| 485 | 485 | ||
| @@ -563,4 +563,5 @@ static void __exit bt878_cleanup_module(void) · 77 unmodified lines | |||
| 563 | module_init(bt878_init_module); | 563 | module_init(bt878_init_module); |
| 564 | module_exit(bt878_cleanup_module); | 564 | module_exit(bt878_cleanup_module); |
| 565 | 565 | ||
| 566 | MODULE_DESCRIPTION("DVB/ATSC Support for bt878 based TV cards"); | ||
| 566 | MODULE_LICENSE("GPL"); | 567 | MODULE_LICENSE("GPL"); |
| @@ -14,6 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <linux/sched.h> | 14 | #include <linux/sched.h> |
| 15 | #include <linux/spinlock.h> | 15 | #include <linux/spinlock.h> |
| 16 | #include <linux/mutex.h> | 16 | #include <linux/mutex.h> |
| 17 | #include <linux/workqueue.h> | ||
| 17 | 18 | ||
| 18 | #include "bt848.h" | 19 | #include "bt848.h" |
| 19 | #include "bttv.h" | 20 | #include "bttv.h" |
| @@ -120,7 +121,7 @@ struct bt878 { · 100 unmodified lines | |||
| 120 | dma_addr_t risc_dma; | 121 | dma_addr_t risc_dma; |
| 121 | u32 risc_pos; | 122 | u32 risc_pos; |
| 122 | 123 | ||
| 123 | struct tasklet_struct tasklet; | 124 | struct work_struct bh_work; |
| 124 | int shutdown; | 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 | #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ | 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 | struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev); | 45 | struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev); |
| 46 | 46 | ||
| 47 | dprintk("%d\n", card->bt->finished_block); | 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 | goto err_disconnect_frontend; | 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 | frontend_init(card, type); | 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 | dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); | 922 | dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr); |
| 923 | 923 | ||
| 924 | bt878_stop(card->bt); | 924 | bt878_stop(card->bt); |
| 925 | tasklet_kill(&card->bt->tasklet); | 925 | cancel_work_sync(&card->bt->bh_work); |
| 926 | dvb_net_release(&card->dvbnet); | 926 | dvb_net_release(&card->dvbnet); |
| 927 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); | 927 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem); |
| 928 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); | 928 | card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); |
| @@ -258,7 +258,7 @@ struct cx18_scb { · 257 unmodified lines | |||
| 258 | struct cx18_mailbox ppu2epu_mb; | 258 | struct cx18_mailbox ppu2epu_mb; |
| 259 | 259 | ||
| 260 | struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS]; | 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 | void cx18_init_scb(struct cx18 *cx); | 264 | void cx18_init_scb(struct cx18 *cx); |
| @@ -298,7 +298,7 @@ struct ddb_link { · 297 unmodified lines | |||
| 298 | spinlock_t lock; /* lock link access */ | 298 | spinlock_t lock; /* lock link access */ |
| 299 | struct mutex flash_mutex; /* lock flash access */ | 299 | struct mutex flash_mutex; /* lock flash access */ |
| 300 | struct ddb_lnb lnb; | 300 | struct ddb_lnb lnb; |
| 301 | struct tasklet_struct tasklet; | 301 | struct work_struct bh_work; |
| 302 | struct ddb_ids ids; | 302 | struct ddb_ids ids; |
| 303 | 303 | ||
| 304 | spinlock_t temp_lock; /* lock temp chip access */ | 304 | spinlock_t temp_lock; /* lock temp chip access */ |
| @@ -43,28 +43,46 @@ · 42 unmodified lines | |||
| 43 | * becoming apparent in the future. | 43 | * becoming apparent in the future. |
| 44 | * | 44 | * |
| 45 | * Do not add an entry for a sensor that is not actually supported. | 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 | static const struct ipu_sensor_config ipu_supported_sensors[] = { | 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 | /* Omnivision OV5693 */ | 58 | /* Omnivision OV5693 */ |
| 49 | IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), | 59 | IPU_SENSOR_CONFIG("INT33BE", 1, 419200000), |
| 60 | /* Omnivision OV2740 */ | ||
| 61 | IPU_SENSOR_CONFIG("INT3474", 1, 180000000), | ||
| 50 | /* Omnivision OV8865 */ | 62 | /* Omnivision OV8865 */ |
| 51 | IPU_SENSOR_CONFIG("INT347A", 1, 360000000), | 63 | IPU_SENSOR_CONFIG("INT347A", 1, 360000000), |
| 52 | /* Omnivision OV7251 */ | 64 | /* Omnivision OV7251 */ |
| 53 | IPU_SENSOR_CONFIG("INT347E", 1, 319200000), | 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 | /* Omnivision OV2680 */ | 82 | /* Omnivision OV2680 */ |
| 55 | IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), | 83 | IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000), |
| 56 | /* Omnivision ov8856 */ | 84 | /* Omnivision OV8856 */ |
| 57 | IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000), | 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 | static const struct ipu_property_names prop_names = { | 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 | writel(ENTRY, isp->base + ipc->csr_out); | 163 | writel(ENTRY, isp->base + ipc->csr_out); |
| 164 | break; | 164 | break; |
| 165 | default: | 165 | default: |
| 166 | dev_warn_ratelimited(&isp->pdev->dev, | 166 | dev_dbg_ratelimited(&isp->pdev->dev, |
| 167 | "Unexpected CSR 0x%x\n", val); | 167 | "Unexpected CSR 0x%x\n", val); |
| 168 | break; | 168 | break; |
| 169 | } | 169 | } |
| 170 | } while (retries--); | 170 | } while (retries--); |
| @@ -345,42 +345,61 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd, · 344 unmodified lines | |||
| 345 | return ret; | 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 | struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd); | 352 | struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd); |
| 351 | struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd); | 353 | struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd); |
| 352 | struct device *dev = &csi2->isys->adev->auxdev.dev; | ||
| 353 | struct ipu6_isys_csi2_timing timing = { }; | 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 | int ret; | 358 | int ret; |
| 356 | 359 | ||
| 357 | dev_dbg(dev, "csi2 stream %s callback\n", enable ? "on" : "off"); | 360 | remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]); |
| 358 | 361 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); | |
| 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 | } | ||
| 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 | ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV); | 367 | ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV); |
| 376 | if (ret) | 368 | if (ret) |
| 377 | return ret; | 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 | if (ret) | 372 | if (ret) |
| 381 | return ret; | 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 | return 0; | 404 | return 0; |
| 386 | } | 405 | } |
| @@ -475,10 +494,6 @@ static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd, · 88 unmodified lines | |||
| 475 | return ret; | 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 | static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = { | 497 | static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = { |
| 483 | .get_fmt = v4l2_subdev_get_fmt, | 498 | .get_fmt = v4l2_subdev_get_fmt, |
| 484 | .set_fmt = ipu6_isys_subdev_set_fmt, | 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 | .set_selection = ipu6_isys_csi2_set_sel, | 501 | .set_selection = ipu6_isys_csi2_set_sel, |
| 487 | .enum_mbus_code = ipu6_isys_subdev_enum_mbus_code, | 502 | .enum_mbus_code = ipu6_isys_subdev_enum_mbus_code, |
| 488 | .set_routing = ipu6_isys_subdev_set_routing, | 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 | static const struct v4l2_subdev_ops csi2_sd_ops = { | 508 | static const struct v4l2_subdev_ops csi2_sd_ops = { |
| 492 | .core = &csi2_sd_core_ops, | 509 | .core = &csi2_sd_core_ops, |
| 493 | .video = &csi2_sd_video_ops, | ||
| 494 | .pad = &csi2_sd_pad_ops, | 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 | return 0; | 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 | u32 receiver_errors; | 45 | u32 receiver_errors; |
| 46 | unsigned int nlanes; | 46 | unsigned int nlanes; |
| 47 | unsigned int port; | 47 | unsigned int port; |
| 48 | unsigned int stream_count; | ||
| 49 | }; | 48 | }; |
| 50 | 49 | ||
| 51 | struct ipu6_isys_csi2_timing { | 50 | struct ipu6_isys_csi2_timing { |
| @@ -77,6 +76,5 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream, · 25 unmodified lines | |||
| 77 | struct ipu6_isys_csi2 *csi2, | 76 | struct ipu6_isys_csi2 *csi2, |
| 78 | struct media_entity *source_entity, | 77 | struct media_entity *source_entity, |
| 79 | struct v4l2_mbus_frame_desc_entry *entry); | 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 | #endif /* IPU6_ISYS_CSI2_H */ | 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 | stream->nr_queues); | 551 | stream->nr_queues); |
| 552 | 552 | ||
| 553 | list_add(&aq->node, &stream->queues); | 553 | list_add(&aq->node, &stream->queues); |
| 554 | ipu6_isys_set_csi2_streams_status(av, true); | ||
| 555 | ipu6_isys_configure_stream_watermark(av, true); | 554 | ipu6_isys_configure_stream_watermark(av, true); |
| 556 | ipu6_isys_update_stream_watermark(av, true); | 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 | struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); | 597 | struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq); |
| 599 | struct ipu6_isys_stream *stream = av->stream; | 598 | struct ipu6_isys_stream *stream = av->stream; |
| 600 | 599 | ||
| 601 | ipu6_isys_set_csi2_streams_status(av, false); | ||
| 602 | |||
| 603 | mutex_lock(&stream->mutex); | 600 | mutex_lock(&stream->mutex); |
| 604 | 601 | ||
| 605 | ipu6_isys_update_stream_watermark(av, false); | 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 | struct v4l2_subdev_state *subdev_state; | 990 | struct v4l2_subdev_state *subdev_state; |
| 991 | struct device *dev = &av->isys->adev->auxdev.dev; | 991 | struct device *dev = &av->isys->adev->auxdev.dev; |
| 992 | struct v4l2_subdev *sd; | 992 | struct v4l2_subdev *sd; |
| 993 | struct v4l2_subdev *ssd; | ||
| 994 | struct media_pad *r_pad; | 993 | struct media_pad *r_pad; |
| 995 | struct media_pad *s_pad; | ||
| 996 | u32 sink_pad, sink_stream; | 994 | u32 sink_pad, sink_stream; |
| 997 | u64 r_stream; | 995 | u64 r_stream; |
| 998 | u64 stream_mask = 0; | 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 | if (WARN(!stream->source_entity, "No source entity for stream\n")) | 1001 | if (WARN(!stream->source_entity, "No source entity for stream\n")) |
| 1004 | return -ENODEV; | 1002 | return -ENODEV; |
| 1005 | 1003 | ||
| 1006 | ssd = media_entity_to_v4l2_subdev(stream->source_entity); | ||
| 1007 | sd = &stream->asd->sd; | 1004 | sd = &stream->asd->sd; |
| 1008 | r_pad = media_pad_remote_pad_first(&av->pad); | 1005 | r_pad = media_pad_remote_pad_first(&av->pad); |
| 1009 | r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index); | 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 | if (ret) | 1014 | if (ret) |
| 1018 | return ret; | 1015 | return ret; |
| 1019 | 1016 | ||
| 1020 | s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]); | ||
| 1021 | |||
| 1022 | stream_mask = get_stream_mask_by_pipeline(av); | 1017 | stream_mask = get_stream_mask_by_pipeline(av); |
| 1023 | if (!state) { | 1018 | if (!state) { |
| 1024 | stop_streaming_firmware(av); | 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 | /* stop sub-device which connects with video */ | 1021 | /* stop sub-device which connects with video */ |
| 1038 | dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name, | 1022 | dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n", |
| 1039 | r_pad->index); | 1023 | sd->name, r_pad->index, stream_mask); |
| 1040 | ret = v4l2_subdev_call(sd, video, s_stream, state); | 1024 | ret = v4l2_subdev_disable_streams(sd, r_pad->index, |
| 1025 | stream_mask); | ||
| 1041 | if (ret) { | 1026 | if (ret) { |
| 1042 | dev_err(dev, "stream off %s failed with %d\n", sd->name, | 1027 | dev_err(dev, "stream off %s failed with %d\n", sd->name, |
| 1043 | ret); | 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 | /* start sub-device which connects with video */ | 1039 | /* start sub-device which connects with video */ |
| 1055 | dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index); | 1040 | dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name, |
| 1056 | ret = v4l2_subdev_call(sd, video, s_stream, state); | 1041 | r_pad->index, stream_mask); |
| 1042 | ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask); | ||
| 1057 | if (ret) { | 1043 | if (ret) { |
| 1058 | dev_err(dev, "stream on %s failed with %d\n", sd->name, | 1044 | dev_err(dev, "stream on %s failed with %d\n", sd->name, |
| 1059 | ret); | 1045 | ret); |
| 1060 | goto out_media_entity_stop_streaming_firmware; | 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 | av->streaming = state; | 1050 | av->streaming = state; |
| 1077 | 1051 | ||
| 1078 | return 0; | 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 | out_media_entity_stop_streaming_firmware: | 1054 | out_media_entity_stop_streaming_firmware: |
| 1084 | stop_streaming_firmware(av); | 1055 | stop_streaming_firmware(av); |
| 1085 | 1056 | ||
| @@ -126,6 +126,8 @@ struct mei_csi { · 125 unmodified lines | |||
| 126 | struct v4l2_ctrl_handler ctrl_handler; | 126 | struct v4l2_ctrl_handler ctrl_handler; |
| 127 | struct v4l2_ctrl *freq_ctrl; | 127 | struct v4l2_ctrl *freq_ctrl; |
| 128 | struct v4l2_ctrl *privacy_ctrl; | 128 | struct v4l2_ctrl *privacy_ctrl; |
| 129 | /* lock for v4l2 controls */ | ||
| 130 | struct mutex ctrl_lock; | ||
| 129 | unsigned int remote_pad; | 131 | unsigned int remote_pad; |
| 130 | /* start streaming or not */ | 132 | /* start streaming or not */ |
| 131 | int streaming; | 133 | int streaming; |
| @@ -136,9 +138,6 @@ struct mei_csi { · 4 unmodified lines | |||
| 136 | u32 nr_of_lanes; | 138 | u32 nr_of_lanes; |
| 137 | /* frequency of the CSI-2 link */ | 139 | /* frequency of the CSI-2 link */ |
| 138 | u64 link_freq; | 140 | u64 link_freq; |
| 139 | |||
| 140 | /* privacy status */ | ||
| 141 | enum ivsc_privacy_status status; | ||
| 142 | }; | 141 | }; |
| 143 | 142 | ||
| 144 | static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = { | 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 | /* command response status */ | 190 | /* command response status */ |
| 192 | ret = csi->cmd_response.status; | 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 | ret = -EINVAL; | 197 | ret = -EINVAL; |
| 195 | goto out; | 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 | switch (notif.cmd_id) { | 269 | switch (notif.cmd_id) { |
| 267 | case CSI_PRIVACY_NOTIF: | 270 | case CSI_PRIVACY_NOTIF: |
| 268 | if (notif.cont.cont < CSI_PRIVACY_MAX) { | 271 | if (notif.cont.cont < CSI_PRIVACY_MAX) |
| 269 | csi->status = notif.cont.cont; | 272 | v4l2_ctrl_s_ctrl(csi->privacy_ctrl, |
| 270 | v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status); | 273 | notif.cont.cont == CSI_PRIVACY_ON); |
| 271 | } | ||
| 272 | break; | 274 | break; |
| 273 | case CSI_SET_OWNER: | 275 | case CSI_SET_OWNER: |
| 274 | case CSI_SET_CONF: | 276 | case CSI_SET_CONF: |
| @@ -559,11 +561,13 @@ static int mei_csi_init_controls(struct mei_csi *csi) · 284 unmodified lines | |||
| 559 | u32 max; | 561 | u32 max; |
| 560 | int ret; | 562 | int ret; |
| 561 | 563 | ||
| 564 | mutex_init(&csi->ctrl_lock); | ||
| 565 | |||
| 562 | ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2); | 566 | ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2); |
| 563 | if (ret) | 567 | if (ret) |
| 564 | return ret; | 568 | return ret; |
| 565 | 569 | ||
| 566 | csi->ctrl_handler.lock = &csi->lock; | 570 | csi->ctrl_handler.lock = &csi->ctrl_lock; |
| 567 | 571 | ||
| 568 | max = ARRAY_SIZE(link_freq_menu_items) - 1; | 572 | max = ARRAY_SIZE(link_freq_menu_items) - 1; |
| 569 | csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler, | 573 | csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler, |
| @@ -755,6 +759,7 @@ err_entity: · 185 unmodified lines | |||
| 755 | 759 | ||
| 756 | err_ctrl_handler: | 760 | err_ctrl_handler: |
| 757 | v4l2_ctrl_handler_free(&csi->ctrl_handler); | 761 | v4l2_ctrl_handler_free(&csi->ctrl_handler); |
| 762 | mutex_destroy(&csi->ctrl_lock); | ||
| 758 | v4l2_async_nf_unregister(&csi->notifier); | 763 | v4l2_async_nf_unregister(&csi->notifier); |
| 759 | v4l2_async_nf_cleanup(&csi->notifier); | 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 | v4l2_async_nf_unregister(&csi->notifier); | 779 | v4l2_async_nf_unregister(&csi->notifier); |
| 775 | v4l2_async_nf_cleanup(&csi->notifier); | 780 | v4l2_async_nf_cleanup(&csi->notifier); |
| 776 | v4l2_ctrl_handler_free(&csi->ctrl_handler); | 781 | v4l2_ctrl_handler_free(&csi->ctrl_handler); |
| 782 | mutex_destroy(&csi->ctrl_lock); | ||
| 777 | v4l2_async_unregister_subdev(&csi->subdev); | 783 | v4l2_async_unregister_subdev(&csi->subdev); |
| 778 | v4l2_subdev_cleanup(&csi->subdev); | 784 | v4l2_subdev_cleanup(&csi->subdev); |
| 779 | media_entity_cleanup(&csi->subdev.entity); | 785 | media_entity_cleanup(&csi->subdev.entity); |
| @@ -371,33 +371,6 @@ int ivtv_msleep_timeout(unsigned int msecs, int intr) · 370 unmodified lines | |||
| 371 | return 0; | 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 | /* Hauppauge card? get values from tveeprom */ | 374 | /* Hauppauge card? get values from tveeprom */ |
| 402 | void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv) | 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 | IVTV_DEBUG_INFO("Enabling pci device\n"); | 807 | IVTV_DEBUG_INFO("Enabling pci device\n"); |
| 835 | 808 | ||
| 836 | if (pci_enable_device(pdev)) { | 809 | if (pcim_enable_device(pdev)) { |
| 837 | IVTV_ERR("Can't enable device!\n"); | 810 | IVTV_ERR("Can't enable device!\n"); |
| 838 | return -EIO; | 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 | IVTV_ERR("No suitable DMA available.\n"); | 814 | IVTV_ERR("No suitable DMA available.\n"); |
| 842 | return -EIO; | 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 | IVTV_ERR("Cannot request encoder memory region.\n"); | 819 | IVTV_ERR("Cannot request encoder memory region.\n"); |
| 846 | return -EIO; | 820 | return -EIO; |
| 847 | } | 821 | } |
| 848 | 822 | ||
| 849 | if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET, | 823 | if (!devm_request_mem_region(&pdev->dev, |
| 850 | IVTV_REG_SIZE, "ivtv registers")) { | 824 | itv->base_addr + IVTV_REG_OFFSET, |
| 825 | IVTV_REG_SIZE, "ivtv registers")) { | ||
| 851 | IVTV_ERR("Cannot request register memory region.\n"); | 826 | IVTV_ERR("Cannot request register memory region.\n"); |
| 852 | release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE); | ||
| 853 | return -EIO; | 827 | return -EIO; |
| 854 | } | 828 | } |
| 855 | 829 | ||
| 856 | if (itv->has_cx23415 && | 830 | if (itv->has_cx23415 && |
| 857 | !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, | 831 | !devm_request_mem_region(&pdev->dev, |
| 858 | IVTV_DECODER_SIZE, "ivtv decoder")) { | 832 | itv->base_addr + IVTV_DECODER_OFFSET, |
| 833 | IVTV_DECODER_SIZE, "ivtv decoder")) { | ||
| 859 | IVTV_ERR("Cannot request decoder memory region.\n"); | 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 | return -EIO; | 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 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); | 843 | pci_read_config_word(pdev, PCI_COMMAND, &cmd); |
| 871 | if (!(cmd & PCI_COMMAND_MASTER)) { | 844 | if (!(cmd & PCI_COMMAND_MASTER)) { |
| 872 | IVTV_ERR("Bus Mastering is not enabled\n"); | 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 | return -ENXIO; | 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 | /* PCI Device Setup */ | 1002 | /* PCI Device Setup */ |
| 1035 | retval = ivtv_setup_pci(itv, pdev, pci_id); | 1003 | retval = ivtv_setup_pci(itv, pdev, pci_id); |
| 1036 | if (retval == -EIO) | 1004 | if (retval == -EIO || retval == -ENXIO) |
| 1037 | goto free_worker; | 1005 | goto free_worker; |
| 1038 | if (retval == -ENXIO) | ||
| 1039 | goto free_mem; | ||
| 1040 | 1006 | ||
| 1041 | /* map io memory */ | 1007 | /* map io memory */ |
| 1042 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", | 1008 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", |
| 1043 | (u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); | 1009 | (u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE); |
| 1044 | itv->enc_mem = ioremap(itv->base_addr + IVTV_ENCODER_OFFSET, | 1010 | itv->enc_mem = devm_ioremap(&pdev->dev, |
| 1045 | IVTV_ENCODER_SIZE); | 1011 | itv->base_addr + IVTV_ENCODER_OFFSET, |
| 1012 | IVTV_ENCODER_SIZE); | ||
| 1046 | if (!itv->enc_mem) { | 1013 | if (!itv->enc_mem) { |
| 1047 | IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 encoder memory\n"); | 1014 | IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 encoder memory\n"); |
| 1048 | IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of vmalloc address space for this window\n"); | 1015 | IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of vmalloc address space for this window\n"); |
| 1049 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); | 1016 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); |
| 1050 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); | 1017 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); |
| 1051 | retval = -ENOMEM; | 1018 | retval = -ENOMEM; |
| 1052 | goto free_mem; | 1019 | goto free_worker; |
| 1053 | } | 1020 | } |
| 1054 | 1021 | ||
| 1055 | if (itv->has_cx23415) { | 1022 | if (itv->has_cx23415) { |
| 1056 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", | 1023 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", |
| 1057 | (u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); | 1024 | (u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE); |
| 1058 | itv->dec_mem = ioremap(itv->base_addr + IVTV_DECODER_OFFSET, | 1025 | itv->dec_mem = devm_ioremap(&pdev->dev, |
| 1059 | IVTV_DECODER_SIZE); | 1026 | itv->base_addr + IVTV_DECODER_OFFSET, |
| 1027 | IVTV_DECODER_SIZE); | ||
| 1060 | if (!itv->dec_mem) { | 1028 | if (!itv->dec_mem) { |
| 1061 | IVTV_ERR("ioremap failed. Can't get a window into CX23415 decoder memory\n"); | 1029 | IVTV_ERR("ioremap failed. Can't get a window into CX23415 decoder memory\n"); |
| 1062 | IVTV_ERR("Each capture card with a CX23415 needs 8 MB of vmalloc address space for this window\n"); | 1030 | IVTV_ERR("Each capture card with a CX23415 needs 8 MB of vmalloc address space for this window\n"); |
| 1063 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); | 1031 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); |
| 1064 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); | 1032 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); |
| 1065 | retval = -ENOMEM; | 1033 | retval = -ENOMEM; |
| 1066 | goto free_mem; | 1034 | goto free_worker; |
| 1067 | } | 1035 | } |
| 1068 | } | 1036 | } |
| 1069 | else { | 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 | /* map registers memory */ | 1041 | /* map registers memory */ |
| 1074 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", | 1042 | IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n", |
| 1075 | (u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | 1043 | (u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); |
| 1076 | itv->reg_mem = | 1044 | itv->reg_mem = devm_ioremap(&pdev->dev, |
| 1077 | ioremap(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE); | 1045 | itv->base_addr + IVTV_REG_OFFSET, |
| 1046 | IVTV_REG_SIZE); | ||
| 1078 | if (!itv->reg_mem) { | 1047 | if (!itv->reg_mem) { |
| 1079 | IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 register space\n"); | 1048 | IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 register space\n"); |
| 1080 | IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of vmalloc address space for this window\n"); | 1049 | IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of vmalloc address space for this window\n"); |
| 1081 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); | 1050 | IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n"); |
| 1082 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); | 1051 | IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n"); |
| 1083 | retval = -ENOMEM; | 1052 | retval = -ENOMEM; |
| 1084 | goto free_io; | 1053 | goto free_worker; |
| 1085 | } | 1054 | } |
| 1086 | 1055 | ||
| 1087 | retval = ivtv_gpio_init(itv); | 1056 | retval = ivtv_gpio_init(itv); |
| 1088 | if (retval) | 1057 | if (retval) |
| 1089 | goto free_io; | 1058 | goto free_worker; |
| 1090 | 1059 | ||
| 1091 | /* active i2c */ | 1060 | /* active i2c */ |
| 1092 | IVTV_DEBUG_INFO("activating i2c...\n"); | 1061 | IVTV_DEBUG_INFO("activating i2c...\n"); |
| 1093 | if (init_ivtv_i2c(itv)) { | 1062 | if (init_ivtv_i2c(itv)) { |
| 1094 | IVTV_ERR("Could not initialize i2c\n"); | 1063 | IVTV_ERR("Could not initialize i2c\n"); |
| 1095 | goto free_io; | 1064 | goto free_worker; |
| 1096 | } | 1065 | } |
| 1097 | 1066 | ||
| 1098 | if (itv->card->hw_all & IVTV_HW_TVEEPROM) { | 1067 | if (itv->card->hw_all & IVTV_HW_TVEEPROM) { |
| @@ -1277,13 +1246,6 @@ free_irq: · 178 unmodified lines | |||
| 1277 | free_i2c: | 1246 | free_i2c: |
| 1278 | v4l2_ctrl_handler_free(&itv->cxhdl.hdl); | 1247 | v4l2_ctrl_handler_free(&itv->cxhdl.hdl); |
| 1279 | exit_ivtv_i2c(itv); | 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 | free_worker: | 1249 | free_worker: |
| 1288 | kthread_stop(itv->irq_worker_task); | 1250 | kthread_stop(itv->irq_worker_task); |
| 1289 | err: | 1251 | err: |
| @@ -1439,14 +1401,7 @@ static void ivtv_remove(struct pci_dev *pdev) · 149 unmodified lines | |||
| 1439 | exit_ivtv_i2c(itv); | 1401 | exit_ivtv_i2c(itv); |
| 1440 | 1402 | ||
| 1441 | free_irq(itv->pdev->irq, (void *)itv); | 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 | for (i = 0; i < IVTV_VBI_FRAMES; i++) | 1405 | for (i = 0; i < IVTV_VBI_FRAMES; i++) |
| 1451 | kfree(itv->vbi.sliced_mpeg_data[i]); | 1406 | kfree(itv->vbi.sliced_mpeg_data[i]); |
| 1452 | 1407 | ||
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include "ivtv-ioctl.h" | 21 | #include "ivtv-ioctl.h" |
| 22 | #include "ivtv-cards.h" | 22 | #include "ivtv-cards.h" |
| 23 | #include "ivtv-firmware.h" | 23 | #include "ivtv-firmware.h" |
| 24 | #include <linux/lockdep.h> | ||
| 24 | #include <media/v4l2-event.h> | 25 | #include <media/v4l2-event.h> |
| 25 | #include <media/i2c/saa7115.h> | 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 | itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num; | 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 | static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) | 210 | static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err) |
| 194 | { | 211 | { |
| 195 | struct ivtv *itv = s->itv; | 212 | struct ivtv *itv = s->itv; |
| 196 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; | 213 | struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI]; |
| 197 | struct ivtv_buffer *buf; | 214 | struct ivtv_buffer *buf; |
| 198 | DEFINE_WAIT(wait); | ||
| 199 | 215 | ||
| 200 | *err = 0; | 216 | *err = 0; |
| 201 | while (1) { | 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 | /* wait for more data to arrive */ | 276 | /* wait for more data to arrive */ |
| 261 | mutex_unlock(&itv->serialize_lock); | 277 | ivtv_schedule(s); |
| 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); | ||
| 268 | if (signal_pending(current)) { | 278 | if (signal_pending(current)) { |
| 269 | /* return if a signal was received */ | 279 | /* return if a signal was received */ |
| 270 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | 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 | return 0; | 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 | static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) | 565 | static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos) |
| 537 | { | 566 | { |
| 538 | struct ivtv_open_id *id = fh2id(filp->private_data); | 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 | int bytes_written = 0; | 573 | int bytes_written = 0; |
| 545 | int mode; | 574 | int mode; |
| 546 | int rc; | 575 | int rc; |
| 547 | DEFINE_WAIT(wait); | ||
| 548 | 576 | ||
| 549 | IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name); | 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 | break; | 646 | break; |
| 619 | if (filp->f_flags & O_NONBLOCK) | 647 | if (filp->f_flags & O_NONBLOCK) |
| 620 | return -EAGAIN; | 648 | return -EAGAIN; |
| 621 | mutex_unlock(&itv->serialize_lock); | 649 | ivtv_schedule(s); |
| 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); | ||
| 628 | if (signal_pending(current)) { | 650 | if (signal_pending(current)) { |
| 629 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); | 651 | IVTV_DEBUG_INFO("User stopped %s\n", s->name); |
| 630 | return -EINTR; | 652 | return -EINTR; |
| @@ -674,20 +696,10 @@ retry: · 43 unmodified lines | |||
| 674 | 696 | ||
| 675 | if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { | 697 | if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) { |
| 676 | if (s->q_full.length >= itv->dma_data_req_size) { | 698 | if (s->q_full.length >= itv->dma_data_req_size) { |
| 677 | int got_sig; | ||
| 678 | |||
| 679 | if (mode == OUT_YUV) | 699 | if (mode == OUT_YUV) |
| 680 | ivtv_yuv_setup_stream_frame(itv); | 700 | ivtv_yuv_setup_stream_frame(itv); |
| 681 | 701 | ||
| 682 | mutex_unlock(&itv->serialize_lock); | 702 | if (ivtv_schedule_dma(s)) { |
| 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) { | ||
| 691 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); | 703 | IVTV_DEBUG_INFO("User interrupted %s\n", s->name); |
| 692 | return -EINTR; | 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 | /* Fill SG List with new values */ | 132 | /* Fill SG List with new values */ |
| 133 | if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) { | 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 | unpin_user_pages(dma->map, dma->page_count); | 136 | unpin_user_pages(dma->map, dma->page_count); |
| 135 | dma->page_count = 0; | 137 | dma->page_count = 0; |
| 136 | return -ENOMEM; | 138 | return -ENOMEM; |
| @@ -139,6 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr, · 2 unmodified lines | |||
| 139 | /* Map SG List */ | 141 | /* Map SG List */ |
| 140 | dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, | 142 | dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, |
| 141 | dma->page_count, DMA_TO_DEVICE); | 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 | /* Fill SG Array with new values */ | 151 | /* Fill SG Array with new values */ |
| 144 | ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1); | 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 | dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, | 115 | dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist, |
| 116 | dma->page_count, DMA_TO_DEVICE); | 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 | /* Fill SG Array with new values */ | 124 | /* Fill SG Array with new values */ |
| 119 | ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size); | 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 | "\t\t\tdefault 640"); | 104 | "\t\t\tdefault 640"); |
| 105 | 105 | ||
| 106 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); | 106 | MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong"); |
| 107 | MODULE_DESCRIPTION("Conexant cx23415 framebuffer support"); | ||
| 107 | MODULE_LICENSE("GPL"); | 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 | /* Map User DMA */ | 282 | /* Map User DMA */ |
| 282 | if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { | 283 | if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) { |
| 283 | mutex_unlock(&itv->udma.lock); | 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 | IVTVFB_WARN("%s, Error in ivtv_udma_setup: %d bytes, %d pages returned\n", |
| 285 | size_in_bytes, itv->udma.page_count); | 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 | return -EIO; | 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 | if (stat & MANTIS_INT_RISCI) { | 116 | if (stat & MANTIS_INT_RISCI) { |
| 117 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); | 117 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); |
| 118 | mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; | 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 | if (stat & MANTIS_INT_I2CDONE) { | 121 | if (stat & MANTIS_INT_I2CDONE) { |
| 122 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); | 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 | if (stat & MANTIS_INT_RISCI) { | 125 | if (stat & MANTIS_INT_RISCI) { |
| 126 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); | 126 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]); |
| 127 | mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28; | 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 | if (stat & MANTIS_INT_I2CDONE) { | 130 | if (stat & MANTIS_INT_I2CDONE) { |
| 131 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); | 131 | dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]); |
| @@ -125,7 +125,7 @@ struct mantis_pci { · 124 unmodified lines | |||
| 125 | __le32 *risc_cpu; | 125 | __le32 *risc_cpu; |
| 126 | dma_addr_t risc_dma; | 126 | dma_addr_t risc_dma; |
| 127 | 127 | ||
| 128 | struct tasklet_struct tasklet; | 128 | struct work_struct bh_work; |
| 129 | spinlock_t intmask_lock; | 129 | spinlock_t intmask_lock; |
| 130 | 130 | ||
| 131 | struct i2c_adapter adapter; | 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 | struct mantis_hwconfig *config = mantis->hwconfig; | 206 | struct mantis_hwconfig *config = mantis->hwconfig; |
| 207 | 207 | ||
| 208 | while (mantis->last_block != mantis->busy_block) { | 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 | extern int mantis_dma_exit(struct mantis_pci *mantis); | 13 | extern int mantis_dma_exit(struct mantis_pci *mantis); |
| 14 | extern void mantis_dma_start(struct mantis_pci *mantis); | 14 | extern void mantis_dma_start(struct mantis_pci *mantis); |
| 15 | extern void mantis_dma_stop(struct mantis_pci *mantis); | 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 | #endif /* __MANTIS_DMA_H */ | 18 | #endif /* __MANTIS_DMA_H */ |
| @@ -105,7 +105,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed) · 104 unmodified lines | |||
| 105 | if (mantis->feeds == 1) { | 105 | if (mantis->feeds == 1) { |
| 106 | dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); | 106 | dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma"); |
| 107 | mantis_dma_start(mantis); | 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 | return mantis->feeds; | 111 | return mantis->feeds; |
| @@ -125,7 +125,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) · 13 unmodified lines | |||
| 125 | mantis->feeds--; | 125 | mantis->feeds--; |
| 126 | if (mantis->feeds == 0) { | 126 | if (mantis->feeds == 0) { |
| 127 | dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); | 127 | dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma"); |
| 128 | tasklet_disable(&mantis->tasklet); | 128 | disable_work_sync(&mantis->bh_work); |
| 129 | mantis_dma_stop(mantis); | 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 | dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); | 207 | dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx); |
| 208 | tasklet_setup(&mantis->tasklet, mantis_dma_xfer); | 208 | INIT_WORK(&mantis->bh_work, mantis_dma_xfer); |
| 209 | tasklet_disable(&mantis->tasklet); | 209 | disable_work_sync(&mantis->bh_work); |
| 210 | if (mantis->hwconfig) { | 210 | if (mantis->hwconfig) { |
| 211 | result = config->frontend_init(mantis, mantis->fe); | 211 | result = config->frontend_init(mantis, mantis->fe); |
| 212 | if (result < 0) { | 212 | if (result < 0) { |
| @@ -235,7 +235,7 @@ int mantis_dvb_init(struct mantis_pci *mantis) · 22 unmodified lines | |||
| 235 | 235 | ||
| 236 | /* Error conditions .. */ | 236 | /* Error conditions .. */ |
| 237 | err5: | 237 | err5: |
| 238 | tasklet_kill(&mantis->tasklet); | 238 | cancel_work_sync(&mantis->bh_work); |
| 239 | dvb_net_release(&mantis->dvbnet); | 239 | dvb_net_release(&mantis->dvbnet); |
| 240 | if (mantis->fe) { | 240 | if (mantis->fe) { |
| 241 | dvb_unregister_frontend(mantis->fe); | 241 | dvb_unregister_frontend(mantis->fe); |
| @@ -273,7 +273,7 @@ int mantis_dvb_exit(struct mantis_pci *mantis) · 31 unmodified lines | |||
| 273 | dvb_frontend_detach(mantis->fe); | 273 | dvb_frontend_detach(mantis->fe); |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | tasklet_kill(&mantis->tasklet); | 276 | cancel_work_sync(&mantis->bh_work); |
| 277 | dvb_net_release(&mantis->dvbnet); | 277 | dvb_net_release(&mantis->dvbnet); |
| 278 | 278 | ||
| 279 | mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem); | 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 | /* nGene interrupt handler **************************************************/ | 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 | while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { | 57 | while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) { |
| 58 | struct EVENT_BUFFER Event = | 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 | struct device *pdev = &chan->dev->pci_dev->dev; | 74 | struct device *pdev = &chan->dev->pci_dev->dev; |
| 75 | struct SBufferHeader *Cur = chan->nextBuffer; | 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 | dev->EventQueueOverflowFlag = 1; | 204 | dev->EventQueueOverflowFlag = 1; |
| 205 | } | 205 | } |
| 206 | dev->EventBuffer->EventStatus &= ~0x80; | 206 | dev->EventBuffer->EventStatus &= ~0x80; |
| 207 | tasklet_schedule(&dev->event_tasklet); | 207 | queue_work(system_bh_wq, &dev->event_bh_work); |
| 208 | rc = IRQ_HANDLED; | 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 | ngeneBuffer.SR.Flags & 0xC0) == 0x80) { | 217 | ngeneBuffer.SR.Flags & 0xC0) == 0x80) { |
| 218 | dev->channel[i].nextBuffer-> | 218 | dev->channel[i].nextBuffer-> |
| 219 | ngeneBuffer.SR.Flags |= 0x40; | 219 | ngeneBuffer.SR.Flags |= 0x40; |
| 220 | tasklet_schedule( | 220 | queue_work(system_bh_wq, |
| 221 | &dev->channel[i].demux_tasklet); | 221 | &dev->channel[i].demux_bh_work); |
| 222 | rc = IRQ_HANDLED; | 222 | rc = IRQ_HANDLED; |
| 223 | } | 223 | } |
| 224 | } | 224 | } |
| @@ -1181,7 +1181,7 @@ static void ngene_init(struct ngene *dev) · 956 unmodified lines | |||
| 1181 | struct device *pdev = &dev->pci_dev->dev; | 1181 | struct device *pdev = &dev->pci_dev->dev; |
| 1182 | int i; | 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 | memset_io(dev->iomem + 0xc000, 0x00, 0x220); | 1186 | memset_io(dev->iomem + 0xc000, 0x00, 0x220); |
| 1187 | memset_io(dev->iomem + 0xc400, 0x00, 0x100); | 1187 | memset_io(dev->iomem + 0xc400, 0x00, 0x100); |
| @@ -1395,7 +1395,7 @@ static void release_channel(struct ngene_channel *chan) · 207 unmodified lines | |||
| 1395 | if (chan->running) | 1395 | if (chan->running) |
| 1396 | set_transfer(chan, 0); | 1396 | set_transfer(chan, 0); |
| 1397 | 1397 | ||
| 1398 | tasklet_kill(&chan->demux_tasklet); | 1398 | cancel_work_sync(&chan->demux_bh_work); |
| 1399 | 1399 | ||
| 1400 | if (chan->ci_dev) { | 1400 | if (chan->ci_dev) { |
| 1401 | dvb_unregister_device(chan->ci_dev); | 1401 | dvb_unregister_device(chan->ci_dev); |
| @@ -1445,7 +1445,7 @@ static int init_channel(struct ngene_channel *chan) · 43 unmodified lines | |||
| 1445 | struct ngene_info *ni = dev->card_info; | 1445 | struct ngene_info *ni = dev->card_info; |
| 1446 | int io = ni->io_type[nr]; | 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 | chan->users = 0; | 1449 | chan->users = 0; |
| 1450 | chan->type = io; | 1450 | chan->type = io; |
| 1451 | chan->mode = chan->type; /* for now only one mode */ | 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 | struct ngene *dev = pci_get_drvdata(pdev); | 1649 | struct ngene *dev = pci_get_drvdata(pdev); |
| 1650 | int i; | 1650 | int i; |
| 1651 | 1651 | ||
| 1652 | tasklet_kill(&dev->event_tasklet); | 1652 | cancel_work_sync(&dev->event_bh_work); |
| 1653 | for (i = MAX_STREAM - 1; i >= 0; i--) | 1653 | for (i = MAX_STREAM - 1; i >= 0; i--) |
| 1654 | release_channel(&dev->channel[i]); | 1654 | release_channel(&dev->channel[i]); |
| 1655 | if (dev->ci.en) | 1655 | if (dev->ci.en) |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | |||
| 16 | #include <linux/scatterlist.h> | 16 | #include <linux/scatterlist.h> |
| 17 | 17 | ||
| 18 | #include <linux/dvb/frontend.h> | 18 | #include <linux/dvb/frontend.h> |
| 19 | #include <linux/workqueue.h> | ||
| 19 | 20 | ||
| 20 | #include <media/dmxdev.h> | 21 | #include <media/dmxdev.h> |
| 21 | #include <media/dvbdev.h> | 22 | #include <media/dvbdev.h> |
| @@ -621,7 +622,7 @@ struct ngene_channel { · 599 unmodified lines | |||
| 621 | int users; | 622 | int users; |
| 622 | struct video_device *v4l_dev; | 623 | struct video_device *v4l_dev; |
| 623 | struct dvb_device *ci_dev; | 624 | struct dvb_device *ci_dev; |
| 624 | struct tasklet_struct demux_tasklet; | 625 | struct work_struct demux_bh_work; |
| 625 | 626 | ||
| 626 | struct SBufferHeader *nextBuffer; | 627 | struct SBufferHeader *nextBuffer; |
| 627 | enum KSSTATE State; | 628 | enum KSSTATE State; |
| @@ -717,7 +718,7 @@ struct ngene { · 89 unmodified lines | |||
| 717 | struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; | 718 | struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE]; |
| 718 | int EventQueueOverflowCount; | 719 | int EventQueueOverflowCount; |
| 719 | int EventQueueOverflowFlag; | 720 | int EventQueueOverflowFlag; |
| 720 | struct tasklet_struct event_tasklet; | 721 | struct work_struct event_bh_work; |
| 721 | struct EVENT_BUFFER *EventBuffer; | 722 | struct EVENT_BUFFER *EventBuffer; |
| 722 | int EventQueueWriteIndex; | 723 | int EventQueueWriteIndex; |
| 723 | int EventQueueReadIndex; | 724 | int EventQueueReadIndex; |
| @@ -1254,5 +1254,6 @@ static void saa7134_alsa_exit(void) · 1253 unmodified lines | |||
| 1254 | /* We initialize this late, to make sure the sound system is up and running */ | 1254 | /* We initialize this late, to make sure the sound system is up and running */ |
| 1255 | late_initcall(saa7134_alsa_init); | 1255 | late_initcall(saa7134_alsa_init); |
| 1256 | module_exit(saa7134_alsa_exit); | 1256 | module_exit(saa7134_alsa_exit); |
| 1257 | MODULE_DESCRIPTION("Philips SAA7134 DMA audio support"); | ||
| 1257 | MODULE_LICENSE("GPL"); | 1258 | MODULE_LICENSE("GPL"); |
| 1258 | MODULE_AUTHOR("Ricardo Cerqueira"); | 1259 | MODULE_AUTHOR("Ricardo Cerqueira"); |
| @@ -52,6 +52,7 @@ · 51 unmodified lines | |||
| 52 | #include "s5h1411.h" | 52 | #include "s5h1411.h" |
| 53 | 53 | ||
| 54 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 54 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
| 55 | MODULE_DESCRIPTION("DVB/ATSC Support for saa7134 based TV cards"); | ||
| 55 | MODULE_LICENSE("GPL"); | 56 | MODULE_LICENSE("GPL"); |
| 56 | 57 | ||
| 57 | static unsigned int antenna_pwr; | 58 | static unsigned int antenna_pwr; |
| @@ -466,7 +467,9 @@ static int philips_europa_tuner_sleep(struct dvb_frontend *fe) · 408 unmodified lines | |||
| 466 | /* switch the board to analog mode */ | 467 | /* switch the board to analog mode */ |
| 467 | if (fe->ops.i2c_gate_ctrl) | 468 | if (fe->ops.i2c_gate_ctrl) |
| 468 | fe->ops.i2c_gate_ctrl(fe, 1); | 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 | return 0; | 473 | return 0; |
| 471 | } | 474 | } |
| 472 | 475 | ||
| @@ -1018,7 +1021,9 @@ static int md8800_set_voltage2(struct dvb_frontend *fe, · 545 unmodified lines | |||
| 1018 | else | 1021 | else |
| 1019 | wbuf[1] = rbuf & 0xef; | 1022 | wbuf[1] = rbuf & 0xef; |
| 1020 | msg[0].len = 2; | 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 | return 0; | 1027 | return 0; |
| 1023 | } | 1028 | } |
| 1024 | 1029 | ||
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | /* ------------------------------------------------------------------ */ | 19 | /* ------------------------------------------------------------------ */ |
| 20 | 20 | ||
| 21 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); | 21 | MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]"); |
| 22 | MODULE_DESCRIPTION("Philips SAA7134 empress support"); | ||
| 22 | MODULE_LICENSE("GPL"); | 23 | MODULE_LICENSE("GPL"); |
| 23 | 24 | ||
| 24 | static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET }; | 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 | module_init(saa7134_go7007_mod_init); | 516 | module_init(saa7134_go7007_mod_init); |
| 517 | module_exit(saa7134_go7007_mod_cleanup); | 517 | module_exit(saa7134_go7007_mod_cleanup); |
| 518 | 518 | ||
| 519 | MODULE_DESCRIPTION("go7007 support for saa7134 based TV cards"); | ||
| 519 | MODULE_LICENSE("GPL v2"); | 520 | MODULE_LICENSE("GPL v2"); |
| @@ -279,10 +279,10 @@ static void smi_port_clearInterrupt(struct smi_port *port) · 278 unmodified lines | |||
| 279 | (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); | 279 | (port->_dmaInterruptCH0 | port->_dmaInterruptCH1)); |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | /* tasklet handler: DMA data to dmx.*/ | 282 | /* BH work handler: DMA data to dmx.*/ |
| 283 | static void smi_dma_xfer(struct tasklet_struct *t) | 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 | struct smi_dev *dev = port->dev; | 286 | struct smi_dev *dev = port->dev; |
| 287 | u32 intr_status, finishedData, dmaManagement; | 287 | u32 intr_status, finishedData, dmaManagement; |
| 288 | u8 dmaChan0State, dmaChan1State; | 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 | smi_port_disableInterrupt(port); | 428 | smi_port_disableInterrupt(port); |
| 429 | tasklet_setup(&port->tasklet, smi_dma_xfer); | 429 | INIT_WORK(&port->bh_work, smi_dma_xfer); |
| 430 | tasklet_disable(&port->tasklet); | 430 | disable_work_sync(&port->bh_work); |
| 431 | port->enable = 1; | 431 | port->enable = 1; |
| 432 | return 0; | 432 | return 0; |
| 433 | err: | 433 | err: |
| @@ -438,7 +438,7 @@ err: · 4 unmodified lines | |||
| 438 | static void smi_port_exit(struct smi_port *port) | 438 | static void smi_port_exit(struct smi_port *port) |
| 439 | { | 439 | { |
| 440 | smi_port_disableInterrupt(port); | 440 | smi_port_disableInterrupt(port); |
| 441 | tasklet_kill(&port->tasklet); | 441 | cancel_work_sync(&port->bh_work); |
| 442 | smi_port_dma_free(port); | 442 | smi_port_dma_free(port); |
| 443 | port->enable = 0; | 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 | smi_port_disableInterrupt(port); | 452 | smi_port_disableInterrupt(port); |
| 453 | port->_int_status = int_status; | 453 | port->_int_status = int_status; |
| 454 | smi_port_clearInterrupt(port); | 454 | smi_port_clearInterrupt(port); |
| 455 | tasklet_schedule(&port->tasklet); | 455 | queue_work(system_bh_wq, &port->bh_work); |
| 456 | handled = 1; | 456 | handled = 1; |
| 457 | } | 457 | } |
| 458 | return handled; | 458 | return handled; |
| @@ -823,7 +823,7 @@ static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed) · 364 unmodified lines | |||
| 823 | smi_port_clearInterrupt(port); | 823 | smi_port_clearInterrupt(port); |
| 824 | smi_port_enableInterrupt(port); | 824 | smi_port_enableInterrupt(port); |
| 825 | smi_write(port->DMA_MANAGEMENT, dmaManagement); | 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 | return port->users; | 828 | return port->users; |
| 829 | } | 829 | } |
| @@ -837,7 +837,7 @@ static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed) · 7 unmodified lines | |||
| 837 | if (--port->users) | 837 | if (--port->users) |
| 838 | return port->users; | 838 | return port->users; |
| 839 | 839 | ||
| 840 | tasklet_disable(&port->tasklet); | 840 | disable_work_sync(&port->bh_work); |
| 841 | smi_port_disableInterrupt(port); | 841 | smi_port_disableInterrupt(port); |
| 842 | smi_clear(port->DMA_MANAGEMENT, 0x30003); | 842 | smi_clear(port->DMA_MANAGEMENT, 0x30003); |
| 843 | return 0; | 843 | return 0; |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include <linux/pci.h> | 17 | #include <linux/pci.h> |
| 18 | #include <linux/dma-mapping.h> | 18 | #include <linux/dma-mapping.h> |
| 19 | #include <linux/slab.h> | 19 | #include <linux/slab.h> |
| 20 | #include <linux/workqueue.h> | ||
| 20 | #include <media/rc-core.h> | 21 | #include <media/rc-core.h> |
| 21 | 22 | ||
| 22 | #include <media/demux.h> | 23 | #include <media/demux.h> |
| @@ -257,7 +258,7 @@ struct smi_port { · 234 unmodified lines | |||
| 257 | u32 _dmaInterruptCH0; | 258 | u32 _dmaInterruptCH0; |
| 258 | u32 _dmaInterruptCH1; | 259 | u32 _dmaInterruptCH1; |
| 259 | u32 _int_status; | 260 | u32 _int_status; |
| 260 | struct tasklet_struct tasklet; | 261 | struct work_struct bh_work; |
| 261 | /* dvb */ | 262 | /* dvb */ |
| 262 | struct dmx_frontend hw_frontend; | 263 | struct dmx_frontend hw_frontend; |
| 263 | struct dmx_frontend mem_frontend; | 264 | struct dmx_frontend mem_frontend; |
| @@ -36,6 +36,7 @@ · 35 unmodified lines | |||
| 36 | #include <linux/interrupt.h> | 36 | #include <linux/interrupt.h> |
| 37 | #include <linux/input.h> | 37 | #include <linux/input.h> |
| 38 | #include <linux/spinlock.h> | 38 | #include <linux/spinlock.h> |
| 39 | #include <linux/workqueue.h> | ||
| 39 | 40 | ||
| 40 | #include <media/dvb_ca_en50221.h> | 41 | #include <media/dvb_ca_en50221.h> |
| 41 | 42 | ||
| @@ -54,7 +55,7 @@ struct budget_av { · 12 unmodified lines | |||
| 54 | struct video_device vd; | 55 | struct video_device vd; |
| 55 | int cur_input; | 56 | int cur_input; |
| 56 | int has_saa7113; | 57 | int has_saa7113; |
| 57 | struct tasklet_struct ciintf_irq_tasklet; | 58 | struct work_struct ciintf_irq_bh_work; |
| 58 | int slot_status; | 59 | int slot_status; |
| 59 | struct dvb_ca_en50221 ca; | 60 | struct dvb_ca_en50221 ca; |
| 60 | u8 reinitialise_demod:1; | 61 | u8 reinitialise_demod:1; |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
| 19 | #include <linux/interrupt.h> | 19 | #include <linux/interrupt.h> |
| 20 | #include <linux/spinlock.h> | 20 | #include <linux/spinlock.h> |
| 21 | #include <linux/workqueue.h> | ||
| 21 | #include <media/rc-core.h> | 22 | #include <media/rc-core.h> |
| 22 | 23 | ||
| 23 | #include "budget.h" | 24 | #include "budget.h" |
| @@ -81,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); · 57 unmodified lines | |||
| 81 | 82 | ||
| 82 | struct budget_ci_ir { | 83 | struct budget_ci_ir { |
| 83 | struct rc_dev *dev; | 84 | struct rc_dev *dev; |
| 84 | struct tasklet_struct msp430_irq_tasklet; | 85 | struct work_struct msp430_irq_bh_work; |
| 85 | char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ | 86 | char name[72]; /* 40 + 32 for (struct saa7146_dev).name */ |
| 86 | char phys[32]; | 87 | char phys[32]; |
| 87 | int rc5_device; | 88 | int rc5_device; |
| @@ -92,7 +93,7 @@ struct budget_ci_ir { · 4 unmodified lines | |||
| 92 | 93 | ||
| 93 | struct budget_ci { | 94 | struct budget_ci { |
| 94 | struct budget budget; | 95 | struct budget budget; |
| 95 | struct tasklet_struct ciintf_irq_tasklet; | 96 | struct work_struct ciintf_irq_bh_work; |
| 96 | int slot_status; | 97 | int slot_status; |
| 97 | int ci_irq; | 98 | int ci_irq; |
| 98 | struct dvb_ca_en50221 ca; | 99 | struct dvb_ca_en50221 ca; |
| @@ -100,9 +101,9 @@ struct budget_ci { · 1 unmodified line | |||
| 100 | u8 tuner_pll_address; /* used for philips_tdm1316l configs */ | 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 | struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); | 107 | struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir); |
| 107 | struct rc_dev *dev = budget_ci->ir.dev; | 108 | struct rc_dev *dev = budget_ci->ir.dev; |
| 108 | u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8; | 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 | budget_ci->ir.dev = dev; | 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 | SAA7146_IER_ENABLE(saa, MASK_06); | 237 | SAA7146_IER_ENABLE(saa, MASK_06); |
| 237 | saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI); | 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 | SAA7146_IER_DISABLE(saa, MASK_06); | 247 | SAA7146_IER_DISABLE(saa, MASK_06); |
| 247 | saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); | 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 | rc_unregister_device(budget_ci->ir.dev); | 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 | return 0; | 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 | struct budget_ci *budget_ci = from_work(budget_ci, t, |
| 355 | ciintf_irq_tasklet); | 356 | ciintf_irq_bh_work); |
| 356 | struct saa7146_dev *saa = budget_ci->budget.dev; | 357 | struct saa7146_dev *saa = budget_ci->budget.dev; |
| 357 | unsigned int flags; | 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 | // Setup CI slot IRQ | 493 | // Setup CI slot IRQ |
| 493 | if (budget_ci->ci_irq) { | 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 | if (budget_ci->slot_status != SLOTSTATUS_NONE) | 496 | if (budget_ci->slot_status != SLOTSTATUS_NONE) |
| 496 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); | 497 | saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO); |
| 497 | else | 498 | else |
| @@ -530,7 +531,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci) · 32 unmodified lines | |||
| 530 | if (budget_ci->ci_irq) { | 531 | if (budget_ci->ci_irq) { |
| 531 | SAA7146_IER_DISABLE(saa, MASK_03); | 532 | SAA7146_IER_DISABLE(saa, MASK_03); |
| 532 | saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT); | 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 | // reset interface | 537 | // reset interface |
| @@ -556,13 +557,13 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 *isr) · 19 unmodified lines | |||
| 556 | dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); | 557 | dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci); |
| 557 | 558 | ||
| 558 | if (*isr & MASK_06) | 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 | if (*isr & MASK_10) | 562 | if (*isr & MASK_10) |
| 562 | ttpci_budget_irq10_handler(dev, isr); | 563 | ttpci_budget_irq10_handler(dev, isr); |
| 563 | 564 | ||
| 564 | if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq)) | 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 | static u8 philips_su1278_tt_inittab[] = { | 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 | return ret; | 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 | u8 *mem = (u8 *) (budget->grabbing); | 178 | u8 *mem = (u8 *) (budget->grabbing); |
| 179 | u32 olddma = budget->ttbp; | 179 | u32 olddma = budget->ttbp; |
| 180 | u32 newdma = saa7146_read(budget->dev, PCI_VDP3); | 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 | /* upload all */ | 525 | /* upload all */ |
| 526 | saa7146_write(dev, GPIO_CTRL, 0x000000); | 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 | /* frontend power on */ | 530 | /* frontend power on */ |
| 531 | if (bi->type != BUDGET_FS_ACTIVY) | 531 | if (bi->type != BUDGET_FS_ACTIVY) |
| @@ -565,7 +565,7 @@ int ttpci_budget_deinit(struct budget *budget) · 33 unmodified lines | |||
| 565 | 565 | ||
| 566 | budget_unregister(budget); | 566 | budget_unregister(budget); |
| 567 | 567 | ||
| 568 | tasklet_kill(&budget->vpe_tasklet); | 568 | cancel_work_sync(&budget->vpe_bh_work); |
| 569 | 569 | ||
| 570 | saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt); | 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 | dprintk(8, "dev: %p, budget: %p\n", dev, budget); | 584 | dprintk(8, "dev: %p, budget: %p\n", dev, budget); |
| 585 | 585 | ||
| 586 | if (*isr & MASK_10) | 586 | if (*isr & MASK_10) |
| 587 | tasklet_schedule(&budget->vpe_tasklet); | 587 | queue_work(system_bh_wq, &budget->vpe_bh_work); |
| 588 | } | 588 | } |
| 589 | EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler); | 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 | EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); | 603 | EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port); |
| 604 | 604 | ||
| 605 | MODULE_DESCRIPTION("base driver for the SAA7146 based Budget DVB cards"); | ||
| 605 | MODULE_LICENSE("GPL"); | 606 | MODULE_LICENSE("GPL"); |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | #include <linux/module.h> | 19 | #include <linux/module.h> |
| 20 | #include <linux/mutex.h> | 20 | #include <linux/mutex.h> |
| 21 | #include <linux/workqueue.h> | ||
| 21 | 22 | ||
| 22 | #include <media/drv-intf/saa7146.h> | 23 | #include <media/drv-intf/saa7146.h> |
| 23 | 24 | ||
| @@ -54,8 +55,8 @@ struct budget { · 30 unmodified lines | |||
| 54 | unsigned char *grabbing; | 55 | unsigned char *grabbing; |
| 55 | struct saa7146_pgtable pt; | 56 | struct saa7146_pgtable pt; |
| 56 | 57 | ||
| 57 | struct tasklet_struct fidb_tasklet; | 58 | struct work_struct fidb_bh_work; |
| 58 | struct tasklet_struct vpe_tasklet; | 59 | struct work_struct vpe_bh_work; |
| 59 | 60 | ||
| 60 | struct dmxdev dmxdev; | 61 | struct dmxdev dmxdev; |
| 61 | struct dvb_demux demux; | 62 | struct dvb_demux demux; |
| @@ -144,7 +144,7 @@ static void tw5864_h264_isr(struct tw5864_dev *dev) · 143 unmodified lines | |||
| 144 | cur_frame->gop_seqno = input->frame_gop_seqno; | 144 | cur_frame->gop_seqno = input->frame_gop_seqno; |
| 145 | 145 | ||
| 146 | dev->h264_buf_w_index = next_frame_index; | 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 | cur_frame = next_frame; | 149 | cur_frame = next_frame; |
| 150 | 150 | ||
| @@ -6,6 +6,7 @@ · 5 unmodified lines | |||
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include <linux/module.h> | 8 | #include <linux/module.h> |
| 9 | #include <linux/workqueue.h> | ||
| 9 | #include <media/v4l2-common.h> | 10 | #include <media/v4l2-common.h> |
| 10 | #include <media/v4l2-event.h> | 11 | #include <media/v4l2-event.h> |
| 11 | #include <media/videobuf2-dma-contig.h> | 12 | #include <media/videobuf2-dma-contig.h> |
| @@ -175,7 +176,7 @@ static const unsigned int intra4x4_lambda3[] = { · 163 unmodified lines | |||
| 175 | static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std); | 176 | static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std); |
| 176 | static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std); | 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 | static void tw5864_handle_frame(struct tw5864_h264_frame *frame); | 180 | static void tw5864_handle_frame(struct tw5864_h264_frame *frame); |
| 180 | static void tw5864_frame_interval_set(struct tw5864_input *input); | 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 | dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER; | 1063 | dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER; |
| 1063 | tw5864_irqmask_apply(dev); | 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 | for (i = 0; i < TW5864_INPUTS; i++) { | 1068 | for (i = 0; i < TW5864_INPUTS; i++) { |
| 1068 | dev->inputs[i].root = dev; | 1069 | dev->inputs[i].root = dev; |
| @@ -1079,7 +1080,7 @@ fini_video_inputs: · 10 unmodified lines | |||
| 1079 | for (i = last_input_nr_registered; i >= 0; i--) | 1080 | for (i = last_input_nr_registered; i >= 0; i--) |
| 1080 | tw5864_video_input_fini(&dev->inputs[i]); | 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 | free_dma: | 1085 | free_dma: |
| 1085 | for (i = last_dma_allocated; i >= 0; i--) { | 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 | int i; | 1200 | int i; |
| 1200 | 1201 | ||
| 1201 | tasklet_kill(&dev->tasklet); | 1202 | cancel_work_sync(&dev->bh_work); |
| 1202 | 1203 | ||
| 1203 | for (i = 0; i < TW5864_INPUTS; i++) | 1204 | for (i = 0; i < TW5864_INPUTS; i++) |
| 1204 | tw5864_video_input_fini(&dev->inputs[i]); | 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 | return detected; | 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 | unsigned long flags; | 1322 | unsigned long flags; |
| 1322 | int batch_size = H264_BUF_CNT; | 1323 | int batch_size = H264_BUF_CNT; |
| 1323 | 1324 | ||
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include <linux/mutex.h> | 12 | #include <linux/mutex.h> |
| 13 | #include <linux/io.h> | 13 | #include <linux/io.h> |
| 14 | #include <linux/interrupt.h> | 14 | #include <linux/interrupt.h> |
| 15 | #include <linux/workqueue.h> | ||
| 15 | 16 | ||
| 16 | #include <media/v4l2-common.h> | 17 | #include <media/v4l2-common.h> |
| 17 | #include <media/v4l2-ioctl.h> | 18 | #include <media/v4l2-ioctl.h> |
| @@ -85,7 +86,7 @@ struct tw5864_input { · 67 unmodified lines | |||
| 85 | int nr; /* input number */ | 86 | int nr; /* input number */ |
| 86 | struct tw5864_dev *root; | 87 | struct tw5864_dev *root; |
| 87 | struct mutex lock; /* used for vidq and vdev */ | 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 | struct video_device vdev; | 90 | struct video_device vdev; |
| 90 | struct v4l2_ctrl_handler hdl; | 91 | struct v4l2_ctrl_handler hdl; |
| 91 | struct vb2_queue vidq; | 92 | struct vb2_queue vidq; |
| @@ -142,7 +143,7 @@ struct tw5864_h264_frame { · 50 unmodified lines | |||
| 142 | 143 | ||
| 143 | /* global device status */ | 144 | /* global device status */ |
| 144 | struct tw5864_dev { | 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 | struct v4l2_device v4l2_dev; | 147 | struct v4l2_device v4l2_dev; |
| 147 | struct tw5864_input inputs[TW5864_INPUTS]; | 148 | struct tw5864_input inputs[TW5864_INPUTS]; |
| 148 | #define H264_BUF_CNT 4 | 149 | #define H264_BUF_CNT 4 |
| @@ -150,7 +151,7 @@ struct tw5864_dev { · 1 unmodified line | |||
| 150 | int h264_buf_r_index; | 151 | int h264_buf_r_index; |
| 151 | int h264_buf_w_index; | 152 | int h264_buf_w_index; |
| 152 | 153 | ||
| 153 | struct tasklet_struct tasklet; | 154 | struct work_struct bh_work; |
| 154 | 155 | ||
| 155 | int encoder_busy; | 156 | int encoder_busy; |
| 156 | /* Input number to check next for ready raw picture (in RR fashion) */ | 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 | source "drivers/media/platform/broadcom/Kconfig" | 70 | source "drivers/media/platform/broadcom/Kconfig" |
| 71 | source "drivers/media/platform/cadence/Kconfig" | 71 | source "drivers/media/platform/cadence/Kconfig" |
| 72 | source "drivers/media/platform/chips-media/Kconfig" | 72 | source "drivers/media/platform/chips-media/Kconfig" |
| 73 | source "drivers/media/platform/imagination/Kconfig" | ||
| 73 | source "drivers/media/platform/intel/Kconfig" | 74 | source "drivers/media/platform/intel/Kconfig" |
| 74 | source "drivers/media/platform/marvell/Kconfig" | 75 | source "drivers/media/platform/marvell/Kconfig" |
| 75 | source "drivers/media/platform/mediatek/Kconfig" | 76 | source "drivers/media/platform/mediatek/Kconfig" |
| @@ -78,6 +79,7 @@ source "drivers/media/platform/nuvoton/Kconfig" · 2 unmodified lines | |||
| 78 | source "drivers/media/platform/nvidia/Kconfig" | 79 | source "drivers/media/platform/nvidia/Kconfig" |
| 79 | source "drivers/media/platform/nxp/Kconfig" | 80 | source "drivers/media/platform/nxp/Kconfig" |
| 80 | source "drivers/media/platform/qcom/Kconfig" | 81 | source "drivers/media/platform/qcom/Kconfig" |
| 82 | source "drivers/media/platform/raspberrypi/Kconfig" | ||
| 81 | source "drivers/media/platform/renesas/Kconfig" | 83 | source "drivers/media/platform/renesas/Kconfig" |
| 82 | source "drivers/media/platform/rockchip/Kconfig" | 84 | source "drivers/media/platform/rockchip/Kconfig" |
| 83 | source "drivers/media/platform/samsung/Kconfig" | 85 | source "drivers/media/platform/samsung/Kconfig" |
| @@ -13,6 +13,7 @@ obj-y += atmel/ · 12 unmodified lines | |||
| 13 | obj-y += broadcom/ | 13 | obj-y += broadcom/ |
| 14 | obj-y += cadence/ | 14 | obj-y += cadence/ |
| 15 | obj-y += chips-media/ | 15 | obj-y += chips-media/ |
| 16 | obj-y += imagination/ | ||
| 16 | obj-y += intel/ | 17 | obj-y += intel/ |
| 17 | obj-y += marvell/ | 18 | obj-y += marvell/ |
| 18 | obj-y += mediatek/ | 19 | obj-y += mediatek/ |
| @@ -21,6 +22,7 @@ obj-y += nuvoton/ · 2 unmodified lines | |||
| 21 | obj-y += nvidia/ | 22 | obj-y += nvidia/ |
| 22 | obj-y += nxp/ | 23 | obj-y += nxp/ |
| 23 | obj-y += qcom/ | 24 | obj-y += qcom/ |
| 25 | obj-y += raspberrypi/ | ||
| 24 | obj-y += renesas/ | 26 | obj-y += renesas/ |
| 25 | obj-y += rockchip/ | 27 | obj-y += rockchip/ |
| 26 | obj-y += samsung/ | 28 | obj-y += samsung/ |
| @@ -96,10 +96,11 @@ struct nal_hevc_vps { · 95 unmodified lines | |||
| 96 | unsigned int extension_data_flag; | 96 | unsigned int extension_data_flag; |
| 97 | }; | 97 | }; |
| 98 | 98 | ||
| 99 | #define N_HRD_PARAMS 1 | ||
| 99 | struct nal_hevc_sub_layer_hrd_parameters { | 100 | struct nal_hevc_sub_layer_hrd_parameters { |
| 100 | unsigned int bit_rate_value_minus1[1]; | 101 | unsigned int bit_rate_value_minus1[N_HRD_PARAMS]; |
| 101 | unsigned int cpb_size_value_minus1[1]; | 102 | unsigned int cpb_size_value_minus1[N_HRD_PARAMS]; |
| 102 | unsigned int cbr_flag[1]; | 103 | unsigned int cbr_flag[N_HRD_PARAMS]; |
| 103 | }; | 104 | }; |
| 104 | 105 | ||
| 105 | struct nal_hevc_hrd_parameters { | 106 | struct nal_hevc_hrd_parameters { |
| @@ -195,7 +195,6 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl) · 194 unmodified lines | |||
| 195 | struct vdec_t *vdec = inst->priv; | 195 | struct vdec_t *vdec = inst->priv; |
| 196 | int ret = 0; | 196 | int ret = 0; |
| 197 | 197 | ||
| 198 | vpu_inst_lock(inst); | ||
| 199 | switch (ctrl->id) { | 198 | switch (ctrl->id) { |
| 200 | case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: | 199 | case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE: |
| 201 | vdec->params.display_delay_enable = ctrl->val; | 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 | ret = -EINVAL; | 206 | ret = -EINVAL; |
| 208 | break; | 207 | break; |
| 209 | } | 208 | } |
| 210 | vpu_inst_unlock(inst); | ||
| 211 | 209 | ||
| 212 | return ret; | 210 | return ret; |
| 213 | } | 211 | } |
| @@ -518,7 +518,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) · 517 unmodified lines | |||
| 518 | struct venc_t *venc = inst->priv; | 518 | struct venc_t *venc = inst->priv; |
| 519 | int ret = 0; | 519 | int ret = 0; |
| 520 | 520 | ||
| 521 | vpu_inst_lock(inst); | ||
| 522 | switch (ctrl->id) { | 521 | switch (ctrl->id) { |
| 523 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: | 522 | case V4L2_CID_MPEG_VIDEO_H264_PROFILE: |
| 524 | venc->params.profile = ctrl->val; | 523 | venc->params.profile = ctrl->val; |
| @@ -579,7 +578,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl) · 54 unmodified lines | |||
| 579 | ret = -EINVAL; | 578 | ret = -EINVAL; |
| 580 | break; | 579 | break; |
| 581 | } | 580 | } |
| 582 | vpu_inst_unlock(inst); | ||
| 583 | 581 | ||
| 584 | return ret; | 582 | return ret; |
| 585 | } | 583 | } |
| @@ -680,6 +678,9 @@ static int venc_ctrl_init(struct vpu_inst *inst) · 94 unmodified lines | |||
| 680 | ~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), | 678 | ~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME), |
| 681 | V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME); | 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 | if (inst->ctrl_handler.error) { | 684 | if (inst->ctrl_handler.error) { |
| 684 | ret = inst->ctrl_handler.error; | 685 | ret = inst->ctrl_handler.error; |
| 685 | v4l2_ctrl_handler_free(&inst->ctrl_handler); | 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 | vbuf->field = inst->cap_format.field; | 820 | vbuf->field = inst->cap_format.field; |
| 820 | vbuf->flags |= frame->info.pic_type; | 821 | vbuf->flags |= frame->info.pic_type; |
| 821 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); | 822 | vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE); |
| 823 | vpu_set_buffer_average_qp(vbuf, frame->info.average_qp); | ||
| 822 | dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); | 824 | dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp); |
| 823 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); | 825 | v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE); |
| 824 | venc->ready_count++; | 826 | venc->ready_count++; |
| @@ -306,6 +306,7 @@ struct vpu_vb2_buffer { · 305 unmodified lines | |||
| 306 | dma_addr_t chroma_v; | 306 | dma_addr_t chroma_v; |
| 307 | unsigned int state; | 307 | unsigned int state; |
| 308 | u32 tag; | 308 | u32 tag; |
| 309 | u32 average_qp; | ||
| 309 | }; | 310 | }; |
| 310 | 311 | ||
| 311 | void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val); | 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 | u32 wptr; | 114 | u32 wptr; |
| 115 | u32 crc; | 115 | u32 crc; |
| 116 | s64 timestamp; | 116 | s64 timestamp; |
| 117 | u32 average_qp; | ||
| 117 | }; | 118 | }; |
| 118 | 119 | ||
| 119 | struct vpu_dec_codec_info { | 120 | struct vpu_dec_codec_info { |
| @@ -207,11 +207,6 @@ struct vpu_malone_dbglog_desc { · 206 unmodified lines | |||
| 207 | u32 reserved; | 207 | u32 reserved; |
| 208 | }; | 208 | }; |
| 209 | 209 | ||
| 210 | struct vpu_malone_frame_buffer { | ||
| 211 | u32 addr; | ||
| 212 | u32 size; | ||
| 213 | }; | ||
| 214 | |||
| 215 | struct vpu_malone_udata { | 210 | struct vpu_malone_udata { |
| 216 | u32 base; | 211 | u32 base; |
| 217 | u32 total_size; | 212 | u32 total_size; |
| @@ -63,6 +63,13 @@ unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf) · 62 unmodified lines | |||
| 63 | return vpu_buf->state; | 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 | void vpu_v4l2_set_error(struct vpu_inst *inst) | 73 | void vpu_v4l2_set_error(struct vpu_inst *inst) |
| 67 | { | 74 | { |
| 68 | vpu_inst_lock(inst); | 75 | vpu_inst_lock(inst); |
| @@ -539,6 +546,15 @@ static void vpu_vb2_buf_finish(struct vb2_buffer *vb) · 470 unmodified lines | |||
| 539 | struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue); | 546 | struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue); |
| 540 | struct vb2_queue *q = vb->vb2_queue; | 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 | if (vbuf->flags & V4L2_BUF_FLAG_LAST) | 558 | if (vbuf->flags & V4L2_BUF_FLAG_LAST) |
| 543 | vpu_notify_eos(inst); | 559 | vpu_notify_eos(inst); |
| 544 | 560 | ||
| @@ -12,6 +12,7 @@ void vpu_inst_lock(struct vpu_inst *inst); · 11 unmodified lines | |||
| 12 | void vpu_inst_unlock(struct vpu_inst *inst); | 12 | void vpu_inst_unlock(struct vpu_inst *inst); |
| 13 | void vpu_set_buffer_state(struct vb2_v4l2_buffer *vbuf, unsigned int state); | 13 | void vpu_set_buffer_state(struct vb2_v4l2_buffer *vbuf, unsigned int state); |
| 14 | unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf); | 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 | int vpu_v4l2_open(struct file *file, struct vpu_inst *inst); | 17 | int vpu_v4l2_open(struct file *file, struct vpu_inst *inst); |
| 17 | int vpu_v4l2_close(struct file *file); | 18 | int vpu_v4l2_close(struct file *file); |
| @@ -499,6 +499,7 @@ struct windsor_pic_info { · 498 unmodified lines | |||
| 499 | u32 proc_dacc_rng_wr_cnt; | 499 | u32 proc_dacc_rng_wr_cnt; |
| 500 | s32 tv_s; | 500 | s32 tv_s; |
| 501 | u32 tv_ns; | 501 | u32 tv_ns; |
| 502 | u32 average_qp; | ||
| 502 | }; | 503 | }; |
| 503 | 504 | ||
| 504 | u32 vpu_windsor_get_data_size(void) | 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 | info->wptr = get_ptr(windsor->str_buff_wptr); | 735 | info->wptr = get_ptr(windsor->str_buff_wptr); |
| 735 | info->crc = windsor->frame_crc; | 736 | info->crc = windsor->frame_crc; |
| 736 | info->timestamp = timespec64_to_ns(&ts); | 737 | info->timestamp = timespec64_to_ns(&ts); |
| 738 | info->average_qp = windsor->average_qp; | ||
| 737 | } | 739 | } |
| 738 | 740 | ||
| 739 | static void vpu_windsor_unpack_mem_req(struct vpu_rpc_event *pkt, void *data) | 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 | int i; | 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 | wave5_vdi_free_sram(inst->dev); | 39 | wave5_vdi_free_sram(inst->dev); |
| 34 | 40 | ||
| 35 | for (i = 0; i < inst->fbc_buf_count; i++) | 41 | for (i = 0; i < inst->fbc_buf_count; i++) |
| @@ -18,18 +18,20 @@ · 17 unmodified lines | |||
| 18 | #define QUEUE_REPORT_MASK 0xffff | 18 | #define QUEUE_REPORT_MASK 0xffff |
| 19 | 19 | ||
| 20 | /* Encoder support fields */ | 20 | /* Encoder support fields */ |
| 21 | #define FEATURE_HEVC10BIT_ENC BIT(3) | 21 | #define W521_FEATURE_HEVC10BIT_ENC BIT(3) |
| 22 | #define FEATURE_AVC10BIT_ENC BIT(11) | 22 | #define W521_FEATURE_AVC10BIT_ENC BIT(11) |
| 23 | #define FEATURE_AVC_ENCODER BIT(1) | 23 | #define W521_FEATURE_AVC_ENCODER BIT(1) |
| 24 | #define FEATURE_HEVC_ENCODER BIT(0) | 24 | #define W521_FEATURE_HEVC_ENCODER BIT(0) |
| 25 | 25 | ||
| 26 | /* Decoder support fields */ | 26 | /* Decoder support fields */ |
| 27 | #define FEATURE_AVC_DECODER BIT(3) | 27 | #define W521_FEATURE_AVC_DECODER BIT(3) |
| 28 | #define FEATURE_HEVC_DECODER BIT(2) | 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) | 32 | #define W521_FEATURE_BACKBONE BIT(16) |
| 31 | #define FEATURE_VCORE_BACKBONE BIT(22) | 33 | #define W521_FEATURE_VCORE_BACKBONE BIT(22) |
| 32 | #define FEATURE_VCPU_BACKBONE BIT(28) | 34 | #define W521_FEATURE_VCPU_BACKBONE BIT(28) |
| 33 | 35 | ||
| 34 | #define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) | 36 | #define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff) |
| 35 | #define REMAP_CTRL_REGISTER_VALUE(index) ( \ | 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 | u32 gdi_status_check_value = 0x3f; | 158 | u32 gdi_status_check_value = 0x3f; |
| 157 | 159 | ||
| 160 | if (vpu_dev->product_code == WAVE515_CODE) | ||
| 161 | gdi_status_check_value = 0x0738; | ||
| 158 | if (vpu_dev->product_code == WAVE521C_CODE || | 162 | if (vpu_dev->product_code == WAVE521C_CODE || |
| 159 | vpu_dev->product_code == WAVE521_CODE || | 163 | vpu_dev->product_code == WAVE521_CODE || |
| 160 | vpu_dev->product_code == WAVE521E1_CODE) | 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 | u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER); | 190 | u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER); |
| 187 | 191 | ||
| 188 | switch (val) { | 192 | switch (val) { |
| 193 | case WAVE515_CODE: | ||
| 194 | return PRODUCT_ID_515; | ||
| 189 | case WAVE521C_CODE: | 195 | case WAVE521C_CODE: |
| 190 | return PRODUCT_ID_521; | 196 | return PRODUCT_ID_521; |
| 191 | case WAVE521_CODE: | 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 | return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL); | 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 | static int setup_wave5_properties(struct device *dev) | 329 | static int setup_wave5_properties(struct device *dev) |
| 303 | { | 330 | { |
| 304 | struct vpu_device *vpu_dev = dev_get_drvdata(dev); | 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 | hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1); | 355 | hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1); |
| 329 | hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE); | 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); | 358 | if (vpu_dev->product_code == WAVE515_CODE) { |
| 332 | p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature); | 359 | p_attr->support_hevc10bit_dec = FIELD_GET(W515_FEATURE_HEVC10BIT_DEC, |
| 333 | 360 | hw_config_feature); | |
| 334 | p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC; | 361 | p_attr->support_decoders = FIELD_GET(W515_FEATURE_HEVC_DECODER, |
| 335 | p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC; | 362 | hw_config_def1) << STD_HEVC; |
| 336 | p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC; | 363 | } else { |
| 337 | p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC; | 364 | p_attr->support_hevc10bit_enc = FIELD_GET(W521_FEATURE_HEVC10BIT_ENC, |
| 338 | 365 | hw_config_feature); | |
| 339 | p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0); | 366 | p_attr->support_avc10bit_enc = FIELD_GET(W521_FEATURE_AVC10BIT_ENC, |
| 340 | p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0); | 367 | hw_config_feature); |
| 341 | p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0); | 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 | return 0; | 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 | common_vb = &vpu_dev->common_mem; | 425 | common_vb = &vpu_dev->common_mem; |
| 381 | 426 | ||
| 382 | code_base = common_vb->daddr; | 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 | /* ALIGN TO 4KB */ | 434 | /* ALIGN TO 4KB */ |
| 384 | code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); | 435 | code_size &= ~0xfff; |
| 385 | if (code_size < size * 2) | 436 | if (code_size < size * 2) |
| 386 | return -EINVAL; | 437 | return -EINVAL; |
| 387 | 438 | ||
| 388 | temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; | 439 | temp_base = code_base + code_size; |
| 389 | temp_size = WAVE5_TEMPBUF_SIZE; | 440 | temp_size = WAVE5_TEMPBUF_SIZE; |
| 390 | 441 | ||
| 391 | ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size); | 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 | /* These register must be reset explicitly */ | 465 | /* These register must be reset explicitly */ |
| 415 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); | 466 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); |
| 416 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); | 467 | |
| 417 | wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | 468 | if (vpu_dev->product_code != WAVE515_CODE) { |
| 418 | vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); | 469 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); |
| 419 | 470 | wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); | |
| 420 | /* Encoder interrupt */ | 471 | vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); |
| 421 | reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); | 472 | } |
| 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); | ||
| 429 | 473 | ||
| 430 | reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); | 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 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | | 476 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | |
| 433 | (WAVE5_PRP_AXI_ID << 24) | | 477 | (WAVE5_PRP_AXI_ID << 24) | |
| 434 | (WAVE5_FBD_Y_AXI_ID << 20) | | 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 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); | 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 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); | 505 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); |
| 444 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); | 506 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); |
| 445 | vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); | 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 | return -EINVAL; | 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 | ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work); | 550 | ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work); |
| 485 | if (ret) | 551 | if (ret) |
| 486 | return ret; | 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 | wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work); | 557 | wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work); |
| 491 | 558 | ||
| 492 | vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr); | 559 | vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr); |
| 493 | vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size); | 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); | 562 | if (inst->dev->product_code != WAVE515_CODE) { |
| 496 | vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size); | 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 | vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr); | 567 | vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr); |
| 499 | vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size); | 568 | vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size); |
| 500 | 569 | ||
| 501 | /* NOTE: SDMA reads MSB first */ | 570 | /* NOTE: SDMA reads MSB first */ |
| 502 | vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN); | 571 | vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN); |
| 503 | /* This register must be reset explicitly */ | 572 | |
| 504 | vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); | 573 | if (inst->dev->product_code != WAVE515_CODE) { |
| 505 | vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1)); | 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 | ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); | 580 | ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL); |
| 508 | if (ret) { | 581 | if (ret) { |
| @@ -553,7 +626,7 @@ static u32 get_bitstream_options(struct dec_info *info) · 44 unmodified lines | |||
| 553 | int wave5_vpu_dec_init_seq(struct vpu_instance *inst) | 626 | int wave5_vpu_dec_init_seq(struct vpu_instance *inst) |
| 554 | { | 627 | { |
| 555 | struct dec_info *p_dec_info = &inst->codec_info->dec_info; | 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 | u32 reg_val, fail_res; | 630 | u32 reg_val, fail_res; |
| 558 | int ret; | 631 | int ret; |
| 559 | 632 | ||
| @@ -563,7 +636,13 @@ int wave5_vpu_dec_init_seq(struct vpu_instance *inst) · 3 unmodified lines | |||
| 563 | vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); | 636 | vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr); |
| 564 | vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr); | 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 | vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option); | 647 | vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option); |
| 569 | vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable); | 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 | info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val); | 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); | 711 | if (inst->dev->product_code != WAVE515_CODE) { |
| 633 | info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); | 712 | info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE); |
| 634 | p_dec_info->vlc_buf_size = info->vlc_buf_size; | 713 | info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE); |
| 635 | p_dec_info->param_buf_size = info->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 | int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info) | 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 | pic_size = (init_info->pic_width << 16) | (init_info->pic_height); | 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) + | 818 | if (inst->dev->product_code != WAVE515_CODE) { |
| 738 | (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH); | 819 | vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) + |
| 739 | vb_buf.daddr = 0; | 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) { | 823 | if (vb_buf.size != p_dec_info->vb_task.size) { |
| 742 | wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task); | 824 | wave5_vdi_free_dma_memory(inst->dev, |
| 743 | ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf); | 825 | &p_dec_info->vb_task); |
| 744 | if (ret) | 826 | ret = wave5_vdi_allocate_dma_memory(inst->dev, |
| 745 | goto free_fbc_c_tbl_buffers; | 827 | &vb_buf); |
| 828 | if (ret) | ||
| 829 | goto free_fbc_c_tbl_buffers; | ||
| 746 | 830 | ||
| 747 | p_dec_info->vb_task = vb_buf; | 831 | p_dec_info->vb_task = vb_buf; |
| 748 | } | 832 | } |
| 749 | 833 | ||
| 750 | vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, | 834 | vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF, |
| 751 | p_dec_info->vb_task.daddr); | 835 | p_dec_info->vb_task.daddr); |
| 752 | vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size); | 836 | vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, |
| 837 | vb_buf.size); | ||
| 838 | } | ||
| 753 | } else { | 839 | } else { |
| 754 | pic_size = (init_info->pic_width << 16) | (init_info->pic_height); | 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 | return ret; | 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 | int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) | 956 | int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) |
| 834 | { | 957 | { |
| 835 | u32 reg_val; | 958 | u32 reg_val; |
| @@ -842,9 +965,7 @@ int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res) · 6 unmodified lines | |||
| 842 | vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); | 965 | vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info)); |
| 843 | 966 | ||
| 844 | /* secondary AXI */ | 967 | /* secondary AXI */ |
| 845 | reg_val = p_dec_info->sec_axi_info.use_bit_enable | | 968 | reg_val = wave5_vpu_dec_validate_sec_axi(inst); |
| 846 | (p_dec_info->sec_axi_info.use_ip_enable << 9) | | ||
| 847 | (p_dec_info->sec_axi_info.use_lf_row_enable << 15); | ||
| 848 | vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val); | 969 | vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val); |
| 849 | 970 | ||
| 850 | /* set attributes of user buffer */ | 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 | common_vb = &vpu_dev->common_mem; | 1113 | common_vb = &vpu_dev->common_mem; |
| 993 | 1114 | ||
| 994 | code_base = common_vb->daddr; | 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 | /* ALIGN TO 4KB */ | 1122 | /* ALIGN TO 4KB */ |
| 996 | code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); | 1123 | code_size &= ~0xfff; |
| 997 | if (code_size < size * 2) | 1124 | if (code_size < size * 2) |
| 998 | return -EINVAL; | 1125 | return -EINVAL; |
| 999 | temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET; | 1126 | |
| 1127 | temp_base = code_base + code_size; | ||
| 1000 | temp_size = WAVE5_TEMPBUF_SIZE; | 1128 | temp_size = WAVE5_TEMPBUF_SIZE; |
| 1001 | 1129 | ||
| 1002 | old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR); | 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 | /* These register must be reset explicitly */ | 1159 | /* These register must be reset explicitly */ |
| 1032 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); | 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 */ | 1162 | if (vpu_dev->product_code != WAVE515_CODE) { |
| 1038 | reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); | 1163 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); |
| 1039 | reg_val |= BIT(INT_WAVE5_ENC_PIC); | 1164 | wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); |
| 1040 | reg_val |= BIT(INT_WAVE5_BSBUF_FULL); | 1165 | vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); |
| 1041 | /* Decoder interrupt */ | 1166 | } |
| 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); | ||
| 1046 | 1167 | ||
| 1047 | reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); | 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 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | | 1170 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | |
| 1050 | (WAVE5_PRP_AXI_ID << 24) | | 1171 | (WAVE5_PRP_AXI_ID << 24) | |
| 1051 | (WAVE5_FBD_Y_AXI_ID << 20) | | 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 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); | 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 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); | 1204 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); |
| 1061 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); | 1205 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU); |
| 1062 | vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1); | 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 | u32 reg_val; | 1225 | u32 reg_val; |
| 1082 | struct vpu_buf *common_vb; | 1226 | struct vpu_buf *common_vb; |
| 1083 | dma_addr_t code_base; | 1227 | dma_addr_t code_base, temp_base; |
| 1084 | u32 code_size, reason_code; | 1228 | u32 code_size, temp_size, reason_code; |
| 1085 | struct vpu_device *vpu_dev = dev_get_drvdata(dev); | 1229 | struct vpu_device *vpu_dev = dev_get_drvdata(dev); |
| 1086 | int ret; | 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 | common_vb = &vpu_dev->common_mem; | 1255 | common_vb = &vpu_dev->common_mem; |
| 1112 | 1256 | ||
| 1113 | code_base = common_vb->daddr; | 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 | /* ALIGN TO 4KB */ | 1264 | /* ALIGN TO 4KB */ |
| 1115 | code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff); | 1265 | code_size &= ~0xfff; |
| 1116 | if (code_size < size * 2) { | 1266 | if (code_size < size * 2) { |
| 1117 | dev_err(dev, "size too small\n"); | 1267 | dev_err(dev, "size too small\n"); |
| 1118 | return -EINVAL; | 1268 | return -EINVAL; |
| 1119 | } | 1269 | } |
| 1120 | 1270 | ||
| 1271 | temp_base = code_base + code_size; | ||
| 1272 | temp_size = WAVE5_TEMPBUF_SIZE; | ||
| 1273 | |||
| 1121 | /* Power on without DEBUG mode */ | 1274 | /* Power on without DEBUG mode */ |
| 1122 | vpu_write_reg(vpu_dev, W5_PO_CONF, 0); | 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 | /* These register must be reset explicitly */ | 1284 | /* These register must be reset explicitly */ |
| 1132 | vpu_write_reg(vpu_dev, W5_HW_OPTION, 0); | 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 */ | 1287 | if (vpu_dev->product_code != WAVE515_CODE) { |
| 1138 | reg_val = BIT(INT_WAVE5_ENC_SET_PARAM); | 1288 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0); |
| 1139 | reg_val |= BIT(INT_WAVE5_ENC_PIC); | 1289 | wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0); |
| 1140 | reg_val |= BIT(INT_WAVE5_BSBUF_FULL); | 1290 | vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0); |
| 1141 | /* Decoder interrupt */ | 1291 | } |
| 1142 | reg_val |= BIT(INT_WAVE5_INIT_SEQ); | 1292 | |
| 1143 | reg_val |= BIT(INT_WAVE5_DEC_PIC); | 1293 | setup_wave5_interrupts(vpu_dev); |
| 1144 | reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY); | ||
| 1145 | vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val); | ||
| 1146 | 1294 | ||
| 1147 | reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0); | 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 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | | 1297 | reg_val = ((WAVE5_PROC_AXI_ID << 28) | |
| 1150 | (WAVE5_PRP_AXI_ID << 24) | | 1298 | (WAVE5_PRP_AXI_ID << 24) | |
| 1151 | (WAVE5_FBD_Y_AXI_ID << 20) | | 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 | wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val); | 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 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); | 1331 | vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1); |
| 1161 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU); | 1332 | vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU); |
| 1162 | /* Start VPU after settings */ | 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 | reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN; | 1572 | reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN; |
| 1402 | vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val); | 1573 | vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val); |
| 1403 | vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0); | 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 | /* This register must be reset explicitly */ | 1577 | /* This register must be reset explicitly */ |
| 1407 | vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0); | 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 | p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf; | 2026 | p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf; |
| 1856 | 2027 | ||
| 1857 | vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) + | 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 | vb_task.daddr = 0; | 2030 | vb_task.daddr = 0; |
| 1860 | if (p_enc_info->vb_task.size == 0) { | 2031 | if (p_enc_info->vb_task.size == 0) { |
| 1861 | ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task); | 2032 | ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task); |
| @@ -1943,6 +2114,31 @@ free_vb_fbc_y_tbl: · 81 unmodified lines | |||
| 1943 | return ret; | 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 | int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res) | 2142 | int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res) |
| 1947 | { | 2143 | { |
| 1948 | u32 src_frame_format; | 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 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI); | 2161 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI); |
| 1966 | /* secondary AXI */ | 2162 | /* secondary AXI */ |
| 1967 | reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) | | 2163 | reg_val = wave5_vpu_enc_validate_sec_axi(inst); |
| 1968 | (p_enc_info->sec_axi_info.use_enc_lf_enable << 15); | ||
| 1969 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val); | 2164 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val); |
| 1970 | 2165 | ||
| 1971 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0); | 2166 | vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0); |
| @@ -205,6 +205,9 @@ enum query_opt { · 204 unmodified lines | |||
| 205 | #define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C) | 205 | #define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C) |
| 206 | #define W5_TEMP_SIZE (W5_REG_BASE + 0x0120) | 206 | #define W5_TEMP_SIZE (W5_REG_BASE + 0x0120) |
| 207 | #define W5_HW_OPTION (W5_REG_BASE + 0x012C) | 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 | #define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180) | 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 | #define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120) | 219 | #define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120) |
| 217 | #define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124) | 220 | #define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124) |
| 218 | #define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130) | 221 | #define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130) |
| 222 | #define W515_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0124) | ||
| 219 | #define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134) | 223 | #define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134) |
| 224 | #define W515_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0128) | ||
| 220 | #define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138) | 225 | #define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138) |
| 221 | #define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C) | 226 | #define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C) |
| 222 | #define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140) | 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 | if (!vpu_dev->common_mem.vaddr) { | 18 | if (!vpu_dev->common_mem.vaddr) { |
| 19 | int ret; | 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 | ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem); | 26 | ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem); |
| 23 | if (ret) { | 27 | if (ret) { |
| 24 | dev_err(dev, "unable to allocate common buffer\n"); | 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 | void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev) | 178 | void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev) |
| 175 | { | 179 | { |
| 176 | struct vpu_buf *vb = &vpu_dev->sram_buf; | 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 | return; | 186 | return; |
| 180 | 187 | ||
| 181 | if (!vb->vaddr) { | 188 | size = min_t(size_t, vpu_dev->sram_size, gen_pool_avail(vpu_dev->sram_pool)); |
| 182 | vb->size = vpu_dev->sram_size; | 189 | vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, size, &daddr); |
| 183 | vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size, | 190 | if (vaddr) { |
| 184 | &vb->daddr); | 191 | vb->vaddr = vaddr; |
| 185 | if (!vb->vaddr) | 192 | vb->daddr = daddr; |
| 186 | vb->size = 0; | 193 | vb->size = size; |
| 187 | } | 194 | } |
| 188 | 195 | ||
| 189 | dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n", | 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 | if (!vb->size || !vb->vaddr) | 204 | if (!vb->size || !vb->vaddr) |
| 198 | return; | 205 | return; |
| 199 | 206 | ||
| 200 | if (vb->vaddr) | 207 | gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, vb->size); |
| 201 | gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, | ||
| 202 | vb->size); | ||
| 203 | 208 | ||
| 204 | memset(vb, 0, sizeof(*vb)); | 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 | int ret, i; | 1055 | int ret, i; |
| 1056 | struct v4l2_m2m_buffer *buf, *n; | 1056 | struct v4l2_m2m_buffer *buf, *n; |
| 1057 | struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx; | 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 | linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx); | 1075 | linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx); |
| 1060 | non_linear_num = inst->fbc_buf_count; | 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 | struct frame_buffer *frame = &inst->frame_buf[i]; | 1079 | struct frame_buffer *frame = &inst->frame_buf[i]; |
| 1064 | struct vpu_buf *vframe = &inst->frame_vbuf[i]; | 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 | fb_height = ALIGN(inst->dst_fmt.height, 32); | 1083 | fb_height = ALIGN(inst->dst_fmt.height, 32); |
| 1068 | luma_size = fb_stride * fb_height; | 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 | if (ret) | 1424 | if (ret) |
| 1409 | goto free_bitstream_vbuf; | 1425 | goto free_bitstream_vbuf; |
| 1410 | } else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { | 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 | if (inst->state == VPU_INST_STATE_STOP) | 1427 | if (inst->state == VPU_INST_STATE_STOP) |
| 1415 | ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); | 1428 | ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ); |
| 1416 | if (ret) | 1429 | if (ret) |
| 1417 | goto return_buffers; | 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 | return ret; | 1433 | return ret; |
| @@ -1864,7 +1868,12 @@ static int wave5_vpu_open_dec(struct file *filp) · 434 unmodified lines | |||
| 1864 | goto cleanup_inst; | 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 | ret = mutex_lock_interruptible(&dev->dev_lock); | 1878 | ret = mutex_lock_interruptible(&dev->dev_lock); |
| 1870 | if (ret) | 1879 | if (ret) |
| @@ -1904,6 +1913,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev) · 33 unmodified lines | |||
| 1904 | struct video_device *vdev_dec; | 1913 | struct video_device *vdev_dec; |
| 1905 | int ret; | 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 | vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL); | 1923 | vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL); |
| 1908 | if (!vdev_dec) | 1924 | if (!vdev_dec) |
| 1909 | return -ENOMEM; | 1925 | return -ENOMEM; |
| @@ -1937,6 +1953,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev) · 27 unmodified lines | |||
| 1937 | 1953 | ||
| 1938 | void wave5_vpu_dec_unregister_device(struct vpu_device *dev) | 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 | video_unregister_device(dev->video_dev_dec); | 1963 | video_unregister_device(dev->video_dev_dec); |
| 1941 | if (dev->v4l2_m2m_dec_dev) | 1964 | if (dev->v4l2_m2m_dec_dev) |
| 1942 | v4l2_m2m_release(dev->v4l2_m2m_dec_dev); | 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 | __func__, initial_info.min_frame_buffer_count, | 1247 | __func__, initial_info.min_frame_buffer_count, |
| 1248 | initial_info.min_src_frame_count); | 1248 | initial_info.min_src_frame_count); |
| 1249 | inst->min_src_buf_count = initial_info.min_src_frame_count + | 1249 | inst->min_src_buf_count = initial_info.min_src_frame_count + |
| 1250 | COMMAND_QUEUE_DEPTH; | 1250 | WAVE521_COMMAND_QUEUE_DEPTH; |
| 1251 | 1251 | ||
| 1252 | ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, | 1252 | ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl, |
| 1253 | V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); | 1253 | V4L2_CID_MIN_BUFFERS_FOR_OUTPUT); |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
| 11 | #include <linux/firmware.h> | 11 | #include <linux/firmware.h> |
| 12 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
| 13 | #include <linux/reset.h> | ||
| 13 | #include "wave5-vpu.h" | 14 | #include "wave5-vpu.h" |
| 14 | #include "wave5-regdefine.h" | 15 | #include "wave5-regdefine.h" |
| 15 | #include "wave5-vpuconfig.h" | 16 | #include "wave5-vpuconfig.h" |
| @@ -24,6 +25,7 @@ · 8 unmodified lines | |||
| 24 | struct wave5_match_data { | 25 | struct wave5_match_data { |
| 25 | int flags; | 26 | int flags; |
| 26 | const char *fw_name; | 27 | const char *fw_name; |
| 28 | u32 sram_size; | ||
| 27 | }; | 29 | }; |
| 28 | 30 | ||
| 29 | static int vpu_poll_interval = 5; | 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 | if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || | 64 | if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) || |
| 63 | irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) { | 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 | seq_done &= ~BIT(inst->id); | 73 | seq_done &= ~BIT(inst->id); |
| 66 | wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, | 74 | wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO, |
| 67 | seq_done); | 75 | seq_done); |
| @@ -179,6 +187,16 @@ static int wave5_vpu_probe(struct platform_device *pdev) · 111 unmodified lines | |||
| 179 | dev_set_drvdata(&pdev->dev, dev); | 187 | dev_set_drvdata(&pdev->dev, dev); |
| 180 | dev->dev = &pdev->dev; | 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 | ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks); | 200 | ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks); |
| 183 | 201 | ||
| 184 | /* continue without clock, assume externally managed */ | 202 | /* continue without clock, assume externally managed */ |
| @@ -191,20 +209,15 @@ static int wave5_vpu_probe(struct platform_device *pdev) · 6 unmodified lines | |||
| 191 | ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks); | 209 | ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks); |
| 192 | if (ret) { | 210 | if (ret) { |
| 193 | dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret); | 211 | dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret); |
| 194 | return ret; | 212 | goto err_reset_assert; |
| 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; | ||
| 202 | } | 213 | } |
| 203 | 214 | ||
| 204 | dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); | 215 | dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0); |
| 205 | if (!dev->sram_pool) | 216 | if (!dev->sram_pool) |
| 206 | dev_warn(&pdev->dev, "sram node not found\n"); | 217 | dev_warn(&pdev->dev, "sram node not found\n"); |
| 207 | 218 | ||
| 219 | dev->sram_size = match_data->sram_size; | ||
| 220 | |||
| 208 | dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER); | 221 | dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER); |
| 209 | ret = wave5_vdi_init(&pdev->dev); | 222 | ret = wave5_vdi_init(&pdev->dev); |
| 210 | if (ret < 0) { | 223 | if (ret < 0) { |
| @@ -282,6 +295,8 @@ err_vdi_release: · 71 unmodified lines | |||
| 282 | wave5_vdi_release(&pdev->dev); | 295 | wave5_vdi_release(&pdev->dev); |
| 283 | err_clk_dis: | 296 | err_clk_dis: |
| 284 | clk_bulk_disable_unprepare(dev->num_clks, dev->clks); | 297 | clk_bulk_disable_unprepare(dev->num_clks, dev->clks); |
| 298 | err_reset_assert: | ||
| 299 | reset_control_assert(dev->resets); | ||
| 285 | 300 | ||
| 286 | return ret; | 301 | return ret; |
| 287 | } | 302 | } |
| @@ -297,6 +312,7 @@ static void wave5_vpu_remove(struct platform_device *pdev) · 9 unmodified lines | |||
| 297 | 312 | ||
| 298 | mutex_destroy(&dev->dev_lock); | 313 | mutex_destroy(&dev->dev_lock); |
| 299 | mutex_destroy(&dev->hw_lock); | 314 | mutex_destroy(&dev->hw_lock); |
| 315 | reset_control_assert(dev->resets); | ||
| 300 | clk_bulk_disable_unprepare(dev->num_clks, dev->clks); | 316 | clk_bulk_disable_unprepare(dev->num_clks, dev->clks); |
| 301 | wave5_vpu_enc_unregister_device(dev); | 317 | wave5_vpu_enc_unregister_device(dev); |
| 302 | wave5_vpu_dec_unregister_device(dev); | 318 | wave5_vpu_dec_unregister_device(dev); |
| @@ -308,6 +324,7 @@ static void wave5_vpu_remove(struct platform_device *pdev) · 5 unmodified lines | |||
| 308 | static const struct wave5_match_data ti_wave521c_data = { | 324 | static const struct wave5_match_data ti_wave521c_data = { |
| 309 | .flags = WAVE5_IS_ENC | WAVE5_IS_DEC, | 325 | .flags = WAVE5_IS_ENC | WAVE5_IS_DEC, |
| 310 | .fw_name = "cnm/wave521c_k3_codec_fw.bin", | 326 | .fw_name = "cnm/wave521c_k3_codec_fw.bin", |
| 327 | .sram_size = (64 * 1024), | ||
| 311 | }; | 328 | }; |
| 312 | 329 | ||
| 313 | static const struct of_device_id wave5_dt_ids[] = { | 330 | static const struct of_device_id wave5_dt_ids[] = { |
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include "wave5-vdi.h" | 18 | #include "wave5-vdi.h" |
| 19 | 19 | ||
| 20 | enum product_id { | 20 | enum product_id { |
| 21 | PRODUCT_ID_515, | ||
| 21 | PRODUCT_ID_521, | 22 | PRODUCT_ID_521, |
| 22 | PRODUCT_ID_511, | 23 | PRODUCT_ID_511, |
| 23 | PRODUCT_ID_517, | 24 | PRODUCT_ID_517, |
| @@ -327,6 +328,7 @@ struct vpu_attr { · 303 unmodified lines | |||
| 327 | u32 support_backbone: 1; | 328 | u32 support_backbone: 1; |
| 328 | u32 support_avc10bit_enc: 1; | 329 | u32 support_avc10bit_enc: 1; |
| 329 | u32 support_hevc10bit_enc: 1; | 330 | u32 support_hevc10bit_enc: 1; |
| 331 | u32 support_hevc10bit_dec: 1; | ||
| 330 | u32 support_vcore_backbone: 1; | 332 | u32 support_vcore_backbone: 1; |
| 331 | u32 support_vcpu_backbone: 1; | 333 | u32 support_vcpu_backbone: 1; |
| 332 | }; | 334 | }; |
| @@ -761,6 +763,7 @@ struct vpu_device { · 428 unmodified lines | |||
| 761 | struct kthread_worker *worker; | 763 | struct kthread_worker *worker; |
| 762 | int vpu_poll_interval; | 764 | int vpu_poll_interval; |
| 763 | int num_clks; | 765 | int num_clks; |
| 766 | struct reset_control *resets; | ||
| 764 | }; | 767 | }; |
| 765 | 768 | ||
| 766 | struct vpu_instance; | 769 | struct vpu_instance; |
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | #ifndef _VPU_CONFIG_H_ | 8 | #ifndef _VPU_CONFIG_H_ |
| 9 | #define _VPU_CONFIG_H_ | 9 | #define _VPU_CONFIG_H_ |
| 10 | 10 | ||
| 11 | #define WAVE515_CODE 0x5150 | ||
| 11 | #define WAVE517_CODE 0x5170 | 12 | #define WAVE517_CODE 0x5170 |
| 12 | #define WAVE537_CODE 0x5370 | 13 | #define WAVE537_CODE 0x5370 |
| 13 | #define WAVE511_CODE 0x5110 | 14 | #define WAVE511_CODE 0x5110 |
| @@ -21,12 +22,13 @@ · 7 unmodified lines | |||
| 21 | ((c) == WAVE517_CODE || (c) == WAVE537_CODE || \ | 22 | ((c) == WAVE517_CODE || (c) == WAVE537_CODE || \ |
| 22 | (c) == WAVE511_CODE || (c) == WAVE521_CODE || \ | 23 | (c) == WAVE511_CODE || (c) == WAVE521_CODE || \ |
| 23 | (c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \ | 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 | #define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024) | 28 | #define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024) |
| 28 | #define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K | 29 | #define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K |
| 29 | #define WAVE521DEC_WORKBUF_SIZE (1784 * 1024) | 30 | #define WAVE521DEC_WORKBUF_SIZE (1784 * 1024) |
| 31 | #define WAVE515DEC_WORKBUF_SIZE (2 * 1024 * 1024) | ||
| 30 | 32 | ||
| 31 | #define MAX_NUM_INSTANCE 32 | 33 | #define MAX_NUM_INSTANCE 32 |
| 32 | 34 | ||
| @@ -49,17 +51,21 @@ · 16 unmodified lines | |||
| 49 | /************************************************************************/ | 51 | /************************************************************************/ |
| 50 | #define VLC_BUF_NUM (2) | 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 | #define W5_REMAP_INDEX0 0 | 57 | #define W5_REMAP_INDEX0 0 |
| 55 | #define W5_REMAP_INDEX1 1 | 58 | #define W5_REMAP_INDEX1 1 |
| 56 | #define W5_REMAP_MAX_SIZE (1024 * 1024) | 59 | #define W5_REMAP_MAX_SIZE (1024 * 1024) |
| 57 | 60 | ||
| 58 | #define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024) | 61 | #define WAVE521_MAX_CODE_BUF_SIZE (2 * 1024 * 1024) |
| 59 | #define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE | 62 | #define WAVE515_MAX_CODE_BUF_SIZE (1024 * 1024) |
| 60 | #define WAVE5_TEMPBUF_SIZE (1024 * 1024) | 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 | //=====4. VPU REPORT MEMORY ======================// | 70 | //=====4. VPU REPORT MEMORY ======================// |
| 65 | 71 | ||
| @@ -22,6 +22,12 @@ · 21 unmodified lines | |||
| 22 | */ | 22 | */ |
| 23 | #define BSOPTION_ENABLE_EXPLICIT_END BIT(0) | 23 | #define BSOPTION_ENABLE_EXPLICIT_END BIT(0) |
| 24 | #define BSOPTION_HIGHLIGHT_STREAM_END BIT(1) | 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 | * Currently the driver only supports hardware with little endian but for source | 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 | #include <linux/videodev2.h> | 43 | #include <linux/videodev2.h> |
| 44 | 44 | ||
| 45 | #include <linux/platform_data/media/camera-pxa.h> | 45 | #include <linux/platform_data/media/camera-pxa.h> |
| 46 | #include <linux/workqueue.h> | ||
| 46 | 47 | ||
| 47 | #define PXA_CAM_VERSION "0.0.6" | 48 | #define PXA_CAM_VERSION "0.0.6" |
| 48 | #define PXA_CAM_DRV_NAME "pxa27x-camera" | 49 | #define PXA_CAM_DRV_NAME "pxa27x-camera" |
| @@ -683,7 +684,7 @@ struct pxa_camera_dev { · 634 unmodified lines | |||
| 683 | unsigned int buf_sequence; | 684 | unsigned int buf_sequence; |
| 684 | 685 | ||
| 685 | struct pxa_buffer *active; | 686 | struct pxa_buffer *active; |
| 686 | struct tasklet_struct task_eof; | 687 | struct work_struct eof_bh_work; |
| 687 | 688 | ||
| 688 | u32 save_cicr[5]; | 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 | clk_disable_unprepare(pcdev->clk); | 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 | unsigned long cifr; | 1153 | unsigned long cifr; |
| 1153 | struct pxa_buffer *buf; | 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 | if (status & CISR_EOF) { | 1186 | if (status & CISR_EOF) { |
| 1186 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; | 1187 | cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM; |
| 1187 | __raw_writel(cicr0, pcdev->base + CICR0); | 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 | return IRQ_HANDLED; | 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 | pxa_camera_activate(pcdev); | 2389 | pxa_camera_activate(pcdev); |
| 2389 | 2390 | ||
| @@ -2409,7 +2410,7 @@ static int pxa_camera_probe(struct platform_device *pdev) · 19 unmodified lines | |||
| 2409 | return 0; | 2410 | return 0; |
| 2410 | exit_deactivate: | 2411 | exit_deactivate: |
| 2411 | pxa_camera_deactivate(pcdev); | 2412 | pxa_camera_deactivate(pcdev); |
| 2412 | tasklet_kill(&pcdev->task_eof); | 2413 | cancel_work_sync(&pcdev->eof_bh_work); |
| 2413 | exit_free_dma: | 2414 | exit_free_dma: |
| 2414 | dma_release_channel(pcdev->dma_chans[2]); | 2415 | dma_release_channel(pcdev->dma_chans[2]); |
| 2415 | exit_free_dma_u: | 2416 | exit_free_dma_u: |
| @@ -2428,7 +2429,7 @@ static void pxa_camera_remove(struct platform_device *pdev) · 12 unmodified lines | |||
| 2428 | struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); | 2429 | struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev); |
| 2429 | 2430 | ||
| 2430 | pxa_camera_deactivate(pcdev); | 2431 | pxa_camera_deactivate(pcdev); |
| 2431 | tasklet_kill(&pcdev->task_eof); | 2432 | cancel_work_sync(&pcdev->eof_bh_work); |
| 2432 | dma_release_channel(pcdev->dma_chans[0]); | 2433 | dma_release_channel(pcdev->dma_chans[0]); |
| 2433 | dma_release_channel(pcdev->dma_chans[1]); | 2434 | dma_release_channel(pcdev->dma_chans[1]); |
| 2434 | dma_release_channel(pcdev->dma_chans[2]); | 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 | * Queue operations | 725 | * Queue operations |
| 726 | */ | 726 | */ |
| 727 | struct vb2_dc_conf { | ||
| 728 | struct device *dev; | ||
| 729 | }; | ||
| 730 | |||
| 731 | static int deinterlace_queue_setup(struct vb2_queue *vq, | 727 | static int deinterlace_queue_setup(struct vb2_queue *vq, |
| 732 | unsigned int *nbuffers, unsigned int *nplanes, | 728 | unsigned int *nbuffers, unsigned int *nplanes, |
| 733 | unsigned int sizes[], struct device *alloc_devs[]) | 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 | * Copy data out to user space in the vmalloc case | 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 | int i; | 445 | int i; |
| 446 | unsigned long flags; | 446 | unsigned long flags; |
| 447 | struct mcam_vb_buffer *buf; | 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 | static void mcam_vmalloc_done(struct mcam_camera *cam, int frame) | 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 | #else /* MCAM_MODE_VMALLOC */ | 499 | #else /* MCAM_MODE_VMALLOC */ |
| @@ -1305,7 +1305,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam) · 805 unmodified lines | |||
| 1305 | break; | 1305 | break; |
| 1306 | case B_vmalloc: | 1306 | case B_vmalloc: |
| 1307 | #ifdef MCAM_MODE_VMALLOC | 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 | vq->ops = &mcam_vb2_ops; | 1309 | vq->ops = &mcam_vb2_ops; |
| 1310 | vq->mem_ops = &vb2_vmalloc_memops; | 1310 | vq->mem_ops = &vb2_vmalloc_memops; |
| 1311 | cam->dma_setup = mcam_ctlr_dma_vmalloc; | 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 | EXPORT_SYMBOL_GPL(mccic_resume); | 1982 | EXPORT_SYMBOL_GPL(mccic_resume); |
| 1983 | 1983 | ||
| 1984 | MODULE_DESCRIPTION("Marvell camera core driver"); | ||
| 1984 | MODULE_LICENSE("GPL v2"); | 1985 | MODULE_LICENSE("GPL v2"); |
| 1985 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | 1986 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <linux/list.h> | 10 | #include <linux/list.h> |
| 11 | #include <linux/clk-provider.h> | 11 | #include <linux/clk-provider.h> |
| 12 | #include <linux/workqueue.h> | ||
| 12 | #include <media/v4l2-common.h> | 13 | #include <media/v4l2-common.h> |
| 13 | #include <media/v4l2-ctrls.h> | 14 | #include <media/v4l2-ctrls.h> |
| 14 | #include <media/v4l2-dev.h> | 15 | #include <media/v4l2-dev.h> |
| @@ -167,7 +168,7 @@ struct mcam_camera { · 152 unmodified lines | |||
| 167 | unsigned int dma_buf_size; /* allocated size */ | 168 | unsigned int dma_buf_size; /* allocated size */ |
| 168 | void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ | 169 | void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */ |
| 169 | dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */ | 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 | #endif | 172 | #endif |
| 172 | unsigned int sequence; /* Frame sequence number */ | 173 | unsigned int sequence; /* Frame sequence number */ |
| 173 | unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */ | 174 | unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */ |
| @@ -30,6 +30,7 @@ · 29 unmodified lines | |||
| 30 | 30 | ||
| 31 | MODULE_ALIAS("platform:mmp-camera"); | 31 | MODULE_ALIAS("platform:mmp-camera"); |
| 32 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); | 32 | MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>"); |
| 33 | MODULE_DESCRIPTION("Support for the camera device found on Marvell MMP processors"); | ||
| 33 | MODULE_LICENSE("GPL"); | 34 | MODULE_LICENSE("GPL"); |
| 34 | 35 | ||
| 35 | static char *mcam_clks[] = {"axi", "func", "phy"}; | 36 | static char *mcam_clks[] = {"axi", "func", "phy"}; |
| @@ -46,6 +46,53 @@ enum mt8183_mdp_comp_id { · 45 unmodified lines | |||
| 46 | MT8183_MDP_COMP_WROT1, /* 25 */ | 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 | enum mt8195_mdp_comp_id { | 96 | enum mt8195_mdp_comp_id { |
| 50 | /* MT8195 Comp id */ | 97 | /* MT8195 Comp id */ |
| 51 | /* ISP */ | 98 | /* ISP */ |
| @@ -123,6 +170,13 @@ static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = { · 71 unmodified lines | |||
| 123 | [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" } | 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 | static const struct of_device_id mt8195_mdp_probe_infra[MDP_INFRA_MAX] = { | 180 | static const struct of_device_id mt8195_mdp_probe_infra[MDP_INFRA_MAX] = { |
| 127 | [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8195-vppsys0" }, | 181 | [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8195-vppsys0" }, |
| 128 | [MDP_INFRA_MMSYS2] = { .compatible = "mediatek,mt8195-vppsys1" }, | 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 | [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0, | 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 | static const u32 mt8195_mutex_idx[MDP_MAX_COMP_COUNT] = { | 258 | static const u32 mt8195_mutex_idx[MDP_MAX_COMP_COUNT] = { |
| 171 | [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, | 259 | [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, |
| 172 | [MDP_COMP_RDMA1] = MUTEX_MOD_IDX_MDP_RDMA1, | 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 | static const struct mdp_comp_data mt8195_mdp_comp_data[MDP_MAX_COMP_COUNT] = { | 544 | static const struct mdp_comp_data mt8195_mdp_comp_data[MDP_MAX_COMP_COUNT] = { |
| 292 | [MDP_COMP_WPEI] = { | 545 | [MDP_COMP_WPEI] = { |
| 293 | {MDP_COMP_TYPE_WPEI, 0, MT8195_MDP_COMP_WPEI, MDP_MM_SUBSYS_0}, | 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 | [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 3} | 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 | static const struct mdp_pipe_info mt8195_pipe_info[] = { | 1311 | static const struct mdp_pipe_info mt8195_pipe_info[] = { |
| 1050 | [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0}, | 1312 | [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0}, |
| 1051 | [MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, MDP_MM_SUBSYS_0, 1}, | 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 | .pp_used = MDP_PP_USED_1, | 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 | const struct mtk_mdp_driver_data mt8195_mdp_driver_data = { | 1365 | const struct mtk_mdp_driver_data mt8195_mdp_driver_data = { |
| 1086 | .mdp_plat_id = MT8195, | 1366 | .mdp_plat_id = MT8195, |
| 1087 | .mdp_con_res = 0x14001000, | 1367 | .mdp_con_res = 0x14001000, |
| @@ -116,6 +116,7 @@ struct img_frameparam { · 115 unmodified lines | |||
| 116 | 116 | ||
| 117 | /* Platform config indicator */ | 117 | /* Platform config indicator */ |
| 118 | #define MT8183 8183 | 118 | #define MT8183 8183 |
| 119 | #define MT8188 8195 | ||
| 119 | #define MT8195 8195 | 120 | #define MT8195 8195 |
| 120 | 121 | ||
| 121 | #define CFG_CHECK(plat, p_id) ((plat) == (p_id)) | 122 | #define CFG_CHECK(plat, p_id) ((plat) == (p_id)) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | 11 | ||
| 12 | extern const struct mtk_mdp_driver_data mt8183_mdp_driver_data; | 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 | extern const struct mtk_mdp_driver_data mt8195_mdp_driver_data; | 14 | extern const struct mtk_mdp_driver_data mt8195_mdp_driver_data; |
| 14 | 15 | ||
| 15 | struct mdp_dev; | 16 | struct mdp_dev; |
| @@ -21,6 +21,9 @@ static const struct of_device_id mdp_of_ids[] = { · 20 unmodified lines | |||
| 21 | { .compatible = "mediatek,mt8183-mdp3-rdma", | 21 | { .compatible = "mediatek,mt8183-mdp3-rdma", |
| 22 | .data = &mt8183_mdp_driver_data, | 22 | .data = &mt8183_mdp_driver_data, |
| 23 | }, | 23 | }, |
| 24 | { .compatible = "mediatek,mt8188-mdp3-rdma", | ||
| 25 | .data = &mt8188_mdp_driver_data, | ||
| 26 | }, | ||
| 24 | { .compatible = "mediatek,mt8195-mdp3-rdma", | 27 | { .compatible = "mediatek,mt8195-mdp3-rdma", |
| 25 | .data = &mt8195_mdp_driver_data, | 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 | id = dec_ctx->id; | 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 | if (!mem->va) { | 68 | if (!mem->va) { |
| 68 | mtk_v4l2_err(plat_dev, "%s dma_alloc size=0x%zx failed!", | 69 | mtk_v4l2_err(plat_dev, "%s dma_alloc size=0x%zx failed!", |
| 69 | __func__, mem->size); | 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 | return &ctx->q_data[MTK_Q_DATA_DST]; | 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, | 83 | static int stateful_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) |
| 84 | struct v4l2_decoder_cmd *cmd) | ||
| 85 | { | 84 | { |
| 86 | return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); | 85 | return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd); |
| 87 | } | 86 | } |
| 88 | 87 | ||
| 89 | 88 | static int stateful_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd) | |
| 90 | static int vidioc_decoder_cmd(struct file *file, void *priv, | ||
| 91 | struct v4l2_decoder_cmd *cmd) | ||
| 92 | { | 89 | { |
| 93 | struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); | 90 | struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv); |
| 94 | struct vb2_queue *src_vq, *dst_vq; | 91 | struct vb2_queue *src_vq, *dst_vq; |
| 95 | int ret; | 92 | int ret; |
| 96 | 93 | ||
| 97 | ret = vidioc_try_decoder_cmd(file, priv, cmd); | 94 | ret = stateful_try_decoder_cmd(file, priv, cmd); |
| 98 | if (ret) | 95 | if (ret) |
| 99 | return ret; | 96 | return ret; |
| 100 | 97 | ||
| @@ -128,6 +125,57 @@ static int vidioc_decoder_cmd(struct file *file, void *priv, · 27 unmodified lines | |||
| 128 | return 0; | 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 | void mtk_vdec_unlock(struct mtk_vcodec_dec_ctx *ctx) | 179 | void mtk_vdec_unlock(struct mtk_vcodec_dec_ctx *ctx) |
| 132 | { | 180 | { |
| 133 | mutex_unlock(&ctx->dev->dec_mutex[ctx->hw_id]); | 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 | inst->frm_cnt, y_fb_dma, c_fb_dma, fb); | 449 | inst->frm_cnt, y_fb_dma, c_fb_dma, fb); |
| 450 | 450 | ||
| 451 | inst->cur_fb = fb; | 451 | inst->cur_fb = fb; |
| 452 | dec->bs_dma = (uint64_t)bs->dma_addr; | 452 | dec->bs_dma = bs->dma_addr; |
| 453 | dec->bs_sz = bs->size; | 453 | dec->bs_sz = bs->size; |
| 454 | dec->cur_y_fb_dma = y_fb_dma; | 454 | dec->cur_y_fb_dma = y_fb_dma; |
| 455 | dec->cur_c_fb_dma = c_fb_dma; | 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 | mtk_vdec_debug(vpu->ctx, "vdec_inst=%p", vpu); | 233 | mtk_vdec_debug(vpu->ctx, "vdec_inst=%p", vpu); |
| 234 | 234 | ||
| 235 | err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg)); | 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 | mtk_vdec_debug(vpu->ctx, "- ret=%d", err); | 242 | mtk_vdec_debug(vpu->ctx, "- ret=%d", err); |
| 237 | return err; | 243 | return err; |
| 238 | } | 244 | } |
| @@ -19,11 +19,6 @@ · 18 unmodified lines | |||
| 19 | #define FLAG_B_FRAME 0x1 | 19 | #define FLAG_B_FRAME 0x1 |
| 20 | #define FLAG_REFERENCE 0x2 | 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 | struct tegra_vde_h264_decoder_ctx { | 22 | struct tegra_vde_h264_decoder_ctx { |
| 28 | unsigned int dpb_frames_nb; | 23 | unsigned int dpb_frames_nb; |
| 29 | unsigned int dpb_ref_frames_with_earlier_poc_nb; | 24 | unsigned int dpb_ref_frames_with_earlier_poc_nb; |
| @@ -47,7 +47,6 @@ struct iommu_group; · 46 unmodified lines | |||
| 47 | struct iommu_domain; | 47 | struct iommu_domain; |
| 48 | struct reset_control; | 48 | struct reset_control; |
| 49 | struct dma_buf_attachment; | 49 | struct dma_buf_attachment; |
| 50 | struct tegra_vde_h264_frame; | ||
| 51 | struct tegra_vde_h264_decoder_ctx; | 50 | struct tegra_vde_h264_decoder_ctx; |
| 52 | 51 | ||
| 53 | struct tegra_video_frame { | 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 | dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); | 1634 | dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx); |
| 1635 | q_data->sequence = 0; | 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 | ret = pm_runtime_resume_and_get(ctx->mxc_jpeg->dev); | 1640 | ret = pm_runtime_resume_and_get(ctx->mxc_jpeg->dev); |
| 1638 | if (ret < 0) { | 1641 | if (ret < 0) { |
| 1639 | dev_err(ctx->mxc_jpeg->dev, "Failed to power up jpeg\n"); | 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 | q_data_out = mxc_jpeg_get_q_data(ctx, | 1844 | q_data_out = mxc_jpeg_get_q_data(ctx, |
| 1842 | V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE); | 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 | q_data_out->w = header.frame.width; | 1846 | q_data_out->w = header.frame.width; |
| 1855 | q_data_out->h = header.frame.height; | 1847 | q_data_out->h = header.frame.height; |
| 1856 | if (header.frame.width > MXC_JPEG_MAX_WIDTH || | 1848 | if (header.frame.width > MXC_JPEG_MAX_WIDTH || |
| @@ -320,7 +320,11 @@ struct mipi_csis_device { · 319 unmodified lines | |||
| 320 | struct v4l2_subdev sd; | 320 | struct v4l2_subdev sd; |
| 321 | struct media_pad pads[CSIS_PADS_NUM]; | 321 | struct media_pad pads[CSIS_PADS_NUM]; |
| 322 | struct v4l2_async_notifier notifier; | 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 | struct v4l2_mbus_config_mipi_csi2 bus; | 329 | struct v4l2_mbus_config_mipi_csi2 bus; |
| 326 | u32 clk_frequency; | 330 | u32 clk_frequency; |
| @@ -597,7 +601,7 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis, · 270 unmodified lines | |||
| 597 | u32 lane_rate; | 601 | u32 lane_rate; |
| 598 | 602 | ||
| 599 | /* Calculate the line rate from the pixel rate. */ | 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 | csis_fmt->width, | 605 | csis_fmt->width, |
| 602 | csis->bus.num_data_lanes * 2); | 606 | csis->bus.num_data_lanes * 2); |
| 603 | if (link_freq < 0) { | 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 | int ret; | 962 | int ret; |
| 959 | 963 | ||
| 960 | if (!enable) { | 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 | mipi_csis_stop_stream(csis); | 968 | mipi_csis_stop_stream(csis); |
| 964 | if (csis->debug.enable) | 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 | mipi_csis_start_stream(csis, format, csis_fmt); | 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 | if (ret < 0) | 996 | if (ret < 0) |
| 991 | goto err_stop; | 997 | goto err_stop; |
| 992 | 998 | ||
| @@ -1233,12 +1239,14 @@ static int mipi_csis_link_setup(struct media_entity *entity, · 240 unmodified lines | |||
| 1233 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); | 1239 | remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity); |
| 1234 | 1240 | ||
| 1235 | if (flags & MEDIA_LNK_FL_ENABLED) { | 1241 | if (flags & MEDIA_LNK_FL_ENABLED) { |
| 1236 | if (csis->src_sd) | 1242 | if (csis->source.sd) |
| 1237 | return -EBUSY; | 1243 | return -EBUSY; |
| 1238 | 1244 | ||
| 1239 | csis->src_sd = remote_sd; | 1245 | csis->source.sd = remote_sd; |
| 1246 | csis->source.pad = remote_pad; | ||
| 1240 | } else { | 1247 | } else { |
| 1241 | csis->src_sd = NULL; | 1248 | csis->source.sd = NULL; |
| 1249 | csis->source.pad = NULL; | ||
| 1242 | } | 1250 | } |
| 1243 | 1251 | ||
| 1244 | return 0; | 1252 | return 0; |
| @@ -1805,6 +1805,9 @@ static int pxp_probe(struct platform_device *pdev) · 1804 unmodified lines | |||
| 1805 | return PTR_ERR(mmio); | 1805 | return PTR_ERR(mmio); |
| 1806 | dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, | 1806 | dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio, |
| 1807 | &pxp_regmap_config); | 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 | irq = platform_get_irq(pdev, 0); | 1812 | irq = platform_get_irq(pdev, 0); |
| 1810 | if (irq < 0) | 1813 | if (irq < 0) |
| @@ -19,5 +19,6 @@ qcom-camss-objs += \ · 18 unmodified lines | |||
| 19 | camss-vfe-gen1.o \ | 19 | camss-vfe-gen1.o \ |
| 20 | camss-vfe.o \ | 20 | camss-vfe.o \ |
| 21 | camss-video.o \ | 21 | camss-video.o \ |
| 22 | camss-format.o \ | ||
| 22 | 23 | ||
| 23 | obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o | 24 | obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o |
| @@ -45,128 +45,6 @@ · 44 unmodified lines | |||
| 45 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n)) | 45 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n)) |
| 46 | #define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n)) | 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 | static void csid_configure_stream(struct csid_device *csid, u8 enable) | 48 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
| 171 | { | 49 | { |
| 172 | struct csid_testgen_config *tg = &csid->testgen; | 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 | if (enable) { | 53 | if (enable) { |
| 176 | struct v4l2_mbus_framefmt *input_format; | 54 | struct v4l2_mbus_framefmt *input_format; |
| 177 | const struct csid_format *format; | 55 | const struct csid_format_info *format; |
| 178 | u8 vc = 0; /* Virtual Channel 0 */ | 56 | u8 vc = 0; /* Virtual Channel 0 */ |
| 179 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ | 57 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ |
| 180 | u8 dt_shift; | 58 | u8 dt_shift; |
| @@ -184,7 +62,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 3 unmodified lines | |||
| 184 | u32 num_lines, num_bytes_per_line; | 62 | u32 num_lines, num_bytes_per_line; |
| 185 | 63 | ||
| 186 | input_format = &csid->fmt[MSM_CSID_PAD_SRC]; | 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 | input_format->code); | 67 | input_format->code); |
| 189 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; | 68 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; |
| 190 | num_lines = input_format->height; | 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 | struct csid_phy_config *phy = &csid->phy; | 90 | struct csid_phy_config *phy = &csid->phy; |
| 212 | 91 | ||
| 213 | input_format = &csid->fmt[MSM_CSID_PAD_SINK]; | 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 | input_format->code); | 95 | input_format->code); |
| 216 | 96 | ||
| 217 | val = phy->lane_cnt - 1; | 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 | static void csid_subdev_init(struct csid_device *csid) | 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 | csid->testgen.modes = csid_testgen_modes; | 194 | csid->testgen.modes = csid_testgen_modes; |
| 317 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; | 195 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; |
| 318 | } | 196 | } |
| @@ -44,156 +44,6 @@ · 43 unmodified lines | |||
| 44 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n)) | 44 | #define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n)) |
| 45 | #define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0bc + 0xc * (n)) | 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 | static void csid_configure_stream(struct csid_device *csid, u8 enable) | 47 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
| 198 | { | 48 | { |
| 199 | struct csid_testgen_config *tg = &csid->testgen; | 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 | if (enable) { | 54 | if (enable) { |
| 205 | struct v4l2_mbus_framefmt *input_format; | 55 | struct v4l2_mbus_framefmt *input_format; |
| 206 | const struct csid_format *format; | 56 | const struct csid_format_info *format; |
| 207 | u8 vc = 0; /* Virtual Channel 0 */ | 57 | u8 vc = 0; /* Virtual Channel 0 */ |
| 208 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ | 58 | u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */ |
| 209 | u8 dt_shift; | 59 | u8 dt_shift; |
| @@ -213,7 +63,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable) · 3 unmodified lines | |||
| 213 | u32 num_bytes_per_line, num_lines; | 63 | u32 num_bytes_per_line, num_lines; |
| 214 | 64 | ||
| 215 | input_format = &csid->fmt[MSM_CSID_PAD_SRC]; | 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 | input_format->code); | 68 | input_format->code); |
| 218 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; | 69 | num_bytes_per_line = input_format->width * format->bpp * format->spp / 8; |
| 219 | num_lines = input_format->height; | 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 | struct csid_phy_config *phy = &csid->phy; | 91 | struct csid_phy_config *phy = &csid->phy; |
| 241 | 92 | ||
| 242 | input_format = &csid->fmt[MSM_CSID_PAD_SINK]; | 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 | input_format->code); | 96 | input_format->code); |
| 245 | 97 | ||
| 246 | val = phy->lane_cnt - 1; | 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 | static void csid_subdev_init(struct csid_device *csid) | 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 | csid->testgen.modes = csid_testgen_modes; | 242 | csid->testgen.modes = csid_testgen_modes; |
| 393 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; | 243 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1; |
| 394 | } | 244 | } |
| @@ -176,306 +176,171 @@ · 175 unmodified lines | |||
| 176 | #define TPG_COLOR_BOX_CFG_MODE 0 | 176 | #define TPG_COLOR_BOX_CFG_MODE 0 |
| 177 | #define TPG_COLOR_BOX_PATTERN_SEL 2 | 177 | #define TPG_COLOR_BOX_PATTERN_SEL 2 |
| 178 | 178 | ||
| 179 | static const struct csid_format csid_formats[] = { | 179 | static void __csid_configure_rx(struct csid_device *csid, |
| 180 | { | 180 | struct csid_phy_config *phy, int vc) |
| 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) | ||
| 337 | { | 181 | { |
| 338 | struct csid_testgen_config *tg = &csid->testgen; | ||
| 339 | u32 val; | ||
| 340 | u32 phy_sel = 0; | ||
| 341 | u8 lane_cnt = csid->phy.lane_cnt; | 182 | u8 lane_cnt = csid->phy.lane_cnt; |
| 342 | /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ | 183 | int val; |
| 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); | ||
| 346 | 184 | ||
| 347 | if (!lane_cnt) | 185 | if (!lane_cnt) |
| 348 | lane_cnt = 4; | 186 | lane_cnt = 4; |
| 349 | 187 | ||
| 350 | if (!tg->enabled) | 188 | val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; |
| 351 | phy_sel = csid->phy.csiphy_id; | 189 | val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; |
| 352 | 190 | val |= phy->csiphy_id << CSI2_RX_CFG0_PHY_NUM_SEL; | |
| 353 | if (enable) { | 191 | writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); |
| 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 | } | ||
| 397 | 192 | ||
| 398 | val = 1 << RDI_CFG0_BYTE_CNTR_EN; | 193 | val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN; |
| 399 | val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN; | 194 | if (vc > 3) |
| 400 | val |= 1 << RDI_CFG0_TIMESTAMP_EN; | 195 | val |= 1 << CSI2_RX_CFG1_VC_MODE; |
| 401 | /* note: for non-RDI path, this should be format->decode_format */ | 196 | val |= 1 << CSI2_RX_CFG1_MISR_EN; |
| 402 | val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT; | 197 | writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); |
| 403 | val |= format->data_type << RDI_CFG0_DATA_TYPE; | 198 | } |
| 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)); | ||
| 407 | 199 | ||
| 408 | /* CSID_TIMESTAMP_STB_POST_IRQ */ | 200 | static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi) |
| 409 | val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL; | 201 | { |
| 410 | writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc)); | 202 | int val; |
| 411 | 203 | ||
| 412 | val = 1; | 204 | if (enable) |
| 413 | writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc)); | 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; | 211 | static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc) |
| 416 | writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(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; | 221 | if (!lane_cnt) |
| 419 | writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc)); | 222 | lane_cnt = 4; |
| 420 | 223 | ||
| 421 | val = 0; | 224 | /* configure one DT, infinite frames */ |
| 422 | writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc)); | 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; | 230 | val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT; |
| 425 | writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc)); | 231 | val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT; |
| 232 | writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1); | ||
| 426 | 233 | ||
| 427 | val = 0; | 234 | writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED); |
| 428 | writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc)); | ||
| 429 | 235 | ||
| 430 | val = 1; | 236 | val = (input_format->height & 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT; |
| 431 | writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc)); | 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; | 240 | val = format->data_type << TPG_DT_n_CFG_1_DATA_TYPE; |
| 434 | writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc)); | 241 | writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0)); |
| 435 | 242 | ||
| 436 | val = 0; | 243 | val = (tg->mode - 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE; |
| 437 | writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc)); | 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)); | 248 | writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG); |
| 440 | val |= 1 << RDI_CFG0_ENABLE; | ||
| 441 | writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc)); | ||
| 442 | } | ||
| 443 | 249 | ||
| 444 | if (tg->enabled) { | 250 | writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG); |
| 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 | } | ||
| 453 | 251 | ||
| 454 | val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES; | 252 | val = enable << TPG_CTRL_TEST_EN; |
| 455 | val |= csid->phy.lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL; | 253 | val |= 1 << TPG_CTRL_FS_PKT_EN; |
| 456 | val |= phy_sel << CSI2_RX_CFG0_PHY_NUM_SEL; | 254 | val |= 1 << TPG_CTRL_FE_PKT_EN; |
| 457 | writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0); | 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; | 261 | static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc) |
| 460 | if (vc > 3) | 262 | { |
| 461 | val |= 1 << CSI2_RX_CFG1_VC_MODE; | 263 | /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */ |
| 462 | val |= 1 << CSI2_RX_CFG1_MISR_EN; | 264 | struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc]; |
| 463 | writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1); | 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) | 270 | /* |
| 466 | val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; | 271 | * DT_ID is a two bit bitfield that is concatenated with |
| 467 | else | 272 | * the four least significant bits of the five bit VC |
| 468 | val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD; | 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 | writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc)); | 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 | static void csid_configure_stream(struct csid_device *csid, u8 enable) | 330 | static void csid_configure_stream(struct csid_device *csid, u8 enable) |
| 473 | { | 331 | { |
| 332 | struct csid_testgen_config *tg = &csid->testgen; | ||
| 474 | u8 i; | 333 | u8 i; |
| 475 | /* Loop through all enabled VCs and configure stream for each */ | 334 | /* Loop through all enabled VCs and configure stream for each */ |
| 476 | for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) | 335 | for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++) |
| 477 | if (csid->phy.en_vc & BIT(i)) | 336 | if (csid->phy.en_vc & BIT(i)) { |
| 478 | __csid_configure_stream(csid, enable, 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 | static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val) | 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 | static void csid_subdev_init(struct csid_device *csid) | 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 | csid->testgen.modes = csid_testgen_modes; | 480 | csid->testgen.modes = csid_testgen_modes; |
| 618 | csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2; | 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 | NULL | 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 | u32 csid_find_code(u32 *codes, unsigned int ncodes, | 492 | u32 csid_find_code(u32 *codes, unsigned int ncodes, |
| 49 | unsigned int match_format_idx, u32 match_code) | 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 | return codes[0]; | 509 | return codes[0]; |
| 66 | } | 510 | } |
| 67 | 511 | ||
| 68 | const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats, | 512 | const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats, |
| 69 | unsigned int nformats, | 513 | unsigned int nformats, |
| 70 | u32 code) | 514 | u32 code) |
| 71 | { | 515 | { |
| 72 | unsigned int i; | 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 | static int csid_set_clock_rates(struct csid_device *csid) | 531 | static int csid_set_clock_rates(struct csid_device *csid) |
| 88 | { | 532 | { |
| 89 | struct device *dev = csid->camss->dev; | 533 | struct device *dev = csid->camss->dev; |
| 90 | const struct csid_format *fmt; | 534 | const struct csid_format_info *fmt; |
| 91 | s64 link_freq; | 535 | s64 link_freq; |
| 92 | int i, j; | 536 | int i, j; |
| 93 | int ret; | 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 | csid->fmt[MSM_CSIPHY_PAD_SINK].code); | 540 | csid->fmt[MSM_CSIPHY_PAD_SINK].code); |
| 97 | link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, | 541 | link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp, |
| 98 | csid->phy.lane_cnt); | 542 | csid->phy.lane_cnt); |
| @@ -158,7 +602,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 59 unmodified lines | |||
| 158 | struct csid_device *csid = v4l2_get_subdevdata(sd); | 602 | struct csid_device *csid = v4l2_get_subdevdata(sd); |
| 159 | struct camss *camss = csid->camss; | 603 | struct camss *camss = csid->camss; |
| 160 | struct device *dev = camss->dev; | 604 | struct device *dev = camss->dev; |
| 161 | struct vfe_device *vfe = &camss->vfe[csid->id]; | ||
| 162 | int ret = 0; | 605 | int ret = 0; |
| 163 | 606 | ||
| 164 | if (on) { | 607 | if (on) { |
| @@ -167,7 +610,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on) · 2 unmodified lines | |||
| 167 | * switching on the CSID. Do so unconditionally, as there is no | 610 | * switching on the CSID. Do so unconditionally, as there is no |
| 168 | * drawback in following the same powering order on older SoCs. | 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 | if (ret < 0) | 614 | if (ret < 0) |
| 172 | return ret; | 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 | enable_irq(csid->irq); | 646 | enable_irq(csid->irq); |
| 204 | 647 | ||
| 205 | ret = csid->ops->reset(csid); | 648 | ret = csid->res->hw_ops->reset(csid); |
| 206 | if (ret < 0) { | 649 | if (ret < 0) { |
| 207 | disable_irq(csid->irq); | 650 | disable_irq(csid->irq); |
| 208 | camss_disable_clocks(csid->nclocks, csid->clock); | 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 | return ret; | 655 | return ret; |
| 213 | } | 656 | } |
| 214 | 657 | ||
| 215 | csid->ops->hw_version(csid); | 658 | csid->res->hw_ops->hw_version(csid); |
| 216 | } else { | 659 | } else { |
| 217 | disable_irq(csid->irq); | 660 | disable_irq(csid->irq); |
| 218 | camss_disable_clocks(csid->nclocks, csid->clock); | 661 | camss_disable_clocks(csid->nclocks, csid->clock); |
| 219 | regulator_bulk_disable(csid->num_supplies, | 662 | regulator_bulk_disable(csid->num_supplies, |
| 220 | csid->supplies); | 663 | csid->supplies); |
| 221 | pm_runtime_put_sync(dev); | 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 | return ret; | 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 | if (csid->phy.need_vc_update) { | 698 | if (csid->phy.need_vc_update) { |
| 256 | csid->ops->configure_stream(csid, enable); | 699 | csid->res->hw_ops->configure_stream(csid, enable); |
| 257 | csid->phy.need_vc_update = false; | 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 | case MSM_CSID_PAD_SINK: | 744 | case MSM_CSID_PAD_SINK: |
| 302 | /* Set format on sink pad */ | 745 | /* Set format on sink pad */ |
| 303 | 746 | ||
| 304 | for (i = 0; i < csid->nformats; i++) | 747 | for (i = 0; i < csid->res->formats->nformats; i++) |
| 305 | if (fmt->code == csid->formats[i].code) | 748 | if (fmt->code == csid->res->formats->formats[i].code) |
| 306 | break; | 749 | break; |
| 307 | 750 | ||
| 308 | /* If not found, use UYVY as default */ | 751 | /* If not found, use UYVY as default */ |
| 309 | if (i >= csid->nformats) | 752 | if (i >= csid->res->formats->nformats) |
| 310 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; | 753 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 311 | 754 | ||
| 312 | fmt->width = clamp_t(u32, fmt->width, 1, 8191); | 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 | *fmt = *__csid_get_format(csid, sd_state, | 769 | *fmt = *__csid_get_format(csid, sd_state, |
| 327 | MSM_CSID_PAD_SINK, which); | 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 | } else { | 772 | } else { |
| 330 | /* Test generator is enabled, set format on source */ | 773 | /* Test generator is enabled, set format on source */ |
| 331 | /* pad to allow test generator usage */ | 774 | /* pad to allow test generator usage */ |
| 332 | 775 | ||
| 333 | for (i = 0; i < csid->nformats; i++) | 776 | for (i = 0; i < csid->res->formats->nformats; i++) |
| 334 | if (csid->formats[i].code == fmt->code) | 777 | if (csid->res->formats->formats[i].code == fmt->code) |
| 335 | break; | 778 | break; |
| 336 | 779 | ||
| 337 | /* If not found, use UYVY as default */ | 780 | /* If not found, use UYVY as default */ |
| 338 | if (i >= csid->nformats) | 781 | if (i >= csid->res->formats->nformats) |
| 339 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; | 782 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 340 | 783 | ||
| 341 | fmt->width = clamp_t(u32, fmt->width, 1, 8191); | 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 | struct csid_device *csid = v4l2_get_subdevdata(sd); | 806 | struct csid_device *csid = v4l2_get_subdevdata(sd); |
| 364 | 807 | ||
| 365 | if (code->pad == MSM_CSID_PAD_SINK) { | 808 | if (code->pad == MSM_CSID_PAD_SINK) { |
| 366 | if (code->index >= csid->nformats) | 809 | if (code->index >= csid->res->formats->nformats) |
| 367 | return -EINVAL; | 810 | return -EINVAL; |
| 368 | 811 | ||
| 369 | code->code = csid->formats[code->index].code; | 812 | code->code = csid->res->formats->formats[code->index].code; |
| 370 | } else { | 813 | } else { |
| 371 | if (csid->testgen_mode->cur.val == 0) { | 814 | if (csid->testgen_mode->cur.val == 0) { |
| 372 | struct v4l2_mbus_framefmt *sink_fmt; | 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 | MSM_CSID_PAD_SINK, | 818 | MSM_CSID_PAD_SINK, |
| 376 | code->which); | 819 | code->which); |
| 377 | 820 | ||
| 378 | code->code = csid->ops->src_pad_code(csid, sink_fmt->code, | 821 | code->code = csid->res->hw_ops->src_pad_code(csid, sink_fmt->code, |
| 379 | code->index, 0); | 822 | code->index, 0); |
| 380 | if (!code->code) | 823 | if (!code->code) |
| 381 | return -EINVAL; | 824 | return -EINVAL; |
| 382 | } else { | 825 | } else { |
| 383 | if (code->index >= csid->nformats) | 826 | if (code->index >= csid->res->formats->nformats) |
| 384 | return -EINVAL; | 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 | tg->enabled = !!value; | 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 | csid->camss = camss; | 1019 | csid->camss = camss; |
| 577 | csid->id = id; | 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 | /* Memory */ | 1030 | /* Memory */ |
| 583 | 1031 | ||
| @@ -587,9 +1035,11 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, · 3 unmodified lines | |||
| 587 | * VFE to be initialized before CSID | 1035 | * VFE to be initialized before CSID |
| 588 | */ | 1036 | */ |
| 589 | if (id >= 2) /* VFE/CSID lite */ | 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 | else | 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 | } else { | 1043 | } else { |
| 594 | csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]); | 1044 | csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]); |
| 595 | if (IS_ERR(csid->base)) | 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 | csid->irq = ret; | 1055 | csid->irq = ret; |
| 606 | snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d", | 1056 | snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d", |
| 607 | dev_name(dev), MSM_CSID_NAME, csid->id); | 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 | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, | 1059 | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, |
| 610 | csid->irq_name, csid); | 1060 | csid->irq_name, csid); |
| 611 | if (ret < 0) { | 1061 | if (ret < 0) { |
| @@ -899,5 +1349,5 @@ void msm_csid_unregister_entity(struct csid_device *csid) · 287 unmodified lines | |||
| 899 | 1349 | ||
| 900 | inline bool csid_is_lite(struct csid_device *csid) | 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 | CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */ | 67 | CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */ |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | struct csid_format { | 70 | struct csid_format_info { |
| 71 | u32 code; | 71 | u32 code; |
| 72 | u8 data_type; | 72 | u8 data_type; |
| 73 | u8 decode_format; | 73 | u8 decode_format; |
| @@ -75,6 +75,11 @@ struct csid_format { · 1 unmodified line | |||
| 75 | u8 spp; /* bus samples per pixel */ | 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 | struct csid_testgen_config { | 83 | struct csid_testgen_config { |
| 79 | enum csid_testgen_mode mode; | 84 | enum csid_testgen_mode mode; |
| 80 | const char * const*modes; | 85 | const char * const*modes; |
| @@ -149,6 +154,13 @@ struct csid_hw_ops { · 68 unmodified lines | |||
| 149 | void (*subdev_init)(struct csid_device *csid); | 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 | struct csid_device { | 164 | struct csid_device { |
| 153 | struct camss *camss; | 165 | struct camss *camss; |
| 154 | u8 id; | 166 | u8 id; |
| @@ -167,9 +179,7 @@ struct csid_device { · 12 unmodified lines | |||
| 167 | struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM]; | 179 | struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM]; |
| 168 | struct v4l2_ctrl_handler ctrls; | 180 | struct v4l2_ctrl_handler ctrls; |
| 169 | struct v4l2_ctrl *testgen_mode; | 181 | struct v4l2_ctrl *testgen_mode; |
| 170 | const struct csid_format *formats; | 182 | const struct csid_subdev_resources *res; |
| 171 | unsigned int nformats; | ||
| 172 | const struct csid_hw_ops *ops; | ||
| 173 | }; | 183 | }; |
| 174 | 184 | ||
| 175 | struct camss_subdev_resources; | 185 | struct camss_subdev_resources; |
| @@ -188,16 +198,16 @@ u32 csid_find_code(u32 *codes, unsigned int ncode, · 12 unmodified lines | |||
| 188 | unsigned int match_format_idx, u32 match_code); | 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 | 201 | * csid_get_fmt_entry - Find csid_format_info entry with matching format code |
| 192 | * @formats: Array of format csid_format entries | 202 | * @formats: Array of format csid_format_info entries |
| 193 | * @nformats: Length of @nformats array | 203 | * @nformats: Length of @nformats array |
| 194 | * @code: Desired format code | 204 | * @code: Desired format code |
| 195 | * | 205 | * |
| 196 | * Return formats[0] on failure to find code | 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, | 208 | const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats, |
| 199 | unsigned int nformats, | 209 | unsigned int nformats, |
| 200 | u32 code); | 210 | u32 code); |
| 201 | 211 | ||
| 202 | int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, | 212 | int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid, |
| 203 | const struct camss_subdev_resources *res, u8 id); | 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 | extern const char * const csid_testgen_modes[]; | 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 | extern const struct csid_hw_ops csid_ops_4_1; | 228 | extern const struct csid_hw_ops csid_ops_4_1; |
| 215 | extern const struct csid_hw_ops csid_ops_4_7; | 229 | extern const struct csid_hw_ops csid_ops_4_7; |
| 216 | extern const struct csid_hw_ops csid_ops_gen2; | 230 | extern const struct csid_hw_ops csid_ops_gen2; |
| @@ -24,12 +24,7 @@ · 23 unmodified lines | |||
| 24 | 24 | ||
| 25 | #define MSM_CSIPHY_NAME "msm_csiphy" | 25 | #define MSM_CSIPHY_NAME "msm_csiphy" |
| 26 | 26 | ||
| 27 | struct csiphy_format { | 27 | static const struct csiphy_format_info formats_8x16[] = { |
| 28 | u32 code; | ||
| 29 | u8 bpp; | ||
| 30 | }; | ||
| 31 | |||
| 32 | static const struct csiphy_format csiphy_formats_8x16[] = { | ||
| 33 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, | 28 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, |
| 34 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, | 29 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, |
| 35 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, | 30 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, |
| @@ -49,7 +44,7 @@ static const struct csiphy_format csiphy_formats_8x16[] = { · 13 unmodified lines | |||
| 49 | { MEDIA_BUS_FMT_Y10_1X10, 10 }, | 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 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, | 48 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, |
| 54 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, | 49 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, |
| 55 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, | 50 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, |
| @@ -73,7 +68,7 @@ static const struct csiphy_format csiphy_formats_8x96[] = { · 17 unmodified lines | |||
| 73 | { MEDIA_BUS_FMT_Y10_1X10, 10 }, | 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 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, | 72 | { MEDIA_BUS_FMT_UYVY8_1X16, 8 }, |
| 78 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, | 73 | { MEDIA_BUS_FMT_VYUY8_1X16, 8 }, |
| 79 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, | 74 | { MEDIA_BUS_FMT_YUYV8_1X16, 8 }, |
| @@ -98,6 +93,21 @@ static const struct csiphy_format csiphy_formats_sdm845[] = { · 18 unmodified lines | |||
| 98 | { MEDIA_BUS_FMT_Y10_1X10, 10 }, | 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 | * csiphy_get_bpp - map media bus format to bits per pixel | 112 | * csiphy_get_bpp - map media bus format to bits per pixel |
| 103 | * @formats: supported media bus formats array | 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 | * Return number of bits per pixel | 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 | unsigned int nformats, u32 code) | 120 | unsigned int nformats, u32 code) |
| 111 | { | 121 | { |
| 112 | unsigned int i; | 122 | unsigned int i; |
| @@ -131,7 +141,7 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy) · 18 unmodified lines | |||
| 131 | int i, j; | 141 | int i, j; |
| 132 | int ret; | 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 | csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); | 145 | csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); |
| 136 | u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; | 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 | enable_irq(csiphy->irq); | 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 | } else { | 232 | } else { |
| 223 | disable_irq(csiphy->irq); | 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 | struct csiphy_config *cfg = &csiphy->cfg; | 254 | struct csiphy_config *cfg = &csiphy->cfg; |
| 245 | s64 link_freq; | 255 | s64 link_freq; |
| 246 | u8 lane_mask = csiphy->ops->get_lane_mask(&cfg->csi2->lane_cfg); | 256 | u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg); |
| 247 | u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats, | 257 | u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats, |
| 248 | csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); | 258 | csiphy->fmt[MSM_CSIPHY_PAD_SINK].code); |
| 249 | u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; | 259 | u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data; |
| 250 | u8 val; | 260 | u8 val; |
| @@ -272,7 +282,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) · 21 unmodified lines | |||
| 272 | wmb(); | 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 | return 0; | 287 | return 0; |
| 278 | } | 288 | } |
| @@ -285,7 +295,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy) · 6 unmodified lines | |||
| 285 | */ | 295 | */ |
| 286 | static void csiphy_stream_off(struct csiphy_device *csiphy) | 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 | case MSM_CSIPHY_PAD_SINK: | 360 | case MSM_CSIPHY_PAD_SINK: |
| 351 | /* Set format on sink pad */ | 361 | /* Set format on sink pad */ |
| 352 | 362 | ||
| 353 | for (i = 0; i < csiphy->nformats; i++) | 363 | for (i = 0; i < csiphy->res->formats->nformats; i++) |
| 354 | if (fmt->code == csiphy->formats[i].code) | 364 | if (fmt->code == csiphy->res->formats->formats[i].code) |
| 355 | break; | 365 | break; |
| 356 | 366 | ||
| 357 | /* If not found, use UYVY as default */ | 367 | /* If not found, use UYVY as default */ |
| 358 | if (i >= csiphy->nformats) | 368 | if (i >= csiphy->res->formats->nformats) |
| 359 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; | 369 | fmt->code = MEDIA_BUS_FMT_UYVY8_1X16; |
| 360 | 370 | ||
| 361 | fmt->width = clamp_t(u32, fmt->width, 1, 8191); | 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 | struct v4l2_mbus_framefmt *format; | 402 | struct v4l2_mbus_framefmt *format; |
| 393 | 403 | ||
| 394 | if (code->pad == MSM_CSIPHY_PAD_SINK) { | 404 | if (code->pad == MSM_CSIPHY_PAD_SINK) { |
| 395 | if (code->index >= csiphy->nformats) | 405 | if (code->index >= csiphy->res->formats->nformats) |
| 396 | return -EINVAL; | 406 | return -EINVAL; |
| 397 | 407 | ||
| 398 | code->code = csiphy->formats[code->index].code; | 408 | code->code = csiphy->res->formats->formats[code->index].code; |
| 399 | } else { | 409 | } else { |
| 400 | if (code->index > 0) | 410 | if (code->index > 0) |
| 401 | return -EINVAL; | 411 | return -EINVAL; |
| @@ -564,25 +574,7 @@ int msm_csiphy_subdev_init(struct camss *camss, · 162 unmodified lines | |||
| 564 | csiphy->camss = camss; | 574 | csiphy->camss = camss; |
| 565 | csiphy->id = id; | 575 | csiphy->id = id; |
| 566 | csiphy->cfg.combo_mode = 0; | 576 | csiphy->cfg.combo_mode = 0; |
| 567 | csiphy->ops = res->ops; | 577 | csiphy->res = &res->csiphy; |
| 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 | } | ||
| 586 | 578 | ||
| 587 | /* Memory */ | 579 | /* Memory */ |
| 588 | 580 | ||
| @@ -610,7 +602,7 @@ int msm_csiphy_subdev_init(struct camss *camss, · 21 unmodified lines | |||
| 610 | snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d", | 602 | snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d", |
| 611 | dev_name(dev), MSM_CSIPHY_NAME, csiphy->id); | 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 | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, | 606 | IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN, |
| 615 | csiphy->irq_name, csiphy); | 607 | csiphy->irq_name, csiphy); |
| 616 | if (ret < 0) { | 608 | if (ret < 0) { |
| @@ -42,6 +42,16 @@ struct csiphy_config { · 41 unmodified lines | |||
| 42 | struct csiphy_csi2_cfg *csi2; | 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 | struct csiphy_device; | 55 | struct csiphy_device; |
| 46 | 56 | ||
| 47 | struct csiphy_hw_ops { | 57 | struct csiphy_hw_ops { |
| @@ -63,6 +73,11 @@ struct csiphy_hw_ops { · 15 unmodified lines | |||
| 63 | irqreturn_t (*isr)(int irq, void *dev); | 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 | struct csiphy_device { | 81 | struct csiphy_device { |
| 67 | struct camss *camss; | 82 | struct camss *camss; |
| 68 | u8 id; | 83 | u8 id; |
| @@ -78,9 +93,7 @@ struct csiphy_device { · 9 unmodified lines | |||
| 78 | u32 timer_clk_rate; | 93 | u32 timer_clk_rate; |
| 79 | struct csiphy_config cfg; | 94 | struct csiphy_config cfg; |
| 80 | struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; | 95 | struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM]; |
| 81 | const struct csiphy_hw_ops *ops; | 96 | const struct csiphy_subdev_resources *res; |
| 82 | const struct csiphy_format *formats; | ||
| 83 | unsigned int nformats; | ||
| 84 | }; | 97 | }; |
| 85 | 98 | ||
| 86 | struct camss_subdev_resources; | 99 | struct camss_subdev_resources; |
| @@ -94,6 +107,10 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy, · 7 unmodified lines | |||
| 94 | 107 | ||
| 95 | void msm_csiphy_unregister_entity(struct csiphy_device *csiphy); | 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 | extern const struct csiphy_hw_ops csiphy_ops_2ph_1_0; | 114 | extern const struct csiphy_hw_ops csiphy_ops_2ph_1_0; |
| 98 | extern const struct csiphy_hw_ops csiphy_ops_3ph_1_0; | 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 | writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0); | 353 | writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0); |
| 354 | writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1); | 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 | vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i)); | 357 | vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i)); |
| 358 | writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i)); | 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 | if (status0 & STATUS_0_RESET_ACK) | 367 | if (status0 & STATUS_0_RESET_ACK) |
| 368 | vfe->isr_ops.reset_ack(vfe); | 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 | if (status0 & STATUS_0_RDI_REG_UPDATE(i)) | 371 | if (status0 & STATUS_0_RDI_REG_UPDATE(i)) |
| 372 | vfe->isr_ops.reg_update(vfe, i); | 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 | if (status0 & STATUS_1_RDI_SOF(i)) | 375 | if (status0 & STATUS_1_RDI_SOF(i)) |
| 376 | vfe->isr_ops.sof(vfe, i); | 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 | struct vfe_device *vfe = to_vfe(line); | 443 | struct vfe_device *vfe = to_vfe(line); |
| 444 | struct vfe_output *output = &line->output; | 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 | struct media_entity *sensor; | 446 | struct media_entity *sensor; |
| 447 | unsigned long flags; | 447 | unsigned long flags; |
| 448 | unsigned int frame_skip = 0; | 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 | unsigned long flags; | 560 | unsigned long flags; |
| 561 | 561 | ||
| 562 | spin_lock_irqsave(&vfe->output_lock, flags); | 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 | output = &vfe->line[line_id].output; | 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 | u32 value0, value1; | 892 | u32 value0, value1; |
| 893 | int i, j; | 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 | dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", | 897 | dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", |
| 898 | value0, value1); | 898 | value0, value1); |
| @@ -901,7 +901,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 2 unmodified lines | |||
| 901 | vfe->isr_ops.reset_ack(vfe); | 901 | vfe->isr_ops.reset_ack(vfe); |
| 902 | 902 | ||
| 903 | if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) | 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 | if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) | 906 | if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) |
| 907 | vfe->isr_ops.halt_ack(vfe); | 907 | vfe->isr_ops.halt_ack(vfe); |
| @@ -1050,7 +1050,7 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 1049 unmodified lines | |||
| 1050 | u32 value0, value1; | 1050 | u32 value0, value1; |
| 1051 | int i, j; | 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 | dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", | 1055 | dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n", |
| 1056 | value0, value1); | 1056 | value0, value1); |
| @@ -1059,12 +1059,12 @@ static irqreturn_t vfe_isr(int irq, void *dev) · 2 unmodified lines | |||
| 1059 | vfe->isr_ops.reset_ack(vfe); | 1059 | vfe->isr_ops.reset_ack(vfe); |
| 1060 | 1060 | ||
| 1061 | if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION) | 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 | if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) | 1064 | if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK) |
| 1065 | vfe->isr_ops.halt_ack(vfe); | 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 | if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i)) | 1068 | if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i)) |
| 1069 | vfe->isr_ops.reg_update(vfe, i); | 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.