summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml78
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml56
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml196
-rw-r--r--Documentation/driver-api/media/v4l2-subdev.rst36
-rw-r--r--Documentation/userspace-api/media/v4l/dev-subdev.rst250
-rw-r--r--Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst4
-rw-r--r--arch/arm64/boot/dts/ti/Makefile19
-rw-r--r--arch/arm64/boot/dts/ti/k3-am64-main.dtsi2
-rw-r--r--arch/arm64/boot/dts/ti/k3-am642-sk.dts14
-rw-r--r--arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi74
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-cpb-fusion.dts112
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-0.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-1.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-2.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-3.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-0.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-1.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-2.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-3.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-0.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-1.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-2.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-3.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-0.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-1.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-2.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-3.dts99
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-fpdlink-sk-fusion.dts125
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-sk.dts46
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi46
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts16
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi10
-rw-r--r--drivers/i2c/Kconfig9
-rw-r--r--drivers/i2c/Makefile1
-rw-r--r--drivers/i2c/i2c-atr.c558
-rw-r--r--drivers/i2c/i2c-core-base.c18
-rw-r--r--drivers/media/dvb-frontends/ascot2e.h2
-rw-r--r--drivers/media/dvb-frontends/cxd2820r.h2
-rw-r--r--drivers/media/dvb-frontends/drxk.h2
-rw-r--r--drivers/media/dvb-frontends/dvb-pll.h2
-rw-r--r--drivers/media/dvb-frontends/helene.h4
-rw-r--r--drivers/media/dvb-frontends/horus3a.h2
-rw-r--r--drivers/media/dvb-frontends/ix2505v.h4
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.h2
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.h2
-rw-r--r--drivers/media/dvb-frontends/stb6000.h2
-rw-r--r--drivers/media/dvb-frontends/tda826x.h2
-rw-r--r--drivers/media/dvb-frontends/zl10036.h4
-rw-r--r--drivers/media/i2c/Kconfig34
-rw-r--r--drivers/media/i2c/Makefile3
-rw-r--r--drivers/media/i2c/ds90ub953.c1006
-rw-r--r--drivers/media/i2c/ds90ub960.c2381
-rw-r--r--drivers/media/i2c/imx390.c900
-rw-r--r--drivers/media/i2c/imx390.h7158
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c85
-rw-r--r--drivers/media/platform/rcar-vin/rcar-v4l2.c9
-rw-r--r--drivers/media/platform/ti/cal/cal-camerarx.c338
-rw-r--r--drivers/media/platform/ti/cal/cal-video.c85
-rw-r--r--drivers/media/platform/ti/cal/cal.c181
-rw-r--r--drivers/media/platform/ti/cal/cal.h25
-rw-r--r--drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c192
-rw-r--r--drivers/media/platform/vsp1/vsp1_entity.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c830
-rw-r--r--drivers/staging/media/ipu3/include/intel-ipu3.h8
-rw-r--r--drivers/staging/media/tegra-video/vi.c10
-rw-r--r--drivers/usb/dwc3/core.c56
-rw-r--r--drivers/usb/dwc3/drd.c43
-rw-r--r--include/linux/i2c-atr.h82
-rw-r--r--include/linux/i2c.h16
-rw-r--r--include/media/cec.h2
-rw-r--r--include/media/dvbdev.h2
-rw-r--r--include/media/v4l2-ctrls.h2
-rw-r--r--include/media/v4l2-dev.h4
-rw-r--r--include/media/v4l2-device.h2
-rw-r--r--include/media/v4l2-dv-timings.h2
-rw-r--r--include/media/v4l2-fwnode.h2
-rw-r--r--include/media/v4l2-h264.h6
-rw-r--r--include/media/v4l2-jpeg.h2
-rw-r--r--include/media/v4l2-mediabus.h6
-rw-r--r--include/media/v4l2-subdev.h314
-rw-r--r--include/media/videobuf2-core.h2
-rw-r--r--include/uapi/linux/cec.h3
-rw-r--r--include/uapi/linux/v4l2-subdev.h40
-rw-r--r--include/uapi/linux/videodev2.h15
-rw-r--r--ti_config_fragments/audio_display.cfg4
85 files changed, 16150 insertions, 994 deletions
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml
new file mode 100644
index 000000000000..3b654948e2e5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx390.yaml
@@ -0,0 +1,78 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx390.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX390 Camera Sensor
+
+maintainers:
+ - Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+
+description: |-
+ Sony IMX390 camera sensor.
+
+properties:
+ compatible:
+ enum:
+ - sony,imx390
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: inck
+
+ xclr-gpios:
+ maxItems: 1
+ description:
+ Specifier for the GPIO connected to the XCLR (System Reset) pin.
+
+ port:
+ $ref: /schemas/graph.yaml#/properties/port
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: ../video-interfaces.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&fixed_clock>;
+ clock-names = "inck";
+
+ xclr-gpios = <&gpio4 17 GPIO_ACTIVE_LOW>;
+
+ port {
+ camera1: endpoint {
+ remote-endpoint = <&vin1a_ep>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml
new file mode 100644
index 000000000000..27cacdfa080f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub953.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ti,ds90ub953.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments DS90UB953 FPD-Link 3 Serializer
+
+maintainers:
+ - Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+
+description: |-
+ The TI DS90UB953 is an FPD-Link 3 video serializer for MIPI CSI-2.
+
+properties:
+ compatible:
+ enum:
+ - ti,ds90ub953-q1
+
+ '#gpio-cells':
+ const: 2
+
+ gpio-controller: true
+
+ ports: true
+
+required:
+ - compatible
+ - '#gpio-cells'
+ - gpio-controller
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ };
+
+ port@1 {
+ reg = <1>;
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml
new file mode 100644
index 000000000000..be2a92c1f754
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ti,ds90ub960.yaml
@@ -0,0 +1,196 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ti,ds90ub960.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Texas Instruments DS90UB960 FPD-Link 3 Deserializer Hub
+
+maintainers:
+ - Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+
+description: |-
+ The TI DS90UB960 is an FPD-Link 3 video deserializer with 4 FPD-Link 3
+ inputs and 2 MIPI CSI-2 outputs. It also features I2C and GPIO forwarding.
+
+properties:
+ compatible:
+ enum:
+ - ti,ds90ub960-q1
+
+ reg:
+ minItems: 1
+ maxItems: 5
+ description:
+ i2c addresses for the deserializer and the serializers
+
+ reg-names:
+ minItems: 1
+ items:
+ - const: main
+ - enum: [ ser0, ser1, ser2, ser3 ]
+ - enum: [ ser0, ser1, ser2, ser3 ]
+ - enum: [ ser0, ser1, ser2, ser3 ]
+ - enum: [ ser0, ser1, ser2, ser3 ]
+ - enum: [ ser0, ser1, ser2, ser3 ]
+
+
+ clocks:
+ maxItems: 1
+ description:
+ Reference clock connected to the REFCLK pin.
+
+ powerdown-gpios:
+ maxItems: 1
+ description:
+ Specifier for the GPIO connected to the PWDN pin.
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: FPD-Link 3 input 0
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+
+ properties:
+ mode:
+ description: FPD3 Input Mode
+ bc-freq:
+ description: back channel frequency
+
+ required:
+ - mode
+ - bc-freq
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: FPD-Link 3 input 1
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+
+ properties:
+ mode:
+ description: FPD3 Input Mode
+ bc-freq:
+ description: back channel frequency
+
+ required:
+ - mode
+ - bc-freq
+
+ port@2:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: FPD-Link 3 input 2
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+
+ properties:
+ mode:
+ description: FPD3 Input Mode
+ bc-freq:
+ description: back channel frequency
+
+ required:
+ - mode
+ - bc-freq
+
+ port@3:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: FPD-Link 3 input 3
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+
+ properties:
+ mode:
+ description: FPD3 Input Mode
+ bc-freq:
+ description: back channel frequency
+
+ required:
+ - mode
+ - bc-freq
+
+ port@4:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: CSI-2 Output 0
+
+ port@5:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ description: CSI-2 Output 1
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ clock-frequency = <400000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ deser@3d {
+ compatible = "ti,ds90ub960-q1";
+
+ reg-names = "main", "ser0", "ser1", "ser2", "ser3";
+ reg = <0x3d>, <0x44>, <0x45>, <0x46>, <0x47>;
+
+ clocks = <&fixed_clock>;
+
+ powerdown-gpios = <&pca9555 7 GPIO_ACTIVE_LOW>;
+
+ i2c-alias-pool = /bits/ 16 <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* Port 0, Camera 0 */
+ port@0 {
+ reg = <0>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub913_out>;
+
+ mode = <0>;
+ bc-freq = <2500000>;
+
+ };
+ };
+
+ /* Port 4, CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ data-rate = <1600000000>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_atr: i2c-atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+...
diff --git a/Documentation/driver-api/media/v4l2-subdev.rst b/Documentation/driver-api/media/v4l2-subdev.rst
index bb5b1a7cdfd9..095610a58d95 100644
--- a/Documentation/driver-api/media/v4l2-subdev.rst
+++ b/Documentation/driver-api/media/v4l2-subdev.rst
@@ -491,6 +491,42 @@ The :c:func:`v4l2_i2c_new_subdev` function will call
:c:type:`i2c_board_info` structure using the ``client_type`` and the
``addr`` to fill it.
+Centrally managed subdev active state
+-------------------------------------
+
+Traditionally V4L2 subdev drivers maintained internal state for the active
+configuration for the subdev. This is often implemented as an array of struct
+v4l2_mbus_framefmt, one entry for each pad.
+
+In addition to the active configuration, each subdev filehandle has contained
+an array of struct v4l2_subdev_pad_config, managed by V4L2 core, which
+contains the TRY configuration.
+
+To simplify the subdev drivers the V4L2 subdev API now optionally supports a
+centrally managed active configuration. A subdev driver must use
+v4l2_subdev_init_finalize() to initialize the active state between calls to
+media_entity_pads_init() and v4l2_*_register_subdev(), and must call
+v4l2_subdev_cleanup() to free the state.
+
+The active state must be locked before access, and can be done with
+v4l2_subdev_lock_state() or v4l2_subdev_lock_active_state().
+
+The V4L2 core will pass either the TRY or ACTIVE state to various subdev ops.
+Unfortunately all the subdev drivers do not comply with this yet, and may pass
+NULL for the ACTIVE case. This is only a problem for subdev drivers which use
+the cetrally managed active state and are used in media pipelines with older
+subdev drivers. In these cases the called subdev ops must also handle the NULL
+case. This can be easily managed by the use of
+v4l2_subdev_validate_and_lock_state() helper.
+
+Streams, multiplexed media pads and internal routing
+----------------------------------------------------
+
+A subdevice driver can implement support for multiplexed streams by setting
+the V4L2_SUBDEV_FL_MULTIPLEXED subdev flag and implementing support for
+centrally managed subdev active state, routing and stream based
+configuration.
+
V4L2 sub-device functions and data structures
---------------------------------------------
diff --git a/Documentation/userspace-api/media/v4l/dev-subdev.rst b/Documentation/userspace-api/media/v4l/dev-subdev.rst
index 6c6a5ea8ba26..3f17709536ef 100644
--- a/Documentation/userspace-api/media/v4l/dev-subdev.rst
+++ b/Documentation/userspace-api/media/v4l/dev-subdev.rst
@@ -502,128 +502,166 @@ source pads.
subdev-formats
+Streams, multiplexed media pads and internal routing
+----------------------------------------------------
+
+Commonly V4L2 subdevices support only separate video streams, that is, each
+link in the media grap and each pad in a subdevice passes through a single
+video stream. Thus each pad contains a format configuration for that single
+stream. In some cases a subdev can do stream processing and split a stream
+into two or compose two streams into one, but the inputs and outputs for the
+subdev are still a single stream per pad.
+
+Some hardware, e.g. MIPI CSI-2, support multiplexed streams, that is, a single
+bus carries multiple streams. Thus a camera could output two streams, a pixel
+stream and a metadata stream, and a bridge subdev could route the streams
+from multiple input pads into a single output pad.
+
+Subdevice drivers that support multiplexed streams are compatible with
+non-multiplexed subdev drivers, but, of course, requires such a routing
+configuration where the link between those two types of drivers contain only
+a single stream.
+
+Understanding streams
+^^^^^^^^^^^^^^^^^^^^^
+
+A stream is a stream of content (e.g. pixel data or metadata) flowing through
+the media pipeline from a source (e.g. a sensor) towards the final sink
+(e.g. a receiver in a SoC). Each media link carries all the streams from
+one end of the link to the other, whereas subdevices have routing tables
+which describe how the incoming streams from sink pads are routed to the
+source pads.
-Multiplexed media pads and internal routing
--------------------------------------------
-
-Routing Table
-^^^^^^^^^^^^^
-
-Subdevice drivers may expose the internal connections between media pads of an
-entity by exposing a routing table that applications can inspect and manipulate.
-A routing table is described by a struct :c:type:`v4l2_subdev_routing`, which
-contains ``num_routes`` route entries, each one represented by a struct
-:c:type:`v4l2_subdev_route`.
-
-Data routes do not just connect one pad to another in an entity, but they refer
-instead to the ``streams`` a media pad provides. Streams are data connection
-endpoints in a media pad. Multiplexed media pads expose multiple ``streams``
-which represent, when the underlying hardware technology allows that, logical
-data flows transported over a single physical media bus.
-
-A noteworthy example of logical stream multiplexing techniques is represented
-by the data interleaving mechanism implemented by mean of Virtual Channels as
-defined by the MIPI CSI-2 media bus specifications. A subdevice that implements
-support for Virtual Channel data interleaving might expose up to 4 data
-``streams``, one for each available Virtual Channel, on the source media pad
-that represents a CSI-2 connection endpoint.
-
-A route is defined as a connection between a ``(sink_pad, sink_stream)`` pair
-and a ``(source_pad, source_stream)`` pair, where ``sink_pad`` and
-``source_pad`` are the indexes of two media pads part of the same media entity,
-and ``sink_stream`` and ``source_stream`` are the identifiers of the data
-streams to be connected in the media pads. The stream identifiers are arbitrary
-numbers, i.e. they have no relevance to the hardware, but they must be unique on
-a single pad, and the entity on the other side of the link must have a matching
-stream identifier.
-
-The current routes are reported to applications in a routing table which can be
-inspected using the :ref:`routing <VIDIOC_SUBDEV_G_ROUTING>` ioctl.
-
-Routes can be added or removed by adding or removing them to/from the routing
-table. Also, a route in the routing table can be activated and deactivated by
-setting or clearing the ``V4L2_SUBDEV_ROUTE_FL_ACTIVE`` flag in the ``flags``
-field of struct :c:type:`v4l2_subdev_route`.
-
-A subdev driver may create routes that cannot be modified by applications. Such
-routes are identified by the presence of the ``V4L2_SUBDEV_ROUTE_FL_IMMUTABLE``
-flag in the ``flags`` field of struct :c:type:`v4l2_subdev_route`. Immutable
-routes are always active.
-
-A special type of a route is a "source route", marked with
-``V4L2_SUBDEV_ROUTE_FL_SOURCE`` flag. Such routes exists in e.g. sensors as the
-routes' origins are internal to the device. A source route has valid
-``source_pad`` and ``source_stream``, but ``sink_pad`` and ``sink_stream`` are
-not used. The purpose of a source route is to describe the streams.
-
-As an example, a subdevice with two sink pads and one output pad has the pads
-defined as follows:
-
-.. flat-table::
- :header-rows: 1
+A stream ID (often just "stream") is a media link-local identifier for a
+stream. In other words, configuration for a particular stream ID must exist
+on both sides of a media link, but another stream ID can be used for the same
+stream at the other side of the subdevice.
- * - Pad Index
- - Function
- * - 0
- - SINK
- * - 1
- - SINK
- * - 2
- - SOURCE
+A stream at a specific point in the media pipeline is identified with the
+subdev and a (pad, stream) pair. For subdevices that do not support
+multiplexed streams the 'stream' is always 0.
-A case where the subdevice would receive a single stream via each sink pad, and
-combine them to the source pad would result in a routing table as follows:
+Configuring streams
+^^^^^^^^^^^^^^^^^^^
-.. flat-table:: routing table
- :header-rows: 1
+The configuration of the streams is done individually for each subdevice and
+the validity of the streams between subdevices is validated when the pipeline
+is started.
- * - Sink Pad/Sink Stream
- - Source Pad/Source Stream
- * - 0/0
- - 2/0
- * - 1/0
- - 2/1
+There are three steps in configuring the streams:
+
+1) Set up links. Connect the pads between subdevices using the :ref:`Media
+Controller API <media_controller>`
+
+2) Routing. The routing table for the subdevice must be set with
+:ref:`VIDIOC_SUBDEV_S_ROUTING <VIDIOC_SUBDEV_G_ROUTING>` ioctl.
+
+3) Configure streams. Each route endpoint must be configured
+with :ref:`VIDIOC_SUBDEV_S_FMT <VIDIOC_SUBDEV_G_FMT>`.
+
+Multiplexed streams setup example
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A simple example of a multiplexed stream setup might be as follows:
+
+- Two identical sensors (Sensor A and Sensor B). Each sensor has a single
+ source pad (pad 0), and outputs two streams, pixel data and metadata.
+
+- Multiplexer bridge (Bridge). The bridge has two sink pads, connected to the
+ sensors (pads 0, 1), and one source pad (pad 2), which outputs all 4
+ streams.
+
+- Receiver in the SoC (Receiver). The receiver has a single sink pad (pad 0),
+ connected to the bridge, and four source pads (pads 1-4), going to the DMA
+ engine. The receiver demultiplexes the incoming streams to the four source
+ pads.
-Whereas if the same subdev would receive two streams via each sink pad, and
-output the combined 4 streams would result in a routing table as follows:
+- Four DMA Engines in the SoC (DMA Engine). Each DMA engine is connected to a
+ single source pad in the receiver.
-.. flat-table:: routing table
+The sensors, the bridge and the receiver are modeled as V4L2 subdevices,
+exposed to userspace via /dev/v4l-subdevX device nodes. The DMA engines are
+modeled as V4L2 devices, exposed to userspace via /dev/videoX nodes.
+
+To configure this pipeline, the userspace must take the following steps:
+
+1) Set up media links between entities: connect the sensors to the bridge,
+bridge to the receiver, and the receiver to the DMA engines. This step does
+not differ from normal non-multiplexed media controller setup.
+
+2) Configure routing.
+
+.. flat-table:: Sensor routing table (identical on both sensors)
:header-rows: 1
- * - Sink Pad/Sink Stream
- - Source Pad/Source Stream
+ * - Sink Pad/Stream
+ - Source Pad/Stream
+ - Routing Flags
+ - Comments
+ * - 0/0 (unused)
+ - 0/0
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE | V4L2_SUBDEV_ROUTE_FL_SOURCE
+ - Pixel data stream. Source route, i.e. the sink fields are unused.
+ * - 0/0 (unused)
+ - 0/1
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE | V4L2_SUBDEV_ROUTE_FL_SOURCE
+ - Metadata stream. Source route, i.e. the sink fields are unused.
+
+.. flat-table:: Bridge routing table
+ :header-rows: 1
+
+ * - Sink Pad/Stream
+ - Source Pad/Stream
+ - Routing Flags
+ - Comments
* - 0/0
- 2/0
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Pixel data stream from Sensor A
* - 0/1
- 2/1
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Metadata stream from Sensor A
* - 1/0
- 2/2
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Pixel data stream from Sensor B
* - 1/1
- 2/3
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Metadata stream from Sensor B
-Some subdevices may have known set of routes, mutable or immutable, dictated by
-the hardware. An example would be a sensor which produces pixel data and
-metadata via CSI-2 bus. In such a case there can ever be only those two streams.
-
-A subdevice that does not produce the data is another matter. Consider a device
-with two CSI-2 sink pads and two CSI-2 source pads, with the ability to route
-streams freely between the sink and source pads based on HW configuration. Each
-sink pad could receive streams for all four CSI-2 virtual channel. If we only
-consider the virtual channels, we would have maximum number of routes of 8.
-
-But CSI-2 also defines a datatype for each CSI-2 packet, allowing one to send,
-say, pixel data and metadata using the same virtual channel but different
-datatype. Now we would have a maximum number of routes of 16.
-
-Generally speaking, the concept of "stream" is very flexible. As a contrived
-example, you might even consider each line of a pixel frame to be a separate
-stream, if your hardware would support such a thing.
-
-Multiplexed Streams
-^^^^^^^^^^^^^^^^^^^
+.. flat-table:: Receiver routing table
+ :header-rows: 1
-When a subdevice exposes multiple streams in a single pad (multiplexed streams),
-the subdevice driver needs to have ``V4L2_SUBDEV_FL_MULTIPLEXED`` flag set. This
-flag indicates that the subdev supports the uAPI extensions needed to support
-multiple streams, and the driver must handle the ``stream`` field in the various
-subdev ioctls.
+ * - Sink Pad/Stream
+ - Source Pad/Stream
+ - Routing Flags
+ - Comments
+ * - 0/0
+ - 1/0
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Pixel data stream from Sensor A
+ * - 0/1
+ - 2/0
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Metadata stream from Sensor A
+ * - 0/2
+ - 3/0
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Pixel data stream from Sensor B
+ * - 0/3
+ - 4/0
+ - V4L2_SUBDEV_ROUTE_FL_ACTIVE
+ - Metadata stream from Sensor B
+
+3) Configure streams
+
+After configuring the routing table, the next step is configuring the streams.
+This step is similar to configuring the pads in a non-multiplexed streams
+setup, with the difference that we need to configure each (pad, stream) pair
+(i.e. route endpoint), instead of just a pad.
+
+Presuming there are no format conversions in the pipeline, the userspace needs
+to configure all the route endpoints using four formats (two pixel formats
+and two metadata formats) with VIDIOC_SUBDEV_S_FMT.
diff --git a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
index 6d953ee23287..41f4873c49f7 100644
--- a/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
+++ b/Documentation/userspace-api/media/v4l/vidioc-subdev-g-routing.rst
@@ -45,6 +45,10 @@ with the VIDIOC_SUBDEV_S_ROUTING ioctl, by adding or removing routes and setting
or clearing the ``V4L2_SUBDEV_ROUTE_FL_ACTIVE`` flag of the ``flags`` field of
a struct :c:type:`v4l2_subdev_route`.
+A special case for routing are routes marked with
+``V4L2_SUBDEV_ROUTE_FL_SOURCE`` flag. These routes are used to describe
+source endpoints on sensors and the sink fields are unused.
+
When inspecting routes through VIDIOC_SUBDEV_G_ROUTING and the application
provided ``num_routes`` is not big enough to contain all the available routes
the subdevice exposes, drivers return the ENOSPC error code and adjust the
diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index d30b73e4d6a1..2ac11a080ff2 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -44,3 +44,22 @@ dtb-$(CONFIG_ARCH_K3) += k3-am625-sk.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am625-skeleton.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-lpmdemo.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am625-sk-csi2-ov5640.dtbo
+
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-cpb-fusion.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-sk-fusion.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-0-0.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-0-1.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-0-2.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-0-3.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-1-0.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-1-1.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-1-2.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-cm-1-3.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-0-0.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-0-1.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-0-2.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-0-3.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-1-0.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-1-1.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-1-2.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-fpdlink-imx390-rcm-1-3.dtbo
diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
index 9ff5cc05bcec..615abec16583 100644
--- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
@@ -467,13 +467,11 @@
clock-names = "clk_ahb", "clk_xin";
mmc-ddr-1_8v;
mmc-hs200-1_8v;
- mmc-hs400-1_8v;
ti,trm-icp = <0x2>;
ti,otap-del-sel-legacy = <0x0>;
ti,otap-del-sel-mmc-hs = <0x0>;
ti,otap-del-sel-ddr52 = <0x6>;
ti,otap-del-sel-hs200 = <0x7>;
- ti,otap-del-sel-hs400 = <0x4>;
};
sdhci1: mmc@fa00000 {
diff --git a/arch/arm64/boot/dts/ti/k3-am642-sk.dts b/arch/arm64/boot/dts/ti/k3-am642-sk.dts
index e536dc0c2e9b..6daac38e9553 100644
--- a/arch/arm64/boot/dts/ti/k3-am642-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am642-sk.dts
@@ -153,6 +153,15 @@
>;
};
+ main_uart0_pins_default: main-uart0-pins-default {
+ pinctrl-single,pins = <
+ AM64X_IOPAD(0x0238, PIN_INPUT, 0) /* (B16) UART0_CTSn */
+ AM64X_IOPAD(0x023c, PIN_OUTPUT, 0) /* (A16) UART0_RTSn */
+ AM64X_IOPAD(0x0230, PIN_INPUT, 0) /* (D15) UART0_RXD */
+ AM64X_IOPAD(0x0234, PIN_OUTPUT, 0) /* (C16) UART0_TXD */
+ >;
+ };
+
main_usb0_pins_default: main-usb0-pins-default {
pinctrl-single,pins = <
AM64X_IOPAD(0x02a8, PIN_OUTPUT, 0) /* (E19) USB0_DRVVBUS */
@@ -238,6 +247,11 @@
status = "disabled";
};
+&main_uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_uart0_pins_default>;
+};
+
&main_uart1 {
/* main_uart1 is reserved for firmware usage */
status = "reserved";
diff --git a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
index 9f70925c8da8..66644f48d346 100644
--- a/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j7200-som-p0.dtsi
@@ -153,6 +153,37 @@
flash@0,0 {
compatible = "cypress,hyperflash", "cfi-flash";
reg = <0x00 0x00 0x4000000>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "hbmc.tiboot3";
+ reg = <0x0 0x100000>;
+ };
+
+ partition@100000 {
+ label = "hbmc.tispl";
+ reg = <0x100000 0x200000>;
+ };
+
+ partition@300000 {
+ label = "hbmc.u-boot";
+ reg = <0x300000 0x400000>;
+ };
+
+ partition@700000 {
+ label = "hbmc.env";
+ reg = <0x700000 0x40000>;
+ };
+
+ partition@800000 {
+ label = "hbmc.rootfs";
+ reg = <0x800000 0x3800000>;
+ };
+ };
};
};
@@ -271,7 +302,7 @@
pinctrl-names = "default";
pinctrl-0 = <&mcu_fss0_ospi0_pins_default>;
- flash@0{
+ flash@0 {
compatible = "jedec,spi-nor";
reg = <0x0>;
spi-tx-bus-width = <8>;
@@ -284,5 +315,46 @@
cdns,read-delay = <4>;
#address-cells = <1>;
#size-cells = <1>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "ospi.tiboot3";
+ reg = <0x0 0x100000>;
+ };
+
+ partition@100000 {
+ label = "ospi.tispl";
+ reg = <0x100000 0x200000>;
+ };
+
+ partition@300000 {
+ label = "ospi.u-boot";
+ reg = <0x300000 0x400000>;
+ };
+
+ partition@700000 {
+ label = "ospi.env";
+ reg = <0x700000 0x40000>;
+ };
+
+ partition@740000 {
+ label = "ospi.env.backup";
+ reg = <0x740000 0x40000>;
+ };
+
+ partition@800000 {
+ label = "ospi.rootfs";
+ reg = <0x800000 0x37c0000>;
+ };
+
+ partition@3fc0000 {
+ label = "ospi.phypattern";
+ reg = <0x3fc0000 0x40000>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-cpb-fusion.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-cpb-fusion.dts
new file mode 100644
index 000000000000..ce4407040c80
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-cpb-fusion.dts
@@ -0,0 +1,112 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_fusion_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+ };
+ };
+};
+
+&main_i2c6 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ deser@3d {
+ compatible = "ti,ds90ub960-q1";
+
+ reg-names = "main", "ser0", "ser1", "ser2", "ser3";
+ reg = <0x3d>, <0x44>, <0x45>, <0x46>, <0x47>;
+
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = /bits/ 16 <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ data-rate = <1600000000>;
+
+ ds90ub960_0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_atr: i2c-atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ deser@36 {
+ compatible = "ti,ds90ub960-q1";
+
+ reg-names = "main", "ser0", "ser1", "ser2", "ser3";
+ reg = <0x36>, <0x54>, <0x55>, <0x56>, <0x57>;
+
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = /bits/ 16 <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>;
+
+ data-rate = <1600000000>;
+
+ ds90ub960_1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 */
+ port@4 {
+ reg = <4>;
+ ds90ub960_1_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csi2_phy1>;
+ };
+ };
+ };
+
+ ds90ub960_1_atr: i2c-atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+};
+
+&csi0_port0 {
+ status = "okay";
+
+ csi2_phy0: endpoint {
+ remote-endpoint = <&ds90ub960_0_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ };
+};
+
+&csi1_port0 {
+ status = "okay";
+
+ csi2_phy1: endpoint {
+ remote-endpoint = <&ds90ub960_1_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-0.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-0.dts
new file mode 100644
index 000000000000..fff3678ab505
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-0.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-0-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 0 */
+ port@0 {
+ reg = <0>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-1.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-1.dts
new file mode 100644
index 000000000000..82c748f4d707
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-1.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 1 */
+ port@1 {
+ reg = <1>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-2.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-2.dts
new file mode 100644
index 000000000000..dd5ff95a1e3c
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-2.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-2-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 2 */
+ port@2 {
+ reg = <2>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-3.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-3.dts
new file mode 100644
index 000000000000..4dd45eec73ec
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-0-3.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-3-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 3 */
+ port@3 {
+ reg = <3>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-0.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-0.dts
new file mode 100644
index 000000000000..847499f3dab0
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-0.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-0-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 0 */
+ port@0 {
+ reg = <0>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-1.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-1.dts
new file mode 100644
index 000000000000..45a9b3d88628
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-1.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-1-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 1 */
+ port@1 {
+ reg = <1>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-2.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-2.dts
new file mode 100644
index 000000000000..799f63a86e7b
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-2.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-2-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 2 */
+ port@2 {
+ reg = <2>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-3.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-3.dts
new file mode 100644
index 000000000000..1e7b13117261
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-cm-1-3.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-3-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 3 */
+ port@3 {
+ reg = <3>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@21 {
+ compatible = "sony,imx390";
+ reg = <0x21>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 1 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-0.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-0.dts
new file mode 100644
index 000000000000..e9b1526c5723
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-0.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-0-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 0 */
+ port@0 {
+ reg = <0>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-1.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-1.dts
new file mode 100644
index 000000000000..3cfebdaf0828
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-1.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 1 */
+ port@1 {
+ reg = <1>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-2.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-2.dts
new file mode 100644
index 000000000000..5dadbd168c01
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-2.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-2-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 2 */
+ port@2 {
+ reg = <2>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-3.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-3.dts
new file mode 100644
index 000000000000..9dbc84e361db
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-0-3.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-3-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_0_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 3 */
+ port@3 {
+ reg = <3>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_0_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-0.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-0.dts
new file mode 100644
index 000000000000..a6fc5693ff62
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-0.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-0-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 0 */
+ port@0 {
+ reg = <0>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-1.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-1.dts
new file mode 100644
index 000000000000..d4460ee6fcea
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-1.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-1-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 1 */
+ port@1 {
+ reg = <1>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@1 {
+ reg = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-2.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-2.dts
new file mode 100644
index 000000000000..6545bf0676ba
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-2.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-2-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 2 */
+ port@2 {
+ reg = <2>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@2 {
+ reg = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-3.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-3.dts
new file mode 100644
index 000000000000..32a71bf34af6
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-imx390-rcm-1-3.dts
@@ -0,0 +1,99 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_cam_27M: fixed-clock-1-3-27M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <27000000>;
+ };
+ };
+ };
+};
+
+&ds90ub960_1_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 3 */
+ port@3 {
+ reg = <3>;
+
+ ds90ub960_fpd3_in: endpoint {
+ remote-endpoint = <&ub953_out>;
+
+ mode = <3>;
+ bc-freq = <50000000>;
+
+ serializer: remote-chip {
+ compatible = "ti,ds90ub953-q1";
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_in: endpoint {
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_out: endpoint {
+ remote-endpoint = <&ds90ub960_fpd3_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
+
+&ds90ub960_1_atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@3 {
+ reg = <3>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&clk_cam_27M>;
+ clock-names = "inck";
+
+ xclr-gpios = <&serializer 1 GPIO_ACTIVE_LOW>;
+ error0-gpios = <&serializer 2 GPIO_ACTIVE_HIGH>;
+ error1-gpios = <&serializer 3 GPIO_ACTIVE_HIGH>;
+ comready-gpios = <&serializer 0 GPIO_ACTIVE_HIGH>;
+
+ port {
+ sensor_out: endpoint {
+ remote-endpoint = <&ub953_in>;
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-sk-fusion.dts b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-sk-fusion.dts
new file mode 100644
index 000000000000..b4cb9c59a1f6
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-fpdlink-sk-fusion.dts
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (C) 2021 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+/ {
+ fragment@101 {
+ target-path = "/";
+
+ __overlay__ {
+ clk_fusion_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+ };
+ };
+};
+
+&main_i2c3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c-switch@70 {
+ compatible = "nxp,pca9543";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+
+ cam0_i2c: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ deser@38 {
+ compatible = "ti,ds90ub960-q1";
+
+ reg-names = "main", "ser0", "ser1", "ser2", "ser3";
+ reg = <0x38>, <0x44>, <0x45>, <0x46>, <0x47>;
+
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = /bits/ 16 <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ data-rate = <1600000000>;
+
+ ds90ub960_0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_atr: i2c-atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+
+ reg-names = "main", "ser0", "ser1", "ser2", "ser3";
+ reg = <0x30>, <0x54>, <0x55>, <0x56>, <0x57>;
+
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = /bits/ 16 <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>;
+
+ data-rate = <1600000000>;
+
+ ds90ub960_1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 */
+ port@4 {
+ reg = <4>;
+ ds90ub960_1_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&csi2_phy1>;
+ };
+ };
+ };
+
+ ds90ub960_1_atr: i2c-atr {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+ };
+};
+
+&csi0_port0 {
+ status = "okay";
+
+ csi2_phy0: endpoint {
+ remote-endpoint = <&ds90ub960_0_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ };
+};
+
+&csi1_port0 {
+ status = "okay";
+
+ csi2_phy1: endpoint {
+ remote-endpoint = <&ds90ub960_1_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
index 30b57f4222e8..3038723afb9c 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721e-sk.dts
@@ -638,6 +638,52 @@
cdns,read-delay = <4>;
#address-cells = <1>;
#size-cells = <1>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "ospi.tiboot3";
+ reg = <0x0 0x80000>;
+ };
+
+ partition@80000 {
+ label = "ospi.tispl";
+ reg = <0x80000 0x200000>;
+ };
+
+ partition@280000 {
+ label = "ospi.u-boot";
+ reg = <0x280000 0x400000>;
+ };
+
+ partition@680000 {
+ label = "ospi.env";
+ reg = <0x680000 0x40000>;
+ };
+
+ partition@6c0000 {
+ label = "ospi.sysfw";
+ reg = <0x6c0000 0x100000>;
+ };
+
+ partition@7c0000 {
+ label = "ospi.env.backup";
+ reg = <0x7c0000 0x40000>;
+ };
+
+ partition@800000 {
+ label = "ospi.rootfs";
+ reg = <0x800000 0x37c0000>;
+ };
+
+ partition@3fc0000 {
+ label = "ospi.phypattern";
+ reg = <0x3fc0000 0x40000>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
index 906d16a240f2..1fb3bb479677 100644
--- a/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721e-som-p0.dtsi
@@ -196,6 +196,52 @@
cdns,read-delay = <0>;
#address-cells = <1>;
#size-cells = <1>;
+
+ partitions {
+ compatible = "fixed-partitions";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "ospi.tiboot3";
+ reg = <0x0 0x80000>;
+ };
+
+ partition@80000 {
+ label = "ospi.tispl";
+ reg = <0x80000 0x200000>;
+ };
+
+ partition@280000 {
+ label = "ospi.u-boot";
+ reg = <0x280000 0x400000>;
+ };
+
+ partition@680000 {
+ label = "ospi.env";
+ reg = <0x680000 0x20000>;
+ };
+
+ partition@6a0000 {
+ label = "ospi.env.backup";
+ reg = <0x6a0000 0x20000>;
+ };
+
+ partition@6c0000 {
+ label = "ospi.sysfw";
+ reg = <0x6c0000 0x100000>;
+ };
+
+ partition@800000 {
+ label = "ospi.rootfs";
+ reg = <0x800000 0x37c0000>;
+ };
+
+ partition@3fe0000 {
+ label = "ospi.phypattern";
+ reg = <0x3fe0000 0x20000>;
+ };
+ };
};
};
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
index c90bd74b3c81..c095e213cfa8 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-common-proc-board.dts
@@ -544,14 +544,14 @@
* VP3 - DPI1
*/
- assigned-clocks = <&k3_clks 158 35>,
- <&k3_clks 158 17>,
- <&k3_clks 158 26>,
- <&k3_clks 158 0>;
- assigned-clock-parents = <&k3_clks 158 36>,
- <&k3_clks 158 19>,
- <&k3_clks 158 28>,
- <&k3_clks 158 4>;
+ assigned-clocks = <&k3_clks 158 2>,
+ <&k3_clks 158 5>,
+ <&k3_clks 158 14>,
+ <&k3_clks 158 18>;
+ assigned-clock-parents = <&k3_clks 158 3>,
+ <&k3_clks 158 7>,
+ <&k3_clks 158 16>,
+ <&k3_clks 158 22>;
};
&dss_ports {
diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
index 937ba065a156..38843f866720 100644
--- a/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j721s2-main.dtsi
@@ -1381,11 +1381,11 @@
"vp1", "vp2", "vp3", "vp4",
"wb";
- clocks = <&k3_clks 158 11>,
- <&k3_clks 158 35>,
- <&k3_clks 158 17>,
- <&k3_clks 158 26>,
- <&k3_clks 158 0>;
+ clocks = <&k3_clks 158 0>,
+ <&k3_clks 158 2>,
+ <&k3_clks 158 5>,
+ <&k3_clks 158 14>,
+ <&k3_clks 158 18>;
clock-names = "fck", "vp1", "vp2", "vp3", "vp4";
power-domains = <&k3_pds 158 TI_SCI_PD_EXCLUSIVE>;
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 438905e2a1d0..c6d1a345ea6d 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -71,6 +71,15 @@ config I2C_MUX
source "drivers/i2c/muxes/Kconfig"
+config I2C_ATR
+ tristate "I2C Address Translator (ATR) support"
+ help
+ Enable support for I2C Address Translator (ATR) chips.
+
+ An ATR allows accessing multiple I2C busses from a single
+ physical bus via address translation instead of bus selection as
+ i2c-muxes do.
+
config I2C_HELPER_AUTO
bool "Autoselect pertinent helper modules"
default y
diff --git a/drivers/i2c/Makefile b/drivers/i2c/Makefile
index c1d493dc9bac..3f71ce4711e3 100644
--- a/drivers/i2c/Makefile
+++ b/drivers/i2c/Makefile
@@ -13,6 +13,7 @@ i2c-core-$(CONFIG_OF) += i2c-core-of.o
obj-$(CONFIG_I2C_SMBUS) += i2c-smbus.o
obj-$(CONFIG_I2C_CHARDEV) += i2c-dev.o
obj-$(CONFIG_I2C_MUX) += i2c-mux.o
+obj-$(CONFIG_I2C_ATR) += i2c-atr.o
obj-y += algos/ busses/ muxes/
obj-$(CONFIG_I2C_STUB) += i2c-stub.o
obj-$(CONFIG_I2C_SLAVE_EEPROM) += i2c-slave-eeprom.o
diff --git a/drivers/i2c/i2c-atr.c b/drivers/i2c/i2c-atr.c
new file mode 100644
index 000000000000..699446be1e90
--- /dev/null
+++ b/drivers/i2c/i2c-atr.c
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: GPL-2.0
+/**
+ * I2C Address Translator
+ *
+ * Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net>
+ *
+ * An I2C Address Translator (ATR) is a device with an I2C slave parent
+ * ("upstream") port and N I2C master child ("downstream") ports, and
+ * forwards transactions from upstream to the appropriate downstream port
+ * with a modified slave address. The address used on the parent bus is
+ * called the "alias" and is (potentially) different from the physical
+ * slave address of the child bus. Address translation is done by the
+ * hardware.
+ *
+ * An ATR looks similar to an i2c-mux except:
+ * - the address on the parent and child busses can be different
+ * - there is normally no need to select the child port; the alias used on
+ * the parent bus implies it
+ *
+ * The ATR functionality can be provided by a chip with many other
+ * features. This file provides a helper to implement an ATR within your
+ * driver.
+ *
+ * The ATR creates a new I2C "child" adapter on each child bus. Adding
+ * devices on the child bus ends up in invoking the driver code to select
+ * an available alias. Maintaining an appropriate pool of available aliases
+ * and picking one for each new device is up to the driver implementer. The
+ * ATR maintains an table of currently assigned alias and uses it to modify
+ * all I2C transactions directed to devices on the child buses.
+ *
+ * A typical example follows.
+ *
+ * Topology:
+ *
+ * Slave X @ 0x10
+ * .-----. |
+ * .-----. | |---+---- B
+ * | CPU |--A--| ATR |
+ * `-----' | |---+---- C
+ * `-----' |
+ * Slave Y @ 0x10
+ *
+ * Alias table:
+ *
+ * Client Alias
+ * -------------
+ * X 0x20
+ * Y 0x30
+ *
+ * Transaction:
+ *
+ * - Slave X driver sends a transaction (on adapter B), slave address 0x10
+ * - ATR driver rewrites messages with address 0x20, forwards to adapter A
+ * - Physical I2C transaction on bus A, slave address 0x20
+ * - ATR chip propagates transaction on bus B with address translated to 0x10
+ * - Slave X chip replies on bus B
+ * - ATR chip forwards reply on bus A
+ * - ATR driver rewrites messages with address 0x10
+ * - Slave X driver gets back the msgs[], with reply and address 0x10
+ *
+ * Usage:
+ *
+ * 1. In your driver (typically in the probe function) add an ATR by
+ * calling i2c_atr_new() passing your attach/detach callbacks
+ * 2. When the attach callback is called pick an appropriate alias,
+ * configure it in your chip and return the chosen alias in the
+ * alias_id parameter
+ * 3. When the detach callback is called, deconfigure the alias from
+ * your chip and put it back in the pool for later usage
+ *
+ * Originally based on i2c-mux.c
+ */
+
+#include <linux/i2c.h>
+#include <linux/i2c-atr.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+/**
+ * struct i2c_atr_cli2alias_pair - Hold the alias assigned to a client.
+ * @node: List node
+ * @client: Pointer to the client on the child bus
+ * @alias: I2C alias address assigned by the driver.
+ * This is the address that will be used to issue I2C transactions
+ * on the parent (physical) bus.
+ */
+struct i2c_atr_cli2alias_pair {
+ struct list_head node;
+ const struct i2c_client *client;
+ u16 alias;
+};
+
+/*
+ * Data for each channel (child bus)
+ */
+struct i2c_atr_chan {
+ struct i2c_adapter adap;
+ struct i2c_atr *atr;
+ u32 chan_id;
+
+ struct list_head alias_list;
+
+ u16 *orig_addrs;
+ unsigned int orig_addrs_size;
+ struct mutex orig_addrs_lock; /* Lock orig_addrs during xfer */
+};
+
+static struct i2c_atr_cli2alias_pair *
+i2c_atr_find_mapping_by_client(struct list_head *list,
+ const struct i2c_client *client)
+{
+ struct i2c_atr_cli2alias_pair *c2a;
+
+ list_for_each_entry(c2a, list, node) {
+ if (c2a->client == client)
+ return c2a;
+ }
+
+ return NULL;
+}
+
+static struct i2c_atr_cli2alias_pair *
+i2c_atr_find_mapping_by_addr(struct list_head *list,
+ u16 phys_addr)
+{
+ struct i2c_atr_cli2alias_pair *c2a;
+
+ list_for_each_entry(c2a, list, node) {
+ if (c2a->client->addr == phys_addr)
+ return c2a;
+ }
+
+ return NULL;
+}
+
+/*
+ * Replace all message addresses with their aliases, saving the original
+ * addresses.
+ *
+ * This function is internal for use in i2c_atr_master_xfer(). It must be
+ * followed by i2c_atr_unmap_msgs() to restore the original addresses.
+ */
+static int i2c_atr_map_msgs(struct i2c_atr_chan *chan,
+ struct i2c_msg msgs[], int num)
+
+{
+ struct i2c_atr *atr = chan->atr;
+ static struct i2c_atr_cli2alias_pair *c2a;
+ int i;
+
+ /* Ensure we have enough room to save the original addresses */
+ if (unlikely(chan->orig_addrs_size < num)) {
+ void *new_buf = kmalloc(num * sizeof(chan->orig_addrs[0]),
+ GFP_KERNEL);
+ if (new_buf == NULL)
+ return -ENOMEM;
+
+ kfree(chan->orig_addrs);
+ chan->orig_addrs = new_buf;
+ chan->orig_addrs_size = num;
+ }
+
+ for (i = 0; i < num; i++) {
+ chan->orig_addrs[i] = msgs[i].addr;
+
+ c2a = i2c_atr_find_mapping_by_addr(&chan->alias_list,
+ msgs[i].addr);
+ if (c2a) {
+ msgs[i].addr = c2a->alias;
+ } else {
+ dev_err(atr->dev, "client 0x%02x not mapped!\n",
+ msgs[i].addr);
+ return -ENXIO;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Restore all message address aliases with the original addresses.
+ *
+ * This function is internal for use in i2c_atr_master_xfer().
+ *
+ * @see i2c_atr_map_msgs()
+ */
+static void i2c_atr_unmap_msgs(struct i2c_atr_chan *chan,
+ struct i2c_msg msgs[], int num)
+{
+ int i;
+
+ for (i = 0; i < num; i++)
+ msgs[i].addr = chan->orig_addrs[i];
+}
+
+static int i2c_atr_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg msgs[], int num)
+{
+ struct i2c_atr_chan *chan = adap->algo_data;
+ struct i2c_atr *atr = chan->atr;
+ struct i2c_adapter *parent = atr->parent;
+ int ret = 0;
+
+ /* Switch to the right atr port */
+ if (atr->ops->select) {
+ ret = atr->ops->select(atr, chan->chan_id);
+ if (ret < 0)
+ goto out;
+ }
+
+ /* Translate addresses */
+ mutex_lock(&chan->orig_addrs_lock);
+ ret = i2c_atr_map_msgs(chan, msgs, num);
+ if (ret < 0) {
+ mutex_unlock(&chan->orig_addrs_lock);
+ goto out;
+ }
+
+ /* Perform the transfer */
+ ret = i2c_transfer(parent, msgs, num);
+
+ /* Restore addresses */
+ i2c_atr_unmap_msgs(chan, msgs, num);
+ mutex_unlock(&chan->orig_addrs_lock);
+
+out:
+ if (atr->ops->deselect)
+ atr->ops->deselect(atr, chan->chan_id);
+
+ return ret;
+}
+
+static int i2c_atr_smbus_xfer(struct i2c_adapter *adap,
+ u16 addr, unsigned short flags,
+ char read_write, u8 command,
+ int size, union i2c_smbus_data *data)
+{
+ struct i2c_atr_chan *chan = adap->algo_data;
+ struct i2c_atr *atr = chan->atr;
+ struct i2c_adapter *parent = atr->parent;
+ struct i2c_atr_cli2alias_pair *c2a;
+ int err = 0;
+
+ c2a = i2c_atr_find_mapping_by_addr(&chan->alias_list, addr);
+ if (!c2a) {
+ dev_err(atr->dev, "client 0x%02x not mapped!\n", addr);
+ return -ENXIO;
+ }
+
+ if (atr->ops->select)
+ err = atr->ops->select(atr, chan->chan_id);
+ if (!err)
+ err = i2c_smbus_xfer(parent, c2a->alias, flags,
+ read_write, command, size, data);
+ if (atr->ops->deselect)
+ atr->ops->deselect(atr, chan->chan_id);
+
+ return err;
+}
+
+static u32 i2c_atr_functionality(struct i2c_adapter *adap)
+{
+ struct i2c_atr_chan *chan = adap->algo_data;
+ struct i2c_adapter *parent = chan->atr->parent;
+
+ return parent->algo->functionality(parent);
+}
+
+static void i2c_atr_lock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+ struct i2c_atr_chan *chan = adapter->algo_data;
+ struct i2c_atr *atr = chan->atr;
+
+ mutex_lock(&atr->lock);
+}
+
+static int i2c_atr_trylock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+ struct i2c_atr_chan *chan = adapter->algo_data;
+ struct i2c_atr *atr = chan->atr;
+
+ return mutex_trylock(&atr->lock);
+}
+
+static void i2c_atr_unlock_bus(struct i2c_adapter *adapter, unsigned int flags)
+{
+ struct i2c_atr_chan *chan = adapter->algo_data;
+ struct i2c_atr *atr = chan->atr;
+
+ mutex_unlock(&atr->lock);
+}
+
+static const struct i2c_lock_operations i2c_atr_lock_ops = {
+ .lock_bus = i2c_atr_lock_bus,
+ .trylock_bus = i2c_atr_trylock_bus,
+ .unlock_bus = i2c_atr_unlock_bus,
+};
+
+static int i2c_atr_attach_client(struct i2c_adapter *adapter,
+ const struct i2c_board_info *info,
+ const struct i2c_client *client)
+{
+ struct i2c_atr_chan *chan = adapter->algo_data;
+ struct i2c_atr *atr = chan->atr;
+ struct i2c_atr_cli2alias_pair *c2a;
+ u16 alias_id = 0;
+ int err = 0;
+
+ c2a = kzalloc(sizeof(struct i2c_atr_cli2alias_pair), GFP_KERNEL);
+ if (!c2a) {
+ err = -ENOMEM;
+ goto err_alloc;
+ }
+
+ err = atr->ops->attach_client(atr, chan->chan_id, info, client,
+ &alias_id);
+ if (err)
+ goto err_attach;
+ if (alias_id == 0) {
+ err = -EINVAL;
+ goto err_attach;
+ }
+
+ c2a->client = client;
+ c2a->alias = alias_id;
+ list_add(&c2a->node, &chan->alias_list);
+
+ return 0;
+
+err_attach:
+ kfree(c2a);
+err_alloc:
+ return err;
+}
+
+static void i2c_atr_detach_client(struct i2c_adapter *adapter,
+ const struct i2c_client *client)
+{
+ struct i2c_atr_chan *chan = adapter->algo_data;
+ struct i2c_atr *atr = chan->atr;
+ struct i2c_atr_cli2alias_pair *c2a;
+
+ atr->ops->detach_client(atr, chan->chan_id, client);
+
+ c2a = i2c_atr_find_mapping_by_client(&chan->alias_list, client);
+ if (c2a != NULL) {
+ list_del(&c2a->node);
+ kfree(c2a);
+ }
+}
+
+static const struct i2c_attach_operations i2c_atr_attach_ops = {
+ .attach_client = i2c_atr_attach_client,
+ .detach_client = i2c_atr_detach_client,
+};
+
+/**
+ * i2c_atr_add_adapter - Create a child ("downstream") I2C bus.
+ * @atr: The I2C ATR
+ * @chan_id: Index of the new adapter (0 .. max_adapters-1). This value is
+ * passed to the callbacks in `struct i2c_atr_ops`.
+ *
+ * After calling this function a new i2c bus will appear. Adding and
+ * removing devices on the downstream bus will result in calls to the
+ * `attach_client` and `detach_client` callbacks for the driver to assign
+ * an alias to the device.
+ *
+ * If there is a device tree node under "i2c-atr" whose "reg" property
+ * equals chan_id, the new adapter will receive that node and perhaps start
+ * adding devices under it. The callbacks for those additions will be made
+ * before i2c_atr_add_adapter() returns.
+ *
+ * Call i2c_atr_del_adapter() to remove the adapter.
+ *
+ * Return: 0 on success, a negative error code otherwise.
+ */
+int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id)
+{
+ struct i2c_adapter *parent = atr->parent;
+ struct device *dev = atr->dev;
+ struct i2c_atr_chan *chan;
+ char symlink_name[20];
+ int err;
+
+ if (chan_id >= atr->max_adapters)
+ return -EINVAL;
+
+ if (atr->adapter[chan_id]) {
+ dev_err(dev, "Adapter %d already present\n", chan_id);
+ return -EEXIST;
+ }
+
+ chan = kzalloc(sizeof(*chan), GFP_KERNEL);
+ if (!chan)
+ return -ENOMEM;
+
+ chan->atr = atr;
+ chan->chan_id = chan_id;
+ INIT_LIST_HEAD(&chan->alias_list);
+ mutex_init(&chan->orig_addrs_lock);
+
+ snprintf(chan->adap.name, sizeof(chan->adap.name),
+ "i2c-%d-atr-%d", i2c_adapter_id(parent), chan_id);
+ chan->adap.owner = THIS_MODULE;
+ chan->adap.algo = &atr->algo;
+ chan->adap.algo_data = chan;
+ chan->adap.dev.parent = dev;
+ chan->adap.retries = parent->retries;
+ chan->adap.timeout = parent->timeout;
+ chan->adap.quirks = parent->quirks;
+ chan->adap.lock_ops = &i2c_atr_lock_ops;
+ chan->adap.attach_ops = &i2c_atr_attach_ops;
+
+ if (dev->of_node) {
+ struct device_node *atr_node;
+ struct device_node *child;
+ u32 reg;
+
+ atr_node = of_get_child_by_name(dev->of_node, "i2c-atr");
+
+ for_each_child_of_node(atr_node, child) {
+ err = of_property_read_u32(child, "reg", &reg);
+ if (err)
+ continue;
+ if (chan_id == reg)
+ break;
+ }
+
+ chan->adap.dev.of_node = child;
+ of_node_put(atr_node);
+ }
+
+ err = i2c_add_adapter(&chan->adap);
+ if (err) {
+ dev_err(dev, "failed to add atr-adapter %u (error=%d)\n",
+ chan_id, err);
+ goto err_add_adapter;
+ }
+
+ WARN(sysfs_create_link(&chan->adap.dev.kobj, &dev->kobj, "atr_device"),
+ "can't create symlink to atr device\n");
+ snprintf(symlink_name, sizeof(symlink_name), "channel-%u", chan_id);
+ WARN(sysfs_create_link(&dev->kobj, &chan->adap.dev.kobj, symlink_name),
+ "can't create symlink for channel %u\n", chan_id);
+
+ dev_dbg(dev, "Added ATR child bus %d\n", i2c_adapter_id(&chan->adap));
+
+ atr->adapter[chan_id] = &chan->adap;
+ return 0;
+
+err_add_adapter:
+ mutex_destroy(&chan->orig_addrs_lock);
+ kfree(chan);
+ return err;
+}
+EXPORT_SYMBOL_GPL(i2c_atr_add_adapter);
+
+/**
+ * i2c_atr_del_adapter - Remove a child ("downstream") I2C bus added by
+ * i2c_atr_del_adapter().
+ * @atr: The I2C ATR
+ * @chan_id: Index of the `adapter to be removed (0 .. max_adapters-1)
+ */
+void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id)
+{
+ char symlink_name[20];
+
+ struct i2c_adapter *adap = atr->adapter[chan_id];
+ struct i2c_atr_chan *chan = adap->algo_data;
+ struct device_node *np = adap->dev.of_node;
+ struct device *dev = atr->dev;
+
+ if (atr->adapter[chan_id] == NULL) {
+ dev_err(dev, "Adapter %d does not exist\n", chan_id);
+ return;
+ }
+
+ dev_dbg(dev, "Removing ATR child bus %d\n", i2c_adapter_id(adap));
+
+ atr->adapter[chan_id] = NULL;
+
+ snprintf(symlink_name, sizeof(symlink_name),
+ "channel-%u", chan->chan_id);
+ sysfs_remove_link(&dev->kobj, symlink_name);
+ sysfs_remove_link(&chan->adap.dev.kobj, "atr_device");
+
+ i2c_del_adapter(adap);
+ of_node_put(np);
+ mutex_destroy(&chan->orig_addrs_lock);
+ kfree(chan->orig_addrs);
+ kfree(chan);
+}
+EXPORT_SYMBOL_GPL(i2c_atr_del_adapter);
+
+/**
+ * i2c_atr_new() - Allocate and initialize an I2C ATR helper.
+ * @parent: The parent (upstream) adapter
+ * @dev: The device acting as an ATR
+ * @ops: Driver-specific callbacks
+ * @max_adapters: Maximum number of child adapters
+ *
+ * The new ATR helper is connected to the parent adapter but has no child
+ * adapters. Call i2c_atr_add_adapter() to add some.
+ *
+ * Call i2c_atr_delete() to remove.
+ *
+ * Return: pointer to the new ATR helper object, or ERR_PTR
+ */
+struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev,
+ const struct i2c_atr_ops *ops, int max_adapters)
+{
+ struct i2c_atr *atr;
+
+ if (!ops || !ops->attach_client || !ops->detach_client)
+ return ERR_PTR(-EINVAL);
+
+ atr = devm_kzalloc(dev, sizeof(*atr)
+ + max_adapters * sizeof(atr->adapter[0]),
+ GFP_KERNEL);
+ if (!atr)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&atr->lock);
+
+ atr->parent = parent;
+ atr->dev = dev;
+ atr->ops = ops;
+ atr->max_adapters = max_adapters;
+
+ if (parent->algo->master_xfer)
+ atr->algo.master_xfer = i2c_atr_master_xfer;
+ if (parent->algo->smbus_xfer)
+ atr->algo.smbus_xfer = i2c_atr_smbus_xfer;
+ atr->algo.functionality = i2c_atr_functionality;
+
+ return atr;
+}
+EXPORT_SYMBOL_GPL(i2c_atr_new);
+
+/**
+ * i2c_atr_delete - Delete an I2C ATR helper.
+ * @atr: I2C ATR helper to be deleted.
+ *
+ * Precondition: all the adapters added with i2c_atr_add_adapter() mumst be
+ * removed by calling i2c_atr_del_adapter().
+ */
+void i2c_atr_delete(struct i2c_atr *atr)
+{
+ mutex_destroy(&atr->lock);
+}
+EXPORT_SYMBOL_GPL(i2c_atr_delete);
+
+MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
+MODULE_DESCRIPTION("I2C Address Translator");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c
index bdce6d3e5327..7fab4214dc93 100644
--- a/drivers/i2c/i2c-core-base.c
+++ b/drivers/i2c/i2c-core-base.c
@@ -921,15 +921,23 @@ i2c_new_client_device(struct i2c_adapter *adap, struct i2c_board_info const *inf
}
}
+ if (adap->attach_ops &&
+ adap->attach_ops->attach_client &&
+ adap->attach_ops->attach_client(adap, info, client) != 0)
+ goto out_free_props;
+
status = device_register(&client->dev);
if (status)
- goto out_free_props;
+ goto out_detach_client;
dev_dbg(&adap->dev, "client [%s] registered with bus id %s\n",
client->name, dev_name(&client->dev));
return client;
+out_detach_client:
+ if (adap->attach_ops && adap->attach_ops->detach_client)
+ adap->attach_ops->detach_client(adap, client);
out_free_props:
if (info->properties)
device_remove_properties(&client->dev);
@@ -952,9 +960,17 @@ EXPORT_SYMBOL_GPL(i2c_new_client_device);
*/
void i2c_unregister_device(struct i2c_client *client)
{
+ struct i2c_adapter *adap;
+
if (IS_ERR_OR_NULL(client))
return;
+ adap = client->adapter;
+
+ if (adap->attach_ops &&
+ adap->attach_ops->detach_client)
+ adap->attach_ops->detach_client(adap, client);
+
if (client->dev.of_node) {
of_node_clear_flag(client->dev.of_node, OF_POPULATED);
of_node_put(client->dev.of_node);
diff --git a/drivers/media/dvb-frontends/ascot2e.h b/drivers/media/dvb-frontends/ascot2e.h
index f886fab1283f..d86b3de85c6a 100644
--- a/drivers/media/dvb-frontends/ascot2e.h
+++ b/drivers/media/dvb-frontends/ascot2e.h
@@ -33,7 +33,7 @@ struct ascot2e_config {
#if IS_REACHABLE(CONFIG_DVB_ASCOT2E)
/**
- * Attach an ascot2e tuner
+ * ascot2e_attach - Attach an ascot2e tuner
*
* @fe: frontend to be attached
* @config: pointer to &struct ascot2e_config with tuner configuration.
diff --git a/drivers/media/dvb-frontends/cxd2820r.h b/drivers/media/dvb-frontends/cxd2820r.h
index a28b8754932b..4aa6cf4fb913 100644
--- a/drivers/media/dvb-frontends/cxd2820r.h
+++ b/drivers/media/dvb-frontends/cxd2820r.h
@@ -96,7 +96,7 @@ struct cxd2820r_config {
#if IS_REACHABLE(CONFIG_DVB_CXD2820R)
/**
- * Attach a cxd2820r demod
+ * cxd2820r_attach - Attach a cxd2820r demod
*
* @config: pointer to &struct cxd2820r_config with demod configuration.
* @i2c: i2c adapter to use.
diff --git a/drivers/media/dvb-frontends/drxk.h b/drivers/media/dvb-frontends/drxk.h
index ee06e89187e4..69fdca00f364 100644
--- a/drivers/media/dvb-frontends/drxk.h
+++ b/drivers/media/dvb-frontends/drxk.h
@@ -54,7 +54,7 @@ struct drxk_config {
#if IS_REACHABLE(CONFIG_DVB_DRXK)
/**
- * Attach a drxk demod
+ * drxk_attach - Attach a drxk demod
*
* @config: pointer to &struct drxk_config with demod configuration.
* @i2c: i2c adapter to use.
diff --git a/drivers/media/dvb-frontends/dvb-pll.h b/drivers/media/dvb-frontends/dvb-pll.h
index 973a66a82e27..71838888743b 100644
--- a/drivers/media/dvb-frontends/dvb-pll.h
+++ b/drivers/media/dvb-frontends/dvb-pll.h
@@ -38,7 +38,7 @@ struct dvb_pll_config {
#if IS_REACHABLE(CONFIG_DVB_PLL)
/**
- * Attach a dvb-pll to the supplied frontend structure.
+ * dvb_pll_attach - Attach a dvb-pll to the supplied frontend structure.
*
* @fe: Frontend to attach to.
* @pll_addr: i2c address of the PLL (if used).
diff --git a/drivers/media/dvb-frontends/helene.h b/drivers/media/dvb-frontends/helene.h
index c026bdcf548d..32e0b1fb268c 100644
--- a/drivers/media/dvb-frontends/helene.h
+++ b/drivers/media/dvb-frontends/helene.h
@@ -44,7 +44,7 @@ struct helene_config {
#if IS_REACHABLE(CONFIG_DVB_HELENE)
/**
- * Attach a helene tuner (terrestrial and cable standards)
+ * helene_attach - Attach a helene tuner (terrestrial and cable standards)
*
* @fe: frontend to be attached
* @config: pointer to &struct helene_config with tuner configuration.
@@ -57,7 +57,7 @@ extern struct dvb_frontend *helene_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c);
/**
- * Attach a helene tuner (satellite standards)
+ * helene_attach_s - Attach a helene tuner (satellite standards)
*
* @fe: frontend to be attached
* @config: pointer to &struct helene_config with tuner configuration.
diff --git a/drivers/media/dvb-frontends/horus3a.h b/drivers/media/dvb-frontends/horus3a.h
index 366c399e3329..91dbe20169cd 100644
--- a/drivers/media/dvb-frontends/horus3a.h
+++ b/drivers/media/dvb-frontends/horus3a.h
@@ -33,7 +33,7 @@ struct horus3a_config {
#if IS_REACHABLE(CONFIG_DVB_HORUS3A)
/**
- * Attach a horus3a tuner
+ * horus3a_attach - Attach a horus3a tuner
*
* @fe: frontend to be attached
* @config: pointer to &struct helene_config with tuner configuration.
diff --git a/drivers/media/dvb-frontends/ix2505v.h b/drivers/media/dvb-frontends/ix2505v.h
index 671c0e0959f7..175569131365 100644
--- a/drivers/media/dvb-frontends/ix2505v.h
+++ b/drivers/media/dvb-frontends/ix2505v.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/**
+/*
* Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
*
* Copyright (C) 2010 Malcolm Priestley
@@ -31,7 +31,7 @@ struct ix2505v_config {
#if IS_REACHABLE(CONFIG_DVB_IX2505V)
/**
- * Attach a ix2505v tuner to the supplied frontend structure.
+ * ix2505v_attach - Attach a ix2505v tuner to the supplied frontend structure.
*
* @fe: Frontend to attach to.
* @config: pointer to &struct ix2505v_config
diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h
index 46b722495e4c..e32b68c0df70 100644
--- a/drivers/media/dvb-frontends/m88ds3103.h
+++ b/drivers/media/dvb-frontends/m88ds3103.h
@@ -128,7 +128,7 @@ struct m88ds3103_config {
#if defined(CONFIG_DVB_M88DS3103) || \
(defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
/**
- * Attach a m88ds3103 demod
+ * m88ds3103_attach - Attach a m88ds3103 demod
*
* @config: pointer to &struct m88ds3103_config with demod configuration.
* @i2c: i2c adapter to use.
diff --git a/drivers/media/dvb-frontends/mb86a20s.h b/drivers/media/dvb-frontends/mb86a20s.h
index 00a6b6e9b5e4..d20d22bf7580 100644
--- a/drivers/media/dvb-frontends/mb86a20s.h
+++ b/drivers/media/dvb-frontends/mb86a20s.h
@@ -26,7 +26,7 @@ struct mb86a20s_config {
#if IS_REACHABLE(CONFIG_DVB_MB86A20S)
/**
- * Attach a mb86a20s demod
+ * mb86a20s_attach - Attach a mb86a20s demod
*
* @config: pointer to &struct mb86a20s_config with demod configuration.
* @i2c: i2c adapter to use.
diff --git a/drivers/media/dvb-frontends/stb6000.h b/drivers/media/dvb-frontends/stb6000.h
index 570a4b1d07d6..38da55af7ea9 100644
--- a/drivers/media/dvb-frontends/stb6000.h
+++ b/drivers/media/dvb-frontends/stb6000.h
@@ -15,7 +15,7 @@
#if IS_REACHABLE(CONFIG_DVB_STB6000)
/**
- * Attach a stb6000 tuner to the supplied frontend structure.
+ * stb6000_attach - Attach a stb6000 tuner to the supplied frontend structure.
*
* @fe: Frontend to attach to.
* @addr: i2c address of the tuner.
diff --git a/drivers/media/dvb-frontends/tda826x.h b/drivers/media/dvb-frontends/tda826x.h
index bb575a251b04..e1d33edbb8ec 100644
--- a/drivers/media/dvb-frontends/tda826x.h
+++ b/drivers/media/dvb-frontends/tda826x.h
@@ -14,7 +14,7 @@
#include <media/dvb_frontend.h>
/**
- * Attach a tda826x tuner to the supplied frontend structure.
+ * tda826x_attach - Attach a tda826x tuner to the supplied frontend structure.
*
* @fe: Frontend to attach to.
* @addr: i2c address of the tuner.
diff --git a/drivers/media/dvb-frontends/zl10036.h b/drivers/media/dvb-frontends/zl10036.h
index 91eea777eaf1..ad83e6344e7f 100644
--- a/drivers/media/dvb-frontends/zl10036.h
+++ b/drivers/media/dvb-frontends/zl10036.h
@@ -1,5 +1,5 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/**
+/*
* Driver for Zarlink ZL10036 DVB-S silicon tuner
*
* Copyright (C) 2006 Tino Reichardt
@@ -19,7 +19,7 @@ struct zl10036_config {
#if IS_REACHABLE(CONFIG_DVB_ZL10036)
/**
- * Attach a zl10036 tuner to the supplied frontend structure.
+ * zl10036_attach - Attach a zl10036 tuner to the supplied frontend structure.
*
* @fe: Frontend to attach to.
* @config: zl10036_config structure.
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index edd79d2bf28a..8f86b43b3e78 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -825,6 +825,18 @@ config VIDEO_IMX355
To compile this driver as a module, choose M here: the
module will be called imx355.
+config VIDEO_IMX390
+ tristate "Sony IMX390 sensor support"
+ depends on I2C && VIDEO_V4L2
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This is a Video4Linux2 sensor driver for the Sony
+ IMX390 camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx390.
+
config VIDEO_OV2640
tristate "OmniVision OV2640 sensor support"
depends on VIDEO_V4L2 && I2C
@@ -1347,4 +1359,26 @@ config VIDEO_LM3646
flash, torch LEDs.
endmenu
+#
+# Video serializers and deserializers (e.g. FPDLink)
+#
+
+menu "Video serializers and deserializers"
+
+config VIDEO_DS90UB953
+ tristate "TI DS90UB953 Serializer"
+ help
+ Device driver for the Texas Instruments DS90UB953
+ FPD-Link III Serializer.
+
+config VIDEO_DS90UB960
+ tristate "TI DS90UB960 Deserializer"
+ depends on OF_GPIO
+ select I2C_ATR
+ help
+ Device driver for the Texas Instruments DS90UB960
+ FPD-Link III Deserializer
+
+endmenu
+
endif # VIDEO_V4L2
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 8577522bd553..469f0f0d44d2 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -120,9 +120,12 @@ obj-$(CONFIG_VIDEO_IMX274) += imx274.o
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
obj-$(CONFIG_VIDEO_IMX355) += imx355.o
+obj-$(CONFIG_VIDEO_IMX390) += imx390.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
rdacm20-camera_module-objs := rdacm20.o max9271.o
obj-$(CONFIG_VIDEO_RDACM20) += rdacm20-camera_module.o
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
obj-$(CONFIG_SDR_MAX2175) += max2175.o
+obj-$(CONFIG_VIDEO_DS90UB953) += ds90ub953.o
+obj-$(CONFIG_VIDEO_DS90UB960) += ds90ub960.o
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c
new file mode 100644
index 000000000000..4b51117bbec4
--- /dev/null
+++ b/drivers/media/i2c/ds90ub953.c
@@ -0,0 +1,1006 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the Texas Instruments DS90UB953 video serializer
+ *
+ * Based on a driver from Luca Ceresoli <luca@lucaceresoli.net>
+ *
+ * Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net>
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_graph.h>
+#include <linux/regmap.h>
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#define UB953_PAD_SINK 0
+#define UB953_PAD_SOURCE 1
+
+#define UB953_NUM_GPIOS 4
+
+#define UB953_REG_RESET_CTL 0x01
+#define UB953_REG_RESET_CTL_DIGITAL_RESET_1 BIT(1)
+#define UB953_REG_RESET_CTL_DIGITAL_RESET_0 BIT(0)
+
+#define UB953_REG_GENERAL_CFG 0x02
+#define UB953_REG_MODE_SEL 0x03
+
+#define UB953_REG_CLKOUT_CTRL0 0x06
+#define UB953_REG_CLKOUT_CTRL1 0x07
+
+#define UB953_REG_SCL_HIGH_TIME 0x0B
+#define UB953_REG_SCL_LOW_TIME 0x0C
+
+#define UB953_REG_LOCAL_GPIO_DATA 0x0d
+#define UB953_REG_LOCAL_GPIO_DATA_GPIO_RMTEN(n) BIT(4 + (n))
+#define UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(n) BIT(0 + (n))
+
+#define UB953_REG_GPIO_INPUT_CTRL 0x0e
+#define UB953_REG_GPIO_INPUT_CTRL_OUT_EN(n) BIT(4 + (n))
+#define UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(n) BIT(0 + (n))
+
+#define UB953_REG_REV_MASK_ID 0x50
+
+#define UB953_REG_GPIO_PIN_STS 0x53
+#define UB953_REG_GPIO_PIN_STS_GPIO_STS(n) BIT(0 + (n))
+
+#define UB953_REG_IND_ACC_CTL 0xb0
+#define UB953_REG_IND_ACC_CTL_IA_AUTO_INC BIT(1)
+#define UB953_REG_IND_ACC_CTL_IA_SEL_MASK GENMASK(4, 2)
+#define UB953_REG_IND_ACC_ADDR 0xb1
+#define UB953_REG_IND_ACC_DATA 0xb2
+
+#define UB953_IND_PGEN_CTL 0x01
+#define UB953_IND_PGEN_CTL_PGEN_ENABLE BIT(0)
+#define UB953_IND_PGEN_CFG 0x02
+#define UB953_IND_PGEN_CSI_DI 0x03
+#define UB953_IND_PGEN_LINE_SIZE1 0x04
+#define UB953_IND_PGEN_LINE_SIZE0 0x05
+#define UB953_IND_PGEN_BAR_SIZE1 0x06
+#define UB953_IND_PGEN_BAR_SIZE0 0x07
+#define UB953_IND_PGEN_ACT_LPF1 0x08
+#define UB953_IND_PGEN_ACT_LPF0 0x09
+#define UB953_IND_PGEN_TOT_LPF1 0x0A
+#define UB953_IND_PGEN_TOT_LPF0 0x0B
+#define UB953_IND_PGEN_LINE_PD1 0x0C
+#define UB953_IND_PGEN_LINE_PD0 0x0D
+#define UB953_IND_PGEN_VBP 0x0E
+#define UB953_IND_PGEN_VFP 0x0F
+#define UB953_IND_PGEN_COLOR(n) (0x10 + (n)) /* n <= 15 */
+
+struct ub953_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+
+ u32 gpio_func[UB953_NUM_GPIOS];
+
+ struct gpio_chip gpio_chip;
+ char gpio_chip_name[64];
+
+ struct v4l2_subdev sd;
+ struct media_pad pads[2];
+
+ struct v4l2_async_notifier notifier;
+
+ struct v4l2_subdev *source_sd;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+
+ bool streaming;
+
+ struct device_node *tx_ep_np;
+};
+
+static inline struct ub953_data *sd_to_ub953(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ub953_data, sd);
+}
+
+/*
+ * HW Access
+ */
+
+static int ub953_read(const struct ub953_data *priv, u8 reg, u8 *val)
+{
+ unsigned int v;
+ int ret;
+
+ ret = regmap_read(priv->regmap, reg, &v);
+ if (ret < 0) {
+ dev_err(&priv->client->dev,
+ "Cannot read register 0x%02x: %d!\n", reg, ret);
+ return ret;
+ }
+
+ *val = v;
+ return 0;
+}
+
+static int ub953_write(const struct ub953_data *priv, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = regmap_write(priv->regmap, reg, val);
+ if (ret < 0)
+ dev_err(&priv->client->dev,
+ "Cannot write register 0x%02x: %d!\n", reg, ret);
+
+ return ret;
+}
+
+static int ub953_write_ind8(const struct ub953_data *priv, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = ub953_write(priv, UB953_REG_IND_ACC_ADDR, reg);
+ if (!ret)
+ ret = ub953_write(priv, UB953_REG_IND_ACC_DATA, val);
+ return ret;
+}
+
+/* Assumes IA_AUTO_INC is set in UB953_REG_IND_ACC_CTL */
+static int ub953_write_ind16(const struct ub953_data *priv, u8 reg, u16 val)
+{
+ int ret;
+
+ ret = ub953_write(priv, UB953_REG_IND_ACC_ADDR, reg);
+ if (!ret)
+ ret = ub953_write(priv, UB953_REG_IND_ACC_DATA, val >> 8);
+ if (!ret)
+ ret = ub953_write(priv, UB953_REG_IND_ACC_DATA, val & 0xff);
+ return ret;
+}
+
+/*
+ * GPIO chip
+ */
+static int ub953_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ub953_data *priv = gpiochip_get_data(gc);
+ int ret;
+ u8 v;
+
+ ret = ub953_read(priv, UB953_REG_GPIO_INPUT_CTRL, &v);
+ if (ret)
+ return ret;
+
+ if (v & UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(offset))
+ return GPIO_LINE_DIRECTION_IN;
+ else
+ return GPIO_LINE_DIRECTION_OUT;
+}
+
+static int ub953_gpio_direction_in(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ub953_data *priv = gpiochip_get_data(gc);
+
+ return regmap_update_bits(
+ priv->regmap, UB953_REG_GPIO_INPUT_CTRL,
+ UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(offset) |
+ UB953_REG_GPIO_INPUT_CTRL_OUT_EN(offset),
+ UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(offset));
+}
+
+static int ub953_gpio_direction_out(struct gpio_chip *gc, unsigned int offset,
+ int value)
+{
+ struct ub953_data *priv = gpiochip_get_data(gc);
+ int ret;
+
+ ret = regmap_update_bits(
+ priv->regmap, UB953_REG_LOCAL_GPIO_DATA,
+ UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset),
+ value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : 0);
+
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(
+ priv->regmap, UB953_REG_GPIO_INPUT_CTRL,
+ UB953_REG_GPIO_INPUT_CTRL_INPUT_EN(offset) |
+ UB953_REG_GPIO_INPUT_CTRL_OUT_EN(offset),
+ UB953_REG_GPIO_INPUT_CTRL_OUT_EN(offset));
+}
+
+static int ub953_gpio_get(struct gpio_chip *gc, unsigned int offset)
+{
+ struct ub953_data *priv = gpiochip_get_data(gc);
+ int ret;
+ u8 v;
+
+ ret = ub953_read(priv, UB953_REG_GPIO_PIN_STS, &v);
+ if (ret)
+ return ret;
+
+ return !!(v & UB953_REG_GPIO_PIN_STS_GPIO_STS(offset));
+}
+
+static void ub953_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
+{
+ struct ub953_data *priv = gpiochip_get_data(gc);
+
+ regmap_update_bits(
+ priv->regmap, UB953_REG_LOCAL_GPIO_DATA,
+ UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset),
+ value ? UB953_REG_LOCAL_GPIO_DATA_GPIO_OUT_SRC(offset) : 0);
+}
+
+static int ub953_gpio_of_xlate(struct gpio_chip *gc,
+ const struct of_phandle_args *gpiospec,
+ u32 *flags)
+{
+ if (flags)
+ *flags = gpiospec->args[1];
+
+ return gpiospec->args[0];
+}
+
+static int ub953_gpiochip_probe(struct ub953_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct gpio_chip *gc = &priv->gpio_chip;
+ int ret;
+
+ /* Set all GPIOs to local mode */
+ ub953_write(priv, UB953_REG_LOCAL_GPIO_DATA, 0);
+
+ scnprintf(priv->gpio_chip_name, sizeof(priv->gpio_chip_name), "%s",
+ dev_name(dev));
+
+ gc->label = priv->gpio_chip_name;
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+ gc->base = -1;
+ gc->can_sleep = 1;
+ gc->ngpio = UB953_NUM_GPIOS;
+ gc->get_direction = ub953_gpio_get_direction;
+ gc->direction_input = ub953_gpio_direction_in;
+ gc->direction_output = ub953_gpio_direction_out;
+ gc->get = ub953_gpio_get;
+ gc->set = ub953_gpio_set;
+ gc->of_xlate = ub953_gpio_of_xlate;
+ gc->of_node = priv->client->dev.of_node;
+ gc->of_gpio_n_cells = 2;
+
+ ret = gpiochip_add_data(gc, priv);
+ if (ret) {
+ dev_err(dev, "Failed to add GPIOs: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ub953_gpiochip_remove(struct ub953_data *priv)
+{
+ gpiochip_remove(&priv->gpio_chip);
+}
+
+/*
+ * V4L2
+ */
+
+static int ub953_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ub953_data *priv = sd_to_ub953(sd);
+ int ret;
+
+ priv->streaming = enable;
+
+ ret = v4l2_subdev_call(priv->source_sd, video, s_stream, enable);
+ if (ret && enable)
+ priv->streaming = false;
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops ub953_video_ops = {
+ .s_stream = ub953_s_stream,
+};
+
+static int _ub953_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing)
+{
+ const struct v4l2_mbus_framefmt format = {
+ .width = 640,
+ .height = 480,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_YCBCR_ENC_601,
+ .quantization = V4L2_QUANTIZATION_LIM_RANGE,
+ .xfer_func = V4L2_XFER_FUNC_SRGB,
+ };
+ int ret;
+
+ /*
+ * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
+ * frame desc is made dynamically allocated.
+ */
+
+ if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+ return -EINVAL;
+
+ ret = v4l2_routing_simple_verify(routing);
+ if (ret)
+ return ret;
+
+ v4l2_subdev_lock_state(state);
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+
+ v4l2_subdev_unlock_state(state);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+
+static int ub953_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct ub953_data *priv = sd_to_ub953(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming)
+ return -EBUSY;
+
+ return _ub953_set_routing(sd, state, routing);
+}
+
+static int ub953_get_source_frame_desc(struct ub953_data *priv,
+ struct v4l2_mbus_frame_desc *desc)
+{
+ struct media_pad *pad;
+ int ret;
+
+ pad = media_entity_remote_pad(&priv->pads[UB953_PAD_SINK]);
+ if (!pad)
+ return -EPIPE;
+
+ ret = v4l2_subdev_call(priv->source_sd, pad, get_frame_desc, pad->index,
+ desc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ub953_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct ub953_data *priv = sd_to_ub953(sd);
+ const struct v4l2_subdev_krouting *routing;
+ struct v4l2_mbus_frame_desc source_fd;
+ struct v4l2_subdev_state *state;
+ unsigned int i;
+ int ret = 0;
+
+ if (pad != 1) /* first tx pad */
+ return -EINVAL;
+
+ ret = ub953_get_source_frame_desc(priv, &source_fd);
+ if (ret)
+ return ret;
+
+ state = v4l2_subdev_lock_active_state(sd);
+
+ routing = &state->routing;
+
+ memset(fd, 0, sizeof(*fd));
+
+ fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routing->routes[i];
+ struct v4l2_mbus_frame_desc_entry *source_entry = NULL;
+ unsigned int j;
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ if (route->source_pad != pad)
+ continue;
+
+ for (j = 0; j < source_fd.num_entries; ++j)
+ if (source_fd.entry[j].stream == route->sink_stream) {
+ source_entry = &source_fd.entry[j];
+ break;
+ }
+
+ if (!source_entry) {
+ dev_err(&priv->client->dev,
+ "Failed to find stream from source frame desc\n");
+ ret = -EPIPE;
+ goto out;
+ }
+
+ fd->entry[fd->num_entries].stream = route->source_stream;
+
+ fd->entry[fd->num_entries].flags =
+ V4L2_MBUS_FRAME_DESC_FL_LEN_MAX;
+ fd->entry[fd->num_entries].length = source_entry->length;
+ fd->entry[fd->num_entries].pixelcode = source_entry->pixelcode;
+ fd->entry[fd->num_entries].bus.csi2.vc =
+ source_entry->bus.csi2.vc;
+ fd->entry[fd->num_entries].bus.csi2.dt =
+ source_entry->bus.csi2.dt;
+
+ fd->num_entries++;
+ }
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int ub953_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct ub953_data *priv = sd_to_ub953(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ int ret = 0;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming)
+ return -EBUSY;
+
+ /* No transcoding, source and sink formats must match. */
+ if (format->pad == 1)
+ return v4l2_subdev_get_fmt(sd, state, format);
+
+ v4l2_subdev_lock_state(state);
+
+ /* Set sink format */
+ fmt = v4l2_state_get_stream_format(state, format->pad, format->stream);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *fmt = format->format;
+
+ /* Propagate to source format */
+ fmt = v4l2_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *fmt = format->format;
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int ub953_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = 0,
+ .sink_stream = 0,
+ .source_pad = 1,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ };
+
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ return _ub953_set_routing(sd, state, &routing);
+}
+
+static const struct v4l2_subdev_pad_ops ub953_pad_ops = {
+ .set_routing = ub953_set_routing,
+ .get_frame_desc = ub953_get_frame_desc,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = ub953_set_fmt,
+ .init_cfg = ub953_init_cfg,
+};
+
+static const struct v4l2_subdev_ops ub953_subdev_ops = {
+ .video = &ub953_video_ops,
+ .pad = &ub953_pad_ops,
+};
+
+static const struct media_entity_operations ub953_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+enum {
+ TEST_PATTERN_DISABLED = 0,
+ TEST_PATTERN_V_COLOR_BARS_1,
+ TEST_PATTERN_V_COLOR_BARS_2,
+ TEST_PATTERN_V_COLOR_BARS_4,
+ TEST_PATTERN_V_COLOR_BARS_8,
+};
+
+static const char *const ub953_tpg_qmenu[] = {
+ "Disabled",
+ "1 vertical color bar",
+ "2 vertical color bars",
+ "4 vertical color bars",
+ "8 vertical color bars",
+};
+
+static void ub953_enable_tpg(struct ub953_data *priv, int tpg_num)
+{
+ struct v4l2_subdev *sd = &priv->sd;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *fmt;
+ u8 vbp, vfp;
+ u16 blank_lines;
+ u16 width;
+ u16 height;
+
+ u16 bytespp = 2; /* For MEDIA_BUS_FMT_UYVY8_1X16 */
+ u8 cbars_idx = tpg_num - TEST_PATTERN_V_COLOR_BARS_1;
+ u8 num_cbars = 1 << cbars_idx;
+
+ u16 line_size; /* Line size [bytes] */
+ u16 bar_size; /* cbar size [bytes] */
+ u16 act_lpf; /* active lines/frame */
+ u16 tot_lpf; /* tot lines/frame */
+ u16 line_pd; /* Line period in 10-ns units */
+
+ u16 fps = 30;
+
+ vbp = 33;
+ vfp = 10;
+ blank_lines = vbp + vfp + 2; /* total blanking lines */
+
+ state = v4l2_subdev_lock_active_state(sd);
+
+ fmt = v4l2_state_get_stream_format(state, UB953_PAD_SOURCE, 0);
+
+ width = fmt->width;
+ height = fmt->height;
+
+ line_size = width * bytespp;
+ bar_size = line_size / num_cbars;
+ act_lpf = height;
+ tot_lpf = act_lpf + blank_lines;
+ line_pd = 100000000 / fps / tot_lpf;
+
+ /* Access Indirect Pattern Gen */
+ ub953_write(priv, UB953_REG_IND_ACC_CTL,
+ UB953_REG_IND_ACC_CTL_IA_AUTO_INC | (0 << 2));
+
+ ub953_write_ind8(priv, UB953_IND_PGEN_CTL,
+ UB953_IND_PGEN_CTL_PGEN_ENABLE);
+
+ /* YUV422 8bit: 2 bytes/block, CSI-2 data type 0x1e */
+ ub953_write_ind8(priv, UB953_IND_PGEN_CFG, cbars_idx << 4 | 0x2);
+ ub953_write_ind8(priv, UB953_IND_PGEN_CSI_DI, 0x1e);
+
+ ub953_write_ind16(priv, UB953_IND_PGEN_LINE_SIZE1, line_size);
+ ub953_write_ind16(priv, UB953_IND_PGEN_BAR_SIZE1, bar_size);
+ ub953_write_ind16(priv, UB953_IND_PGEN_ACT_LPF1, act_lpf);
+ ub953_write_ind16(priv, UB953_IND_PGEN_TOT_LPF1, tot_lpf);
+ ub953_write_ind16(priv, UB953_IND_PGEN_LINE_PD1, line_pd);
+ ub953_write_ind8(priv, UB953_IND_PGEN_VBP, vbp);
+ ub953_write_ind8(priv, UB953_IND_PGEN_VFP, vfp);
+
+ v4l2_subdev_unlock_state(state);
+}
+
+static void ub953_disable_tpg(struct ub953_data *priv)
+{
+ ub953_write_ind8(priv, UB953_IND_PGEN_CTL, 0x00);
+}
+
+static int ub953_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ub953_data *priv =
+ container_of(ctrl->handler, struct ub953_data, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_TEST_PATTERN:
+ if (ctrl->val == 0)
+ ub953_disable_tpg(priv);
+ else
+ ub953_enable_tpg(priv, ctrl->val);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops ub953_ctrl_ops = {
+ .s_ctrl = ub953_s_ctrl,
+};
+
+static int ub953_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *source_subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct ub953_data *priv = sd_to_ub953(notifier->sd);
+ struct device *dev = &priv->client->dev;
+ unsigned int src_pad;
+ int ret;
+
+ dev_dbg(dev, "Bind %s\n", source_subdev->name);
+
+ ret = media_entity_get_fwnode_pad(&source_subdev->entity,
+ source_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to find pad for %s\n",
+ source_subdev->name);
+ return ret;
+ }
+
+ priv->source_sd = source_subdev;
+ src_pad = ret;
+
+ ret = media_create_pad_link(
+ &source_subdev->entity, src_pad, &priv->sd.entity, 0,
+ MEDIA_LNK_FL_ENABLED | MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "Unable to link %s:%u -> %s:0\n",
+ source_subdev->name, src_pad, priv->sd.name);
+ return ret;
+ }
+
+ dev_dbg(dev, "Bound %s:%u\n", source_subdev->name, src_pad);
+
+ dev_dbg(dev, "All subdevs bound\n");
+
+ return 0;
+}
+
+static void ub953_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *source_subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct ub953_data *priv = sd_to_ub953(notifier->sd);
+ struct device *dev = &priv->client->dev;
+
+ dev_dbg(dev, "Unbind %s\n", source_subdev->name);
+}
+
+static const struct v4l2_async_notifier_operations ub953_notify_ops = {
+ .bound = ub953_notify_bound,
+ .unbind = ub953_notify_unbind,
+};
+
+static int ub953_v4l2_notifier_register(struct ub953_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct v4l2_async_subdev *asd;
+ struct device_node *ep_node;
+ int ret;
+
+ dev_dbg(dev, "register async notif\n");
+
+ ep_node = of_graph_get_endpoint_by_regs(dev->of_node, 0, 0);
+ if (!ep_node) {
+ dev_err(dev, "No graph endpoint\n");
+ return -ENODEV;
+ }
+
+ v4l2_async_notifier_init(&priv->notifier);
+
+ asd = v4l2_async_notifier_add_fwnode_remote_subdev(
+ &priv->notifier, of_fwnode_handle(ep_node),
+ sizeof(*asd));
+
+ of_node_put(ep_node);
+
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd));
+ v4l2_async_notifier_cleanup(&priv->notifier);
+ return PTR_ERR(asd);
+ }
+
+ priv->notifier.ops = &ub953_notify_ops;
+
+ ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register subdev_notifier");
+ v4l2_async_notifier_cleanup(&priv->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ub953_v4l2_notifier_unregister(struct ub953_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ dev_dbg(dev, "Unregister async notif\n");
+
+ v4l2_async_notifier_unregister(&priv->notifier);
+ v4l2_async_notifier_cleanup(&priv->notifier);
+}
+
+/*
+ * Probing
+ */
+
+static void ub953_soft_reset(struct ub953_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+ int retries;
+
+ ub953_write(priv, UB953_REG_RESET_CTL,
+ UB953_REG_RESET_CTL_DIGITAL_RESET_1);
+
+ usleep_range(10000, 30000);
+
+ retries = 10;
+ while (retries-- > 0) {
+ int ret;
+ u8 v;
+
+ ret = ub953_read(priv, UB953_REG_RESET_CTL, &v);
+
+ if (ret >= 0 &&
+ (v & UB953_REG_RESET_CTL_DIGITAL_RESET_1) == 0) {
+ dev_dbg(dev, "reset done\n");
+ break;
+ }
+
+ usleep_range(1000, 3000);
+ }
+
+ if (retries == 0)
+ dev_err(dev, "reset timeout\n");
+}
+
+static int ub953_i2c_init(struct ub953_data *priv)
+{
+ /* i2c fast mode */
+ u32 scl_high = 915; /* ns */
+ u32 scl_low = 1641; /* ns */
+ u32 ref = 25000000; /* TODO: get refclock from deserializer */
+ int ret = 0;
+
+ scl_high = div64_u64((u64)scl_high * ref, 1000000000) - 5;
+ scl_low = div64_u64((u64)scl_low * ref, 1000000000) - 5;
+
+ ret = ub953_write(priv, UB953_REG_SCL_HIGH_TIME, scl_high);
+ if (ret)
+ return ret;
+
+ ret = ub953_write(priv, UB953_REG_SCL_LOW_TIME, scl_low);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ub953_parse_dt(struct ub953_data *priv)
+{
+ struct device_node *np = priv->client->dev.of_node;
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ if (!np) {
+ dev_err(dev, "OF: no device tree node!\n");
+ return -ENOENT;
+ }
+
+ /* optional, if absent all GPIO pins are unused */
+ ret = of_property_read_u32_array(np, "gpio-functions", priv->gpio_func,
+ ARRAY_SIZE(priv->gpio_func));
+ if (ret && ret != -EINVAL)
+ dev_err(dev, "DT: invalid gpio-functions property (%d)", ret);
+
+ return 0;
+}
+
+static const struct regmap_config ub953_regmap_config = {
+ .name = "ds90ub953",
+ .reg_bits = 8,
+ .val_bits = 8,
+ .reg_format_endian = REGMAP_ENDIAN_DEFAULT,
+ .val_format_endian = REGMAP_ENDIAN_DEFAULT,
+};
+
+static int ub953_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct ub953_data *priv;
+ int ret;
+ u8 rev;
+
+ dev_dbg(dev, "probing, addr 0x%02x\n", client->addr);
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ priv->regmap = devm_regmap_init_i2c(client, &ub953_regmap_config);
+ if (IS_ERR(priv->regmap)) {
+ dev_err(dev, "Failed to init regmap\n");
+ return PTR_ERR(priv->regmap);
+ }
+
+ ret = ub953_parse_dt(priv);
+ if (ret)
+ return ret;
+
+ ub953_soft_reset(priv);
+
+ ret = ub953_read(priv, UB953_REG_REV_MASK_ID, &rev);
+ if (ret) {
+ dev_err(dev, "Failed to read revision: %d", ret);
+ return ret;
+ }
+
+ dev_info(dev, "Found rev %u, mask %u\n", rev >> 4, rev & 0xf);
+
+ ret = ub953_i2c_init(priv);
+ if (ret) {
+ dev_err(dev, "i2c init failed: %d\n", ret);
+ return ret;
+ }
+
+ ret = ub953_gpiochip_probe(priv);
+ if (ret) {
+ dev_err(dev, "Failed to init gpiochip\n");
+ return ret;
+ }
+
+ v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub953_subdev_ops);
+
+ v4l2_ctrl_handler_init(&priv->ctrl_handler,
+ ARRAY_SIZE(ub953_tpg_qmenu) - 1);
+ priv->sd.ctrl_handler = &priv->ctrl_handler;
+
+ v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &ub953_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ub953_tpg_qmenu) - 1, 0, 0,
+ ub953_tpg_qmenu);
+
+ if (priv->ctrl_handler.error) {
+ ret = priv->ctrl_handler.error;
+ goto err_gpiochip_remove;
+ }
+
+ priv->sd.flags |=
+ V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_MULTIPLEXED;
+ priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ priv->sd.entity.ops = &ub953_entity_ops;
+
+ priv->pads[0].flags = MEDIA_PAD_FL_SINK;
+ priv->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads);
+ if (ret) {
+ dev_err(dev, "Failed to init pads\n");
+ goto err_remove_ctrls;
+ }
+
+ priv->tx_ep_np = of_graph_get_endpoint_by_regs(dev->of_node, 1, 0);
+ priv->sd.fwnode = of_fwnode_handle(priv->tx_ep_np);
+
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = ub953_v4l2_notifier_register(priv);
+ if (ret) {
+ dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret);
+ goto err_free_state;
+ }
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret) {
+ dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret);
+ goto err_unreg_notif;
+ }
+
+ /*
+ * TODO compute these hard-coded values
+ *
+ * SET CLK_OUT:
+ * MODE = 0 = CSI-2 sync (strap, reg 0x03) -> refclk from deser
+ * REFCLK = 23..26 MHz (REFCLK pin @ remote deserializer)
+ * FC = fwd channel data rate = 160 x REFCLK
+ * CLK_OUT = FC * M / (HS_CLK_DIV * N)
+ * = FC * 1 / (4 * 20) = 2 * REFCLK
+ */
+ ub953_write(priv, UB953_REG_CLKOUT_CTRL0, 0x41); /* div by 4, M=1 */
+ ub953_write(priv, UB953_REG_CLKOUT_CTRL1, 0x25); /* N */
+
+ ub953_write(priv, UB953_REG_GENERAL_CFG,
+ (1 << 6) | /* continuous clk */
+ (3 << 4) | /* 4 lanes */
+ (1 << 1)); /* CRC TX gen */
+
+ dev_dbg(dev, "Successfully probed\n");
+
+ return 0;
+
+err_unreg_notif:
+ ub953_v4l2_notifier_unregister(priv);
+err_free_state:
+ v4l2_subdev_cleanup(&priv->sd);
+err_entity_cleanup:
+ if (priv->tx_ep_np)
+ of_node_put(priv->tx_ep_np);
+
+ media_entity_cleanup(&priv->sd.entity);
+err_remove_ctrls:
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+err_gpiochip_remove:
+ ub953_gpiochip_remove(priv);
+
+ return ret;
+}
+
+static int ub953_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ub953_data *priv = sd_to_ub953(sd);
+
+ dev_dbg(&client->dev, "Removing\n");
+
+ ub953_v4l2_notifier_unregister(priv);
+ v4l2_async_unregister_subdev(&priv->sd);
+
+ v4l2_subdev_cleanup(&priv->sd);
+
+ of_node_put(priv->tx_ep_np);
+
+ media_entity_cleanup(&priv->sd.entity);
+
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+
+ ub953_gpiochip_remove(priv);
+
+ return 0;
+}
+
+static const struct i2c_device_id ub953_id[] = { { "ds90ub953-q1", 0 }, {} };
+MODULE_DEVICE_TABLE(i2c, ub953_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ub953_dt_ids[] = {
+ { .compatible = "ti,ds90ub953-q1", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, ub953_dt_ids);
+#endif
+
+static struct i2c_driver ds90ub953_driver = {
+ .probe_new = ub953_probe,
+ .remove = ub953_remove,
+ .id_table = ub953_id,
+ .driver = {
+ .name = "ds90ub953",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ub953_dt_ids),
+ },
+};
+
+module_i2c_driver(ds90ub953_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Texas Instruments DS90UB953 serializer driver");
+MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>");
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c
new file mode 100644
index 000000000000..26079edd9096
--- /dev/null
+++ b/drivers/media/i2c/ds90ub960.c
@@ -0,0 +1,2381 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for the Texas Instruments DS90UB960-Q1 video deserializer
+ *
+ * Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net>
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c-atr.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/kthread.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_graph.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-subdev.h>
+
+#define UB960_MAX_RX_NPORTS 4
+#define UB960_MAX_TX_NPORTS 2
+#define UB960_MAX_NPORTS (UB960_MAX_RX_NPORTS + UB960_MAX_TX_NPORTS)
+
+#define UB960_NUM_SLAVE_ALIASES 8
+#define UB960_MAX_POOL_ALIASES (UB960_MAX_RX_NPORTS * UB960_NUM_SLAVE_ALIASES)
+
+/*
+ * Register map
+ *
+ * 0x00-0x32 Shared (UB960_SR)
+ * 0x33-0x3A CSI-2 TX (per-port paged on DS90UB960, shared on 954) (UB960_TR)
+ * 0x4C Shared (UB960_SR)
+ * 0x4D-0x7F FPD-Link RX, per-port paged (UB960_RR)
+ * 0xB0-0xBF Shared (UB960_SR)
+ * 0xD0-0xDF FPD-Link RX, per-port paged (UB960_RR)
+ * 0xF0-0xF5 Shared (UB960_SR)
+ * 0xF8-0xFB Shared (UB960_SR)
+ * All others Reserved
+ *
+ * Register prefixes:
+ * UB960_SR_* = Shared register
+ * UB960_RR_* = FPD-Link RX, per-port paged register
+ * UB960_TR_* = CSI-2 TX, per-port paged register
+ * UB960_XR_* = Reserved register
+ * UB960_IR_* = Indirect register
+ */
+
+#define UB960_SR_I2C_DEV_ID 0x00
+#define UB960_SR_RESET 0x01
+#define UB960_SR_GEN_CONFIG 0x02
+#define UB960_SR_REV_MASK 0x03
+#define UB960_SR_DEVICE_STS 0x04
+#define UB960_SR_PAR_ERR_THOLD_HI 0x05
+#define UB960_SR_PAR_ERR_THOLD_LO 0x06
+#define UB960_SR_BCC_WDOG_CTL 0x07
+#define UB960_SR_I2C_CTL1 0x08
+#define UB960_SR_I2C_CTL2 0x09
+#define UB960_SR_SCL_HIGH_TIME 0x0A
+#define UB960_SR_SCL_LOW_TIME 0x0B
+#define UB960_SR_RX_PORT_CTL 0x0C
+#define UB960_SR_IO_CTL 0x0D
+#define UB960_SR_GPIO_PIN_STS 0x0E
+#define UB960_SR_GPIO_INPUT_CTL 0x0F
+#define UB960_SR_GPIO_PIN_CTL(n) (0x10 + (n)) /* n < UB960_NUM_GPIOS */
+#define UB960_SR_FS_CTL 0x18
+#define UB960_SR_FS_HIGH_TIME_1 0x19
+#define UB960_SR_FS_HIGH_TIME_0 0x1A
+#define UB960_SR_FS_LOW_TIME_1 0x1B
+#define UB960_SR_FS_LOW_TIME_0 0x1C
+#define UB960_SR_MAX_FRM_HI 0x1D
+#define UB960_SR_MAX_FRM_LO 0x1E
+#define UB960_SR_CSI_PLL_CTL 0x1F
+
+#define UB960_SR_FWD_CTL1 0x20
+#define UB960_SR_FWD_CTL1_PORT_DIS(n) BIT((n) + 4)
+
+#define UB960_SR_FWD_CTL2 0x21
+#define UB960_SR_FWD_STS 0x22
+
+#define UB960_SR_INTERRUPT_CTL 0x23
+#define UB960_SR_INTERRUPT_CTL_INT_EN BIT(7)
+#define UB960_SR_INTERRUPT_CTL_IE_CSI_TX0 BIT(4)
+#define UB960_SR_INTERRUPT_CTL_IE_RX(n) BIT((n)) /* rxport[n] IRQ */
+#define UB960_SR_INTERRUPT_CTL_ALL 0x83 /* TODO 0x93 to enable CSI */
+
+#define UB960_SR_INTERRUPT_STS 0x24
+#define UB960_SR_INTERRUPT_STS_INT BIT(7)
+#define UB960_SR_INTERRUPT_STS_IS_CSI_TX(n) BIT(4 + (n)) /* txport[n] IRQ */
+#define UB960_SR_INTERRUPT_STS_IS_RX(n) BIT((n)) /* rxport[n] IRQ */
+
+#define UB960_SR_TS_CONFIG 0x25
+#define UB960_SR_TS_CONTROL 0x26
+#define UB960_SR_TS_LINE_HI 0x27
+#define UB960_SR_TS_LINE_LO 0x28
+#define UB960_SR_TS_STATUS 0x29
+#define UB960_SR_TIMESTAMP_P0_HI 0x2A
+#define UB960_SR_TIMESTAMP_P0_LO 0x2B
+#define UB960_SR_TIMESTAMP_P1_HI 0x2C
+#define UB960_SR_TIMESTAMP_P1_LO 0x2D
+
+#define UB960_SR_CSI_PORT_SEL 0x32
+
+#define UB960_TR_CSI_CTL 0x33
+#define UB960_TR_CSI_CTL_CSI_CAL_EN BIT(6)
+#define UB960_TR_CSI_CTL_CSI_ENABLE BIT(0)
+
+#define UB960_TR_CSI_CTL2 0x34
+#define UB960_TR_CSI_STS 0x35
+#define UB960_TR_CSI_TX_ICR 0x36
+
+#define UB960_TR_CSI_TX_ISR 0x37
+#define UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR BIT(3)
+#define UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR BIT(1)
+
+#define UB960_TR_CSI_TEST_CTL 0x38
+#define UB960_TR_CSI_TEST_PATT_HI 0x39
+#define UB960_TR_CSI_TEST_PATT_LO 0x3A
+
+#define UB960_XR_AEQ_CTL1 0x42
+#define UB960_XR_AEQ_ERR_THOLD 0x43
+
+#define UB960_RR_BCC_ERR_CTL 0x46
+#define UB960_RR_BCC_STATUS 0x47
+
+#define UB960_RR_FPD3_CAP 0x4A
+#define UB960_RR_RAW_EMBED_DTYPE 0x4B
+
+#define UB960_SR_FPD3_PORT_SEL 0x4C
+
+#define UB960_RR_RX_PORT_STS1 0x4D
+#define UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR BIT(5)
+#define UB960_RR_RX_PORT_STS1_LOCK_STS_CHG BIT(4)
+#define UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR BIT(3)
+#define UB960_RR_RX_PORT_STS1_PARITY_ERROR BIT(2)
+#define UB960_RR_RX_PORT_STS1_PORT_PASS BIT(1)
+#define UB960_RR_RX_PORT_STS1_LOCK_STS BIT(0)
+
+#define UB960_RR_RX_PORT_STS2 0x4E
+#define UB960_RR_RX_PORT_STS2_LINE_LEN_UNSTABLE BIT(7)
+#define UB960_RR_RX_PORT_STS2_LINE_LEN_CHG BIT(6)
+#define UB960_RR_RX_PORT_STS2_FPD3_ENCODE_ERROR BIT(5)
+#define UB960_RR_RX_PORT_STS2_BUFFER_ERROR BIT(4)
+#define UB960_RR_RX_PORT_STS2_CSI_ERROR BIT(3)
+#define UB960_RR_RX_PORT_STS2_FREQ_STABLE BIT(2)
+#define UB960_RR_RX_PORT_STS2_CABLE_FAULT BIT(1)
+#define UB960_RR_RX_PORT_STS2_LINE_CNT_CHG BIT(0)
+
+#define UB960_RR_RX_FREQ_HIGH 0x4F
+#define UB960_RR_RX_FREQ_LOW 0x50
+#define UB960_RR_SENSOR_STS_0 0x51
+#define UB960_RR_SENSOR_STS_1 0x52
+#define UB960_RR_SENSOR_STS_2 0x53
+#define UB960_RR_SENSOR_STS_3 0x54
+#define UB960_RR_RX_PAR_ERR_HI 0x55
+#define UB960_RR_RX_PAR_ERR_LO 0x56
+#define UB960_RR_BIST_ERR_COUNT 0x57
+
+#define UB960_RR_BCC_CONFIG 0x58
+#define UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH BIT(6)
+
+#define UB960_RR_DATAPATH_CTL1 0x59
+#define UB960_RR_DATAPATH_CTL2 0x5A
+#define UB960_RR_SER_ID 0x5B
+#define UB960_RR_SER_ALIAS_ID 0x5C
+
+/* For these two register sets: n < UB960_NUM_SLAVE_ALIASES */
+#define UB960_RR_SLAVE_ID(n) (0x5D + (n))
+#define UB960_RR_SLAVE_ALIAS(n) (0x65 + (n))
+
+#define UB960_RR_PORT_CONFIG 0x6D
+#define UB960_RR_BC_GPIO_CTL(n) (0x6E + (n)) /* n < 2 */
+#define UB960_RR_RAW10_ID 0x70
+#define UB960_RR_RAW12_ID 0x71
+#define UB960_RR_CSI_VC_MAP 0x72
+#define UB960_RR_LINE_COUNT_HI 0x73
+#define UB960_RR_LINE_COUNT_LO 0x74
+#define UB960_RR_LINE_LEN_1 0x75
+#define UB960_RR_LINE_LEN_0 0x76
+#define UB960_RR_FREQ_DET_CTL 0x77
+#define UB960_RR_MAILBOX_1 0x78
+#define UB960_RR_MAILBOX_2 0x79
+
+#define UB960_RR_CSI_RX_STS 0x7A
+#define UB960_RR_CSI_RX_STS_LENGTH_ERR BIT(3)
+#define UB960_RR_CSI_RX_STS_CKSUM_ERR BIT(2)
+#define UB960_RR_CSI_RX_STS_ECC2_ERR BIT(1)
+#define UB960_RR_CSI_RX_STS_ECC1_ERR BIT(0)
+
+#define UB960_RR_CSI_ERR_COUNTER 0x7B
+#define UB960_RR_PORT_CONFIG2 0x7C
+#define UB960_RR_PORT_PASS_CTL 0x7D
+#define UB960_RR_SEN_INT_RISE_CTL 0x7E
+#define UB960_RR_SEN_INT_FALL_CTL 0x7F
+
+#define UB960_XR_REFCLK_FREQ 0xA5
+
+#define UB960_SR_IND_ACC_CTL 0xB0
+#define UB960_SR_IND_ACC_CTL_IA_AUTO_INC BIT(1)
+
+#define UB960_SR_IND_ACC_ADDR 0xB1
+#define UB960_SR_IND_ACC_DATA 0xB2
+#define UB960_SR_BIST_CONTROL 0xB3
+#define UB960_SR_MODE_IDX_STS 0xB8
+#define UB960_SR_LINK_ERROR_COUNT 0xB9
+#define UB960_SR_FPD3_ENC_CTL 0xBA
+#define UB960_SR_FV_MIN_TIME 0xBC
+#define UB960_SR_GPIO_PD_CTL 0xBE
+
+#define UB960_RR_PORT_DEBUG 0xD0
+#define UB960_RR_AEQ_CTL2 0xD2
+#define UB960_RR_AEQ_STATUS 0xD3
+#define UB960_RR_AEQ_BYPASS 0xD4
+#define UB960_RR_AEQ_MIN_MAX 0xD5
+#define UB960_RR_PORT_ICR_HI 0xD8
+#define UB960_RR_PORT_ICR_LO 0xD9
+#define UB960_RR_PORT_ISR_HI 0xDA
+#define UB960_RR_PORT_ISR_LO 0xDB
+#define UB960_RR_FC_GPIO_STS 0xDC
+#define UB960_RR_FC_GPIO_ICR 0xDD
+#define UB960_RR_SEN_INT_RISE_STS 0xDE
+#define UB960_RR_SEN_INT_FALL_STS 0xDF
+
+#define UB960_SR_FPD3_RX_ID0 0xF0
+#define UB960_SR_FPD3_RX_ID1 0xF1
+#define UB960_SR_FPD3_RX_ID2 0xF2
+#define UB960_SR_FPD3_RX_ID3 0xF3
+#define UB960_SR_FPD3_RX_ID4 0xF4
+#define UB960_SR_FPD3_RX_ID5 0xF5
+#define UB960_SR_I2C_RX_ID(n) (0xF8 + (n)) /* < UB960_FPD_RX_NPORTS */
+
+/* UB960_IR_PGEN_*: Indirect Registers for Test Pattern Generator */
+
+#define UB960_IR_PGEN_CTL 0x01
+#define UB960_IR_PGEN_CTL_PGEN_ENABLE BIT(0)
+
+#define UB960_IR_PGEN_CFG 0x02
+#define UB960_IR_PGEN_CSI_DI 0x03
+#define UB960_IR_PGEN_LINE_SIZE1 0x04
+#define UB960_IR_PGEN_LINE_SIZE0 0x05
+#define UB960_IR_PGEN_BAR_SIZE1 0x06
+#define UB960_IR_PGEN_BAR_SIZE0 0x07
+#define UB960_IR_PGEN_ACT_LPF1 0x08
+#define UB960_IR_PGEN_ACT_LPF0 0x09
+#define UB960_IR_PGEN_TOT_LPF1 0x0A
+#define UB960_IR_PGEN_TOT_LPF0 0x0B
+#define UB960_IR_PGEN_LINE_PD1 0x0C
+#define UB960_IR_PGEN_LINE_PD0 0x0D
+#define UB960_IR_PGEN_VBP 0x0E
+#define UB960_IR_PGEN_VFP 0x0F
+#define UB960_IRT_PGEN_COLOR(n) (0x10 + (n)) /* n < 15 */
+
+struct ub960_hw_data {
+ u8 num_rxports;
+ u8 num_txports;
+};
+
+enum ub960_rxport_mode {
+ RXPORT_MODE_RAW10 = 0,
+ RXPORT_MODE_RAW12_HF = 1,
+ RXPORT_MODE_RAW12_LF = 2,
+ RXPORT_MODE_CSI2 = 3,
+};
+
+struct ub960_rxport {
+ struct ub960_data *priv;
+ u8 nport; /* RX port number, and index in priv->rxport[] */
+
+ struct v4l2_subdev *sd; /* Connected subdev */
+ struct fwnode_handle *fwnode;
+
+ enum ub960_rxport_mode mode;
+
+ struct device_node *remote_of_node; /* "remote-chip" OF node */
+ struct i2c_client *ser_client; /* remote serializer */
+ unsigned short ser_alias; /* ser i2c alias (lower 7 bits) */
+ bool locked;
+};
+
+struct ub960_asd {
+ struct v4l2_async_subdev base;
+ struct ub960_rxport *rxport;
+};
+
+static inline struct ub960_asd *to_ub960_asd(struct v4l2_async_subdev *asd)
+{
+ return container_of(asd, struct ub960_asd, base);
+}
+
+struct ub960_txport {
+ u32 num_data_lanes;
+};
+
+struct ub960_data {
+ const struct ub960_hw_data *hw_data;
+ struct i2c_client *client; /* for shared local registers */
+ struct regmap *regmap;
+ struct gpio_desc *pd_gpio;
+ struct task_struct *kthread;
+ struct i2c_atr *atr;
+ struct ub960_rxport *rxports[UB960_MAX_RX_NPORTS];
+ struct ub960_txport *txports[UB960_MAX_TX_NPORTS];
+
+ struct v4l2_subdev sd;
+ struct media_pad pads[UB960_MAX_NPORTS];
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_async_notifier notifier;
+
+ unsigned long refclk;
+
+ u32 tx_data_rate; /* Nominal data rate (Gb/s) */
+ s64 tx_link_freq[1];
+
+ /* Address Translator alias-to-slave map table */
+ size_t atr_alias_num; /* Number of aliases configured */
+ u16 atr_alias_id[UB960_MAX_POOL_ALIASES]; /* 0 = no alias */
+ u16 atr_slave_id[UB960_MAX_POOL_ALIASES]; /* 0 = not in use */
+ struct mutex alias_table_lock;
+
+ u8 current_read_rxport;
+ u8 current_write_rxport_mask;
+
+ u8 current_read_csiport;
+ u8 current_write_csiport_mask;
+
+ bool streaming;
+};
+
+static inline struct ub960_data *sd_to_ub960(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ub960_data, sd);
+}
+
+enum {
+ TEST_PATTERN_DISABLED = 0,
+ TEST_PATTERN_V_COLOR_BARS_1,
+ TEST_PATTERN_V_COLOR_BARS_2,
+ TEST_PATTERN_V_COLOR_BARS_4,
+ TEST_PATTERN_V_COLOR_BARS_8,
+};
+
+static const char * const ub960_tpg_qmenu[] = {
+ "Disabled",
+ "1 vertical color bar",
+ "2 vertical color bars",
+ "4 vertical color bars",
+ "8 vertical color bars",
+};
+
+static inline bool ub960_pad_is_sink(struct ub960_data *priv, u32 pad)
+{
+ return pad < priv->hw_data->num_rxports;
+}
+
+static inline bool ub960_pad_is_source(struct ub960_data *priv, u32 pad)
+{
+ return pad >= priv->hw_data->num_rxports &&
+ pad < (priv->hw_data->num_rxports + priv->hw_data->num_txports);
+}
+
+struct ub960_format_info {
+ u32 code;
+ u32 bpp;
+ u8 datatype;
+ bool meta;
+};
+
+static const struct ub960_format_info ub960_formats[] = {
+ { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, .datatype = 0x1e, },
+ { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .datatype = 0x1e, },
+ { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, .datatype = 0x1e, },
+ { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, .datatype = 0x1e, },
+
+ /* Legacy */
+ { .code = MEDIA_BUS_FMT_YUYV8_2X8, .bpp = 16, .datatype = 0x1e, },
+ { .code = MEDIA_BUS_FMT_UYVY8_2X8, .bpp = 16, .datatype = 0x1e, },
+ { .code = MEDIA_BUS_FMT_VYUY8_2X8, .bpp = 16, .datatype = 0x1e, },
+ { .code = MEDIA_BUS_FMT_YVYU8_2X8, .bpp = 16, .datatype = 0x1e, },
+
+ /* RAW */
+ { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12, .datatype = 0x2c, },
+ { .code = MEDIA_BUS_FMT_SRGGB12_1X12, .bpp = 12, .datatype = 0x2c, },
+};
+
+static const struct ub960_format_info *ub960_find_format(u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(ub960_formats); ++i) {
+ if (ub960_formats[i].code == code)
+ return &ub960_formats[i];
+ }
+
+ return NULL;
+}
+
+/* -----------------------------------------------------------------------------
+ * Basic device access
+ */
+
+static int ub960_read(const struct ub960_data *priv, u8 reg, u8 *val)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int v;
+ int ret;
+
+ ret = regmap_read(priv->regmap, reg, &v);
+ if (ret) {
+ dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ *val = v;
+
+ return 0;
+}
+
+static int ub960_write(const struct ub960_data *priv, u8 reg, u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = regmap_write(priv->regmap, reg, val);
+ if (ret < 0)
+ dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ub960_update_bits_shared(const struct ub960_data *priv, u8 reg,
+ u8 mask, u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = regmap_update_bits(priv->regmap, reg, mask, val);
+ if (ret < 0)
+ dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ub960_rxport_select(struct ub960_data *priv, u8 nport)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ if (priv->current_read_rxport == nport &&
+ priv->current_write_rxport_mask == BIT(nport))
+ return 0;
+
+ ret = regmap_write(priv->regmap, UB960_SR_FPD3_PORT_SEL,
+ (nport << 4) | (1 << nport));
+ if (ret) {
+ dev_err(dev, "%s: cannot select rxport %d (%d)!\n", __func__,
+ nport, ret);
+ return ret;
+ }
+
+ priv->current_read_rxport = nport;
+ priv->current_write_rxport_mask = BIT(nport);
+
+ return 0;
+}
+
+static int ub960_rxport_read(struct ub960_data *priv, u8 nport, u8 reg,
+ u8 *val)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int v;
+ int ret;
+
+ ub960_rxport_select(priv, nport);
+
+ ret = regmap_read(priv->regmap, reg, &v);
+ if (ret) {
+ dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ *val = v;
+
+ return 0;
+}
+
+static int ub960_rxport_write(struct ub960_data *priv, u8 nport, u8 reg,
+ u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ub960_rxport_select(priv, nport);
+
+ ret = regmap_write(priv->regmap, reg, val);
+ if (ret)
+ dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ub960_rxport_update_bits(struct ub960_data *priv, u8 nport, u8 reg,
+ u8 mask, u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ub960_rxport_select(priv, nport);
+
+ ret = regmap_update_bits(priv->regmap, reg, mask, val);
+
+ if (ret)
+ dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ub960_csiport_select(struct ub960_data *priv, u8 nport)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ if (priv->current_read_csiport == nport &&
+ priv->current_write_csiport_mask == BIT(nport))
+ return 0;
+
+ ret = regmap_write(priv->regmap, UB960_SR_CSI_PORT_SEL,
+ (nport << 4) | (1 << nport));
+ if (ret) {
+ dev_err(dev, "%s: cannot select csi port %d (%d)!\n", __func__,
+ nport, ret);
+ return ret;
+ }
+
+ priv->current_read_csiport = nport;
+ priv->current_write_csiport_mask = BIT(nport);
+
+ return 0;
+}
+
+static int ub960_csiport_read(struct ub960_data *priv, u8 nport, u8 reg,
+ u8 *val)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int v;
+ int ret;
+
+ ub960_csiport_select(priv, nport);
+
+ ret = regmap_read(priv->regmap, reg, &v);
+ if (ret) {
+ dev_err(dev, "%s: cannot read register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+ return ret;
+ }
+
+ *val = v;
+
+ return 0;
+}
+
+static int ub960_csiport_write(struct ub960_data *priv, u8 nport, u8 reg,
+ u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ub960_csiport_select(priv, nport);
+
+ ret = regmap_write(priv->regmap, reg, val);
+ if (ret)
+ dev_err(dev, "%s: cannot write register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+__maybe_unused
+static int ub960_csiport_update_bits(struct ub960_data *priv, u8 nport, u8 reg,
+ u8 mask, u8 val)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ub960_csiport_select(priv, nport);
+
+ ret = regmap_update_bits(priv->regmap, reg, mask, val);
+
+ if (ret)
+ dev_err(dev, "%s: cannot update register 0x%02x (%d)!\n",
+ __func__, reg, ret);
+
+ return ret;
+}
+
+static int ub960_write_ind8(const struct ub960_data *priv, u8 reg, u8 val)
+{
+ int ret;
+
+ ret = ub960_write(priv, UB960_SR_IND_ACC_ADDR, reg);
+ if (!ret)
+ ret = ub960_write(priv, UB960_SR_IND_ACC_DATA, val);
+ return ret;
+}
+
+/* Assumes IA_AUTO_INC is set in UB960_SR_IND_ACC_CTL */
+static int ub960_write_ind16(const struct ub960_data *priv, u8 reg, u16 val)
+{
+ int ret;
+
+ ret = ub960_write(priv, UB960_SR_IND_ACC_ADDR, reg);
+ if (!ret)
+ ret = ub960_write(priv, UB960_SR_IND_ACC_DATA, val >> 8);
+ if (!ret)
+ ret = ub960_write(priv, UB960_SR_IND_ACC_DATA, val & 0xff);
+ return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * I2C-ATR (address translator)
+ */
+
+static int ub960_atr_attach_client(struct i2c_atr *atr, u32 chan_id,
+ const struct i2c_board_info *info,
+ const struct i2c_client *client,
+ u16 *alias_id)
+{
+ struct ub960_data *priv = i2c_atr_get_clientdata(atr);
+ struct ub960_rxport *rxport = priv->rxports[chan_id];
+ struct device *dev = &priv->client->dev;
+ unsigned int reg_idx;
+ unsigned int pool_idx;
+ u16 alias = 0;
+ int ret = 0;
+
+ dev_dbg(dev, "rx%d: %s\n", chan_id, __func__);
+
+ mutex_lock(&priv->alias_table_lock);
+
+ /* Find unused alias in table */
+
+ for (pool_idx = 0; pool_idx < priv->atr_alias_num; pool_idx++)
+ if (priv->atr_slave_id[pool_idx] == 0)
+ break;
+
+ if (pool_idx == priv->atr_alias_num) {
+ dev_warn(dev, "rx%d: alias pool exhausted\n", rxport->nport);
+ ret = -EADDRNOTAVAIL;
+ goto out;
+ }
+
+ alias = priv->atr_alias_id[pool_idx];
+
+ /* Find first unused alias register */
+
+ for (reg_idx = 0; reg_idx < UB960_NUM_SLAVE_ALIASES; reg_idx++) {
+ u8 regval;
+
+ ret = ub960_rxport_read(priv, chan_id,
+ UB960_RR_SLAVE_ALIAS(reg_idx), &regval);
+ if (!ret && regval == 0)
+ break;
+ }
+
+ if (reg_idx == UB960_NUM_SLAVE_ALIASES) {
+ dev_warn(dev, "rx%d: all aliases in use\n", rxport->nport);
+ ret = -EADDRNOTAVAIL;
+ goto out;
+ }
+
+ /* Map alias to slave */
+
+ ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ID(reg_idx),
+ client->addr << 1);
+ ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx),
+ alias << 1);
+
+ priv->atr_slave_id[pool_idx] = client->addr;
+
+ *alias_id = alias; /* tell the atr which alias we chose */
+
+ dev_dbg(dev, "rx%d: client 0x%02x mapped at alias 0x%02x (%s)\n",
+ rxport->nport, client->addr, alias, client->name);
+
+out:
+ mutex_unlock(&priv->alias_table_lock);
+ return ret;
+}
+
+static void ub960_atr_detach_client(struct i2c_atr *atr, u32 chan_id,
+ const struct i2c_client *client)
+{
+ struct ub960_data *priv = i2c_atr_get_clientdata(atr);
+ struct ub960_rxport *rxport = priv->rxports[chan_id];
+ struct device *dev = &priv->client->dev;
+ unsigned int reg_idx;
+ unsigned int pool_idx;
+ u16 alias = 0;
+
+ mutex_lock(&priv->alias_table_lock);
+
+ /* Find alias mapped to this client */
+
+ for (pool_idx = 0; pool_idx < priv->atr_alias_num; pool_idx++)
+ if (priv->atr_slave_id[pool_idx] == client->addr)
+ break;
+
+ if (pool_idx == priv->atr_alias_num) {
+ dev_err(dev, "rx%d: client 0x%02x is not mapped!\n",
+ rxport->nport, client->addr);
+ goto out;
+ }
+
+ alias = priv->atr_alias_id[pool_idx];
+
+ /* Find alias register used for this client */
+
+ for (reg_idx = 0; reg_idx < UB960_NUM_SLAVE_ALIASES; reg_idx++) {
+ u8 regval;
+ int ret;
+
+ ret = ub960_rxport_read(priv, chan_id,
+ UB960_RR_SLAVE_ALIAS(reg_idx), &regval);
+ if (!ret && regval == (alias << 1))
+ break;
+ }
+
+ if (reg_idx == UB960_NUM_SLAVE_ALIASES) {
+ dev_err(dev,
+ "rx%d: cannot find alias 0x%02x reg (client 0x%02x)!\n",
+ rxport->nport, alias, client->addr);
+ goto out;
+ }
+
+ /* Unmap */
+
+ ub960_rxport_write(priv, chan_id, UB960_RR_SLAVE_ALIAS(reg_idx), 0);
+ priv->atr_slave_id[pool_idx] = 0;
+
+ dev_dbg(dev, "rx%d: client 0x%02x unmapped from alias 0x%02x (%s)\n",
+ rxport->nport, client->addr, alias, client->name);
+
+out:
+ mutex_unlock(&priv->alias_table_lock);
+}
+
+static const struct i2c_atr_ops ub960_atr_ops = {
+ .attach_client = ub960_atr_attach_client,
+ .detach_client = ub960_atr_detach_client,
+};
+
+/* -----------------------------------------------------------------------------
+ * CSI ports
+ */
+
+static int ub960_csiport_probe_one(struct ub960_data *priv,
+ const struct device_node *np,
+ u8 nport)
+{
+ struct device *dev = &priv->client->dev;
+ struct ub960_txport *txport;
+ int ret;
+
+ if (priv->txports[nport]) {
+ dev_err(dev, "OF: %s: duplicate tx port\n",
+ of_node_full_name(np));
+ return -EADDRINUSE;
+ }
+
+ txport = kzalloc(sizeof(*txport), GFP_KERNEL);
+ if (!txport)
+ return -ENOMEM;
+
+ priv->txports[nport] = txport;
+
+ ret = of_property_count_u32_elems(np, "data-lanes");
+
+ if (ret <= 0) {
+ dev_err(dev, "OF: %s: failed to parse data-lanes: %d\n",
+ of_node_full_name(np), ret);
+ goto err_free_txport;
+ }
+
+ txport->num_data_lanes = ret;
+
+ return 0;
+
+err_free_txport:
+ kfree(txport);
+
+ return ret;
+}
+
+static void ub960_txport_remove_one(struct ub960_data *priv, u8 nport)
+{
+ struct ub960_txport *txport = priv->txports[nport];
+
+ kfree(txport);
+ priv->txports[nport] = NULL;
+}
+
+static void ub960_csi_handle_events(struct ub960_data *priv, u8 nport)
+{
+ struct device *dev = &priv->client->dev;
+ u8 csi_tx_isr;
+ int ret;
+
+ ret = ub960_csiport_read(priv, nport, UB960_TR_CSI_TX_ISR, &csi_tx_isr);
+
+ if (!ret) {
+ if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_SYNC_ERROR)
+ dev_warn(dev, "TX%u: CSI_SYNC_ERROR\n", nport);
+
+ if (csi_tx_isr & UB960_TR_CSI_TX_ISR_IS_CSI_PASS_ERROR)
+ dev_warn(dev, "TX%u: CSI_PASS_ERROR\n", nport);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * RX ports
+ */
+
+/*
+ * Instantiate serializer and i2c adapter for a locked remote end.
+ *
+ * Must be called with priv->alias_table_lock not held! The added i2c adapter
+ * will probe new slaves, which can request i2c transfers, ending up in
+ * calling ub960_atr_attach_client() where the lock is taken.
+ */
+static int ub960_rxport_add_serializer(struct ub960_data *priv, u8 nport)
+{
+ struct ub960_rxport *rxport = priv->rxports[nport];
+ struct device *dev = &priv->client->dev;
+ struct i2c_board_info ser_info = {
+ .of_node = rxport->remote_of_node,
+ };
+
+ /*
+ * Adding the serializer under rxport->adap would be cleaner, but it
+ * would need tweaks to bypass the alias table. Adding to the
+ * upstream adapter is way simpler.
+ */
+ ser_info.addr = rxport->ser_alias;
+ rxport->ser_client =
+ i2c_new_client_device(priv->client->adapter, &ser_info);
+ if (!rxport->ser_client) {
+ dev_err(dev, "rx%d: cannot add %s i2c device", nport,
+ ser_info.type);
+ return -EIO;
+ }
+
+ dev_dbg(dev, "rx%d: remote serializer at alias 0x%02x\n", nport,
+ rxport->ser_client->addr);
+
+ return 0;
+}
+
+static void ub960_rxport_remove_serializer(struct ub960_data *priv, u8 nport)
+{
+ struct ub960_rxport *rxport = priv->rxports[nport];
+
+ if (rxport->ser_client) {
+ i2c_unregister_device(rxport->ser_client);
+ rxport->ser_client = NULL;
+ }
+}
+
+static int ub960_rxport_probe_serializers(struct ub960_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned long timeout;
+ u8 nport;
+ unsigned int missing = 0;
+
+ timeout = jiffies + msecs_to_jiffies(750);
+
+ while (time_before(jiffies, timeout)) {
+ missing = 0;
+
+ for (nport = 0; nport < priv->hw_data->num_rxports; ++nport) {
+ struct ub960_rxport *rxport = priv->rxports[nport];
+ u8 rx_port_sts1;
+ int ret;
+
+ /* No serializer in DT? */
+ if (!rxport)
+ continue;
+
+ /* Serializer already added? */
+ if (rxport->ser_client)
+ continue;
+
+ ret = ub960_rxport_read(priv, nport,
+ UB960_RR_RX_PORT_STS1,
+ &rx_port_sts1);
+ if (ret)
+ return ret;
+
+ /* Serializer not locked yet? */
+ if (!(rx_port_sts1 & UB960_RR_RX_PORT_STS1_LOCK_STS)) {
+ missing++;
+ continue;
+ }
+
+ ret = ub960_rxport_add_serializer(priv, nport);
+ if (ret)
+ return ret;
+
+ rxport->locked = true;
+ }
+
+ if (missing == 0)
+ return 0;
+
+ usleep_range(500, 5000);
+ }
+
+ dev_err(dev, "timeout, continuing with %u missing serializer(s)\n",
+ missing);
+
+ return 0;
+}
+
+/*
+ * Return the local alias for a given remote serializer.
+ */
+static int ub960_of_get_reg(struct device_node *np, const char *serializer_name)
+{
+ u32 alias;
+ int ret;
+ int idx;
+
+ if (!np)
+ return -ENODEV;
+
+ idx = of_property_match_string(np, "reg-names", serializer_name);
+ if (idx < 0)
+ return idx;
+
+ ret = of_property_read_u32_index(np, "reg", idx, &alias);
+ if (ret)
+ return ret;
+
+ return alias;
+}
+
+static int ub960_rxport_probe_one(struct ub960_data *priv,
+ const struct device_node *np,
+ u8 nport)
+{
+ const char *ser_names[UB960_MAX_RX_NPORTS] = { "ser0", "ser1", "ser2",
+ "ser3" };
+ struct device *dev = &priv->client->dev;
+ struct ub960_rxport *rxport;
+ u32 bc_freq, bc_freq_val;
+ int ret;
+ u32 mode;
+
+ if (priv->rxports[nport]) {
+ dev_err(dev, "OF: %s: reg value %d is duplicated\n",
+ of_node_full_name(np), nport);
+ return -EADDRINUSE;
+ }
+
+ rxport = kzalloc(sizeof(*rxport), GFP_KERNEL);
+ if (!rxport)
+ return -ENOMEM;
+
+ priv->rxports[nport] = rxport;
+
+ rxport->nport = nport;
+ rxport->priv = priv;
+
+ ret = ub960_of_get_reg(priv->client->dev.of_node, ser_names[nport]);
+ if (ret < 0)
+ goto err_free_rxport;
+
+ rxport->ser_alias = ret;
+
+ ret = of_property_read_u32(np, "mode", &mode);
+ if (ret < 0) {
+ dev_err(dev, "Missing RX port mode: %d\n", ret);
+ goto err_free_rxport;
+ }
+
+ if (mode > RXPORT_MODE_CSI2) {
+ dev_err(dev, "Bad RX port mode %u\n", mode);
+ goto err_free_rxport;
+ }
+
+ rxport->mode = mode;
+
+ ret = of_property_read_u32(np, "bc-freq", &bc_freq);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read BC freq for port %u: %d\n", nport,
+ ret);
+ goto err_free_rxport;
+ }
+
+ switch (bc_freq) {
+ case 2500000:
+ bc_freq_val = 0; break;
+ case 10000000:
+ bc_freq_val = 2; break;
+ case 50000000:
+ bc_freq_val = 6; break;
+ default:
+ dev_err(dev, "Bad BC freq %u\n", bc_freq);
+ goto err_free_rxport;
+ }
+
+ rxport->remote_of_node = of_get_child_by_name(np, "remote-chip");
+ if (!rxport->remote_of_node) {
+ dev_err(dev, "OF: %s: missing remote-chip child\n",
+ of_node_full_name(np));
+ ret = -EINVAL;
+ goto err_free_rxport;
+ }
+
+ rxport->fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(np));
+ if (!rxport->fwnode) {
+ dev_err(dev, "No remote endpoint for rxport%d\n", nport);
+ ret = -ENODEV;
+ goto err_node_put;
+ }
+
+ /*
+ * Back channel frequency select.
+ * Override FREQ_SELECT from the strap.
+ * 0 - 2.5 Mbps (DS90UB913A-Q1 / DS90UB933-Q1)
+ * 2 - 10 Mbps
+ * 6 - 50 Mbps (DS90UB953-Q1)
+ *
+ * Note that changing this setting will result in some errors on the back
+ * channel for a short period of time.
+ */
+ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG, 0x7,
+ bc_freq_val);
+
+ switch (rxport->mode) {
+ default:
+ WARN_ON(true);
+ fallthrough;
+
+ case RXPORT_MODE_RAW10:
+ /* FPD3_MODE = RAW10 Mode (DS90UB913A-Q1 / DS90UB933-Q1 compatible) */
+ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 0x3,
+ 0x3);
+
+ /*
+ * RAW10_8BIT_CTL = 0b11 : 8-bit processing using lower 8 bits
+ * 0b10 : 8-bit processing using upper 8 bits
+ */
+ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2,
+ 0x3 << 6, 0x2 << 6);
+
+ break;
+
+ case RXPORT_MODE_CSI2:
+ /* CSI-2 Mode (DS90UB953-Q1 compatible) */
+ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG, 0x3,
+ 0x0);
+
+ break;
+ }
+
+ /* LV_POLARITY & FV_POLARITY */
+ ub960_rxport_update_bits(priv, nport, UB960_RR_PORT_CONFIG2, 0x3, 0x1);
+
+ /* Enable all interrupt sources from this port */
+ ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_HI, 0x07);
+ ub960_rxport_write(priv, nport, UB960_RR_PORT_ICR_LO, 0x7f);
+
+ /* Enable I2C_PASS_THROUGH */
+ ub960_rxport_update_bits(priv, nport, UB960_RR_BCC_CONFIG,
+ UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH,
+ UB960_RR_BCC_CONFIG_I2C_PASS_THROUGH);
+
+ /* Enable I2C communication to the serializer via the alias addr */
+ ub960_rxport_write(priv, nport, UB960_RR_SER_ALIAS_ID,
+ rxport->ser_alias << 1);
+
+ dev_dbg(dev, "ser%d: at alias 0x%02x\n", nport, rxport->ser_alias);
+
+ ret = i2c_atr_add_adapter(priv->atr, nport);
+ if (ret) {
+ dev_err(dev, "rx%d: cannot add adapter", nport);
+ goto err_node_put;
+ }
+
+ return 0;
+
+err_node_put:
+ of_node_put(rxport->remote_of_node);
+err_free_rxport:
+ priv->rxports[nport] = NULL;
+ kfree(rxport);
+ return ret;
+}
+
+static void ub960_rxport_remove_one(struct ub960_data *priv, u8 nport)
+{
+ struct ub960_rxport *rxport = priv->rxports[nport];
+
+ i2c_atr_del_adapter(priv->atr, nport);
+ ub960_rxport_remove_serializer(priv, nport);
+ of_node_put(rxport->remote_of_node);
+ kfree(rxport);
+}
+
+static int ub960_atr_probe(struct ub960_data *priv)
+{
+ struct i2c_adapter *parent_adap = priv->client->adapter;
+ struct device *dev = &priv->client->dev;
+
+ priv->atr = i2c_atr_new(parent_adap, dev, &ub960_atr_ops,
+ priv->hw_data->num_rxports);
+ if (IS_ERR(priv->atr))
+ return PTR_ERR(priv->atr);
+
+ i2c_atr_set_clientdata(priv->atr, priv);
+
+ return 0;
+}
+
+static void ub960_atr_remove(struct ub960_data *priv)
+{
+ i2c_atr_delete(priv->atr);
+ priv->atr = NULL;
+}
+
+static void ub960_rxport_handle_events(struct ub960_data *priv, u8 nport)
+{
+ struct device *dev = &priv->client->dev;
+ u8 rx_port_sts1;
+ u8 rx_port_sts2;
+ u8 csi_rx_sts;
+ u8 bcc_sts;
+ int ret = 0;
+
+ /* Read interrupts (also clears most of them) */
+ if (!ret)
+ ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1,
+ &rx_port_sts1);
+ if (!ret)
+ ret = ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2,
+ &rx_port_sts2);
+ if (!ret)
+ ret = ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS,
+ &csi_rx_sts);
+ if (!ret)
+ ret = ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS,
+ &bcc_sts);
+
+ if (ret)
+ return;
+
+ dev_dbg(dev, "Handle RX%d events: STS: %x, %x, %x, BCC %x\n", nport,
+ rx_port_sts1, rx_port_sts2, csi_rx_sts, bcc_sts);
+
+ if (rx_port_sts1 & (UB960_RR_RX_PORT_STS1_BCC_CRC_ERROR |
+ UB960_RR_RX_PORT_STS1_BCC_SEQ_ERROR |
+ UB960_RR_RX_PORT_STS1_PARITY_ERROR))
+ dev_err(dev, "RX%u STS1 error: %#02x\n", nport, rx_port_sts1);
+
+ if (rx_port_sts2 & (UB960_RR_RX_PORT_STS2_FPD3_ENCODE_ERROR |
+ UB960_RR_RX_PORT_STS2_BUFFER_ERROR |
+ UB960_RR_RX_PORT_STS2_CSI_ERROR |
+ UB960_RR_RX_PORT_STS2_CABLE_FAULT))
+ dev_err(dev, "RX%u STS2 error: %#02x\n", nport, rx_port_sts2);
+
+ if (csi_rx_sts)
+ dev_err(dev, "RX%u CSI error: %#02x\n", nport, csi_rx_sts);
+
+ if (bcc_sts)
+ dev_err(dev, "RX%u BCC error: %#02x\n", nport, bcc_sts);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2
+ */
+
+static int ub960_start_streaming(struct ub960_data *priv)
+{
+ const struct v4l2_subdev_krouting *routing;
+ struct v4l2_subdev_state *state;
+ unsigned int i;
+ u8 nport;
+ int ret;
+ u32 csi_ctl;
+ u32 speed_select;
+ u32 fwd_ctl;
+ struct {
+ u32 num_streams;
+ u8 pixel_dt;
+ u8 meta_dt;
+ u32 meta_lines;
+ u32 tx_port;
+ } rx_data[UB960_MAX_RX_NPORTS] = { 0 };
+
+ ret = 0;
+
+ state = v4l2_subdev_lock_active_state(&priv->sd);
+
+ routing = &state->routing;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ struct v4l2_subdev_route *route = &routing->routes[i];
+ u32 port = route->sink_pad;
+ struct ub960_rxport *rxport = priv->rxports[port];
+ struct v4l2_mbus_framefmt *fmt;
+ const struct ub960_format_info *ub960_fmt;
+
+ if (!rxport)
+ continue;
+
+ rx_data[port].tx_port =
+ route->source_pad - priv->hw_data->num_rxports;
+
+ /* For the rest, we are only interested in parallel busses */
+ if (rxport->mode == RXPORT_MODE_CSI2)
+ continue;
+
+ rx_data[port].num_streams++;
+
+ if (rx_data[port].num_streams > 2) {
+ ret = -EPIPE;
+ break;
+ }
+
+ fmt = v4l2_state_get_stream_format(state, port,
+ route->sink_stream);
+ if (!fmt) {
+ ret = -EPIPE;
+ break;
+ }
+
+ ub960_fmt = ub960_find_format(fmt->code);
+ if (!ub960_fmt) {
+ ret = -EPIPE;
+ break;
+ }
+
+ if (ub960_fmt->meta) {
+ if (fmt->height > 3) {
+ dev_err(&priv->client->dev,
+ "Unsupported metadata height %u\n",
+ fmt->height);
+ ret = -EPIPE;
+ break;
+ }
+
+ rx_data[port].meta_dt = ub960_fmt->datatype;
+ rx_data[port].meta_lines = fmt->height;
+ } else {
+ rx_data[port].pixel_dt = ub960_fmt->datatype;
+ }
+ }
+
+ v4l2_subdev_unlock_state(state);
+
+ if (ret)
+ return ret;
+
+ switch (priv->tx_data_rate) {
+ case 1600000000:
+ default:
+ speed_select = 0;
+ break;
+ case 1200000000:
+ speed_select = 1;
+ break;
+ case 800000000:
+ speed_select = 2;
+ break;
+ case 400000000:
+ speed_select = 3;
+ break;
+ }
+
+ ub960_write(priv, UB960_SR_CSI_PLL_CTL, speed_select);
+
+ for (nport = 0; nport < priv->hw_data->num_txports; nport++) {
+ struct ub960_txport *txport = priv->txports[nport];
+
+ if (!txport)
+ continue;
+
+ csi_ctl = UB960_TR_CSI_CTL_CSI_ENABLE;
+
+ /*
+ * From the datasheet: "initial CSI Skew-Calibration
+ * sequence [...] should be set when operating at 1.6 Gbps"
+ */
+ if (speed_select == 0)
+ csi_ctl |= UB960_TR_CSI_CTL_CSI_CAL_EN;
+
+ csi_ctl |= (4 - txport->num_data_lanes) << 4;
+
+ ub960_csiport_write(priv, nport, UB960_TR_CSI_CTL, csi_ctl);
+ }
+
+ for (nport = 0; nport < priv->hw_data->num_rxports; ++nport) {
+ struct ub960_rxport *rxport = priv->rxports[nport];
+
+ if (!rxport || !rxport->locked)
+ continue;
+
+ switch (rxport->mode) {
+ default:
+ WARN_ON(true);
+ fallthrough;
+
+ case RXPORT_MODE_RAW10:
+ /* VC=nport */
+ ub960_rxport_write(priv, nport, UB960_RR_RAW10_ID,
+ rx_data[nport].pixel_dt |
+ (nport << 6));
+
+ ub960_rxport_write(priv, rxport->nport,
+ UB960_RR_RAW_EMBED_DTYPE,
+ (rx_data[nport].meta_lines << 6) |
+ rx_data[nport].meta_dt);
+
+ break;
+
+ case RXPORT_MODE_CSI2:
+ /* Map all VCs from this port to VC(nport) */
+ ub960_rxport_write(priv, nport, UB960_RR_CSI_VC_MAP,
+ (nport << 6) | (nport << 4) |
+ (nport << 2) | (nport << 0));
+
+ break;
+ }
+ }
+
+ /* Start all cameras */
+
+ priv->streaming = true;
+
+ for (nport = 0; nport < priv->hw_data->num_rxports; ++nport) {
+ struct ub960_rxport *rxport = priv->rxports[nport];
+
+ if (!rxport || !rxport->locked)
+ continue;
+
+ ret = v4l2_subdev_call(rxport->sd, video, s_stream, 1);
+ if (ret) {
+ for (; nport > 0; --nport) {
+ rxport = priv->rxports[nport - 1];
+ if (!rxport)
+ continue;
+
+ v4l2_subdev_call(rxport->sd, video, s_stream,
+ 0);
+ }
+
+ priv->streaming = false;
+
+ return ret;
+ }
+ }
+
+ /* Forwarding */
+
+ fwd_ctl = 0;
+
+ for (nport = 0; nport < priv->hw_data->num_rxports; ++nport) {
+ struct ub960_rxport *rxport = priv->rxports[nport];
+
+ if (!rxport || !rxport->locked) {
+ fwd_ctl |= BIT(4 + nport); /* forward disable */
+ continue;
+ }
+
+ if (rx_data[nport].tx_port == 1)
+ fwd_ctl |= BIT(nport); /* forward to TX1 */
+ }
+
+ ub960_write(priv, UB960_SR_FWD_CTL1, fwd_ctl);
+
+ return 0;
+}
+
+static int ub960_stop_streaming(struct ub960_data *priv)
+{
+ unsigned int i;
+
+ /* Disable forwarding */
+ ub960_write(priv, UB960_SR_FWD_CTL1,
+ (BIT(0) | BIT(1) | BIT(2) | BIT(3)) << 4);
+
+ /* Stop all cameras */
+ for (i = 0; i < priv->hw_data->num_rxports; ++i) {
+ struct ub960_rxport *rxport = priv->rxports[i];
+
+ if (!rxport || !rxport->locked)
+ continue;
+
+ v4l2_subdev_call(rxport->sd, video, s_stream, 0);
+ }
+
+ for (i = 0; i < priv->hw_data->num_txports; i++) {
+ struct ub960_txport *txport = priv->txports[i];
+
+ if (!txport)
+ continue;
+
+ ub960_csiport_write(priv, i, UB960_TR_CSI_CTL, 0);
+ }
+
+ priv->streaming = false;
+
+ return 0;
+}
+
+static int ub960_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ub960_data *priv = sd_to_ub960(sd);
+
+ if (enable)
+ return ub960_start_streaming(priv);
+ else
+ return ub960_stop_streaming(priv);
+}
+
+static const struct v4l2_subdev_video_ops ub960_video_ops = {
+ .s_stream = ub960_s_stream,
+};
+
+static int _ub960_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing)
+{
+ const struct v4l2_mbus_framefmt format = {
+ .width = 640,
+ .height = 480,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_YCBCR_ENC_601,
+ .quantization = V4L2_QUANTIZATION_LIM_RANGE,
+ .xfer_func = V4L2_XFER_FUNC_SRGB,
+ };
+ int ret;
+
+ /*
+ * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
+ * frame desc is made dynamically allocated.
+ */
+
+ if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+ return -EINVAL;
+
+ ret = v4l2_routing_simple_verify(routing);
+ if (ret)
+ return ret;
+
+ v4l2_subdev_lock_state(state);
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+
+ v4l2_subdev_unlock_state(state);
+
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ub960_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct ub960_data *priv = sd_to_ub960(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming)
+ return -EBUSY;
+
+ return _ub960_set_routing(sd, state, routing);
+}
+
+static int ub960_get_source_frame_desc(struct ub960_data *priv,
+ struct v4l2_mbus_frame_desc *desc,
+ u8 nport)
+{
+ struct v4l2_subdev *sd;
+ struct media_pad *pad;
+ int ret;
+
+ pad = media_entity_remote_pad(&priv->pads[nport]);
+ if (!pad)
+ return -EPIPE;
+
+ sd = priv->rxports[nport]->sd;
+
+ ret = v4l2_subdev_call(sd, pad, get_frame_desc, pad->index,
+ desc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int ub960_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct ub960_data *priv = sd_to_ub960(sd);
+ const struct v4l2_subdev_krouting *routing;
+ struct v4l2_subdev_state *state;
+ int ret = 0;
+ unsigned int i;
+ struct device *dev = &priv->client->dev;
+
+ dev_dbg(dev, "%s for pad %d\n", __func__, pad);
+
+ if (!ub960_pad_is_source(priv, pad))
+ return -EINVAL;
+
+ state = v4l2_subdev_lock_active_state(&priv->sd);
+
+ routing = &state->routing;
+
+ memset(fd, 0, sizeof(*fd));
+
+ fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routing->routes[i];
+ struct v4l2_mbus_frame_desc_entry *source_entry = NULL;
+ struct v4l2_mbus_frame_desc source_fd;
+ unsigned int j;
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ if (route->source_pad != pad)
+ continue;
+
+ ret = ub960_get_source_frame_desc(priv, &source_fd,
+ route->sink_pad);
+ if (ret) {
+ dev_err(dev,
+ "Failed to get source frame desc for port %u\n",
+ route->sink_pad);
+ goto out;
+ }
+
+ for (j = 0; j < source_fd.num_entries; ++j)
+ if (source_fd.entry[j].stream == route->sink_stream) {
+ source_entry = &source_fd.entry[j];
+ break;
+ }
+
+ if (!source_entry) {
+ dev_err(dev,
+ "Failed to find stream from source frame desc\n");
+ ret = -EPIPE;
+ goto out;
+ }
+
+ fd->entry[fd->num_entries].stream = route->source_stream;
+
+ fd->entry[fd->num_entries].flags =
+ V4L2_MBUS_FRAME_DESC_FL_LEN_MAX;
+ fd->entry[fd->num_entries].length = source_entry->length;
+ fd->entry[fd->num_entries].pixelcode =
+ source_entry->pixelcode;
+
+ /* Use the RX channel number as VC. See ub960_start_streaming() */
+ fd->entry[fd->num_entries].bus.csi2.vc = route->sink_pad;
+
+ if (source_fd.type == V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ fd->entry[fd->num_entries].bus.csi2.dt =
+ source_entry->bus.csi2.dt;
+ } else {
+ const struct ub960_format_info *ub960_fmt;
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_state_get_stream_format(
+ state, pad, route->source_stream);
+
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ub960_fmt = ub960_find_format(fmt->code);
+ if (!ub960_fmt) {
+ dev_err(dev, "Unable to find format\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fd->entry[fd->num_entries].bus.csi2.dt =
+ ub960_fmt->datatype;
+ }
+
+ fd->num_entries++;
+ }
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int ub960_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct ub960_data *priv = sd_to_ub960(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ int ret = 0;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->streaming)
+ return -EBUSY;
+
+ /* No transcoding, source and sink formats must match. */
+ if (ub960_pad_is_source(priv, format->pad))
+ return v4l2_subdev_get_fmt(sd, state, format);
+
+ /* TODO: implement fmt validation */
+
+ v4l2_subdev_lock_state(state);
+
+ fmt = v4l2_state_get_stream_format(state, format->pad, format->stream);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *fmt = format->format;
+
+ fmt = v4l2_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ *fmt = format->format;
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int ub960_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct ub960_data *priv = sd_to_ub960(sd);
+
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = 0,
+ .sink_stream = 0,
+ .source_pad = priv->hw_data->num_rxports,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ };
+
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ return _ub960_set_routing(sd, state, &routing);
+}
+
+static const struct v4l2_subdev_pad_ops ub960_pad_ops = {
+ .set_routing = ub960_set_routing,
+ .get_frame_desc = ub960_get_frame_desc,
+
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = ub960_set_fmt,
+
+ .init_cfg = ub960_init_cfg,
+};
+
+static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = {
+ .log_status = v4l2_ctrl_subdev_log_status,
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops ub960_subdev_ops = {
+ .core = &ub960_subdev_core_ops,
+ .video = &ub960_video_ops,
+ .pad = &ub960_pad_ops,
+};
+
+static const struct media_entity_operations ub960_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+ .has_route = v4l2_subdev_has_route
+};
+
+static void ub960_enable_tpg(struct ub960_data *priv, int tpg_num)
+{
+ /*
+ * Note: no need to write UB960_REG_IND_ACC_CTL: the only indirect
+ * registers target we use is "CSI-2 Pattern Generator & Timing
+ * Registers", which is the default
+ */
+
+ /*
+ * TPG can only provide a single stream per CSI TX port. If
+ * multiple streams are currently enabled, only the first
+ * one will use the TPG, other streams will be halted.
+ */
+
+ struct v4l2_mbus_framefmt *fmt;
+ u8 vbp, vfp;
+ u16 blank_lines;
+ u16 width;
+ u16 height;
+
+ u16 bytespp = 2; /* For MEDIA_BUS_FMT_UYVY8_1X16 */
+ u8 cbars_idx = tpg_num - TEST_PATTERN_V_COLOR_BARS_1;
+ u8 num_cbars = 1 << cbars_idx;
+
+ u16 line_size; /* Line size [bytes] */
+ u16 bar_size; /* cbar size [bytes] */
+ u16 act_lpf; /* active lines/frame */
+ u16 tot_lpf; /* tot lines/frame */
+ u16 line_pd; /* Line period in 10-ns units */
+
+ struct v4l2_subdev_state *state;
+
+ state = v4l2_subdev_lock_active_state(&priv->sd);
+
+ vbp = 33;
+ vfp = 10;
+ blank_lines = vbp + vfp + 2; /* total blanking lines */
+
+ fmt = v4l2_state_get_stream_format(state, 4, 0);
+
+ width = fmt->width;
+ height = fmt->height;
+
+ line_size = width * bytespp;
+ bar_size = line_size / num_cbars;
+ act_lpf = height;
+ tot_lpf = act_lpf + blank_lines;
+ line_pd = 100000000 / 60 / tot_lpf;
+
+ /* Disable forwarding from FPD-3 RX ports */
+ ub960_write(priv, UB960_SR_FWD_CTL1,
+ UB960_SR_FWD_CTL1_PORT_DIS(0) |
+ UB960_SR_FWD_CTL1_PORT_DIS(1));
+
+ /* Access Indirect Pattern Gen */
+ ub960_write(priv, UB960_SR_IND_ACC_CTL,
+ UB960_SR_IND_ACC_CTL_IA_AUTO_INC | 0);
+
+ ub960_write_ind8(priv, UB960_IR_PGEN_CTL,
+ UB960_IR_PGEN_CTL_PGEN_ENABLE);
+
+ /* YUV422 8bit: 2 bytes/block, CSI-2 data type 0x1e */
+ ub960_write_ind8(priv, UB960_IR_PGEN_CFG, cbars_idx << 4 | 0x2);
+ ub960_write_ind8(priv, UB960_IR_PGEN_CSI_DI, 0x1e);
+
+ ub960_write_ind16(priv, UB960_IR_PGEN_LINE_SIZE1, line_size);
+ ub960_write_ind16(priv, UB960_IR_PGEN_BAR_SIZE1, bar_size);
+ ub960_write_ind16(priv, UB960_IR_PGEN_ACT_LPF1, act_lpf);
+ ub960_write_ind16(priv, UB960_IR_PGEN_TOT_LPF1, tot_lpf);
+ ub960_write_ind16(priv, UB960_IR_PGEN_LINE_PD1, line_pd);
+ ub960_write_ind8(priv, UB960_IR_PGEN_VBP, vbp);
+ ub960_write_ind8(priv, UB960_IR_PGEN_VFP, vfp);
+
+ v4l2_subdev_unlock_state(state);
+}
+
+static void ub960_disable_tpg(struct ub960_data *priv)
+{
+ /* TPG off, enable forwarding from FPD-3 RX ports */
+ ub960_write(priv, UB960_SR_FWD_CTL1, 0x00);
+
+ ub960_write_ind8(priv, UB960_IR_PGEN_CTL, 0x00);
+}
+
+static int ub960_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ub960_data *priv =
+ container_of(ctrl->handler, struct ub960_data, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_TEST_PATTERN:
+ if (ctrl->val == 0)
+ ub960_disable_tpg(priv);
+ else
+ ub960_enable_tpg(priv, ctrl->val);
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops ub960_ctrl_ops = {
+ .s_ctrl = ub960_s_ctrl,
+};
+
+/* -----------------------------------------------------------------------------
+ * Core
+ */
+
+static irqreturn_t ub960_handle_events(int irq, void *arg)
+{
+ struct ub960_data *priv = arg;
+ unsigned int i;
+ u8 int_sts;
+ int ret;
+
+ ret = ub960_read(priv, UB960_SR_INTERRUPT_STS, &int_sts);
+
+ if (!ret && int_sts) {
+ u8 fwd_sts;
+
+ dev_dbg(&priv->client->dev, "INTERRUPT_STS %x\n", int_sts);
+
+ ub960_read(priv, UB960_SR_FWD_STS, &fwd_sts);
+
+ dev_dbg(&priv->client->dev, "FWD_STS %#x\n", fwd_sts);
+
+ for (i = 0; i < priv->hw_data->num_txports; ++i) {
+ if (int_sts & UB960_SR_INTERRUPT_STS_IS_CSI_TX(i))
+ ub960_csi_handle_events(priv, i);
+ }
+
+ for (i = 0; i < priv->hw_data->num_rxports; i++) {
+ if (!priv->rxports[i] || !priv->rxports[i]->locked)
+ continue;
+
+ if (int_sts & UB960_SR_INTERRUPT_STS_IS_RX(i))
+ ub960_rxport_handle_events(priv, i);
+ }
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int ub960_run(void *arg)
+{
+ struct ub960_data *priv = arg;
+
+ while (!kthread_should_stop()) {
+ ub960_handle_events(0, priv);
+
+ msleep(500);
+ }
+
+ return 0;
+}
+
+static void ub960_remove_ports(struct ub960_data *priv)
+{
+ unsigned int i;
+
+ for (i = 0; i < priv->hw_data->num_rxports; i++)
+ if (priv->rxports[i])
+ ub960_rxport_remove_one(priv, i);
+
+ for (i = 0; i < priv->hw_data->num_txports; i++)
+ if (priv->txports[i])
+ ub960_txport_remove_one(priv, i);
+}
+
+static int ub960_parse_dt(struct ub960_data *priv)
+{
+ struct device_node *np = priv->client->dev.of_node;
+ struct device *dev = &priv->client->dev;
+ int ret = 0;
+ int n;
+
+ if (!np) {
+ dev_err(dev, "OF: no device tree node!\n");
+ return -ENOENT;
+ }
+
+ n = of_property_read_variable_u16_array(np, "i2c-alias-pool",
+ priv->atr_alias_id,
+ 2, UB960_MAX_POOL_ALIASES);
+ if (n < 0)
+ dev_warn(dev,
+ "OF: no i2c-alias-pool, can't access remote I2C slaves");
+
+ priv->atr_alias_num = n;
+
+ dev_dbg(dev, "i2c-alias-pool has %zu aliases", priv->atr_alias_num);
+
+ if (of_property_read_u32(np, "data-rate", &priv->tx_data_rate) != 0) {
+ dev_err(dev, "OF: %s: missing \"data-rate\" node\n",
+ of_node_full_name(np));
+ return -EINVAL;
+ }
+
+ if (priv->tx_data_rate != 1600000000 &&
+ priv->tx_data_rate != 1200000000 &&
+ priv->tx_data_rate != 800000000 &&
+ priv->tx_data_rate != 400000000) {
+ dev_err(dev, "OF: %s: invalid \"data-rate\" node\n",
+ of_node_full_name(np));
+ return -EINVAL;
+ }
+
+ priv->tx_link_freq[0] = priv->tx_data_rate / 2;
+
+ dev_dbg(dev, "Nominal data rate: %u", priv->tx_data_rate);
+
+ for (n = 0; n < priv->hw_data->num_rxports + priv->hw_data->num_txports; ++n) {
+ struct device_node *ep_np;
+
+ ep_np = of_graph_get_endpoint_by_regs(np, n, 0);
+ if (!ep_np)
+ continue;
+
+ if (n < priv->hw_data->num_rxports)
+ ret = ub960_rxport_probe_one(priv, ep_np, n);
+ else
+ ret = ub960_csiport_probe_one(
+ priv, ep_np, n - priv->hw_data->num_rxports);
+
+ of_node_put(ep_np);
+
+ if (ret)
+ break;
+ }
+
+ if (ret)
+ ub960_remove_ports(priv);
+
+ return ret;
+}
+
+static int ub960_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct ub960_data *priv = sd_to_ub960(notifier->sd);
+ struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport;
+ struct device *dev = &priv->client->dev;
+ u8 nport = rxport->nport;
+ unsigned int src_pad;
+ unsigned int i;
+ int ret;
+
+ dev_dbg(dev, "Bind %s\n", subdev->name);
+
+ ret = media_entity_get_fwnode_pad(&subdev->entity, rxport->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to find pad for %s\n", subdev->name);
+ return ret;
+ }
+
+ rxport->sd = subdev;
+ src_pad = ret;
+
+ ret = media_create_pad_link(&rxport->sd->entity, src_pad,
+ &priv->sd.entity, nport,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "Unable to link %s:%u -> %s:%u\n",
+ rxport->sd->name, src_pad, priv->sd.name, nport);
+ return ret;
+ }
+
+ dev_dbg(dev, "Bound %s pad: %u on index %u\n", subdev->name, src_pad,
+ nport);
+
+ for (i = 0; i < priv->hw_data->num_rxports; ++i) {
+ if (priv->rxports[i] && rxport->locked && !priv->rxports[i]->sd) {
+ dev_dbg(dev, "Waiting for more subdevs to be bound\n");
+ return 0;
+ }
+ }
+
+ dev_dbg(dev, "All subdevs bound\n");
+
+ return 0;
+}
+
+static void ub960_notify_unbind(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct ub960_data *priv = sd_to_ub960(notifier->sd);
+ struct ub960_rxport *rxport = to_ub960_asd(asd)->rxport;
+ struct device *dev = &priv->client->dev;
+
+ dev_dbg(dev, "Unbind %s\n", subdev->name);
+
+ rxport->sd = NULL;
+}
+
+static const struct v4l2_async_notifier_operations ub960_notify_ops = {
+ .bound = ub960_notify_bound,
+ .unbind = ub960_notify_unbind,
+};
+
+static int ub960_v4l2_notifier_register(struct ub960_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int i;
+ int ret;
+
+ v4l2_async_notifier_init(&priv->notifier);
+
+ for (i = 0; i < priv->hw_data->num_rxports; ++i) {
+ struct ub960_rxport *rxport = priv->rxports[i];
+ struct v4l2_async_subdev *asd;
+ struct ub960_asd *ubasd;
+
+ if (!rxport || !rxport->locked)
+ continue;
+
+ asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier,
+ rxport->fwnode,
+ sizeof(*ubasd));
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev for source %u: %ld",
+ i, PTR_ERR(asd));
+ v4l2_async_notifier_cleanup(&priv->notifier);
+ return PTR_ERR(asd);
+ }
+
+ ubasd = to_ub960_asd(asd);
+ ubasd->rxport = rxport;
+ }
+
+ priv->notifier.ops = &ub960_notify_ops;
+
+ ret = v4l2_async_subdev_notifier_register(&priv->sd, &priv->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register subdev_notifier");
+ v4l2_async_notifier_cleanup(&priv->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static void ub960_v4l2_notifier_unregister(struct ub960_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ dev_dbg(dev, "Unregister async notif\n");
+
+ v4l2_async_notifier_unregister(&priv->notifier);
+ v4l2_async_notifier_cleanup(&priv->notifier);
+}
+
+static int ub960_create_subdev(struct ub960_data *priv)
+{
+ struct device *dev = &priv->client->dev;
+ unsigned int i;
+ int ret;
+
+ v4l2_i2c_subdev_init(&priv->sd, priv->client, &ub960_subdev_ops);
+ v4l2_ctrl_handler_init(&priv->ctrl_handler,
+ ARRAY_SIZE(ub960_tpg_qmenu) - 1);
+ priv->sd.ctrl_handler = &priv->ctrl_handler;
+
+ v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler, &ub960_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(ub960_tpg_qmenu) - 1, 0, 0,
+ ub960_tpg_qmenu);
+
+ v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(priv->tx_link_freq) - 1, 0,
+ priv->tx_link_freq);
+
+ if (priv->ctrl_handler.error) {
+ ret = priv->ctrl_handler.error;
+ goto err_free_ctrl;
+ }
+
+ priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS |
+ V4L2_SUBDEV_FL_MULTIPLEXED;
+ priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ priv->sd.entity.ops = &ub960_entity_ops;
+
+ for (i = 0; i < priv->hw_data->num_rxports + priv->hw_data->num_txports; i++) {
+ priv->pads[i].flags = ub960_pad_is_sink(priv, i) ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+ }
+
+ ret = media_entity_pads_init(&priv->sd.entity,
+ priv->hw_data->num_rxports +
+ priv->hw_data->num_txports,
+ priv->pads);
+ if (ret)
+ goto err_free_ctrl;
+
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = ub960_v4l2_notifier_register(priv);
+ if (ret) {
+ dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret);
+ goto err_free_state;
+ }
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret) {
+ dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret);
+ goto err_unreg_notif;
+ }
+
+ return 0;
+
+err_unreg_notif:
+ ub960_v4l2_notifier_unregister(priv);
+err_free_state:
+ v4l2_subdev_cleanup(&priv->sd);
+err_entity_cleanup:
+ media_entity_cleanup(&priv->sd.entity);
+err_free_ctrl:
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+
+ return ret;
+}
+
+static void ub960_destroy_subdev(struct ub960_data *priv)
+{
+ ub960_v4l2_notifier_unregister(priv);
+ v4l2_async_unregister_subdev(&priv->sd);
+
+ v4l2_subdev_cleanup(&priv->sd);
+
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+}
+
+static const struct regmap_config ub960_regmap_config = {
+ .name = "ds90ub960",
+
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = 0xff,
+};
+
+static void ub960_sw_reset(struct ub960_data *priv)
+{
+ unsigned int i;
+
+ ub960_write(priv, UB960_SR_RESET, BIT(1));
+
+ for (i = 0; i < 10; ++i) {
+ int ret;
+ u8 v;
+
+ ret = ub960_read(priv, UB960_SR_RESET, &v);
+
+ if (ret || v == 0)
+ break;
+ }
+}
+
+static int ub960_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct ub960_data *priv;
+ unsigned int nport;
+ struct clk *clk;
+ u8 rev_mask;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ priv->hw_data = of_device_get_match_data(dev);
+ if (!priv->hw_data)
+ return -ENODEV;
+
+ mutex_init(&priv->alias_table_lock);
+
+ priv->regmap = devm_regmap_init_i2c(client, &ub960_regmap_config);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ /* get power-down pin from DT */
+ priv->pd_gpio = devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->pd_gpio)) {
+ ret = PTR_ERR(priv->pd_gpio);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Cannot get powerdown GPIO (%d)", ret);
+ return ret;
+ }
+
+ if (priv->pd_gpio) {
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+ /* wait min 2 ms for reset to complete */
+ usleep_range(2000, 5000);
+ gpiod_set_value_cansleep(priv->pd_gpio, 0);
+ /* wait min 2 ms for power up to finish */
+ usleep_range(2000, 5000);
+ } else {
+ /* Use SW reset if we don't have PD gpio */
+ ub960_sw_reset(priv);
+ }
+
+ clk = clk_get(dev, NULL);
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ if (ret != -EPROBE_DEFER)
+ dev_err(dev, "Cannot get REFCLK (%d)", ret);
+ return ret;
+ }
+ priv->refclk = clk_get_rate(clk);
+ clk_put(clk);
+ dev_dbg(dev, "REFCLK %lu", priv->refclk);
+
+ /* Runtime check register accessibility */
+ ret = ub960_read(priv, UB960_SR_REV_MASK, &rev_mask);
+ if (ret) {
+ dev_err(dev, "Cannot read first register (%d), abort\n", ret);
+ goto err_reg_read;
+ }
+
+ ret = ub960_atr_probe(priv);
+ if (ret)
+ goto err_atr_probe;
+
+ ret = ub960_parse_dt(priv);
+ if (ret)
+ goto err_parse_dt;
+
+ ret = ub960_rxport_probe_serializers(priv);
+ if (ret)
+ goto err_parse_dt;
+
+ /*
+ * Clear any errors caused by switching the RX port settings while
+ * probing.
+ */
+ for (nport = 0; nport < priv->hw_data->num_rxports; ++nport) {
+ u8 dummy;
+
+ ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS1, &dummy);
+ ub960_rxport_read(priv, nport, UB960_RR_RX_PORT_STS2, &dummy);
+ ub960_rxport_read(priv, nport, UB960_RR_CSI_RX_STS, &dummy);
+ ub960_rxport_read(priv, nport, UB960_RR_BCC_STATUS, &dummy);
+ }
+
+ ret = ub960_create_subdev(priv);
+ if (ret)
+ goto err_subdev;
+
+ if (client->irq) {
+ dev_dbg(dev, "using IRQ %d\n", client->irq);
+
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ ub960_handle_events,
+ IRQF_ONESHOT, client->name,
+ priv);
+ if (ret) {
+ dev_err(dev, "Cannot enable IRQ (%d)\n", ret);
+ goto err_irq;
+ }
+
+ /* Disable GPIO3 as input */
+ ub960_update_bits_shared(priv, UB960_SR_GPIO_INPUT_CTL, BIT(3),
+ 0);
+ /* Enable GPIO3 as output, active low interrupt */
+ ub960_write(priv, UB960_SR_GPIO_PIN_CTL(3), 0xd1);
+
+ ub960_write(priv, UB960_SR_INTERRUPT_CTL,
+ UB960_SR_INTERRUPT_CTL_ALL);
+ } else {
+ /* No IRQ, fallback to polling */
+
+ priv->kthread = kthread_run(ub960_run, priv, dev_name(dev));
+ if (IS_ERR(priv->kthread)) {
+ ret = PTR_ERR(priv->kthread);
+ dev_err(dev, "Cannot create kthread (%d)\n", ret);
+ goto err_kthread;
+ }
+ dev_dbg(dev, "using polling mode\n");
+ }
+
+ dev_info(dev, "Successfully probed (rev/mask %02x)\n", rev_mask);
+
+ return 0;
+
+err_kthread:
+err_irq:
+ ub960_destroy_subdev(priv);
+err_subdev:
+ ub960_remove_ports(priv);
+err_parse_dt:
+ ub960_atr_remove(priv);
+err_atr_probe:
+err_reg_read:
+ if (priv->pd_gpio)
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+ mutex_destroy(&priv->alias_table_lock);
+ return ret;
+}
+
+static int ub960_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ub960_data *priv = sd_to_ub960(sd);
+
+ dev_dbg(&client->dev, "Removing\n");
+
+ if (priv->kthread)
+ kthread_stop(priv->kthread);
+ ub960_destroy_subdev(priv);
+ ub960_remove_ports(priv);
+ ub960_atr_remove(priv);
+ if (priv->pd_gpio)
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+ mutex_destroy(&priv->alias_table_lock);
+
+ dev_dbg(&client->dev, "Remove done\n");
+
+ return 0;
+}
+
+static const struct ub960_hw_data ds90ub960_hw = {
+ .num_rxports = 4,
+ .num_txports = 2,
+};
+
+static const struct i2c_device_id ub960_id[] = {
+ { "ds90ub960-q1", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ub960_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id ub960_dt_ids[] = {
+ { .compatible = "ti,ds90ub960-q1", .data = &ds90ub960_hw },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ub960_dt_ids);
+#endif
+
+static struct i2c_driver ds90ub960_driver = {
+ .probe_new = ub960_probe,
+ .remove = ub960_remove,
+ .id_table = ub960_id,
+ .driver = {
+ .name = "ds90ub960",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ub960_dt_ids),
+ },
+};
+
+module_i2c_driver(ds90ub960_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Texas Instruments DS90UB960-Q1 FPDLink-3 deserializer driver");
+MODULE_AUTHOR("Luca Ceresoli <luca@lucaceresoli.net>");
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>");
diff --git a/drivers/media/i2c/imx390.c b/drivers/media/i2c/imx390.c
new file mode 100644
index 000000000000..a81896401f00
--- /dev/null
+++ b/drivers/media/i2c/imx390.c
@@ -0,0 +1,900 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Sony IMX390 CMOS Image Sensor Driver
+ *
+ * Copyright (c) 2021 Apurva Nandan <a-nandan@ti.com>
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+#include "imx390.h"
+
+static inline struct imx390 *to_imx390(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct imx390, subdev);
+}
+
+static int imx390_read(struct imx390 *imx390, u16 addr, u32 *val, size_t nbytes)
+{
+ int ret;
+ __le32 val_le = 0;
+
+ ret = regmap_bulk_read(imx390->regmap, addr, &val_le, nbytes);
+ if (ret < 0) {
+ dev_err(imx390->dev, "%s: failed to read reg 0x%04x: %d\n",
+ __func__, addr, ret);
+ return ret;
+ }
+
+ *val = le32_to_cpu(val_le);
+ return 0;
+}
+
+static int imx390_write(struct imx390 *imx390, u16 addr, u32 val, size_t nbytes)
+{
+ int ret;
+ __le32 val_le = cpu_to_le32(val);
+
+ ret = regmap_bulk_write(imx390->regmap, addr, &val_le, nbytes);
+ if (ret < 0)
+ dev_err(imx390->dev, "%s: failed to write reg 0x%04x: %d\n",
+ __func__, addr, ret);
+ return ret;
+}
+
+static int imx390_update_bits(struct imx390 *imx390, u16 addr, u32 val,
+ u32 mask, size_t nbytes)
+{
+ int ret;
+ u32 cfg;
+
+ ret = imx390_read(imx390, addr, &cfg, nbytes);
+ if (ret < 0)
+ return ret;
+
+ cfg = (val) ? (cfg | mask) : (cfg & (~mask));
+
+ return imx390_write(imx390, addr, cfg, nbytes);
+}
+
+static int imx390_write_table(struct imx390 *imx390,
+ const struct reg_sequence *regs,
+ unsigned int nr_regs)
+{
+ int ret;
+
+ ret = regmap_multi_reg_write(imx390->regmap, regs, nr_regs);
+ if (ret < 0)
+ dev_err(imx390->dev,
+ "%s: failed to write reg table (%d)!\n", __func__, ret);
+ return ret;
+}
+
+static void imx390_init_formats(struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *format;
+
+ format = v4l2_state_get_stream_format(state, 0, 0);
+ format->code = imx390_mbus_formats[0];
+ format->width = imx390_framesizes[0].width;
+ format->height = imx390_framesizes[0].height;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SMPTE170M;
+}
+
+static int _imx390_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .source_pad = 0,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_IMMUTABLE |
+ V4L2_SUBDEV_ROUTE_FL_SOURCE |
+ V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ {
+ .source_pad = 0,
+ .source_stream = 1,
+ .flags = V4L2_SUBDEV_ROUTE_FL_IMMUTABLE |
+ V4L2_SUBDEV_ROUTE_FL_SOURCE,
+ }
+ };
+
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ int ret;
+
+ ret = v4l2_subdev_set_routing(sd, state, &routing);
+ if (ret < 0)
+ return ret;
+
+ imx390_init_formats(state);
+
+ return 0;
+}
+
+static int imx390_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ int ret;
+
+ v4l2_subdev_lock_state(state);
+
+ ret = _imx390_set_routing(sd, state);
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int imx390_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(imx390_mbus_formats))
+ return -EINVAL;
+
+ code->code = imx390_mbus_formats[code->index];
+
+ return 0;
+}
+
+static int imx390_enum_frame_sizes(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx390_mbus_formats); ++i) {
+ if (imx390_mbus_formats[i] == fse->code)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(imx390_mbus_formats))
+ return -EINVAL;
+
+ if (fse->index >= ARRAY_SIZE(imx390_framesizes))
+ return -EINVAL;
+
+ fse->min_width = imx390_framesizes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->max_height = imx390_framesizes[fse->index].height;
+ fse->min_height = fse->max_height;
+
+ return 0;
+}
+
+static int imx390_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct imx390 *imx390 = to_imx390(sd);
+ struct v4l2_mbus_framefmt *format;
+ const struct v4l2_area *fsize;
+ unsigned int i;
+ u32 code;
+ int ret = 0;
+
+ if (fmt->pad != 0)
+ return -EINVAL;
+
+ if (fmt->stream != 0)
+ return -EINVAL;
+
+ /*
+ * Validate the media bus code, defaulting to the first one if the
+ * requested code isn't supported.
+ */
+ for (i = 0; i < ARRAY_SIZE(imx390_mbus_formats); ++i) {
+ if (imx390_mbus_formats[i] == fmt->format.code) {
+ code = fmt->format.code;
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(imx390_mbus_formats))
+ code = imx390_mbus_formats[0];
+
+ /* Find the nearest supported frame size. */
+ fsize = v4l2_find_nearest_size(imx390_framesizes,
+ ARRAY_SIZE(imx390_framesizes), width,
+ height, fmt->format.width,
+ fmt->format.height);
+
+ v4l2_subdev_lock_state(state);
+
+ /* Update the stored format and return it. */
+ format = v4l2_state_get_stream_format(state, fmt->pad, fmt->stream);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && imx390->streaming) {
+ ret = -EBUSY;
+ goto done;
+ }
+
+ format->code = code;
+ format->width = fsize->width;
+ format->height = fsize->height;
+
+ fmt->format = *format;
+
+done:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int imx390_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *fmt;
+ u32 bpp;
+ int ret = 0;
+
+ if (pad != 0)
+ return -EINVAL;
+
+ state = v4l2_subdev_lock_active_state(sd);
+
+ fmt = v4l2_state_get_stream_format(state, 0, 0);
+ if (!fmt) {
+ ret = -EPIPE;
+ goto out;
+ }
+
+ memset(fd, 0, sizeof(*fd));
+
+ fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+
+ /* pixel stream */
+
+ bpp = 12;
+
+ fd->entry[fd->num_entries].stream = 0;
+
+ fd->entry[fd->num_entries].flags = V4L2_MBUS_FRAME_DESC_FL_LEN_MAX;
+ fd->entry[fd->num_entries].length = fmt->width * fmt->height * bpp / 8;
+ fd->entry[fd->num_entries].pixelcode = fmt->code;
+ fd->entry[fd->num_entries].bus.csi2.vc = 0;
+ fd->entry[fd->num_entries].bus.csi2.dt = 0x2c; /* SRGGB12 */
+
+ fd->num_entries++;
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int imx390_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ int ret;
+
+ if (routing->num_routes == 0 || routing->num_routes > 1)
+ return -EINVAL;
+
+ v4l2_subdev_lock_state(state);
+
+ ret = _imx390_set_routing(sd, state);
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int imx390_check_non_wdr_mode_fps(struct imx390 *imx390, bool enable)
+{
+ if (!enable && imx390->fps > IMX390_FRAMERATE_MAX_LINEAR) {
+ dev_err(imx390->dev,
+ "%s: failed, %dFPS unsupported in non-WDR mode\n",
+ __func__, imx390->fps);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int imx390_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx390 *imx390 = container_of(ctrl->handler,
+ struct imx390, ctrl.handler);
+ int ret;
+
+ dev_dbg(imx390->dev,
+ "%s: %s, value: %d\n", __func__, ctrl->name, ctrl->val);
+
+ /* V4L2 controls values will be applied only when power is already up */
+ if (!pm_runtime_get_if_in_use(imx390->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_WIDE_DYNAMIC_RANGE:
+ ret = imx390_check_non_wdr_mode_fps(imx390, ctrl->val);
+ break;
+
+ case V4L2_CID_EXPOSURE:
+ ret = imx390_write(imx390, IMX390_REG_CAT0_SHS1,
+ IMX390_EXPOSURE_SHS_VAL(ctrl->val,
+ imx390->fps), 3);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = imx390_write(imx390, IMX390_REG_CAT0_AGAIN_SP1H,
+ ctrl->val, 2);
+ if (ret < 0)
+ break;
+
+ ret = imx390_write(imx390, IMX390_REG_CAT0_AGAIN_SP1L,
+ ctrl->val / IMX390_AGAIN_CONV_GAIN_RATIO, 2);
+ break;
+
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = imx390_write(imx390, IMX390_REG_CAT0_PGA_GAIN,
+ ctrl->val, 2);
+ break;
+
+ case V4L2_CID_RED_BALANCE:
+ ret = imx390_write(imx390, IMX390_REG_CAT0_WBGAIN_R,
+ ctrl->val, 2);
+ break;
+
+ case V4L2_CID_BLUE_BALANCE:
+ ret = imx390_write(imx390, IMX390_REG_CAT0_WBGAIN_B,
+ ctrl->val, 2);
+ break;
+
+ case V4L2_CID_HFLIP:
+ ret = imx390_update_bits(imx390, IMX390_REG_CAT0_V_H_REVERSE,
+ ctrl->val, IMX390_H_REV_MASK, 1);
+ if (ret < 0)
+ break;
+
+ ret = imx390_update_bits(imx390, IMX390_REG_SM_CFG_REVERSE_APL,
+ ctrl->val, IMX390_H_REV_APL_MASK, 1);
+ break;
+
+ case V4L2_CID_VFLIP:
+ ret = imx390_update_bits(imx390, IMX390_REG_CAT0_V_H_REVERSE,
+ ctrl->val, IMX390_V_REV_MASK, 1);
+ if (ret < 0)
+ break;
+
+ ret = imx390_update_bits(imx390, IMX390_REG_SM_CFG_REVERSE_APL,
+ ctrl->val, IMX390_V_REV_APL_MASK, 1);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx390_write(imx390, IMX390_REG_CAT0_PGMODE_PGREGEN,
+ imx390_pg_mode_reg_val[ctrl->val], 1);
+ if (ret < 0)
+ break;
+
+ ret = imx390_update_bits(imx390, IMX390_SM_CFG_SM_PGREGEN_APL,
+ ctrl->val, IMX390_SM_PG_APL_MASK, 1);
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ pm_runtime_put_noidle(imx390->dev);
+ return ret;
+}
+
+static int imx390_detect(struct imx390 *imx390)
+{
+ int ret;
+ u32 id;
+
+ ret = imx390_read(imx390, IMX390_REG_VERSION_ROM_VERSION, &id, 2);
+ if (ret < 0)
+ return ret;
+
+ if (id != IMX390_ROM_VERSION) {
+ dev_err(imx390->dev,
+ "%s: unknown chip ID 0x%04x\n", __func__, id);
+ return -ENODEV;
+ }
+
+ dev_dbg(imx390->dev, "%s: detected chip ID 0x%04x\n", __func__, id);
+ return 0;
+}
+
+static int imx390_power_on(struct imx390 *imx390)
+{
+ int ret;
+
+ ret = clk_prepare_enable(imx390->clk);
+ if (ret < 0)
+ return ret;
+
+ if (imx390->xclr_gpio) {
+ gpiod_set_value_cansleep(imx390->xclr_gpio, 1);
+ /* Keep the XCLR pin on Low for 100 us or longer */
+ usleep_range(100, 1000);
+ gpiod_set_value_cansleep(imx390->xclr_gpio, 0);
+ /* It takes max 30 ms for the sensor to be ready */
+ msleep(30);
+ }
+ return 0;
+}
+
+static void imx390_power_off(struct imx390 *imx390)
+{
+ if (imx390->xclr_gpio) {
+ gpiod_set_value_cansleep(imx390->xclr_gpio, 1);
+ /* Wait for the XCLR pin to be Low for atleast 1 us */
+ usleep_range(1, 10);
+ }
+
+ clk_disable_unprepare(imx390->clk);
+}
+
+static int imx390_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct imx390 *imx390 = to_imx390(sd);
+
+ fi->interval.numerator = 1;
+ fi->interval.denominator = imx390->fps;
+ return 0;
+}
+
+static int imx390_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct imx390 *imx390 = to_imx390(sd);
+ struct v4l2_ctrl *ctrl = imx390->ctrl.exposure;
+ u32 req_fps;
+ int ret;
+
+ mutex_lock(&imx390->lock);
+
+ if (fi->interval.numerator == 0 || fi->interval.denominator == 0) {
+ fi->interval.denominator = IMX390_FRAMERATE_DEFAULT;
+ fi->interval.numerator = 1;
+ }
+
+ req_fps = clamp_val(DIV_ROUND_CLOSEST(fi->interval.denominator,
+ fi->interval.numerator),
+ IMX390_FRAMERATE_MIN, IMX390_FRAMERATE_MAX);
+
+ fi->interval.numerator = 1;
+ fi->interval.denominator = req_fps;
+
+ imx390->fps = req_fps;
+
+ ret = __v4l2_ctrl_modify_range(ctrl, 0, IMX390_EXPOSURE_MAX(req_fps), 1,
+ IMX390_EXPOSURE_DEFAULT);
+ if (ret < 0) {
+ dev_err(imx390->dev,
+ "%s: exposure ctrl range update failed %d\n",
+ __func__, ret);
+ }
+
+ mutex_unlock(&imx390->lock);
+ dev_dbg(imx390->dev, "%s frame rate = %d\n", __func__, imx390->fps);
+
+ return ret;
+}
+
+static int imx390_start_stream(struct imx390 *imx390)
+{
+ int ret;
+
+ if (!imx390->ctrl.wdr->val &&
+ imx390->fps <= IMX390_FRAMERATE_MAX_LINEAR)
+ ret = imx390_write_table(imx390, imx390_linear_1936x1096,
+ ARRAY_SIZE(imx390_linear_1936x1096));
+ else
+ ret = imx390_write_table(imx390, imx390_wdr_1936x1096,
+ ARRAY_SIZE(imx390_wdr_1936x1096));
+ if (ret < 0)
+ return ret;
+
+ msleep(100);
+
+ /* Restore the V4L2 control values into the registers */
+ ret = __v4l2_ctrl_handler_setup(imx390->subdev.ctrl_handler);
+ if (ret < 0) {
+ dev_err(imx390->dev,
+ "%s: failed to apply v4l2 ctrls: %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = imx390_write(imx390, IMX390_REG_MODE_HMAX,
+ (u32)IMX390_FPS_TO_MODE_HMAX(imx390->fps), 2);
+ if (ret < 0)
+ return ret;
+
+ /* Set active */
+ ret = imx390_write(imx390, IMX390_REG_CAT0_STANDBY, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* No communication is possible for a while after exiting standby */
+ msleep(20);
+
+ return 0;
+}
+
+static int imx390_stop_stream(struct imx390 *imx390)
+{
+ int ret;
+
+ /* Set standby */
+ ret = imx390_write(imx390, IMX390_REG_CAT0_STANDBY, 1, 1);
+ if (ret < 0)
+ return ret;
+
+ /* No communication is possible for a while after entering standby */
+ usleep_range(10000, 20000);
+ return 0;
+}
+
+static int imx390_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct imx390 *imx390 = to_imx390(sd);
+ int ret;
+
+ mutex_lock(&imx390->lock);
+ if (imx390->streaming == enable) {
+ mutex_unlock(&imx390->lock);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_get_sync(imx390->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(imx390->dev);
+ goto err_unlock;
+ }
+
+ ret = imx390_start_stream(imx390);
+ if (ret < 0)
+ goto err_runtime_put;
+ } else {
+ ret = imx390_stop_stream(imx390);
+ if (ret < 0)
+ goto err_runtime_put;
+ pm_runtime_mark_last_busy(imx390->dev);
+ pm_runtime_put_autosuspend(imx390->dev);
+ }
+
+ imx390->streaming = enable;
+ /* WDR, HFLIP, VFLIP, TEST PATTERN cannot change during streaming */
+ __v4l2_ctrl_grab(imx390->ctrl.wdr, enable);
+ __v4l2_ctrl_grab(imx390->ctrl.h_flip, enable);
+ __v4l2_ctrl_grab(imx390->ctrl.v_flip, enable);
+ __v4l2_ctrl_grab(imx390->ctrl.pg_mode, enable);
+
+ mutex_unlock(&imx390->lock);
+ return 0;
+
+err_runtime_put:
+ pm_runtime_put(imx390->dev);
+
+err_unlock:
+ mutex_unlock(&imx390->lock);
+ dev_err(imx390->dev,
+ "%s: failed to setup streaming %d\n", __func__, ret);
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops imx390_subdev_video_ops = {
+ .g_frame_interval = imx390_get_frame_interval,
+ .s_frame_interval = imx390_set_frame_interval,
+ .s_stream = imx390_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops imx390_subdev_pad_ops = {
+ .init_cfg = imx390_init_cfg,
+ .enum_mbus_code = imx390_enum_mbus_code,
+ .enum_frame_size = imx390_enum_frame_sizes,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = imx390_set_fmt,
+ .set_routing = imx390_set_routing,
+ .get_frame_desc = imx390_get_frame_desc,
+};
+
+static const struct v4l2_subdev_ops imx390_subdev_ops = {
+ .video = &imx390_subdev_video_ops,
+ .pad = &imx390_subdev_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops imx390_ctrl_ops = {
+ .s_ctrl = imx390_set_ctrl,
+};
+
+static int imx390_probe(struct i2c_client *client)
+{
+ struct imx390 *imx390;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *ctrl_hdr;
+ int ret;
+
+ imx390 = devm_kzalloc(&client->dev, sizeof(*imx390), GFP_KERNEL);
+ if (!imx390)
+ return -ENOMEM;
+
+ imx390->dev = &client->dev;
+
+ imx390->regmap = devm_regmap_init_i2c(client, &imx390_regmap_config);
+ if (IS_ERR(imx390->regmap))
+ return PTR_ERR(imx390->regmap);
+
+ imx390->xclr_gpio = devm_gpiod_get_optional(imx390->dev,
+ "xclr", GPIOD_OUT_LOW);
+ if (IS_ERR(imx390->xclr_gpio))
+ return PTR_ERR(imx390->xclr_gpio);
+
+ imx390->clk = devm_clk_get(imx390->dev, "inck");
+ if (IS_ERR(imx390->clk))
+ return PTR_ERR(imx390->clk);
+
+ imx390->clk_rate = clk_get_rate(imx390->clk);
+ dev_info(imx390->dev, "inck rate: %lu Hz\n", imx390->clk_rate);
+
+ if (imx390->clk_rate < 6000000 || imx390->clk_rate > 27000000)
+ return -EINVAL;
+
+ ret = imx390_power_on(imx390);
+ if (ret < 0)
+ return ret;
+
+ ret = imx390_detect(imx390);
+ if (ret < 0)
+ return ret;
+
+ /* Initialize the subdev and its controls. */
+ sd = &imx390->subdev;
+ v4l2_i2c_subdev_init(sd, client, &imx390_subdev_ops);
+
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS |
+ V4L2_SUBDEV_FL_MULTIPLEXED;
+
+ /* Initialize the media entity. */
+ imx390->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &imx390->pad);
+ if (ret < 0) {
+ dev_err(imx390->dev,
+ "%s: media entity init failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ /* Initialize controls */
+ ctrl_hdr = &imx390->ctrl.handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdr, 9);
+ if (ret < 0) {
+ dev_err(imx390->dev,
+ "%s: ctrl handler init failed: %d\n", __func__, ret);
+ goto err_media_cleanup;
+ }
+
+ mutex_init(&imx390->lock);
+ imx390->ctrl.handler.lock = &imx390->lock;
+ imx390->fps = IMX390_FRAMERATE_DEFAULT;
+
+ /* Add new controls */
+ imx390->ctrl.exposure = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0,
+ IMX390_EXPOSURE_MAX(imx390->fps),
+ 1, IMX390_EXPOSURE_DEFAULT);
+
+ imx390->ctrl.again = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 0,
+ IMX390_ANALOG_GAIN_MAX, 1,
+ IMX390_ANALOG_GAIN_DEFAULT);
+
+ imx390->ctrl.dgain = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_DIGITAL_GAIN, 0,
+ IMX390_DIGITAL_GAIN_MAX, 1,
+ IMX390_DIGITAL_GAIN_DEFAULT);
+
+ imx390->ctrl.r_balance = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0,
+ IMX390_R_B_BALANCE_MAX, 1,
+ IMX390_R_B_BALANCE_DEFAULT);
+
+ imx390->ctrl.b_balance = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0,
+ IMX390_R_B_BALANCE_MAX, 1,
+ IMX390_R_B_BALANCE_DEFAULT);
+
+ imx390->ctrl.wdr = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_WIDE_DYNAMIC_RANGE,
+ 0, 1, 1, 1);
+
+ imx390->ctrl.h_flip = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+
+ imx390->ctrl.v_flip = v4l2_ctrl_new_std(ctrl_hdr, &imx390_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+
+ imx390->ctrl.pg_mode = v4l2_ctrl_new_std_menu_items(ctrl_hdr,
+ &imx390_ctrl_ops, V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx390_ctrl_pg_qmenu) - 1,
+ 0, 0, imx390_ctrl_pg_qmenu);
+
+ imx390->subdev.ctrl_handler = ctrl_hdr;
+ if (imx390->ctrl.handler.error) {
+ ret = imx390->ctrl.handler.error;
+ dev_err(imx390->dev,
+ "%s: failed to add the ctrls: %d\n", __func__, ret);
+ goto err_ctrl_free;
+ }
+
+ pm_runtime_set_active(imx390->dev);
+ pm_runtime_enable(imx390->dev);
+ pm_runtime_set_autosuspend_delay(imx390->dev, IMX390_PM_IDLE_TIMEOUT);
+ pm_runtime_use_autosuspend(imx390->dev);
+ pm_runtime_get_noresume(imx390->dev);
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0)
+ goto err_pm_disable;
+
+ /* Finally, register the subdev. */
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0) {
+ dev_err(imx390->dev,
+ "%s: v4l2 subdev register failed %d\n", __func__, ret);
+ goto err_subdev_cleanup;
+ }
+
+ dev_info(imx390->dev, "imx390 probed\n");
+ pm_runtime_mark_last_busy(imx390->dev);
+ pm_runtime_put_autosuspend(imx390->dev);
+ return 0;
+
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(&imx390->subdev);
+
+err_pm_disable:
+ pm_runtime_dont_use_autosuspend(imx390->dev);
+ pm_runtime_put_noidle(imx390->dev);
+ pm_runtime_disable(imx390->dev);
+
+err_ctrl_free:
+ v4l2_ctrl_handler_free(ctrl_hdr);
+ mutex_destroy(&imx390->lock);
+
+err_media_cleanup:
+ media_entity_cleanup(&imx390->subdev.entity);
+
+ return ret;
+}
+
+static int __maybe_unused imx390_runtime_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx390 *imx390 = to_imx390(sd);
+ int ret;
+
+ ret = imx390_power_on(imx390);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static int __maybe_unused imx390_runtime_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx390 *imx390 = to_imx390(sd);
+
+ imx390_power_off(imx390);
+
+ return 0;
+}
+
+static int __maybe_unused imx390_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx390 *imx390 = to_imx390(sd);
+ int ret;
+
+ if (imx390->streaming)
+ imx390_stop_stream(imx390);
+
+ ret = pm_runtime_force_suspend(dev);
+ if (ret < 0)
+ dev_warn(dev, "%s: failed to suspend: %i\n", __func__, ret);
+
+ return 0;
+}
+
+static int __maybe_unused imx390_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx390 *imx390 = to_imx390(sd);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ dev_warn(dev, "%s: failed to resume: %i\n", __func__, ret);
+
+ if (imx390->streaming)
+ ret = imx390_start_stream(imx390);
+
+ if (ret < 0) {
+ imx390_stop_stream(imx390);
+ imx390->streaming = 0;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int imx390_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx390 *imx390 = to_imx390(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&imx390->ctrl.handler);
+ v4l2_subdev_cleanup(&imx390->subdev);
+ media_entity_cleanup(&sd->entity);
+ mutex_destroy(&imx390->lock);
+
+ pm_runtime_disable(imx390->dev);
+ pm_runtime_dont_use_autosuspend(imx390->dev);
+ pm_runtime_set_suspended(imx390->dev);
+
+ return 0;
+}
+
+static const struct dev_pm_ops imx390_pm_ops = {
+ SET_RUNTIME_PM_OPS(imx390_runtime_suspend,
+ imx390_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(imx390_suspend, imx390_resume)
+};
+
+static const struct of_device_id imx390_dt_id[] = {
+ { .compatible = "sony,imx390" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, imx390_dt_id);
+
+static struct i2c_driver imx390_i2c_driver = {
+ .driver = {
+ .name = "imx390",
+ .of_match_table = of_match_ptr(imx390_dt_id),
+ .pm = &imx390_pm_ops,
+ },
+ .probe_new = imx390_probe,
+ .remove = imx390_remove,
+};
+
+module_i2c_driver(imx390_i2c_driver);
+
+MODULE_DESCRIPTION("Camera Sensor Driver for Sony IMX390");
+MODULE_AUTHOR("Apurva Nandan <a-nandan@ti.com>");
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/imx390.h b/drivers/media/i2c/imx390.h
new file mode 100644
index 000000000000..30e518afb163
--- /dev/null
+++ b/drivers/media/i2c/imx390.h
@@ -0,0 +1,7158 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Sony IMX390 CMOS Image Sensor Driver
+ *
+ * Copyright (c) 2021 Apurva Nandan <a-nandan@ti.com>
+ *
+ * Copyright (c) 2021 Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
+ */
+
+#include <linux/types.h>
+
+#define IMX390_ACTIVE_AREA_WIDTH 1936
+#define IMX390_ACTIVE_AREA_HEIGHT 1096
+
+/* SMPG cannot be disabled, and datatype is the same as the pixel data */
+#define IMX390_SMPG_HEIGHT 4
+
+#define IMX390_OUT_WIDTH IMX390_ACTIVE_AREA_WIDTH
+#define IMX390_OUT_HEIGHT (IMX390_ACTIVE_AREA_HEIGHT + IMX390_SMPG_HEIGHT)
+
+#define IMX390_FRAMERATE_DEFAULT 30
+#define IMX390_FRAMERATE_MIN 25
+#define IMX390_FRAMERATE_MAX 60
+#define IMX390_FRAMERATE_MAX_LINEAR 30
+
+#define IMX390_MODE_VMAX 0x465
+#define IMX390_MODE_HMAX_DEFAULT 0x1130
+#define IMX390_REG_MODE_HMAX 0x200C
+#define IMX390_FPS_TO_MODE_HMAX(_fps) \
+ ((IMX390_MODE_HMAX_DEFAULT * IMX390_FRAMERATE_DEFAULT) / (_fps))
+
+#define IMX390_REG_VERSION_ROM_VERSION 0x0330
+#define IMX390_ROM_VERSION 0x3815
+
+#define IMX390_REG_CAT0_STANDBY 0x0000
+
+/* Exposure control */
+#define IMX390_REG_CAT0_SHS1 0x000C
+#define IMX390_EXPOSURE_LINES_MAX (IMX390_MODE_VMAX - 2)
+#define IMX390_EXPOSURE_MAX(_fps) \
+ ((IMX390_EXPOSURE_LINES_MAX * 1000000) / (IMX390_MODE_VMAX * (_fps)))
+
+#define IMX390_EXPOSURE_SHS_VAL(_exp, _fps) \
+ (IMX390_MODE_VMAX - ((_exp) * (_fps) * IMX390_MODE_VMAX) / 1000000)
+
+#define IMX390_EXPOSURE_DEFAULT 11111
+
+/* Analog gain control */
+#define IMX390_REG_CAT0_AGAIN_SP1H 0x0018
+#define IMX390_REG_CAT0_AGAIN_SP1L 0x001A
+#define IMX390_ANALOG_GAIN_MAX 0x3FF
+#define IMX390_ANALOG_GAIN_DEFAULT 0x20
+#define IMX390_AGAIN_CONV_GAIN_RATIO 4
+
+/* Digital gain control */
+#define IMX390_REG_CAT0_PGA_GAIN 0x0024
+#define IMX390_DIGITAL_GAIN_MAX 0x1FF
+#define IMX390_DIGITAL_GAIN_DEFAULT 0x20
+
+/* White Balance control */
+#define IMX390_REG_CAT0_WBGAIN_R 0x0030
+#define IMX390_REG_CAT0_WBGAIN_B 0x0036
+#define IMX390_R_B_BALANCE_MAX 0xFFF
+#define IMX390_R_B_BALANCE_DEFAULT 0x200
+
+/* Vertical and Horizontal Flip control */
+#define IMX390_REG_CAT0_V_H_REVERSE 0x0074
+#define IMX390_V_REV_MASK BIT(0)
+#define IMX390_H_REV_MASK BIT(1)
+#define IMX390_REG_SM_CFG_REVERSE_APL 0x03C0
+#define IMX390_V_REV_APL_MASK BIT(2)
+#define IMX390_H_REV_APL_MASK BIT(3)
+
+/* Test Pattern control */
+#define IMX390_REG_CAT0_PGMODE_PGREGEN 0x01DB
+#define IMX390_SM_CFG_SM_PGREGEN_APL 0x03C0
+#define IMX390_SM_PG_APL_MASK BIT(1)
+
+#define IMX390_PM_IDLE_TIMEOUT 1000
+
+struct imx390_ctrl {
+ struct v4l2_ctrl_handler handler;
+ struct v4l2_ctrl *wdr;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *again;
+ struct v4l2_ctrl *dgain;
+ struct v4l2_ctrl *r_balance;
+ struct v4l2_ctrl *b_balance;
+ struct v4l2_ctrl *h_flip;
+ struct v4l2_ctrl *v_flip;
+ struct v4l2_ctrl *pg_mode;
+};
+
+/*
+ * struct im390 - imx390 device structure
+ * @dev: Device handle
+ * @clk: Pointer to imx390 clock
+ * @client: Pointer to I2C client
+ * @regmap: Pointer to regmap structure
+ * @xclr_gpio: Pointer to XCLR gpio
+ * @subddev: V4L2 subdevice structure
+ * @format: V4L2 media bus frame format structure
+ * (width and height are in sync with the compose rect)
+ * @pad: Media pad structure
+ * @ctrl: imx390 control structure
+ * @frame_interval: Time period of one frame in seconds
+ * @clk_rate: Frequency of imx390 clock
+ * @lock: Mutex structure for V4L2 ctrl handler
+ * @streaming: Flag to store the streaming on/off status
+ */
+struct imx390 {
+ struct device *dev;
+
+ struct clk *clk;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct gpio_desc *xclr_gpio;
+
+ struct v4l2_subdev subdev;
+ struct v4l2_mbus_framefmt format;
+ struct media_pad pad;
+
+ struct imx390_ctrl ctrl;
+
+ unsigned long clk_rate;
+ u32 fps;
+
+ /* mutex for V4L2 ctrl handler */
+ struct mutex lock;
+ bool streaming;
+};
+
+static const struct v4l2_area imx390_framesizes[] = {
+ {
+ .width = IMX390_OUT_WIDTH,
+ .height = IMX390_OUT_HEIGHT,
+ },
+};
+
+static const u32 imx390_mbus_formats[] = {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+};
+
+static const struct regmap_config imx390_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+};
+
+static const u32 imx390_pg_mode_reg_val[] = {
+ 0x00,
+ 0x32,
+ 0x33,
+ 0x35,
+ 0x3D,
+};
+
+static const char *const imx390_ctrl_pg_qmenu[] = {
+ "Disabled",
+ "Horizontal Color Bars",
+ "Vertical Color Bars",
+ "Gradation",
+ "Checker Pattern",
+};
+
+static const struct reg_sequence imx390_wdr_1936x1096[] = {
+ { 0x000C, 0x7F },
+ { 0x000D, 0x01 },
+ { 0x000E, 0x00 },
+ { 0x0010, 0x7F },
+ { 0x0011, 0x01 },
+ { 0x0012, 0x00 },
+ { 0x0018, 0x20 },
+ { 0x0019, 0x00 },
+ { 0x001A, 0x0C },
+ { 0x001B, 0x00 },
+ { 0x0038, 0x00 },
+ { 0x003C, 0x00 },
+ { 0x003D, 0x00 },
+ { 0x003E, 0x00 },
+ { 0x0040, 0x00 },
+ { 0x0041, 0x00 },
+ { 0x0042, 0x00 },
+ { 0x0044, 0x00 },
+ { 0x0045, 0x00 },
+ { 0x0046, 0x00 },
+ { 0x0048, 0x00 },
+ { 0x0049, 0x00 },
+ { 0x004A, 0x00 },
+ { 0x004C, 0x00 },
+ { 0x004D, 0x00 },
+ { 0x004E, 0x00 },
+ { 0x0050, 0x00 },
+ { 0x0051, 0x00 },
+ { 0x0052, 0x00 },
+ { 0x0054, 0x00 },
+ { 0x0055, 0x00 },
+ { 0x0056, 0x00 },
+ { 0x0058, 0x00 },
+ { 0x0059, 0x00 },
+ { 0x005A, 0x00 },
+ { 0x005C, 0x00 },
+ { 0x005D, 0x00 },
+ { 0x005E, 0x00 },
+ { 0x0060, 0x00 },
+ { 0x0061, 0x00 },
+ { 0x0062, 0x00 },
+ { 0x0064, 0x00 },
+ { 0x0065, 0x00 },
+ { 0x0066, 0x00 },
+ { 0x0068, 0x00 },
+ { 0x0069, 0x00 },
+ { 0x006A, 0x00 },
+ { 0x0078, 0x01 },
+ { 0x007C, 0x08 },
+ { 0x007D, 0x00 },
+ { 0x0080, 0x08 },
+ { 0x0081, 0x00 },
+ { 0x0090, 0x00 },
+ { 0x00F4, 0x1C },
+ { 0x00F5, 0xF8 },
+ { 0x00F6, 0x01 },
+ { 0x00F8, 0x03 },
+ { 0x00F9, 0x01 },
+ { 0x00FA, 0x00 },
+ { 0x00FB, 0x02 },
+ { 0x0114, 0x00 },
+ { 0x0115, 0x01 },
+ { 0x0118, 0x20 },
+ { 0x0119, 0x03 },
+ { 0x011A, 0x00 },
+ { 0x011B, 0x41 },
+ { 0x011C, 0x80 },
+ { 0x011D, 0x00 },
+ { 0x0120, 0x20 },
+ { 0x0121, 0x00 },
+ { 0x0122, 0x00 },
+ { 0x0123, 0x44 },
+ { 0x0124, 0x00 },
+ { 0x0125, 0x01 },
+ { 0x0128, 0xAC },
+ { 0x0129, 0x0D },
+ { 0x012A, 0x00 },
+ { 0x012B, 0xA4 },
+ { 0x012C, 0x00 },
+ { 0x012D, 0x01 },
+ { 0x0130, 0xC4 },
+ { 0x0131, 0x09 },
+ { 0x0132, 0x00 },
+ { 0x0133, 0xDA },
+ { 0x0138, 0x00 }, /* DB_CMN_POST_PEDESTAL (0x0138: 0x0139) = 0 */
+ { 0x0139, 0x00 }, /* DB_CMN_POST_PEDESTAL (0x0138: 0x0139) = 0 */
+ { 0x013A, 0x00 },
+ { 0x013B, 0x00 },
+ { 0x013C, 0x00 },
+ { 0x013D, 0x00 },
+ { 0x013E, 0x00 },
+ { 0x0140, 0x00 },
+ { 0x0141, 0x00 },
+ { 0x0142, 0x00 },
+ /* Start of PWL Registers */
+ { 0x0144, 0x00 }, /* pwl_cp1_x 2048 */
+ { 0x0145, 0x08 }, /* pwl_cp1_x 2048 */
+ { 0x0146, 0x00 }, /* pwl_cp1_x 2048 */
+ { 0x0147, 0x00 }, /* pwl_cp1_x 2048 */
+ { 0x0148, 0x00 }, /* pwl_cp1_y 51 */
+ { 0x0149, 0x02 }, /* pwl_cp1_y 51 */
+ { 0x014A, 0x00 }, /* pwl_cp1_y 51 */
+ { 0x014B, 0x00 }, /* pwl_cp1_y 51 */
+ { 0x014C, 0x00 }, /* pwl_cp2_x 1638 */
+ { 0x014D, 0x40 }, /* pwl_cp2_x 1638 */
+ { 0x014E, 0x00 }, /* pwl_cp2_x 1638 */
+ { 0x014F, 0x00 }, /* pwl_cp2_x 1638 */
+ { 0x0150, 0x80 }, /* pwl_cp2_y 1408 */
+ { 0x0151, 0x05 }, /* pwl_cp2_y 1408 */
+ { 0x0152, 0x00 }, /* pwl_cp2_y 1408 */
+ { 0x0153, 0x00 }, /* pwl_cp2_y 1408 */
+ { 0x0154, 0x00 }, /* pwl_cp3_x 6553 */
+ { 0x0155, 0x00 }, /* pwl_cp3_x 6553 */
+ { 0x0156, 0x01 }, /* pwl_cp3_x 6553 */
+ { 0x0157, 0x00 }, /* pwl_cp3_x 6553 */
+ { 0x0158, 0x80 }, /* pwl_cp3_y 2176 */
+ { 0x0159, 0x08 }, /* pwl_cp3_y 2176 */
+ { 0x015A, 0x00 }, /* pwl_cp3_y 2176 */
+ { 0x015B, 0x00 }, /* pwl_cp3_y 2176 */
+ { 0x015C, 0x00 }, /* pwl_cp4_x 0x100000 */
+ { 0x015D, 0x00 }, /* pwl_cp4_x 0x100000 */
+ { 0x015E, 0x10 }, /* pwl_cp4_x 0x100000 */
+ { 0x015F, 0x00 }, /* pwl_cp4_x 0x100000 */
+ { 0x0160, 0x00 }, /* pwl_cp4_y 0x1000 */
+ { 0x0161, 0x10 }, /* pwl_cp4_y 0x1000 */
+ { 0x0162, 0x00 }, /* pwl_cp4_y 0x1000 */
+ { 0x0163, 0x00 }, /* pwl_cp4_y 0x1000 */
+ { 0x0164, 0x00 }, /* pwl_cp5_x 0x100000 */
+ { 0x0165, 0x00 }, /* pwl_cp5_x 0x100000 */
+ { 0x0166, 0x10 }, /* pwl_cp5_x 0x100000 */
+ { 0x0167, 0x00 }, /* pwl_cp5_x 0x100000 */
+ { 0x0168, 0x00 }, /* pwl_cp5_y 0x1000 */
+ { 0x0169, 0x10 }, /* pwl_cp5_y 0x1000 */
+ { 0x016A, 0x00 }, /* pwl_cp5_y 0x1000 */
+ { 0x016B, 0x00 }, /* pwl_cp5_y 0x1000 */
+ { 0x016C, 0x00 }, /* pwl_cp6_x 0x100000 */
+ { 0x016D, 0x00 }, /* pwl_cp6_x 0x100000 */
+ { 0x016E, 0x10 }, /* pwl_cp6_x 0x100000 */
+ { 0x016F, 0x00 }, /* pwl_cp6_x 0x100000 */
+ { 0x0170, 0x00 }, /* pwl_cp6_y 0x1000 */
+ { 0x0171, 0x10 }, /* pwl_cp6_y 0x1000 */
+ { 0x0172, 0x00 }, /* pwl_cp6_y 0x1000 */
+ { 0x0173, 0x00 }, /* pwl_cp6_y 0x1000 */
+ { 0x0174, 0x00 }, /* pwl_cp7_x 0x100000 */
+ { 0x0175, 0x00 }, /* pwl_cp7_x 0x100000 */
+ { 0x0176, 0x10 }, /* pwl_cp7_x 0x100000 */
+ { 0x0177, 0x00 }, /* pwl_cp7_x 0x100000 */
+ { 0x0178, 0x00 }, /* pwl_cp7_y 0x1000 */
+ { 0x0179, 0x10 }, /* pwl_cp7_y 0x1000 */
+ { 0x017A, 0x00 }, /* pwl_cp7_y 0x1000 */
+ { 0x017B, 0x00 }, /* pwl_cp7_y 0x1000 */
+ { 0x017C, 0x00 }, /* pwl_cp8_x 0x100000 */
+ { 0x017D, 0x00 }, /* pwl_cp8_x 0x100000 */
+ { 0x017E, 0x10 }, /* pwl_cp8_x 0x100000 */
+ { 0x017F, 0x00 }, /* pwl_cp8_x 0x100000 */
+ { 0x0180, 0x00 }, /* pwl_cp8_y 0x1000 */
+ { 0x0181, 0x10 }, /* pwl_cp8_y 0x1000 */
+ { 0x0182, 0x00 }, /* pwl_cp8_y 0x1000 */
+ { 0x0183, 0x00 }, /* pwl_cp8_y 0x1000 */
+ { 0x0184, 0x00 }, /* pwl_cp9_x 0x100000 */
+ { 0x0185, 0x00 }, /* pwl_cp9_x 0x100000 */
+ { 0x0186, 0x10 }, /* pwl_cp9_x 0x100000 */
+ { 0x0187, 0x00 }, /* pwl_cp9_x 0x100000 */
+ { 0x0188, 0x00 }, /* pwl_cp9_y 0x1000 */
+ { 0x0189, 0x10 }, /* pwl_cp9_y 0x1000 */
+ { 0x018A, 0x00 }, /* pwl_cp9_y 0x1000 */
+ { 0x018B, 0x00 }, /* pwl_cp9_y 0x1000 */
+ { 0x018C, 0x00 }, /* pwl_cp10_x 0x10000 */
+ { 0x018D, 0x00 }, /* pwl_cp10_x 0x10000 */
+ { 0x018E, 0x10 }, /* pwl_cp10_x 0x10000 */
+ { 0x018F, 0x00 }, /* pwl_cp10_x 0x10000 */
+ { 0x0190, 0x00 }, /* pwl_cp10_y 0x100 */
+ { 0x0191, 0x10 }, /* pwl_cp10_y 0x100 */
+ { 0x0192, 0x00 }, /* pwl_cp10_y 0x100 */
+ { 0x0193, 0x00 }, /* pwl_cp10_y 0x100 */
+ { 0x0198, 0x00 }, /* pwl gain0 0x040 0000 */
+ { 0x0199, 0x00 },
+ { 0x019A, 0x40 },
+ { 0x019B, 0x00 },
+ { 0x019C, 0x00 }, /* pwl gain1 0x010 0000 */
+ { 0x019D, 0x00 },
+ { 0x019E, 0x10 },
+ { 0x019F, 0x00 },
+ { 0x01A0, 0x00 }, /* pwl gain2 0x004 0000 */
+ { 0x01A1, 0x00 },
+ { 0x01A2, 0x04 },
+ { 0x01A3, 0x00 },
+ { 0x01A4, 0x00 }, /* pwl gain3 0x000 8000 */
+ { 0x01A5, 0x80 },
+ { 0x01A6, 0x00 },
+ { 0x01A7, 0x00 },
+ { 0x01A8, 0x00 },
+ { 0x01A9, 0x00 },
+ { 0x01AA, 0x00 },
+ { 0x01AB, 0x00 },
+ /* End of PWL Registers*/
+ { 0x01AC, 0x00 },
+ { 0x01AD, 0x00 },
+ { 0x01AE, 0x00 },
+ { 0x01AF, 0x00 },
+ { 0x01B0, 0x00 },
+ { 0x01B1, 0x00 },
+ { 0x01B2, 0x00 },
+ { 0x01B3, 0x00 },
+ { 0x01B4, 0x00 },
+ { 0x01B5, 0x00 },
+ { 0x01B6, 0x00 },
+ { 0x01B7, 0x00 },
+ { 0x01B8, 0x00 },
+ { 0x01B9, 0x00 },
+ { 0x01BA, 0x00 },
+ { 0x01BB, 0x00 },
+ { 0x01BC, 0x00 },
+ { 0x01BD, 0x00 },
+ { 0x01BE, 0x00 },
+ { 0x01BF, 0x00 },
+ { 0x01C0, 0x00 },
+ { 0x01C1, 0x00 },
+ { 0x01C2, 0x00 },
+ { 0x01C3, 0x00 },
+ { 0x01C4, 0x00 },
+ { 0x01C5, 0x00 },
+ { 0x01CC, 0x01 },
+ { 0x01D0, 0x09 },
+ { 0x01D4, 0x01 },
+ { 0x0332, 0x67 },
+ { 0x0333, 0x02 },
+ { 0x0390, 0x00 },
+ { 0x0391, 0x00 },
+ { 0x0392, 0x00 },
+ { 0x03C0, 0x01 },
+ { 0x2000, 0x55 },
+ { 0x2001, 0x55 },
+ { 0x2002, 0x55 },
+ { 0x2003, 0x05 },
+ { 0x2004, 0x02 },
+ { 0x2008, 0x65 },
+ { 0x2009, 0x04 },
+ { 0x200A, 0x00 },
+ { 0x200C, 0x98 },
+ { 0x200D, 0x08 },
+ { 0x2010, 0x04 },
+ { 0x2014, 0x00 },
+ { 0x2018, 0x02 },
+ { 0x2019, 0x04 },
+ { 0x201A, 0x00 },
+ { 0x201C, 0x21 },
+ { 0x201D, 0x11 },
+ { 0x201E, 0x00 },
+ { 0x201F, 0x00 },
+ { 0x2020, 0xBC },
+ { 0x2021, 0x00 },
+ { 0x2022, 0x7F },
+ { 0x2023, 0x00 },
+ { 0x2024, 0xBA },
+ { 0x2025, 0x00 },
+ { 0x2026, 0x81 },
+ { 0x2027, 0x00 },
+ { 0x2028, 0x7D },
+ { 0x2029, 0x90 },
+ { 0x202A, 0x05 },
+ { 0x202C, 0xFC },
+ { 0x202D, 0x02 },
+ { 0x202E, 0x25 },
+ { 0x202F, 0x03 },
+ { 0x2030, 0x05 },
+ { 0x2031, 0x02 },
+ { 0x2032, 0xCA },
+ { 0x2033, 0x02 },
+ { 0x2034, 0xFC },
+ { 0x2035, 0x02 },
+ { 0x2036, 0x25 },
+ { 0x2037, 0x03 },
+ { 0x2038, 0xF8 },
+ { 0x2039, 0xE4 },
+ { 0x203A, 0xE3 },
+ { 0x203B, 0x01 },
+ { 0x203C, 0xF5 },
+ { 0x203D, 0x8E },
+ { 0x203E, 0x0C },
+ { 0x203F, 0x2D },
+ { 0x2040, 0x69 },
+ { 0x2041, 0x01 },
+ { 0x2042, 0x8E },
+ { 0x2043, 0x01 },
+ { 0x2044, 0x0C },
+ { 0x2045, 0x02 },
+ { 0x2046, 0x31 },
+ { 0x2047, 0x02 },
+ { 0x2048, 0x6A },
+ { 0x2049, 0x01 },
+ { 0x204A, 0x8E },
+ { 0x204B, 0x01 },
+ { 0x204C, 0x0D },
+ { 0x204D, 0x02 },
+ { 0x204E, 0x31 },
+ { 0x204F, 0x02 },
+ { 0x2050, 0x7B },
+ { 0x2051, 0x00 },
+ { 0x2052, 0x7D },
+ { 0x2053, 0x00 },
+ { 0x2054, 0x95 },
+ { 0x2055, 0x00 },
+ { 0x2056, 0x97 },
+ { 0x2057, 0x00 },
+ { 0x2058, 0xAD },
+ { 0x2059, 0x00 },
+ { 0x205A, 0xAF },
+ { 0x205B, 0x00 },
+ { 0x205C, 0x92 },
+ { 0x205D, 0x00 },
+ { 0x205E, 0x94 },
+ { 0x205F, 0x00 },
+ { 0x2060, 0x8E },
+ { 0x2061, 0x00 },
+ { 0x2062, 0x90 },
+ { 0x2063, 0x00 },
+ { 0x2064, 0xB1 },
+ { 0x2065, 0x00 },
+ { 0x2066, 0xB3 },
+ { 0x2067, 0x00 },
+ { 0x2068, 0x08 },
+ { 0x2069, 0x00 },
+ { 0x206A, 0x04 },
+ { 0x206B, 0x00 },
+ { 0x206C, 0x84 },
+ { 0x206D, 0x00 },
+ { 0x206E, 0x80 },
+ { 0x206F, 0x00 },
+ { 0x2070, 0x04 },
+ { 0x2071, 0x00 },
+ { 0x2072, 0x46 },
+ { 0x2073, 0x00 },
+ { 0x2074, 0xE9 },
+ { 0x2075, 0x01 },
+ { 0x2076, 0x74 },
+ { 0x2077, 0x02 },
+ { 0x2078, 0x80 },
+ { 0x2079, 0x00 },
+ { 0x207A, 0xC1 },
+ { 0x207B, 0x00 },
+ { 0x207C, 0xFF },
+ { 0x207D, 0x03 },
+ { 0x207E, 0xFF },
+ { 0x207F, 0x03 },
+ { 0x2080, 0x78 },
+ { 0x2081, 0x00 },
+ { 0x2082, 0x6A },
+ { 0x2083, 0x01 },
+ { 0x2084, 0xE4 },
+ { 0x2085, 0x01 },
+ { 0x2086, 0x2B },
+ { 0x2087, 0x03 },
+ { 0x2088, 0x00 },
+ { 0x2089, 0x00 },
+ { 0x208A, 0xFF },
+ { 0x208B, 0x03 },
+ { 0x208C, 0xFF },
+ { 0x208D, 0x03 },
+ { 0x208E, 0xFF },
+ { 0x208F, 0x03 },
+ { 0x2090, 0x7D },
+ { 0x2091, 0x00 },
+ { 0x2092, 0x62 },
+ { 0x2093, 0x01 },
+ { 0x2094, 0xE9 },
+ { 0x2095, 0x01 },
+ { 0x2096, 0x00 },
+ { 0x2097, 0x00 },
+ { 0x2098, 0x7C },
+ { 0x2099, 0x00 },
+ { 0x209A, 0x21 },
+ { 0x209B, 0x03 },
+ { 0x209C, 0xE9 },
+ { 0x209D, 0x01 },
+ { 0x209E, 0x21 },
+ { 0x209F, 0x03 },
+ { 0x20A0, 0xFF },
+ { 0x20A1, 0x03 },
+ { 0x20A2, 0xFF },
+ { 0x20A3, 0x03 },
+ { 0x20A4, 0xFF },
+ { 0x20A5, 0x03 },
+ { 0x20A6, 0xFF },
+ { 0x20A7, 0x03 },
+ { 0x20A8, 0xFF },
+ { 0x20A9, 0x03 },
+ { 0x20AA, 0xFF },
+ { 0x20AB, 0x03 },
+ { 0x20AC, 0xFF },
+ { 0x20AD, 0x03 },
+ { 0x20AE, 0xFF },
+ { 0x20AF, 0x03 },
+ { 0x20B0, 0xFF },
+ { 0x20B1, 0x03 },
+ { 0x20B2, 0xFF },
+ { 0x20B3, 0x03 },
+ { 0x20B4, 0x87 },
+ { 0x20B5, 0xCC },
+ { 0x20B6, 0x87 },
+ { 0x20B7, 0x08 },
+ { 0x20B8, 0xF4 },
+ { 0x20B9, 0xA5 },
+ { 0x20BA, 0x07 },
+ { 0x20BC, 0x1F },
+ { 0x20BD, 0x01 },
+ { 0x20BE, 0xF6 },
+ { 0x20BF, 0x00 },
+ { 0x20C0, 0x90 },
+ { 0x20C1, 0x01 },
+ { 0x20C2, 0x67 },
+ { 0x20C3, 0x01 },
+ { 0x20C4, 0xFF },
+ { 0x20C5, 0x03 },
+ { 0x20C6, 0xFF },
+ { 0x20C7, 0x03 },
+ { 0x20C8, 0x33 },
+ { 0x20C9, 0x02 },
+ { 0x20CA, 0x0A },
+ { 0x20CB, 0x02 },
+ { 0x20CC, 0x7F },
+ { 0x20CD, 0x00 },
+ { 0x20CE, 0xD2 },
+ { 0x20CF, 0x00 },
+ { 0x20D0, 0x81 },
+ { 0x20D1, 0x00 },
+ { 0x20D2, 0x87 },
+ { 0x20D3, 0x00 },
+ { 0x20D4, 0x09 },
+ { 0x20D5, 0x00 },
+ { 0x20D8, 0x7F },
+ { 0x20D9, 0x00 },
+ { 0x20DA, 0x62 },
+ { 0x20DB, 0x01 },
+ { 0x20DC, 0x7F },
+ { 0x20DD, 0x00 },
+ { 0x20DE, 0x62 },
+ { 0x20DF, 0x01 },
+ { 0x20E0, 0x65 },
+ { 0x20E1, 0x00 },
+ { 0x20E2, 0x75 },
+ { 0x20E3, 0x00 },
+ { 0x20E4, 0xE0 },
+ { 0x20E5, 0x00 },
+ { 0x20E6, 0xF0 },
+ { 0x20E7, 0x00 },
+ { 0x20E8, 0x4C },
+ { 0x20E9, 0x01 },
+ { 0x20EA, 0x5C },
+ { 0x20EB, 0x01 },
+ { 0x20EC, 0xD1 },
+ { 0x20ED, 0x01 },
+ { 0x20EE, 0xE1 },
+ { 0x20EF, 0x01 },
+ { 0x20F0, 0x93 },
+ { 0x20F1, 0x02 },
+ { 0x20F2, 0xA3 },
+ { 0x20F3, 0x02 },
+ { 0x20F4, 0x0D },
+ { 0x20F5, 0x03 },
+ { 0x20F6, 0x1D },
+ { 0x20F7, 0x03 },
+ { 0x20F8, 0x57 },
+ { 0x20F9, 0x00 },
+ { 0x20FA, 0x7B },
+ { 0x20FB, 0x00 },
+ { 0x20FC, 0xD2 },
+ { 0x20FD, 0x00 },
+ { 0x20FE, 0xF6 },
+ { 0x20FF, 0x00 },
+ { 0x2100, 0x3E },
+ { 0x2101, 0x01 },
+ { 0x2102, 0x60 },
+ { 0x2103, 0x01 },
+ { 0x2104, 0xC3 },
+ { 0x2105, 0x01 },
+ { 0x2106, 0xE5 },
+ { 0x2107, 0x01 },
+ { 0x2108, 0x85 },
+ { 0x2109, 0x02 },
+ { 0x210A, 0xA9 },
+ { 0x210B, 0x02 },
+ { 0x210C, 0xFF },
+ { 0x210D, 0x02 },
+ { 0x210E, 0x21 },
+ { 0x210F, 0x03 },
+ { 0x2110, 0xFF },
+ { 0x2111, 0x03 },
+ { 0x2112, 0x00 },
+ { 0x2113, 0x00 },
+ { 0x2114, 0xFF },
+ { 0x2115, 0x03 },
+ { 0x2116, 0xFF },
+ { 0x2117, 0x03 },
+ { 0x2118, 0xFF },
+ { 0x2119, 0x03 },
+ { 0x211A, 0xFF },
+ { 0x211B, 0x03 },
+ { 0x211C, 0xFF },
+ { 0x211D, 0x03 },
+ { 0x211E, 0xFF },
+ { 0x211F, 0x03 },
+ { 0x2120, 0xFF },
+ { 0x2121, 0x03 },
+ { 0x2122, 0xFF },
+ { 0x2123, 0x03 },
+ { 0x2124, 0xFF },
+ { 0x2125, 0x03 },
+ { 0x2126, 0xFF },
+ { 0x2127, 0x03 },
+ { 0x2128, 0x7D },
+ { 0x2129, 0x90 },
+ { 0x212A, 0xD5 },
+ { 0x212B, 0x07 },
+ { 0x212C, 0x64 },
+ { 0x212D, 0x01 },
+ { 0x2130, 0x5F },
+ { 0x2131, 0x7D },
+ { 0x2132, 0x05 },
+ { 0x2134, 0x78 },
+ { 0x2135, 0x00 },
+ { 0x2136, 0x76 },
+ { 0x2137, 0x00 },
+ { 0x2138, 0xF3 },
+ { 0x2139, 0x00 },
+ { 0x213A, 0xF1 },
+ { 0x213B, 0x00 },
+ { 0x213C, 0xA6 },
+ { 0x213D, 0x02 },
+ { 0x213E, 0xA4 },
+ { 0x213F, 0x02 },
+ { 0x2140, 0x7D },
+ { 0x2141, 0x00 },
+ { 0x2142, 0x8D },
+ { 0x2143, 0x00 },
+ { 0x2144, 0xA1 },
+ { 0x2145, 0x01 },
+ { 0x2146, 0xB1 },
+ { 0x2147, 0x01 },
+ { 0x2148, 0xAB },
+ { 0x2149, 0x02 },
+ { 0x214A, 0xBB },
+ { 0x214B, 0x02 },
+ { 0x214C, 0x17 },
+ { 0x214D, 0x5C },
+ { 0x214E, 0x00 },
+ { 0x2150, 0x00 },
+ { 0x2151, 0x00 },
+ { 0x2152, 0xF8 },
+ { 0x2153, 0x00 },
+ { 0x2154, 0xBE },
+ { 0x2155, 0x00 },
+ { 0x2156, 0x7D },
+ { 0x2157, 0x00 },
+ { 0x2158, 0x25 },
+ { 0x2159, 0x00 },
+ { 0x215A, 0x7D },
+ { 0x215B, 0x00 },
+ { 0x215C, 0x62 },
+ { 0x215D, 0x01 },
+ { 0x215E, 0xFF },
+ { 0x215F, 0x03 },
+ { 0x2160, 0x26 },
+ { 0x2161, 0x00 },
+ { 0x2162, 0x7D },
+ { 0x2163, 0x00 },
+ { 0x2164, 0x63 },
+ { 0x2165, 0x01 },
+ { 0x2166, 0xFF },
+ { 0x2167, 0x03 },
+ { 0x2168, 0xCB },
+ { 0x2169, 0x02 },
+ { 0x216A, 0xCF },
+ { 0x216B, 0x02 },
+ { 0x216C, 0xFF },
+ { 0x216D, 0x03 },
+ { 0x216E, 0xFF },
+ { 0x216F, 0x03 },
+ { 0x2170, 0xFF },
+ { 0x2171, 0x03 },
+ { 0x2172, 0xFF },
+ { 0x2173, 0x03 },
+ { 0x2174, 0xFF },
+ { 0x2175, 0x03 },
+ { 0x2176, 0xFF },
+ { 0x2177, 0x03 },
+ { 0x2178, 0x7E },
+ { 0x2179, 0x00 },
+ { 0x217A, 0xBD },
+ { 0x217B, 0x00 },
+ { 0x217C, 0xEC },
+ { 0x217D, 0x01 },
+ { 0x217E, 0x7B },
+ { 0x217F, 0x02 },
+ { 0x2180, 0xD1 },
+ { 0x2181, 0x02 },
+ { 0x2182, 0x25 },
+ { 0x2183, 0x03 },
+ { 0x2184, 0x7F },
+ { 0x2185, 0x00 },
+ { 0x2186, 0xBD },
+ { 0x2187, 0x00 },
+ { 0x2188, 0xED },
+ { 0x2189, 0x01 },
+ { 0x218A, 0x7B },
+ { 0x218B, 0x02 },
+ { 0x218C, 0xD2 },
+ { 0x218D, 0x02 },
+ { 0x218E, 0x25 },
+ { 0x218F, 0x03 },
+ { 0x2190, 0xFF },
+ { 0x2191, 0x03 },
+ { 0x2192, 0xFF },
+ { 0x2193, 0x03 },
+ { 0x2194, 0xE9 },
+ { 0x2195, 0x01 },
+ { 0x2196, 0x21 },
+ { 0x2197, 0x03 },
+ { 0x2198, 0x17 },
+ { 0x2199, 0xFC },
+ { 0x219A, 0x7F },
+ { 0x219B, 0x01 },
+ { 0x219C, 0xFF },
+ { 0x219D, 0x03 },
+ { 0x21A0, 0x1B },
+ { 0x21A1, 0x1B },
+ { 0x21A2, 0x1B },
+ { 0x21A3, 0x1B },
+ { 0x21A4, 0x2B },
+ { 0x21A5, 0x80 },
+ { 0x21A6, 0x00 },
+ { 0x21A8, 0x04 },
+ { 0x21A9, 0x98 },
+ { 0x21AA, 0x60 },
+ { 0x21AB, 0x03 },
+ { 0x21AC, 0x7F },
+ { 0x21AD, 0x80 },
+ { 0x21AE, 0x09 },
+ { 0x21B0, 0x1C },
+ { 0x21B1, 0x00 },
+ { 0x21B2, 0xA0 },
+ { 0x21B3, 0x00 },
+ { 0x21B4, 0x0C },
+ { 0x21B5, 0x00 },
+ { 0x21B6, 0x2D },
+ { 0x21B7, 0x00 },
+ { 0x21B8, 0x20 },
+ { 0x21B9, 0x00 },
+ { 0x21BA, 0x02 },
+ { 0x21BB, 0x00 },
+ { 0x21BC, 0xCC },
+ { 0x21BD, 0x00 },
+ { 0x21BE, 0x4A },
+ { 0x21BF, 0x00 },
+ { 0x21C0, 0xD0 },
+ { 0x21C1, 0x00 },
+ { 0x21C2, 0x44 },
+ { 0x21C3, 0x00 },
+ { 0x21C4, 0x00 },
+ { 0x21C5, 0xE0 },
+ { 0x21C6, 0x00 },
+ { 0x21C8, 0x11 },
+ { 0x21C9, 0x00 },
+ { 0x21CA, 0x02 },
+ { 0x21CC, 0x08 },
+ { 0x21CD, 0xC0 },
+ { 0x21CE, 0x0C },
+ { 0x21D0, 0x44 },
+ { 0x21D1, 0x00 },
+ { 0x21D2, 0x02 },
+ { 0x21D4, 0x02 },
+ { 0x21D5, 0x20 },
+ { 0x21D6, 0x2C },
+ { 0x21D8, 0xFE },
+ { 0x21D9, 0x9D },
+ { 0x21DA, 0xDF },
+ { 0x21DB, 0x03 },
+ { 0x21DC, 0x62 },
+ { 0x21DD, 0x01 },
+ { 0x21DE, 0x7F },
+ { 0x21DF, 0x00 },
+ { 0x21E0, 0xB7 },
+ { 0x21E1, 0x01 },
+ { 0x21E2, 0xB5 },
+ { 0x21E3, 0x01 },
+ { 0x21E4, 0xC1 },
+ { 0x21E5, 0x02 },
+ { 0x21E6, 0xBF },
+ { 0x21E7, 0x02 },
+ { 0x21E8, 0xB3 },
+ { 0x21E9, 0x0D },
+ { 0x21EA, 0x00 },
+ { 0x21EB, 0x04 },
+ { 0x21EC, 0x90 },
+ { 0x21ED, 0x07 },
+ { 0x21EE, 0x58 },
+ { 0x21EF, 0x04 },
+ { 0x21F0, 0x54 },
+ { 0x21F1, 0x04 },
+ { 0x21F4, 0x02 },
+ { 0x21F5, 0x00 },
+ { 0x21F6, 0x00 },
+ { 0x21F8, 0x3C },
+ { 0x21F9, 0x00 },
+ { 0x21FC, 0x28 },
+ { 0x21FD, 0x00 },
+ { 0x21FE, 0x3C },
+ { 0x21FF, 0x00 },
+ { 0x2200, 0x00 },
+ { 0x2204, 0x4C },
+ { 0x2205, 0x04 },
+ { 0x2206, 0x65 },
+ { 0x2207, 0x04 },
+ { 0x2208, 0x0A },
+ { 0x2209, 0x00 },
+ { 0x220C, 0x57 },
+ { 0x220D, 0x00 },
+ { 0x220E, 0x37 },
+ { 0x220F, 0x00 },
+ { 0x2210, 0x1F },
+ { 0x2211, 0x00 },
+ { 0x2212, 0x1F },
+ { 0x2213, 0x00 },
+ { 0x2214, 0x1F },
+ { 0x2215, 0x00 },
+ { 0x2216, 0x77 },
+ { 0x2217, 0x00 },
+ { 0x2218, 0x1F },
+ { 0x2219, 0x00 },
+ { 0x221A, 0x17 },
+ { 0x221B, 0x00 },
+ { 0x221C, 0x03 },
+ { 0x2220, 0x24 },
+ { 0x2221, 0x00 },
+ { 0x2222, 0x00 },
+ { 0x2223, 0x00 },
+ { 0x2224, 0xA7 },
+ { 0x2225, 0xAA },
+ { 0x2226, 0x80 },
+ { 0x2227, 0x08 },
+ { 0x2228, 0x01 },
+ { 0x2260, 0xFF },
+ { 0x2261, 0x1F },
+ { 0x2262, 0x00 },
+ { 0x2263, 0x00 },
+ { 0x2264, 0x00 },
+ { 0x2265, 0x00 },
+ { 0x2266, 0xFF },
+ { 0x2267, 0x1F },
+ { 0x2268, 0x00 },
+ { 0x2269, 0x00 },
+ { 0x226A, 0xFF },
+ { 0x226B, 0x1F },
+ { 0x226C, 0x00 },
+ { 0x226D, 0x00 },
+ { 0x226E, 0xFF },
+ { 0x226F, 0x1F },
+ { 0x227C, 0xB2 },
+ { 0x227D, 0x0C },
+ { 0x227E, 0x6A },
+ { 0x227F, 0x09 },
+ { 0x2280, 0xD2 },
+ { 0x2281, 0x0C },
+ { 0x2282, 0x5A },
+ { 0x2283, 0x09 },
+ { 0x2284, 0xC4 },
+ { 0x2285, 0x0C },
+ { 0x2286, 0x54 },
+ { 0x2287, 0x09 },
+ { 0x22B2, 0x92 },
+ { 0x22B4, 0x20 },
+ { 0x22B5, 0x00 },
+ { 0x22B6, 0x20 },
+ { 0x22B7, 0x00 },
+ { 0x22B8, 0x20 },
+ { 0x22B9, 0x00 },
+ { 0x22BA, 0x20 },
+ { 0x22BB, 0x00 },
+ { 0x22BC, 0x20 },
+ { 0x22BD, 0x00 },
+ { 0x22BE, 0x20 },
+ { 0x22BF, 0x00 },
+ { 0x22C0, 0x20 },
+ { 0x22C1, 0x00 },
+ { 0x22C2, 0x20 },
+ { 0x22C3, 0x00 },
+ { 0x22C4, 0x20 },
+ { 0x22C5, 0x00 },
+ { 0x22C6, 0x20 },
+ { 0x22C7, 0x00 },
+ { 0x22C8, 0x20 },
+ { 0x22C9, 0x00 },
+ { 0x22CA, 0x20 },
+ { 0x22CB, 0x00 },
+ { 0x22CC, 0x20 },
+ { 0x22CD, 0x00 },
+ { 0x22CE, 0x20 },
+ { 0x22CF, 0x00 },
+ { 0x22DA, 0x00 },
+ { 0x22EF, 0x82 },
+ { 0x2308, 0x01 },
+ { 0x2310, 0x4B },
+ { 0x2311, 0x09 },
+ { 0x2318, 0x40 },
+ { 0x2319, 0xCD },
+ { 0x231A, 0x54 },
+ { 0x2324, 0x20 },
+ { 0x2325, 0x00 },
+ { 0x2328, 0x00 },
+ { 0x234A, 0x9F },
+ { 0x234B, 0x07 },
+ { 0x2354, 0x0C },
+ { 0x23C0, 0x5D },
+ { 0x244C, 0xFF },
+ { 0x244D, 0x03 },
+ { 0x244E, 0xFF },
+ { 0x244F, 0x03 },
+ { 0x24A0, 0x00 },
+ { 0x24A4, 0x16 },
+ { 0x24A5, 0x01 },
+ { 0x24A6, 0xA6 },
+ { 0x24A7, 0x02 },
+ { 0x24A8, 0xD5 },
+ { 0x24A9, 0x02 },
+ { 0x24BC, 0x17 },
+ { 0x24BD, 0x01 },
+ { 0x24BE, 0xA7 },
+ { 0x24BF, 0x02 },
+ { 0x24C0, 0xD5 },
+ { 0x24C1, 0x02 },
+ { 0x24DA, 0x6F },
+ { 0x24DB, 0x00 },
+ { 0x24DC, 0x62 },
+ { 0x24DD, 0x01 },
+ { 0x24EA, 0x32 },
+ { 0x24EB, 0x00 },
+ { 0x24EC, 0xDC },
+ { 0x24ED, 0x00 },
+ { 0x24FA, 0x32 },
+ { 0x24FB, 0x00 },
+ { 0x24FC, 0xDD },
+ { 0x24FD, 0x00 },
+ { 0x254A, 0x15 },
+ { 0x254B, 0x01 },
+ { 0x255A, 0x15 },
+ { 0x255B, 0x01 },
+ { 0x2560, 0x01 },
+ { 0x2561, 0x00 },
+ { 0x2562, 0x2A },
+ { 0x2563, 0x00 },
+ { 0x2564, 0xF8 },
+ { 0x2565, 0x00 },
+ { 0x2566, 0x15 },
+ { 0x2567, 0x01 },
+ { 0x2568, 0x0C },
+ { 0x2569, 0x02 },
+ { 0x256A, 0x31 },
+ { 0x256B, 0x02 },
+ { 0x2578, 0x90 },
+ { 0x2579, 0x01 },
+ { 0x257A, 0x92 },
+ { 0x257B, 0x01 },
+ { 0x257C, 0xB8 },
+ { 0x257D, 0x02 },
+ { 0x257E, 0xBA },
+ { 0x257F, 0x02 },
+ { 0x2584, 0x90 },
+ { 0x2585, 0x01 },
+ { 0x2586, 0x92 },
+ { 0x2587, 0x01 },
+ { 0x2588, 0xB8 },
+ { 0x2589, 0x02 },
+ { 0x258A, 0xBA },
+ { 0x258B, 0x02 },
+ { 0x267A, 0xF8 },
+ { 0x267B, 0x00 },
+ { 0x267C, 0x16 },
+ { 0x267D, 0x01 },
+ { 0x267E, 0xA6 },
+ { 0x267F, 0x02 },
+ { 0x2680, 0xD5 },
+ { 0x2681, 0x02 },
+ { 0x2690, 0xF8 },
+ { 0x2691, 0x00 },
+ { 0x2694, 0xA6 },
+ { 0x2695, 0x02 },
+ { 0x2696, 0x16 },
+ { 0x2697, 0x01 },
+ { 0x269A, 0xD5 },
+ { 0x269B, 0x02 },
+ { 0x26B8, 0x10 },
+ { 0x26B9, 0x00 },
+ { 0x26BA, 0x33 },
+ { 0x26BB, 0x00 },
+ { 0x26BC, 0x89 },
+ { 0x26BD, 0x00 },
+ { 0x26BE, 0xB0 },
+ { 0x26BF, 0x00 },
+ { 0x26C4, 0x4E },
+ { 0x26C5, 0x00 },
+ { 0x26C8, 0xC9 },
+ { 0x26C9, 0x00 },
+ { 0x26CC, 0x35 },
+ { 0x26CD, 0x01 },
+ { 0x26D0, 0xBA },
+ { 0x26D1, 0x01 },
+ { 0x26D4, 0x7C },
+ { 0x26D5, 0x02 },
+ { 0x26D8, 0xF6 },
+ { 0x26D9, 0x02 },
+ { 0x26DE, 0x51 },
+ { 0x26DF, 0x00 },
+ { 0x26E0, 0x7F },
+ { 0x26E1, 0x00 },
+ { 0x26E2, 0xCC },
+ { 0x26E3, 0x00 },
+ { 0x26E4, 0xF8 },
+ { 0x26E5, 0x00 },
+ { 0x26E6, 0x38 },
+ { 0x26E7, 0x01 },
+ { 0x26E8, 0x65 },
+ { 0x26E9, 0x01 },
+ { 0x26EA, 0xBD },
+ { 0x26EB, 0x01 },
+ { 0x26EE, 0x7F },
+ { 0x26EF, 0x02 },
+ { 0x26F0, 0xAB },
+ { 0x26F1, 0x02 },
+ { 0x26F2, 0xF9 },
+ { 0x26F3, 0x02 },
+ { 0x2722, 0x59 },
+ { 0x2723, 0x02 },
+ { 0x2938, 0x55 },
+ { 0x2939, 0x00 },
+ { 0x293A, 0x17 },
+ { 0x293B, 0x00 },
+ { 0x293C, 0xD0 },
+ { 0x293D, 0x00 },
+ { 0x293E, 0x91 },
+ { 0x293F, 0x00 },
+ { 0x2940, 0x3C },
+ { 0x2941, 0x01 },
+ { 0x2942, 0x0C },
+ { 0x2943, 0x01 },
+ { 0x2944, 0xC1 },
+ { 0x2945, 0x01 },
+ { 0x2946, 0x76 },
+ { 0x2947, 0x01 },
+ { 0x2948, 0x83 },
+ { 0x2949, 0x02 },
+ { 0x294A, 0xFB },
+ { 0x294B, 0x01 },
+ { 0x294C, 0xFD },
+ { 0x294D, 0x02 },
+ { 0x294E, 0xBF },
+ { 0x294F, 0x02 },
+ { 0x2A06, 0x25 },
+ { 0x2A07, 0x03 },
+ { 0x2A0C, 0x45 },
+ { 0x2A0D, 0x00 },
+ { 0x2A0E, 0x00 },
+ { 0x2A0F, 0x00 },
+ { 0x2A20, 0x00 },
+ { 0x2A21, 0x00 },
+ { 0x2A22, 0x7D },
+ { 0x2A23, 0x00 },
+ { 0x2B11, 0x1A },
+ { 0x2B13, 0x11 },
+ { 0x2B14, 0x11 },
+ { 0x2B15, 0x11 },
+ { 0x2B16, 0x11 },
+ { 0x2B17, 0x10 },
+ { 0x2B18, 0x0F },
+ { 0x2B19, 0x0E },
+ { 0x2B1A, 0x0D },
+ { 0x2B1B, 0x0C },
+ { 0x2B1C, 0x0B },
+ { 0x2B1D, 0x0B },
+ { 0x2B1E, 0x0A },
+ { 0x2B1F, 0x09 },
+ { 0x2B20, 0x08 },
+ { 0x2B21, 0x07 },
+ { 0x2B22, 0x06 },
+ { 0x2B23, 0x05 },
+ { 0x2B24, 0x04 },
+ { 0x2B25, 0x03 },
+ { 0x2B26, 0x03 },
+ { 0x2B38, 0x01 },
+ { 0x2B45, 0xE3 },
+ { 0x2B50, 0x01 },
+ { 0x2B51, 0x00 },
+ { 0x2B62, 0x66 },
+ { 0x2B6D, 0x47 },
+ { 0x2B70, 0x03 },
+ { 0x2B71, 0x02 },
+ { 0x2B72, 0x02 },
+ { 0x2B7B, 0x42 },
+ { 0x2B7F, 0x7F },
+ { 0x2B80, 0x94 },
+ { 0x2B81, 0x06 },
+ { 0x2B87, 0x1B },
+ { 0x2B88, 0x1A },
+ { 0x2B89, 0x17 },
+ { 0x2B8A, 0x17 },
+ { 0x2B8B, 0x12 },
+ { 0x2B8D, 0x2B },
+ { 0x2B8E, 0x2B },
+ { 0x2B8F, 0x2B },
+ { 0x2B90, 0x7F },
+ { 0x2B91, 0x0F },
+ { 0x2B92, 0x31 },
+ { 0x2B93, 0x07 },
+ { 0x2B94, 0xFE },
+ { 0x2B95, 0x26 },
+ { 0x2B96, 0x84 },
+ { 0x2B97, 0x0C },
+ { 0x2B98, 0xFE },
+ { 0x2B99, 0x56 },
+ { 0x2B9B, 0x2A },
+ { 0x2BA8, 0xBC },
+ { 0x2BA9, 0x62 },
+ { 0x2BC1, 0x70 },
+ { 0x2BC5, 0x80 },
+ { 0x2BD5, 0x30 },
+ { 0x2BD6, 0xF0 },
+ { 0x2BD8, 0xDB },
+ { 0x2BD9, 0xF6 },
+ { 0x2BDA, 0x21 },
+ { 0x2BDB, 0x06 },
+ { 0x2BDC, 0x57 },
+ { 0x2BFE, 0x00 },
+ { 0x2BFF, 0x00 },
+ { 0x2C98, 0xE1 },
+ { 0x2C99, 0x2E },
+ { 0x2C9B, 0x80 },
+ { 0x2CA9, 0x80 },
+ { 0x2CAA, 0x01 },
+ { 0x2CBF, 0x08 },
+ { 0x2D39, 0x0E },
+ { 0x2D50, 0x80 },
+ { 0x2D54, 0x00 },
+ { 0x2D5B, 0x58 },
+ { 0x2DFD, 0x01 },
+ { 0x2D64, 0x64 },
+ { 0x2D65, 0x80 },
+ { 0x3000, 0x00 },
+ { 0x3001, 0x00 },
+ { 0x3002, 0x23 },
+ { 0x3003, 0xA1 },
+ { 0x3004, 0x00 },
+ { 0x3005, 0x20 },
+ { 0x3006, 0x58 },
+ { 0x3007, 0x00 },
+ { 0x3008, 0x06 },
+ { 0x3009, 0xB4 },
+ { 0x300A, 0x1F },
+ { 0x300B, 0x00 },
+ { 0x300C, 0x00 },
+ { 0x300D, 0x1B },
+ { 0x300E, 0x90 },
+ { 0x300F, 0x97 },
+ { 0x3010, 0x00 },
+ { 0x3011, 0x00 },
+ { 0x3012, 0x20 },
+ { 0x3013, 0x21 },
+ { 0x3014, 0x00 },
+ { 0x3015, 0x20 },
+ { 0x3016, 0x84 },
+ { 0x3017, 0x00 },
+ { 0x3018, 0x30 },
+ { 0x3019, 0x09 },
+ { 0x301A, 0x46 },
+ { 0x301B, 0x00 },
+ { 0x3070, 0xC1 },
+ { 0x3071, 0x81 },
+ { 0x3072, 0x29 },
+ { 0x3073, 0x81 },
+ { 0x3080, 0xC4 },
+ { 0x3081, 0x0C },
+ { 0x3082, 0xD2 },
+ { 0x3083, 0x0C },
+ { 0x3084, 0x5C },
+ { 0x3085, 0x00 },
+ { 0x3086, 0x90 },
+ { 0x3087, 0x00 },
+ { 0x3088, 0x07 },
+ { 0x3089, 0x0A },
+ { 0x308A, 0x52 },
+ { 0x308B, 0x09 },
+ { 0x308C, 0x44 },
+ { 0x308D, 0x03 },
+ { 0x308E, 0x70 },
+ { 0x308F, 0x03 },
+ { 0x3090, 0x54 },
+ { 0x3091, 0x09 },
+ { 0x3092, 0x5A },
+ { 0x3093, 0x09 },
+ { 0x3094, 0x1C },
+ { 0x3095, 0x00 },
+ { 0x3096, 0x10 },
+ { 0x3097, 0x00 },
+ { 0x3098, 0x70 },
+ { 0x3099, 0x03 },
+ { 0x309A, 0xF8 },
+ { 0x309B, 0x04 },
+ { 0x309C, 0x74 },
+ { 0x309D, 0x01 },
+ { 0x309E, 0x60 },
+ { 0x309F, 0x01 },
+ { 0x3370, 0x01 },
+ { 0x3374, 0xF0 },
+ { 0x3375, 0x00 },
+ { 0x3376, 0x01 },
+ { 0x3377, 0x00 },
+ { 0x3410, (IMX390_OUT_WIDTH & 0xFF) },
+ { 0x3411, (IMX390_OUT_WIDTH >> 8) },
+ { 0x3418, (IMX390_OUT_HEIGHT & 0xFF) },
+ { 0x3419, (IMX390_OUT_HEIGHT >> 8) },
+ { 0x34A0, 0x30 },
+ { 0x34BE, 0x6A },
+ { 0x34BF, 0x01 },
+ { 0x34C0, 0x40 },
+ { 0x34C1, 0x00 },
+ { 0x34C2, 0x40 },
+ { 0x34C3, 0x00 },
+ { 0x34C4, 0x40 },
+ { 0x34C5, 0x00 },
+ { 0x34C6, 0x40 },
+ { 0x34C7, 0x00 },
+ { 0x34C8, 0x40 },
+ { 0x34C9, 0x00 },
+ { 0x34CA, 0x40 },
+ { 0x34CB, 0x00 },
+ { 0x34CC, 0x40 },
+ { 0x34CD, 0x00 },
+ { 0x34CE, 0x40 },
+ { 0x34CF, 0x00 },
+ { 0x3584, 0x00 },
+ { 0x3586, 0x00 },
+ { 0x3587, 0x01 },
+ { 0x3588, 0xE6 },
+ { 0x3589, 0x00 },
+ { 0x3590, 0x00 },
+ { 0x3591, 0x00 },
+ { 0x3594, 0x40 },
+ { 0x3598, 0x03 },
+ { 0x3599, 0x00 },
+ { 0x359A, 0x80 },
+ { 0x359B, 0x00 },
+ { 0x359C, 0x00 },
+ { 0x359D, 0x01 },
+ { 0x359E, 0x00 },
+ { 0x359F, 0x02 },
+ { 0x35A0, 0x00 },
+ { 0x35A1, 0x04 },
+ { 0x35A2, 0x20 },
+ { 0x35A3, 0x00 },
+ { 0x35A4, 0x40 },
+ { 0x35A5, 0x00 },
+ { 0x35A6, 0x80 },
+ { 0x35A7, 0x00 },
+ { 0x35A8, 0x00 },
+ { 0x35A9, 0x01 },
+ { 0x35AC, 0x80 },
+ { 0x35AD, 0x00 },
+ { 0x35AE, 0x00 },
+ { 0x35AF, 0x01 },
+ { 0x35B0, 0x00 },
+ { 0x35B1, 0x02 },
+ { 0x35B2, 0x00 },
+ { 0x35B3, 0x04 },
+ { 0x35B4, 0x02 },
+ { 0x35B5, 0x00 },
+ { 0x35B6, 0x04 },
+ { 0x35B7, 0x00 },
+ { 0x35B8, 0x08 },
+ { 0x35B9, 0x00 },
+ { 0x35BA, 0x10 },
+ { 0x35BB, 0x00 },
+ { 0x35C8, 0x00 },
+ { 0x35C9, 0x01 },
+ { 0x35CA, 0x00 },
+ { 0x35CB, 0x04 },
+ { 0x35CC, 0x00 },
+ { 0x35CD, 0x10 },
+ { 0x35CE, 0x00 },
+ { 0x35CF, 0x40 },
+ { 0x35D0, 0x00 },
+ { 0x35D1, 0x0C },
+ { 0x35D2, 0x00 },
+ { 0x35D3, 0x0C },
+ { 0x35D4, 0x00 },
+ { 0x35D5, 0x0C },
+ { 0x35D6, 0x00 },
+ { 0x35D7, 0x0C },
+ { 0x35D8, 0x00 },
+ { 0x35D9, 0x00 },
+ { 0x35DA, 0x08 },
+ { 0x35DB, 0x00 },
+ { 0x35DC, 0xD8 },
+ { 0x35DD, 0x0E },
+ { 0x35F0, 0x00 },
+ { 0x35F1, 0x10 },
+ { 0x35F2, 0x00 },
+ { 0x35F3, 0x10 },
+ { 0x35F4, 0x00 },
+ { 0x35F5, 0x10 },
+ { 0x35F6, 0x00 },
+ { 0x35F7, 0x03 },
+ { 0x35F8, 0x00 },
+ { 0x35F9, 0x02 },
+ { 0x35FA, 0x38 },
+ { 0x35FB, 0x00 },
+ { 0x35FC, 0xB3 },
+ { 0x35FD, 0x01 },
+ { 0x35FE, 0x00 },
+ { 0x35FF, 0x00 },
+ { 0x3600, 0x05 },
+ { 0x3601, 0x06 },
+ { 0x3604, 0x03 },
+ { 0x3605, 0x00 },
+ { 0x3608, 0x03 },
+ { 0x3609, 0x00 },
+ { 0x360C, 0x00 },
+ { 0x360D, 0x00 },
+ { 0x3610, 0x10 },
+ { 0x3611, 0x01 },
+ { 0x3612, 0x00 },
+ { 0x3613, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3615, 0x00 },
+ { 0x361C, 0x00 },
+ { 0x361D, 0x01 },
+ { 0x361E, 0x00 },
+ { 0x361F, 0x01 },
+ { 0x3620, 0x00 },
+ { 0x3621, 0x00 },
+ { 0x3622, 0xB0 },
+ { 0x3623, 0x04 },
+ { 0x3624, 0xDC },
+ { 0x3625, 0x05 },
+ { 0x3626, 0x00 },
+ { 0x3627, 0x01 },
+ { 0x3628, 0xFF },
+ { 0x3629, 0x0F },
+ { 0x362A, 0x00 },
+ { 0x362B, 0x10 },
+ { 0x362C, 0x00 },
+ { 0x362D, 0x01 },
+ { 0x3630, 0x41 },
+ { 0x3631, 0x00 },
+ { 0x3632, 0x41 },
+ { 0x3633, 0x00 },
+ { 0x3634, 0x41 },
+ { 0x3635, 0x00 },
+ { 0x3636, 0x41 },
+ { 0x3637, 0x00 },
+ { 0x3638, 0x44 },
+ { 0x3639, 0x00 },
+ { 0x363A, 0x47 },
+ { 0x363B, 0x00 },
+ { 0x363C, 0x47 },
+ { 0x363D, 0x00 },
+ { 0x363E, 0x44 },
+ { 0x363F, 0x00 },
+ { 0x36C4, 0xFF },
+ { 0x36C5, 0x0F },
+ { 0x36C6, 0xFF },
+ { 0x36C7, 0x0F },
+ { 0x36C8, 0xFF },
+ { 0x36C9, 0x0F },
+ { 0x36CC, 0x00 },
+ { 0x36CD, 0x00 },
+ { 0x36CE, 0x00 },
+ { 0x36CF, 0x00 },
+ { 0x36D0, 0x00 },
+ { 0x36D1, 0x00 },
+ { 0x36D4, 0xFF },
+ { 0x36D5, 0x0F },
+ { 0x36D6, 0xFF },
+ { 0x36D7, 0x0F },
+ { 0x36D8, 0xFF },
+ { 0x36D9, 0x0F },
+ { 0x36DC, 0xFF },
+ { 0x36DD, 0x0F },
+ { 0x36DE, 0xFF },
+ { 0x36DF, 0x0F },
+ { 0x36E0, 0xFF },
+ { 0x36E1, 0x0F },
+ { 0x36E4, 0xFF },
+ { 0x36E5, 0x0F },
+ { 0x36E6, 0xFF },
+ { 0x36E7, 0x0F },
+ { 0x36E8, 0xFF },
+ { 0x36E9, 0x0F },
+ { 0x36EE, 0x00 },
+ { 0x36EF, 0x00 },
+ { 0x36F0, 0x00 },
+ { 0x36F1, 0x80 },
+ { 0x36F8, 0x01 },
+ { 0x3700, 0x03 },
+ { 0x3701, 0x05 },
+ { 0x3702, 0x03 },
+ { 0x3703, 0x04 },
+ { 0x3704, 0x08 },
+ { 0x3705, 0x03 },
+ { 0x3706, 0x03 },
+ { 0x3707, 0x03 },
+ { 0x3708, 0x03 },
+ { 0x3709, 0x03 },
+ { 0x370A, 0x03 },
+ { 0x370B, 0x03 },
+ { 0x370C, 0x03 },
+ { 0x370D, 0x03 },
+ { 0x370E, 0x0E },
+ { 0x3718, 0x64 },
+ { 0x3719, 0x47 },
+ { 0x371A, 0x36 },
+ { 0x371B, 0x1E },
+ { 0x371C, 0x50 },
+ { 0x371D, 0x41 },
+ { 0x371E, 0x2F },
+ { 0x371F, 0x1A },
+ { 0x3720, 0x95 },
+ { 0x3721, 0x9D },
+ { 0x3722, 0xA5 },
+ { 0x3723, 0xAD },
+ { 0x3748, 0xA8 },
+ { 0x3749, 0x9E },
+ { 0x374A, 0x94 },
+ { 0x374B, 0x80 },
+ { 0x37C0, 0x00 },
+ { 0x37C1, 0x00 },
+ { 0x37C2, 0x00 },
+ { 0x37C4, 0x00 },
+ { 0x37C5, 0x00 },
+ { 0x37C6, 0x00 },
+ { 0x37C8, 0x00 },
+ { 0x37C9, 0x00 },
+ { 0x37CA, 0x00 },
+ { 0x37CC, 0x00 },
+ { 0x37CD, 0x00 },
+ { 0x37CE, 0x00 },
+ { 0x37D0, 0x00 },
+ { 0x37D1, 0x00 },
+ { 0x37D2, 0x00 },
+ { 0x37D4, 0x00 },
+ { 0x37D5, 0x00 },
+ { 0x37D6, 0x00 },
+ { 0x37D8, 0x00 },
+ { 0x37D9, 0x00 },
+ { 0x37DA, 0x00 },
+ { 0x37DC, 0x00 },
+ { 0x37DD, 0x00 },
+ { 0x37DE, 0x00 },
+ { 0x37E0, 0x00 },
+ { 0x37E1, 0x00 },
+ { 0x37E2, 0x00 },
+ { 0x37E4, 0x00 },
+ { 0x37E5, 0x00 },
+ { 0x37E6, 0x00 },
+ { 0x37E8, 0x00 },
+ { 0x37E9, 0x00 },
+ { 0x37EA, 0x00 },
+ { 0x37EC, 0x00 },
+ { 0x37ED, 0x00 },
+ { 0x37EE, 0x00 },
+ { 0x37F0, 0x00 },
+ { 0x37F4, 0x00 },
+ { 0x37F5, 0x1E },
+ { 0x37F6, 0x34 },
+ { 0x37F7, 0x00 },
+ { 0x37F8, 0xFF },
+ { 0x37F9, 0xFF },
+ { 0x37FA, 0x03 },
+ { 0x37FC, 0x00 },
+ { 0x37FD, 0x00 },
+ { 0x37FE, 0x04 },
+ { 0x3800, 0xFF },
+ { 0x3801, 0xFF },
+ { 0x3802, 0x03 },
+ { 0x3804, 0x00 },
+ { 0x3805, 0x00 },
+ { 0x3806, 0x04 },
+ { 0x3808, 0x00 },
+ { 0x3809, 0x00 },
+ { 0x380A, 0x00 },
+ { 0x380C, 0x00 },
+ { 0x380D, 0x00 },
+ { 0x380E, 0x00 },
+ { 0x3810, 0x00 },
+ { 0x3811, 0x00 },
+ { 0x3812, 0x00 },
+ { 0x3814, 0x00 },
+ { 0x3815, 0x00 },
+ { 0x3816, 0x00 },
+ { 0x3818, 0x00 },
+ { 0x3819, 0x00 },
+ { 0x381A, 0x00 },
+ { 0x381C, 0x00 },
+ { 0x381D, 0x00 },
+ { 0x381E, 0x00 },
+ { 0x3820, 0x00 },
+ { 0x3821, 0x00 },
+ { 0x3822, 0x00 },
+ { 0x3824, 0x00 },
+ { 0x3825, 0x00 },
+ { 0x3826, 0x00 },
+ { 0x3828, 0x00 },
+ { 0x3829, 0x00 },
+ { 0x382A, 0x00 },
+ { 0x382C, 0x00 },
+ { 0x382D, 0x00 },
+ { 0x382E, 0x00 },
+ { 0x3830, 0x00 },
+ { 0x3831, 0x00 },
+ { 0x3832, 0x00 },
+ { 0x3834, 0x00 },
+ { 0x3835, 0x00 },
+ { 0x3836, 0x00 },
+ { 0x3838, 0x47 },
+ { 0x3839, 0x00 },
+ { 0x383A, 0x34 },
+ { 0x383B, 0x00 },
+ { 0x383C, 0x48 },
+ { 0x383D, 0x00 },
+ { 0x383E, 0x39 },
+ { 0x383F, 0x00 },
+ { 0x3840, 0x13 },
+ { 0x3841, 0x00 },
+ { 0x3842, 0x13 },
+ { 0x3843, 0x00 },
+ { 0x3844, 0x1D },
+ { 0x3845, 0x00 },
+ { 0x3846, 0x1D },
+ { 0x3847, 0x00 },
+ { 0x3848, 0x08 },
+ { 0x3849, 0x00 },
+ { 0x384A, 0x07 },
+ { 0x384B, 0x00 },
+ { 0x384C, 0x05 },
+ { 0x384D, 0x00 },
+ { 0x384E, 0x00 },
+ { 0x384F, 0x00 },
+ { 0x3850, 0xFF },
+ { 0x3851, 0x0F },
+ { 0x3852, 0x00 },
+ { 0x3853, 0x10 },
+ { 0x3854, 0xFF },
+ { 0x3855, 0x0F },
+ { 0x3856, 0x00 },
+ { 0x3857, 0x10 },
+ { 0x3858, 0xFF },
+ { 0x3859, 0x0F },
+ { 0x385A, 0x00 },
+ { 0x385B, 0x10 },
+ { 0x385C, 0x02 },
+ { 0x385D, 0x00 },
+ { 0x385E, 0x06 },
+ { 0x385F, 0x00 },
+ { 0x3860, 0x06 },
+ { 0x3861, 0x00 },
+ { 0x3862, 0x08 },
+ { 0x3863, 0x00 },
+ { 0x3864, 0x02 },
+ { 0x3865, 0x00 },
+ { 0x3870, 0x00 },
+ { 0x3871, 0x01 },
+ { 0x38A0, 0x01 },
+ { 0x38A1, 0x01 },
+ { 0x38A2, 0x00 },
+ { 0x38A3, 0x01 },
+ { 0x38A4, 0x07 },
+ { 0x38A5, 0x00 },
+ { 0x38A6, 0x04 },
+ { 0x38A7, 0x04 },
+ { 0x38A8, 0x00 },
+ { 0x38A9, 0x00 },
+ { 0x38AC, 0x00 },
+ { 0x38AD, 0x00 },
+ { 0x38AE, 0x01 },
+ { 0x38B0, 0x02 },
+ { 0x38B2, 0x43 },
+ { 0x38B3, 0x00 },
+ { 0x38B4, 0x10 },
+ { 0x38B5, 0x00 },
+ { 0x38B6, 0x09 },
+ { 0x38B7, 0x00 },
+ { 0x38B8, 0x09 },
+ { 0x38B9, 0x00 },
+ { 0x38BA, 0x47 },
+ { 0x38BB, 0x00 },
+ { 0x38BC, 0x16 },
+ { 0x38BD, 0x00 },
+ { 0x38BE, 0x0E },
+ { 0x38BF, 0x00 },
+ { 0x38C0, 0x0B },
+ { 0x38C1, 0x00 },
+ { 0x38C2, 0x4A },
+ { 0x38C3, 0x00 },
+ { 0x38C4, 0x1C },
+ { 0x38C5, 0x00 },
+ { 0x38C6, 0x12 },
+ { 0x38C7, 0x00 },
+ { 0x38C8, 0x0D },
+ { 0x38C9, 0x00 },
+ { 0x38CA, 0x51 },
+ { 0x38CB, 0x00 },
+ { 0x38CC, 0x24 },
+ { 0x38CD, 0x00 },
+ { 0x38CE, 0x19 },
+ { 0x38CF, 0x00 },
+ { 0x38D0, 0x10 },
+ { 0x38D1, 0x00 },
+ { 0x38D2, 0x5D },
+ { 0x38D3, 0x00 },
+ { 0x38D4, 0x30 },
+ { 0x38D5, 0x00 },
+ { 0x38D6, 0x23 },
+ { 0x38D7, 0x00 },
+ { 0x38D8, 0x17 },
+ { 0x38D9, 0x00 },
+ { 0x38DA, 0x72 },
+ { 0x38DB, 0x00 },
+ { 0x38DC, 0x43 },
+ { 0x38DD, 0x00 },
+ { 0x38DE, 0x31 },
+ { 0x38DF, 0x00 },
+ { 0x38E0, 0x20 },
+ { 0x38E1, 0x00 },
+ { 0x38E2, 0x96 },
+ { 0x38E3, 0x00 },
+ { 0x38E4, 0x5E },
+ { 0x38E5, 0x00 },
+ { 0x38E6, 0x46 },
+ { 0x38E7, 0x00 },
+ { 0x38E8, 0x2E },
+ { 0x38E9, 0x00 },
+ { 0x38EA, 0xD4 },
+ { 0x38EB, 0x00 },
+ { 0x38EC, 0x87 },
+ { 0x38ED, 0x00 },
+ { 0x38EE, 0x65 },
+ { 0x38EF, 0x00 },
+ { 0x38F0, 0x43 },
+ { 0x38F1, 0x00 },
+ { 0x38F2, 0x3F },
+ { 0x38F3, 0x01 },
+ { 0x38F4, 0xC4 },
+ { 0x38F5, 0x00 },
+ { 0x38F6, 0x94 },
+ { 0x38F7, 0x00 },
+ { 0x38F8, 0x64 },
+ { 0x38F9, 0x00 },
+ { 0x38FA, 0x00 },
+ { 0x38FB, 0x01 },
+ { 0x38FC, 0x00 },
+ { 0x38FD, 0x01 },
+ { 0x38FE, 0x00 },
+ { 0x38FF, 0x01 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x01 },
+ { 0x3902, 0x60 },
+ { 0x3903, 0x00 },
+ { 0x3904, 0x25 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x18 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x10 },
+ { 0x3909, 0x00 },
+ { 0x390A, 0xE6 },
+ { 0x390B, 0x00 },
+ { 0x390C, 0xD5 },
+ { 0x390D, 0x00 },
+ { 0x390E, 0xAA },
+ { 0x390F, 0x00 },
+ { 0x3910, 0x85 },
+ { 0x3911, 0x00 },
+ { 0x3912, 0xE6 },
+ { 0x3913, 0x00 },
+ { 0x3914, 0xD5 },
+ { 0x3915, 0x00 },
+ { 0x3916, 0xAA },
+ { 0x3917, 0x00 },
+ { 0x3918, 0x85 },
+ { 0x3919, 0x00 },
+ { 0x391A, 0xE6 },
+ { 0x391B, 0x00 },
+ { 0x391C, 0xD5 },
+ { 0x391D, 0x00 },
+ { 0x391E, 0xAA },
+ { 0x391F, 0x00 },
+ { 0x3920, 0x85 },
+ { 0x3921, 0x00 },
+ { 0x3922, 0x40 },
+ { 0x3923, 0x00 },
+ { 0x3924, 0x40 },
+ { 0x3925, 0x00 },
+ { 0x3926, 0x40 },
+ { 0x3927, 0x00 },
+ { 0x3928, 0x40 },
+ { 0x3929, 0x00 },
+ { 0x392A, 0x80 },
+ { 0x392B, 0x00 },
+ { 0x392C, 0x80 },
+ { 0x392D, 0x00 },
+ { 0x392E, 0x80 },
+ { 0x392F, 0x00 },
+ { 0x3930, 0x80 },
+ { 0x3931, 0x00 },
+ { 0x3932, 0x4C },
+ { 0x3933, 0x4C },
+ { 0x3934, 0x4C },
+ { 0x3940, 0x01 },
+ { 0x3941, 0x01 },
+ { 0x3942, 0x00 },
+ { 0x3943, 0x01 },
+ { 0x3944, 0x07 },
+ { 0x3945, 0x00 },
+ { 0x3946, 0x04 },
+ { 0x3947, 0x04 },
+ { 0x3948, 0x00 },
+ { 0x3949, 0x00 },
+ { 0x394C, 0x00 },
+ { 0x394D, 0x00 },
+ { 0x394E, 0x01 },
+ { 0x3950, 0x03 },
+ { 0x3952, 0x1B },
+ { 0x3953, 0x00 },
+ { 0x3954, 0x0C },
+ { 0x3955, 0x00 },
+ { 0x3956, 0x09 },
+ { 0x3957, 0x00 },
+ { 0x3958, 0x07 },
+ { 0x3959, 0x00 },
+ { 0x395A, 0x1D },
+ { 0x395B, 0x00 },
+ { 0x395C, 0x0E },
+ { 0x395D, 0x00 },
+ { 0x395E, 0x0B },
+ { 0x395F, 0x00 },
+ { 0x3960, 0x08 },
+ { 0x3961, 0x00 },
+ { 0x3962, 0x1E },
+ { 0x3963, 0x00 },
+ { 0x3964, 0x10 },
+ { 0x3965, 0x00 },
+ { 0x3966, 0x0C },
+ { 0x3967, 0x00 },
+ { 0x3968, 0x09 },
+ { 0x3969, 0x00 },
+ { 0x396A, 0x21 },
+ { 0x396B, 0x00 },
+ { 0x396C, 0x13 },
+ { 0x396D, 0x00 },
+ { 0x396E, 0x0E },
+ { 0x396F, 0x00 },
+ { 0x3970, 0x0A },
+ { 0x3971, 0x00 },
+ { 0x3972, 0x25 },
+ { 0x3973, 0x00 },
+ { 0x3974, 0x19 },
+ { 0x3975, 0x00 },
+ { 0x3976, 0x12 },
+ { 0x3977, 0x00 },
+ { 0x3978, 0x0D },
+ { 0x3979, 0x00 },
+ { 0x397A, 0x2E },
+ { 0x397B, 0x00 },
+ { 0x397C, 0x21 },
+ { 0x397D, 0x00 },
+ { 0x397E, 0x19 },
+ { 0x397F, 0x00 },
+ { 0x3980, 0x11 },
+ { 0x3981, 0x00 },
+ { 0x3982, 0x3C },
+ { 0x3983, 0x00 },
+ { 0x3984, 0x2F },
+ { 0x3985, 0x00 },
+ { 0x3986, 0x23 },
+ { 0x3987, 0x00 },
+ { 0x3988, 0x19 },
+ { 0x3989, 0x00 },
+ { 0x398A, 0x56 },
+ { 0x398B, 0x00 },
+ { 0x398C, 0x44 },
+ { 0x398D, 0x00 },
+ { 0x398E, 0x35 },
+ { 0x398F, 0x00 },
+ { 0x3990, 0x27 },
+ { 0x3991, 0x00 },
+ { 0x3992, 0x84 },
+ { 0x3993, 0x00 },
+ { 0x3994, 0x68 },
+ { 0x3995, 0x00 },
+ { 0x3996, 0x53 },
+ { 0x3997, 0x00 },
+ { 0x3998, 0x40 },
+ { 0x3999, 0x00 },
+ { 0x399A, 0x00 },
+ { 0x399B, 0x01 },
+ { 0x399C, 0x00 },
+ { 0x399D, 0x01 },
+ { 0x399E, 0x00 },
+ { 0x399F, 0x01 },
+ { 0x39A0, 0x00 },
+ { 0x39A1, 0x01 },
+ { 0x39A2, 0x60 },
+ { 0x39A3, 0x00 },
+ { 0x39A4, 0x20 },
+ { 0x39A5, 0x00 },
+ { 0x39A6, 0x15 },
+ { 0x39A7, 0x00 },
+ { 0x39A8, 0x10 },
+ { 0x39A9, 0x00 },
+ { 0x39AA, 0xE6 },
+ { 0x39AB, 0x00 },
+ { 0x39AC, 0xD5 },
+ { 0x39AD, 0x00 },
+ { 0x39AE, 0xAA },
+ { 0x39AF, 0x00 },
+ { 0x39B0, 0x85 },
+ { 0x39B1, 0x00 },
+ { 0x39B2, 0xE6 },
+ { 0x39B3, 0x00 },
+ { 0x39B4, 0xD5 },
+ { 0x39B5, 0x00 },
+ { 0x39B6, 0xAA },
+ { 0x39B7, 0x00 },
+ { 0x39B8, 0x85 },
+ { 0x39B9, 0x00 },
+ { 0x39BA, 0xE6 },
+ { 0x39BB, 0x00 },
+ { 0x39BC, 0xD5 },
+ { 0x39BD, 0x00 },
+ { 0x39BE, 0xAA },
+ { 0x39BF, 0x00 },
+ { 0x39C0, 0x85 },
+ { 0x39C1, 0x00 },
+ { 0x39C2, 0x40 },
+ { 0x39C3, 0x00 },
+ { 0x39C4, 0x40 },
+ { 0x39C5, 0x00 },
+ { 0x39C6, 0x40 },
+ { 0x39C7, 0x00 },
+ { 0x39C8, 0x40 },
+ { 0x39C9, 0x00 },
+ { 0x39CA, 0x80 },
+ { 0x39CB, 0x00 },
+ { 0x39CC, 0x80 },
+ { 0x39CD, 0x00 },
+ { 0x39CE, 0x80 },
+ { 0x39CF, 0x00 },
+ { 0x39D0, 0x80 },
+ { 0x39D1, 0x00 },
+ { 0x39D2, 0x4C },
+ { 0x39D3, 0x4C },
+ { 0x39D4, 0x4C },
+ { 0x39E0, 0x01 },
+ { 0x39E1, 0x00 },
+ { 0x39E4, 0x40 },
+ { 0x39E5, 0x01 },
+ { 0x39E6, 0x01 },
+ { 0x39E8, 0x00 },
+ { 0x39E9, 0x01 },
+ { 0x39EA, 0x00 },
+ { 0x39EB, 0x00 },
+ { 0x39EC, 0x01 },
+ { 0x39ED, 0x00 },
+ { 0x39EE, 0x01 },
+ { 0x39F0, 0x03 },
+ { 0x39F1, 0x04 },
+ { 0x39F2, 0x0E },
+ { 0x39F4, 0x19 },
+ { 0x39F5, 0x00 },
+ { 0x39F6, 0x12 },
+ { 0x39F7, 0x00 },
+ { 0x39F8, 0x0D },
+ { 0x39F9, 0x00 },
+ { 0x39FA, 0x07 },
+ { 0x39FB, 0x00 },
+ { 0x39FC, 0x2B },
+ { 0x39FD, 0x00 },
+ { 0x39FE, 0x1B },
+ { 0x39FF, 0x00 },
+ { 0x3A00, 0x11 },
+ { 0x3A01, 0x00 },
+ { 0x3A02, 0x08 },
+ { 0x3A03, 0x00 },
+ { 0x3A04, 0x37 },
+ { 0x3A05, 0x00 },
+ { 0x3A06, 0x21 },
+ { 0x3A07, 0x00 },
+ { 0x3A08, 0x14 },
+ { 0x3A09, 0x00 },
+ { 0x3A0A, 0x09 },
+ { 0x3A0B, 0x00 },
+ { 0x3A0C, 0x4A },
+ { 0x3A0D, 0x00 },
+ { 0x3A0E, 0x2C },
+ { 0x3A0F, 0x00 },
+ { 0x3A10, 0x18 },
+ { 0x3A11, 0x00 },
+ { 0x3A12, 0x0B },
+ { 0x3A13, 0x00 },
+ { 0x3A14, 0x66 },
+ { 0x3A15, 0x00 },
+ { 0x3A16, 0x3B },
+ { 0x3A17, 0x00 },
+ { 0x3A18, 0x20 },
+ { 0x3A19, 0x00 },
+ { 0x3A1A, 0x0F },
+ { 0x3A1B, 0x00 },
+ { 0x3A1C, 0x8E },
+ { 0x3A1D, 0x00 },
+ { 0x3A1E, 0x51 },
+ { 0x3A1F, 0x00 },
+ { 0x3A20, 0x2B },
+ { 0x3A21, 0x00 },
+ { 0x3A22, 0x14 },
+ { 0x3A23, 0x00 },
+ { 0x3A24, 0xC8 },
+ { 0x3A25, 0x00 },
+ { 0x3A26, 0x72 },
+ { 0x3A27, 0x00 },
+ { 0x3A28, 0x3C },
+ { 0x3A29, 0x00 },
+ { 0x3A2A, 0x1B },
+ { 0x3A2B, 0x00 },
+ { 0x3A2C, 0x19 },
+ { 0x3A2D, 0x01 },
+ { 0x3A2E, 0xA0 },
+ { 0x3A2F, 0x00 },
+ { 0x3A30, 0x54 },
+ { 0x3A31, 0x00 },
+ { 0x3A32, 0x25 },
+ { 0x3A33, 0x00 },
+ { 0x3A34, 0x8D },
+ { 0x3A35, 0x01 },
+ { 0x3A36, 0xE1 },
+ { 0x3A37, 0x00 },
+ { 0x3A38, 0x76 },
+ { 0x3A39, 0x00 },
+ { 0x3A3A, 0x35 },
+ { 0x3A3B, 0x00 },
+ { 0x3A3C, 0x00 },
+ { 0x3A3D, 0x01 },
+ { 0x3A3E, 0x00 },
+ { 0x3A3F, 0x01 },
+ { 0x3A40, 0x00 },
+ { 0x3A41, 0x01 },
+ { 0x3A42, 0x00 },
+ { 0x3A43, 0x01 },
+ { 0x3A44, 0x70 },
+ { 0x3A45, 0x00 },
+ { 0x3A46, 0x25 },
+ { 0x3A47, 0x00 },
+ { 0x3A48, 0x18 },
+ { 0x3A49, 0x00 },
+ { 0x3A4A, 0x10 },
+ { 0x3A4B, 0x00 },
+ { 0x3A4C, 0xE6 },
+ { 0x3A4D, 0x00 },
+ { 0x3A4E, 0xD5 },
+ { 0x3A4F, 0x00 },
+ { 0x3A50, 0xAA },
+ { 0x3A51, 0x00 },
+ { 0x3A52, 0x85 },
+ { 0x3A53, 0x00 },
+ { 0x3A54, 0xE6 },
+ { 0x3A55, 0x00 },
+ { 0x3A56, 0xD5 },
+ { 0x3A57, 0x00 },
+ { 0x3A58, 0xAA },
+ { 0x3A59, 0x00 },
+ { 0x3A5A, 0x85 },
+ { 0x3A5B, 0x00 },
+ { 0x3A5C, 0xE6 },
+ { 0x3A5D, 0x00 },
+ { 0x3A5E, 0xD5 },
+ { 0x3A5F, 0x00 },
+ { 0x3A60, 0xAA },
+ { 0x3A61, 0x00 },
+ { 0x3A62, 0x85 },
+ { 0x3A63, 0x00 },
+ { 0x3A64, 0x19 },
+ { 0x3A65, 0x00 },
+ { 0x3A66, 0x12 },
+ { 0x3A67, 0x00 },
+ { 0x3A68, 0x0D },
+ { 0x3A69, 0x00 },
+ { 0x3A6A, 0x07 },
+ { 0x3A6B, 0x00 },
+ { 0x3A6C, 0x0C },
+ { 0x3A6D, 0x00 },
+ { 0x3A6E, 0x07 },
+ { 0x3A6F, 0x00 },
+ { 0x3A70, 0x05 },
+ { 0x3A71, 0x00 },
+ { 0x3A72, 0x04 },
+ { 0x3A73, 0x00 },
+ { 0x3A74, 0x1B },
+ { 0x3A75, 0x00 },
+ { 0x3A76, 0x15 },
+ { 0x3A77, 0x00 },
+ { 0x3A78, 0x0C },
+ { 0x3A79, 0x00 },
+ { 0x3A7A, 0x08 },
+ { 0x3A7B, 0x00 },
+ { 0x3A7C, 0x80 },
+ { 0x3A7D, 0x00 },
+ { 0x3A7E, 0x80 },
+ { 0x3A7F, 0x00 },
+ { 0x3A80, 0x80 },
+ { 0x3A81, 0x00 },
+ { 0x3A82, 0x80 },
+ { 0x3A83, 0x00 },
+ { 0x3A84, 0x09 },
+ { 0x3A85, 0x00 },
+ { 0x3A86, 0x06 },
+ { 0x3A87, 0x00 },
+ { 0x3A88, 0x04 },
+ { 0x3A89, 0x00 },
+ { 0x3A8A, 0x03 },
+ { 0x3A8B, 0x00 },
+ { 0x3A8C, 0xFA },
+ { 0x3A8D, 0x00 },
+ { 0x3A8E, 0xC8 },
+ { 0x3A8F, 0x00 },
+ { 0x3A90, 0x96 },
+ { 0x3A91, 0x00 },
+ { 0x3A92, 0x64 },
+ { 0x3A93, 0x00 },
+ { 0x3A94, 0xE1 },
+ { 0x3A95, 0x00 },
+ { 0x3A96, 0xC8 },
+ { 0x3A97, 0x00 },
+ { 0x3A98, 0x96 },
+ { 0x3A99, 0x00 },
+ { 0x3A9A, 0x64 },
+ { 0x3A9B, 0x00 },
+ { 0x3A9C, 0x08 },
+ { 0x3A9D, 0x10 },
+ { 0x3A9E, 0x4C },
+ { 0x3A9F, 0x4C },
+ { 0x3AA0, 0x4C },
+ { 0x3AA1, 0x04 },
+ { 0x3AA2, 0x04 },
+ { 0x3AC0, 0x01 },
+ { 0x3AC4, 0x81 },
+ { 0x3AC5, 0x00 },
+ { 0x3AC6, 0x00 },
+ { 0x3AC7, 0x00 },
+ { 0x3AC8, 0x00 },
+ { 0x3AC9, 0x00 },
+ { 0x3ACA, 0x00 },
+ { 0x3ACB, 0x00 },
+ { 0x3ACC, 0x02 },
+ { 0x3ACD, 0x00 },
+ { 0x3ACE, 0x81 },
+ { 0x3ACF, 0x00 },
+ { 0x3AD0, 0x00 },
+ { 0x3AD1, 0x00 },
+ { 0x3AD2, 0xFD },
+ { 0x3AD3, 0x03 },
+ { 0x3AD4, 0x02 },
+ { 0x3AD5, 0x00 },
+ { 0x3AD6, 0x00 },
+ { 0x3AD7, 0x00 },
+ { 0x3AD8, 0x81 },
+ { 0x3AD9, 0x00 },
+ { 0x3ADA, 0xFD },
+ { 0x3ADB, 0x03 },
+ { 0x3ADC, 0xFF },
+ { 0x3ADD, 0x03 },
+ { 0x3ADE, 0x01 },
+ { 0x3ADF, 0x00 },
+ { 0x3AE0, 0x01 },
+ { 0x3AE1, 0x00 },
+ { 0x3AE2, 0x7E },
+ { 0x3AE3, 0x00 },
+ { 0x3AF4, 0x00 },
+ { 0x3AF6, 0x40 },
+ { 0x3AF7, 0x1E },
+ { 0x3AF8, 0x00 },
+ { 0x3AFA, 0x00 },
+ { 0x3AFB, 0x00 },
+ { 0x3AFC, 0x00 },
+ { 0x3AFD, 0x00 },
+ { 0x3AFE, 0x00 },
+ { 0x3AFF, 0x00 },
+ { 0x3B00, 0x00 },
+ { 0x3B01, 0x00 },
+ { 0x3B02, 0x00 },
+ { 0x3B03, 0x00 },
+ { 0x3B04, 0x00 },
+ { 0x3B05, 0x00 },
+ { 0x3B06, 0x00 },
+ { 0x3B07, 0x00 },
+ { 0x3B08, 0x00 },
+ { 0x3B09, 0x00 },
+ { 0x3B0A, 0x00 },
+ { 0x3B0B, 0x00 },
+ { 0x3B0C, 0x00 },
+ { 0x3B0D, 0x00 },
+ { 0x3B0E, 0x00 },
+ { 0x3B0F, 0x00 },
+ { 0x3B10, 0x00 },
+ { 0x3B11, 0x00 },
+ { 0x3B12, 0x00 },
+ { 0x3B13, 0x00 },
+ { 0x3B14, 0x00 },
+ { 0x3B15, 0x00 },
+ { 0x3B16, 0x00 },
+ { 0x3B17, 0x00 },
+ { 0x3B18, 0x00 },
+ { 0x3B19, 0x00 },
+ { 0x3B1A, 0x00 },
+ { 0x3B1B, 0x00 },
+ { 0x3B1C, 0x00 },
+ { 0x3B1D, 0x00 },
+ { 0x3B1E, 0x00 },
+ { 0x3B1F, 0x00 },
+ { 0x3B20, 0x00 },
+ { 0x3B21, 0x00 },
+ { 0x3B22, 0x00 },
+ { 0x3B23, 0x00 },
+ { 0x3B24, 0x00 },
+ { 0x3B25, 0x00 },
+ { 0x3B26, 0x00 },
+ { 0x3B27, 0x00 },
+ { 0x3B28, 0x00 },
+ { 0x3B29, 0x00 },
+ { 0x3B2A, 0x00 },
+ { 0x3B2C, 0x00 },
+ { 0x3B2E, 0x00 },
+ { 0x3B30, 0x00 },
+ { 0x3B32, 0x0C },
+ { 0x4000, 0xAF },
+ { 0x4001, 0xA7 },
+ { 0x4002, 0xA8 },
+ { 0x4003, 0xA5 },
+ { 0x4004, 0x98 },
+ { 0x4005, 0x93 },
+ { 0x4006, 0x94 },
+ { 0x4007, 0x93 },
+ { 0x4008, 0x8E },
+ { 0x4009, 0x8C },
+ { 0x400A, 0x8C },
+ { 0x400B, 0x8C },
+ { 0x400C, 0x89 },
+ { 0x400D, 0x88 },
+ { 0x400E, 0x89 },
+ { 0x400F, 0x89 },
+ { 0x4010, 0x87 },
+ { 0x4011, 0x87 },
+ { 0x4012, 0x87 },
+ { 0x4013, 0x86 },
+ { 0x4014, 0x88 },
+ { 0x4015, 0x87 },
+ { 0x4016, 0x87 },
+ { 0x4017, 0x87 },
+ { 0x4018, 0x8B },
+ { 0x4019, 0x89 },
+ { 0x401A, 0x89 },
+ { 0x401B, 0x8A },
+ { 0x401C, 0x92 },
+ { 0x401D, 0x8F },
+ { 0x401E, 0x8F },
+ { 0x401F, 0x8F },
+ { 0x4020, 0xA2 },
+ { 0x4021, 0x9C },
+ { 0x4022, 0x9B },
+ { 0x4023, 0x9C },
+ { 0x4024, 0xA1 },
+ { 0x4025, 0x9A },
+ { 0x4026, 0x9B },
+ { 0x4027, 0x99 },
+ { 0x4028, 0x94 },
+ { 0x4029, 0x90 },
+ { 0x402A, 0x90 },
+ { 0x402B, 0x90 },
+ { 0x402C, 0x8B },
+ { 0x402D, 0x89 },
+ { 0x402E, 0x89 },
+ { 0x402F, 0x89 },
+ { 0x4030, 0x86 },
+ { 0x4031, 0x85 },
+ { 0x4032, 0x86 },
+ { 0x4033, 0x85 },
+ { 0x4034, 0x84 },
+ { 0x4035, 0x84 },
+ { 0x4036, 0x84 },
+ { 0x4037, 0x84 },
+ { 0x4038, 0x85 },
+ { 0x4039, 0x85 },
+ { 0x403A, 0x85 },
+ { 0x403B, 0x85 },
+ { 0x403C, 0x88 },
+ { 0x403D, 0x87 },
+ { 0x403E, 0x87 },
+ { 0x403F, 0x87 },
+ { 0x4040, 0x8E },
+ { 0x4041, 0x8C },
+ { 0x4042, 0x8C },
+ { 0x4043, 0x8C },
+ { 0x4044, 0x98 },
+ { 0x4045, 0x93 },
+ { 0x4046, 0x93 },
+ { 0x4047, 0x94 },
+ { 0x4048, 0x9D },
+ { 0x4049, 0x96 },
+ { 0x404A, 0x97 },
+ { 0x404B, 0x96 },
+ { 0x404C, 0x91 },
+ { 0x404D, 0x8C },
+ { 0x404E, 0x8D },
+ { 0x404F, 0x8C },
+ { 0x4050, 0x89 },
+ { 0x4051, 0x86 },
+ { 0x4052, 0x87 },
+ { 0x4053, 0x86 },
+ { 0x4054, 0x83 },
+ { 0x4055, 0x82 },
+ { 0x4056, 0x82 },
+ { 0x4057, 0x82 },
+ { 0x4058, 0x80 },
+ { 0x4059, 0x80 },
+ { 0x405A, 0x80 },
+ { 0x405B, 0x80 },
+ { 0x405C, 0x82 },
+ { 0x405D, 0x82 },
+ { 0x405E, 0x82 },
+ { 0x405F, 0x82 },
+ { 0x4060, 0x86 },
+ { 0x4061, 0x85 },
+ { 0x4062, 0x85 },
+ { 0x4063, 0x85 },
+ { 0x4064, 0x8B },
+ { 0x4065, 0x8A },
+ { 0x4066, 0x89 },
+ { 0x4067, 0x89 },
+ { 0x4068, 0x94 },
+ { 0x4069, 0x91 },
+ { 0x406A, 0x90 },
+ { 0x406B, 0x91 },
+ { 0x406C, 0x9E },
+ { 0x406D, 0x95 },
+ { 0x406E, 0x96 },
+ { 0x406F, 0x95 },
+ { 0x4070, 0x91 },
+ { 0x4071, 0x8C },
+ { 0x4072, 0x8C },
+ { 0x4073, 0x8C },
+ { 0x4074, 0x89 },
+ { 0x4075, 0x86 },
+ { 0x4076, 0x86 },
+ { 0x4077, 0x86 },
+ { 0x4078, 0x83 },
+ { 0x4079, 0x82 },
+ { 0x407A, 0x82 },
+ { 0x407B, 0x82 },
+ { 0x407C, 0x80 },
+ { 0x407D, 0x80 },
+ { 0x407E, 0x80 },
+ { 0x407F, 0x80 },
+ { 0x4080, 0x82 },
+ { 0x4081, 0x81 },
+ { 0x4082, 0x81 },
+ { 0x4083, 0x81 },
+ { 0x4084, 0x85 },
+ { 0x4085, 0x85 },
+ { 0x4086, 0x85 },
+ { 0x4087, 0x84 },
+ { 0x4088, 0x8B },
+ { 0x4089, 0x8A },
+ { 0x408A, 0x89 },
+ { 0x408B, 0x89 },
+ { 0x408C, 0x93 },
+ { 0x408D, 0x90 },
+ { 0x408E, 0x8F },
+ { 0x408F, 0x8F },
+ { 0x4090, 0xA3 },
+ { 0x4091, 0x99 },
+ { 0x4092, 0x9A },
+ { 0x4093, 0x99 },
+ { 0x4094, 0x95 },
+ { 0x4095, 0x8F },
+ { 0x4096, 0x8F },
+ { 0x4097, 0x8F },
+ { 0x4098, 0x8B },
+ { 0x4099, 0x87 },
+ { 0x409A, 0x87 },
+ { 0x409B, 0x87 },
+ { 0x409C, 0x86 },
+ { 0x409D, 0x84 },
+ { 0x409E, 0x84 },
+ { 0x409F, 0x84 },
+ { 0x40A0, 0x84 },
+ { 0x40A1, 0x83 },
+ { 0x40A2, 0x83 },
+ { 0x40A3, 0x82 },
+ { 0x40A4, 0x84 },
+ { 0x40A5, 0x84 },
+ { 0x40A6, 0x83 },
+ { 0x40A7, 0x83 },
+ { 0x40A8, 0x88 },
+ { 0x40A9, 0x87 },
+ { 0x40AA, 0x86 },
+ { 0x40AB, 0x86 },
+ { 0x40AC, 0x8E },
+ { 0x40AD, 0x8C },
+ { 0x40AE, 0x8C },
+ { 0x40AF, 0x8B },
+ { 0x40B0, 0x9A },
+ { 0x40B1, 0x96 },
+ { 0x40B2, 0x96 },
+ { 0x40B3, 0x95 },
+ { 0x40B4, 0xBA },
+ { 0x40B5, 0xAC },
+ { 0x40B6, 0xAD },
+ { 0x40B7, 0xAC },
+ { 0x40B8, 0x99 },
+ { 0x40B9, 0x90 },
+ { 0x40BA, 0x91 },
+ { 0x40BB, 0x90 },
+ { 0x40BC, 0x90 },
+ { 0x40BD, 0x8A },
+ { 0x40BE, 0x8A },
+ { 0x40BF, 0x8A },
+ { 0x40C0, 0x89 },
+ { 0x40C1, 0x86 },
+ { 0x40C2, 0x86 },
+ { 0x40C3, 0x87 },
+ { 0x40C4, 0x87 },
+ { 0x40C5, 0x85 },
+ { 0x40C6, 0x85 },
+ { 0x40C7, 0x85 },
+ { 0x40C8, 0x87 },
+ { 0x40C9, 0x86 },
+ { 0x40CA, 0x85 },
+ { 0x40CB, 0x85 },
+ { 0x40CC, 0x8A },
+ { 0x40CD, 0x88 },
+ { 0x40CE, 0x88 },
+ { 0x40CF, 0x87 },
+ { 0x40D0, 0x92 },
+ { 0x40D1, 0x8F },
+ { 0x40D2, 0x8E },
+ { 0x40D3, 0x8E },
+ { 0x40D4, 0xA2 },
+ { 0x40D5, 0x9D },
+ { 0x40D6, 0x9D },
+ { 0x40D7, 0x9B },
+ { 0x4100, 0x80 },
+ { 0x4101, 0x80 },
+ { 0x4102, 0x80 },
+ { 0x4103, 0x80 },
+ { 0x4104, 0x80 },
+ { 0x4105, 0x80 },
+ { 0x4106, 0x80 },
+ { 0x4107, 0x80 },
+ { 0x4108, 0x80 },
+ { 0x4109, 0x80 },
+ { 0x410A, 0x80 },
+ { 0x410B, 0x80 },
+ { 0x410C, 0x80 },
+ { 0x410D, 0x80 },
+ { 0x410E, 0x80 },
+ { 0x410F, 0x80 },
+ { 0x4110, 0x80 },
+ { 0x4111, 0x80 },
+ { 0x4112, 0x80 },
+ { 0x4113, 0x80 },
+ { 0x4114, 0x80 },
+ { 0x4115, 0x80 },
+ { 0x4116, 0x80 },
+ { 0x4117, 0x80 },
+ { 0x4118, 0x80 },
+ { 0x4119, 0x80 },
+ { 0x411A, 0x80 },
+ { 0x411B, 0x80 },
+ { 0x411C, 0x80 },
+ { 0x411D, 0x80 },
+ { 0x411E, 0x80 },
+ { 0x411F, 0x80 },
+ { 0x4120, 0x80 },
+ { 0x4121, 0x80 },
+ { 0x4122, 0x80 },
+ { 0x4123, 0x80 },
+ { 0x4124, 0x80 },
+ { 0x4125, 0x80 },
+ { 0x4126, 0x80 },
+ { 0x4127, 0x80 },
+ { 0x4128, 0x80 },
+ { 0x4129, 0x80 },
+ { 0x412A, 0x80 },
+ { 0x412B, 0x80 },
+ { 0x412C, 0x80 },
+ { 0x412D, 0x80 },
+ { 0x412E, 0x80 },
+ { 0x412F, 0x80 },
+ { 0x4130, 0x80 },
+ { 0x4131, 0x80 },
+ { 0x4132, 0x80 },
+ { 0x4133, 0x80 },
+ { 0x4134, 0x80 },
+ { 0x4135, 0x80 },
+ { 0x4136, 0x80 },
+ { 0x4137, 0x80 },
+ { 0x4138, 0x80 },
+ { 0x4139, 0x80 },
+ { 0x413A, 0x80 },
+ { 0x413B, 0x80 },
+ { 0x413C, 0x80 },
+ { 0x413D, 0x80 },
+ { 0x413E, 0x80 },
+ { 0x413F, 0x80 },
+ { 0x4140, 0x80 },
+ { 0x4141, 0x80 },
+ { 0x4142, 0x80 },
+ { 0x4143, 0x80 },
+ { 0x4144, 0x80 },
+ { 0x4145, 0x80 },
+ { 0x4146, 0x80 },
+ { 0x4147, 0x80 },
+ { 0x4148, 0x80 },
+ { 0x4149, 0x80 },
+ { 0x414A, 0x80 },
+ { 0x414B, 0x80 },
+ { 0x414C, 0x80 },
+ { 0x414D, 0x80 },
+ { 0x414E, 0x80 },
+ { 0x414F, 0x80 },
+ { 0x4150, 0x80 },
+ { 0x4151, 0x80 },
+ { 0x4152, 0x80 },
+ { 0x4153, 0x80 },
+ { 0x4154, 0x80 },
+ { 0x4155, 0x80 },
+ { 0x4156, 0x80 },
+ { 0x4157, 0x80 },
+ { 0x4158, 0x80 },
+ { 0x4159, 0x80 },
+ { 0x415A, 0x80 },
+ { 0x415B, 0x80 },
+ { 0x415C, 0x80 },
+ { 0x415D, 0x80 },
+ { 0x415E, 0x80 },
+ { 0x415F, 0x80 },
+ { 0x4160, 0x80 },
+ { 0x4161, 0x80 },
+ { 0x4162, 0x80 },
+ { 0x4163, 0x80 },
+ { 0x4164, 0x80 },
+ { 0x4165, 0x80 },
+ { 0x4166, 0x80 },
+ { 0x4167, 0x80 },
+ { 0x4168, 0x80 },
+ { 0x4169, 0x80 },
+ { 0x416A, 0x80 },
+ { 0x416B, 0x80 },
+ { 0x416C, 0x80 },
+ { 0x416D, 0x80 },
+ { 0x416E, 0x80 },
+ { 0x416F, 0x80 },
+ { 0x4170, 0x80 },
+ { 0x4171, 0x80 },
+ { 0x4172, 0x80 },
+ { 0x4173, 0x80 },
+ { 0x4174, 0x80 },
+ { 0x4175, 0x80 },
+ { 0x4176, 0x80 },
+ { 0x4177, 0x80 },
+ { 0x4178, 0x80 },
+ { 0x4179, 0x80 },
+ { 0x417A, 0x80 },
+ { 0x417B, 0x80 },
+ { 0x417C, 0x80 },
+ { 0x417D, 0x80 },
+ { 0x417E, 0x80 },
+ { 0x417F, 0x80 },
+ { 0x4180, 0x80 },
+ { 0x4181, 0x80 },
+ { 0x4182, 0x80 },
+ { 0x4183, 0x80 },
+ { 0x4184, 0x80 },
+ { 0x4185, 0x80 },
+ { 0x4186, 0x80 },
+ { 0x4187, 0x80 },
+ { 0x4188, 0x80 },
+ { 0x4189, 0x80 },
+ { 0x418A, 0x80 },
+ { 0x418B, 0x80 },
+ { 0x418C, 0x80 },
+ { 0x418D, 0x80 },
+ { 0x418E, 0x80 },
+ { 0x418F, 0x80 },
+ { 0x4190, 0x80 },
+ { 0x4191, 0x80 },
+ { 0x4192, 0x80 },
+ { 0x4193, 0x80 },
+ { 0x4194, 0x80 },
+ { 0x4195, 0x80 },
+ { 0x4196, 0x80 },
+ { 0x4197, 0x80 },
+ { 0x4198, 0x80 },
+ { 0x4199, 0x80 },
+ { 0x419A, 0x80 },
+ { 0x419B, 0x80 },
+ { 0x419C, 0x80 },
+ { 0x419D, 0x80 },
+ { 0x419E, 0x80 },
+ { 0x419F, 0x80 },
+ { 0x41A0, 0x80 },
+ { 0x41A1, 0x80 },
+ { 0x41A2, 0x80 },
+ { 0x41A3, 0x80 },
+ { 0x41A4, 0x80 },
+ { 0x41A5, 0x80 },
+ { 0x41A6, 0x80 },
+ { 0x41A7, 0x80 },
+ { 0x41A8, 0x80 },
+ { 0x41A9, 0x80 },
+ { 0x41AA, 0x80 },
+ { 0x41AB, 0x80 },
+ { 0x41AC, 0x80 },
+ { 0x41AD, 0x80 },
+ { 0x41AE, 0x80 },
+ { 0x41AF, 0x80 },
+ { 0x41B0, 0x80 },
+ { 0x41B1, 0x80 },
+ { 0x41B2, 0x80 },
+ { 0x41B3, 0x80 },
+ { 0x41B4, 0x80 },
+ { 0x41B5, 0x80 },
+ { 0x41B6, 0x80 },
+ { 0x41B7, 0x80 },
+ { 0x41B8, 0x80 },
+ { 0x41B9, 0x80 },
+ { 0x41BA, 0x80 },
+ { 0x41BB, 0x80 },
+ { 0x41BC, 0x80 },
+ { 0x41BD, 0x80 },
+ { 0x41BE, 0x80 },
+ { 0x41BF, 0x80 },
+ { 0x41C0, 0x80 },
+ { 0x41C1, 0x80 },
+ { 0x41C2, 0x80 },
+ { 0x41C3, 0x80 },
+ { 0x41C4, 0x80 },
+ { 0x41C5, 0x80 },
+ { 0x41C6, 0x80 },
+ { 0x41C7, 0x80 },
+ { 0x41C8, 0x80 },
+ { 0x41C9, 0x80 },
+ { 0x41CA, 0x80 },
+ { 0x41CB, 0x80 },
+ { 0x41CC, 0x80 },
+ { 0x41CD, 0x80 },
+ { 0x41CE, 0x80 },
+ { 0x41CF, 0x80 },
+ { 0x41D0, 0x80 },
+ { 0x41D1, 0x80 },
+ { 0x41D2, 0x80 },
+ { 0x41D3, 0x80 },
+ { 0x41D4, 0x80 },
+ { 0x41D5, 0x80 },
+ { 0x41D6, 0x80 },
+ { 0x41D7, 0x80 },
+ { 0x4200, 0x80 },
+ { 0x4201, 0x80 },
+ { 0x4202, 0x80 },
+ { 0x4203, 0x80 },
+ { 0x4204, 0x80 },
+ { 0x4205, 0x80 },
+ { 0x4206, 0x80 },
+ { 0x4207, 0x80 },
+ { 0x4208, 0x80 },
+ { 0x4209, 0x80 },
+ { 0x420A, 0x80 },
+ { 0x420B, 0x80 },
+ { 0x420C, 0x80 },
+ { 0x420D, 0x80 },
+ { 0x420E, 0x80 },
+ { 0x420F, 0x80 },
+ { 0x4210, 0x80 },
+ { 0x4211, 0x80 },
+ { 0x4212, 0x80 },
+ { 0x4213, 0x80 },
+ { 0x4214, 0x80 },
+ { 0x4215, 0x80 },
+ { 0x4216, 0x80 },
+ { 0x4217, 0x80 },
+ { 0x4218, 0x80 },
+ { 0x4219, 0x80 },
+ { 0x421A, 0x80 },
+ { 0x421B, 0x80 },
+ { 0x421C, 0x80 },
+ { 0x421D, 0x80 },
+ { 0x421E, 0x80 },
+ { 0x421F, 0x80 },
+ { 0x4220, 0x80 },
+ { 0x4221, 0x80 },
+ { 0x4222, 0x80 },
+ { 0x4223, 0x80 },
+ { 0x4224, 0x80 },
+ { 0x4225, 0x80 },
+ { 0x4226, 0x80 },
+ { 0x4227, 0x80 },
+ { 0x4228, 0x80 },
+ { 0x4229, 0x80 },
+ { 0x422A, 0x80 },
+ { 0x422B, 0x80 },
+ { 0x422C, 0x80 },
+ { 0x422D, 0x80 },
+ { 0x422E, 0x80 },
+ { 0x422F, 0x80 },
+ { 0x4230, 0x80 },
+ { 0x4231, 0x80 },
+ { 0x4232, 0x80 },
+ { 0x4233, 0x80 },
+ { 0x4234, 0x80 },
+ { 0x4235, 0x80 },
+ { 0x4236, 0x80 },
+ { 0x4237, 0x80 },
+ { 0x4238, 0x80 },
+ { 0x4239, 0x80 },
+ { 0x423A, 0x80 },
+ { 0x423B, 0x80 },
+ { 0x423C, 0x80 },
+ { 0x423D, 0x80 },
+ { 0x423E, 0x80 },
+ { 0x423F, 0x80 },
+ { 0x4240, 0x80 },
+ { 0x4241, 0x80 },
+ { 0x4242, 0x80 },
+ { 0x4243, 0x80 },
+ { 0x4244, 0x80 },
+ { 0x4245, 0x80 },
+ { 0x4246, 0x80 },
+ { 0x4247, 0x80 },
+ { 0x4248, 0x80 },
+ { 0x4249, 0x80 },
+ { 0x424A, 0x80 },
+ { 0x424B, 0x80 },
+ { 0x424C, 0x80 },
+ { 0x424D, 0x80 },
+ { 0x424E, 0x80 },
+ { 0x424F, 0x80 },
+ { 0x4250, 0x80 },
+ { 0x4251, 0x80 },
+ { 0x4252, 0x80 },
+ { 0x4253, 0x80 },
+ { 0x4254, 0x80 },
+ { 0x4255, 0x80 },
+ { 0x4256, 0x80 },
+ { 0x4257, 0x80 },
+ { 0x4258, 0x80 },
+ { 0x4259, 0x80 },
+ { 0x425A, 0x80 },
+ { 0x425B, 0x80 },
+ { 0x425C, 0x80 },
+ { 0x425D, 0x80 },
+ { 0x425E, 0x80 },
+ { 0x425F, 0x80 },
+ { 0x4260, 0x80 },
+ { 0x4261, 0x80 },
+ { 0x4262, 0x80 },
+ { 0x4263, 0x80 },
+ { 0x4264, 0x80 },
+ { 0x4265, 0x80 },
+ { 0x4266, 0x80 },
+ { 0x4267, 0x80 },
+ { 0x4268, 0x80 },
+ { 0x4269, 0x80 },
+ { 0x426A, 0x80 },
+ { 0x426B, 0x80 },
+ { 0x426C, 0x80 },
+ { 0x426D, 0x80 },
+ { 0x426E, 0x80 },
+ { 0x426F, 0x80 },
+ { 0x4270, 0x80 },
+ { 0x4271, 0x80 },
+ { 0x4272, 0x80 },
+ { 0x4273, 0x80 },
+ { 0x4274, 0x80 },
+ { 0x4275, 0x80 },
+ { 0x4276, 0x80 },
+ { 0x4277, 0x80 },
+ { 0x4278, 0x80 },
+ { 0x4279, 0x80 },
+ { 0x427A, 0x80 },
+ { 0x427B, 0x80 },
+ { 0x427C, 0x80 },
+ { 0x427D, 0x80 },
+ { 0x427E, 0x80 },
+ { 0x427F, 0x80 },
+ { 0x4280, 0x80 },
+ { 0x4281, 0x80 },
+ { 0x4282, 0x80 },
+ { 0x4283, 0x80 },
+ { 0x4284, 0x80 },
+ { 0x4285, 0x80 },
+ { 0x4286, 0x80 },
+ { 0x4287, 0x80 },
+ { 0x4288, 0x80 },
+ { 0x4289, 0x80 },
+ { 0x428A, 0x80 },
+ { 0x428B, 0x80 },
+ { 0x428C, 0x80 },
+ { 0x428D, 0x80 },
+ { 0x428E, 0x80 },
+ { 0x428F, 0x80 },
+ { 0x4290, 0x80 },
+ { 0x4291, 0x80 },
+ { 0x4292, 0x80 },
+ { 0x4293, 0x80 },
+ { 0x4294, 0x80 },
+ { 0x4295, 0x80 },
+ { 0x4296, 0x80 },
+ { 0x4297, 0x80 },
+ { 0x4298, 0x80 },
+ { 0x4299, 0x80 },
+ { 0x429A, 0x80 },
+ { 0x429B, 0x80 },
+ { 0x429C, 0x80 },
+ { 0x429D, 0x80 },
+ { 0x429E, 0x80 },
+ { 0x429F, 0x80 },
+ { 0x42A0, 0x80 },
+ { 0x42A1, 0x80 },
+ { 0x42A2, 0x80 },
+ { 0x42A3, 0x80 },
+ { 0x42A4, 0x80 },
+ { 0x42A5, 0x80 },
+ { 0x42A6, 0x80 },
+ { 0x42A7, 0x80 },
+ { 0x42A8, 0x80 },
+ { 0x42A9, 0x80 },
+ { 0x42AA, 0x80 },
+ { 0x42AB, 0x80 },
+ { 0x42AC, 0x80 },
+ { 0x42AD, 0x80 },
+ { 0x42AE, 0x80 },
+ { 0x42AF, 0x80 },
+ { 0x42B0, 0x80 },
+ { 0x42B1, 0x80 },
+ { 0x42B2, 0x80 },
+ { 0x42B3, 0x80 },
+ { 0x42B4, 0x80 },
+ { 0x42B5, 0x80 },
+ { 0x42B6, 0x80 },
+ { 0x42B7, 0x80 },
+ { 0x42B8, 0x80 },
+ { 0x42B9, 0x80 },
+ { 0x42BA, 0x80 },
+ { 0x42BB, 0x80 },
+ { 0x42BC, 0x80 },
+ { 0x42BD, 0x80 },
+ { 0x42BE, 0x80 },
+ { 0x42BF, 0x80 },
+ { 0x42C0, 0x80 },
+ { 0x42C1, 0x80 },
+ { 0x42C2, 0x80 },
+ { 0x42C3, 0x80 },
+ { 0x42C4, 0x80 },
+ { 0x42C5, 0x80 },
+ { 0x42C6, 0x80 },
+ { 0x42C7, 0x80 },
+ { 0x42C8, 0x80 },
+ { 0x42C9, 0x80 },
+ { 0x42CA, 0x80 },
+ { 0x42CB, 0x80 },
+ { 0x42CC, 0x80 },
+ { 0x42CD, 0x80 },
+ { 0x42CE, 0x80 },
+ { 0x42CF, 0x80 },
+ { 0x42D0, 0x80 },
+ { 0x42D1, 0x80 },
+ { 0x42D2, 0x80 },
+ { 0x42D3, 0x80 },
+ { 0x42D4, 0x80 },
+ { 0x42D5, 0x80 },
+ { 0x42D6, 0x80 },
+ { 0x42D7, 0x80 },
+ { 0x42D8, 0x00 },
+ { 0x42D9, 0x00 },
+ { 0x4300, 0xA2 },
+ { 0x4301, 0xAA },
+ { 0x4302, 0xA7 },
+ { 0x4303, 0xAD },
+ { 0x4304, 0x8E },
+ { 0x4305, 0x92 },
+ { 0x4306, 0x90 },
+ { 0x4307, 0x93 },
+ { 0x4308, 0x86 },
+ { 0x4309, 0x89 },
+ { 0x430A, 0x87 },
+ { 0x430B, 0x88 },
+ { 0x430C, 0x82 },
+ { 0x430D, 0x84 },
+ { 0x430E, 0x83 },
+ { 0x430F, 0x84 },
+ { 0x4310, 0x80 },
+ { 0x4311, 0x82 },
+ { 0x4312, 0x82 },
+ { 0x4313, 0x82 },
+ { 0x4314, 0x83 },
+ { 0x4315, 0x85 },
+ { 0x4316, 0x84 },
+ { 0x4317, 0x85 },
+ { 0x4318, 0x8D },
+ { 0x4319, 0x8D },
+ { 0x431A, 0x8D },
+ { 0x431B, 0x8D },
+ { 0x431C, 0x99 },
+ { 0x431D, 0x9A },
+ { 0x431E, 0x9A },
+ { 0x431F, 0x9A },
+ { 0x4320, 0xAE },
+ { 0x4321, 0xB4 },
+ { 0x4322, 0xB4 },
+ { 0x4323, 0xB5 },
+ { 0x4324, 0x9A },
+ { 0x4325, 0x9D },
+ { 0x4326, 0x9B },
+ { 0x4327, 0x9E },
+ { 0x4328, 0x8C },
+ { 0x4329, 0x8F },
+ { 0x432A, 0x8D },
+ { 0x432B, 0x8F },
+ { 0x432C, 0x83 },
+ { 0x432D, 0x85 },
+ { 0x432E, 0x85 },
+ { 0x432F, 0x85 },
+ { 0x4330, 0x80 },
+ { 0x4331, 0x81 },
+ { 0x4332, 0x81 },
+ { 0x4333, 0x81 },
+ { 0x4334, 0x80 },
+ { 0x4335, 0x80 },
+ { 0x4336, 0x80 },
+ { 0x4337, 0x81 },
+ { 0x4338, 0x83 },
+ { 0x4339, 0x83 },
+ { 0x433A, 0x83 },
+ { 0x433B, 0x83 },
+ { 0x433C, 0x88 },
+ { 0x433D, 0x88 },
+ { 0x433E, 0x88 },
+ { 0x433F, 0x88 },
+ { 0x4340, 0x93 },
+ { 0x4341, 0x93 },
+ { 0x4342, 0x93 },
+ { 0x4343, 0x93 },
+ { 0x4344, 0xA2 },
+ { 0x4345, 0xA4 },
+ { 0x4346, 0xA4 },
+ { 0x4347, 0xA4 },
+ { 0x4348, 0x97 },
+ { 0x4349, 0x99 },
+ { 0x434A, 0x97 },
+ { 0x434B, 0x97 },
+ { 0x434C, 0x89 },
+ { 0x434D, 0x8C },
+ { 0x434E, 0x8B },
+ { 0x434F, 0x8A },
+ { 0x4350, 0x81 },
+ { 0x4351, 0x83 },
+ { 0x4352, 0x83 },
+ { 0x4353, 0x83 },
+ { 0x4354, 0x7F },
+ { 0x4355, 0x80 },
+ { 0x4356, 0x80 },
+ { 0x4357, 0x80 },
+ { 0x4358, 0x7F },
+ { 0x4359, 0x7F },
+ { 0x435A, 0x7F },
+ { 0x435B, 0x7F },
+ { 0x435C, 0x82 },
+ { 0x435D, 0x81 },
+ { 0x435E, 0x81 },
+ { 0x435F, 0x82 },
+ { 0x4360, 0x86 },
+ { 0x4361, 0x86 },
+ { 0x4362, 0x86 },
+ { 0x4363, 0x87 },
+ { 0x4364, 0x8F },
+ { 0x4365, 0x8F },
+ { 0x4366, 0x8F },
+ { 0x4367, 0x90 },
+ { 0x4368, 0x9E },
+ { 0x4369, 0x9E },
+ { 0x436A, 0x9E },
+ { 0x436B, 0x9F },
+ { 0x436C, 0x99 },
+ { 0x436D, 0x9B },
+ { 0x436E, 0x9A },
+ { 0x436F, 0x98 },
+ { 0x4370, 0x8B },
+ { 0x4371, 0x8D },
+ { 0x4372, 0x8D },
+ { 0x4373, 0x8B },
+ { 0x4374, 0x83 },
+ { 0x4375, 0x84 },
+ { 0x4376, 0x84 },
+ { 0x4377, 0x83 },
+ { 0x4378, 0x80 },
+ { 0x4379, 0x81 },
+ { 0x437A, 0x81 },
+ { 0x437B, 0x80 },
+ { 0x437C, 0x81 },
+ { 0x437D, 0x80 },
+ { 0x437E, 0x80 },
+ { 0x437F, 0x80 },
+ { 0x4380, 0x83 },
+ { 0x4381, 0x83 },
+ { 0x4382, 0x83 },
+ { 0x4383, 0x83 },
+ { 0x4384, 0x88 },
+ { 0x4385, 0x87 },
+ { 0x4386, 0x87 },
+ { 0x4387, 0x88 },
+ { 0x4388, 0x91 },
+ { 0x4389, 0x90 },
+ { 0x438A, 0x90 },
+ { 0x438B, 0x91 },
+ { 0x438C, 0x9E },
+ { 0x438D, 0x9E },
+ { 0x438E, 0x9E },
+ { 0x438F, 0xA0 },
+ { 0x4390, 0xA0 },
+ { 0x4391, 0xA2 },
+ { 0x4392, 0xA2 },
+ { 0x4393, 0xA0 },
+ { 0x4394, 0x92 },
+ { 0x4395, 0x94 },
+ { 0x4396, 0x94 },
+ { 0x4397, 0x91 },
+ { 0x4398, 0x89 },
+ { 0x4399, 0x8A },
+ { 0x439A, 0x89 },
+ { 0x439B, 0x88 },
+ { 0x439C, 0x85 },
+ { 0x439D, 0x85 },
+ { 0x439E, 0x85 },
+ { 0x439F, 0x84 },
+ { 0x43A0, 0x85 },
+ { 0x43A1, 0x84 },
+ { 0x43A2, 0x84 },
+ { 0x43A3, 0x84 },
+ { 0x43A4, 0x88 },
+ { 0x43A5, 0x86 },
+ { 0x43A6, 0x86 },
+ { 0x43A7, 0x87 },
+ { 0x43A8, 0x8E },
+ { 0x43A9, 0x8B },
+ { 0x43AA, 0x8B },
+ { 0x43AB, 0x8D },
+ { 0x43AC, 0x97 },
+ { 0x43AD, 0x96 },
+ { 0x43AE, 0x96 },
+ { 0x43AF, 0x98 },
+ { 0x43B0, 0xA5 },
+ { 0x43B1, 0xA5 },
+ { 0x43B2, 0xA5 },
+ { 0x43B3, 0xA9 },
+ { 0x43B4, 0xB7 },
+ { 0x43B5, 0xBB },
+ { 0x43B6, 0xBB },
+ { 0x43B7, 0xB8 },
+ { 0x43B8, 0x9C },
+ { 0x43B9, 0x9C },
+ { 0x43BA, 0x9C },
+ { 0x43BB, 0x9A },
+ { 0x43BC, 0x92 },
+ { 0x43BD, 0x92 },
+ { 0x43BE, 0x92 },
+ { 0x43BF, 0x8F },
+ { 0x43C0, 0x8B },
+ { 0x43C1, 0x8B },
+ { 0x43C2, 0x8B },
+ { 0x43C3, 0x89 },
+ { 0x43C4, 0x8A },
+ { 0x43C5, 0x89 },
+ { 0x43C6, 0x89 },
+ { 0x43C7, 0x88 },
+ { 0x43C8, 0x8D },
+ { 0x43C9, 0x8B },
+ { 0x43CA, 0x8B },
+ { 0x43CB, 0x8C },
+ { 0x43CC, 0x94 },
+ { 0x43CD, 0x91 },
+ { 0x43CE, 0x92 },
+ { 0x43CF, 0x93 },
+ { 0x43D0, 0x9E },
+ { 0x43D1, 0x9D },
+ { 0x43D2, 0x9D },
+ { 0x43D3, 0xA1 },
+ { 0x43D4, 0xB2 },
+ { 0x43D5, 0xB4 },
+ { 0x43D6, 0xB5 },
+ { 0x43D7, 0xBD },
+ { 0x4400, 0x80 },
+ { 0x4401, 0x80 },
+ { 0x4402, 0x80 },
+ { 0x4403, 0x80 },
+ { 0x4404, 0x80 },
+ { 0x4405, 0x80 },
+ { 0x4406, 0x80 },
+ { 0x4407, 0x80 },
+ { 0x4408, 0x80 },
+ { 0x4409, 0x80 },
+ { 0x440A, 0x80 },
+ { 0x440B, 0x80 },
+ { 0x440C, 0x80 },
+ { 0x440D, 0x80 },
+ { 0x440E, 0x80 },
+ { 0x440F, 0x80 },
+ { 0x4410, 0x80 },
+ { 0x4411, 0x80 },
+ { 0x4412, 0x80 },
+ { 0x4413, 0x80 },
+ { 0x4414, 0x80 },
+ { 0x4415, 0x80 },
+ { 0x4416, 0x80 },
+ { 0x4417, 0x80 },
+ { 0x4418, 0x80 },
+ { 0x4419, 0x80 },
+ { 0x441A, 0x80 },
+ { 0x441B, 0x80 },
+ { 0x441C, 0x80 },
+ { 0x441D, 0x80 },
+ { 0x441E, 0x80 },
+ { 0x441F, 0x80 },
+ { 0x4420, 0x80 },
+ { 0x4421, 0x80 },
+ { 0x4422, 0x80 },
+ { 0x4423, 0x80 },
+ { 0x4424, 0x80 },
+ { 0x4425, 0x80 },
+ { 0x4426, 0x80 },
+ { 0x4427, 0x80 },
+ { 0x4428, 0x80 },
+ { 0x4429, 0x80 },
+ { 0x442A, 0x80 },
+ { 0x442B, 0x80 },
+ { 0x442C, 0x80 },
+ { 0x442D, 0x80 },
+ { 0x442E, 0x80 },
+ { 0x442F, 0x80 },
+ { 0x4430, 0x80 },
+ { 0x4431, 0x80 },
+ { 0x4432, 0x80 },
+ { 0x4433, 0x80 },
+ { 0x4434, 0x80 },
+ { 0x4435, 0x80 },
+ { 0x4436, 0x80 },
+ { 0x4437, 0x80 },
+ { 0x4438, 0x80 },
+ { 0x4439, 0x80 },
+ { 0x443A, 0x80 },
+ { 0x443B, 0x80 },
+ { 0x443C, 0x80 },
+ { 0x443D, 0x80 },
+ { 0x443E, 0x80 },
+ { 0x443F, 0x80 },
+ { 0x4440, 0x80 },
+ { 0x4441, 0x80 },
+ { 0x4442, 0x80 },
+ { 0x4443, 0x80 },
+ { 0x4444, 0x80 },
+ { 0x4445, 0x80 },
+ { 0x4446, 0x80 },
+ { 0x4447, 0x80 },
+ { 0x4448, 0x80 },
+ { 0x4449, 0x80 },
+ { 0x444A, 0x80 },
+ { 0x444B, 0x80 },
+ { 0x444C, 0x80 },
+ { 0x444D, 0x80 },
+ { 0x444E, 0x80 },
+ { 0x444F, 0x80 },
+ { 0x4450, 0x80 },
+ { 0x4451, 0x80 },
+ { 0x4452, 0x80 },
+ { 0x4453, 0x80 },
+ { 0x4454, 0x80 },
+ { 0x4455, 0x80 },
+ { 0x4456, 0x80 },
+ { 0x4457, 0x80 },
+ { 0x4458, 0x80 },
+ { 0x4459, 0x80 },
+ { 0x445A, 0x80 },
+ { 0x445B, 0x80 },
+ { 0x445C, 0x80 },
+ { 0x445D, 0x80 },
+ { 0x445E, 0x80 },
+ { 0x445F, 0x80 },
+ { 0x4460, 0x80 },
+ { 0x4461, 0x80 },
+ { 0x4462, 0x80 },
+ { 0x4463, 0x80 },
+ { 0x4464, 0x80 },
+ { 0x4465, 0x80 },
+ { 0x4466, 0x80 },
+ { 0x4467, 0x80 },
+ { 0x4468, 0x80 },
+ { 0x4469, 0x80 },
+ { 0x446A, 0x80 },
+ { 0x446B, 0x80 },
+ { 0x446C, 0x80 },
+ { 0x446D, 0x80 },
+ { 0x446E, 0x80 },
+ { 0x446F, 0x80 },
+ { 0x4470, 0x80 },
+ { 0x4471, 0x80 },
+ { 0x4472, 0x80 },
+ { 0x4473, 0x80 },
+ { 0x4474, 0x80 },
+ { 0x4475, 0x80 },
+ { 0x4476, 0x80 },
+ { 0x4477, 0x80 },
+ { 0x4478, 0x80 },
+ { 0x4479, 0x80 },
+ { 0x447A, 0x80 },
+ { 0x447B, 0x80 },
+ { 0x447C, 0x80 },
+ { 0x447D, 0x80 },
+ { 0x447E, 0x80 },
+ { 0x447F, 0x80 },
+ { 0x4480, 0x80 },
+ { 0x4481, 0x80 },
+ { 0x4482, 0x80 },
+ { 0x4483, 0x80 },
+ { 0x4484, 0x80 },
+ { 0x4485, 0x80 },
+ { 0x4486, 0x80 },
+ { 0x4487, 0x80 },
+ { 0x4488, 0x80 },
+ { 0x4489, 0x80 },
+ { 0x448A, 0x80 },
+ { 0x448B, 0x80 },
+ { 0x448C, 0x80 },
+ { 0x448D, 0x80 },
+ { 0x448E, 0x80 },
+ { 0x448F, 0x80 },
+ { 0x4490, 0x80 },
+ { 0x4491, 0x80 },
+ { 0x4492, 0x80 },
+ { 0x4493, 0x80 },
+ { 0x4494, 0x80 },
+ { 0x4495, 0x80 },
+ { 0x4496, 0x80 },
+ { 0x4497, 0x80 },
+ { 0x4498, 0x80 },
+ { 0x4499, 0x80 },
+ { 0x449A, 0x80 },
+ { 0x449B, 0x80 },
+ { 0x449C, 0x80 },
+ { 0x449D, 0x80 },
+ { 0x449E, 0x80 },
+ { 0x449F, 0x80 },
+ { 0x44A0, 0x80 },
+ { 0x44A1, 0x80 },
+ { 0x44A2, 0x80 },
+ { 0x44A3, 0x80 },
+ { 0x44A4, 0x80 },
+ { 0x44A5, 0x80 },
+ { 0x44A6, 0x80 },
+ { 0x44A7, 0x80 },
+ { 0x44A8, 0x80 },
+ { 0x44A9, 0x80 },
+ { 0x44AA, 0x80 },
+ { 0x44AB, 0x80 },
+ { 0x44AC, 0x80 },
+ { 0x44AD, 0x80 },
+ { 0x44AE, 0x80 },
+ { 0x44AF, 0x80 },
+ { 0x44B0, 0x80 },
+ { 0x44B1, 0x80 },
+ { 0x44B2, 0x80 },
+ { 0x44B3, 0x80 },
+ { 0x44B4, 0x80 },
+ { 0x44B5, 0x80 },
+ { 0x44B6, 0x80 },
+ { 0x44B7, 0x80 },
+ { 0x44B8, 0x80 },
+ { 0x44B9, 0x80 },
+ { 0x44BA, 0x80 },
+ { 0x44BB, 0x80 },
+ { 0x44BC, 0x80 },
+ { 0x44BD, 0x80 },
+ { 0x44BE, 0x80 },
+ { 0x44BF, 0x80 },
+ { 0x44C0, 0x80 },
+ { 0x44C1, 0x80 },
+ { 0x44C2, 0x80 },
+ { 0x44C3, 0x80 },
+ { 0x44C4, 0x80 },
+ { 0x44C5, 0x80 },
+ { 0x44C6, 0x80 },
+ { 0x44C7, 0x80 },
+ { 0x44C8, 0x80 },
+ { 0x44C9, 0x80 },
+ { 0x44CA, 0x80 },
+ { 0x44CB, 0x80 },
+ { 0x44CC, 0x80 },
+ { 0x44CD, 0x80 },
+ { 0x44CE, 0x80 },
+ { 0x44CF, 0x80 },
+ { 0x44D0, 0x80 },
+ { 0x44D1, 0x80 },
+ { 0x44D2, 0x80 },
+ { 0x44D3, 0x80 },
+ { 0x44D4, 0x80 },
+ { 0x44D5, 0x80 },
+ { 0x44D6, 0x80 },
+ { 0x44D7, 0x80 },
+ { 0x4500, 0x80 },
+ { 0x4501, 0x80 },
+ { 0x4502, 0x80 },
+ { 0x4503, 0x80 },
+ { 0x4504, 0x80 },
+ { 0x4505, 0x80 },
+ { 0x4506, 0x80 },
+ { 0x4507, 0x80 },
+ { 0x4508, 0x80 },
+ { 0x4509, 0x80 },
+ { 0x450A, 0x80 },
+ { 0x450B, 0x80 },
+ { 0x450C, 0x80 },
+ { 0x450D, 0x80 },
+ { 0x450E, 0x80 },
+ { 0x450F, 0x80 },
+ { 0x4510, 0x80 },
+ { 0x4511, 0x80 },
+ { 0x4512, 0x80 },
+ { 0x4513, 0x80 },
+ { 0x4514, 0x80 },
+ { 0x4515, 0x80 },
+ { 0x4516, 0x80 },
+ { 0x4517, 0x80 },
+ { 0x4518, 0x80 },
+ { 0x4519, 0x80 },
+ { 0x451A, 0x80 },
+ { 0x451B, 0x80 },
+ { 0x451C, 0x80 },
+ { 0x451D, 0x80 },
+ { 0x451E, 0x80 },
+ { 0x451F, 0x80 },
+ { 0x4520, 0x80 },
+ { 0x4521, 0x80 },
+ { 0x4522, 0x80 },
+ { 0x4523, 0x80 },
+ { 0x4524, 0x80 },
+ { 0x4525, 0x80 },
+ { 0x4526, 0x80 },
+ { 0x4527, 0x80 },
+ { 0x4528, 0x80 },
+ { 0x4529, 0x80 },
+ { 0x452A, 0x80 },
+ { 0x452B, 0x80 },
+ { 0x452C, 0x80 },
+ { 0x452D, 0x80 },
+ { 0x452E, 0x80 },
+ { 0x452F, 0x80 },
+ { 0x4530, 0x80 },
+ { 0x4531, 0x80 },
+ { 0x4532, 0x80 },
+ { 0x4533, 0x80 },
+ { 0x4534, 0x80 },
+ { 0x4535, 0x80 },
+ { 0x4536, 0x80 },
+ { 0x4537, 0x80 },
+ { 0x4538, 0x80 },
+ { 0x4539, 0x80 },
+ { 0x453A, 0x80 },
+ { 0x453B, 0x80 },
+ { 0x453C, 0x80 },
+ { 0x453D, 0x80 },
+ { 0x453E, 0x80 },
+ { 0x453F, 0x80 },
+ { 0x4540, 0x80 },
+ { 0x4541, 0x80 },
+ { 0x4542, 0x80 },
+ { 0x4543, 0x80 },
+ { 0x4544, 0x80 },
+ { 0x4545, 0x80 },
+ { 0x4546, 0x80 },
+ { 0x4547, 0x80 },
+ { 0x4548, 0x80 },
+ { 0x4549, 0x80 },
+ { 0x454A, 0x80 },
+ { 0x454B, 0x80 },
+ { 0x454C, 0x80 },
+ { 0x454D, 0x80 },
+ { 0x454E, 0x80 },
+ { 0x454F, 0x80 },
+ { 0x4550, 0x80 },
+ { 0x4551, 0x80 },
+ { 0x4552, 0x80 },
+ { 0x4553, 0x80 },
+ { 0x4554, 0x80 },
+ { 0x4555, 0x80 },
+ { 0x4556, 0x80 },
+ { 0x4557, 0x80 },
+ { 0x4558, 0x80 },
+ { 0x4559, 0x80 },
+ { 0x455A, 0x80 },
+ { 0x455B, 0x80 },
+ { 0x455C, 0x80 },
+ { 0x455D, 0x80 },
+ { 0x455E, 0x80 },
+ { 0x455F, 0x80 },
+ { 0x4560, 0x80 },
+ { 0x4561, 0x80 },
+ { 0x4562, 0x80 },
+ { 0x4563, 0x80 },
+ { 0x4564, 0x80 },
+ { 0x4565, 0x80 },
+ { 0x4566, 0x80 },
+ { 0x4567, 0x80 },
+ { 0x4568, 0x80 },
+ { 0x4569, 0x80 },
+ { 0x456A, 0x80 },
+ { 0x456B, 0x80 },
+ { 0x456C, 0x80 },
+ { 0x456D, 0x80 },
+ { 0x456E, 0x80 },
+ { 0x456F, 0x80 },
+ { 0x4570, 0x80 },
+ { 0x4571, 0x80 },
+ { 0x4572, 0x80 },
+ { 0x4573, 0x80 },
+ { 0x4574, 0x80 },
+ { 0x4575, 0x80 },
+ { 0x4576, 0x80 },
+ { 0x4577, 0x80 },
+ { 0x4578, 0x80 },
+ { 0x4579, 0x80 },
+ { 0x457A, 0x80 },
+ { 0x457B, 0x80 },
+ { 0x457C, 0x80 },
+ { 0x457D, 0x80 },
+ { 0x457E, 0x80 },
+ { 0x457F, 0x80 },
+ { 0x4580, 0x80 },
+ { 0x4581, 0x80 },
+ { 0x4582, 0x80 },
+ { 0x4583, 0x80 },
+ { 0x4584, 0x80 },
+ { 0x4585, 0x80 },
+ { 0x4586, 0x80 },
+ { 0x4587, 0x80 },
+ { 0x4588, 0x80 },
+ { 0x4589, 0x80 },
+ { 0x458A, 0x80 },
+ { 0x458B, 0x80 },
+ { 0x458C, 0x80 },
+ { 0x458D, 0x80 },
+ { 0x458E, 0x80 },
+ { 0x458F, 0x80 },
+ { 0x4590, 0x80 },
+ { 0x4591, 0x80 },
+ { 0x4592, 0x80 },
+ { 0x4593, 0x80 },
+ { 0x4594, 0x80 },
+ { 0x4595, 0x80 },
+ { 0x4596, 0x80 },
+ { 0x4597, 0x80 },
+ { 0x4598, 0x80 },
+ { 0x4599, 0x80 },
+ { 0x459A, 0x80 },
+ { 0x459B, 0x80 },
+ { 0x459C, 0x80 },
+ { 0x459D, 0x80 },
+ { 0x459E, 0x80 },
+ { 0x459F, 0x80 },
+ { 0x45A0, 0x80 },
+ { 0x45A1, 0x80 },
+ { 0x45A2, 0x80 },
+ { 0x45A3, 0x80 },
+ { 0x45A4, 0x80 },
+ { 0x45A5, 0x80 },
+ { 0x45A6, 0x80 },
+ { 0x45A7, 0x80 },
+ { 0x45A8, 0x80 },
+ { 0x45A9, 0x80 },
+ { 0x45AA, 0x80 },
+ { 0x45AB, 0x80 },
+ { 0x45AC, 0x80 },
+ { 0x45AD, 0x80 },
+ { 0x45AE, 0x80 },
+ { 0x45AF, 0x80 },
+ { 0x45B0, 0x80 },
+ { 0x45B1, 0x80 },
+ { 0x45B2, 0x80 },
+ { 0x45B3, 0x80 },
+ { 0x45B4, 0x80 },
+ { 0x45B5, 0x80 },
+ { 0x45B6, 0x80 },
+ { 0x45B7, 0x80 },
+ { 0x45B8, 0x80 },
+ { 0x45B9, 0x80 },
+ { 0x45BA, 0x80 },
+ { 0x45BB, 0x80 },
+ { 0x45BC, 0x80 },
+ { 0x45BD, 0x80 },
+ { 0x45BE, 0x80 },
+ { 0x45BF, 0x80 },
+ { 0x45C0, 0x80 },
+ { 0x45C1, 0x80 },
+ { 0x45C2, 0x80 },
+ { 0x45C3, 0x80 },
+ { 0x45C4, 0x80 },
+ { 0x45C5, 0x80 },
+ { 0x45C6, 0x80 },
+ { 0x45C7, 0x80 },
+ { 0x45C8, 0x80 },
+ { 0x45C9, 0x80 },
+ { 0x45CA, 0x80 },
+ { 0x45CB, 0x80 },
+ { 0x45CC, 0x80 },
+ { 0x45CD, 0x80 },
+ { 0x45CE, 0x80 },
+ { 0x45CF, 0x80 },
+ { 0x45D0, 0x80 },
+ { 0x45D1, 0x80 },
+ { 0x45D2, 0x80 },
+ { 0x45D3, 0x80 },
+ { 0x45D4, 0x80 },
+ { 0x45D5, 0x80 },
+ { 0x45D6, 0x80 },
+ { 0x45D7, 0x80 },
+ { 0x7000, 0xAB },
+ { 0x7001, 0xBA },
+ { 0x7002, 0x40 },
+ { 0x7003, 0x02 },
+ { 0x7004, 0x00 },
+ { 0x7005, 0x00 },
+ { 0x7006, 0x00 },
+ { 0x7007, 0x00 },
+ { 0x7008, 0x00 },
+ { 0x7009, 0x00 },
+ { 0x700A, 0x00 },
+ { 0x700B, 0x00 },
+ { 0x700C, 0x00 },
+ { 0x700D, 0x00 },
+ { 0x700E, 0x00 },
+ { 0x700F, 0x00 },
+ { 0x7010, 0x55 },
+ { 0x7011, 0x88 },
+ { 0x7012, 0x40 },
+ { 0x7013, 0x01 },
+ { 0x7014, 0x72 },
+ { 0x7015, 0xF1 },
+ { 0x7016, 0x02 },
+ { 0x7017, 0xF8 },
+ { 0x7018, 0x00 },
+ { 0x7019, 0x00 },
+ { 0x701A, 0x00 },
+ { 0x701B, 0x00 },
+ { 0x701C, 0x00 },
+ { 0x701D, 0x00 },
+ { 0x701E, 0x00 },
+ { 0x701F, 0x00 },
+ { 0x7020, 0x00 },
+ { 0x7021, 0x00 },
+ { 0x7022, 0x00 },
+ { 0x7023, 0x00 },
+ { 0x7024, 0x00 },
+ { 0x7025, 0x00 },
+ { 0x7026, 0x00 },
+ { 0x7027, 0x00 },
+ { 0x7028, 0x00 },
+ { 0x7029, 0x00 },
+ { 0x702A, 0x00 },
+ { 0x702B, 0x00 },
+ { 0x702C, 0x00 },
+ { 0x702D, 0x00 },
+ { 0x702E, 0x00 },
+ { 0x702F, 0x00 },
+ { 0x7030, 0x00 },
+ { 0x7031, 0x00 },
+ { 0x7032, 0x00 },
+ { 0x7033, 0x00 },
+ { 0x7034, 0x00 },
+ { 0x7035, 0x00 },
+ { 0x7036, 0x00 },
+ { 0x7037, 0x00 },
+ { 0x7038, 0x00 },
+ { 0x7039, 0x00 },
+ { 0x703A, 0x00 },
+ { 0x703B, 0x00 },
+ { 0x703C, 0x00 },
+ { 0x703D, 0x00 },
+ { 0x703E, 0x00 },
+ { 0x703F, 0x00 },
+ { 0x7040, 0x00 },
+ { 0x7041, 0x00 },
+ { 0x7042, 0x00 },
+ { 0x7043, 0x00 },
+ { 0x7044, 0x00 },
+ { 0x7045, 0x00 },
+ { 0x7046, 0x00 },
+ { 0x7047, 0x00 },
+ { 0x7048, 0x00 },
+ { 0x7049, 0x00 },
+ { 0x704A, 0x00 },
+ { 0x704B, 0x00 },
+ { 0x704C, 0x00 },
+ { 0x704D, 0x00 },
+ { 0x704E, 0x00 },
+ { 0x704F, 0x00 },
+ { 0x7050, 0x00 },
+ { 0x7051, 0x00 },
+ { 0x7052, 0x00 },
+ { 0x7053, 0x00 },
+ { 0x7054, 0x00 },
+ { 0x7055, 0x00 },
+ { 0x7056, 0x00 },
+ { 0x7057, 0x00 },
+ { 0x7058, 0x00 },
+ { 0x7059, 0x00 },
+ { 0x705A, 0x00 },
+ { 0x705B, 0x00 },
+ { 0x705C, 0x00 },
+ { 0x705D, 0x00 },
+ { 0x705E, 0x00 },
+ { 0x705F, 0x00 },
+ { 0x7060, 0x00 },
+ { 0x7061, 0x00 },
+ { 0x7062, 0x00 },
+ { 0x7063, 0x00 },
+ { 0x7064, 0x00 },
+ { 0x7065, 0x00 },
+ { 0x7066, 0x00 },
+ { 0x7067, 0x00 },
+ { 0x7068, 0x00 },
+ { 0x7069, 0x00 },
+ { 0x706A, 0x00 },
+ { 0x706B, 0x00 },
+ { 0x706C, 0x00 },
+ { 0x706D, 0x00 },
+ { 0x706E, 0x00 },
+ { 0x706F, 0x00 },
+ { 0x7070, 0x00 },
+ { 0x7071, 0x00 },
+ { 0x7072, 0x00 },
+ { 0x7073, 0x00 },
+ { 0x7074, 0x00 },
+ { 0x7075, 0x00 },
+ { 0x7076, 0x00 },
+ { 0x7077, 0x00 },
+ { 0x7078, 0x00 },
+ { 0x7079, 0x00 },
+ { 0x707A, 0x00 },
+ { 0x707B, 0x00 },
+ { 0x707C, 0x00 },
+ { 0x707D, 0x00 },
+ { 0x707E, 0x00 },
+ { 0x707F, 0x00 },
+ { 0x7080, 0x00 },
+ { 0x7081, 0x00 },
+ { 0x7082, 0x00 },
+ { 0x7083, 0x00 },
+ { 0x7084, 0x00 },
+ { 0x7085, 0x00 },
+ { 0x7086, 0x00 },
+ { 0x7087, 0x00 },
+ { 0x7088, 0x00 },
+ { 0x7089, 0x00 },
+ { 0x708A, 0x00 },
+ { 0x708B, 0x00 },
+ { 0x708C, 0x00 },
+ { 0x708D, 0x00 },
+ { 0x708E, 0x00 },
+ { 0x708F, 0x00 },
+ { 0x7090, 0x00 },
+ { 0x7091, 0xF0 },
+ { 0x7092, 0x02 },
+ { 0x7093, 0xF8 },
+ { 0x7094, 0x8D },
+ { 0x7095, 0xF6 },
+ { 0x7096, 0xFA },
+ { 0x7097, 0xFF },
+ { 0x7098, 0xF0 },
+ { 0x7099, 0xB5 },
+ { 0x709A, 0x04 },
+ { 0x709B, 0x46 },
+ { 0x709C, 0x8F },
+ { 0x709D, 0xB0 },
+ { 0x709E, 0x5F },
+ { 0x709F, 0x48 },
+ { 0x70A0, 0x0C },
+ { 0x70A1, 0x90 },
+ { 0x70A2, 0x5F },
+ { 0x70A3, 0x48 },
+ { 0x70A4, 0x06 },
+ { 0x70A5, 0x90 },
+ { 0x70A6, 0x20 },
+ { 0x70A7, 0x46 },
+ { 0x70A8, 0x34 },
+ { 0x70A9, 0x30 },
+ { 0x70AA, 0x0B },
+ { 0x70AB, 0x90 },
+ { 0x70AC, 0x5B },
+ { 0x70AD, 0x48 },
+ { 0x70AE, 0x5A },
+ { 0x70AF, 0x49 },
+ { 0x70B0, 0x26 },
+ { 0x70B1, 0x46 },
+ { 0x70B2, 0x66 },
+ { 0x70B3, 0x30 },
+ { 0x70B4, 0x3A },
+ { 0x70B5, 0x31 },
+ { 0x70B6, 0x3C },
+ { 0x70B7, 0x36 },
+ { 0x70B8, 0x05 },
+ { 0x70B9, 0x90 },
+ { 0x70BA, 0x0A },
+ { 0x70BB, 0x30 },
+ { 0x70BC, 0x04 },
+ { 0x70BD, 0x90 },
+ { 0x70BE, 0x59 },
+ { 0x70BF, 0x48 },
+ { 0x70C0, 0x55 },
+ { 0x70C1, 0x4A },
+ { 0x70C2, 0x40 },
+ { 0x70C3, 0x6E },
+ { 0x70C4, 0xC0 },
+ { 0x70C5, 0x07 },
+ { 0x70C6, 0x7D },
+ { 0x70C7, 0xD1 },
+ { 0x70C8, 0x17 },
+ { 0x70C9, 0x88 },
+ { 0x70CA, 0x0A },
+ { 0x70CB, 0x5E },
+ { 0x70CC, 0x0D },
+ { 0x70CD, 0x92 },
+ { 0x70CE, 0x53 },
+ { 0x70CF, 0x49 },
+ { 0x70D0, 0x55 },
+ { 0x70D1, 0x48 },
+ { 0x70D2, 0x94 },
+ { 0x70D3, 0x31 },
+ { 0x70D4, 0x89 },
+ { 0x70D5, 0x6B },
+ { 0x70D6, 0x80 },
+ { 0x70D7, 0x68 },
+ { 0x70D8, 0x09 },
+ { 0x70D9, 0x02 },
+ { 0x70DA, 0x00 },
+ { 0x70DB, 0x03 },
+ { 0x70DC, 0x09 },
+ { 0x70DD, 0x0E },
+ { 0x70DE, 0x00 },
+ { 0x70DF, 0x0B },
+ { 0x70E0, 0x49 },
+ { 0x70E1, 0x1C },
+ { 0x70E2, 0x48 },
+ { 0x70E3, 0x43 },
+ { 0x70E4, 0x4D },
+ { 0x70E5, 0x49 },
+ { 0x70E6, 0x6C },
+ { 0x70E7, 0x39 },
+ { 0x70E8, 0x8A },
+ { 0x70E9, 0x6A },
+ { 0x70EA, 0x07 },
+ { 0x70EB, 0x92 },
+ { 0x70EC, 0xCA },
+ { 0x70ED, 0x6A },
+ { 0x70EE, 0x00 },
+ { 0x70EF, 0x21 },
+ { 0x70F0, 0xC9 },
+ { 0x70F1, 0x43 },
+ { 0x70F2, 0x03 },
+ { 0x70F3, 0x92 },
+ { 0x70F4, 0x00 },
+ { 0x70F5, 0x22 },
+ { 0x70F6, 0x00 },
+ { 0x70F7, 0x91 },
+ { 0x70F8, 0x01 },
+ { 0x70F9, 0x92 },
+ { 0x70FA, 0x39 },
+ { 0x70FB, 0x46 },
+ { 0x70FC, 0x8F },
+ { 0x70FD, 0xF6 },
+ { 0x70FE, 0xCE },
+ { 0x70FF, 0xFB },
+ { 0x7100, 0x01 },
+ { 0x7101, 0x22 },
+ { 0x7102, 0x00 },
+ { 0x7103, 0x23 },
+ { 0x7104, 0x8C },
+ { 0x7105, 0xF6 },
+ { 0x7106, 0x02 },
+ { 0x7107, 0xFA },
+ { 0x7108, 0x00 },
+ { 0x7109, 0x21 },
+ { 0x710A, 0x05 },
+ { 0x710B, 0x46 },
+ { 0x710C, 0x01 },
+ { 0x710D, 0x91 },
+ { 0x710E, 0x00 },
+ { 0x710F, 0x90 },
+ { 0x7110, 0x39 },
+ { 0x7111, 0x46 },
+ { 0x7112, 0x07 },
+ { 0x7113, 0x98 },
+ { 0x7114, 0x8F },
+ { 0x7115, 0xF6 },
+ { 0x7116, 0xC2 },
+ { 0x7117, 0xFB },
+ { 0x7118, 0x0D },
+ { 0x7119, 0x9A },
+ { 0x711A, 0xD3 },
+ { 0x711B, 0x17 },
+ { 0x711C, 0x80 },
+ { 0x711D, 0x18 },
+ { 0x711E, 0x59 },
+ { 0x711F, 0x41 },
+ { 0x7120, 0x01 },
+ { 0x7121, 0x22 },
+ { 0x7122, 0x00 },
+ { 0x7123, 0x23 },
+ { 0x7124, 0x8C },
+ { 0x7125, 0xF6 },
+ { 0x7126, 0xCD },
+ { 0x7127, 0xF9 },
+ { 0x7128, 0x07 },
+ { 0x7129, 0x90 },
+ { 0x712A, 0x00 },
+ { 0x712B, 0x20 },
+ { 0x712C, 0x01 },
+ { 0x712D, 0x90 },
+ { 0x712E, 0x00 },
+ { 0x712F, 0x95 },
+ { 0x7130, 0x39 },
+ { 0x7131, 0x46 },
+ { 0x7132, 0x03 },
+ { 0x7133, 0x98 },
+ { 0x7134, 0x8F },
+ { 0x7135, 0xF6 },
+ { 0x7136, 0xB2 },
+ { 0x7137, 0xFB },
+ { 0x7138, 0x01 },
+ { 0x7139, 0x22 },
+ { 0x713A, 0x00 },
+ { 0x713B, 0x23 },
+ { 0x713C, 0x8C },
+ { 0x713D, 0xF6 },
+ { 0x713E, 0xE6 },
+ { 0x713F, 0xF9 },
+ { 0x7140, 0x02 },
+ { 0x7141, 0x46 },
+ { 0x7142, 0x07 },
+ { 0x7143, 0x98 },
+ { 0x7144, 0x00 },
+ { 0x7145, 0x23 },
+ { 0x7146, 0x81 },
+ { 0x7147, 0x0B },
+ { 0x7148, 0x80 },
+ { 0x7149, 0x04 },
+ { 0x714A, 0x7A },
+ { 0x714B, 0xF6 },
+ { 0x714C, 0x54 },
+ { 0x714D, 0xF8 },
+ { 0x714E, 0x37 },
+ { 0x714F, 0x4A },
+ { 0x7150, 0x00 },
+ { 0x7151, 0x23 },
+ { 0x7152, 0x00 },
+ { 0x7153, 0x92 },
+ { 0x7154, 0x01 },
+ { 0x7155, 0x93 },
+ { 0x7156, 0x01 },
+ { 0x7157, 0x22 },
+ { 0x7158, 0x8C },
+ { 0x7159, 0xF6 },
+ { 0x715A, 0xD8 },
+ { 0x715B, 0xF9 },
+ { 0x715C, 0x05 },
+ { 0x715D, 0x46 },
+ { 0x715E, 0x60 },
+ { 0x715F, 0x68 },
+ { 0x7160, 0x00 },
+ { 0x7161, 0x23 },
+ { 0x7162, 0x01 },
+ { 0x7163, 0x0C },
+ { 0x7164, 0x00 },
+ { 0x7165, 0x04 },
+ { 0x7166, 0xE2 },
+ { 0x7167, 0x68 },
+ { 0x7168, 0x7A },
+ { 0x7169, 0xF6 },
+ { 0x716A, 0x45 },
+ { 0x716B, 0xF8 },
+ { 0x716C, 0x00 },
+ { 0x716D, 0x22 },
+ { 0x716E, 0xD2 },
+ { 0x716F, 0x43 },
+ { 0x7170, 0x00 },
+ { 0x7171, 0x23 },
+ { 0x7172, 0x00 },
+ { 0x7173, 0x92 },
+ { 0x7174, 0x01 },
+ { 0x7175, 0x93 },
+ { 0x7176, 0x1A },
+ { 0x7177, 0x46 },
+ { 0x7178, 0x8C },
+ { 0x7179, 0xF6 },
+ { 0x717A, 0xC8 },
+ { 0x717B, 0xF9 },
+ { 0x717C, 0x29 },
+ { 0x717D, 0x46 },
+ { 0x717E, 0x8F },
+ { 0x717F, 0xF6 },
+ { 0x7180, 0x8D },
+ { 0x7181, 0xFB },
+ { 0x7182, 0x8A },
+ { 0x7183, 0x03 },
+ { 0x7184, 0x80 },
+ { 0x7185, 0x0C },
+ { 0x7186, 0x10 },
+ { 0x7187, 0x43 },
+ { 0x7188, 0x00 },
+ { 0x7189, 0x22 },
+ { 0x718A, 0xD2 },
+ { 0x718B, 0x43 },
+ { 0x718C, 0x00 },
+ { 0x718D, 0x23 },
+ { 0x718E, 0x00 },
+ { 0x718F, 0x92 },
+ { 0x7190, 0x89 },
+ { 0x7191, 0x0C },
+ { 0x7192, 0x01 },
+ { 0x7193, 0x93 },
+ { 0x7194, 0x1A },
+ { 0x7195, 0x46 },
+ { 0x7196, 0x8C },
+ { 0x7197, 0xF6 },
+ { 0x7198, 0xB9 },
+ { 0x7199, 0xF9 },
+ { 0x719A, 0x00 },
+ { 0x719B, 0x24 },
+ { 0x719C, 0x03 },
+ { 0x719D, 0x90 },
+ { 0x719E, 0x0C },
+ { 0x719F, 0x98 },
+ { 0x71A0, 0x61 },
+ { 0x71A1, 0x00 },
+ { 0x71A2, 0x45 },
+ { 0x71A3, 0x5A },
+ { 0x71A4, 0x06 },
+ { 0x71A5, 0x98 },
+ { 0x71A6, 0x22 },
+ { 0x71A7, 0x4A },
+ { 0x71A8, 0x40 },
+ { 0x71A9, 0x5A },
+ { 0x71AA, 0x00 },
+ { 0x71AB, 0x21 },
+ { 0x71AC, 0x8C },
+ { 0x71AD, 0xF6 },
+ { 0x71AE, 0xBE },
+ { 0x71AF, 0xF9 },
+ { 0x71B0, 0x07 },
+ { 0x71B1, 0x46 },
+ { 0x71B2, 0x28 },
+ { 0x71B3, 0x46 },
+ { 0x71B4, 0x03 },
+ { 0x71B5, 0x99 },
+ { 0x71B6, 0x8F },
+ { 0x71B7, 0xF6 },
+ { 0x71B8, 0x71 },
+ { 0x71B9, 0xFB },
+ { 0x71BA, 0x3A },
+ { 0x71BB, 0x46 },
+ { 0x71BC, 0x00 },
+ { 0x71BD, 0x23 },
+ { 0x71BE, 0x79 },
+ { 0x71BF, 0xF6 },
+ { 0x71C0, 0xCA },
+ { 0x71C1, 0xFF },
+ { 0x71C2, 0x00 },
+ { 0x71C3, 0xE0 },
+ { 0x71C4, 0x0F },
+ { 0x71C5, 0xE0 },
+ { 0x71C6, 0x8A },
+ { 0x71C7, 0x02 },
+ { 0x71C8, 0x80 },
+ { 0x71C9, 0x0D },
+ { 0x71CA, 0x10 },
+ { 0x71CB, 0x43 },
+ { 0x71CC, 0x19 },
+ { 0x71CD, 0x4A },
+ { 0x71CE, 0x00 },
+ { 0x71CF, 0x23 },
+ { 0x71D0, 0x00 },
+ { 0x71D1, 0x92 },
+ { 0x71D2, 0x89 },
+ { 0x71D3, 0x0D },
+ { 0x71D4, 0x01 },
+ { 0x71D5, 0x93 },
+ { 0x71D6, 0x40 },
+ { 0x71D7, 0x22 },
+ { 0x71D8, 0x8C },
+ { 0x71D9, 0xF6 },
+ { 0x71DA, 0x98 },
+ { 0x71DB, 0xF9 },
+ { 0x71DC, 0xA1 },
+ { 0x71DD, 0x00 },
+ { 0x71DE, 0x64 },
+ { 0x71DF, 0x1C },
+ { 0x71E0, 0x70 },
+ { 0x71E1, 0x50 },
+ { 0x71E2, 0x04 },
+ { 0x71E3, 0x2C },
+ { 0x71E4, 0xDB },
+ { 0x71E5, 0xD3 },
+ { 0x71E6, 0x14 },
+ { 0x71E7, 0x4D },
+ { 0x71E8, 0x00 },
+ { 0x71E9, 0x24 },
+ { 0x71EA, 0x0B },
+ { 0x71EB, 0x98 },
+ { 0x71EC, 0x67 },
+ { 0x71ED, 0x00 },
+ { 0x71EE, 0xC0 },
+ { 0x71EF, 0x5B },
+ { 0x71F0, 0x2A },
+ { 0x71F1, 0x46 },
+ { 0x71F2, 0x40 },
+ { 0x71F3, 0x21 },
+ { 0x71F4, 0x8C },
+ { 0x71F5, 0xF6 },
+ { 0x71F6, 0x9A },
+ { 0x71F7, 0xF9 },
+ { 0x71F8, 0x05 },
+ { 0x71F9, 0x99 },
+ { 0x71FA, 0x0E },
+ { 0x71FB, 0x4A },
+ { 0x71FC, 0xC8 },
+ { 0x71FD, 0x53 },
+ { 0x71FE, 0xA7 },
+ { 0x71FF, 0x00 },
+ { 0x7200, 0xF0 },
+ { 0x7201, 0x59 },
+ { 0x7202, 0x40 },
+ { 0x7203, 0x21 },
+ { 0x7204, 0x8C },
+ { 0x7205, 0xF6 },
+ { 0x7206, 0x7B },
+ { 0x7207, 0xF9 },
+ { 0x7208, 0x04 },
+ { 0x7209, 0x99 },
+ { 0x720A, 0x64 },
+ { 0x720B, 0x1C },
+ { 0x720C, 0xC8 },
+ { 0x720D, 0x51 },
+ { 0x720E, 0x04 },
+ { 0x720F, 0x2C },
+ { 0x7210, 0xEB },
+ { 0x7211, 0xD3 },
+ { 0x7212, 0x0F },
+ { 0x7213, 0xB0 },
+ { 0x7214, 0xF0 },
+ { 0x7215, 0xBD },
+ { 0x7216, 0x00 },
+ { 0x7217, 0x00 },
+ { 0x7218, 0x76 },
+ { 0x7219, 0x69 },
+ { 0x721A, 0x18 },
+ { 0x721B, 0x00 },
+ { 0x721C, 0xEC },
+ { 0x721D, 0x58 },
+ { 0x721E, 0x18 },
+ { 0x721F, 0x00 },
+ { 0x7220, 0x38 },
+ { 0x7221, 0x36 },
+ { 0x7222, 0x18 },
+ { 0x7223, 0x00 },
+ { 0x7224, 0x00 },
+ { 0x7225, 0x35 },
+ { 0x7226, 0x18 },
+ { 0x7227, 0x00 },
+ { 0x7228, 0x00 },
+ { 0x7229, 0x20 },
+ { 0x722A, 0x18 },
+ { 0x722B, 0x00 },
+ { 0x722C, 0xFF },
+ { 0x722D, 0xFF },
+ { 0x722E, 0xFF },
+ { 0x722F, 0x3F },
+ { 0x7230, 0xFF },
+ { 0x7231, 0x07 },
+ { 0x7232, 0x00 },
+ { 0x7233, 0x00 },
+ { 0x7234, 0xFF },
+ { 0x7235, 0xFF },
+ { 0x7236, 0x07 },
+ { 0x7237, 0x00 },
+ { 0x7238, 0xFF },
+ { 0x7239, 0x1F },
+ { 0x723A, 0x00 },
+ { 0x723B, 0x00 },
+ { 0x723C, 0x01 },
+ { 0x723D, 0xF6 },
+ { 0x723E, 0x45 },
+ { 0x723F, 0x12 },
+};
+
+static const struct reg_sequence imx390_linear_1936x1096[] = {
+ { 0x000C, 0xF2 },
+ { 0x000D, 0x02 },
+ { 0x000E, 0x00 },
+ { 0x0010, 0xF2 },
+ { 0x0011, 0x02 },
+ { 0x0012, 0x00 },
+ { 0x0018, 0x0F },
+ { 0x0019, 0x00 },
+ { 0x001A, 0x0C },
+ { 0x001B, 0x00 },
+ { 0x0038, 0x00 },
+ { 0x003C, 0x00 }, /* OBB_CLAMP_R_SP1H */
+ { 0x003D, 0x00 }, /* OBB_CLAMP_R_SP1H */
+ { 0x003E, 0x00 },
+ { 0x0040, 0x00 }, /* OBB_CLAMP_GR_SP1H */
+ { 0x0041, 0x00 }, /* OBB_CLAMP_GR_SP1H */
+ { 0x0042, 0x00 },
+ { 0x0044, 0x00 }, /* OBB_CLAMP_GB_SP1H */
+ { 0x0045, 0x00 }, /* OBB_CLAMP_GB_SP1H */
+ { 0x0046, 0x00 },
+ { 0x0048, 0x00 },
+ { 0x0049, 0x00 },
+ { 0x004A, 0x00 },
+ { 0x004C, 0x00 },
+ { 0x004D, 0x00 },
+ { 0x004E, 0x00 },
+ { 0x0050, 0x00 },
+ { 0x0051, 0x00 },
+ { 0x0052, 0x00 },
+ { 0x0054, 0x00 },
+ { 0x0055, 0x00 },
+ { 0x0056, 0x00 },
+ { 0x0058, 0x00 },
+ { 0x0059, 0x00 },
+ { 0x005A, 0x00 },
+ { 0x005C, 0x00 },
+ { 0x005D, 0x00 },
+ { 0x005E, 0x00 },
+ { 0x0060, 0x00 },
+ { 0x0061, 0x00 },
+ { 0x0062, 0x00 },
+ { 0x0064, 0x00 },
+ { 0x0065, 0x00 },
+ { 0x0066, 0x00 },
+ { 0x0068, 0x00 },
+ { 0x0069, 0x00 },
+ { 0x006A, 0x00 },
+ { 0x0074, 0x00 },
+ { 0x0078, 0x00 },
+ { 0x007C, 0x00 },
+ { 0x007D, 0x00 },
+ { 0x0080, 0x00 },
+ { 0x0081, 0x00 },
+ { 0x00F4, 0x1C },
+ { 0x00F5, 0xF8 },
+ { 0x00F6, 0x01 },
+ { 0x00F8, 0x03 },
+ { 0x00F9, 0x00 },
+ { 0x00FA, 0x00 },
+ { 0x00FB, 0x00 },
+ { 0x0114, 0x00 },
+ { 0x0115, 0x01 },
+ { 0x0118, 0x20 },
+ { 0x0119, 0x03 },
+ { 0x011A, 0x00 },
+ { 0x011B, 0x41 },
+ { 0x011C, 0x80 },
+ { 0x011D, 0x00 },
+ { 0x0120, 0x20 },
+ { 0x0121, 0x00 },
+ { 0x0122, 0x00 },
+ { 0x0123, 0x44 },
+ { 0x0124, 0x00 },
+ { 0x0125, 0x01 },
+ { 0x0128, 0xAC },
+ { 0x0129, 0x0D },
+ { 0x012A, 0x00 },
+ { 0x012B, 0xA4 },
+ { 0x012C, 0x00 },
+ { 0x012D, 0x01 },
+ { 0x0130, 0xC4 },
+ { 0x0131, 0x09 },
+ { 0x0132, 0x00 },
+ { 0x0133, 0xDA },
+ { 0x013B, 0x01 },
+ { 0x01C4, 0x00 },
+ { 0x01C5, 0x00 },
+ { 0x01CC, 0x01 },
+ { 0x01D0, 0x09 },
+ { 0x01D4, 0x01 },
+ { 0x0232, 0x18 },
+ { 0x0233, 0x00 },
+ { 0x0390, 0x00 },
+ { 0x0391, 0x00 },
+ { 0x0392, 0x00 },
+ { 0x03C0, 0x04 },
+ { 0x2000, 0x55 },
+ { 0x2001, 0x55 },
+ { 0x2002, 0x55 },
+ { 0x2003, 0x05 },
+ { 0x2004, 0x02 },
+ { 0x2008, 0x65 },
+ { 0x2009, 0x04 },
+ { 0x200A, 0x00 },
+ { 0x200C, 0x30 },
+ { 0x200D, 0x11 },
+ { 0x2010, 0x04 },
+ { 0x2014, 0x01 },
+ { 0x2018, 0x02 },
+ { 0x2019, 0x04 },
+ { 0x201A, 0x00 },
+ { 0x201C, 0x21 },
+ { 0x201D, 0x11 },
+ { 0x201E, 0x00 },
+ { 0x201F, 0x00 },
+ { 0x2020, 0xBC },
+ { 0x2021, 0x00 },
+ { 0x2022, 0x7F },
+ { 0x2023, 0x00 },
+ { 0x2024, 0xBA },
+ { 0x2025, 0x00 },
+ { 0x2026, 0x81 },
+ { 0x2027, 0x00 },
+ { 0x2028, 0x7D },
+ { 0x2029, 0x90 },
+ { 0x202A, 0x05 },
+ { 0x202C, 0xFC },
+ { 0x202D, 0x02 },
+ { 0x202E, 0x25 },
+ { 0x202F, 0x03 },
+ { 0x2030, 0x05 },
+ { 0x2031, 0x02 },
+ { 0x2032, 0xCA },
+ { 0x2033, 0x02 },
+ { 0x2034, 0xFC },
+ { 0x2035, 0x02 },
+ { 0x2036, 0x25 },
+ { 0x2037, 0x03 },
+ { 0x2038, 0x25 },
+ { 0x2039, 0x97 },
+ { 0x203A, 0xEC },
+ { 0x203B, 0x01 },
+ { 0x203C, 0xF5 },
+ { 0x203D, 0x8E },
+ { 0x203E, 0x0C },
+ { 0x203F, 0x2D },
+ { 0x2040, 0x69 },
+ { 0x2041, 0x01 },
+ { 0x2042, 0x8E },
+ { 0x2043, 0x01 },
+ { 0x2044, 0x0C },
+ { 0x2045, 0x02 },
+ { 0x2046, 0x31 },
+ { 0x2047, 0x02 },
+ { 0x2048, 0x6A },
+ { 0x2049, 0x01 },
+ { 0x204A, 0x8E },
+ { 0x204B, 0x01 },
+ { 0x204C, 0x0D },
+ { 0x204D, 0x02 },
+ { 0x204E, 0x31 },
+ { 0x204F, 0x02 },
+ { 0x2050, 0x7B },
+ { 0x2051, 0x00 },
+ { 0x2052, 0x7D },
+ { 0x2053, 0x00 },
+ { 0x2054, 0x95 },
+ { 0x2055, 0x00 },
+ { 0x2056, 0x97 },
+ { 0x2057, 0x00 },
+ { 0x2058, 0xAD },
+ { 0x2059, 0x00 },
+ { 0x205A, 0xAF },
+ { 0x205B, 0x00 },
+ { 0x205C, 0x92 },
+ { 0x205D, 0x00 },
+ { 0x205E, 0x94 },
+ { 0x205F, 0x00 },
+ { 0x2060, 0x8E },
+ { 0x2061, 0x00 },
+ { 0x2062, 0x90 },
+ { 0x2063, 0x00 },
+ { 0x2064, 0xB1 },
+ { 0x2065, 0x00 },
+ { 0x2066, 0xB3 },
+ { 0x2067, 0x00 },
+ { 0x2068, 0x08 },
+ { 0x2069, 0x00 },
+ { 0x206A, 0x04 },
+ { 0x206B, 0x00 },
+ { 0x206C, 0x84 },
+ { 0x206D, 0x00 },
+ { 0x206E, 0x80 },
+ { 0x206F, 0x00 },
+ { 0x2070, 0x04 },
+ { 0x2071, 0x00 },
+ { 0x2072, 0x46 },
+ { 0x2073, 0x00 },
+ { 0x2074, 0xE9 },
+ { 0x2075, 0x01 },
+ { 0x2076, 0x74 },
+ { 0x2077, 0x02 },
+ { 0x2078, 0x80 },
+ { 0x2079, 0x00 },
+ { 0x207A, 0xC1 },
+ { 0x207B, 0x00 },
+ { 0x207C, 0xFF },
+ { 0x207D, 0x03 },
+ { 0x207E, 0xFF },
+ { 0x207F, 0x03 },
+ { 0x2080, 0x78 },
+ { 0x2081, 0x00 },
+ { 0x2082, 0x6A },
+ { 0x2083, 0x01 },
+ { 0x2084, 0xE4 },
+ { 0x2085, 0x01 },
+ { 0x2086, 0x2B },
+ { 0x2087, 0x03 },
+ { 0x2088, 0x00 },
+ { 0x2089, 0x00 },
+ { 0x208A, 0xFF },
+ { 0x208B, 0x03 },
+ { 0x208C, 0xFF },
+ { 0x208D, 0x03 },
+ { 0x208E, 0xFF },
+ { 0x208F, 0x03 },
+ { 0x2090, 0x7D },
+ { 0x2091, 0x00 },
+ { 0x2092, 0x62 },
+ { 0x2093, 0x01 },
+ { 0x2094, 0xE9 },
+ { 0x2095, 0x01 },
+ { 0x2096, 0x00 },
+ { 0x2097, 0x00 },
+ { 0x2098, 0x7C },
+ { 0x2099, 0x00 },
+ { 0x209A, 0x21 },
+ { 0x209B, 0x03 },
+ { 0x209C, 0xE9 },
+ { 0x209D, 0x01 },
+ { 0x209E, 0x21 },
+ { 0x209F, 0x03 },
+ { 0x20A0, 0xFF },
+ { 0x20A1, 0x03 },
+ { 0x20A2, 0xFF },
+ { 0x20A3, 0x03 },
+ { 0x20A4, 0xFF },
+ { 0x20A5, 0x03 },
+ { 0x20A6, 0xFF },
+ { 0x20A7, 0x03 },
+ { 0x20A8, 0xFF },
+ { 0x20A9, 0x03 },
+ { 0x20AA, 0xFF },
+ { 0x20AB, 0x03 },
+ { 0x20AC, 0xFF },
+ { 0x20AD, 0x03 },
+ { 0x20AE, 0xFF },
+ { 0x20AF, 0x03 },
+ { 0x20B0, 0xFF },
+ { 0x20B1, 0x03 },
+ { 0x20B2, 0xFF },
+ { 0x20B3, 0x03 },
+ { 0x20B4, 0x87 },
+ { 0x20B5, 0xCC },
+ { 0x20B6, 0x87 },
+ { 0x20B7, 0x08 },
+ { 0x20B8, 0xF4 },
+ { 0x20B9, 0xA5 },
+ { 0x20BA, 0x07 },
+ { 0x20BC, 0x1F },
+ { 0x20BD, 0x01 },
+ { 0x20BE, 0xF6 },
+ { 0x20BF, 0x00 },
+ { 0x20C0, 0x90 },
+ { 0x20C1, 0x01 },
+ { 0x20C2, 0x67 },
+ { 0x20C3, 0x01 },
+ { 0x20C4, 0xFF },
+ { 0x20C5, 0x03 },
+ { 0x20C6, 0xFF },
+ { 0x20C7, 0x03 },
+ { 0x20C8, 0x33 },
+ { 0x20C9, 0x02 },
+ { 0x20CA, 0x0A },
+ { 0x20CB, 0x02 },
+ { 0x20CC, 0x7F },
+ { 0x20CD, 0x00 },
+ { 0x20CE, 0xD2 },
+ { 0x20CF, 0x00 },
+ { 0x20D0, 0x81 },
+ { 0x20D1, 0x00 },
+ { 0x20D2, 0x87 },
+ { 0x20D3, 0x00 },
+ { 0x20D4, 0x09 },
+ { 0x20D5, 0x00 },
+ { 0x20D8, 0x7F },
+ { 0x20D9, 0x00 },
+ { 0x20DA, 0x62 },
+ { 0x20DB, 0x01 },
+ { 0x20DC, 0x7F },
+ { 0x20DD, 0x00 },
+ { 0x20DE, 0x62 },
+ { 0x20DF, 0x01 },
+ { 0x20E0, 0x65 },
+ { 0x20E1, 0x00 },
+ { 0x20E2, 0x75 },
+ { 0x20E3, 0x00 },
+ { 0x20E4, 0xE0 },
+ { 0x20E5, 0x00 },
+ { 0x20E6, 0xF0 },
+ { 0x20E7, 0x00 },
+ { 0x20E8, 0x4C },
+ { 0x20E9, 0x01 },
+ { 0x20EA, 0x5C },
+ { 0x20EB, 0x01 },
+ { 0x20EC, 0xD1 },
+ { 0x20ED, 0x01 },
+ { 0x20EE, 0xE1 },
+ { 0x20EF, 0x01 },
+ { 0x20F0, 0x93 },
+ { 0x20F1, 0x02 },
+ { 0x20F2, 0xA3 },
+ { 0x20F3, 0x02 },
+ { 0x20F4, 0x0D },
+ { 0x20F5, 0x03 },
+ { 0x20F6, 0x1D },
+ { 0x20F7, 0x03 },
+ { 0x20F8, 0x57 },
+ { 0x20F9, 0x00 },
+ { 0x20FA, 0x7B },
+ { 0x20FB, 0x00 },
+ { 0x20FC, 0xD2 },
+ { 0x20FD, 0x00 },
+ { 0x20FE, 0xF6 },
+ { 0x20FF, 0x00 },
+ { 0x2100, 0x3E },
+ { 0x2101, 0x01 },
+ { 0x2102, 0x60 },
+ { 0x2103, 0x01 },
+ { 0x2104, 0xC3 },
+ { 0x2105, 0x01 },
+ { 0x2106, 0xE5 },
+ { 0x2107, 0x01 },
+ { 0x2108, 0x85 },
+ { 0x2109, 0x02 },
+ { 0x210A, 0xA9 },
+ { 0x210B, 0x02 },
+ { 0x210C, 0xFF },
+ { 0x210D, 0x02 },
+ { 0x210E, 0x21 },
+ { 0x210F, 0x03 },
+ { 0x2110, 0xFF },
+ { 0x2111, 0x03 },
+ { 0x2112, 0x00 },
+ { 0x2113, 0x00 },
+ { 0x2114, 0xFF },
+ { 0x2115, 0x03 },
+ { 0x2116, 0xFF },
+ { 0x2117, 0x03 },
+ { 0x2118, 0xFF },
+ { 0x2119, 0x03 },
+ { 0x211A, 0xFF },
+ { 0x211B, 0x03 },
+ { 0x211C, 0xFF },
+ { 0x211D, 0x03 },
+ { 0x211E, 0xFF },
+ { 0x211F, 0x03 },
+ { 0x2120, 0xFF },
+ { 0x2121, 0x03 },
+ { 0x2122, 0xFF },
+ { 0x2123, 0x03 },
+ { 0x2124, 0xFF },
+ { 0x2125, 0x03 },
+ { 0x2126, 0xFF },
+ { 0x2127, 0x03 },
+ { 0x2128, 0x7D },
+ { 0x2129, 0x90 },
+ { 0x212A, 0xD5 },
+ { 0x212B, 0x07 },
+ { 0x212C, 0x64 },
+ { 0x212D, 0x01 },
+ { 0x2130, 0x5F },
+ { 0x2131, 0x7D },
+ { 0x2132, 0x05 },
+ { 0x2134, 0x78 },
+ { 0x2135, 0x00 },
+ { 0x2136, 0x76 },
+ { 0x2137, 0x00 },
+ { 0x2138, 0xF3 },
+ { 0x2139, 0x00 },
+ { 0x213A, 0xF1 },
+ { 0x213B, 0x00 },
+ { 0x213C, 0xA6 },
+ { 0x213D, 0x02 },
+ { 0x213E, 0xA4 },
+ { 0x213F, 0x02 },
+ { 0x2140, 0x7D },
+ { 0x2141, 0x00 },
+ { 0x2142, 0x8D },
+ { 0x2143, 0x00 },
+ { 0x2144, 0xA1 },
+ { 0x2145, 0x01 },
+ { 0x2146, 0xB1 },
+ { 0x2147, 0x01 },
+ { 0x2148, 0xAB },
+ { 0x2149, 0x02 },
+ { 0x214A, 0xBB },
+ { 0x214B, 0x02 },
+ { 0x214C, 0x17 },
+ { 0x214D, 0x5C },
+ { 0x214E, 0x00 },
+ { 0x2150, 0x00 },
+ { 0x2151, 0x00 },
+ { 0x2152, 0xF8 },
+ { 0x2153, 0x00 },
+ { 0x2154, 0xBE },
+ { 0x2155, 0x00 },
+ { 0x2156, 0x7D },
+ { 0x2157, 0x00 },
+ { 0x2158, 0x25 },
+ { 0x2159, 0x00 },
+ { 0x215A, 0x7D },
+ { 0x215B, 0x00 },
+ { 0x215C, 0x62 },
+ { 0x215D, 0x01 },
+ { 0x215E, 0xFF },
+ { 0x215F, 0x03 },
+ { 0x2160, 0x26 },
+ { 0x2161, 0x00 },
+ { 0x2162, 0x7D },
+ { 0x2163, 0x00 },
+ { 0x2164, 0x63 },
+ { 0x2165, 0x01 },
+ { 0x2166, 0xFF },
+ { 0x2167, 0x03 },
+ { 0x2168, 0xCB },
+ { 0x2169, 0x02 },
+ { 0x216A, 0xCF },
+ { 0x216B, 0x02 },
+ { 0x216C, 0xFF },
+ { 0x216D, 0x03 },
+ { 0x216E, 0xFF },
+ { 0x216F, 0x03 },
+ { 0x2170, 0xFF },
+ { 0x2171, 0x03 },
+ { 0x2172, 0xFF },
+ { 0x2173, 0x03 },
+ { 0x2174, 0xFF },
+ { 0x2175, 0x03 },
+ { 0x2176, 0xFF },
+ { 0x2177, 0x03 },
+ { 0x2178, 0x7E },
+ { 0x2179, 0x00 },
+ { 0x217A, 0xBD },
+ { 0x217B, 0x00 },
+ { 0x217C, 0xEC },
+ { 0x217D, 0x01 },
+ { 0x217E, 0x7B },
+ { 0x217F, 0x02 },
+ { 0x2180, 0xD1 },
+ { 0x2181, 0x02 },
+ { 0x2182, 0x25 },
+ { 0x2183, 0x03 },
+ { 0x2184, 0x7F },
+ { 0x2185, 0x00 },
+ { 0x2186, 0xBD },
+ { 0x2187, 0x00 },
+ { 0x2188, 0xED },
+ { 0x2189, 0x01 },
+ { 0x218A, 0x7B },
+ { 0x218B, 0x02 },
+ { 0x218C, 0xD2 },
+ { 0x218D, 0x02 },
+ { 0x218E, 0x25 },
+ { 0x218F, 0x03 },
+ { 0x2190, 0xFF },
+ { 0x2191, 0x03 },
+ { 0x2192, 0xFF },
+ { 0x2193, 0x03 },
+ { 0x2194, 0xE9 },
+ { 0x2195, 0x01 },
+ { 0x2196, 0x21 },
+ { 0x2197, 0x03 },
+ { 0x2198, 0x17 },
+ { 0x2199, 0xFC },
+ { 0x219A, 0x7F },
+ { 0x219B, 0x01 },
+ { 0x219C, 0xFF },
+ { 0x219D, 0x03 },
+ { 0x21A0, 0x1B },
+ { 0x21A1, 0x1B },
+ { 0x21A2, 0x1B },
+ { 0x21A3, 0x1B },
+ { 0x21A4, 0x2E },
+ { 0x21A5, 0x80 },
+ { 0x21A6, 0x00 },
+ { 0x21A8, 0x04 },
+ { 0x21A9, 0x98 },
+ { 0x21AA, 0x60 },
+ { 0x21AB, 0x03 },
+ { 0x21AC, 0x7F },
+ { 0x21AD, 0x80 },
+ { 0x21AE, 0x09 },
+ { 0x21B0, 0x1C },
+ { 0x21B1, 0x00 },
+ { 0x21B2, 0xA0 },
+ { 0x21B3, 0x00 },
+ { 0x21B4, 0x0C },
+ { 0x21B5, 0x00 },
+ { 0x21B6, 0x2D },
+ { 0x21B7, 0x00 },
+ { 0x21B8, 0x20 },
+ { 0x21B9, 0x00 },
+ { 0x21BA, 0x02 },
+ { 0x21BB, 0x00 },
+ { 0x21BC, 0xCC },
+ { 0x21BD, 0x00 },
+ { 0x21BE, 0x4A },
+ { 0x21BF, 0x00 },
+ { 0x21C0, 0xD0 },
+ { 0x21C1, 0x00 },
+ { 0x21C2, 0x44 },
+ { 0x21C3, 0x00 },
+ { 0x21C4, 0x00 },
+ { 0x21C5, 0xE0 },
+ { 0x21C6, 0x00 },
+ { 0x21C8, 0x11 },
+ { 0x21C9, 0x00 },
+ { 0x21CA, 0x02 },
+ { 0x21CC, 0x08 },
+ { 0x21CD, 0xC0 },
+ { 0x21CE, 0x0C },
+ { 0x21D0, 0x44 },
+ { 0x21D1, 0x00 },
+ { 0x21D2, 0x02 },
+ { 0x21D4, 0x02 },
+ { 0x21D5, 0x20 },
+ { 0x21D6, 0x2C },
+ { 0x21D8, 0xFE },
+ { 0x21D9, 0x9D },
+ { 0x21DA, 0xDF },
+ { 0x21DB, 0x03 },
+ { 0x21DC, 0x62 },
+ { 0x21DD, 0x01 },
+ { 0x21DE, 0x7F },
+ { 0x21DF, 0x00 },
+ { 0x21E0, 0xB7 },
+ { 0x21E1, 0x01 },
+ { 0x21E2, 0xB5 },
+ { 0x21E3, 0x01 },
+ { 0x21E4, 0xC1 },
+ { 0x21E5, 0x02 },
+ { 0x21E6, 0xBF },
+ { 0x21E7, 0x02 },
+ { 0x21E8, 0xB3 },
+ { 0x21E9, 0x0D },
+ { 0x21EA, 0x00 },
+ { 0x21EB, 0x04 },
+ { 0x21EC, 0x90 },
+ { 0x21ED, 0x07 },
+ { 0x21EE, 0x58 },
+ { 0x21EF, 0x04 },
+ { 0x21F0, 0x54 },
+ { 0x21F1, 0x04 },
+ { 0x21F4, 0x02 },
+ { 0x21F5, 0x00 },
+ { 0x21F6, 0x00 },
+ { 0x21F8, 0x3C },
+ { 0x21F9, 0x00 },
+ { 0x21FC, 0x28 },
+ { 0x21FD, 0x00 },
+ { 0x21FE, 0x3C },
+ { 0x21FF, 0x00 },
+ { 0x2200, 0x00 },
+ { 0x2204, 0x4C },
+ { 0x2205, 0x04 },
+ { 0x2206, 0x65 },
+ { 0x2207, 0x04 },
+ { 0x2208, 0x0A },
+ { 0x2209, 0x00 },
+ { 0x220C, 0x47 },
+ { 0x220D, 0x00 },
+ { 0x220E, 0x1F },
+ { 0x220F, 0x00 },
+ { 0x2210, 0x17 },
+ { 0x2211, 0x00 },
+ { 0x2212, 0x0F },
+ { 0x2213, 0x00 },
+ { 0x2214, 0x17 },
+ { 0x2215, 0x00 },
+ { 0x2216, 0x47 },
+ { 0x2217, 0x00 },
+ { 0x2218, 0x0F },
+ { 0x2219, 0x00 },
+ { 0x221A, 0x0F },
+ { 0x221B, 0x00 },
+ { 0x221C, 0x03 },
+ { 0x2220, 0x20 },
+ { 0x2221, 0x20 },
+ { 0x2222, 0x22 },
+ { 0x2223, 0x02 },
+ { 0x2224, 0xA7 },
+ { 0x2225, 0xAA },
+ { 0x2226, 0x80 },
+ { 0x2227, 0x08 },
+ { 0x2228, 0x01 },
+ { 0x22B2, 0x92 },
+ { 0x22B4, 0x20 },
+ { 0x22B5, 0x00 },
+ { 0x22B6, 0x20 },
+ { 0x22B7, 0x00 },
+ { 0x22B8, 0x20 },
+ { 0x22B9, 0x00 },
+ { 0x22BA, 0x20 },
+ { 0x22BB, 0x00 },
+ { 0x22BC, 0x20 },
+ { 0x22BD, 0x00 },
+ { 0x22BE, 0x20 },
+ { 0x22BF, 0x00 },
+ { 0x22C0, 0x20 },
+ { 0x22C1, 0x00 },
+ { 0x22C2, 0x20 },
+ { 0x22C3, 0x00 },
+ { 0x22C4, 0x20 },
+ { 0x22C5, 0x00 },
+ { 0x22C6, 0x20 },
+ { 0x22C7, 0x00 },
+ { 0x22C8, 0x20 },
+ { 0x22C9, 0x00 },
+ { 0x22CA, 0x20 },
+ { 0x22CB, 0x00 },
+ { 0x22CC, 0x20 },
+ { 0x22CD, 0x00 },
+ { 0x22CE, 0x20 },
+ { 0x22CF, 0x00 },
+ { 0x22DA, 0x00 },
+ { 0x2308, 0x01 },
+ { 0x2311, 0x09 },
+ { 0x2318, 0x40 },
+ { 0x2319, 0xCD },
+ { 0x231A, 0x54 },
+ { 0x2324, 0x10 },
+ { 0x2325, 0x00 },
+ { 0x2328, 0x00 },
+ { 0x2354, 0x0C },
+ { 0x23C0, 0x5D },
+ { 0x244C, 0x00 },
+ { 0x244D, 0x02 },
+ { 0x244E, 0x54 },
+ { 0x244F, 0x02 },
+ { 0x24A0, 0x00 },
+ { 0x24DA, 0x6F },
+ { 0x24DB, 0x00 },
+ { 0x24DC, 0x62 },
+ { 0x24DD, 0x01 },
+ { 0x24EA, 0x32 },
+ { 0x24EB, 0x00 },
+ { 0x24EC, 0xDC },
+ { 0x24ED, 0x00 },
+ { 0x24FA, 0x32 },
+ { 0x24FB, 0x00 },
+ { 0x24FC, 0xDD },
+ { 0x24FD, 0x00 },
+ { 0x254A, 0x15 },
+ { 0x254B, 0x01 },
+ { 0x255A, 0x15 },
+ { 0x255B, 0x01 },
+ { 0x2560, 0x01 },
+ { 0x2561, 0x00 },
+ { 0x2562, 0x2A },
+ { 0x2563, 0x00 },
+ { 0x2564, 0xF8 },
+ { 0x2565, 0x00 },
+ { 0x2566, 0x15 },
+ { 0x2567, 0x01 },
+ { 0x2568, 0x0C },
+ { 0x2569, 0x02 },
+ { 0x256A, 0x31 },
+ { 0x256B, 0x02 },
+ { 0x2578, 0x90 },
+ { 0x2579, 0x01 },
+ { 0x257A, 0x92 },
+ { 0x257B, 0x01 },
+ { 0x257C, 0xB8 },
+ { 0x257D, 0x02 },
+ { 0x257E, 0xBA },
+ { 0x257F, 0x02 },
+ { 0x2584, 0x90 },
+ { 0x2585, 0x01 },
+ { 0x2586, 0x92 },
+ { 0x2587, 0x01 },
+ { 0x2588, 0xB8 },
+ { 0x2589, 0x02 },
+ { 0x258A, 0xBA },
+ { 0x258B, 0x02 },
+ { 0x26B8, 0x10 },
+ { 0x26B9, 0x00 },
+ { 0x26BA, 0x33 },
+ { 0x26BB, 0x00 },
+ { 0x26BC, 0x89 },
+ { 0x26BD, 0x00 },
+ { 0x26BE, 0xB0 },
+ { 0x26BF, 0x00 },
+ { 0x26C4, 0x4E },
+ { 0x26C5, 0x00 },
+ { 0x26C8, 0xC9 },
+ { 0x26C9, 0x00 },
+ { 0x26CC, 0x35 },
+ { 0x26CD, 0x01 },
+ { 0x26D0, 0xBA },
+ { 0x26D1, 0x01 },
+ { 0x26D4, 0x7C },
+ { 0x26D5, 0x02 },
+ { 0x26D8, 0xF6 },
+ { 0x26D9, 0x02 },
+ { 0x26DE, 0x51 },
+ { 0x26DF, 0x00 },
+ { 0x26E0, 0x7F },
+ { 0x26E1, 0x00 },
+ { 0x26E2, 0xCC },
+ { 0x26E3, 0x00 },
+ { 0x26E4, 0xF8 },
+ { 0x26E5, 0x00 },
+ { 0x26E6, 0x38 },
+ { 0x26E7, 0x01 },
+ { 0x26E8, 0x65 },
+ { 0x26E9, 0x01 },
+ { 0x26EA, 0xBD },
+ { 0x26EB, 0x01 },
+ { 0x26EE, 0x7F },
+ { 0x26EF, 0x02 },
+ { 0x26F0, 0xAB },
+ { 0x26F1, 0x02 },
+ { 0x26F2, 0xF9 },
+ { 0x26F3, 0x02 },
+ { 0x2722, 0x59 },
+ { 0x2723, 0x02 },
+ { 0x2938, 0x55 },
+ { 0x2939, 0x00 },
+ { 0x293A, 0x17 },
+ { 0x293B, 0x00 },
+ { 0x293C, 0xD0 },
+ { 0x293D, 0x00 },
+ { 0x293E, 0x91 },
+ { 0x293F, 0x00 },
+ { 0x2940, 0x3C },
+ { 0x2941, 0x01 },
+ { 0x2942, 0x0C },
+ { 0x2943, 0x01 },
+ { 0x2944, 0xC1 },
+ { 0x2945, 0x01 },
+ { 0x2946, 0x76 },
+ { 0x2947, 0x01 },
+ { 0x2948, 0x83 },
+ { 0x2949, 0x02 },
+ { 0x294A, 0xFB },
+ { 0x294B, 0x01 },
+ { 0x294C, 0xFD },
+ { 0x294D, 0x02 },
+ { 0x294E, 0xBF },
+ { 0x294F, 0x02 },
+ { 0x2A06, 0xFF },
+ { 0x2A07, 0x03 },
+ { 0x2A20, 0x00 },
+ { 0x2A21, 0x00 },
+ { 0x2A22, 0x7D },
+ { 0x2A23, 0x00 },
+ { 0x2B11, 0x19 },
+ { 0x2B13, 0x15 },
+ { 0x2B14, 0x14 },
+ { 0x2B15, 0x13 },
+ { 0x2B16, 0x12 },
+ { 0x2B17, 0x11 },
+ { 0x2B18, 0x10 },
+ { 0x2B19, 0x0F },
+ { 0x2B1A, 0x0E },
+ { 0x2B1B, 0x0D },
+ { 0x2B1C, 0x0C },
+ { 0x2B1D, 0x0B },
+ { 0x2B1E, 0x0A },
+ { 0x2B1F, 0x09 },
+ { 0x2B20, 0x08 },
+ { 0x2B21, 0x07 },
+ { 0x2B22, 0x06 },
+ { 0x2B23, 0x05 },
+ { 0x2B24, 0x04 },
+ { 0x2B25, 0x03 },
+ { 0x2B26, 0x03 },
+ { 0x2B38, 0x01 },
+ { 0x2B45, 0xE3 },
+ { 0x2B50, 0x01 },
+ { 0x2B51, 0x00 },
+ { 0x2B6D, 0x47 },
+ { 0x2B70, 0x02 },
+ { 0x2B71, 0x02 },
+ { 0x2B72, 0x02 },
+ { 0x2B7F, 0x7F },
+ { 0x2B80, 0x94 },
+ { 0x2B81, 0x06 },
+ { 0x2B87, 0x1B },
+ { 0x2B88, 0x1B },
+ { 0x2B89, 0x17 },
+ { 0x2B8A, 0x12 },
+ { 0x2B8B, 0x12 },
+ { 0x2B8D, 0x2B },
+ { 0x2B8E, 0x2B },
+ { 0x2B8F, 0x2B },
+ { 0x2B90, 0x7F },
+ { 0x2B91, 0x1F },
+ { 0x2B94, 0x7F },
+ { 0x2B95, 0x27 },
+ { 0x2B98, 0x7F },
+ { 0x2B99, 0x57 },
+ { 0x2BA8, 0xBC },
+ { 0x2BA9, 0x62 },
+ { 0x2BC1, 0x70 },
+ { 0x2BC5, 0x80 },
+ { 0x2BD5, 0x30 },
+ { 0x2BD6, 0xF0 },
+ { 0x2BD8, 0xDB },
+ { 0x2BD9, 0xF6 },
+ { 0x2BDA, 0x63 },
+ { 0x2BDB, 0x0C },
+ { 0x2BDC, 0x5C },
+ { 0x2C98, 0xE1 },
+ { 0x2C99, 0x2E },
+ { 0x2C9B, 0x86 },
+ { 0x2CA9, 0x80 },
+ { 0x2CAA, 0x01 },
+ { 0x2D39, 0x0E },
+ { 0x2D54, 0x00 },
+ { 0x2D5B, 0x58 },
+ { 0x2D64, 0x64 },
+ { 0x2D65, 0x80 },
+ { 0x3000, 0x00 },
+ { 0x3001, 0x00 },
+ { 0x3002, 0x23 },
+ { 0x3003, 0xA1 },
+ { 0x3004, 0x00 },
+ { 0x3005, 0x20 },
+ { 0x3006, 0x84 },
+ { 0x3007, 0x00 },
+ { 0x3008, 0x06 },
+ { 0x3009, 0xB4 },
+ { 0x300A, 0x1F },
+ { 0x300B, 0x00 },
+ { 0x300C, 0x00 },
+ { 0x300D, 0x1B },
+ { 0x300E, 0x90 },
+ { 0x300F, 0x97 },
+ { 0x3010, 0x00 },
+ { 0x3011, 0x00 },
+ { 0x3012, 0x21 },
+ { 0x3013, 0x21 },
+ { 0x3014, 0x00 },
+ { 0x3015, 0x20 },
+ { 0x3016, 0x84 },
+ { 0x3017, 0x00 },
+ { 0x3018, 0x30 },
+ { 0x3019, 0x09 },
+ { 0x301A, 0x46 },
+ { 0x301B, 0x00 },
+ { 0x3070, 0xC1 },
+ { 0x3071, 0x81 },
+ { 0x3072, 0x29 },
+ { 0x3073, 0x81 },
+ { 0x3410, (IMX390_OUT_WIDTH & 0xFF) },
+ { 0x3411, (IMX390_OUT_WIDTH >> 8) },
+ { 0x3418, (IMX390_OUT_HEIGHT & 0xFF) },
+ { 0x3419, (IMX390_OUT_HEIGHT >> 8) },
+ { 0x34A0, 0x30 },
+ { 0x34C0, 0xD3 },
+ { 0x34C1, 0x00 },
+ { 0x34C2, 0xD3 },
+ { 0x34C3, 0x00 },
+ { 0x34C4, 0xD3 },
+ { 0x34C5, 0x00 },
+ { 0x34C6, 0xD3 },
+ { 0x34C7, 0x00 },
+ { 0x34C8, 0xE2 },
+ { 0x34C9, 0x21 },
+ { 0x34CA, 0xE0 },
+ { 0x34CB, 0x1F },
+ { 0x34CC, 0x06 },
+ { 0x34CD, 0x20 },
+ { 0x34CE, 0x28 },
+ { 0x34CF, 0x1F },
+ { 0x3584, 0x00 },
+ { 0x3586, 0x00 },
+ { 0x3587, 0x01 },
+ { 0x3588, 0xE6 },
+ { 0x3589, 0x00 },
+ { 0x3590, 0x00 },
+ { 0x3591, 0x00 },
+ { 0x3594, 0x40 },
+ { 0x3598, 0x03 },
+ { 0x3599, 0x00 },
+ { 0x359A, 0x80 },
+ { 0x359B, 0x00 },
+ { 0x359C, 0x00 },
+ { 0x359D, 0x01 },
+ { 0x359E, 0x00 },
+ { 0x359F, 0x02 },
+ { 0x35A0, 0x00 },
+ { 0x35A1, 0x04 },
+ { 0x35A2, 0x20 },
+ { 0x35A3, 0x00 },
+ { 0x35A4, 0x40 },
+ { 0x35A5, 0x00 },
+ { 0x35A6, 0x80 },
+ { 0x35A7, 0x00 },
+ { 0x35A8, 0x00 },
+ { 0x35A9, 0x01 },
+ { 0x35AA, 0x3A },
+ { 0x35AB, 0x00 },
+ { 0x35AC, 0x80 },
+ { 0x35AD, 0x00 },
+ { 0x35AE, 0x00 },
+ { 0x35AF, 0x01 },
+ { 0x35B0, 0x00 },
+ { 0x35B1, 0x02 },
+ { 0x35B2, 0x00 },
+ { 0x35B3, 0x04 },
+ { 0x35B4, 0x02 },
+ { 0x35B5, 0x00 },
+ { 0x35B6, 0x04 },
+ { 0x35B7, 0x00 },
+ { 0x35B8, 0x08 },
+ { 0x35B9, 0x00 },
+ { 0x35BA, 0x10 },
+ { 0x35BB, 0x00 },
+ { 0x35BC, 0x03 },
+ { 0x35BD, 0x00 },
+ { 0x35C8, 0x00 },
+ { 0x35C9, 0x01 },
+ { 0x35CA, 0x00 },
+ { 0x35CB, 0x04 },
+ { 0x35CC, 0x00 },
+ { 0x35CD, 0x10 },
+ { 0x35CE, 0x00 },
+ { 0x35CF, 0x40 },
+ { 0x35D0, 0x00 },
+ { 0x35D1, 0x0C },
+ { 0x35D2, 0x00 },
+ { 0x35D3, 0x0C },
+ { 0x35D4, 0x00 },
+ { 0x35D5, 0x0C },
+ { 0x35D6, 0x00 },
+ { 0x35D7, 0x0C },
+ { 0x35D8, 0x00 },
+ { 0x35D9, 0x00 },
+ { 0x35DA, 0x08 },
+ { 0x35DB, 0x00 },
+ { 0x35DC, 0xD8 },
+ { 0x35DD, 0x0E },
+ { 0x35F0, 0x00 },
+ { 0x35F1, 0x10 },
+ { 0x35F2, 0x00 },
+ { 0x35F3, 0x10 },
+ { 0x35F4, 0x00 },
+ { 0x35F5, 0x10 },
+ { 0x35F6, 0x00 },
+ { 0x35F7, 0x03 },
+ { 0x35F8, 0x00 },
+ { 0x35F9, 0x01 },
+ { 0x35FA, 0x38 },
+ { 0x35FB, 0x00 },
+ { 0x35FC, 0xB3 },
+ { 0x35FD, 0x01 },
+ { 0x35FE, 0x00 },
+ { 0x35FF, 0x00 },
+ { 0x3600, 0x04 },
+ { 0x3601, 0x06 },
+ { 0x3604, 0x03 },
+ { 0x3605, 0x00 },
+ { 0x3608, 0x03 },
+ { 0x3609, 0x00 },
+ { 0x360C, 0x00 },
+ { 0x360D, 0x00 },
+ { 0x3610, 0x10 },
+ { 0x3611, 0x01 },
+ { 0x3612, 0x00 },
+ { 0x3613, 0x00 },
+ { 0x3614, 0x00 },
+ { 0x3615, 0x00 },
+ { 0x361C, 0x00 },
+ { 0x361D, 0x01 },
+ { 0x361E, 0x00 },
+ { 0x361F, 0x01 },
+ { 0x3620, 0x01 },
+ { 0x3621, 0x00 },
+ { 0x3622, 0xB0 },
+ { 0x3623, 0x04 },
+ { 0x3624, 0xDC },
+ { 0x3625, 0x05 },
+ { 0x3626, 0x00 },
+ { 0x3627, 0x01 },
+ { 0x3628, 0xFF },
+ { 0x3629, 0x0F },
+ { 0x362A, 0x00 },
+ { 0x362B, 0x10 },
+ { 0x362C, 0x00 },
+ { 0x362D, 0x01 },
+ { 0x3630, 0x40 },
+ { 0x3631, 0x00 },
+ { 0x3632, 0x40 },
+ { 0x3633, 0x00 },
+ { 0x3634, 0x40 },
+ { 0x3635, 0x00 },
+ { 0x3636, 0x40 },
+ { 0x3637, 0x00 },
+ { 0x3638, 0x40 },
+ { 0x3639, 0x00 },
+ { 0x363A, 0x40 },
+ { 0x363B, 0x00 },
+ { 0x363C, 0x40 },
+ { 0x363D, 0x00 },
+ { 0x363E, 0x40 },
+ { 0x363F, 0x00 },
+ { 0x36C4, 0x99 },
+ { 0x36C5, 0x09 },
+ { 0x36C6, 0x18 },
+ { 0x36C7, 0x07 },
+ { 0x36C8, 0x65 },
+ { 0x36C9, 0x0E },
+ { 0x36CC, 0x99 },
+ { 0x36CD, 0x01 },
+ { 0x36CE, 0x47 },
+ { 0x36CF, 0x00 },
+ { 0x36D0, 0x04 },
+ { 0x36D1, 0x00 },
+ { 0x36D4, 0x65 },
+ { 0x36D5, 0x0E },
+ { 0x36D6, 0xA4 },
+ { 0x36D7, 0x0A },
+ { 0x36D8, 0x65 },
+ { 0x36D9, 0x0E },
+ { 0x36DC, 0x65 },
+ { 0x36DD, 0x0E },
+ { 0x36DE, 0xA4 },
+ { 0x36DF, 0x0A },
+ { 0x36E0, 0x65 },
+ { 0x36E1, 0x0E },
+ { 0x36E4, 0x65 },
+ { 0x36E5, 0x0E },
+ { 0x36E6, 0xA4 },
+ { 0x36E7, 0x0A },
+ { 0x36E8, 0x65 },
+ { 0x36E9, 0x0E },
+ { 0x36EE, 0x00 },
+ { 0x36EF, 0x00 },
+ { 0x36F0, 0x00 },
+ { 0x36F1, 0x80 },
+ { 0x36F8, 0x00 },
+ { 0x3702, 0x03 },
+ { 0x3703, 0x04 },
+ { 0x3704, 0x08 },
+ { 0x370E, 0x0E },
+ { 0x3718, 0x62 },
+ { 0x3719, 0x4A },
+ { 0x371A, 0x38 },
+ { 0x371B, 0x20 },
+ { 0x371C, 0x64 },
+ { 0x371D, 0x42 },
+ { 0x371E, 0x32 },
+ { 0x371F, 0x1B },
+ { 0x3720, 0x9C },
+ { 0x3721, 0xA4 },
+ { 0x3722, 0xAC },
+ { 0x3723, 0xB4 },
+ { 0x3748, 0xAA },
+ { 0x3749, 0x96 },
+ { 0x374A, 0x7D },
+ { 0x374B, 0x69 },
+ { 0x37C0, 0x00 },
+ { 0x37C1, 0x00 },
+ { 0x37C2, 0x00 },
+ { 0x37C4, 0x00 },
+ { 0x37C5, 0x00 },
+ { 0x37C6, 0x00 },
+ { 0x37C8, 0x00 },
+ { 0x37C9, 0x00 },
+ { 0x37CA, 0x00 },
+ { 0x37CC, 0x00 },
+ { 0x37CD, 0x00 },
+ { 0x37CE, 0x00 },
+ { 0x37D0, 0x00 },
+ { 0x37D1, 0x00 },
+ { 0x37D2, 0x00 },
+ { 0x37D4, 0x00 },
+ { 0x37D5, 0x00 },
+ { 0x37D6, 0x00 },
+ { 0x37D8, 0x00 },
+ { 0x37D9, 0x00 },
+ { 0x37DA, 0x00 },
+ { 0x37DC, 0x00 },
+ { 0x37DD, 0x00 },
+ { 0x37DE, 0x00 },
+ { 0x37E0, 0x00 },
+ { 0x37E1, 0x00 },
+ { 0x37E2, 0x00 },
+ { 0x37E4, 0x00 },
+ { 0x37E5, 0x00 },
+ { 0x37E6, 0x00 },
+ { 0x37E8, 0x00 },
+ { 0x37E9, 0x00 },
+ { 0x37EA, 0x00 },
+ { 0x37EC, 0x00 },
+ { 0x37ED, 0x00 },
+ { 0x37EE, 0x00 },
+ { 0x37F0, 0x00 },
+ { 0x37F4, 0x00 },
+ { 0x37F5, 0x1E },
+ { 0x37F6, 0x34 },
+ { 0x37F7, 0x00 },
+ { 0x37F8, 0xFF },
+ { 0x37F9, 0xFF },
+ { 0x37FA, 0x03 },
+ { 0x37FC, 0x00 },
+ { 0x37FD, 0x00 },
+ { 0x37FE, 0x04 },
+ { 0x3800, 0xFF },
+ { 0x3801, 0xFF },
+ { 0x3802, 0x03 },
+ { 0x3804, 0x00 },
+ { 0x3805, 0x00 },
+ { 0x3806, 0x04 },
+ { 0x3808, 0x00 },
+ { 0x3809, 0x00 },
+ { 0x380A, 0x00 },
+ { 0x380C, 0x00 },
+ { 0x380D, 0x00 },
+ { 0x380E, 0x00 },
+ { 0x3810, 0x00 },
+ { 0x3811, 0x00 },
+ { 0x3812, 0x00 },
+ { 0x3814, 0x00 },
+ { 0x3815, 0x00 },
+ { 0x3816, 0x00 },
+ { 0x3818, 0x00 },
+ { 0x3819, 0x00 },
+ { 0x381A, 0x00 },
+ { 0x381C, 0x00 },
+ { 0x381D, 0x00 },
+ { 0x381E, 0x00 },
+ { 0x3820, 0x00 },
+ { 0x3821, 0x00 },
+ { 0x3822, 0x00 },
+ { 0x3824, 0x00 },
+ { 0x3825, 0x00 },
+ { 0x3826, 0x00 },
+ { 0x3828, 0x00 },
+ { 0x3829, 0x00 },
+ { 0x382A, 0x00 },
+ { 0x382C, 0x00 },
+ { 0x382D, 0x00 },
+ { 0x382E, 0x00 },
+ { 0x3830, 0x00 },
+ { 0x3831, 0x00 },
+ { 0x3832, 0x00 },
+ { 0x3834, 0x00 },
+ { 0x3835, 0x00 },
+ { 0x3836, 0x00 },
+ { 0x3838, 0x00 },
+ { 0x3839, 0x00 },
+ { 0x383A, 0x00 },
+ { 0x383B, 0x00 },
+ { 0x383C, 0x00 },
+ { 0x383D, 0x00 },
+ { 0x383E, 0x00 },
+ { 0x383F, 0x00 },
+ { 0x3840, 0x00 },
+ { 0x3841, 0x00 },
+ { 0x3842, 0x00 },
+ { 0x3843, 0x00 },
+ { 0x3844, 0x00 },
+ { 0x3845, 0x00 },
+ { 0x3846, 0x00 },
+ { 0x3847, 0x00 },
+ { 0x3848, 0x00 },
+ { 0x3849, 0x00 },
+ { 0x384A, 0x00 },
+ { 0x384B, 0x00 },
+ { 0x384C, 0x00 },
+ { 0x384D, 0x00 },
+ { 0x384E, 0x00 },
+ { 0x384F, 0x00 },
+ { 0x3850, 0xFF },
+ { 0x3851, 0x0F },
+ { 0x3852, 0x00 },
+ { 0x3853, 0x10 },
+ { 0x3854, 0xFF },
+ { 0x3855, 0x0F },
+ { 0x3856, 0x00 },
+ { 0x3857, 0x10 },
+ { 0x3858, 0xFF },
+ { 0x3859, 0x0F },
+ { 0x385A, 0x00 },
+ { 0x385B, 0x10 },
+ { 0x385C, 0x02 },
+ { 0x385D, 0x00 },
+ { 0x385E, 0x06 },
+ { 0x385F, 0x00 },
+ { 0x3860, 0x06 },
+ { 0x3861, 0x00 },
+ { 0x3862, 0x08 },
+ { 0x3863, 0x00 },
+ { 0x3864, 0x02 },
+ { 0x3865, 0x00 },
+ { 0x38A0, 0x01 },
+ { 0x38A1, 0x01 },
+ { 0x38A2, 0x00 },
+ { 0x38A3, 0x01 },
+ { 0x38A4, 0x07 },
+ { 0x38A5, 0x00 },
+ { 0x38A6, 0x04 },
+ { 0x38A7, 0x05 },
+ { 0x38A8, 0x00 },
+ { 0x38A9, 0x00 },
+ { 0x38AC, 0x00 },
+ { 0x38AD, 0x00 },
+ { 0x38AE, 0x01 },
+ { 0x38B0, 0x02 },
+ { 0x38B2, 0x22 },
+ { 0x38B3, 0x00 },
+ { 0x38B4, 0x17 },
+ { 0x38B5, 0x00 },
+ { 0x38B6, 0x11 },
+ { 0x38B7, 0x00 },
+ { 0x38B8, 0x0E },
+ { 0x38B9, 0x00 },
+ { 0x38BA, 0x2A },
+ { 0x38BB, 0x00 },
+ { 0x38BC, 0x1C },
+ { 0x38BD, 0x00 },
+ { 0x38BE, 0x14 },
+ { 0x38BF, 0x00 },
+ { 0x38C0, 0x10 },
+ { 0x38C1, 0x00 },
+ { 0x38C2, 0x31 },
+ { 0x38C3, 0x00 },
+ { 0x38C4, 0x21 },
+ { 0x38C5, 0x00 },
+ { 0x38C6, 0x18 },
+ { 0x38C7, 0x00 },
+ { 0x38C8, 0x12 },
+ { 0x38C9, 0x00 },
+ { 0x38CA, 0x3C },
+ { 0x38CB, 0x00 },
+ { 0x38CC, 0x29 },
+ { 0x38CD, 0x00 },
+ { 0x38CE, 0x1D },
+ { 0x38CF, 0x00 },
+ { 0x38D0, 0x15 },
+ { 0x38D1, 0x00 },
+ { 0x38D2, 0x4E },
+ { 0x38D3, 0x00 },
+ { 0x38D4, 0x35 },
+ { 0x38D5, 0x00 },
+ { 0x38D6, 0x26 },
+ { 0x38D7, 0x00 },
+ { 0x38D8, 0x1A },
+ { 0x38D9, 0x00 },
+ { 0x38DA, 0x69 },
+ { 0x38DB, 0x00 },
+ { 0x38DC, 0x48 },
+ { 0x38DD, 0x00 },
+ { 0x38DE, 0x33 },
+ { 0x38DF, 0x00 },
+ { 0x38E0, 0x22 },
+ { 0x38E1, 0x00 },
+ { 0x38E2, 0x93 },
+ { 0x38E3, 0x00 },
+ { 0x38E4, 0x64 },
+ { 0x38E5, 0x00 },
+ { 0x38E6, 0x48 },
+ { 0x38E7, 0x00 },
+ { 0x38E8, 0x30 },
+ { 0x38E9, 0x00 },
+ { 0x38EA, 0xD3 },
+ { 0x38EB, 0x00 },
+ { 0x38EC, 0x90 },
+ { 0x38ED, 0x00 },
+ { 0x38EE, 0x69 },
+ { 0x38EF, 0x00 },
+ { 0x38F0, 0x49 },
+ { 0x38F1, 0x00 },
+ { 0x38F2, 0x39 },
+ { 0x38F3, 0x01 },
+ { 0x38F4, 0xD5 },
+ { 0x38F5, 0x00 },
+ { 0x38F6, 0x9F },
+ { 0x38F7, 0x00 },
+ { 0x38F8, 0x75 },
+ { 0x38F9, 0x00 },
+ { 0x38FA, 0x00 },
+ { 0x38FB, 0x01 },
+ { 0x38FC, 0x00 },
+ { 0x38FD, 0x01 },
+ { 0x38FE, 0x00 },
+ { 0x38FF, 0x01 },
+ { 0x3900, 0x00 },
+ { 0x3901, 0x01 },
+ { 0x3902, 0x70 },
+ { 0x3903, 0x00 },
+ { 0x3904, 0x30 },
+ { 0x3905, 0x00 },
+ { 0x3906, 0x25 },
+ { 0x3907, 0x00 },
+ { 0x3908, 0x20 },
+ { 0x3909, 0x00 },
+ { 0x390A, 0xB2 },
+ { 0x390B, 0x00 },
+ { 0x390C, 0x80 },
+ { 0x390D, 0x00 },
+ { 0x390E, 0x70 },
+ { 0x390F, 0x00 },
+ { 0x3910, 0x50 },
+ { 0x3911, 0x00 },
+ { 0x3912, 0xB2 },
+ { 0x3913, 0x00 },
+ { 0x3914, 0x80 },
+ { 0x3915, 0x00 },
+ { 0x3916, 0x70 },
+ { 0x3917, 0x00 },
+ { 0x3918, 0x50 },
+ { 0x3919, 0x00 },
+ { 0x391A, 0xB2 },
+ { 0x391B, 0x00 },
+ { 0x391C, 0x80 },
+ { 0x391D, 0x00 },
+ { 0x391E, 0x70 },
+ { 0x391F, 0x00 },
+ { 0x3920, 0x50 },
+ { 0x3921, 0x00 },
+ { 0x3922, 0x40 },
+ { 0x3923, 0x00 },
+ { 0x3924, 0x40 },
+ { 0x3925, 0x00 },
+ { 0x3926, 0x40 },
+ { 0x3927, 0x00 },
+ { 0x3928, 0x40 },
+ { 0x3929, 0x00 },
+ { 0x392A, 0x80 },
+ { 0x392B, 0x00 },
+ { 0x392C, 0x80 },
+ { 0x392D, 0x00 },
+ { 0x392E, 0x80 },
+ { 0x392F, 0x00 },
+ { 0x3930, 0x80 },
+ { 0x3931, 0x00 },
+ { 0x3932, 0x80 },
+ { 0x3933, 0x80 },
+ { 0x3934, 0x80 },
+ { 0x3940, 0x01 },
+ { 0x3941, 0x01 },
+ { 0x3942, 0x00 },
+ { 0x3943, 0x01 },
+ { 0x3944, 0x07 },
+ { 0x3945, 0x00 },
+ { 0x3946, 0x04 },
+ { 0x3947, 0x05 },
+ { 0x3948, 0x00 },
+ { 0x3949, 0x00 },
+ { 0x394C, 0x00 },
+ { 0x394D, 0x00 },
+ { 0x394E, 0x01 },
+ { 0x3950, 0x03 },
+ { 0x3952, 0x14 },
+ { 0x3953, 0x00 },
+ { 0x3954, 0x0F },
+ { 0x3955, 0x00 },
+ { 0x3956, 0x0E },
+ { 0x3957, 0x00 },
+ { 0x3958, 0x0E },
+ { 0x3959, 0x00 },
+ { 0x395A, 0x19 },
+ { 0x395B, 0x00 },
+ { 0x395C, 0x11 },
+ { 0x395D, 0x00 },
+ { 0x395E, 0x0F },
+ { 0x395F, 0x00 },
+ { 0x3960, 0x0E },
+ { 0x3961, 0x00 },
+ { 0x3962, 0x1C },
+ { 0x3963, 0x00 },
+ { 0x3964, 0x13 },
+ { 0x3965, 0x00 },
+ { 0x3966, 0x0F },
+ { 0x3967, 0x00 },
+ { 0x3968, 0x0E },
+ { 0x3969, 0x00 },
+ { 0x396A, 0x23 },
+ { 0x396B, 0x00 },
+ { 0x396C, 0x15 },
+ { 0x396D, 0x00 },
+ { 0x396E, 0x11 },
+ { 0x396F, 0x00 },
+ { 0x3970, 0x0E },
+ { 0x3971, 0x00 },
+ { 0x3972, 0x2E },
+ { 0x3973, 0x00 },
+ { 0x3974, 0x1A },
+ { 0x3975, 0x00 },
+ { 0x3976, 0x14 },
+ { 0x3977, 0x00 },
+ { 0x3978, 0x0F },
+ { 0x3979, 0x00 },
+ { 0x397A, 0x3E },
+ { 0x397B, 0x00 },
+ { 0x397C, 0x23 },
+ { 0x397D, 0x00 },
+ { 0x397E, 0x1A },
+ { 0x397F, 0x00 },
+ { 0x3980, 0x12 },
+ { 0x3981, 0x00 },
+ { 0x3982, 0x56 },
+ { 0x3983, 0x00 },
+ { 0x3984, 0x31 },
+ { 0x3985, 0x00 },
+ { 0x3986, 0x25 },
+ { 0x3987, 0x00 },
+ { 0x3988, 0x1A },
+ { 0x3989, 0x00 },
+ { 0x398A, 0x7B },
+ { 0x398B, 0x00 },
+ { 0x398C, 0x49 },
+ { 0x398D, 0x00 },
+ { 0x398E, 0x39 },
+ { 0x398F, 0x00 },
+ { 0x3990, 0x2C },
+ { 0x3991, 0x00 },
+ { 0x3992, 0xB4 },
+ { 0x3993, 0x00 },
+ { 0x3994, 0x75 },
+ { 0x3995, 0x00 },
+ { 0x3996, 0x61 },
+ { 0x3997, 0x00 },
+ { 0x3998, 0x53 },
+ { 0x3999, 0x00 },
+ { 0x399A, 0x00 },
+ { 0x399B, 0x01 },
+ { 0x399C, 0x00 },
+ { 0x399D, 0x01 },
+ { 0x399E, 0x00 },
+ { 0x399F, 0x01 },
+ { 0x39A0, 0x00 },
+ { 0x39A1, 0x01 },
+ { 0x39A2, 0x70 },
+ { 0x39A3, 0x00 },
+ { 0x39A4, 0x30 },
+ { 0x39A5, 0x00 },
+ { 0x39A6, 0x25 },
+ { 0x39A7, 0x00 },
+ { 0x39A8, 0x20 },
+ { 0x39A9, 0x00 },
+ { 0x39AA, 0xB2 },
+ { 0x39AB, 0x00 },
+ { 0x39AC, 0x80 },
+ { 0x39AD, 0x00 },
+ { 0x39AE, 0x70 },
+ { 0x39AF, 0x00 },
+ { 0x39B0, 0x80 },
+ { 0x39B1, 0x00 },
+ { 0x39B2, 0xB2 },
+ { 0x39B3, 0x00 },
+ { 0x39B4, 0x80 },
+ { 0x39B5, 0x00 },
+ { 0x39B6, 0x70 },
+ { 0x39B7, 0x00 },
+ { 0x39B8, 0x80 },
+ { 0x39B9, 0x00 },
+ { 0x39BA, 0xB2 },
+ { 0x39BB, 0x00 },
+ { 0x39BC, 0x80 },
+ { 0x39BD, 0x00 },
+ { 0x39BE, 0x70 },
+ { 0x39BF, 0x00 },
+ { 0x39C0, 0x80 },
+ { 0x39C1, 0x00 },
+ { 0x39C2, 0x40 },
+ { 0x39C3, 0x00 },
+ { 0x39C4, 0x40 },
+ { 0x39C5, 0x00 },
+ { 0x39C6, 0x40 },
+ { 0x39C7, 0x00 },
+ { 0x39C8, 0x40 },
+ { 0x39C9, 0x00 },
+ { 0x39CA, 0x80 },
+ { 0x39CB, 0x00 },
+ { 0x39CC, 0x80 },
+ { 0x39CD, 0x00 },
+ { 0x39CE, 0x80 },
+ { 0x39CF, 0x00 },
+ { 0x39D0, 0x80 },
+ { 0x39D1, 0x00 },
+ { 0x39D2, 0x80 },
+ { 0x39D3, 0x80 },
+ { 0x39D4, 0x80 },
+ { 0x39E0, 0x01 },
+ { 0x39E1, 0x00 },
+ { 0x39E4, 0x40 },
+ { 0x39E5, 0x01 },
+ { 0x39E6, 0x01 },
+ { 0x39E8, 0x00 },
+ { 0x39E9, 0x01 },
+ { 0x39EA, 0x00 },
+ { 0x39EB, 0x00 },
+ { 0x39EC, 0x01 },
+ { 0x39ED, 0x00 },
+ { 0x39EE, 0x01 },
+ { 0x39F0, 0x03 },
+ { 0x39F1, 0x04 },
+ { 0x39F2, 0x0E },
+ { 0x39F4, 0x1C },
+ { 0x39F5, 0x00 },
+ { 0x39F6, 0x13 },
+ { 0x39F7, 0x00 },
+ { 0x39F8, 0x0D },
+ { 0x39F9, 0x00 },
+ { 0x39FA, 0x07 },
+ { 0x39FB, 0x00 },
+ { 0x39FC, 0x38 },
+ { 0x39FD, 0x00 },
+ { 0x39FE, 0x1C },
+ { 0x39FF, 0x00 },
+ { 0x3A00, 0x11 },
+ { 0x3A01, 0x00 },
+ { 0x3A02, 0x08 },
+ { 0x3A03, 0x00 },
+ { 0x3A04, 0x4A },
+ { 0x3A05, 0x00 },
+ { 0x3A06, 0x23 },
+ { 0x3A07, 0x00 },
+ { 0x3A08, 0x15 },
+ { 0x3A09, 0x00 },
+ { 0x3A0A, 0x09 },
+ { 0x3A0B, 0x00 },
+ { 0x3A0C, 0x65 },
+ { 0x3A0D, 0x00 },
+ { 0x3A0E, 0x2D },
+ { 0x3A0F, 0x00 },
+ { 0x3A10, 0x1A },
+ { 0x3A11, 0x00 },
+ { 0x3A12, 0x0B },
+ { 0x3A13, 0x00 },
+ { 0x3A14, 0x8D },
+ { 0x3A15, 0x00 },
+ { 0x3A16, 0x3D },
+ { 0x3A17, 0x00 },
+ { 0x3A18, 0x23 },
+ { 0x3A19, 0x00 },
+ { 0x3A1A, 0x0E },
+ { 0x3A1B, 0x00 },
+ { 0x3A1C, 0xC5 },
+ { 0x3A1D, 0x00 },
+ { 0x3A1E, 0x55 },
+ { 0x3A1F, 0x00 },
+ { 0x3A20, 0x30 },
+ { 0x3A21, 0x00 },
+ { 0x3A22, 0x13 },
+ { 0x3A23, 0x00 },
+ { 0x3A24, 0x16 },
+ { 0x3A25, 0x01 },
+ { 0x3A26, 0x76 },
+ { 0x3A27, 0x00 },
+ { 0x3A28, 0x42 },
+ { 0x3A29, 0x00 },
+ { 0x3A2A, 0x1A },
+ { 0x3A2B, 0x00 },
+ { 0x3A2C, 0x88 },
+ { 0x3A2D, 0x01 },
+ { 0x3A2E, 0xA7 },
+ { 0x3A2F, 0x00 },
+ { 0x3A30, 0x5D },
+ { 0x3A31, 0x00 },
+ { 0x3A32, 0x24 },
+ { 0x3A33, 0x00 },
+ { 0x3A34, 0x2A },
+ { 0x3A35, 0x02 },
+ { 0x3A36, 0xEB },
+ { 0x3A37, 0x00 },
+ { 0x3A38, 0x83 },
+ { 0x3A39, 0x00 },
+ { 0x3A3A, 0x32 },
+ { 0x3A3B, 0x00 },
+ { 0x3A3C, 0x00 },
+ { 0x3A3D, 0x01 },
+ { 0x3A3E, 0x00 },
+ { 0x3A3F, 0x01 },
+ { 0x3A40, 0x00 },
+ { 0x3A41, 0x01 },
+ { 0x3A42, 0x00 },
+ { 0x3A43, 0x01 },
+ { 0x3A44, 0x80 },
+ { 0x3A45, 0x00 },
+ { 0x3A46, 0x50 },
+ { 0x3A47, 0x00 },
+ { 0x3A48, 0x30 },
+ { 0x3A49, 0x00 },
+ { 0x3A4A, 0x20 },
+ { 0x3A4B, 0x00 },
+ { 0x3A4C, 0x99 },
+ { 0x3A4D, 0x00 },
+ { 0x3A4E, 0x80 },
+ { 0x3A4F, 0x00 },
+ { 0x3A50, 0x80 },
+ { 0x3A51, 0x00 },
+ { 0x3A52, 0x80 },
+ { 0x3A53, 0x00 },
+ { 0x3A54, 0x99 },
+ { 0x3A55, 0x00 },
+ { 0x3A56, 0x80 },
+ { 0x3A57, 0x00 },
+ { 0x3A58, 0x80 },
+ { 0x3A59, 0x00 },
+ { 0x3A5A, 0x80 },
+ { 0x3A5B, 0x00 },
+ { 0x3A5C, 0x99 },
+ { 0x3A5D, 0x00 },
+ { 0x3A5E, 0x80 },
+ { 0x3A5F, 0x00 },
+ { 0x3A60, 0x80 },
+ { 0x3A61, 0x00 },
+ { 0x3A62, 0x80 },
+ { 0x3A63, 0x00 },
+ { 0x3A64, 0x1C },
+ { 0x3A65, 0x00 },
+ { 0x3A66, 0x13 },
+ { 0x3A67, 0x00 },
+ { 0x3A68, 0x0D },
+ { 0x3A69, 0x00 },
+ { 0x3A6A, 0x07 },
+ { 0x3A6B, 0x00 },
+ { 0x3A6C, 0x0C },
+ { 0x3A6D, 0x00 },
+ { 0x3A6E, 0x09 },
+ { 0x3A6F, 0x00 },
+ { 0x3A70, 0x06 },
+ { 0x3A71, 0x00 },
+ { 0x3A72, 0x03 },
+ { 0x3A73, 0x00 },
+ { 0x3A74, 0x1F },
+ { 0x3A75, 0x00 },
+ { 0x3A76, 0x1B },
+ { 0x3A77, 0x00 },
+ { 0x3A78, 0x0F },
+ { 0x3A79, 0x00 },
+ { 0x3A7A, 0x08 },
+ { 0x3A7B, 0x00 },
+ { 0x3A7C, 0x80 },
+ { 0x3A7D, 0x00 },
+ { 0x3A7E, 0x80 },
+ { 0x3A7F, 0x00 },
+ { 0x3A80, 0x80 },
+ { 0x3A81, 0x00 },
+ { 0x3A82, 0x80 },
+ { 0x3A83, 0x00 },
+ { 0x3A84, 0x09 },
+ { 0x3A85, 0x00 },
+ { 0x3A86, 0x04 },
+ { 0x3A87, 0x00 },
+ { 0x3A88, 0x03 },
+ { 0x3A89, 0x00 },
+ { 0x3A8A, 0x01 },
+ { 0x3A8B, 0x00 },
+ { 0x3A8C, 0x19 },
+ { 0x3A8D, 0x01 },
+ { 0x3A8E, 0xD2 },
+ { 0x3A8F, 0x00 },
+ { 0x3A90, 0x8C },
+ { 0x3A91, 0x00 },
+ { 0x3A92, 0x64 },
+ { 0x3A93, 0x00 },
+ { 0x3A94, 0xFF },
+ { 0x3A95, 0x00 },
+ { 0x3A96, 0xD2 },
+ { 0x3A97, 0x00 },
+ { 0x3A98, 0x8C },
+ { 0x3A99, 0x00 },
+ { 0x3A9A, 0x64 },
+ { 0x3A9B, 0x00 },
+ { 0x3A9C, 0x08 },
+ { 0x3A9D, 0x10 },
+ { 0x3A9E, 0x80 },
+ { 0x3A9F, 0x80 },
+ { 0x3AA0, 0x80 },
+ { 0x3AA1, 0x04 },
+ { 0x3AA2, 0x05 },
+ { 0x3AC0, 0x01 },
+ { 0x3AC4, 0x81 },
+ { 0x3AC5, 0x00 },
+ { 0x3AC6, 0x00 },
+ { 0x3AC7, 0x00 },
+ { 0x3AC8, 0x00 },
+ { 0x3AC9, 0x00 },
+ { 0x3ACA, 0x00 },
+ { 0x3ACB, 0x00 },
+ { 0x3ACC, 0x02 },
+ { 0x3ACD, 0x00 },
+ { 0x3ACE, 0x81 },
+ { 0x3ACF, 0x00 },
+ { 0x3AD0, 0x00 },
+ { 0x3AD1, 0x00 },
+ { 0x3AD2, 0xFD },
+ { 0x3AD3, 0x03 },
+ { 0x3AD4, 0x02 },
+ { 0x3AD5, 0x00 },
+ { 0x3AD6, 0x00 },
+ { 0x3AD7, 0x00 },
+ { 0x3AD8, 0x81 },
+ { 0x3AD9, 0x00 },
+ { 0x3ADA, 0xFD },
+ { 0x3ADB, 0x03 },
+ { 0x3ADC, 0xFF },
+ { 0x3ADD, 0x03 },
+ { 0x3ADE, 0x01 },
+ { 0x3ADF, 0x00 },
+ { 0x3AE0, 0x01 },
+ { 0x3AE1, 0x00 },
+ { 0x3AE2, 0x7E },
+ { 0x3AE3, 0x00 },
+ { 0x3AF4, 0x00 },
+ { 0x3AF6, 0x40 },
+ { 0x3AF7, 0x1E },
+ { 0x3AF8, 0x01 },
+ { 0x3AFA, 0x63 },
+ { 0x3AFB, 0x09 },
+ { 0x3AFC, 0x11 },
+ { 0x3AFD, 0x09 },
+ { 0x3AFE, 0x00 },
+ { 0x3AFF, 0x00 },
+ { 0x3B00, 0x00 },
+ { 0x3B01, 0x00 },
+ { 0x3B02, 0x84 },
+ { 0x3B03, 0x06 },
+ { 0x3B04, 0x30 },
+ { 0x3B05, 0x06 },
+ { 0x3B06, 0x00 },
+ { 0x3B07, 0x00 },
+ { 0x3B08, 0x00 },
+ { 0x3B09, 0x00 },
+ { 0x3B0A, 0x00 },
+ { 0x3B0B, 0x00 },
+ { 0x3B0C, 0x00 },
+ { 0x3B0D, 0x00 },
+ { 0x3B0E, 0x00 },
+ { 0x3B0F, 0x00 },
+ { 0x3B10, 0x00 },
+ { 0x3B11, 0x00 },
+ { 0x3B12, 0x00 },
+ { 0x3B13, 0x00 },
+ { 0x3B14, 0x00 },
+ { 0x3B15, 0x00 },
+ { 0x3B16, 0x00 },
+ { 0x3B17, 0x00 },
+ { 0x3B18, 0x00 },
+ { 0x3B19, 0x00 },
+ { 0x3B1A, 0x00 },
+ { 0x3B1B, 0x00 },
+ { 0x3B1C, 0x00 },
+ { 0x3B1D, 0x00 },
+ { 0x3B1E, 0x00 },
+ { 0x3B1F, 0x00 },
+ { 0x3B20, 0x00 },
+ { 0x3B21, 0x00 },
+ { 0x3B22, 0x00 },
+ { 0x3B23, 0x00 },
+ { 0x3B24, 0x00 },
+ { 0x3B25, 0x00 },
+ { 0x3B26, 0x00 },
+ { 0x3B27, 0x00 },
+ { 0x3B28, 0x00 },
+ { 0x3B29, 0x00 },
+ { 0x3B2A, 0x00 },
+ { 0x3B2C, 0x00 },
+ { 0x3B2E, 0x00 },
+ { 0x3B30, 0x00 },
+ { 0x3B32, 0x0C },
+ { 0x4000, 0xD1 },
+ { 0x4001, 0xC0 },
+ { 0x4002, 0xC0 },
+ { 0x4003, 0xB8 },
+ { 0x4004, 0xC0 },
+ { 0x4005, 0xB8 },
+ { 0x4006, 0xB9 },
+ { 0x4007, 0xB7 },
+ { 0x4008, 0xB0 },
+ { 0x4009, 0xAB },
+ { 0x400A, 0xAC },
+ { 0x400B, 0xAB },
+ { 0x400C, 0xA8 },
+ { 0x400D, 0xA6 },
+ { 0x400E, 0xA6 },
+ { 0x400F, 0xA5 },
+ { 0x4010, 0xA2 },
+ { 0x4011, 0xA0 },
+ { 0x4012, 0xA0 },
+ { 0x4013, 0x9F },
+ { 0x4014, 0xA4 },
+ { 0x4015, 0xA2 },
+ { 0x4016, 0xA2 },
+ { 0x4017, 0x9C },
+ { 0x4018, 0xA8 },
+ { 0x4019, 0xA6 },
+ { 0x401A, 0xA8 },
+ { 0x401B, 0xAA },
+ { 0x401C, 0xB0 },
+ { 0x401D, 0xAE },
+ { 0x401E, 0xAE },
+ { 0x401F, 0xAE },
+ { 0x4020, 0xBA },
+ { 0x4021, 0xAE },
+ { 0x4022, 0xAF },
+ { 0x4023, 0xAE },
+ { 0x4024, 0xC6 },
+ { 0x4025, 0xBD },
+ { 0x4026, 0xBD },
+ { 0x4027, 0xBA },
+ { 0x4028, 0xB0 },
+ { 0x4029, 0xA9 },
+ { 0x402A, 0xAA },
+ { 0x402B, 0xA8 },
+ { 0x402C, 0x9F },
+ { 0x402D, 0x9C },
+ { 0x402E, 0x9C },
+ { 0x402F, 0x9B },
+ { 0x4030, 0x93 },
+ { 0x4031, 0x91 },
+ { 0x4032, 0x92 },
+ { 0x4033, 0x91 },
+ { 0x4034, 0x8D },
+ { 0x4035, 0x8C },
+ { 0x4036, 0x8C },
+ { 0x4037, 0x8C },
+ { 0x4038, 0x8F },
+ { 0x4039, 0x8E },
+ { 0x403A, 0x8E },
+ { 0x403B, 0x8E },
+ { 0x403C, 0x98 },
+ { 0x403D, 0x96 },
+ { 0x403E, 0x96 },
+ { 0x403F, 0x95 },
+ { 0x4040, 0xA4 },
+ { 0x4041, 0xA0 },
+ { 0x4042, 0xA0 },
+ { 0x4043, 0x9E },
+ { 0x4044, 0xB3 },
+ { 0x4045, 0xAE },
+ { 0x4046, 0xAF },
+ { 0x4047, 0xAB },
+ { 0x4048, 0xC2 },
+ { 0x4049, 0xB7 },
+ { 0x404A, 0xB8 },
+ { 0x404B, 0xB5 },
+ { 0x404C, 0xAB },
+ { 0x404D, 0xA4 },
+ { 0x404E, 0xA5 },
+ { 0x404F, 0xA3 },
+ { 0x4050, 0x99 },
+ { 0x4051, 0x96 },
+ { 0x4052, 0x96 },
+ { 0x4053, 0x96 },
+ { 0x4054, 0x8B },
+ { 0x4055, 0x8A },
+ { 0x4056, 0x8A },
+ { 0x4057, 0x8A },
+ { 0x4058, 0x82 },
+ { 0x4059, 0x81 },
+ { 0x405A, 0x81 },
+ { 0x405B, 0x81 },
+ { 0x405C, 0x85 },
+ { 0x405D, 0x86 },
+ { 0x405E, 0x85 },
+ { 0x405F, 0x85 },
+ { 0x4060, 0x90 },
+ { 0x4061, 0x90 },
+ { 0x4062, 0x8F },
+ { 0x4063, 0x8F },
+ { 0x4064, 0x9D },
+ { 0x4065, 0x9B },
+ { 0x4066, 0x9B },
+ { 0x4067, 0x9A },
+ { 0x4068, 0xAF },
+ { 0x4069, 0xAA },
+ { 0x406A, 0xAC },
+ { 0x406B, 0xAA },
+ { 0x406C, 0xC2 },
+ { 0x406D, 0xB7 },
+ { 0x406E, 0xB8 },
+ { 0x406F, 0xB5 },
+ { 0x4070, 0xAB },
+ { 0x4071, 0xA4 },
+ { 0x4072, 0xA4 },
+ { 0x4073, 0xA3 },
+ { 0x4074, 0x99 },
+ { 0x4075, 0x96 },
+ { 0x4076, 0x96 },
+ { 0x4077, 0x96 },
+ { 0x4078, 0x8B },
+ { 0x4079, 0x8A },
+ { 0x407A, 0x8A },
+ { 0x407B, 0x8A },
+ { 0x407C, 0x82 },
+ { 0x407D, 0x82 },
+ { 0x407E, 0x82 },
+ { 0x407F, 0x82 },
+ { 0x4080, 0x85 },
+ { 0x4081, 0x86 },
+ { 0x4082, 0x86 },
+ { 0x4083, 0x86 },
+ { 0x4084, 0x90 },
+ { 0x4085, 0x90 },
+ { 0x4086, 0x8F },
+ { 0x4087, 0x8F },
+ { 0x4088, 0x9D },
+ { 0x4089, 0x9B },
+ { 0x408A, 0x9B },
+ { 0x408B, 0x99 },
+ { 0x408C, 0xAE },
+ { 0x408D, 0xAA },
+ { 0x408E, 0xAA },
+ { 0x408F, 0xA7 },
+ { 0x4090, 0xC7 },
+ { 0x4091, 0xBA },
+ { 0x4092, 0xBC },
+ { 0x4093, 0xB9 },
+ { 0x4094, 0xB1 },
+ { 0x4095, 0xA8 },
+ { 0x4096, 0xA8 },
+ { 0x4097, 0xA7 },
+ { 0x4098, 0x9F },
+ { 0x4099, 0x9B },
+ { 0x409A, 0x9B },
+ { 0x409B, 0x9B },
+ { 0x409C, 0x93 },
+ { 0x409D, 0x91 },
+ { 0x409E, 0x91 },
+ { 0x409F, 0x91 },
+ { 0x40A0, 0x8D },
+ { 0x40A1, 0x8C },
+ { 0x40A2, 0x8C },
+ { 0x40A3, 0x8C },
+ { 0x40A4, 0x8E },
+ { 0x40A5, 0x8E },
+ { 0x40A6, 0x8D },
+ { 0x40A7, 0x8D },
+ { 0x40A8, 0x96 },
+ { 0x40A9, 0x95 },
+ { 0x40AA, 0x95 },
+ { 0x40AB, 0x94 },
+ { 0x40AC, 0xA2 },
+ { 0x40AD, 0x9F },
+ { 0x40AE, 0x9F },
+ { 0x40AF, 0x9D },
+ { 0x40B0, 0xB1 },
+ { 0x40B1, 0xAC },
+ { 0x40B2, 0xAB },
+ { 0x40B3, 0xAA },
+ { 0x40B4, 0xD3 },
+ { 0x40B5, 0xBC },
+ { 0x40B6, 0xBD },
+ { 0x40B7, 0xBC },
+ { 0x40B8, 0xC1 },
+ { 0x40B9, 0xB7 },
+ { 0x40BA, 0xB7 },
+ { 0x40BB, 0xB5 },
+ { 0x40BC, 0xB0 },
+ { 0x40BD, 0xAA },
+ { 0x40BE, 0xAA },
+ { 0x40BF, 0xAA },
+ { 0x40C0, 0xA8 },
+ { 0x40C1, 0xA4 },
+ { 0x40C2, 0xA4 },
+ { 0x40C3, 0xA4 },
+ { 0x40C4, 0xA2 },
+ { 0x40C5, 0x9F },
+ { 0x40C6, 0x9F },
+ { 0x40C7, 0x9F },
+ { 0x40C8, 0xA3 },
+ { 0x40C9, 0xA0 },
+ { 0x40CA, 0xA0 },
+ { 0x40CB, 0xA0 },
+ { 0x40CC, 0xA6 },
+ { 0x40CD, 0xA3 },
+ { 0x40CE, 0xA3 },
+ { 0x40CF, 0xA2 },
+ { 0x40D0, 0xAF },
+ { 0x40D1, 0xAB },
+ { 0x40D2, 0xAA },
+ { 0x40D3, 0xA8 },
+ { 0x40D4, 0xBA },
+ { 0x40D5, 0xAE },
+ { 0x40D6, 0xAE },
+ { 0x40D7, 0xAB },
+ { 0x4100, 0xBD },
+ { 0x4101, 0xBA },
+ { 0x4102, 0xBD },
+ { 0x4103, 0xB7 },
+ { 0x4104, 0xB7 },
+ { 0x4105, 0xB7 },
+ { 0x4106, 0xB8 },
+ { 0x4107, 0xB5 },
+ { 0x4108, 0xAB },
+ { 0x4109, 0xAA },
+ { 0x410A, 0xAC },
+ { 0x410B, 0xAB },
+ { 0x410C, 0xA4 },
+ { 0x410D, 0xA5 },
+ { 0x410E, 0xA5 },
+ { 0x410F, 0xA4 },
+ { 0x4110, 0x9F },
+ { 0x4111, 0xA0 },
+ { 0x4112, 0xA0 },
+ { 0x4113, 0x9F },
+ { 0x4114, 0xA0 },
+ { 0x4115, 0xA0 },
+ { 0x4116, 0xA0 },
+ { 0x4117, 0x9F },
+ { 0x4118, 0xA1 },
+ { 0x4119, 0xA1 },
+ { 0x411A, 0xA1 },
+ { 0x411B, 0xA0 },
+ { 0x411C, 0xA7 },
+ { 0x411D, 0xA6 },
+ { 0x411E, 0xA6 },
+ { 0x411F, 0xA6 },
+ { 0x4120, 0xA7 },
+ { 0x4121, 0xA6 },
+ { 0x4122, 0xA6 },
+ { 0x4123, 0xA3 },
+ { 0x4124, 0xB9 },
+ { 0x4125, 0xB9 },
+ { 0x4126, 0xBA },
+ { 0x4127, 0xB8 },
+ { 0x4128, 0xA6 },
+ { 0x4129, 0xA7 },
+ { 0x412A, 0xA7 },
+ { 0x412B, 0xA6 },
+ { 0x412C, 0x9B },
+ { 0x412D, 0x9B },
+ { 0x412E, 0x9B },
+ { 0x412F, 0x9B },
+ { 0x4130, 0x91 },
+ { 0x4131, 0x92 },
+ { 0x4132, 0x92 },
+ { 0x4133, 0x91 },
+ { 0x4134, 0x8C },
+ { 0x4135, 0x8C },
+ { 0x4136, 0x8C },
+ { 0x4137, 0x8C },
+ { 0x4138, 0x8D },
+ { 0x4139, 0x8D },
+ { 0x413A, 0x8D },
+ { 0x413B, 0x8D },
+ { 0x413C, 0x93 },
+ { 0x413D, 0x93 },
+ { 0x413E, 0x93 },
+ { 0x413F, 0x92 },
+ { 0x4140, 0x9A },
+ { 0x4141, 0x9A },
+ { 0x4142, 0x9A },
+ { 0x4143, 0x99 },
+ { 0x4144, 0xA7 },
+ { 0x4145, 0xA5 },
+ { 0x4146, 0xA6 },
+ { 0x4147, 0xA6 },
+ { 0x4148, 0xB8 },
+ { 0x4149, 0xB4 },
+ { 0x414A, 0xB4 },
+ { 0x414B, 0xB3 },
+ { 0x414C, 0xA3 },
+ { 0x414D, 0xA2 },
+ { 0x414E, 0xA3 },
+ { 0x414F, 0xA2 },
+ { 0x4150, 0x96 },
+ { 0x4151, 0x96 },
+ { 0x4152, 0x96 },
+ { 0x4153, 0x96 },
+ { 0x4154, 0x8A },
+ { 0x4155, 0x8A },
+ { 0x4156, 0x8A },
+ { 0x4157, 0x8A },
+ { 0x4158, 0x82 },
+ { 0x4159, 0x82 },
+ { 0x415A, 0x82 },
+ { 0x415B, 0x82 },
+ { 0x415C, 0x84 },
+ { 0x415D, 0x85 },
+ { 0x415E, 0x84 },
+ { 0x415F, 0x84 },
+ { 0x4160, 0x8D },
+ { 0x4161, 0x8D },
+ { 0x4162, 0x8D },
+ { 0x4163, 0x8D },
+ { 0x4164, 0x96 },
+ { 0x4165, 0x96 },
+ { 0x4166, 0x96 },
+ { 0x4167, 0x95 },
+ { 0x4168, 0xA5 },
+ { 0x4169, 0xA2 },
+ { 0x416A, 0xA3 },
+ { 0x416B, 0xA2 },
+ { 0x416C, 0xB7 },
+ { 0x416D, 0xB3 },
+ { 0x416E, 0xB5 },
+ { 0x416F, 0xB4 },
+ { 0x4170, 0xA4 },
+ { 0x4171, 0xA2 },
+ { 0x4172, 0xA3 },
+ { 0x4173, 0xA2 },
+ { 0x4174, 0x97 },
+ { 0x4175, 0x96 },
+ { 0x4176, 0x96 },
+ { 0x4177, 0x96 },
+ { 0x4178, 0x8B },
+ { 0x4179, 0x8A },
+ { 0x417A, 0x8A },
+ { 0x417B, 0x8A },
+ { 0x417C, 0x81 },
+ { 0x417D, 0x81 },
+ { 0x417E, 0x81 },
+ { 0x417F, 0x81 },
+ { 0x4180, 0x84 },
+ { 0x4181, 0x84 },
+ { 0x4182, 0x84 },
+ { 0x4183, 0x84 },
+ { 0x4184, 0x8C },
+ { 0x4185, 0x8D },
+ { 0x4186, 0x8D },
+ { 0x4187, 0x8D },
+ { 0x4188, 0x95 },
+ { 0x4189, 0x96 },
+ { 0x418A, 0x96 },
+ { 0x418B, 0x95 },
+ { 0x418C, 0xA1 },
+ { 0x418D, 0xA1 },
+ { 0x418E, 0xA1 },
+ { 0x418F, 0xA0 },
+ { 0x4190, 0xBC },
+ { 0x4191, 0xB8 },
+ { 0x4192, 0xB8 },
+ { 0x4193, 0xB9 },
+ { 0x4194, 0xA8 },
+ { 0x4195, 0xA5 },
+ { 0x4196, 0xA6 },
+ { 0x4197, 0xA5 },
+ { 0x4198, 0x9C },
+ { 0x4199, 0x9A },
+ { 0x419A, 0x9A },
+ { 0x419B, 0x9A },
+ { 0x419C, 0x91 },
+ { 0x419D, 0x91 },
+ { 0x419E, 0x91 },
+ { 0x419F, 0x91 },
+ { 0x41A0, 0x8B },
+ { 0x41A1, 0x8B },
+ { 0x41A2, 0x8B },
+ { 0x41A3, 0x8B },
+ { 0x41A4, 0x8C },
+ { 0x41A5, 0x8C },
+ { 0x41A6, 0x8C },
+ { 0x41A7, 0x8C },
+ { 0x41A8, 0x91 },
+ { 0x41A9, 0x92 },
+ { 0x41AA, 0x91 },
+ { 0x41AB, 0x91 },
+ { 0x41AC, 0x98 },
+ { 0x41AD, 0x99 },
+ { 0x41AE, 0x99 },
+ { 0x41AF, 0x98 },
+ { 0x41B0, 0xA3 },
+ { 0x41B1, 0xA3 },
+ { 0x41B2, 0xA3 },
+ { 0x41B3, 0xA2 },
+ { 0x41B4, 0xC1 },
+ { 0x41B5, 0xB8 },
+ { 0x41B6, 0xB9 },
+ { 0x41B7, 0xBA },
+ { 0x41B8, 0xB8 },
+ { 0x41B9, 0xB4 },
+ { 0x41BA, 0xB4 },
+ { 0x41BB, 0xB4 },
+ { 0x41BC, 0xAA },
+ { 0x41BD, 0xA7 },
+ { 0x41BE, 0xA7 },
+ { 0x41BF, 0xA8 },
+ { 0x41C0, 0xA4 },
+ { 0x41C1, 0xA2 },
+ { 0x41C2, 0xA2 },
+ { 0x41C3, 0xA3 },
+ { 0x41C4, 0x9E },
+ { 0x41C5, 0x9D },
+ { 0x41C6, 0x9D },
+ { 0x41C7, 0x9D },
+ { 0x41C8, 0x9E },
+ { 0x41C9, 0x9D },
+ { 0x41CA, 0x9D },
+ { 0x41CB, 0x9D },
+ { 0x41CC, 0x9E },
+ { 0x41CD, 0x9E },
+ { 0x41CE, 0x9E },
+ { 0x41CF, 0x9E },
+ { 0x41D0, 0xA3 },
+ { 0x41D1, 0xA3 },
+ { 0x41D2, 0xA2 },
+ { 0x41D3, 0xA1 },
+ { 0x41D4, 0xA7 },
+ { 0x41D5, 0xA7 },
+ { 0x41D6, 0xA7 },
+ { 0x41D7, 0xA3 },
+ { 0x4200, 0xCE },
+ { 0x4201, 0xC0 },
+ { 0x4202, 0xC1 },
+ { 0x4203, 0xB9 },
+ { 0x4204, 0xC3 },
+ { 0x4205, 0xB9 },
+ { 0x4206, 0xBC },
+ { 0x4207, 0xBD },
+ { 0x4208, 0xB3 },
+ { 0x4209, 0xAE },
+ { 0x420A, 0xAF },
+ { 0x420B, 0xAE },
+ { 0x420C, 0xAA },
+ { 0x420D, 0xA8 },
+ { 0x420E, 0xA8 },
+ { 0x420F, 0xA6 },
+ { 0x4210, 0xA4 },
+ { 0x4211, 0xA2 },
+ { 0x4212, 0xA2 },
+ { 0x4213, 0xA0 },
+ { 0x4214, 0xA4 },
+ { 0x4215, 0xA3 },
+ { 0x4216, 0xA2 },
+ { 0x4217, 0xA0 },
+ { 0x4218, 0xA7 },
+ { 0x4219, 0xA5 },
+ { 0x421A, 0xA3 },
+ { 0x421B, 0xA1 },
+ { 0x421C, 0xB0 },
+ { 0x421D, 0xA8 },
+ { 0x421E, 0xA8 },
+ { 0x421F, 0xA6 },
+ { 0x4220, 0xB4 },
+ { 0x4221, 0xAA },
+ { 0x4222, 0xA5 },
+ { 0x4223, 0xA3 },
+ { 0x4224, 0xC7 },
+ { 0x4225, 0xBC },
+ { 0x4226, 0xBE },
+ { 0x4227, 0xBC },
+ { 0x4228, 0xB0 },
+ { 0x4229, 0xA9 },
+ { 0x422A, 0xA9 },
+ { 0x422B, 0xA8 },
+ { 0x422C, 0xA0 },
+ { 0x422D, 0x9D },
+ { 0x422E, 0x9D },
+ { 0x422F, 0x9C },
+ { 0x4230, 0x94 },
+ { 0x4231, 0x93 },
+ { 0x4232, 0x93 },
+ { 0x4233, 0x92 },
+ { 0x4234, 0x8E },
+ { 0x4235, 0x8D },
+ { 0x4236, 0x8D },
+ { 0x4237, 0x8C },
+ { 0x4238, 0x8F },
+ { 0x4239, 0x8E },
+ { 0x423A, 0x8E },
+ { 0x423B, 0x8D },
+ { 0x423C, 0x96 },
+ { 0x423D, 0x94 },
+ { 0x423E, 0x94 },
+ { 0x423F, 0x92 },
+ { 0x4240, 0xA1 },
+ { 0x4241, 0x9C },
+ { 0x4242, 0x9C },
+ { 0x4243, 0x99 },
+ { 0x4244, 0xB0 },
+ { 0x4245, 0xA8 },
+ { 0x4246, 0xAB },
+ { 0x4247, 0xA7 },
+ { 0x4248, 0xC3 },
+ { 0x4249, 0xB7 },
+ { 0x424A, 0xB7 },
+ { 0x424B, 0xBC },
+ { 0x424C, 0xAB },
+ { 0x424D, 0xA4 },
+ { 0x424E, 0xA5 },
+ { 0x424F, 0xA5 },
+ { 0x4250, 0x9A },
+ { 0x4251, 0x97 },
+ { 0x4252, 0x97 },
+ { 0x4253, 0x98 },
+ { 0x4254, 0x8C },
+ { 0x4255, 0x8B },
+ { 0x4256, 0x8B },
+ { 0x4257, 0x8B },
+ { 0x4258, 0x82 },
+ { 0x4259, 0x82 },
+ { 0x425A, 0x82 },
+ { 0x425B, 0x82 },
+ { 0x425C, 0x85 },
+ { 0x425D, 0x85 },
+ { 0x425E, 0x85 },
+ { 0x425F, 0x84 },
+ { 0x4260, 0x8F },
+ { 0x4261, 0x8E },
+ { 0x4262, 0x8E },
+ { 0x4263, 0x8D },
+ { 0x4264, 0x9B },
+ { 0x4265, 0x98 },
+ { 0x4266, 0x98 },
+ { 0x4267, 0x95 },
+ { 0x4268, 0xAE },
+ { 0x4269, 0xA5 },
+ { 0x426A, 0xA7 },
+ { 0x426B, 0xA2 },
+ { 0x426C, 0xC2 },
+ { 0x426D, 0xB7 },
+ { 0x426E, 0xB8 },
+ { 0x426F, 0xB9 },
+ { 0x4270, 0xAA },
+ { 0x4271, 0xA4 },
+ { 0x4272, 0xA4 },
+ { 0x4273, 0xA5 },
+ { 0x4274, 0x99 },
+ { 0x4275, 0x96 },
+ { 0x4276, 0x97 },
+ { 0x4277, 0x98 },
+ { 0x4278, 0x8B },
+ { 0x4279, 0x8A },
+ { 0x427A, 0x8A },
+ { 0x427B, 0x8B },
+ { 0x427C, 0x81 },
+ { 0x427D, 0x81 },
+ { 0x427E, 0x81 },
+ { 0x427F, 0x82 },
+ { 0x4280, 0x84 },
+ { 0x4281, 0x84 },
+ { 0x4282, 0x84 },
+ { 0x4283, 0x84 },
+ { 0x4284, 0x8E },
+ { 0x4285, 0x8E },
+ { 0x4286, 0x8D },
+ { 0x4287, 0x8C },
+ { 0x4288, 0x9A },
+ { 0x4289, 0x97 },
+ { 0x428A, 0x97 },
+ { 0x428B, 0x95 },
+ { 0x428C, 0xAA },
+ { 0x428D, 0xA3 },
+ { 0x428E, 0xA3 },
+ { 0x428F, 0xA2 },
+ { 0x4290, 0xC7 },
+ { 0x4291, 0xBA },
+ { 0x4292, 0xC0 },
+ { 0x4293, 0xC3 },
+ { 0x4294, 0xB0 },
+ { 0x4295, 0xA7 },
+ { 0x4296, 0xA7 },
+ { 0x4297, 0xA9 },
+ { 0x4298, 0x9F },
+ { 0x4299, 0x9B },
+ { 0x429A, 0x9B },
+ { 0x429B, 0x9D },
+ { 0x429C, 0x93 },
+ { 0x429D, 0x91 },
+ { 0x429E, 0x91 },
+ { 0x429F, 0x92 },
+ { 0x42A0, 0x8C },
+ { 0x42A1, 0x8B },
+ { 0x42A2, 0x8B },
+ { 0x42A3, 0x8C },
+ { 0x42A4, 0x8D },
+ { 0x42A5, 0x8C },
+ { 0x42A6, 0x8C },
+ { 0x42A7, 0x8C },
+ { 0x42A8, 0x94 },
+ { 0x42A9, 0x93 },
+ { 0x42AA, 0x92 },
+ { 0x42AB, 0x91 },
+ { 0x42AC, 0x9E },
+ { 0x42AD, 0x9B },
+ { 0x42AE, 0x9B },
+ { 0x42AF, 0x98 },
+ { 0x42B0, 0xAC },
+ { 0x42B1, 0xA6 },
+ { 0x42B2, 0xA6 },
+ { 0x42B3, 0xA2 },
+ { 0x42B4, 0xCE },
+ { 0x42B5, 0xBA },
+ { 0x42B6, 0xBC },
+ { 0x42B7, 0xB7 },
+ { 0x42B8, 0xC5 },
+ { 0x42B9, 0xB5 },
+ { 0x42BA, 0xBA },
+ { 0x42BB, 0xC0 },
+ { 0x42BC, 0xB1 },
+ { 0x42BD, 0xA8 },
+ { 0x42BE, 0xAE },
+ { 0x42BF, 0xAF },
+ { 0x42C0, 0xA7 },
+ { 0x42C1, 0xA3 },
+ { 0x42C2, 0xA3 },
+ { 0x42C3, 0xA5 },
+ { 0x42C4, 0xA0 },
+ { 0x42C5, 0x9D },
+ { 0x42C6, 0x9D },
+ { 0x42C7, 0x9F },
+ { 0x42C8, 0xA0 },
+ { 0x42C9, 0x9E },
+ { 0x42CA, 0x9E },
+ { 0x42CB, 0x9F },
+ { 0x42CC, 0xA2 },
+ { 0x42CD, 0xA0 },
+ { 0x42CE, 0xA0 },
+ { 0x42CF, 0xA0 },
+ { 0x42D0, 0xA8 },
+ { 0x42D1, 0xA5 },
+ { 0x42D2, 0xA5 },
+ { 0x42D3, 0xA2 },
+ { 0x42D4, 0xB3 },
+ { 0x42D5, 0xAA },
+ { 0x42D6, 0xAB },
+ { 0x42D7, 0xA3 },
+ { 0x42D8, 0x00 },
+ { 0x42D9, 0x00 },
+ { 0x4300, 0xA2 },
+ { 0x4301, 0xAE },
+ { 0x4302, 0xAD },
+ { 0x4303, 0xB5 },
+ { 0x4304, 0x95 },
+ { 0x4305, 0x9A },
+ { 0x4306, 0x98 },
+ { 0x4307, 0x9B },
+ { 0x4308, 0x8D },
+ { 0x4309, 0x90 },
+ { 0x430A, 0x8F },
+ { 0x430B, 0x91 },
+ { 0x430C, 0x86 },
+ { 0x430D, 0x88 },
+ { 0x430E, 0x87 },
+ { 0x430F, 0x89 },
+ { 0x4310, 0x86 },
+ { 0x4311, 0x87 },
+ { 0x4312, 0x86 },
+ { 0x4313, 0x88 },
+ { 0x4314, 0x89 },
+ { 0x4315, 0x88 },
+ { 0x4316, 0x88 },
+ { 0x4317, 0x8E },
+ { 0x4318, 0x90 },
+ { 0x4319, 0x8F },
+ { 0x431A, 0x8C },
+ { 0x431B, 0x8C },
+ { 0x431C, 0x9C },
+ { 0x431D, 0x99 },
+ { 0x431E, 0x98 },
+ { 0x431F, 0x99 },
+ { 0x4320, 0xAB },
+ { 0x4321, 0xB0 },
+ { 0x4322, 0xAD },
+ { 0x4323, 0xAF },
+ { 0x4324, 0x9B },
+ { 0x4325, 0x9F },
+ { 0x4326, 0x9E },
+ { 0x4327, 0xA1 },
+ { 0x4328, 0x8E },
+ { 0x4329, 0x91 },
+ { 0x432A, 0x90 },
+ { 0x432B, 0x93 },
+ { 0x432C, 0x86 },
+ { 0x432D, 0x88 },
+ { 0x432E, 0x87 },
+ { 0x432F, 0x89 },
+ { 0x4330, 0x82 },
+ { 0x4331, 0x84 },
+ { 0x4332, 0x83 },
+ { 0x4333, 0x84 },
+ { 0x4334, 0x82 },
+ { 0x4335, 0x82 },
+ { 0x4336, 0x82 },
+ { 0x4337, 0x83 },
+ { 0x4338, 0x85 },
+ { 0x4339, 0x84 },
+ { 0x433A, 0x84 },
+ { 0x433B, 0x85 },
+ { 0x433C, 0x8A },
+ { 0x433D, 0x89 },
+ { 0x433E, 0x88 },
+ { 0x433F, 0x89 },
+ { 0x4340, 0x93 },
+ { 0x4341, 0x91 },
+ { 0x4342, 0x91 },
+ { 0x4343, 0x93 },
+ { 0x4344, 0xA0 },
+ { 0x4345, 0x9E },
+ { 0x4346, 0x9D },
+ { 0x4347, 0xA1 },
+ { 0x4348, 0x95 },
+ { 0x4349, 0x9B },
+ { 0x434A, 0x9A },
+ { 0x434B, 0x9C },
+ { 0x434C, 0x8A },
+ { 0x434D, 0x8D },
+ { 0x434E, 0x8C },
+ { 0x434F, 0x8D },
+ { 0x4350, 0x83 },
+ { 0x4351, 0x85 },
+ { 0x4352, 0x84 },
+ { 0x4353, 0x85 },
+ { 0x4354, 0x80 },
+ { 0x4355, 0x81 },
+ { 0x4356, 0x81 },
+ { 0x4357, 0x81 },
+ { 0x4358, 0x80 },
+ { 0x4359, 0x80 },
+ { 0x435A, 0x80 },
+ { 0x435B, 0x80 },
+ { 0x435C, 0x82 },
+ { 0x435D, 0x81 },
+ { 0x435E, 0x81 },
+ { 0x435F, 0x81 },
+ { 0x4360, 0x85 },
+ { 0x4361, 0x84 },
+ { 0x4362, 0x84 },
+ { 0x4363, 0x85 },
+ { 0x4364, 0x8D },
+ { 0x4365, 0x8B },
+ { 0x4366, 0x8B },
+ { 0x4367, 0x8D },
+ { 0x4368, 0x98 },
+ { 0x4369, 0x98 },
+ { 0x436A, 0x95 },
+ { 0x436B, 0x98 },
+ { 0x436C, 0x95 },
+ { 0x436D, 0x9A },
+ { 0x436E, 0x99 },
+ { 0x436F, 0x9A },
+ { 0x4370, 0x8A },
+ { 0x4371, 0x8D },
+ { 0x4372, 0x8C },
+ { 0x4373, 0x8C },
+ { 0x4374, 0x83 },
+ { 0x4375, 0x85 },
+ { 0x4376, 0x84 },
+ { 0x4377, 0x84 },
+ { 0x4378, 0x80 },
+ { 0x4379, 0x80 },
+ { 0x437A, 0x80 },
+ { 0x437B, 0x80 },
+ { 0x437C, 0x7F },
+ { 0x437D, 0x7F },
+ { 0x437E, 0x7F },
+ { 0x437F, 0x7F },
+ { 0x4380, 0x81 },
+ { 0x4381, 0x80 },
+ { 0x4382, 0x80 },
+ { 0x4383, 0x81 },
+ { 0x4384, 0x84 },
+ { 0x4385, 0x83 },
+ { 0x4386, 0x83 },
+ { 0x4387, 0x84 },
+ { 0x4388, 0x8B },
+ { 0x4389, 0x8A },
+ { 0x438A, 0x8A },
+ { 0x438B, 0x8C },
+ { 0x438C, 0x97 },
+ { 0x438D, 0x96 },
+ { 0x438E, 0x96 },
+ { 0x438F, 0x99 },
+ { 0x4390, 0x99 },
+ { 0x4391, 0x9F },
+ { 0x4392, 0x9E },
+ { 0x4393, 0x9D },
+ { 0x4394, 0x8D },
+ { 0x4395, 0x90 },
+ { 0x4396, 0x90 },
+ { 0x4397, 0x8F },
+ { 0x4398, 0x85 },
+ { 0x4399, 0x87 },
+ { 0x439A, 0x87 },
+ { 0x439B, 0x86 },
+ { 0x439C, 0x81 },
+ { 0x439D, 0x83 },
+ { 0x439E, 0x82 },
+ { 0x439F, 0x82 },
+ { 0x43A0, 0x80 },
+ { 0x43A1, 0x81 },
+ { 0x43A2, 0x81 },
+ { 0x43A3, 0x81 },
+ { 0x43A4, 0x82 },
+ { 0x43A5, 0x82 },
+ { 0x43A6, 0x82 },
+ { 0x43A7, 0x82 },
+ { 0x43A8, 0x86 },
+ { 0x43A9, 0x85 },
+ { 0x43AA, 0x85 },
+ { 0x43AB, 0x87 },
+ { 0x43AC, 0x8D },
+ { 0x43AD, 0x8D },
+ { 0x43AE, 0x8D },
+ { 0x43AF, 0x90 },
+ { 0x43B0, 0x9A },
+ { 0x43B1, 0x9A },
+ { 0x43B2, 0x9B },
+ { 0x43B3, 0x9D },
+ { 0x43B4, 0xA0 },
+ { 0x43B5, 0xAD },
+ { 0x43B6, 0xAC },
+ { 0x43B7, 0xAA },
+ { 0x43B8, 0x93 },
+ { 0x43B9, 0x97 },
+ { 0x43BA, 0x97 },
+ { 0x43BB, 0x96 },
+ { 0x43BC, 0x8B },
+ { 0x43BD, 0x8E },
+ { 0x43BE, 0x8E },
+ { 0x43BF, 0x8C },
+ { 0x43C0, 0x83 },
+ { 0x43C1, 0x85 },
+ { 0x43C2, 0x85 },
+ { 0x43C3, 0x84 },
+ { 0x43C4, 0x82 },
+ { 0x43C5, 0x84 },
+ { 0x43C6, 0x83 },
+ { 0x43C7, 0x83 },
+ { 0x43C8, 0x83 },
+ { 0x43C9, 0x84 },
+ { 0x43CA, 0x84 },
+ { 0x43CB, 0x85 },
+ { 0x43CC, 0x8A },
+ { 0x43CD, 0x8A },
+ { 0x43CE, 0x8A },
+ { 0x43CF, 0x8C },
+ { 0x43D0, 0x92 },
+ { 0x43D1, 0x93 },
+ { 0x43D2, 0x93 },
+ { 0x43D3, 0x96 },
+ { 0x43D4, 0x9F },
+ { 0x43D5, 0xA6 },
+ { 0x43D6, 0xA5 },
+ { 0x43D7, 0xAA },
+ { 0x4400, 0xA1 },
+ { 0x4401, 0xAB },
+ { 0x4402, 0xA7 },
+ { 0x4403, 0xB0 },
+ { 0x4404, 0x91 },
+ { 0x4405, 0x96 },
+ { 0x4406, 0x94 },
+ { 0x4407, 0x99 },
+ { 0x4408, 0x8A },
+ { 0x4409, 0x8E },
+ { 0x440A, 0x8C },
+ { 0x440B, 0x8F },
+ { 0x440C, 0x85 },
+ { 0x440D, 0x86 },
+ { 0x440E, 0x86 },
+ { 0x440F, 0x88 },
+ { 0x4410, 0x85 },
+ { 0x4411, 0x86 },
+ { 0x4412, 0x85 },
+ { 0x4413, 0x87 },
+ { 0x4414, 0x88 },
+ { 0x4415, 0x87 },
+ { 0x4416, 0x87 },
+ { 0x4417, 0x89 },
+ { 0x4418, 0x91 },
+ { 0x4419, 0x8F },
+ { 0x441A, 0x8F },
+ { 0x441B, 0x90 },
+ { 0x441C, 0x9C },
+ { 0x441D, 0x9B },
+ { 0x441E, 0x9A },
+ { 0x441F, 0x9A },
+ { 0x4420, 0xB3 },
+ { 0x4421, 0xB1 },
+ { 0x4422, 0xB0 },
+ { 0x4423, 0xB2 },
+ { 0x4424, 0x96 },
+ { 0x4425, 0x9C },
+ { 0x4426, 0x9A },
+ { 0x4427, 0x9E },
+ { 0x4428, 0x8B },
+ { 0x4429, 0x8F },
+ { 0x442A, 0x8E },
+ { 0x442B, 0x91 },
+ { 0x442C, 0x84 },
+ { 0x442D, 0x87 },
+ { 0x442E, 0x86 },
+ { 0x442F, 0x88 },
+ { 0x4430, 0x82 },
+ { 0x4431, 0x83 },
+ { 0x4432, 0x82 },
+ { 0x4433, 0x84 },
+ { 0x4434, 0x82 },
+ { 0x4435, 0x82 },
+ { 0x4436, 0x82 },
+ { 0x4437, 0x83 },
+ { 0x4438, 0x84 },
+ { 0x4439, 0x84 },
+ { 0x443A, 0x84 },
+ { 0x443B, 0x84 },
+ { 0x443C, 0x8B },
+ { 0x443D, 0x89 },
+ { 0x443E, 0x89 },
+ { 0x443F, 0x89 },
+ { 0x4440, 0x95 },
+ { 0x4441, 0x93 },
+ { 0x4442, 0x93 },
+ { 0x4443, 0x93 },
+ { 0x4444, 0xA2 },
+ { 0x4445, 0xA2 },
+ { 0x4446, 0xA1 },
+ { 0x4447, 0xA0 },
+ { 0x4448, 0x8F },
+ { 0x4449, 0x97 },
+ { 0x444A, 0x97 },
+ { 0x444B, 0x98 },
+ { 0x444C, 0x87 },
+ { 0x444D, 0x8B },
+ { 0x444E, 0x8A },
+ { 0x444F, 0x8B },
+ { 0x4450, 0x81 },
+ { 0x4451, 0x83 },
+ { 0x4452, 0x83 },
+ { 0x4453, 0x84 },
+ { 0x4454, 0x7F },
+ { 0x4455, 0x80 },
+ { 0x4456, 0x80 },
+ { 0x4457, 0x81 },
+ { 0x4458, 0x80 },
+ { 0x4459, 0x80 },
+ { 0x445A, 0x80 },
+ { 0x445B, 0x80 },
+ { 0x445C, 0x82 },
+ { 0x445D, 0x81 },
+ { 0x445E, 0x81 },
+ { 0x445F, 0x81 },
+ { 0x4460, 0x87 },
+ { 0x4461, 0x85 },
+ { 0x4462, 0x85 },
+ { 0x4463, 0x86 },
+ { 0x4464, 0x90 },
+ { 0x4465, 0x8E },
+ { 0x4466, 0x8E },
+ { 0x4467, 0x8E },
+ { 0x4468, 0x9B },
+ { 0x4469, 0x9C },
+ { 0x446A, 0x9A },
+ { 0x446B, 0x9A },
+ { 0x446C, 0x91 },
+ { 0x446D, 0x97 },
+ { 0x446E, 0x95 },
+ { 0x446F, 0x95 },
+ { 0x4470, 0x87 },
+ { 0x4471, 0x8A },
+ { 0x4472, 0x8A },
+ { 0x4473, 0x89 },
+ { 0x4474, 0x81 },
+ { 0x4475, 0x83 },
+ { 0x4476, 0x83 },
+ { 0x4477, 0x83 },
+ { 0x4478, 0x7F },
+ { 0x4479, 0x80 },
+ { 0x447A, 0x80 },
+ { 0x447B, 0x80 },
+ { 0x447C, 0x80 },
+ { 0x447D, 0x80 },
+ { 0x447E, 0x80 },
+ { 0x447F, 0x7F },
+ { 0x4480, 0x81 },
+ { 0x4481, 0x81 },
+ { 0x4482, 0x81 },
+ { 0x4483, 0x81 },
+ { 0x4484, 0x85 },
+ { 0x4485, 0x85 },
+ { 0x4486, 0x85 },
+ { 0x4487, 0x85 },
+ { 0x4488, 0x8E },
+ { 0x4489, 0x8D },
+ { 0x448A, 0x8D },
+ { 0x448B, 0x8E },
+ { 0x448C, 0x9D },
+ { 0x448D, 0x9C },
+ { 0x448E, 0x9C },
+ { 0x448F, 0x9C },
+ { 0x4490, 0x94 },
+ { 0x4491, 0x9B },
+ { 0x4492, 0x9A },
+ { 0x4493, 0x97 },
+ { 0x4494, 0x8A },
+ { 0x4495, 0x8E },
+ { 0x4496, 0x8E },
+ { 0x4497, 0x8C },
+ { 0x4498, 0x84 },
+ { 0x4499, 0x86 },
+ { 0x449A, 0x86 },
+ { 0x449B, 0x84 },
+ { 0x449C, 0x81 },
+ { 0x449D, 0x83 },
+ { 0x449E, 0x83 },
+ { 0x449F, 0x81 },
+ { 0x44A0, 0x81 },
+ { 0x44A1, 0x82 },
+ { 0x44A2, 0x82 },
+ { 0x44A3, 0x81 },
+ { 0x44A4, 0x83 },
+ { 0x44A5, 0x83 },
+ { 0x44A6, 0x83 },
+ { 0x44A7, 0x83 },
+ { 0x44A8, 0x88 },
+ { 0x44A9, 0x88 },
+ { 0x44AA, 0x88 },
+ { 0x44AB, 0x88 },
+ { 0x44AC, 0x91 },
+ { 0x44AD, 0x91 },
+ { 0x44AE, 0x91 },
+ { 0x44AF, 0x92 },
+ { 0x44B0, 0xA0 },
+ { 0x44B1, 0xA0 },
+ { 0x44B2, 0xA0 },
+ { 0x44B3, 0xA0 },
+ { 0x44B4, 0x9E },
+ { 0x44B5, 0xA9 },
+ { 0x44B6, 0xA8 },
+ { 0x44B7, 0xA3 },
+ { 0x44B8, 0x90 },
+ { 0x44B9, 0x95 },
+ { 0x44BA, 0x95 },
+ { 0x44BB, 0x92 },
+ { 0x44BC, 0x8A },
+ { 0x44BD, 0x8E },
+ { 0x44BE, 0x8E },
+ { 0x44BF, 0x8B },
+ { 0x44C0, 0x84 },
+ { 0x44C1, 0x86 },
+ { 0x44C2, 0x86 },
+ { 0x44C3, 0x84 },
+ { 0x44C4, 0x84 },
+ { 0x44C5, 0x85 },
+ { 0x44C6, 0x85 },
+ { 0x44C7, 0x84 },
+ { 0x44C8, 0x86 },
+ { 0x44C9, 0x87 },
+ { 0x44CA, 0x87 },
+ { 0x44CB, 0x86 },
+ { 0x44CC, 0x8D },
+ { 0x44CD, 0x8E },
+ { 0x44CE, 0x8E },
+ { 0x44CF, 0x8D },
+ { 0x44D0, 0x98 },
+ { 0x44D1, 0x98 },
+ { 0x44D2, 0x99 },
+ { 0x44D3, 0x9A },
+ { 0x44D4, 0xA9 },
+ { 0x44D5, 0xAA },
+ { 0x44D6, 0xAA },
+ { 0x44D7, 0xAD },
+ { 0x4500, 0x9F },
+ { 0x4501, 0xA8 },
+ { 0x4502, 0xA5 },
+ { 0x4503, 0xAF },
+ { 0x4504, 0x8F },
+ { 0x4505, 0x96 },
+ { 0x4506, 0x92 },
+ { 0x4507, 0x94 },
+ { 0x4508, 0x89 },
+ { 0x4509, 0x8D },
+ { 0x450A, 0x8A },
+ { 0x450B, 0x8E },
+ { 0x450C, 0x84 },
+ { 0x450D, 0x85 },
+ { 0x450E, 0x84 },
+ { 0x450F, 0x87 },
+ { 0x4510, 0x84 },
+ { 0x4511, 0x85 },
+ { 0x4512, 0x84 },
+ { 0x4513, 0x86 },
+ { 0x4514, 0x87 },
+ { 0x4515, 0x86 },
+ { 0x4516, 0x86 },
+ { 0x4517, 0x88 },
+ { 0x4518, 0x8F },
+ { 0x4519, 0x8D },
+ { 0x451A, 0x8D },
+ { 0x451B, 0x8F },
+ { 0x451C, 0x9A },
+ { 0x451D, 0x9A },
+ { 0x451E, 0x98 },
+ { 0x451F, 0x9A },
+ { 0x4520, 0xAF },
+ { 0x4521, 0xAF },
+ { 0x4522, 0xB2 },
+ { 0x4523, 0xB1 },
+ { 0x4524, 0x95 },
+ { 0x4525, 0x9B },
+ { 0x4526, 0x97 },
+ { 0x4527, 0x9C },
+ { 0x4528, 0x8A },
+ { 0x4529, 0x8E },
+ { 0x452A, 0x8D },
+ { 0x452B, 0x90 },
+ { 0x452C, 0x84 },
+ { 0x452D, 0x86 },
+ { 0x452E, 0x85 },
+ { 0x452F, 0x87 },
+ { 0x4530, 0x81 },
+ { 0x4531, 0x82 },
+ { 0x4532, 0x82 },
+ { 0x4533, 0x83 },
+ { 0x4534, 0x81 },
+ { 0x4535, 0x81 },
+ { 0x4536, 0x81 },
+ { 0x4537, 0x82 },
+ { 0x4538, 0x84 },
+ { 0x4539, 0x83 },
+ { 0x453A, 0x83 },
+ { 0x453B, 0x84 },
+ { 0x453C, 0x8A },
+ { 0x453D, 0x88 },
+ { 0x453E, 0x88 },
+ { 0x453F, 0x89 },
+ { 0x4540, 0x94 },
+ { 0x4541, 0x92 },
+ { 0x4542, 0x91 },
+ { 0x4543, 0x92 },
+ { 0x4544, 0xA1 },
+ { 0x4545, 0xA0 },
+ { 0x4546, 0x9C },
+ { 0x4547, 0x9D },
+ { 0x4548, 0x8F },
+ { 0x4549, 0x96 },
+ { 0x454A, 0x95 },
+ { 0x454B, 0x92 },
+ { 0x454C, 0x87 },
+ { 0x454D, 0x8A },
+ { 0x454E, 0x89 },
+ { 0x454F, 0x8A },
+ { 0x4550, 0x81 },
+ { 0x4551, 0x83 },
+ { 0x4552, 0x82 },
+ { 0x4553, 0x83 },
+ { 0x4554, 0x7F },
+ { 0x4555, 0x80 },
+ { 0x4556, 0x80 },
+ { 0x4557, 0x81 },
+ { 0x4558, 0x7F },
+ { 0x4559, 0x80 },
+ { 0x455A, 0x7F },
+ { 0x455B, 0x80 },
+ { 0x455C, 0x81 },
+ { 0x455D, 0x81 },
+ { 0x455E, 0x81 },
+ { 0x455F, 0x81 },
+ { 0x4560, 0x86 },
+ { 0x4561, 0x85 },
+ { 0x4562, 0x85 },
+ { 0x4563, 0x85 },
+ { 0x4564, 0x8F },
+ { 0x4565, 0x8D },
+ { 0x4566, 0x8D },
+ { 0x4567, 0x8D },
+ { 0x4568, 0x99 },
+ { 0x4569, 0x9A },
+ { 0x456A, 0x97 },
+ { 0x456B, 0x99 },
+ { 0x456C, 0x90 },
+ { 0x456D, 0x95 },
+ { 0x456E, 0x93 },
+ { 0x456F, 0x92 },
+ { 0x4570, 0x87 },
+ { 0x4571, 0x8A },
+ { 0x4572, 0x88 },
+ { 0x4573, 0x87 },
+ { 0x4574, 0x81 },
+ { 0x4575, 0x83 },
+ { 0x4576, 0x82 },
+ { 0x4577, 0x82 },
+ { 0x4578, 0x7F },
+ { 0x4579, 0x80 },
+ { 0x457A, 0x80 },
+ { 0x457B, 0x80 },
+ { 0x457C, 0x80 },
+ { 0x457D, 0x80 },
+ { 0x457E, 0x80 },
+ { 0x457F, 0x80 },
+ { 0x4580, 0x81 },
+ { 0x4581, 0x81 },
+ { 0x4582, 0x81 },
+ { 0x4583, 0x81 },
+ { 0x4584, 0x85 },
+ { 0x4585, 0x85 },
+ { 0x4586, 0x84 },
+ { 0x4587, 0x85 },
+ { 0x4588, 0x8E },
+ { 0x4589, 0x8D },
+ { 0x458A, 0x8C },
+ { 0x458B, 0x8D },
+ { 0x458C, 0x9B },
+ { 0x458D, 0x9B },
+ { 0x458E, 0x9A },
+ { 0x458F, 0x98 },
+ { 0x4590, 0x94 },
+ { 0x4591, 0x9A },
+ { 0x4592, 0x94 },
+ { 0x4593, 0x90 },
+ { 0x4594, 0x8A },
+ { 0x4595, 0x8D },
+ { 0x4596, 0x8C },
+ { 0x4597, 0x89 },
+ { 0x4598, 0x84 },
+ { 0x4599, 0x86 },
+ { 0x459A, 0x85 },
+ { 0x459B, 0x83 },
+ { 0x459C, 0x82 },
+ { 0x459D, 0x83 },
+ { 0x459E, 0x82 },
+ { 0x459F, 0x80 },
+ { 0x45A0, 0x81 },
+ { 0x45A1, 0x82 },
+ { 0x45A2, 0x81 },
+ { 0x45A3, 0x80 },
+ { 0x45A4, 0x83 },
+ { 0x45A5, 0x83 },
+ { 0x45A6, 0x83 },
+ { 0x45A7, 0x83 },
+ { 0x45A8, 0x88 },
+ { 0x45A9, 0x87 },
+ { 0x45AA, 0x87 },
+ { 0x45AB, 0x88 },
+ { 0x45AC, 0x91 },
+ { 0x45AD, 0x90 },
+ { 0x45AE, 0x90 },
+ { 0x45AF, 0x91 },
+ { 0x45B0, 0x9F },
+ { 0x45B1, 0x9F },
+ { 0x45B2, 0x9E },
+ { 0x45B3, 0x9F },
+ { 0x45B4, 0x9F },
+ { 0x45B5, 0xA8 },
+ { 0x45B6, 0xA6 },
+ { 0x45B7, 0xA7 },
+ { 0x45B8, 0x8D },
+ { 0x45B9, 0x95 },
+ { 0x45BA, 0x90 },
+ { 0x45BB, 0x8A },
+ { 0x45BC, 0x89 },
+ { 0x45BD, 0x8D },
+ { 0x45BE, 0x88 },
+ { 0x45BF, 0x86 },
+ { 0x45C0, 0x84 },
+ { 0x45C1, 0x86 },
+ { 0x45C2, 0x85 },
+ { 0x45C3, 0x82 },
+ { 0x45C4, 0x84 },
+ { 0x45C5, 0x85 },
+ { 0x45C6, 0x85 },
+ { 0x45C7, 0x83 },
+ { 0x45C8, 0x86 },
+ { 0x45C9, 0x86 },
+ { 0x45CA, 0x86 },
+ { 0x45CB, 0x85 },
+ { 0x45CC, 0x8E },
+ { 0x45CD, 0x8D },
+ { 0x45CE, 0x8D },
+ { 0x45CF, 0x8C },
+ { 0x45D0, 0x99 },
+ { 0x45D1, 0x98 },
+ { 0x45D2, 0x98 },
+ { 0x45D3, 0x98 },
+ { 0x45D4, 0xA6 },
+ { 0x45D5, 0xA9 },
+ { 0x45D6, 0xA7 },
+ { 0x45D7, 0xAC },
+};
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 155898d3d7ad..2f66395989ff 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -120,6 +120,54 @@ static const struct csi2rx_fmt formats[] = {
.code = MEDIA_BUS_FMT_VYUY8_2X8,
.bpp = 16,
},
+ {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .bpp = 8,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .bpp = 8,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .bpp = 8,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .bpp = 8,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .bpp = 10,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .bpp = 12,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .bpp = 12,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .bpp = 12,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .bpp = 12,
+ },
};
static u8 csi2rx_get_bpp(u32 code)
@@ -231,7 +279,6 @@ static int csi2rx_configure_external_dphy(struct csi2rx_priv *csi2rx)
struct phy_configure_opts_mipi_dphy *cfg = &opts.mipi_dphy;
s64 link_freq;
int ret;
- bool got_pm = true;
link_freq = csi2rx_get_link_freq(csi2rx);
if (link_freq < 0)
@@ -245,9 +292,7 @@ static int csi2rx_configure_external_dphy(struct csi2rx_priv *csi2rx)
cfg->lanes = csi2rx->num_lanes;
ret = phy_pm_runtime_get_sync(csi2rx->dphy);
- if (ret == -ENOTSUPP)
- got_pm = false;
- else if (ret)
+ if (ret < 0 && ret != -ENOTSUPP)
return ret;
ret = phy_set_mode_ext(csi2rx->dphy, PHY_MODE_MIPI_DPHY,
@@ -267,9 +312,7 @@ static int csi2rx_configure_external_dphy(struct csi2rx_priv *csi2rx)
}
out:
- if (got_pm)
- phy_pm_runtime_put(csi2rx->dphy);
-
+ phy_pm_runtime_put(csi2rx->dphy);
return ret;
}
@@ -307,10 +350,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx)
writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG);
- ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true);
- if (ret)
- goto err_disable_pclk;
-
/* Enable DPHY clk and data lanes. */
if (csi2rx->dphy) {
reg = CSI2RX_DPHY_CL_EN | CSI2RX_DPHY_CL_RST;
@@ -320,6 +359,13 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx)
}
writel(reg, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG);
+
+ ret = csi2rx_configure_external_dphy(csi2rx);
+ if (ret) {
+ dev_err(csi2rx->dev,
+ "Failed to configure external DPHY: %d\n", ret);
+ goto err_disable_pclk;
+ }
}
/*
@@ -352,14 +398,9 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx)
if (ret)
goto err_disable_pixclk;
- if (csi2rx->dphy) {
- ret = csi2rx_configure_external_dphy(csi2rx);
- if (ret) {
- dev_err(csi2rx->dev,
- "Failed to configure external DPHY: %d\n", ret);
- goto err_disable_sysclk;
- }
- }
+ ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true);
+ if (ret)
+ goto err_disable_sysclk;
clk_disable_unprepare(csi2rx->p_clk);
@@ -371,6 +412,10 @@ err_disable_pixclk:
for (; i > 0; i--)
clk_disable_unprepare(csi2rx->pixel_clk[i - 1]);
+ if (csi2rx->dphy) {
+ phy_power_off(csi2rx->dphy);
+ phy_pm_runtime_put(csi2rx->dphy);
+ }
err_disable_pclk:
clk_disable_unprepare(csi2rx->p_clk);
@@ -411,6 +456,8 @@ static void csi2rx_stop(struct csi2rx_priv *csi2rx)
if (phy_power_off(csi2rx->dphy))
dev_warn(csi2rx->dev, "Couldn't power off DPHY\n");
+
+ phy_pm_runtime_put(csi2rx->dphy);
}
}
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 021c003026c7..32563cffbf05 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -251,6 +251,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
{
struct v4l2_subdev *sd = vin_to_source(vin);
struct v4l2_subdev_state *sd_state;
+ static struct lock_class_key key;
struct v4l2_subdev_format format = {
.which = which,
.pad = vin->parallel->source_pad,
@@ -259,9 +260,9 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
u32 width, height;
int ret;
- sd_state = v4l2_subdev_alloc_state(sd);
- if (sd_state == NULL)
- return -ENOMEM;
+ sd_state = __v4l2_subdev_state_alloc(sd, "rvin:state->lock", &key);
+ if (IS_ERR(sd_state))
+ return PTR_ERR(sd_state);
if (!rvin_format_from_pixel(vin, pix->pixelformat))
pix->pixelformat = RVIN_DEFAULT_FORMAT;
@@ -295,7 +296,7 @@ static int rvin_try_format(struct rvin_dev *vin, u32 which,
rvin_format_align(vin, pix);
done:
- v4l2_subdev_free_state(sd_state);
+ __v4l2_subdev_state_free(sd_state);
return ret;
}
diff --git a/drivers/media/platform/ti/cal/cal-camerarx.c b/drivers/media/platform/ti/cal/cal-camerarx.c
index ae8ae046a512..3ccd06d37924 100644
--- a/drivers/media/platform/ti/cal/cal-camerarx.c
+++ b/drivers/media/platform/ti/cal/cal-camerarx.c
@@ -49,34 +49,48 @@ static s64 cal_camerarx_get_ext_link_freq(struct cal_camerarx *phy)
{
struct v4l2_fwnode_bus_mipi_csi2 *mipi_csi2 = &phy->endpoint.bus.mipi_csi2;
u32 num_lanes = mipi_csi2->num_data_lanes;
+ struct v4l2_subdev_state *state;
u32 bpp;
s64 freq;
/*
- * With multistream input we don't have bpp, and cannot use
- * V4L2_CID_PIXEL_RATE. Passing 0 as bpp causes v4l2_get_link_freq()
- * to return an error if it falls back to V4L2_CID_PIXEL_RATE.
+ * v4l2_get_link_freq() uses V4L2_CID_LINK_FREQ first, and falls back
+ * to V4L2_CID_PIXEL_RATE if V4L2_CID_LINK_FREQ is not available.
+ *
+ * With multistream input there is no single pixel rate, and thus we
+ * cannot use V4L2_CID_PIXEL_RATE, so we pass 0 as the bpp which
+ * causes v4l2_get_link_freq() to return an error if it falls back to
+ * V4L2_CID_PIXEL_RATE.
*/
- if (phy->stream_configs.num_configs == 0)
+ state = v4l2_subdev_lock_active_state(&phy->subdev);
+
+ if (state->routing.num_routes == 0) {
+ v4l2_subdev_unlock_state(state);
return -EINVAL;
+ }
- if (phy->stream_configs.num_configs > 2) {
+ if (state->routing.num_routes > 1) {
bpp = 0;
} else {
const struct cal_format_info *fmtinfo;
+ struct v4l2_subdev_route *route = &state->routing.routes[0];
struct v4l2_mbus_framefmt *fmt;
- /* The first format is for the sink */
- fmt = &phy->stream_configs.configs[0].fmt;
+ fmt = v4l2_state_get_stream_format(state, route->sink_pad,
+ route->sink_stream);
fmtinfo = cal_format_by_code(fmt->code);
- if (!fmtinfo)
+ if (!fmtinfo) {
+ v4l2_subdev_unlock_state(state);
return -EINVAL;
+ }
bpp = fmtinfo->bpp;
}
+ v4l2_subdev_unlock_state(state);
+
freq = v4l2_get_link_freq(phy->source->ctrl_handler, bpp, 2 * num_lanes);
if (freq < 0) {
phy_err(phy, "failed to get link freq for subdev '%s'\n",
@@ -602,25 +616,26 @@ done:
}
int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy,
- struct v4l2_mbus_frame_desc *fd)
+ struct v4l2_mbus_frame_desc *desc)
{
struct media_pad *pad;
int ret;
if (!phy->source)
- return -ENODEV;
+ return -EPIPE;
pad = media_entity_remote_pad(&phy->pads[CAL_CAMERARX_PAD_SINK]);
if (!pad)
- return -ENODEV;
+ return -EPIPE;
ret = v4l2_subdev_call(phy->source, pad, get_frame_desc, pad->index,
- fd);
+ desc);
if (ret)
return ret;
- if (fd->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
- dev_err(phy->cal->dev, "Frame desc do not describe CSI-2 link");
+ if (desc->type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ dev_err(phy->cal->dev,
+ "Frame descriptor does not describe CSI-2 link");
return -EINVAL;
}
@@ -649,142 +664,52 @@ cal_camerarx_get_phy_from_entity(struct media_entity *entity)
return to_cal_camerarx(sd);
}
-static struct v4l2_subdev_krouting *
-cal_camerarx_get_routing_table(struct cal_camerarx *phy,
- struct v4l2_subdev_state *cfg, u32 which)
-{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &phy->routing;
- else
- return &cfg->routing;
-}
-
-static struct v4l2_subdev_stream_configs *
-cal_camerarx_get_stream_configs(struct cal_camerarx *phy,
- struct v4l2_subdev_state *cfg, u32 which)
-{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &phy->stream_configs;
- else
- return &cfg->stream_configs;
-}
-
-struct v4l2_mbus_framefmt *
-cal_camerarx_get_stream_format(struct cal_camerarx *phy,
- struct v4l2_subdev_state *cfg,
- unsigned int pad, u32 stream, u32 which)
-{
- struct v4l2_subdev_stream_configs *stream_configs;
- unsigned int i;
-
- stream_configs = cal_camerarx_get_stream_configs(phy, cfg, which);
-
- for (i = 0; i < stream_configs->num_configs; ++i) {
- if (stream_configs->configs[i].pad == pad &&
- stream_configs->configs[i].stream == stream)
- return &stream_configs->configs[i].fmt;
- }
-
- return NULL;
-}
-
-static int cal_camerarx_find_opposite_end(struct v4l2_subdev_krouting *routing,
- u32 pad, u32 stream, u32 *other_pad,
- u32 *other_stream)
-{
- unsigned int i;
-
- for (i = 0; i < routing->num_routes; ++i) {
- struct v4l2_subdev_route *route = &routing->routes[i];
-
- if (cal_rx_pad_is_source(pad)) {
- if (route->source_pad == pad &&
- route->source_stream == stream) {
- *other_pad = route->sink_pad;
- *other_stream = route->sink_stream;
- return 0;
- }
- } else {
- if (route->sink_pad == pad &&
- route->sink_stream == stream) {
- *other_pad = route->source_pad;
- *other_stream = route->source_stream;
- return 0;
- }
- }
- }
-
- return -EINVAL;
-}
-
-static struct v4l2_mbus_framefmt *
-cal_camerarx_get_opposite_stream_format(struct cal_camerarx *phy,
- struct v4l2_subdev_state *cfg,
- u32 pad, u32 stream, u32 which)
-{
- struct v4l2_subdev_krouting *routing;
- u32 other_pad, other_stream;
- int ret;
-
- routing = cal_camerarx_get_routing_table(phy, cfg, which);
-
- ret = cal_camerarx_find_opposite_end(routing, pad, stream, &other_pad,
- &other_stream);
- if (ret)
- return NULL;
-
- return cal_camerarx_get_stream_format(phy, cfg, other_pad,
- other_stream, which);
-}
-
static int cal_camerarx_sd_s_stream(struct v4l2_subdev *sd, int enable)
{
struct cal_camerarx *phy = to_cal_camerarx(sd);
- int r = 0;
+ int ret = 0;
mutex_lock(&phy->mutex);
if (enable)
- r = cal_camerarx_start(phy);
+ ret = cal_camerarx_start(phy);
else
cal_camerarx_stop(phy);
mutex_unlock(&phy->mutex);
- return r;
+ return ret;
}
static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_mbus_code_enum *code)
{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
- int r = 0;
+ int ret = 0;
- mutex_lock(&phy->mutex);
+ v4l2_subdev_lock_state(state);
/* No transcoding, source and sink codes must match. */
if (cal_rx_pad_is_source(code->pad)) {
struct v4l2_mbus_framefmt *fmt;
if (code->index > 0) {
- r = -EINVAL;
+ ret = -EINVAL;
goto out;
}
- fmt = cal_camerarx_get_opposite_stream_format(phy, sd_state,
- code->pad, code->stream,
- code->which);
+ fmt = v4l2_state_get_opposite_stream_format(state, code->pad,
+ code->stream);
if (!fmt) {
- r = -EINVAL;
+ ret = -EINVAL;
goto out;
}
code->code = fmt->code;
} else {
if (code->index >= cal_num_formats) {
- r = -EINVAL;
+ ret = -EINVAL;
goto out;
}
@@ -792,38 +717,37 @@ static int cal_camerarx_sd_enum_mbus_code(struct v4l2_subdev *sd,
}
out:
- mutex_unlock(&phy->mutex);
+ v4l2_subdev_unlock_state(state);
- return r;
+ return ret;
}
static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_frame_size_enum *fse)
{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
const struct cal_format_info *fmtinfo;
- int r = 0;
+ int ret = 0;
if (fse->index > 0)
return -EINVAL;
- mutex_lock(&phy->mutex);
+ v4l2_subdev_lock_state(state);
/* No transcoding, source and sink formats must match. */
if (cal_rx_pad_is_source(fse->pad)) {
struct v4l2_mbus_framefmt *fmt;
- fmt = cal_camerarx_get_opposite_stream_format(
- phy, sd_state, fse->pad, fse->stream, fse->which);
+ fmt = v4l2_state_get_opposite_stream_format(state, fse->pad,
+ fse->stream);
if (!fmt) {
- r = -EINVAL;
+ ret = -EINVAL;
goto out;
}
if (fse->code != fmt->code) {
- r = -EINVAL;
+ ret = -EINVAL;
goto out;
}
@@ -834,53 +758,26 @@ static int cal_camerarx_sd_enum_frame_size(struct v4l2_subdev *sd,
} else {
fmtinfo = cal_format_by_code(fse->code);
if (!fmtinfo) {
- r = -EINVAL;
+ ret = -EINVAL;
goto out;
}
- fse->min_width =
- CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
- fse->max_width =
- CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
+ fse->min_width = CAL_MIN_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
+ fse->max_width = CAL_MAX_WIDTH_BYTES * 8 / ALIGN(fmtinfo->bpp, 8);
fse->min_height = CAL_MIN_HEIGHT_LINES;
fse->max_height = CAL_MAX_HEIGHT_LINES;
}
out:
- mutex_unlock(&phy->mutex);
-
- return r;
-}
+ v4l2_subdev_unlock_state(state);
-static int cal_camerarx_sd_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
- struct v4l2_mbus_framefmt *fmt;
-
- mutex_lock(&phy->mutex);
-
- fmt = cal_camerarx_get_stream_format(phy, sd_state, format->pad,
- format->stream, format->which);
-
- if (!fmt) {
- mutex_unlock(&phy->mutex);
- return -EINVAL;
- }
-
- format->format = *fmt;
-
- mutex_unlock(&phy->mutex);
-
- return 0;
+ return ret;
}
static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
const struct cal_format_info *fmtinfo;
struct v4l2_mbus_framefmt *fmt;
unsigned int bpp;
@@ -888,7 +785,7 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
/* No transcoding, source and sink formats must match. */
if (cal_rx_pad_is_source(format->pad))
- return cal_camerarx_sd_get_fmt(sd, sd_state, format);
+ return v4l2_subdev_get_fmt(sd, state, format);
/*
* Default to the first format if the requested media bus code isn't
@@ -912,10 +809,10 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
/* Store the format and propagate it to the source pad. */
- mutex_lock(&phy->mutex);
+ v4l2_subdev_lock_state(state);
- fmt = cal_camerarx_get_stream_format(phy, sd_state, format->pad,
- format->stream, format->which);
+ fmt = v4l2_state_get_stream_format(state, format->pad,
+ format->stream);
if (!fmt) {
ret = -EINVAL;
goto out;
@@ -923,9 +820,8 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
*fmt = format->format;
- fmt = cal_camerarx_get_opposite_stream_format(phy, sd_state, format->pad,
- format->stream,
- format->which);
+ fmt = v4l2_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
if (!fmt) {
ret = -EINVAL;
goto out;
@@ -934,29 +830,15 @@ static int cal_camerarx_sd_set_fmt(struct v4l2_subdev *sd,
*fmt = format->format;
out:
- mutex_unlock(&phy->mutex);
+ v4l2_subdev_unlock_state(state);
return ret;
}
-static int cal_camerarx_sd_get_routing(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *cfg,
+static int _cal_camerarx_sd_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_krouting *routing)
{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
- struct v4l2_subdev_krouting *src;
-
- src = cal_camerarx_get_routing_table(phy, cfg, routing->which);
-
- return v4l2_subdev_cpy_routing(routing, src);
-}
-
-static void cal_camerarx_init_formats(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *cfg,
- u32 which)
-{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
-
static const struct v4l2_mbus_framefmt format = {
.width = 640,
.height = 480,
@@ -967,48 +849,37 @@ static void cal_camerarx_init_formats(struct v4l2_subdev *sd,
.quantization = V4L2_QUANTIZATION_LIM_RANGE,
.xfer_func = V4L2_XFER_FUNC_SRGB,
};
+ int ret;
- struct v4l2_subdev_stream_configs *stream_configs;
- unsigned int i;
-
- stream_configs = cal_camerarx_get_stream_configs(phy, cfg, which);
+ ret = v4l2_routing_simple_verify(routing);
+ if (ret)
+ return ret;
- for (i = 0; i < stream_configs->num_configs; ++i)
- stream_configs->configs[i].fmt = format;
-}
+ /* TODO: verify that all streams from a single RX port go to a single TX port */
-static int cal_camerarx_sd_set_routing(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *cfg,
- struct v4l2_subdev_krouting *routing)
-{
- struct cal_camerarx *phy = to_cal_camerarx(sd);
- int ret;
- struct v4l2_subdev_krouting *dst;
- struct v4l2_subdev_stream_configs *stream_configs;
+ v4l2_subdev_lock_state(state);
- dst = cal_camerarx_get_routing_table(phy, cfg, routing->which);
- stream_configs =
- cal_camerarx_get_stream_configs(phy, cfg, routing->which);
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
- ret = v4l2_subdev_dup_routing(dst, routing);
- if (ret)
- return ret;
+ v4l2_subdev_unlock_state(state);
- ret = v4l2_init_stream_configs(stream_configs, dst);
if (ret)
return ret;
- /* Initialize stream formats */
- cal_camerarx_init_formats(sd, cfg, routing->which);
-
return 0;
}
-static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+static int cal_camerarx_sd_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
{
- u32 which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ return _cal_camerarx_sd_set_routing(sd, state, routing);
+}
+static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
struct v4l2_subdev_route routes[] = { {
.sink_pad = 0,
.sink_stream = 0,
@@ -1018,13 +889,12 @@ static int cal_camerarx_sd_init_cfg(struct v4l2_subdev *sd,
} };
struct v4l2_subdev_krouting routing = {
- .which = which,
.num_routes = 1,
.routes = routes,
};
/* Initialize routing to single route to the fist source pad */
- return cal_camerarx_sd_set_routing(sd, sd_state, &routing);
+ return _cal_camerarx_sd_set_routing(sd, state, &routing);
}
static const struct v4l2_subdev_video_ops cal_camerarx_video_ops = {
@@ -1035,9 +905,8 @@ static const struct v4l2_subdev_pad_ops cal_camerarx_pad_ops = {
.init_cfg = cal_camerarx_sd_init_cfg,
.enum_mbus_code = cal_camerarx_sd_enum_mbus_code,
.enum_frame_size = cal_camerarx_sd_enum_frame_size,
- .get_fmt = cal_camerarx_sd_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = cal_camerarx_sd_set_fmt,
- .get_routing = cal_camerarx_sd_get_routing,
.set_routing = cal_camerarx_sd_set_routing,
};
@@ -1046,18 +915,9 @@ static const struct v4l2_subdev_ops cal_camerarx_subdev_ops = {
.pad = &cal_camerarx_pad_ops,
};
-static bool cal_camerarx_has_route(struct media_entity *entity, unsigned int pad0,
- unsigned int pad1)
-{
- struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
- struct cal_camerarx *phy = to_cal_camerarx(sd);
-
- return v4l2_subdev_has_route(&phy->routing, pad0, pad1);
-}
-
static struct media_entity_operations cal_camerarx_media_ops = {
.link_validate = v4l2_subdev_link_validate,
- .has_route = cal_camerarx_has_route,
+ .has_route = v4l2_subdev_has_route,
};
/* ------------------------------------------------------------------
@@ -1071,8 +931,8 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
struct platform_device *pdev = to_platform_device(cal->dev);
struct cal_camerarx *phy;
struct v4l2_subdev *sd;
- int ret;
unsigned int i;
+ int ret;
phy = kzalloc(sizeof(*phy), GFP_KERNEL);
if (!phy)
@@ -1081,6 +941,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
phy->cal = cal;
phy->instance = instance;
+ spin_lock_init(&phy->vc_lock);
mutex_init(&phy->mutex);
phy->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
@@ -1091,7 +952,7 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
if (IS_ERR(phy->base)) {
cal_err(cal, "failed to ioremap\n");
ret = PTR_ERR(phy->base);
- goto error;
+ goto err_free_phy;
}
cal_dbg(1, cal, "ioresource %s at %pa - %pa\n",
@@ -1099,11 +960,11 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
ret = cal_camerarx_regmap_init(cal, phy);
if (ret)
- goto error;
+ goto err_free_phy;
ret = cal_camerarx_parse_dt(phy);
if (ret)
- goto error;
+ goto err_free_phy;
/* Initialize the V4L2 subdev and media entity. */
sd = &phy->subdev;
@@ -1121,22 +982,23 @@ struct cal_camerarx *cal_camerarx_create(struct cal_dev *cal,
ret = media_entity_pads_init(&sd->entity, ARRAY_SIZE(phy->pads),
phy->pads);
if (ret)
- goto error;
+ goto err_free_phy;
- ret = cal_camerarx_sd_init_cfg(sd, NULL);
+ ret = v4l2_subdev_init_finalize(sd);
if (ret)
- goto error;
+ goto err_entity_cleanup;
ret = v4l2_device_register_subdev(&cal->v4l2_dev, sd);
if (ret)
- goto error;
+ goto err_free_state;
return phy;
-error:
- v4l2_subdev_free_routing(&phy->routing);
- v4l2_uninit_stream_configs(&phy->stream_configs);
+err_free_state:
+ v4l2_subdev_cleanup(sd);
+err_entity_cleanup:
media_entity_cleanup(&phy->subdev.entity);
+err_free_phy:
kfree(phy);
return ERR_PTR(ret);
}
@@ -1147,10 +1009,12 @@ void cal_camerarx_destroy(struct cal_camerarx *phy)
return;
v4l2_device_unregister_subdev(&phy->subdev);
- v4l2_subdev_free_routing(&phy->routing);
- v4l2_uninit_stream_configs(&phy->stream_configs);
+
+ v4l2_subdev_cleanup(&phy->subdev);
+
media_entity_cleanup(&phy->subdev.entity);
of_node_put(phy->source_ep_node);
of_node_put(phy->source_node);
+ mutex_destroy(&phy->mutex);
kfree(phy);
}
diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c
index 3b0e5c421904..963e0bf3436d 100644
--- a/drivers/media/platform/ti/cal/cal-video.c
+++ b/drivers/media/platform/ti/cal/cal-video.c
@@ -123,12 +123,13 @@ static int __subdev_get_format(struct cal_ctx *ctx,
{
struct v4l2_subdev_format sd_fmt;
struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+ struct v4l2_subdev *sd = ctx->phy->source;
int ret;
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_fmt.pad = 0;
- ret = v4l2_subdev_call(ctx->phy->source, pad, get_fmt, NULL, &sd_fmt);
+ ret = v4l2_subdev_call(sd, pad, get_fmt, NULL, &sd_fmt);
if (ret)
return ret;
@@ -145,13 +146,14 @@ static int __subdev_set_format(struct cal_ctx *ctx,
{
struct v4l2_subdev_format sd_fmt;
struct v4l2_mbus_framefmt *mbus_fmt = &sd_fmt.format;
+ struct v4l2_subdev *sd = ctx->phy->source;
int ret;
sd_fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
sd_fmt.pad = 0;
*mbus_fmt = *fmt;
- ret = v4l2_subdev_call(ctx->phy->source, pad, set_fmt, NULL, &sd_fmt);
+ ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &sd_fmt);
if (ret)
return ret;
@@ -193,9 +195,10 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cal_ctx *ctx = video_drvdata(file);
+ struct v4l2_subdev *sd = ctx->phy->source;
const struct cal_format_info *fmtinfo;
struct v4l2_subdev_frame_size_enum fse;
- int ret, found;
+ int found;
fmtinfo = find_format_by_pix(ctx, f->fmt.pix.pixelformat);
if (!fmtinfo) {
@@ -210,13 +213,14 @@ static int cal_legacy_try_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.field = ctx->v_fmt.fmt.pix.field;
/* check for/find a valid width/height */
- ret = 0;
found = false;
fse.pad = 0;
fse.code = fmtinfo->code;
fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
for (fse.index = 0; ; fse.index++) {
- ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size,
+ int ret;
+
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size,
NULL, &fse);
if (ret)
break;
@@ -253,6 +257,7 @@ static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cal_ctx *ctx = video_drvdata(file);
+ struct v4l2_subdev *sd = &ctx->phy->subdev;
struct vb2_queue *q = &ctx->vb_vidq;
struct v4l2_subdev_format sd_fmt = {
.which = V4L2_SUBDEV_FORMAT_ACTIVE,
@@ -292,7 +297,8 @@ static int cal_legacy_s_fmt_vid_cap(struct file *file, void *priv,
ctx->v_fmt.fmt.pix.field = sd_fmt.format.field;
cal_calc_format_size(ctx, fmtinfo, &ctx->v_fmt);
- v4l2_subdev_call(&ctx->phy->subdev, pad, set_fmt, NULL, &sd_fmt);
+ v4l2_subdev_call(sd, pad, set_fmt, v4l2_subdev_get_active_state(sd),
+ &sd_fmt);
ctx->fmtinfo = fmtinfo;
*f = ctx->v_fmt;
@@ -304,6 +310,7 @@ static int cal_legacy_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
struct cal_ctx *ctx = video_drvdata(file);
+ struct v4l2_subdev *sd = ctx->phy->source;
const struct cal_format_info *fmtinfo;
struct v4l2_subdev_frame_size_enum fse;
int ret;
@@ -321,8 +328,8 @@ static int cal_legacy_enum_framesizes(struct file *file, void *fh,
fse.code = fmtinfo->code;
fse.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_size, NULL,
- &fse);
+ ret = v4l2_subdev_call(sd, pad, enum_frame_size,
+ v4l2_subdev_get_active_state(sd), &fse);
if (ret)
return ret;
@@ -364,6 +371,7 @@ static int cal_legacy_enum_frameintervals(struct file *file, void *priv,
struct v4l2_frmivalenum *fival)
{
struct cal_ctx *ctx = video_drvdata(file);
+ struct v4l2_subdev *sd = ctx->phy->source;
const struct cal_format_info *fmtinfo;
struct v4l2_subdev_frame_interval_enum fie = {
.index = fival->index,
@@ -378,8 +386,10 @@ static int cal_legacy_enum_frameintervals(struct file *file, void *priv,
return -EINVAL;
fie.code = fmtinfo->code;
- ret = v4l2_subdev_call(ctx->phy->source, pad, enum_frame_interval,
- NULL, &fie);
+
+ ret = v4l2_subdev_call(sd, pad, enum_frame_interval,
+ v4l2_subdev_get_active_state(sd), &fie);
+
if (ret)
return ret;
fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
@@ -688,24 +698,34 @@ static int cal_video_check_format(struct cal_ctx *ctx)
{
const struct v4l2_mbus_framefmt *format;
struct media_pad *remote_pad;
+ struct v4l2_subdev_state *state;
+ int ret = 0;
remote_pad = media_entity_remote_pad(&ctx->pad);
if (!remote_pad)
return -ENODEV;
- format = cal_camerarx_get_stream_format(ctx->phy, NULL,
- remote_pad->index, 0,
- V4L2_SUBDEV_FORMAT_ACTIVE);
- if (!format)
- return -EINVAL;
+ state = v4l2_subdev_lock_active_state(&ctx->phy->subdev);
+
+ format = v4l2_state_get_stream_format(state,
+ remote_pad->index, 0);
+ if (!format) {
+ ret = -EINVAL;
+ goto out;
+ }
if (ctx->fmtinfo->code != format->code ||
ctx->v_fmt.fmt.pix.height != format->height ||
ctx->v_fmt.fmt.pix.width != format->width ||
- ctx->v_fmt.fmt.pix.field != format->field)
- return -EPIPE;
+ ctx->v_fmt.fmt.pix.field != format->field) {
+ ret = -EPIPE;
+ goto out;
+ }
- return 0;
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
}
static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
@@ -719,6 +739,7 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
struct v4l2_subdev_route *route = NULL;
struct media_pad *remote_pad;
unsigned int i;
+ struct v4l2_subdev_state *state;
/* Find the PHY connected to this video device */
@@ -731,11 +752,13 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
ctx->phy = cal_camerarx_get_phy_from_entity(remote_pad->entity);
+ state = v4l2_subdev_lock_active_state(&ctx->phy->subdev);
+
/* Find the stream */
- for (i = 0; i < ctx->phy->routing.num_routes; ++i) {
+ for (i = 0; i < state->routing.num_routes; ++i) {
struct v4l2_subdev_route *r =
- &ctx->phy->routing.routes[i];
+ &state->routing.routes[i];
if (!(r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
continue;
@@ -749,12 +772,15 @@ static int cal_start_streaming(struct vb2_queue *vq, unsigned int count)
}
if (!route) {
+ v4l2_subdev_unlock_state(state);
ctx_err(ctx, "Failed to find route\n");
ret = -ENODEV;
goto error_release_buffers;
}
ctx->stream = route->sink_stream;
+
+ v4l2_subdev_unlock_state(state);
}
ret = media_pipeline_start(ctx->vdev.entity.pads, &ctx->phy->pipe);
@@ -868,6 +894,7 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
const struct cal_format_info *fmtinfo;
unsigned int i, j, k;
int ret = 0;
+ struct v4l2_subdev *sd = ctx->phy->source;
/* Enumerate sub device formats and enable all matching local formats */
ctx->active_fmt = devm_kcalloc(ctx->cal->dev, cal_num_formats,
@@ -879,20 +906,20 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
memset(&mbus_code, 0, sizeof(mbus_code));
mbus_code.index = j;
mbus_code.which = V4L2_SUBDEV_FORMAT_ACTIVE;
- ret = v4l2_subdev_call(ctx->phy->source, pad, enum_mbus_code,
+ ret = v4l2_subdev_call(sd, pad, enum_mbus_code,
NULL, &mbus_code);
if (ret == -EINVAL)
break;
if (ret) {
ctx_err(ctx, "Error enumerating mbus codes in subdev %s: %d\n",
- ctx->phy->source->name, ret);
+ sd->name, ret);
return ret;
}
ctx_dbg(2, ctx,
"subdev %s: code: %04x idx: %u\n",
- ctx->phy->source->name, mbus_code.code, j);
+ sd->name, mbus_code.code, j);
for (k = 0; k < cal_num_formats; k++) {
fmtinfo = &cal_formats[k];
@@ -910,7 +937,7 @@ static int cal_ctx_v4l2_init_formats(struct cal_ctx *ctx)
if (i == 0) {
ctx_err(ctx, "No suitable format reported by subdev %s\n",
- ctx->phy->source->name);
+ sd->name);
return -EINVAL;
}
@@ -1002,11 +1029,13 @@ int cal_ctx_v4l2_register(struct cal_ctx *ctx)
/* Create links from all video nodes to all PHYs */
- for (phy_idx = 0; phy_idx < ctx->cal->data->num_csi2_phy; ++phy_idx) {
- for (pad_idx = 1; pad_idx < CAL_CAMERARX_NUM_PADS; ++pad_idx) {
+ for (phy_idx = 0; phy_idx < ctx->cal->data->num_csi2_phy;
+ ++phy_idx) {
+ for (pad_idx = 1; pad_idx < CAL_CAMERARX_NUM_PADS;
+ ++pad_idx) {
/*
- * Enable only links from video0 to PHY0 pad 1, and
- * video1 to PHY1 pad 1.
+ * Enable only links from video0 to PHY0 pad 1,
+ * and video1 to PHY1 pad 1.
*/
bool enable = (ctx->dma_ctx == 0 &&
phy_idx == 0 && pad_idx == 1) ||
diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
index 69a7ed9667c4..0399ac9f57d6 100644
--- a/drivers/media/platform/ti/cal/cal.c
+++ b/drivers/media/platform/ti/cal/cal.c
@@ -492,6 +492,10 @@ cal_get_remote_frame_desc_entry(struct cal_camerarx *phy, u32 stream,
}
}
+ dev_err(phy->cal->dev,
+ "Failed to find stream %u from remote frame descriptor\n",
+ stream);
+
return -ENODEV;
}
@@ -507,15 +511,12 @@ int cal_ctx_prepare(struct cal_ctx *ctx)
ctx->datatype = CAL_CSI2_CTX_DT_ANY;
} else if (!ret) {
ctx_dbg(2, ctx, "Framedesc: stream %u, len %u, vc %u, dt %#x\n",
- entry.stream,
- entry.length,
- entry.bus.csi2.vc,
- entry.bus.csi2.dt);
+ entry.stream, entry.length, entry.bus.csi2.vc,
+ entry.bus.csi2.dt);
ctx->vc = entry.bus.csi2.vc;
ctx->datatype = entry.bus.csi2.dt;
} else {
- ctx_err(ctx, "Failed to get remote frame desc: %d\n", ret);
return ret;
}
@@ -542,6 +543,22 @@ void cal_ctx_unprepare(struct cal_ctx *ctx)
void cal_ctx_start(struct cal_ctx *ctx)
{
+ struct cal_camerarx *phy = ctx->phy;
+
+ /*
+ * Reset the frame number & sequence number, but only if the
+ * virtual channel is not already in use.
+ */
+
+ spin_lock(&phy->vc_lock);
+
+ if (phy->vc_enable_count[ctx->vc]++ == 0) {
+ phy->vc_frame_number[ctx->vc] = 0;
+ phy->vc_sequence[ctx->vc] = 0;
+ }
+
+ spin_unlock(&phy->vc_lock);
+
ctx->dma.state = CAL_DMA_RUNNING;
/* Configure the CSI-2, pixel processing and write DMA contexts. */
@@ -561,8 +578,15 @@ void cal_ctx_start(struct cal_ctx *ctx)
void cal_ctx_stop(struct cal_ctx *ctx)
{
+ struct cal_camerarx *phy = ctx->phy;
long timeout;
+ WARN_ON(phy->vc_enable_count[ctx->vc] == 0);
+
+ spin_lock(&phy->vc_lock);
+ phy->vc_enable_count[ctx->vc]--;
+ spin_unlock(&phy->vc_lock);
+
/*
* Request DMA stop and wait until it completes. If completion times
* out, forcefully disable the DMA.
@@ -599,6 +623,32 @@ void cal_ctx_stop(struct cal_ctx *ctx)
* ------------------------------------------------------------------
*/
+/*
+ * Track a sequence number for each virtual channel, which is shared by
+ * all contexts using the same virtual channel. This is done using the
+ * CSI-2 frame number as a base.
+ */
+static void cal_update_seq_number(struct cal_ctx *ctx)
+{
+ struct cal_dev *cal = ctx->cal;
+ struct cal_camerarx *phy = ctx->phy;
+ u32 prev_frame_num, frame_num;
+ u8 vc = ctx->vc;
+
+ frame_num = cal_read(cal, CAL_CSI2_STATUS(phy->instance, ctx->csi2_ctx));
+ frame_num &= 0xffff;
+
+ if (phy->vc_frame_number[vc] != frame_num) {
+ prev_frame_num = phy->vc_frame_number[vc];
+
+ if (prev_frame_num > frame_num)
+ prev_frame_num = 0;
+
+ phy->vc_sequence[vc] += frame_num - prev_frame_num;
+ phy->vc_frame_number[vc] = frame_num;
+ }
+}
+
static inline void cal_irq_wdma_start(struct cal_ctx *ctx)
{
spin_lock(&ctx->dma.lock);
@@ -629,15 +679,13 @@ static inline void cal_irq_wdma_start(struct cal_ctx *ctx)
}
spin_unlock(&ctx->dma.lock);
+
+ cal_update_seq_number(ctx);
}
static inline void cal_irq_wdma_end(struct cal_ctx *ctx)
{
struct cal_buffer *buf = NULL;
- u32 frame_num;
-
- frame_num = cal_read(ctx->cal, CAL_CSI2_STATUS(ctx->phy->instance,
- ctx->csi2_ctx)) & 0xffff;
spin_lock(&ctx->dma.lock);
@@ -659,27 +707,62 @@ static inline void cal_irq_wdma_end(struct cal_ctx *ctx)
if (buf) {
buf->vb.vb2_buf.timestamp = ktime_get_ns();
buf->vb.field = ctx->v_fmt.fmt.pix.field;
- buf->vb.sequence = frame_num;
+ buf->vb.sequence = ctx->phy->vc_sequence[ctx->vc];
+
vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
}
}
+static void cal_irq_handle_wdma(struct cal_ctx *ctx, bool start, bool end)
+{
+ /*
+ * CAL HW interrupts are inherently racy. If we get both start and end
+ * interrupts, we don't know what has happened: did the DMA for a single
+ * frame start and end, or did one frame end and a new frame start?
+ *
+ * Usually for normal pixel frames we get the interrupts separately. If
+ * we do get both, we have to guess. The assumption in the code below is
+ * that the active vertical area is larger than the blanking vertical
+ * area, and thus it is more likely that we get the end of the old frame
+ * and the start of a new frame.
+ *
+ * However, for embedded data, which is only a few lines high, we always
+ * get both interrupts. Here the assumption is that we get both for the
+ * same frame.
+ */
+ if (ctx->v_fmt.fmt.pix.height < 10) {
+ if (start)
+ cal_irq_wdma_start(ctx);
+
+ if (end)
+ cal_irq_wdma_end(ctx);
+ } else {
+ if (end)
+ cal_irq_wdma_end(ctx);
+
+ if (start)
+ cal_irq_wdma_start(ctx);
+ }
+}
+
static irqreturn_t cal_irq(int irq_cal, void *data)
{
struct cal_dev *cal = data;
- u32 status;
-
- status = cal_read(cal, CAL_HL_IRQSTATUS(0));
- if (status) {
- unsigned int i;
+ u32 status[3];
+ unsigned int i;
- cal_write(cal, CAL_HL_IRQSTATUS(0), status);
+ for (i = 0; i < 3; ++i) {
+ status[i] = cal_read(cal, CAL_HL_IRQSTATUS(i));
+ if (status[i])
+ cal_write(cal, CAL_HL_IRQSTATUS(i), status[i]);
+ }
- if (status & CAL_HL_IRQ_OCPO_ERR_MASK)
+ if (status[0]) {
+ if (status[0] & CAL_HL_IRQ_OCPO_ERR_MASK)
dev_err_ratelimited(cal->dev, "OCPO ERROR\n");
for (i = 0; i < cal->data->num_csi2_phy; ++i) {
- if (status & CAL_HL_IRQ_CIO_MASK(i)) {
+ if (status[0] & CAL_HL_IRQ_CIO_MASK(i)) {
u32 cio_stat = cal_read(cal,
CAL_CSI2_COMPLEXIO_IRQSTATUS(i));
@@ -690,7 +773,7 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
cio_stat);
}
- if (status & CAL_HL_IRQ_VC_MASK(i)) {
+ if (status[0] & CAL_HL_IRQ_VC_MASK(i)) {
u32 vc_stat = cal_read(cal, CAL_CSI2_VC_IRQSTATUS(i));
dev_err_ratelimited(cal->dev,
@@ -702,32 +785,12 @@ static irqreturn_t cal_irq(int irq_cal, void *data)
}
}
- /* Check which DMA just finished */
- status = cal_read(cal, CAL_HL_IRQSTATUS(1));
- if (status) {
- unsigned int i;
-
- /* Clear Interrupt status */
- cal_write(cal, CAL_HL_IRQSTATUS(1), status);
-
- for (i = 0; i < cal->num_contexts; ++i) {
- if (status & CAL_HL_IRQ_WDMA_END_MASK(i))
- cal_irq_wdma_end(cal->ctx[i]);
- }
- }
-
- /* Check which DMA just started */
- status = cal_read(cal, CAL_HL_IRQSTATUS(2));
- if (status) {
- unsigned int i;
-
- /* Clear Interrupt status */
- cal_write(cal, CAL_HL_IRQSTATUS(2), status);
+ for (i = 0; i < cal->num_contexts; ++i) {
+ bool end = !!(status[1] & CAL_HL_IRQ_WDMA_END_MASK(i));
+ bool start = !!(status[2] & CAL_HL_IRQ_WDMA_START_MASK(i));
- for (i = 0; i < cal->num_contexts; ++i) {
- if (status & CAL_HL_IRQ_WDMA_START_MASK(i))
- cal_irq_wdma_start(cal->ctx[i]);
- }
+ if (start || end)
+ cal_irq_handle_wdma(cal->ctx[i], start, end);
}
return IRQ_HANDLED;
@@ -792,16 +855,30 @@ static int cal_async_notifier_complete(struct v4l2_async_notifier *notifier)
{
struct cal_dev *cal = container_of(notifier, struct cal_dev, notifier);
unsigned int i;
- int ret = 0;
+ int ret;
for (i = 0; i < cal->num_contexts; ++i) {
ret = cal_ctx_v4l2_register(cal->ctx[i]);
if (ret)
- return ret;
+ goto err_ctx_unreg;
}
- if (cal_mc_api)
- ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev);
+ if (!cal_mc_api)
+ return 0;
+
+ ret = v4l2_device_register_subdev_nodes(&cal->v4l2_dev);
+ if (ret)
+ goto err_ctx_unreg;
+
+ return 0;
+
+err_ctx_unreg:
+ for (; i > 0; --i) {
+ if (!cal->ctx[i - 1])
+ continue;
+
+ cal_ctx_v4l2_unregister(cal->ctx[i - 1]);
+ }
return ret;
}
@@ -1184,14 +1261,14 @@ static int cal_probe(struct platform_device *pdev)
if (!cal->phy[i]->source_node)
continue;
- cal->ctx[i] = cal_ctx_create(cal, i);
- if (!cal->ctx[i]) {
- cal_err(cal, "Failed to create context %u\n", i);
+ cal->ctx[cal->num_contexts] = cal_ctx_create(cal, i);
+ if (!cal->ctx[cal->num_contexts]) {
+ cal_err(cal, "Failed to create context %u\n", cal->num_contexts);
ret = -ENODEV;
goto error_context;
}
- cal->ctx[i]->phy = cal->phy[i];
+ cal->ctx[cal->num_contexts]->phy = cal->phy[i];
cal->num_contexts++;
}
diff --git a/drivers/media/platform/ti/cal/cal.h b/drivers/media/platform/ti/cal/cal.h
index 6626c2a59fc2..444f0de591ac 100644
--- a/drivers/media/platform/ti/cal/cal.h
+++ b/drivers/media/platform/ti/cal/cal.h
@@ -179,13 +179,21 @@ struct cal_camerarx {
struct v4l2_subdev subdev;
struct media_pad pads[CAL_CAMERARX_NUM_PADS];
- /* mutex for camerarx ops */
+ /* protects the vc_* fields below */
+ spinlock_t vc_lock;
+ u8 vc_enable_count[4];
+ u8 vc_frame_number[4];
+ u32 vc_sequence[4];
+
+ /*
+ * Lock for camerarx ops. Protects:
+ * - routing
+ * - stream_configs
+ * - enable_count
+ */
struct mutex mutex;
- unsigned int enable_count;
-
- struct v4l2_subdev_krouting routing;
- struct v4l2_subdev_stream_configs stream_configs;
+ unsigned int enable_count;
};
struct cal_dev {
@@ -322,7 +330,7 @@ const struct cal_format_info *cal_format_by_code(u32 code);
void cal_quickdump_regs(struct cal_dev *cal);
int cal_camerarx_get_remote_frame_desc(struct cal_camerarx *phy,
- struct v4l2_mbus_frame_desc *fd);
+ struct v4l2_mbus_frame_desc *desc);
struct cal_camerarx *cal_camerarx_get_phy_from_entity(struct media_entity *entity);
void cal_camerarx_disable(struct cal_camerarx *phy);
void cal_camerarx_i913_errata(struct cal_camerarx *phy);
@@ -341,9 +349,4 @@ void cal_ctx_v4l2_unregister(struct cal_ctx *ctx);
int cal_ctx_v4l2_init(struct cal_ctx *ctx);
void cal_ctx_v4l2_cleanup(struct cal_ctx *ctx);
-struct v4l2_mbus_framefmt *
-cal_camerarx_get_stream_format(struct cal_camerarx *phy,
- struct v4l2_subdev_state *state,
- unsigned int pad, u32 stream, u32 which);
-
#endif /* __TI_CAL_H__ */
diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
index 71282b85b784..6e791e152755 100644
--- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
+++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
@@ -25,12 +25,16 @@
#define SHIM_DMACNTX(i) (0x20 + ((i) * 0x20))
#define SHIM_DMACNTX_EN BIT(31)
#define SHIM_DMACNTX_YUV422 GENMASK(27, 26)
+#define SHIM_DMACNTX_SIZE GENMASK(21, 20)
#define SHIM_DMACNTX_VC GENMASK(9, 6)
#define SHIM_DMACNTX_FMT GENMASK(5, 0)
#define SHIM_DMACNTX_UYVY 0
#define SHIM_DMACNTX_VYUY 1
#define SHIM_DMACNTX_YUYV 2
#define SHIM_DMACNTX_YVYU 3
+#define SHIM_DMACNTX_SIZE_8 0
+#define SHIM_DMACNTX_SIZE_16 1
+#define SHIM_DMACNTX_SIZE_32 2
#define SHIM_PSI_CFG0(i) (0x24 + ((i) * 0x20))
#define SHIM_PSI_CFG0_SRC_TAG GENMASK(15, 0)
@@ -40,6 +44,9 @@
#define CSI_DF_YUV422 0x1e
#define CSI_DF_RGB444 0x20
#define CSI_DF_RGB888 0x24
+#define CSI_DF_RAW8 0x2a
+#define CSI_DF_RAW10 0x2b
+#define CSI_DF_RAW12 0x2c
#define PSIL_WORD_SIZE_BYTES 16
#define TI_CSI2RX_MAX_CTX 32
@@ -66,6 +73,7 @@ struct ti_csi2rx_fmt {
enum v4l2_colorspace colorspace;
u32 csi_df; /* CSI Data format. */
u8 bpp; /* Bits per pixel. */
+ u8 size; /* Data size shift when unpacking. */
};
struct ti_csi2rx_buffer {
@@ -125,8 +133,6 @@ struct ti_csi2rx_dev {
struct v4l2_device v4l2_dev;
struct v4l2_subdev *source;
struct v4l2_subdev subdev;
- struct v4l2_subdev_krouting routing;
- struct v4l2_subdev_stream_configs stream_configs;
struct ti_csi2rx_ctx ctx[TI_CSI2RX_MAX_CTX];
};
@@ -137,24 +143,112 @@ static const struct ti_csi2rx_fmt formats[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.csi_df = CSI_DF_YUV422,
.bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_8,
}, {
.fourcc = V4L2_PIX_FMT_UYVY,
.code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SRGB,
.csi_df = CSI_DF_YUV422,
.bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_8,
}, {
.fourcc = V4L2_PIX_FMT_YVYU,
.code = MEDIA_BUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_SRGB,
.csi_df = CSI_DF_YUV422,
.bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_8,
}, {
.fourcc = V4L2_PIX_FMT_VYUY,
.code = MEDIA_BUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_SRGB,
.csi_df = CSI_DF_YUV422,
.bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW8,
+ .bpp = 8,
+ .size = SHIM_DMACNTX_SIZE_8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW8,
+ .bpp = 8,
+ .size = SHIM_DMACNTX_SIZE_8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW8,
+ .bpp = 8,
+ .size = SHIM_DMACNTX_SIZE_8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW8,
+ .bpp = 8,
+ .size = SHIM_DMACNTX_SIZE_8,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW10,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW10,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW10,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW10,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW12,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW12,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW12,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
+ }, {
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .csi_df = CSI_DF_RAW12,
+ .bpp = 16,
+ .size = SHIM_DMACNTX_SIZE_16,
},
/* More formats can be supported but they are not listed for now. */
@@ -482,6 +576,7 @@ static void ti_csi2rx_setup_shim(struct ti_csi2rx_ctx *ctx)
break;
}
+ reg |= FIELD_PREP(SHIM_DMACNTX_SIZE, fmt->size);
reg |= FIELD_PREP(SHIM_DMACNTX_VC, ctx->vc);
writel(reg, csi->shim + SHIM_DMACNTX(ctx->idx));
@@ -733,10 +828,12 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count)
struct ti_csi2rx_dev *csi = ctx->csi;
struct ti_csi2rx_dma *dma = &ctx->dma;
struct ti_csi2rx_buffer *buf, *tmp;
+ struct v4l2_subdev_krouting *routing;
struct v4l2_subdev_route *route = NULL;
struct media_pad *remote_pad;
unsigned long flags = 0;
int ret = 0, i;
+ struct v4l2_subdev_state *state;
spin_lock_irqsave(&dma->lock, flags);
if (list_empty(&dma->queue))
@@ -755,9 +852,13 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count)
goto err_pipeline;
}
+ state = v4l2_subdev_lock_active_state(&csi->subdev);
+
+ routing = &state->routing;
+
/* Find the stream to process. */
- for (i = 0; i < csi->routing.num_routes; i++) {
- struct v4l2_subdev_route *r = &csi->routing.routes[i];
+ for (i = 0; i < routing->num_routes; i++) {
+ struct v4l2_subdev_route *r = &routing->routes[i];
if (!(r->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
continue;
@@ -771,11 +872,14 @@ static int ti_csi2rx_start_streaming(struct vb2_queue *vq, unsigned int count)
if (!route) {
ret = -ENODEV;
+ v4l2_subdev_unlock_state(state);
goto err_pipeline;
}
ctx->stream = route->sink_stream;
+ v4l2_subdev_unlock_state(state);
+
ret = ti_csi2rx_get_vc(ctx);
if (ret == -ENOIOCTLCMD)
ctx->vc = 0;
@@ -891,67 +995,43 @@ static inline struct ti_csi2rx_dev *to_csi2rx_dev(struct v4l2_subdev *sd)
return container_of(sd, struct ti_csi2rx_dev, subdev);
}
-static struct v4l2_subdev_krouting *
-ti_csi2rx_get_routing_table(struct ti_csi2rx_dev *csi,
- struct v4l2_subdev_state *state, u32 which)
-{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &csi->routing;
- else
- return &state->routing;
-}
-
-static struct v4l2_subdev_stream_configs *
-ti_csi2rx_get_stream_configs(struct ti_csi2rx_dev *csi,
- struct v4l2_subdev_state *state, u32 which)
-{
- if (which == V4L2_SUBDEV_FORMAT_ACTIVE)
- return &csi->stream_configs;
- else
- return &state->stream_configs;
-}
-
-static int ti_csi2rx_sd_get_routing(struct v4l2_subdev *sd,
+static int _ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
struct v4l2_subdev_krouting *routing)
{
- struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd);
- struct v4l2_subdev_krouting *src;
+ int ret;
+
+ const struct v4l2_mbus_framefmt format = {
+ .width = 640,
+ .height = 480,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .ycbcr_enc = V4L2_YCBCR_ENC_601,
+ .quantization = V4L2_QUANTIZATION_LIM_RANGE,
+ .xfer_func = V4L2_XFER_FUNC_SRGB,
+ };
+
+ v4l2_subdev_lock_state(state);
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
- src = ti_csi2rx_get_routing_table(csi, state, routing->which);
+ v4l2_subdev_unlock_state(state);
- return v4l2_subdev_cpy_routing(routing, src);
+ return ret;
}
static int ti_csi2rx_sd_set_routing(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
struct v4l2_subdev_krouting *routing)
{
- struct ti_csi2rx_dev *csi = to_csi2rx_dev(sd);
- struct v4l2_subdev_krouting *dst;
- struct v4l2_subdev_stream_configs *stream_configs;
- int ret;
-
- dst = ti_csi2rx_get_routing_table(csi, state, routing->which);
- stream_configs = ti_csi2rx_get_stream_configs(csi, state,
- routing->which);
-
- ret = v4l2_subdev_dup_routing(dst, routing);
- if (ret)
- return ret;
-
- ret = v4l2_init_stream_configs(stream_configs, dst);
- if (ret)
- return ret;
-
- return 0;
+ return _ti_csi2rx_sd_set_routing(sd, state, routing);
}
static int ti_csi2rx_sd_init_cfg(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state)
+ struct v4l2_subdev_state *state)
{
- u32 which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
-
struct v4l2_subdev_route routes[] = { {
.sink_pad = 0,
.sink_stream = 0,
@@ -961,13 +1041,12 @@ static int ti_csi2rx_sd_init_cfg(struct v4l2_subdev *sd,
} };
struct v4l2_subdev_krouting routing = {
- .which = which,
.num_routes = 1,
.routes = routes,
};
/* Initialize routing to single route to the fist source pad */
- return ti_csi2rx_sd_set_routing(sd, sd_state, &routing);
+ return _ti_csi2rx_sd_set_routing(sd, state, &routing);
}
static int ti_csi2rx_sd_s_stream(struct v4l2_subdev *sd, int enable)
@@ -1011,7 +1090,6 @@ static const struct v4l2_subdev_video_ops ti_csi2rx_subdev_video_ops = {
static const struct v4l2_subdev_pad_ops ti_csi2rx_subdev_pad_ops = {
.init_cfg = ti_csi2rx_sd_init_cfg,
- .get_routing = ti_csi2rx_sd_get_routing,
.set_routing = ti_csi2rx_sd_set_routing,
};
@@ -1130,7 +1208,7 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi)
v4l2_subdev_init(sd, &ti_csi2rx_subdev_ops);
sd->entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
- sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_MULTIPLEXED;
strscpy(sd->name, dev_name(csi->dev), sizeof(sd->name));
sd->dev = csi->dev;
@@ -1146,16 +1224,18 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi)
if (ret)
goto unregister_media;
- ret = ti_csi2rx_sd_init_cfg(sd, NULL);
+ ret = v4l2_subdev_init_finalize(sd);
if (ret)
goto unregister_media;
ret = v4l2_device_register_subdev(&csi->v4l2_dev, sd);
if (ret)
- goto unregister_media;
+ goto cleanup_subdev;
return 0;
+cleanup_subdev:
+ v4l2_subdev_cleanup(sd);
unregister_media:
media_device_unregister(mdev);
unregister_v4l2:
diff --git a/drivers/media/platform/vsp1/vsp1_entity.c b/drivers/media/platform/vsp1/vsp1_entity.c
index 7d92262f3378..dded3ff57830 100644
--- a/drivers/media/platform/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/vsp1/vsp1_entity.c
@@ -613,6 +613,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
const char *name, unsigned int num_pads,
const struct v4l2_subdev_ops *ops, u32 function)
{
+ static struct lock_class_key key;
struct v4l2_subdev *subdev;
unsigned int i;
int ret;
@@ -675,10 +676,11 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
* Allocate the pad configuration to store formats and selection
* rectangles.
*/
- entity->config = v4l2_subdev_alloc_state(&entity->subdev);
- if (entity->config == NULL) {
+ entity->config = __v4l2_subdev_state_alloc(&entity->subdev,
+ "vsp1:config->lock", &key);
+ if (IS_ERR(entity->config)) {
media_entity_cleanup(&entity->subdev.entity);
- return -ENOMEM;
+ return PTR_ERR(entity->config);
}
return 0;
@@ -690,6 +692,6 @@ void vsp1_entity_destroy(struct vsp1_entity *entity)
entity->ops->destroy(entity);
if (entity->subdev.ctrl_handler)
v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
- v4l2_subdev_free_state(entity->config);
+ __v4l2_subdev_state_free(entity->config);
media_entity_cleanup(&entity->subdev.entity);
}
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 4f03bfa300a1..0b97c9083607 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -28,8 +28,9 @@
static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
{
struct v4l2_subdev_state *state;
+ static struct lock_class_key key;
- state = v4l2_subdev_alloc_state(sd);
+ state = __v4l2_subdev_state_alloc(sd, "fh->state->lock", &key);
if (IS_ERR(state))
return PTR_ERR(state);
@@ -40,7 +41,7 @@ static int subdev_fh_init(struct v4l2_subdev_fh *fh, struct v4l2_subdev *sd)
static void subdev_fh_free(struct v4l2_subdev_fh *fh)
{
- v4l2_subdev_free_state(fh->state);
+ __v4l2_subdev_state_free(fh->state);
fh->state = NULL;
}
@@ -149,9 +150,40 @@ static inline int check_pad(struct v4l2_subdev *sd, u32 pad)
return 0;
}
-static int check_cfg(u32 which, struct v4l2_subdev_state *state)
+static int check_state_pads(struct v4l2_subdev *sd, u32 which,
+ struct v4l2_subdev_state *state)
{
- if (which == V4L2_SUBDEV_FORMAT_TRY && !state)
+ if (sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED)
+ return 0;
+
+ if (which == V4L2_SUBDEV_FORMAT_TRY && (!state || !state->pads))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int check_state_pad_stream(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u32 stream)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ if (!(sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED))
+ return 0;
+
+ /*
+ * We need to take the state lock to access the format, but as we then
+ * have to unlock, nothing prevents someone changing the state before
+ * this call thread enters the driver's op and the driver has the
+ * change to lock the state.
+ */
+ v4l2_subdev_lock_state(state);
+
+ fmt = v4l2_state_get_stream_format(state, pad, stream);
+
+ v4l2_subdev_unlock_state(state);
+
+ if (!fmt)
return -EINVAL;
return 0;
@@ -165,7 +197,8 @@ static inline int check_format(struct v4l2_subdev *sd,
return -EINVAL;
return check_which(format->which) ? : check_pad(sd, format->pad) ? :
- check_cfg(format->which, state);
+ check_state_pads(sd, format->which, state) ? :
+ check_state_pad_stream(sd, state, format->pad, format->stream);
}
static int call_get_fmt(struct v4l2_subdev *sd,
@@ -192,7 +225,8 @@ static int call_enum_mbus_code(struct v4l2_subdev *sd,
return -EINVAL;
return check_which(code->which) ? : check_pad(sd, code->pad) ? :
- check_cfg(code->which, state) ? :
+ check_state_pads(sd, code->which, state) ? :
+ check_state_pad_stream(sd, state, code->pad, code->stream) ? :
sd->ops->pad->enum_mbus_code(sd, state, code);
}
@@ -204,7 +238,8 @@ static int call_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
return check_which(fse->which) ? : check_pad(sd, fse->pad) ? :
- check_cfg(fse->which, state) ? :
+ check_state_pads(sd, fse->which, state) ? :
+ check_state_pad_stream(sd, state, fse->pad, fse->stream) ? :
sd->ops->pad->enum_frame_size(sd, state, fse);
}
@@ -239,7 +274,8 @@ static int call_enum_frame_interval(struct v4l2_subdev *sd,
return -EINVAL;
return check_which(fie->which) ? : check_pad(sd, fie->pad) ? :
- check_cfg(fie->which, state) ? :
+ check_state_pads(sd, fie->which, state) ? :
+ check_state_pad_stream(sd, state, fie->pad, fie->stream) ? :
sd->ops->pad->enum_frame_interval(sd, state, fie);
}
@@ -251,7 +287,8 @@ static inline int check_selection(struct v4l2_subdev *sd,
return -EINVAL;
return check_which(sel->which) ? : check_pad(sd, sel->pad) ? :
- check_cfg(sel->which, state);
+ check_state_pads(sd, sel->which, state) ? :
+ check_state_pad_stream(sd, state, sel->pad, sel->stream);
}
static int call_get_selection(struct v4l2_subdev *sd,
@@ -354,6 +391,59 @@ const struct v4l2_subdev_ops v4l2_subdev_call_wrappers = {
EXPORT_SYMBOL(v4l2_subdev_call_wrappers);
#if defined(CONFIG_VIDEO_V4L2_SUBDEV_API)
+
+static struct v4l2_subdev_state *
+subdev_ioctl_get_state(struct v4l2_subdev *sd, struct v4l2_subdev_fh *subdev_fh,
+ unsigned int cmd, void *arg)
+{
+ u32 which;
+
+ switch (cmd) {
+ default:
+ return NULL;
+
+ case VIDIOC_SUBDEV_G_FMT:
+ case VIDIOC_SUBDEV_S_FMT: {
+ which = ((struct v4l2_subdev_format *)arg)->which;
+ break;
+ }
+ case VIDIOC_SUBDEV_G_CROP:
+ case VIDIOC_SUBDEV_S_CROP: {
+ which = ((struct v4l2_subdev_crop *)arg)->which;
+ break;
+ }
+ case VIDIOC_SUBDEV_ENUM_MBUS_CODE: {
+ which = ((struct v4l2_subdev_mbus_code_enum *)arg)->which;
+ break;
+ }
+ case VIDIOC_SUBDEV_ENUM_FRAME_SIZE: {
+ which = ((struct v4l2_subdev_frame_size_enum *)arg)->which;
+ break;
+ }
+
+ case VIDIOC_SUBDEV_ENUM_FRAME_INTERVAL: {
+ which = ((struct v4l2_subdev_frame_interval_enum *)arg)->which;
+ break;
+ }
+
+ case VIDIOC_SUBDEV_G_SELECTION:
+ case VIDIOC_SUBDEV_S_SELECTION: {
+ which = ((struct v4l2_subdev_selection *)arg)->which;
+ break;
+ }
+
+ case VIDIOC_SUBDEV_G_ROUTING:
+ case VIDIOC_SUBDEV_S_ROUTING: {
+ which = ((struct v4l2_subdev_routing *)arg)->which;
+ break;
+ }
+ }
+
+ return which == V4L2_SUBDEV_FORMAT_TRY ?
+ subdev_fh->state :
+ v4l2_subdev_get_active_state(sd);
+}
+
static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
@@ -361,15 +451,20 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_fh *vfh = file->private_data;
struct v4l2_subdev_fh *subdev_fh = to_v4l2_subdev_fh(vfh);
bool ro_subdev = test_bit(V4L2_FL_SUBDEV_RO_DEVNODE, &vdev->flags);
+ struct v4l2_subdev_state *state;
int rval;
+ state = subdev_ioctl_get_state(sd, subdev_fh, cmd, arg);
+
switch (cmd) {
case VIDIOC_SUBDEV_QUERYCAP: {
struct v4l2_subdev_capability *cap = arg;
memset(cap->reserved, 0, sizeof(cap->reserved));
cap->version = LINUX_VERSION_CODE;
- cap->capabilities = ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0;
+ cap->capabilities =
+ (ro_subdev ? V4L2_SUBDEV_CAP_RO_SUBDEV : 0) |
+ ((sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED) ? V4L2_SUBDEV_CAP_MPLEXED : 0);
return 0;
}
@@ -485,7 +580,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
- return v4l2_subdev_call(sd, pad, get_fmt, subdev_fh->state, format);
+ return v4l2_subdev_call(sd, pad, get_fmt, state, format);
}
case VIDIOC_SUBDEV_S_FMT: {
@@ -496,7 +591,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(format->reserved, 0, sizeof(format->reserved));
memset(format->format.reserved, 0, sizeof(format->format.reserved));
- return v4l2_subdev_call(sd, pad, set_fmt, subdev_fh->state, format);
+ return v4l2_subdev_call(sd, pad, set_fmt, state, format);
}
case VIDIOC_SUBDEV_G_CROP: {
@@ -510,7 +605,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sel.target = V4L2_SEL_TGT_CROP;
rval = v4l2_subdev_call(
- sd, pad, get_selection, subdev_fh->state, &sel);
+ sd, pad, get_selection, state, &sel);
crop->rect = sel.r;
@@ -532,7 +627,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
sel.r = crop->rect;
rval = v4l2_subdev_call(
- sd, pad, set_selection, subdev_fh->state, &sel);
+ sd, pad, set_selection, state, &sel);
crop->rect = sel.r;
@@ -543,7 +638,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_mbus_code_enum *code = arg;
memset(code->reserved, 0, sizeof(code->reserved));
- return v4l2_subdev_call(sd, pad, enum_mbus_code, subdev_fh->state,
+ return v4l2_subdev_call(sd, pad, enum_mbus_code, state,
code);
}
@@ -551,7 +646,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_frame_size_enum *fse = arg;
memset(fse->reserved, 0, sizeof(fse->reserved));
- return v4l2_subdev_call(sd, pad, enum_frame_size, subdev_fh->state,
+ return v4l2_subdev_call(sd, pad, enum_frame_size, state,
fse);
}
@@ -576,7 +671,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_frame_interval_enum *fie = arg;
memset(fie->reserved, 0, sizeof(fie->reserved));
- return v4l2_subdev_call(sd, pad, enum_frame_interval, subdev_fh->state,
+ return v4l2_subdev_call(sd, pad, enum_frame_interval, state,
fie);
}
@@ -585,7 +680,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
- sd, pad, get_selection, subdev_fh->state, sel);
+ sd, pad, get_selection, state, sel);
}
case VIDIOC_SUBDEV_S_SELECTION: {
@@ -596,7 +691,7 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
memset(sel->reserved, 0, sizeof(sel->reserved));
return v4l2_subdev_call(
- sd, pad, set_selection, subdev_fh->state, sel);
+ sd, pad, set_selection, state, sel);
}
case VIDIOC_G_EDID: {
@@ -662,19 +757,26 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_SUBDEV_G_ROUTING: {
struct v4l2_subdev_routing *routing = arg;
- struct v4l2_subdev_krouting krouting = {
- .which = routing->which,
- .num_routes = routing->num_routes,
- .routes = (struct v4l2_subdev_route *)(uintptr_t)
- routing->routes,
- };
- int ret;
+ struct v4l2_subdev_krouting *krouting;
- ret = v4l2_subdev_call(sd, pad, get_routing, subdev_fh->state, &krouting);
+ if (!(sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED))
+ return -ENOIOCTLCMD;
- routing->num_routes = krouting.num_routes;
+ memset(routing->reserved, 0, sizeof(routing->reserved));
- return ret;
+ krouting = &state->routing;
+
+ if (routing->num_routes < krouting->num_routes) {
+ routing->num_routes = krouting->num_routes;
+ return -ENOSPC;
+ }
+
+ memcpy((struct v4l2_subdev_route *)(uintptr_t)routing->routes,
+ krouting->routes,
+ krouting->num_routes * sizeof(*krouting->routes));
+ routing->num_routes = krouting->num_routes;
+
+ return 0;
}
case VIDIOC_SUBDEV_S_ROUTING: {
@@ -684,26 +786,41 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
struct v4l2_subdev_krouting krouting = {};
unsigned int i;
+ if (!(sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED))
+ return -ENOIOCTLCMD;
+
if (routing->which != V4L2_SUBDEV_FORMAT_TRY && ro_subdev)
return -EPERM;
+ memset(routing->reserved, 0, sizeof(routing->reserved));
+
for (i = 0; i < routing->num_routes; ++i) {
- if (routes[i].sink_pad >= sd->entity.num_pads ||
- routes[i].source_pad >= sd->entity.num_pads)
+ const struct v4l2_subdev_route *route = &routes[i];
+ const struct media_pad *pads = sd->entity.pads;
+
+ /* Do not check sink pad for source routes */
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_SOURCE)) {
+ if (route->sink_pad >= sd->entity.num_pads)
+ return -EINVAL;
+
+ if (!(pads[route->sink_pad].flags &
+ MEDIA_PAD_FL_SINK))
+ return -EINVAL;
+ }
+
+ if (route->source_pad >= sd->entity.num_pads)
return -EINVAL;
- if (!(sd->entity.pads[routes[i].sink_pad].flags &
- MEDIA_PAD_FL_SINK) ||
- !(sd->entity.pads[routes[i].source_pad].flags &
+ if (!(pads[route->source_pad].flags &
MEDIA_PAD_FL_SOURCE))
return -EINVAL;
}
- krouting.which = routing->which;
krouting.num_routes = routing->num_routes;
krouting.routes = routes;
- return v4l2_subdev_call(sd, pad, set_routing, subdev_fh->state, &krouting);
+ return v4l2_subdev_call(sd, pad, set_routing, state,
+ routing->which, &krouting);
}
default:
@@ -789,6 +906,71 @@ const struct v4l2_file_operations v4l2_subdev_fops = {
.poll = subdev_poll,
};
+static int
+v4l2_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs,
+ const struct v4l2_subdev_krouting *routing)
+{
+ u32 num_configs = 0;
+ unsigned int i;
+ u32 format_idx = 0;
+
+ kvfree(stream_configs->configs);
+ stream_configs->configs = NULL;
+ stream_configs->num_configs = 0;
+
+ /* Count number of formats needed */
+ for (i = 0; i < routing->num_routes; ++i) {
+ struct v4l2_subdev_route *route = &routing->routes[i];
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ /*
+ * Each route needs a format on both ends of the route, except
+ * for source streams which only need one format.
+ */
+ num_configs +=
+ (route->flags & V4L2_SUBDEV_ROUTE_FL_SOURCE) ? 1 : 2;
+ }
+
+ if (num_configs) {
+ stream_configs->configs =
+ kvcalloc(num_configs, sizeof(*stream_configs->configs),
+ GFP_KERNEL);
+
+ if (!stream_configs->configs)
+ return -ENOMEM;
+
+ stream_configs->num_configs = num_configs;
+ }
+
+ /*
+ * Fill in the 'pad' and stream' value for each item in the array from
+ * the routing table
+ */
+ for (i = 0; i < routing->num_routes; ++i) {
+ struct v4l2_subdev_route *route = &routing->routes[i];
+ u32 idx;
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_SOURCE)) {
+ idx = format_idx++;
+
+ stream_configs->configs[idx].pad = route->sink_pad;
+ stream_configs->configs[idx].stream = route->sink_stream;
+ }
+
+ idx = format_idx++;
+
+ stream_configs->configs[idx].pad = route->source_pad;
+ stream_configs->configs[idx].stream = route->source_stream;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_MEDIA_CONTROLLER
int v4l2_subdev_get_fwnode_pad_1_to_1(struct media_entity *entity,
@@ -843,11 +1025,14 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
if (is_media_entity_v4l2_subdev(pad->entity)) {
struct v4l2_subdev *sd =
media_entity_to_v4l2_subdev(pad->entity);
+ struct v4l2_subdev_state *state;
+
+ state = v4l2_subdev_get_active_state(sd);
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
fmt->pad = pad->index;
fmt->stream = stream;
- return v4l2_subdev_call(sd, pad, get_fmt, NULL, fmt);
+ return v4l2_subdev_call(sd, pad, get_fmt, state, fmt);
}
WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
@@ -857,234 +1042,133 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad,
return -EINVAL;
}
-int v4l2_subdev_get_routing(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_krouting *routing)
+static int cmp_u32(const void *a, const void *b)
{
- int ret;
-
- routing->which = state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- routing->routes = NULL;
- routing->num_routes = 0;
-
- ret = v4l2_subdev_call(sd, pad, get_routing, state, routing);
- if (ret == 0)
- return 0;
- if (ret != -ENOSPC)
- return ret;
-
- routing->routes = kvmalloc_array(routing->num_routes,
- sizeof(*routing->routes), GFP_KERNEL);
- if (!routing->routes)
- return -ENOMEM;
-
- ret = v4l2_subdev_call(sd, pad, get_routing, state, routing);
- if (ret) {
- kvfree(routing->routes);
- return ret;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_get_routing);
+ u32 a32 = *(u32 *)a;
+ u32 b32 = *(u32 *)b;
-void v4l2_subdev_free_routing(struct v4l2_subdev_krouting *routing)
-{
- kvfree(routing->routes);
- routing->routes = NULL;
- routing->num_routes = 0;
+ return a32 > b32 ? 1 : (a32 < b32 ? -1 : 0);
}
-EXPORT_SYMBOL_GPL(v4l2_subdev_free_routing);
-int v4l2_subdev_cpy_routing(struct v4l2_subdev_krouting *dst,
- const struct v4l2_subdev_krouting *src)
+static int v4l2_link_validate_get_streams(struct media_link *link,
+ bool is_source, u32 *out_num_streams,
+ const u32 **out_streams,
+ bool *allocated)
{
- if (dst->num_routes < src->num_routes) {
- dst->num_routes = src->num_routes;
- return -ENOSPC;
- }
-
- memcpy(dst->routes, src->routes,
- src->num_routes * sizeof(*src->routes));
- dst->num_routes = src->num_routes;
- dst->which = src->which;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_cpy_routing);
+ static const u32 default_streams[] = { 0 };
+ struct v4l2_subdev_krouting *routing;
+ struct v4l2_subdev *subdev;
+ u32 num_streams;
+ u32 *streams;
+ unsigned int i;
+ struct v4l2_subdev_state *state;
-int v4l2_subdev_dup_routing(struct v4l2_subdev_krouting *dst,
- const struct v4l2_subdev_krouting *src)
-{
- v4l2_subdev_free_routing(dst);
+ if (is_source)
+ subdev = media_entity_to_v4l2_subdev(link->source->entity);
+ else
+ subdev = media_entity_to_v4l2_subdev(link->sink->entity);
- if (src->num_routes == 0) {
- dst->which = src->which;
+ if (!(subdev->flags & V4L2_SUBDEV_FL_MULTIPLEXED)) {
+ *out_num_streams = 1;
+ *out_streams = default_streams;
+ *allocated = false;
return 0;
}
- dst->routes = kvmalloc_array(src->num_routes, sizeof(*src->routes),
- GFP_KERNEL);
- if (!dst->routes)
- return -ENOMEM;
+ state = v4l2_subdev_lock_active_state(subdev);
- memcpy(dst->routes, src->routes,
- src->num_routes * sizeof(*src->routes));
- dst->num_routes = src->num_routes;
- dst->which = src->which;
+ routing = &state->routing;
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_dup_routing);
+ streams = kmalloc_array(routing->num_routes, sizeof(u32), GFP_KERNEL);
-bool v4l2_subdev_has_route(struct v4l2_subdev_krouting *routing,
- unsigned int pad0, unsigned int pad1)
-{
- unsigned int i;
+ if (!streams) {
+ v4l2_subdev_unlock_state(state);
+ return -ENOMEM;
+ }
+
+ num_streams = 0;
for (i = 0; i < routing->num_routes; ++i) {
struct v4l2_subdev_route *route = &routing->routes[i];
+ int j;
+ u32 route_pad;
+ u32 route_stream;
+ u32 link_pad;
+
+ if (is_source) {
+ route_pad = route->source_pad;
+ route_stream = route->source_stream;
+ link_pad = link->source->index;
+ } else {
+ route_pad = route->sink_pad;
+ route_stream = route->sink_stream;
+ link_pad = link->sink->index;
+ }
if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
continue;
- if ((route->sink_pad == pad0 && route->source_pad == pad1) ||
- (route->source_pad == pad0 && route->sink_pad == pad1))
- return true;
+ if (route_pad != link_pad)
+ continue;
+
+ /* look for duplicates... */
+ for (j = 0; j < num_streams; ++j) {
+ if (streams[j] == route_stream)
+ break;
+ }
+
+ /* ...and drop the stream if we already have it */
+ if (j != num_streams)
+ continue;
+
+ streams[num_streams++] = route_stream;
}
- return false;
-}
-EXPORT_SYMBOL_GPL(v4l2_subdev_has_route);
+ v4l2_subdev_unlock_state(state);
-static int cmp_u32(const void *a, const void *b)
-{
- u32 a32 = *(u32 *)a;
- u32 b32 = *(u32 *)b;
+ sort(streams, num_streams, sizeof(u32), &cmp_u32, NULL);
- return a32 > b32 ? 1 : (a32 < b32 ? -1 : 0);
+ *out_num_streams = num_streams;
+ *out_streams = streams;
+ *allocated = true;
+
+ return 0;
}
int v4l2_subdev_link_validate(struct media_link *link)
{
- int ret;
- unsigned int i;
-
- struct v4l2_subdev *source_subdev =
- media_entity_to_v4l2_subdev(link->source->entity);
struct v4l2_subdev *sink_subdev =
media_entity_to_v4l2_subdev(link->sink->entity);
struct device *dev = sink_subdev->entity.graph_obj.mdev->dev;
-
- struct v4l2_subdev_krouting routing;
-
- static const u32 default_streams[] = { 0 };
-
- u32 num_source_streams = 0;
- const u32 *source_streams = NULL;
- u32 num_sink_streams = 0;
- const u32 *sink_streams = NULL;
+ u32 num_source_streams;
+ const u32 *source_streams;
+ bool source_allocated;
+ u32 num_sink_streams;
+ const u32 *sink_streams;
+ bool sink_allocated;
+ unsigned int sink_idx;
+ unsigned int source_idx;
+ int ret;
dev_dbg(dev, "validating link \"%s\":%u -> \"%s\":%u\n",
link->source->entity->name, link->source->index,
link->sink->entity->name, link->sink->index);
- /* Get source streams */
-
- memset(&routing, 0, sizeof(routing));
-
- ret = v4l2_subdev_get_routing(source_subdev, NULL, &routing);
-
- if (ret && ret != -ENOIOCTLCMD)
+ ret = v4l2_link_validate_get_streams(link, true, &num_source_streams,
+ &source_streams,
+ &source_allocated);
+ if (ret)
return ret;
- if (ret == -ENOIOCTLCMD) {
- num_source_streams = 1;
- source_streams = default_streams;
- } else {
- u32 *streams;
-
- streams = kmalloc_array(routing.num_routes, sizeof(u32),
- GFP_KERNEL);
-
- for (i = 0; i < routing.num_routes; ++i) {
- int j;
- struct v4l2_subdev_route *route = &routing.routes[i];
-
- if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
- continue;
-
- if (route->source_pad != link->source->index)
- continue;
-
- for (j = 0; j < num_source_streams; ++j) {
- if (streams[j] == route->source_stream)
- break;
- }
-
- if (j != num_source_streams)
- continue;
-
- streams[num_source_streams++] = route->source_stream;
-
- }
-
- sort(streams, num_source_streams, sizeof(u32), &cmp_u32, NULL);
-
- source_streams = streams;
-
- v4l2_subdev_free_routing(&routing);
- }
-
- /* Get sink streams */
-
- memset(&routing, 0, sizeof(routing));
-
- ret = v4l2_subdev_get_routing(sink_subdev, NULL, &routing);
+ ret = v4l2_link_validate_get_streams(link, false, &num_sink_streams,
+ &sink_streams, &sink_allocated);
+ if (ret)
+ goto free_source;
- if (ret && ret != -ENOIOCTLCMD)
- goto out;
-
- if (ret == -ENOIOCTLCMD) {
- num_sink_streams = 1;
- sink_streams = default_streams;
- } else {
- u32 *streams;
-
- streams = kmalloc_array(routing.num_routes, sizeof(u32),
- GFP_KERNEL);
-
- for (i = 0; i < routing.num_routes; ++i) {
- struct v4l2_subdev_route *route = &routing.routes[i];
- int j;
-
- if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
- continue;
-
- if (route->sink_pad != link->sink->index)
- continue;
-
- for (j = 0; j < num_sink_streams; ++j) {
- if (streams[j] == route->sink_stream)
- break;
- }
-
- if (j != num_sink_streams)
- continue;
-
- streams[num_sink_streams++] = route->sink_stream;
- }
-
- sort(streams, num_sink_streams, sizeof(u32), &cmp_u32, NULL);
-
- sink_streams = streams;
-
- v4l2_subdev_free_routing(&routing);
- }
-
- if (num_source_streams != num_sink_streams) {
+ /* It is ok to have more source streams than sink streams */
+ if (num_source_streams < num_sink_streams) {
dev_err(dev,
- "Sink and source stream count mismatch: %d vs %d\n",
+ "Not enough source streams: %d < %d\n",
num_source_streams, num_sink_streams);
ret = -EINVAL;
goto out;
@@ -1092,18 +1176,26 @@ int v4l2_subdev_link_validate(struct media_link *link)
/* Validate source and sink stream formats */
- for (i = 0; i < num_source_streams; ++i) {
+ source_idx = 0;
+
+ for (sink_idx = 0; sink_idx < num_sink_streams; ++sink_idx) {
struct v4l2_subdev_format sink_fmt, source_fmt;
u32 stream;
- if (source_streams[i] != sink_streams[i]) {
- dev_err(dev, "Sink and source streams do not match\n");
+ stream = sink_streams[sink_idx];
+
+ for (; source_idx < num_source_streams; ++source_idx) {
+ if (source_streams[source_idx] == stream)
+ break;
+ }
+
+ if (source_idx == num_source_streams) {
+ dev_err(dev, "No source stream for sink stream %u\n",
+ stream);
ret = -EINVAL;
goto out;
}
- stream = source_streams[i];
-
dev_dbg(dev, "validating stream \"%s\":%u:%u -> \"%s\":%u:%u\n",
link->source->entity->name, link->source->index, stream,
link->sink->entity->name, link->sink->index, stream);
@@ -1145,26 +1237,60 @@ int v4l2_subdev_link_validate(struct media_link *link)
}
out:
- if (source_streams != default_streams)
- kfree(source_streams);
-
- if (sink_streams != default_streams)
+ if (sink_allocated)
kfree(sink_streams);
+free_source:
+ if (source_allocated)
+ kfree(source_streams);
+
return ret;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_link_validate);
-struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd)
+bool v4l2_subdev_has_route(struct media_entity *entity, unsigned int pad0,
+ unsigned int pad1)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct v4l2_subdev_krouting *routing;
+ unsigned int i;
+ struct v4l2_subdev_state *state;
+
+ state = v4l2_subdev_lock_active_state(sd);
+
+ routing = &state->routing;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ struct v4l2_subdev_route *route = &routing->routes[i];
+
+ if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
+ continue;
+
+ if ((route->sink_pad == pad0 && route->source_pad == pad1) ||
+ (route->source_pad == pad0 && route->sink_pad == pad1)) {
+ v4l2_subdev_unlock_state(state);
+ return true;
+ }
+ }
+
+ v4l2_subdev_unlock_state(state);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_has_route);
+
+struct v4l2_subdev_state *
+__v4l2_subdev_state_alloc(struct v4l2_subdev *sd, const char *lock_name,
+ struct lock_class_key *lock_key)
{
struct v4l2_subdev_state *state;
int ret;
state = kzalloc(sizeof(*state), GFP_KERNEL);
- if (!state) {
- ret = -ENOMEM;
- goto err;
- }
+ if (!state)
+ return ERR_PTR(-ENOMEM);
+
+ __mutex_init(&state->lock, lock_name, lock_key);
/* Drivers that support streams do not need the legacy pad config */
if (!(sd->flags & V4L2_SUBDEV_FL_MULTIPLEXED) && sd->entity.num_pads) {
@@ -1191,17 +1317,21 @@ err:
return ERR_PTR(ret);
}
-EXPORT_SYMBOL_GPL(v4l2_subdev_alloc_state);
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_alloc);
-void v4l2_subdev_free_state(struct v4l2_subdev_state *state)
+void __v4l2_subdev_state_free(struct v4l2_subdev_state *state)
{
- v4l2_subdev_free_routing(&state->routing);
- v4l2_uninit_stream_configs(&state->stream_configs);
+ if (!state)
+ return;
+
+ mutex_destroy(&state->lock);
+ kvfree(state->routing.routes);
+ kvfree(state->stream_configs.configs);
kvfree(state->pads);
- kvfree(state);
+ kfree(state);
}
-EXPORT_SYMBOL_GPL(v4l2_subdev_free_state);
+EXPORT_SYMBOL_GPL(__v4l2_subdev_state_free);
#endif /* CONFIG_MEDIA_CONTROLLER */
@@ -1232,64 +1362,202 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
}
EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event);
-int v4l2_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs,
- const struct v4l2_subdev_krouting *routing)
+int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
+ struct lock_class_key *key)
{
- u32 num_configs = 0;
- unsigned int i;
- u32 format_idx = 0;
+ struct v4l2_subdev_state *state;
- v4l2_uninit_stream_configs(stream_configs);
+ state = __v4l2_subdev_state_alloc(sd, name, key);
+ if (IS_ERR(state))
+ return PTR_ERR(state);
- /* Count number of formats needed */
- for (i = 0; i < routing->num_routes; ++i) {
- struct v4l2_subdev_route *route = &routing->routes[i];
+ sd->state = state;
- if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
- continue;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(__v4l2_subdev_init_finalize);
- /* Each route needs a format on both ends of the route */
- num_configs += 2;
- }
+void v4l2_subdev_cleanup(struct v4l2_subdev *sd)
+{
+ __v4l2_subdev_state_free(sd->state);
+ sd->state = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_cleanup);
- if (num_configs) {
- stream_configs->configs =
- kvcalloc(num_configs, sizeof(*stream_configs->configs),
- GFP_KERNEL);
+struct v4l2_subdev_state *v4l2_subdev_lock_active_state(struct v4l2_subdev *sd)
+{
+ mutex_lock(&sd->state->lock);
- if (!stream_configs->configs)
+ return sd->state;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_lock_active_state);
+
+void v4l2_subdev_lock_state(struct v4l2_subdev_state *state)
+{
+ mutex_lock(&state->lock);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_lock_state);
+
+void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state)
+{
+ mutex_unlock(&state->lock);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_unlock_state);
+
+int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct v4l2_subdev_krouting *dst = &state->routing;
+ const struct v4l2_subdev_krouting *src = routing;
+
+ lockdep_assert_held(&state->lock);
+
+ kvfree(dst->routes);
+ dst->routes = NULL;
+ dst->num_routes = 0;
+
+ if (src->num_routes > 0) {
+ dst->routes = kvmalloc_array(src->num_routes,
+ sizeof(*src->routes), GFP_KERNEL);
+ if (!dst->routes)
return -ENOMEM;
- stream_configs->num_configs = num_configs;
+ memcpy(dst->routes, src->routes,
+ src->num_routes * sizeof(*src->routes));
+ dst->num_routes = src->num_routes;
+ }
+
+ return v4l2_init_stream_configs(&state->stream_configs, dst);
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing);
+
+int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing,
+ const struct v4l2_mbus_framefmt *fmt)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+ int ret;
+
+ ret = v4l2_subdev_set_routing(sd, state, routing);
+ if (ret)
+ return ret;
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i)
+ stream_configs->configs[i].fmt = *fmt;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_set_routing_with_fmt);
+
+struct v4l2_mbus_framefmt *
+v4l2_state_get_stream_format(struct v4l2_subdev_state *state, unsigned int pad,
+ u32 stream)
+{
+ struct v4l2_subdev_stream_configs *stream_configs;
+ unsigned int i;
+
+ lockdep_assert_held(&state->lock);
+
+ stream_configs = &state->stream_configs;
+
+ for (i = 0; i < stream_configs->num_configs; ++i) {
+ if (stream_configs->configs[i].pad == pad &&
+ stream_configs->configs[i].stream == stream)
+ return &stream_configs->configs[i].fmt;
}
- /* Fill in the 'pad' and stream' value for each item in the array from the routing table */
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_state_get_stream_format);
+
+int v4l2_state_find_opposite_end(struct v4l2_subdev_krouting *routing, u32 pad,
+ u32 stream, u32 *other_pad, u32 *other_stream)
+{
+ unsigned int i;
+
for (i = 0; i < routing->num_routes; ++i) {
struct v4l2_subdev_route *route = &routing->routes[i];
- u32 idx;
- if (!(route->flags & V4L2_SUBDEV_ROUTE_FL_ACTIVE))
- continue;
+ if (route->source_pad == pad &&
+ route->source_stream == stream) {
+ *other_pad = route->sink_pad;
+ *other_stream = route->sink_stream;
+ return 0;
+ }
- idx = format_idx++;
+ if (route->sink_pad == pad && route->sink_stream == stream) {
+ *other_pad = route->source_pad;
+ *other_stream = route->source_stream;
+ return 0;
+ }
+ }
- stream_configs->configs[idx].pad = route->sink_pad;
- stream_configs->configs[idx].stream = route->sink_stream;
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(v4l2_state_find_opposite_end);
- idx = format_idx++;
+struct v4l2_mbus_framefmt *
+v4l2_state_get_opposite_stream_format(struct v4l2_subdev_state *state, u32 pad,
+ u32 stream)
+{
+ u32 other_pad, other_stream;
+ int ret;
- stream_configs->configs[idx].pad = route->source_pad;
- stream_configs->configs[idx].stream = route->source_stream;
+ ret = v4l2_state_find_opposite_end(&state->routing, pad, stream,
+ &other_pad, &other_stream);
+ if (ret)
+ return NULL;
+
+ return v4l2_state_get_stream_format(state, other_pad, other_stream);
+}
+EXPORT_SYMBOL_GPL(v4l2_state_get_opposite_stream_format);
+
+int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ v4l2_subdev_lock_state(state);
+
+ fmt = v4l2_state_get_stream_format(state, format->pad, format->stream);
+ if (!fmt) {
+ v4l2_subdev_unlock_state(state);
+ return -EINVAL;
}
+ format->format = *fmt;
+
+ v4l2_subdev_unlock_state(state);
+
return 0;
}
-EXPORT_SYMBOL_GPL(v4l2_init_stream_configs);
+EXPORT_SYMBOL_GPL(v4l2_subdev_get_fmt);
-void v4l2_uninit_stream_configs(struct v4l2_subdev_stream_configs *stream_configs)
+int v4l2_routing_simple_verify(const struct v4l2_subdev_krouting *routing)
{
- kvfree(stream_configs->configs);
- stream_configs->configs = NULL;
- stream_configs->num_configs = 0;
+ unsigned int i, j;
+
+ for (i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routing->routes[i];
+
+ for (j = i + 1; j < routing->num_routes; ++j) {
+ const struct v4l2_subdev_route *r = &routing->routes[j];
+
+ if (route->sink_pad == r->sink_pad &&
+ route->sink_stream == r->sink_stream)
+ return -EINVAL;
+
+ if (route->source_pad == r->source_pad &&
+ route->source_stream == r->source_stream)
+ return -EINVAL;
+ }
+ }
+
+ return 0;
}
-EXPORT_SYMBOL_GPL(v4l2_uninit_stream_configs);
+EXPORT_SYMBOL_GPL(v4l2_routing_simple_verify);
diff --git a/drivers/staging/media/ipu3/include/intel-ipu3.h b/drivers/staging/media/ipu3/include/intel-ipu3.h
index 3a45c1fe4957..edd8edda0647 100644
--- a/drivers/staging/media/ipu3/include/intel-ipu3.h
+++ b/drivers/staging/media/ipu3/include/intel-ipu3.h
@@ -418,7 +418,7 @@ struct ipu3_uapi_af_config_s {
IPU3_UAPI_AWB_FR_SPARE_FOR_BUBBLES) * IPU3_UAPI_MAX_STRIPES)
/**
- * struct ipu3_uapi_awb_fr_meta_data - AWB filter response meta data
+ * struct ipu3_uapi_awb_fr_raw_buffer - AWB filter response meta data
*
* @meta_data: Statistics output on the grid after convolving with 1D filter.
*/
@@ -1506,7 +1506,7 @@ struct ipu3_uapi_sharp_cfg {
} __packed;
/**
- * struct struct ipu3_uapi_far_w - Sharpening config for far sub-group
+ * struct ipu3_uapi_far_w - Sharpening config for far sub-group
*
* @dir_shrp: Weight of wide direct sharpening, u1.6, range [0, 64], default 64.
* @reserved0: reserved
@@ -1526,7 +1526,7 @@ struct ipu3_uapi_far_w {
} __packed;
/**
- * struct struct ipu3_uapi_unsharp_cfg - Unsharp config
+ * struct ipu3_uapi_unsharp_cfg - Unsharp config
*
* @unsharp_weight: Unsharp mask blending weight.
* u1.6, range [0, 64], default 16.
@@ -1772,7 +1772,7 @@ struct ipu3_uapi_vss_lut_y {
} __packed;
/**
- * struct ipu3_uapi_yuvp1_iefd_vssnlm_cf - IEFd Vssnlm Lookup table
+ * struct ipu3_uapi_yuvp1_iefd_vssnlm_cfg - IEFd Vssnlm Lookup table
*
* @vss_lut_x: vss lookup table. See &ipu3_uapi_vss_lut_x description
* @vss_lut_y: vss lookup table. See &ipu3_uapi_vss_lut_y description
diff --git a/drivers/staging/media/tegra-video/vi.c b/drivers/staging/media/tegra-video/vi.c
index ce4bb7cd890b..b95dd336e95d 100644
--- a/drivers/staging/media/tegra-video/vi.c
+++ b/drivers/staging/media/tegra-video/vi.c
@@ -490,6 +490,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
struct v4l2_pix_format *pix)
{
const struct tegra_video_format *fmtinfo;
+ static struct lock_class_key key;
struct v4l2_subdev *subdev;
struct v4l2_subdev_format fmt;
struct v4l2_subdev_state *sd_state;
@@ -506,9 +507,10 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
if (!subdev)
return -ENODEV;
- sd_state = v4l2_subdev_alloc_state(subdev);
- if (!sd_state)
- return -ENOMEM;
+ sd_state = __v4l2_subdev_state_alloc(subdev, "tegra:state->lock",
+ &key);
+ if (IS_ERR(sd_state))
+ return PTR_ERR(sd_state);
/*
* Retrieve the format information and if requested format isn't
* supported, keep the current format.
@@ -550,7 +552,7 @@ static int __tegra_channel_try_format(struct tegra_vi_channel *chan,
v4l2_fill_pix_format(pix, &fmt.format);
tegra_channel_fmt_align(chan, pix, fmtinfo->bpp);
- v4l2_subdev_free_state(sd_state);
+ __v4l2_subdev_state_free(sd_state);
return 0;
}
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 43d43972901e..1580d51aea4f 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -23,7 +23,6 @@
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/of.h>
-#include <linux/of_graph.h>
#include <linux/acpi.h>
#include <linux/pinctrl/consumer.h>
#include <linux/reset.h>
@@ -85,7 +84,7 @@ static int dwc3_get_dr_mode(struct dwc3 *dwc)
* mode. If the controller supports DRD but the dr_mode is not
* specified or set to OTG, then set the mode to peripheral.
*/
- if (mode == USB_DR_MODE_OTG && !dwc->edev &&
+ if (mode == USB_DR_MODE_OTG &&
(!IS_ENABLED(CONFIG_USB_ROLE_SWITCH) ||
!device_property_read_bool(dwc->dev, "usb-role-switch")) &&
!DWC3_VER_IS_PRIOR(DWC3, 330A))
@@ -1471,51 +1470,6 @@ static void dwc3_check_params(struct dwc3 *dwc)
}
}
-static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
-{
- struct device *dev = dwc->dev;
- struct device_node *np_phy;
- struct extcon_dev *edev = NULL;
- const char *name;
-
- if (device_property_read_bool(dev, "extcon"))
- return extcon_get_edev_by_phandle(dev, 0);
-
- /*
- * Device tree platforms should get extcon via phandle.
- * On ACPI platforms, we get the name from a device property.
- * This device property is for kernel internal use only and
- * is expected to be set by the glue code.
- */
- if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
- edev = extcon_get_extcon_dev(name);
- if (!edev)
- return ERR_PTR(-EPROBE_DEFER);
-
- return edev;
- }
-
- /*
- * Try to get an extcon device from the USB PHY controller's "port"
- * node. Check if it has the "port" node first, to avoid printing the
- * error message from underlying code, as it's a valid case: extcon
- * device (and "port" node) may be missing in case of "usb-role-switch"
- * or OTG mode.
- */
- np_phy = of_parse_phandle(dev->of_node, "phys", 0);
- if (of_graph_is_present(np_phy)) {
- struct device_node *np_conn;
-
- np_conn = of_graph_get_remote_node(np_phy, -1, -1);
- if (np_conn)
- edev = extcon_find_edev_by_node(np_conn);
- of_node_put(np_conn);
- }
- of_node_put(np_phy);
-
- return edev;
-}
-
static int dwc3_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -1616,14 +1570,6 @@ static int dwc3_probe(struct platform_device *pdev)
goto err2;
}
- dwc->edev = dwc3_get_extcon(dwc);
- if (IS_ERR(dwc->edev)) {
- ret = PTR_ERR(dwc->edev);
- dev_err_probe(dwc->dev, ret, "failed to get extcon");
-
- goto err3;
- }
-
ret = dwc3_get_dr_mode(dwc);
if (ret)
goto err3;
diff --git a/drivers/usb/dwc3/drd.c b/drivers/usb/dwc3/drd.c
index 9a414edc439a..3e1c1aacf002 100644
--- a/drivers/usb/dwc3/drd.c
+++ b/drivers/usb/dwc3/drd.c
@@ -8,6 +8,7 @@
*/
#include <linux/extcon.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/property.h>
@@ -437,6 +438,44 @@ static int dwc3_drd_notifier(struct notifier_block *nb,
return NOTIFY_DONE;
}
+static struct extcon_dev *dwc3_get_extcon(struct dwc3 *dwc)
+{
+ struct device *dev = dwc->dev;
+ struct device_node *np_phy, *np_conn;
+ struct extcon_dev *edev;
+ const char *name;
+
+ if (device_property_read_bool(dev, "extcon"))
+ return extcon_get_edev_by_phandle(dev, 0);
+
+ /*
+ * Device tree platforms should get extcon via phandle.
+ * On ACPI platforms, we get the name from a device property.
+ * This device property is for kernel internal use only and
+ * is expected to be set by the glue code.
+ */
+ if (device_property_read_string(dev, "linux,extcon-name", &name) == 0) {
+ edev = extcon_get_extcon_dev(name);
+ if (!edev)
+ return ERR_PTR(-EPROBE_DEFER);
+
+ return edev;
+ }
+
+ np_phy = of_parse_phandle(dev->of_node, "phys", 0);
+ np_conn = of_graph_get_remote_node(np_phy, -1, -1);
+
+ if (np_conn)
+ edev = extcon_find_edev_by_node(np_conn);
+ else
+ edev = NULL;
+
+ of_node_put(np_conn);
+ of_node_put(np_phy);
+
+ return edev;
+}
+
#if IS_ENABLED(CONFIG_USB_ROLE_SWITCH)
#define ROLE_SWITCH 1
static int dwc3_usb_role_switch_set(struct usb_role_switch *sw,
@@ -529,6 +568,10 @@ int dwc3_drd_init(struct dwc3 *dwc)
{
int ret, irq;
+ dwc->edev = dwc3_get_extcon(dwc);
+ if (IS_ERR(dwc->edev))
+ return PTR_ERR(dwc->edev);
+
if (ROLE_SWITCH &&
device_property_read_bool(dwc->dev, "usb-role-switch")) {
ret = dwc3_setup_role_switch(dwc);
diff --git a/include/linux/i2c-atr.h b/include/linux/i2c-atr.h
new file mode 100644
index 000000000000..e015db668f44
--- /dev/null
+++ b/include/linux/i2c-atr.h
@@ -0,0 +1,82 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * drivers/i2c/i2c-atr.h -- I2C Address Translator
+ *
+ * Copyright (c) 2019 Luca Ceresoli <luca@lucaceresoli.net>
+ *
+ * Based on i2c-mux.h
+ */
+
+#ifndef _LINUX_I2C_ATR_H
+#define _LINUX_I2C_ATR_H
+
+#ifdef __KERNEL__
+
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+
+struct i2c_atr;
+
+/**
+ * struct i2c_atr_ops - Callbacks from ATR to the device driver.
+ * @select: Ask the driver to select a child bus (optional)
+ * @deselect: Ask the driver to deselect a child bus (optional)
+ * @attach_client: Notify the driver of a new device connected on a child
+ * bus. The driver must choose an I2C alias, configure the
+ * hardware to use it and return it in `alias_id`.
+ * @detach_client: Notify the driver of a device getting disconnected. The
+ * driver must configure the hardware to stop using the
+ * alias.
+ *
+ * All these functions return 0 on success, a negative error code otherwise.
+ */
+struct i2c_atr_ops {
+ int (*select)(struct i2c_atr *atr, u32 chan_id);
+ int (*deselect)(struct i2c_atr *atr, u32 chan_id);
+ int (*attach_client)(struct i2c_atr *atr, u32 chan_id,
+ const struct i2c_board_info *info,
+ const struct i2c_client *client,
+ u16 *alias_id);
+ void (*detach_client)(struct i2c_atr *atr, u32 chan_id,
+ const struct i2c_client *client);
+};
+
+/*
+ * Helper to add I2C ATR features to a device driver.
+ */
+struct i2c_atr {
+ /* private: internal use only */
+
+ struct i2c_adapter *parent;
+ struct device *dev;
+ const struct i2c_atr_ops *ops;
+
+ void *priv;
+
+ struct i2c_algorithm algo;
+ struct mutex lock;
+ int max_adapters;
+
+ struct i2c_adapter *adapter[0];
+};
+
+struct i2c_atr *i2c_atr_new(struct i2c_adapter *parent, struct device *dev,
+ const struct i2c_atr_ops *ops, int max_adapters);
+void i2c_atr_delete(struct i2c_atr *atr);
+
+static inline void i2c_atr_set_clientdata(struct i2c_atr *atr, void *data)
+{
+ atr->priv = data;
+}
+
+static inline void *i2c_atr_get_clientdata(struct i2c_atr *atr)
+{
+ return atr->priv;
+}
+
+int i2c_atr_add_adapter(struct i2c_atr *atr, u32 chan_id);
+void i2c_atr_del_adapter(struct i2c_atr *atr, u32 chan_id);
+
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_I2C_ATR_H */
diff --git a/include/linux/i2c.h b/include/linux/i2c.h
index a670ae129f4b..752f049faae9 100644
--- a/include/linux/i2c.h
+++ b/include/linux/i2c.h
@@ -561,6 +561,21 @@ struct i2c_lock_operations {
};
/**
+ * struct i2c_attach_operations - callbacks to notify client attach/detach
+ * @attach_client: Notify of new client being attached
+ * @detach_client: Notify of new client being detached
+ *
+ * Both ops are optional.
+ */
+struct i2c_attach_operations {
+ int (*attach_client)(struct i2c_adapter *adapter,
+ const struct i2c_board_info *info,
+ const struct i2c_client *client);
+ void (*detach_client)(struct i2c_adapter *adapter,
+ const struct i2c_client *client);
+};
+
+/**
* struct i2c_timings - I2C timing information
* @bus_freq_hz: the bus frequency in Hz
* @scl_rise_ns: time SCL signal takes to rise in ns; t(r) in the I2C specification
@@ -702,6 +717,7 @@ struct i2c_adapter {
/* data fields that are valid for all devices */
const struct i2c_lock_operations *lock_ops;
+ const struct i2c_attach_operations *attach_ops;
struct rt_mutex bus_lock;
struct rt_mutex mux_lock;
diff --git a/include/media/cec.h b/include/media/cec.h
index cd35ae6b7560..208c9613c07e 100644
--- a/include/media/cec.h
+++ b/include/media/cec.h
@@ -28,8 +28,8 @@
* @minor: device node minor number
* @registered: the device was correctly registered
* @unregistered: the device was unregistered
- * @fhs_lock: lock to control access to the filehandle list
* @fhs: the list of open filehandles (cec_fh)
+ * @lock: lock to control access to this structure
*
* This structure represents a cec-related device node.
*
diff --git a/include/media/dvbdev.h b/include/media/dvbdev.h
index e547cbeee431..b04a38be5183 100644
--- a/include/media/dvbdev.h
+++ b/include/media/dvbdev.h
@@ -321,7 +321,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
int dvb_generic_open(struct inode *inode, struct file *file);
/**
- * dvb_generic_close - Digital TV close function, used by DVB devices
+ * dvb_generic_release - Digital TV close function, used by DVB devices
*
* @inode: pointer to &struct inode.
* @file: pointer to &struct file.
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index 9ecbb98908f0..de0a0820cfb2 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -1294,7 +1294,7 @@ static inline void v4l2_ctrl_request_hdl_put(struct v4l2_ctrl_handler *hdl)
}
/**
- * v4l2_ctrl_request_ctrl_find() - Find a control with the given ID.
+ * v4l2_ctrl_request_hdl_ctrl_find() - Find a control with the given ID.
*
* @hdl: The control handler from the request.
* @id: The ID of the control to find.
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index ad2d41952442..6a4afd4a7df2 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -43,8 +43,8 @@ enum vfl_devnode_type {
};
/**
- * enum vfl_direction - Identifies if a &struct video_device corresponds
- * to a receiver, a transmitter or a mem-to-mem device.
+ * enum vfl_devnode_direction - Identifies if a &struct video_device
+ * corresponds to a receiver, a transmitter or a mem-to-mem device.
*
* @VFL_DIR_RX: device is a receiver.
* @VFL_DIR_TX: device is a transmitter.
diff --git a/include/media/v4l2-device.h b/include/media/v4l2-device.h
index 64ec4de948e9..8a8977a33ec1 100644
--- a/include/media/v4l2-device.h
+++ b/include/media/v4l2-device.h
@@ -174,7 +174,7 @@ int __must_check v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd);
/**
- * __v4l2_device_register_ro_subdev_nodes - Registers device nodes for
+ * __v4l2_device_register_subdev_nodes - Registers device nodes for
* all subdevs of the v4l2 device that are marked with the
* %V4L2_SUBDEV_FL_HAS_DEVNODE flag.
*
diff --git a/include/media/v4l2-dv-timings.h b/include/media/v4l2-dv-timings.h
index 2cc0cabc124f..8fa963326bf6 100644
--- a/include/media/v4l2-dv-timings.h
+++ b/include/media/v4l2-dv-timings.h
@@ -224,7 +224,7 @@ static inline bool can_reduce_fps(struct v4l2_bt_timings *bt)
}
/**
- * struct v4l2_hdmi_rx_colorimetry - describes the HDMI colorimetry information
+ * struct v4l2_hdmi_colorimetry - describes the HDMI colorimetry information
* @colorspace: enum v4l2_colorspace, the colorspace
* @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
* @quantization: enum v4l2_quantization, colorspace quantization
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index ed0840f3d5df..c542fa53e209 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -520,7 +520,7 @@ v4l2_async_notifier_parse_fwnode_endpoints_by_port(struct device *dev,
parse_endpoint_func parse_endpoint);
/**
- * v4l2_fwnode_reference_parse_sensor_common - parse common references on
+ * v4l2_async_notifier_parse_fwnode_sensor_common - parse common references on
* sensors for async sub-devices
* @dev: the device node the properties of which are parsed for references
* @notifier: the async notifier where the async subdevs will be added
diff --git a/include/media/v4l2-h264.h b/include/media/v4l2-h264.h
index f08ba181263d..1cc89d2e693a 100644
--- a/include/media/v4l2-h264.h
+++ b/include/media/v4l2-h264.h
@@ -66,11 +66,11 @@ v4l2_h264_build_b_ref_lists(const struct v4l2_h264_reflist_builder *builder,
u8 *b0_reflist, u8 *b1_reflist);
/**
- * v4l2_h264_build_b_ref_lists() - Build the P reference list
+ * v4l2_h264_build_p_ref_list() - Build the P reference list
*
* @builder: reference list builder context
- * @p_reflist: 16-bytes array used to store the P reference list. Each entry
- * is an index in the DPB
+ * @reflist: 16-bytes array used to store the P reference list. Each entry
+ * is an index in the DPB
*
* This functions builds the P reference lists. This procedure is describe in
* section '8.2.4 Decoding process for reference picture lists construction'
diff --git a/include/media/v4l2-jpeg.h b/include/media/v4l2-jpeg.h
index ddba2a56c321..3a3344a97678 100644
--- a/include/media/v4l2-jpeg.h
+++ b/include/media/v4l2-jpeg.h
@@ -91,7 +91,9 @@ struct v4l2_jpeg_scan_header {
* struct v4l2_jpeg_header - parsed JPEG header
* @sof: pointer to frame header and size
* @sos: pointer to scan header and size
+ * @num_dht: number of entries in @dht
* @dht: pointers to huffman tables and sizes
+ * @num_dqt: number of entries in @dqt
* @dqt: pointers to quantization tables and sizes
* @frame: parsed frame header
* @scan: pointer to parsed scan header, optional
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index c20e2dc6d432..841e190aedd9 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -147,7 +147,7 @@ v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
}
/**
- * v4l2_fill_pix_format - Ancillary routine that fills a &struct
+ * v4l2_fill_mbus_format - Ancillary routine that fills a &struct
* v4l2_mbus_framefmt from a &struct v4l2_pix_format and a
* data format code.
*
@@ -170,7 +170,7 @@ static inline void v4l2_fill_mbus_format(struct v4l2_mbus_framefmt *mbus_fmt,
}
/**
- * v4l2_fill_pix_format - Ancillary routine that fills a &struct
+ * v4l2_fill_pix_format_mplane - Ancillary routine that fills a &struct
* v4l2_pix_format_mplane fields from a media bus structure.
*
* @pix_mp_fmt: pointer to &struct v4l2_pix_format_mplane to be filled
@@ -190,7 +190,7 @@ v4l2_fill_pix_format_mplane(struct v4l2_pix_format_mplane *pix_mp_fmt,
}
/**
- * v4l2_fill_pix_format - Ancillary routine that fills a &struct
+ * v4l2_fill_mbus_format_mplane - Ancillary routine that fills a &struct
* v4l2_mbus_framefmt from a &struct v4l2_pix_format_mplane.
*
* @mbus_fmt: pointer to &struct v4l2_mbus_framefmt to be filled
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index e25a304cd0c8..fdeaae7f4e44 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -693,7 +693,7 @@ struct v4l2_subdev_stream_config {
* struct v4l2_subdev_stream_configs - A collection of stream configs.
*
* @num_configs: number of entries in @config.
- * @config: an array of &struct v4l2_subdev_stream_configs.
+ * @configs: an array of &struct v4l2_subdev_stream_configs.
*/
struct v4l2_subdev_stream_configs {
u32 num_configs;
@@ -703,22 +703,20 @@ struct v4l2_subdev_stream_configs {
/**
* struct v4l2_subdev_krouting - subdev routing table
*
- * @which: format type (from enum v4l2_subdev_format_whence)
- * @routes: &struct v4l2_subdev_route
* @num_routes: number of routes
+ * @routes: &struct v4l2_subdev_route
*
- * This structure is used to translate arguments received from
- * VIDIOC_SUBDEV_G/S_ROUTING() ioctl to subdev device drivers operations.
+ * This structure contains the routing table for a subdev.
*/
struct v4l2_subdev_krouting {
- u32 which;
- struct v4l2_subdev_route *routes;
unsigned int num_routes;
+ struct v4l2_subdev_route *routes;
};
/**
- * struct v4l2_subdev_state - Used for storing subdev information.
+ * struct v4l2_subdev_state - Used for storing subdev state information.
*
+ * @lock: mutex for the state
* @pads: &struct v4l2_subdev_pad_config array
* @routing: routing table for the subdev
* @stream_configs: stream configurations (only for V4L2_SUBDEV_FL_MULTIPLEXED)
@@ -728,6 +726,7 @@ struct v4l2_subdev_krouting {
* %V4L2_SUBDEV_FORMAT_ACTIVE it is safe to pass %NULL.
*/
struct v4l2_subdev_state {
+ struct mutex lock;
struct v4l2_subdev_pad_config *pads;
struct v4l2_subdev_krouting routing;
struct v4l2_subdev_stream_configs stream_configs;
@@ -795,7 +794,6 @@ struct v4l2_subdev_state {
* pad index it has been called on is not valid or in case of
* unrecoverable failures.
*
- * @get_routing: get the subdevice routing table.
* @set_routing: enable or disable data connection routes described in the
* subdevice routing table.
*/
@@ -842,11 +840,9 @@ struct v4l2_subdev_pad_ops {
struct v4l2_mbus_config *config);
int (*set_mbus_config)(struct v4l2_subdev *sd, unsigned int pad,
struct v4l2_mbus_config *config);
- int (*get_routing)(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_krouting *route);
int (*set_routing)(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
struct v4l2_subdev_krouting *route);
};
@@ -925,7 +921,12 @@ struct v4l2_subdev_internal_ops {
/*
* Set this flag if this subdev supports multiplexed streams. This means
* that the driver supports routing and handles the stream parameter in its
- * v4l2_subdev_pad_ops handlers.
+ * v4l2_subdev_pad_ops handlers. More specifically, this means:
+ *
+ * - Centrally managed active state is enabled
+ * - Legacy pad config is _not_ supported (state->pads)
+ * - Routing ioctls are available
+ * - Multiple streams per pad are supported
*/
#define V4L2_SUBDEV_FL_MULTIPLEXED (1U << 4)
@@ -982,6 +983,8 @@ struct v4l2_subdev_platform_data {
* @subdev_notifier: A sub-device notifier implicitly registered for the sub-
* device using v4l2_device_register_sensor_subdev().
* @pdata: common part of subdevice platform data
+ * @state: active state for the subdev (NULL for subdevs tracking the state
+ * internally)
*
* Each instance of a subdev driver should create this struct, either
* stand-alone or embedded in a larger struct.
@@ -1013,6 +1016,19 @@ struct v4l2_subdev {
struct v4l2_async_notifier *notifier;
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_subdev_platform_data *pdata;
+
+ /*
+ * The fields below are private, and should only be accessed via
+ * appropriate functions.
+ */
+
+ /*
+ * TODO: state should most likely be changed from a pointer to an
+ * embedded field. For the time being it's kept as a pointer to more
+ * easily catch uses of state in the cases where the driver doesn't
+ * support it.
+ */
+ struct v4l2_subdev_state *state;
};
@@ -1071,8 +1087,8 @@ struct v4l2_subdev_fh {
* &struct v4l2_subdev_pad_config->try_fmt
*
* @sd: pointer to &struct v4l2_subdev
- * @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the @state array.
+ * @state: pointer to &struct v4l2_subdev_state
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array
*/
static inline struct v4l2_mbus_framefmt *
v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
@@ -1090,7 +1106,7 @@ v4l2_subdev_get_try_format(struct v4l2_subdev *sd,
*
* @sd: pointer to &struct v4l2_subdev
* @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the @state array.
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
*/
static inline struct v4l2_rect *
v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
@@ -1108,7 +1124,7 @@ v4l2_subdev_get_try_crop(struct v4l2_subdev *sd,
*
* @sd: pointer to &struct v4l2_subdev
* @state: pointer to &struct v4l2_subdev_state.
- * @pad: index of the pad in the @state array.
+ * @pad: index of the pad in the &struct v4l2_subdev_state->pads array.
*/
static inline struct v4l2_rect *
v4l2_subdev_get_try_compose(struct v4l2_subdev *sd,
@@ -1219,16 +1235,40 @@ int v4l2_subdev_link_validate_default(struct v4l2_subdev *sd,
int v4l2_subdev_link_validate(struct media_link *link);
/**
- * v4l2_subdev_alloc_state - allocate v4l2_subdev_state
+ * v4l2_subdev_has_route - MC has_route implementation for subdevs
*
- * Must call v4l2_subdev_free_state() when state is no longer needed.
+ * @entity: pointer to &struct media_entity
+ * @pad0: pad number for the first pad
+ * @pad1: pad number for the second pad
+ *
+ * This function looks at the routing in subdev's active state and returns if
+ * there is a route connecting pad0 and pad1.
+ *
+ * This function can be used as implementation for
+ * media_entity_operations.has_route.
*/
-struct v4l2_subdev_state *v4l2_subdev_alloc_state(struct v4l2_subdev *sd);
+bool v4l2_subdev_has_route(struct media_entity *entity, unsigned int pad0,
+ unsigned int pad1);
/**
- * v4l2_subdev_free_state - uninitialize v4l2_subdev_state
+ * __v4l2_subdev_state_alloc - allocate v4l2_subdev_state
+ *
+ * @sd: pointer to &struct v4l2_subdev for which the state is being allocated.
+ * @lock_name: name of the state lock
+ * @key: lock_class_key for the lock
+ *
+ * Must call __v4l2_subdev_state_free() when state is no longer needed.
*/
-void v4l2_subdev_free_state(struct v4l2_subdev_state *state);
+struct v4l2_subdev_state *__v4l2_subdev_state_alloc(struct v4l2_subdev *sd,
+ const char *lock_name,
+ struct lock_class_key *key);
+
+/**
+ * __v4l2_subdev_state_free - free a v4l2_subdev_state
+ *
+ * @state: v4l2_subdev_state to be freed.
+ */
+void __v4l2_subdev_state_free(struct v4l2_subdev_state *state);
#endif /* CONFIG_MEDIA_CONTROLLER */
@@ -1298,96 +1338,220 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
const struct v4l2_event *ev);
/**
- * v4l2_subdev_get_routing() - Get routing from a subdevice
+ * v4l2_subdev_init_finalize() - Finalize the initialization of the subdevice
+ * @sd: The subdev
*
- * @sd: The subdev from which to get the routing
- * @state: Pointer to &struct v4l2_subdev_state
- * @routing: Pointer to the target &struct v4l2_subdev_krouting
+ * This finalizes the initialization of the subdev, including allocation of
+ * the active state for the subdev.
*
- * Get a copy of the subdevice's routing table.
+ * This must be called by the subdev drivers that use the centralized active
+ * state, after the subdev struct has been initialized and
+ * media_entity_pads_init() has been called.
*
- * Must be freed with v4l2_subdev_free_routing after use.
+ * Must call v4l2_subdev_cleanup() when the subdev is being removed.
*/
-int v4l2_subdev_get_routing(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *state,
- struct v4l2_subdev_krouting *routing);
+#define v4l2_subdev_init_finalize(sd) \
+ ({ \
+ static struct lock_class_key __key; \
+ const char *name = KBUILD_BASENAME \
+ ":" __stringify(__LINE__) ":subdev->state->lock"; \
+ __v4l2_subdev_init_finalize(sd, name, &__key); \
+ })
+
+int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
+ struct lock_class_key *key);
/**
- * v4l2_subdev_free_routing() - Free the routing
+ * v4l2_subdev_cleanup() - Release the resources needed by the subdevice
+ * @sd: The subdevice
*
- * @routing: The routing to be freed
- *
- * Frees the routing data in @routing.
+ * This will release the resources allocated in v4l2_subdev_init_finalize.
*/
-void v4l2_subdev_free_routing(struct v4l2_subdev_krouting *routing);
+void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
/**
- * v4l2_subdev_cpy_routing() - Copy the routing
+ * v4l2_subdev_get_active_state() - Return the active subdev state for subdevice
+ * @sd: The subdevice
*
- * @dst: The destination routing
- * @src: The source routing
+ * Return the active state for the subdevice, or NULL if the subdev does not
+ * support active state.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_get_active_state(struct v4l2_subdev *sd)
+{
+ return sd->state;
+}
+
+/**
+ * v4l2_subdev_lock_active_state() - Lock and return the active subdev state for
+ * subdevice
+ * @sd: The subdevice
*
- * Copies routing from @src to @dst without allocating space. If @dst does not
- * have enough space, set dst->num_routes to the required number of routes, and
- * return -ENOSPC.
+ * Return the locked active state for the subdevice, or NULL if the subdev
+ * does not support active state.
*
- * Can be used in subdevice's v4l2_subdev_pad_ops.get_routing() callback.
+ * Must be unlocked with v4l2_subdev_unlock_state() after use.
*/
-int v4l2_subdev_cpy_routing(struct v4l2_subdev_krouting *dst,
- const struct v4l2_subdev_krouting *src);
+struct v4l2_subdev_state *v4l2_subdev_lock_active_state(struct v4l2_subdev *sd);
/**
- * v4l2_subdev_dup_routing() - Duplicate the routing
+ * v4l2_subdev_lock_state() - Lock the subdev state
+ * @state: The subdevice state
*
- * @dst: The destination routing
- * @src: The source routing
+ * Lock the given subdev state.
*
- * Makes a duplicate of the routing from @src to @dst by allocating enough
- * memory and making a copy of the routing.
+ * Must be unlocked with v4l2_subdev_unlock_state() after use.
+ */
+void v4l2_subdev_lock_state(struct v4l2_subdev_state *state);
+
+/**
+ * v4l2_subdev_unlock_state() - Unlock the subdev state
+ * @state: The subdevice state
+ *
+ * Unlock the given subdev state.
+ */
+void v4l2_subdev_unlock_state(struct v4l2_subdev_state *state);
+
+/**
+ * v4l2_subdev_validate_and_lock_state() - Gets locked TRY or ACTIVE subdev
+ * state
+ * @sd: subdevice
+ * @state: subdevice state as passed to the subdev op
+ *
+ * Due to legacy reasons, when subdev drivers call ops in other subdevs they use
+ * NULL as the state parameter, as subdevs always used to have their active
+ * state stored privately.
+ *
+ * However, newer state-aware subdev drivers, which store their active state in
+ * a common place, subdev->state, expect to always get a proper state as a
+ * parameter.
+ *
+ * These state-aware drivers can use v4l2_subdev_validate_and_lock_state()
+ * instead of v4l2_subdev_lock_state(). v4l2_subdev_validate_and_lock_state()
+ * solves the issue by using subdev->state in case the passed state is
+ * NULL.
+ *
+ * This is a temporary helper function, and should be removed when we can ensure
+ * that all drivers pass proper state when calling other subdevs.
+ */
+static inline struct v4l2_subdev_state *
+v4l2_subdev_validate_and_lock_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ state = state ? state : sd->state;
+
+ v4l2_subdev_lock_state(state);
+
+ return state;
+}
+
+/**
+ * v4l2_subdev_set_routing() - Set given routing to subdev state
+ * @sd: The subdevice
+ * @state: The subdevice state
+ * @routing: Routing that will be copied to subdev state
*
- * Can be used in subdevice's v4l2_subdev_pad_ops.set_routing() callback
- * to store the given routing.
+ * This will release old routing table (if any) from the state, allocate
+ * enough space for the given routing, and copy the routing.
*
- * Must be freed with v4l2_subdev_free_routing after use.
+ * This can be used from the subdev driver's set_routing op, after validating
+ * the routing.
*/
-int v4l2_subdev_dup_routing(struct v4l2_subdev_krouting *dst,
- const struct v4l2_subdev_krouting *src);
+int v4l2_subdev_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing);
/**
- * v4l2_subdev_has_route() - Check if there is a route between two pads
+ * v4l2_subdev_set_routing_with_fmt() - Set given routing and format to subdev
+ * state
+ * @sd: The subdevice
+ * @state: The subdevice state
+ * @routing: Routing that will be copied to subdev state
+ * @fmt: Format used to initialize all the streams
+ *
+ * This is the same as v4l2_subdev_set_routing, but additionally initializes
+ * all the streams using the given format.
+ */
+int v4l2_subdev_set_routing_with_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing,
+ const struct v4l2_mbus_framefmt *fmt);
+
+/**
+ * v4l2_state_get_stream_format() - Get pointer to a stream format
+ * @state: subdevice state
+ * @pad: pad id
+ * @stream: stream id
*
- * @routing: The subdevice's routing
- * @pad0: First pad
- * @pad1: Second pad
+ * This returns a pointer to &struct v4l2_mbus_framefmt for the given pad +
+ * stream in the subdev state.
*
- * Returns whether there is a route between @pad0 and @pad1 of the same
- * subdevice according to the given routing.
+ * If the state does not contain the given pad + stream, NULL is returned.
*/
-bool v4l2_subdev_has_route(struct v4l2_subdev_krouting *routing,
- unsigned int pad0, unsigned int pad1);
+struct v4l2_mbus_framefmt *
+v4l2_state_get_stream_format(struct v4l2_subdev_state *state, unsigned int pad,
+ u32 stream);
+/**
+ * v4l2_state_find_opposite_end() - Find the opposite stream
+ * @routing: routing used to find the opposite side
+ * @pad: pad id
+ * @stream: stream id
+ * @other_pad: pointer used to return the opposite pad
+ * @other_stream: pointer used to return the opposite stream
+ *
+ * This function uses the routing table to find the pad + stream which is
+ * opposite the given pad + stream.
+ *
+ * Returns 0 on success, or -EINVAL if no matching route is found.
+ */
+int v4l2_state_find_opposite_end(struct v4l2_subdev_krouting *routing, u32 pad,
+ u32 stream, u32 *other_pad, u32 *other_stream);
/**
- * v4l2_init_stream_configs() - Initialize stream configs according to routing
+ * v4l2_state_get_opposite_stream_format() - Get pointer to opposite stream
+ * format
+ * @state: subdevice state
+ * @pad: pad id
+ * @stream: stream id
+ *
+ * This returns a pointer to &struct v4l2_mbus_framefmt for the pad + stream
+ * that is opposite the given pad + stream in the subdev state.
+ *
+ * If the state does not contain the given pad + stream, NULL is returned.
+ */
+struct v4l2_mbus_framefmt *
+v4l2_state_get_opposite_stream_format(struct v4l2_subdev_state *state, u32 pad,
+ u32 stream);
+/**
+ * v4l2_subdev_get_fmt() - Fill format based on state
+ * @sd: subdevice
+ * @state: subdevice state
+ * @format: pointer to &struct v4l2_subdev_format
*
- * @stream_configs: The stream configs to initialize
- * @routing: The routing used for the stream configs
+ * Fill @format based on the pad and stream given in the @format struct.
*
- * Initializes @stream_configs according to @routing, allocating enough
- * space to hold configuration for each route endpoint.
+ * This function can be used by the subdev drivers to implement
+ * v4l2_subdev_pad_ops.get_fmt if the subdev driver does not need to do
+ * anything special in their get_fmt op.
*
- * Must be freed with v4l2_uninit_stream_configs().
+ * Returns 0 on success, error value otherwise.
*/
-int v4l2_init_stream_configs(struct v4l2_subdev_stream_configs *stream_configs,
- const struct v4l2_subdev_krouting *routing);
+int v4l2_subdev_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format);
/**
- * v4l2_uninit_stream_configs() - Uninitialize stream configs
+ * v4l2_routing_simple_verify() - Verify that all streams are non-overlapping
+ * 1-to-1 streams
+ * @routing: routing to verify
*
- * @stream_configs: The stream configs to uninitialize
+ * This verifies that the given routing contains only non-overlapping 1-to-1
+ * streams. In other words, no two streams have the same source or sink
+ * stream ID on a single pad. This is the most common case of routing
+ * supported by devices.
*
- * Frees any allocated memory in @stream_configs.
+ * Returns 0 on success, error value otherwise.
*/
-void v4l2_uninit_stream_configs(struct v4l2_subdev_stream_configs *stream_configs);
+int v4l2_routing_simple_verify(const struct v4l2_subdev_krouting *routing);
#endif
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index ee359c5bc74a..a92505493c47 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -1043,7 +1043,7 @@ __poll_t vb2_core_poll(struct vb2_queue *q, struct file *file,
size_t vb2_read(struct vb2_queue *q, char __user *data, size_t count,
loff_t *ppos, int nonblock);
/**
- * vb2_read() - implements write() syscall logic.
+ * vb2_write() - implements write() syscall logic.
* @q: pointer to &struct vb2_queue with videobuf2 queue.
* @data: pointed to target userspace buffer
* @count: number of bytes to write
diff --git a/include/uapi/linux/cec.h b/include/uapi/linux/cec.h
index 7d1a06c52469..dc8879d179fd 100644
--- a/include/uapi/linux/cec.h
+++ b/include/uapi/linux/cec.h
@@ -396,6 +396,7 @@ struct cec_drm_connector_info {
* associated with the CEC adapter.
* @type: connector type (if any)
* @drm: drm connector info
+ * @raw: array to pad the union
*/
struct cec_connector_info {
__u32 type;
@@ -453,7 +454,7 @@ struct cec_event_lost_msgs {
* struct cec_event - CEC event structure
* @ts: the timestamp of when the event was sent.
* @event: the event.
- * array.
+ * @flags: event flags.
* @state_change: the event payload for CEC_EVENT_STATE_CHANGE.
* @lost_msgs: the event payload for CEC_EVENT_LOST_MSGS.
* @raw: array to pad the union.
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index 41dc6c265ef1..75ef6129264d 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -44,6 +44,8 @@ enum v4l2_subdev_format_whence {
* @which: format type (from enum v4l2_subdev_format_whence)
* @pad: pad number, as reported by the media API
* @format: media bus format (format code and frame size)
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_format {
__u32 which;
@@ -58,6 +60,8 @@ struct v4l2_subdev_format {
* @which: format type (from enum v4l2_subdev_format_whence)
* @pad: pad number, as reported by the media API
* @rect: pad crop rectangle boundaries
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_crop {
__u32 which;
@@ -80,6 +84,8 @@ struct v4l2_subdev_crop {
* @code: format code (MEDIA_BUS_FMT_ definitions)
* @which: format type (from enum v4l2_subdev_format_whence)
* @flags: flags set by the driver, (V4L2_SUBDEV_MBUS_CODE_*)
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_mbus_code_enum {
__u32 pad;
@@ -93,10 +99,16 @@ struct v4l2_subdev_mbus_code_enum {
/**
* struct v4l2_subdev_frame_size_enum - Media bus format enumeration
- * @pad: pad number, as reported by the media API
* @index: format index during enumeration
+ * @pad: pad number, as reported by the media API
* @code: format code (MEDIA_BUS_FMT_ definitions)
+ * @min_width: minimum frame width, in pixels
+ * @max_width: maximum frame width, in pixels
+ * @min_height: minimum frame height, in pixels
+ * @max_height: maximum frame height, in pixels
* @which: format type (from enum v4l2_subdev_format_whence)
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_frame_size_enum {
__u32 index;
@@ -115,6 +127,8 @@ struct v4l2_subdev_frame_size_enum {
* struct v4l2_subdev_frame_interval - Pad-level frame rate
* @pad: pad number, as reported by the media API
* @interval: frame interval in seconds
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_frame_interval {
__u32 pad;
@@ -132,6 +146,8 @@ struct v4l2_subdev_frame_interval {
* @height: frame height in pixels
* @interval: frame interval in seconds
* @which: format type (from enum v4l2_subdev_format_whence)
+ * @stream: stream number, defined in subdev routing
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_subdev_frame_interval_enum {
__u32 index;
@@ -154,6 +170,7 @@ struct v4l2_subdev_frame_interval_enum {
* defined in v4l2-common.h; V4L2_SEL_TGT_* .
* @flags: constraint flags, defined in v4l2-common.h; V4L2_SEL_FLAG_*.
* @r: coordinates of the selection window
+ * @stream: stream number, defined in subdev routing
* @reserved: for future use, set to zero for now
*
* Hardware may use multiple helper windows to process a video stream.
@@ -185,24 +202,29 @@ struct v4l2_subdev_capability {
/* The v4l2 sub-device video device node is registered in read-only mode. */
#define V4L2_SUBDEV_CAP_RO_SUBDEV 0x00000001
-/**
+/* The v4l2 sub-device supports multiplexed streams. */
+#define V4L2_SUBDEV_CAP_MPLEXED 0x00000002
+
+/*
* Is the route active? An active route will start when streaming is enabled
* on a video node.
*/
-#define V4L2_SUBDEV_ROUTE_FL_ACTIVE BIT(0)
+#define V4L2_SUBDEV_ROUTE_FL_ACTIVE _BITUL(0)
-/**
+/*
* Is the route immutable, i.e. can it be activated and inactivated?
* Set by the driver.
*/
-#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE BIT(1)
+#define V4L2_SUBDEV_ROUTE_FL_IMMUTABLE _BITUL(1)
-/**
- * Is the route a source endpoint? A source endpoint route doesn't come
- * from "anywhere", and the sink_pad and sink_stream fields are unused.
+/*
+ * Is the route a source endpoint? A source endpoint route refers to a stream
+ * generated internally by the subdevice (usually a sensor), and thus there
+ * is no sink-side endpoint for the route. The sink_pad and sink_stream
+ * fields are unused.
* Set by the driver.
*/
-#define V4L2_SUBDEV_ROUTE_FL_SOURCE BIT(2)
+#define V4L2_SUBDEV_ROUTE_FL_SOURCE _BITUL(2)
/**
* struct v4l2_subdev_route - A route inside a subdev
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index c637b697af2e..50d7bc4fa6ad 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -978,8 +978,10 @@ struct v4l2_requestbuffers {
* pointing to this plane
* @fd: when memory is V4L2_MEMORY_DMABUF, a userspace file
* descriptor associated with this plane
+ * @m: union of @mem_offset, @userptr and @fd
* @data_offset: offset in the plane to the start of data; usually 0,
* unless there is a header in front of the data
+ * @reserved: drivers and applications must zero this array
*
* Multi-planar buffers consist of one or more planes, e.g. an YCbCr buffer
* with two planes can have one plane for Y, and another for interleaved CbCr
@@ -1021,10 +1023,14 @@ struct v4l2_plane {
* a userspace file descriptor associated with this buffer
* @planes: for multiplanar buffers; userspace pointer to the array of plane
* info structs for this buffer
+ * @m: union of @offset, @userptr, @planes and @fd
* @length: size in bytes of the buffer (NOT its payload) for single-plane
* buffers (when type != *_MPLANE); number of elements in the
* planes array for multi-plane buffers
+ * @reserved2: drivers and applications must zero this field
* @request_fd: fd of the request that this buffer should use
+ * @reserved: for backwards compatibility with applications that do not know
+ * about @request_fd
*
* Contains data exchanged by application and driver using one of the Streaming
* I/O methods.
@@ -1062,7 +1068,7 @@ struct v4l2_buffer {
#ifndef __KERNEL__
/**
* v4l2_timeval_to_ns - Convert timeval to nanoseconds
- * @ts: pointer to the timeval variable to be converted
+ * @tv: pointer to the timeval variable to be converted
*
* Returns the scalar nanosecond representation of the timeval
* parameter.
@@ -1123,6 +1129,7 @@ static inline __u64 v4l2_timeval_to_ns(const struct timeval *tv)
* @flags: flags for newly created file, currently only O_CLOEXEC is
* supported, refer to manual of open syscall for more details
* @fd: file descriptor associated with DMABUF (set by driver)
+ * @reserved: drivers and applications must zero this array
*
* Contains data used for exporting a video buffer as DMABUF file descriptor.
* The buffer is identified by a 'cookie' returned by VIDIOC_QUERYBUF
@@ -2216,6 +2223,7 @@ struct v4l2_mpeg_vbi_fmt_ivtv {
* this plane will be used
* @bytesperline: distance in bytes between the leftmost pixels in two
* adjacent lines
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_plane_pix_format {
__u32 sizeimage;
@@ -2234,8 +2242,10 @@ struct v4l2_plane_pix_format {
* @num_planes: number of planes for this format
* @flags: format flags (V4L2_PIX_FMT_FLAG_*)
* @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @hsv_enc: enum v4l2_hsv_encoding, HSV encoding
* @quantization: enum v4l2_quantization, colorspace quantization
* @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_pix_format_mplane {
__u32 width;
@@ -2260,6 +2270,7 @@ struct v4l2_pix_format_mplane {
* struct v4l2_sdr_format - SDR format definition
* @pixelformat: little endian four character code (fourcc)
* @buffersize: maximum size in bytes required for data
+ * @reserved: drivers and applications must zero this array
*/
struct v4l2_sdr_format {
__u32 pixelformat;
@@ -2286,6 +2297,8 @@ struct v4l2_meta_format {
* @vbi: raw VBI capture or output parameters
* @sliced: sliced VBI capture or output parameters
* @raw_data: placeholder for future extensions and custom formats
+ * @fmt: union of @pix, @pix_mp, @win, @vbi, @sliced, @sdr, @meta
+ * and @raw_data
*/
struct v4l2_format {
__u32 type;
diff --git a/ti_config_fragments/audio_display.cfg b/ti_config_fragments/audio_display.cfg
index 28635cfb35f8..32799e681905 100644
--- a/ti_config_fragments/audio_display.cfg
+++ b/ti_config_fragments/audio_display.cfg
@@ -137,6 +137,10 @@ CONFIG_VIDEO_OV1063X=m
CONFIG_VIDEO_MT9T11X=m
CONFIG_VIDEO_OV490=m
CONFIG_VIDEO_OV5640=m
+CONFIG_VIDEO_IMX390=m
+
+CONFIG_VIDEO_DS90UB960=m
+CONFIG_VIDEO_DS90UB953=m
CONFIG_MEDIA_USB_SUPPORT=y
CONFIG_USB_VIDEO_CLASS=m