summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancesco Dolcini <francesco.dolcini@toradex.com>2024-03-16 22:04:16 +0100
committerFrancesco Dolcini <francesco.dolcini@toradex.com>2024-03-16 22:04:16 +0100
commit63fefa27cfd1f1a9ec07e411029c491a5a2b62a5 (patch)
treee3fa9ca6a77a42490707192ee0944f6807565b91
parent5ad31c6933212d01edfd0f80d82326bb5f709b9f (diff)
parent1c154b1fe4c462d8b383515bb388e289816e4b01 (diff)
Merge tag '09.02.00.008' into dev/toradex_ti-linux-6.1.y-merge-09.02.00.008
RC Release 09.02.00.008
-rw-r--r--Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml87
-rw-r--r--arch/arm/configs/multi_v7_defconfig1
-rw-r--r--arch/arm64/boot/dts/ti/Makefile20
-rw-r--r--arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso68
-rw-r--r--arch/arm64/boot/dts/ti/k3-am64-main.dtsi8
-rw-r--r--arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso161
-rw-r--r--arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso156
-rw-r--r--arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso81
-rw-r--r--arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso93
-rw-r--r--arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso93
-rw-r--r--arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso93
-rw-r--r--arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso93
-rw-r--r--arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso164
-rw-r--r--arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso146
-rw-r--r--arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso173
-rw-r--r--arch/arm64/boot/dts/ti/k3-j722s-evm.dts9
-rw-r--r--arch/arm64/boot/dts/ti/k3-j722s.dtsi11
-rw-r--r--arch/arm64/configs/defconfig1
-rw-r--r--drivers/gpu/drm/bridge/sii902x.c10
-rw-r--r--drivers/media/i2c/Kconfig13
-rw-r--r--drivers/media/i2c/Makefile1
-rw-r--r--drivers/media/i2c/ox05b1s.c1139
-rw-r--r--drivers/media/platform/img/e5010/e5010-jpeg-enc.c6
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-defs.c3
-rw-r--r--drivers/mtd/spi-nor/core.c153
-rw-r--r--drivers/net/ethernet/ti/am65-cpsw-nuss.c48
-rw-r--r--drivers/net/ethernet/ti/am65-cpts.c85
-rw-r--r--drivers/net/ethernet/ti/am65-cpts.h11
-rw-r--r--drivers/net/ethernet/ti/icss_iep.c72
-rw-r--r--drivers/net/ethernet/ti/icss_iep.h72
-rw-r--r--drivers/net/ethernet/ti/icssg_config.c15
-rw-r--r--drivers/net/ethernet/ti/icssg_config.h2
-rw-r--r--drivers/net/ethernet/ti/icssg_prueth.c41
-rw-r--r--drivers/net/ethernet/ti/icssg_prueth.h1
-rw-r--r--drivers/net/ethernet/ti/icssg_qos.c3
-rw-r--r--drivers/spi/spi-cadence-quadspi.c59
-rw-r--r--include/uapi/linux/v4l2-controls.h6
-rw-r--r--net/hsr/hsr_slave.c5
38 files changed, 3047 insertions, 156 deletions
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml
new file mode 100644
index 000000000000..f84ccd4d5d91
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/ovti,ox05b.yaml
@@ -0,0 +1,87 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ox05b.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: OmniVision OX05B1S Camera Sensor
+
+maintainers:
+ - Abhishek Sharma <abhishek.sharma@ti.com>
+
+description: |-
+ Omnivision OX05B1S is an RGBIR camera sensor with an active array size of
+ 2592x1944. It is programmable through the I2C interface. The i2c client
+ address is fixed at 0x36 as per the sensor datasheet. Every alternate frame,
+ the sensor changes the exposure/gain registers to stream an -
+ A. IR-dominant frame on CSI-2 virtual channel 0
+ B. RGB-dominant frame on CSI-2 virtual channel 1
+
+ Both streams are captured at a resolution 2592x1944, 30 fps each
+ (60 fps total). The sensor also supports a few v4l2 controls like
+ exposure and gain controls.
+
+properties:
+ compatible:
+ enum:
+ - ovti,ox05b
+
+ reg:
+ description: I2C address
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ clock-names:
+ const: inck
+
+ pwdn-gpios:
+ maxItems: 1
+ description:
+ Specifier for the GPIO connected to the PWDN pin.
+
+ port:
+ $ref: /schemas/graph.yaml#/properties/port
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - clock-names
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ ox05b1s: camera@36 {
+ compatible = "ovti,ox05b";
+ reg = <0x36>;
+
+ clocks = <&clk_ox05b1s_fixed>;
+ clock-names = "inck";
+
+ pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>;
+
+ port {
+ csi2_cam0: endpoint {
+ remote-endpoint = <&csi2rx0_in_sensor>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index c979fb22bf0e..e00f4078a533 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -184,6 +184,7 @@ CONFIG_BT_MRVL_SDIO=m
CONFIG_BT_QCOMSMD=m
CONFIG_CFG80211=m
CONFIG_MAC80211=m
+CONFIG_IWLWIFI=m
CONFIG_RFKILL=y
CONFIG_RFKILL_INPUT=y
CONFIG_RFKILL_GPIO=y
diff --git a/arch/arm64/boot/dts/ti/Makefile b/arch/arm64/boot/dts/ti/Makefile
index 888ff46cef7b..2709426aea5f 100644
--- a/arch/arm64/boot/dts/ti/Makefile
+++ b/arch/arm64/boot/dts/ti/Makefile
@@ -47,6 +47,7 @@ k3-am62a7-sk-ub954-evm-ov2312-dtbs := k3-am62a7-sk.dtb \
k3-am62a7-sk-ub954-evm.dtbo \
k3-fpdlink-ov2312-0-0.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-imx219.dtb
+dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-csi2-ox05b1s.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-e3-max-opp.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-ethernet-dc01.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am62a7-sk-fusion-imx390.dtb
@@ -103,6 +104,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-ov5640.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-csi2-rpi-imx219.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-fusion.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j721e-sk-rpi-hdr-ehrpwm.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j721e-common-proc-board-infotainment.dtbo
# Boards with J721s2 SoC
dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-base-board.dtb
@@ -111,6 +113,7 @@ dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-bb-rpi-cam-imx219.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-fpdlink-fusion.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-rpi-hdr-ehrpwm.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-som-ddr-mem-carveout.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am68-sk-v3link-fusion.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j721s2-common-proc-board.dtb
dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-csi2-ov5640.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j721s2-evm-fusion.dtbo
@@ -123,14 +126,18 @@ dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-ov5640.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-rpi-cam-imx219.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-csi2-tevi-ov5640.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-dsi-rpi-7inch-panel.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-fpdlink-fusion.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-microtips-mf101hie-panel.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-j722s-evm-v3link-fusion.dtbo
# Boards with J784s4 SoC
dtb-$(CONFIG_ARCH_K3) += k3-am69-sk.dtb
dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-ov5640.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-ddr-mem-carveout.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-rpi-cam-imx219.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-csi2-v3link-fusion.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion.dtbo
+dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-fpdlink-fusion-auxport.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-am69-sk-rpi-hdr-ehrpwm.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm.dtb
dtb-$(CONFIG_ARCH_K3) += k3-j784s4-evm-csi2-ov5640.dtbo
@@ -157,7 +164,11 @@ dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-imx390-rcm-0-0.dtbo \
k3-fpdlink-imx390-rcm-1-0.dtbo \
k3-fpdlink-imx390-rcm-1-1.dtbo \
k3-fpdlink-imx390-rcm-1-2.dtbo \
- k3-fpdlink-imx390-rcm-1-3.dtbo
+ k3-fpdlink-imx390-rcm-1-3.dtbo \
+ k3-fpdlink-imx390-rcm-2-0.dtbo \
+ k3-fpdlink-imx390-rcm-2-1.dtbo \
+ k3-fpdlink-imx390-rcm-2-2.dtbo \
+ k3-fpdlink-imx390-rcm-2-3.dtbo
dtb-$(CONFIG_ARCH_K3) += k3-fpdlink-ov2312-0-0.dtbo \
k3-fpdlink-ov2312-0-1.dtbo \
k3-fpdlink-ov2312-0-2.dtbo \
@@ -179,7 +190,12 @@ DTC_FLAGS_k3-am62p5-sk += -@
DTC_FLAGS_k3-am62x-sk-csi2-v3link-fusion += -@
DTC_FLAGS_k3-am654-base-board += -@
DTC_FLAGS_k3-am68-sk-base-board += -@
+DTC_FLAGS_k3-am68-sk-fpdlink-fusion += -@
+DTC_FLAGS_k3-am68-sk-v3link-fusion += -@
DTC_FLAGS_k3-am69-sk += -@
+DTC_FLAGS_k3-am69-sk-csi2-v3link-fusion += -@
+DTC_FLAGS_k3-am69-sk-fpdlink-fusion += -@
+DTC_FLAGS_k3-am69-sk-fpdlink-fusion-auxport += -@
DTC_FLAGS_k3-j7200-common-proc-board += -@
DTC_FLAGS_k3-j721e-beagleboneai64 += -@
DTC_FLAGS_k3-j721e-common-proc-board += -@
@@ -189,5 +205,7 @@ DTC_FLAGS_k3-j721e-sk-fusion += -@
DTC_FLAGS_k3-j721s2-common-proc-board += -@
DTC_FLAGS_k3-j721s2-evm-fusion += -@
DTC_FLAGS_k3-j722s-evm += -@
+DTC_FLAGS_k3-j722s-evm-fpdlink-fusion += -@
+DTC_FLAGS_k3-j722s-evm-v3link-fusion += -@
DTC_FLAGS_k3-j784s4-evm += -@
DTC_FLAGS_k3-am642-evm += -@
diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso
new file mode 100644
index 000000000000..e82589579013
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk-csi2-ox05b1s.dtso
@@ -0,0 +1,68 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OX05B1S Camera Module
+ * Copyright (C) 2023-2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+ clk_ox05b1s_fixed: ox05b1s-xclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ };
+};
+
+&main_i2c2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ i2c-switch@71 {
+ compatible = "nxp,pca9543";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x71>;
+
+ /* CAM port */
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ ox05b1s: camera@36 {
+ compatible = "ovti,ox05b";
+ reg = <0x36>;
+
+ clocks = <&clk_ox05b1s_fixed>;
+ clock-names = "inck";
+
+ pwdn-gpios = <&exp1 13 GPIO_ACTIVE_LOW>;
+
+ port {
+ csi2_cam0: endpoint {
+ remote-endpoint = <&csi2rx0_in_sensor>;
+ link-frequencies = /bits/ 64 <480000000>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ };
+ };
+ };
+ };
+ };
+};
+
+&csi0_port0 {
+ status = "okay";
+
+ csi2rx0_in_sensor: endpoint {
+ remote-endpoint = <&csi2_cam0>;
+ bus-type = <4>; /* CSI2 DPHY. */
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
index ecf1a50f197c..2bf45e8dfde3 100644
--- a/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-am64-main.dtsi
@@ -1093,6 +1093,8 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x00 0x30000000 0x80000>;
+ assigned-clocks = <&k3_clks 81 0>;
+ assigned-clock-parents = <&k3_clks 81 2>;
icssg0_mem: memories@0 {
reg = <0x0 0x2000>,
@@ -1118,7 +1120,7 @@
clocks = <&k3_clks 81 0>, /* icssg0_core_clk */
<&k3_clks 81 20>; /* icssg0_iclk */
assigned-clocks = <&icssg0_coreclk_mux>;
- assigned-clock-parents = <&k3_clks 81 20>;
+ assigned-clock-parents = <&k3_clks 81 0>;
};
icssg0_iepclk_mux: iepclk-mux@30 {
@@ -1263,6 +1265,8 @@
#address-cells = <1>;
#size-cells = <1>;
ranges = <0x0 0x00 0x30080000 0x80000>;
+ assigned-clocks = <&k3_clks 82 0>;
+ assigned-clock-parents = <&k3_clks 82 2>;
icssg1_mem: memories@0 {
reg = <0x0 0x2000>,
@@ -1288,7 +1292,7 @@
clocks = <&k3_clks 82 0>, /* icssg1_core_clk */
<&k3_clks 82 20>; /* icssg1_iclk */
assigned-clocks = <&icssg1_coreclk_mux>;
- assigned-clock-parents = <&k3_clks 82 20>;
+ assigned-clock-parents = <&k3_clks 82 0>;
};
icssg1_iepclk_mux: iepclk-mux@30 {
diff --git a/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso
new file mode 100644
index 000000000000..04ae5d0fa1a5
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am68-sk-v3link-fusion.dtso
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DT Overlay for Arducam V3Link UC-A09 board
+ * https://www.arducam.com/fpd-link-3-cameras/
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include "k3-pinctrl.h"
+
+&{/} {
+ clk_fusion_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+};
+
+&exp3 {
+ p01-hog {
+ /* CSI_MUX_SEL_2 */
+ gpio-hog;
+ gpios = <1 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "CSI_MUX_SEL_2";
+ };
+};
+
+&main_i2c1 {
+ status = "okay";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c-switch@70 {
+ compatible = "nxp,pca9543";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x70>;
+
+ /* CAM0 I2C */
+ cam0_i2c: i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x30>;
+
+ clock-names = "refclk";
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ ds90ub960_0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ clock-lanes = <0>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+
+ /* CAM1 I2C */
+ cam1_i2c: i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x30>;
+
+ clock-names = "refclk";
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>;
+
+ ds90ub960_1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_1_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ clock-lanes = <0>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy1>;
+ };
+ };
+ };
+
+ ds90ub960_1_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+ };
+};
+
+&cdns_csi2rx0 {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi0_port0: port@0 {
+ reg = <0>;
+ status = "okay";
+
+ csi2_phy0: endpoint {
+ remote-endpoint = <&ds90ub960_0_csi_out>;
+ bus-type = <4>; /* CSI2 DPHY. */
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&cdns_csi2rx1 {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi1_port0: port@0 {
+ reg = <0>;
+ status = "okay";
+
+ csi2_phy1: endpoint {
+ remote-endpoint = <&ds90ub960_1_csi_out>;
+ bus-type = <4>; /* CSI2 DPHY. */
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+}; \ No newline at end of file
diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso
new file mode 100644
index 000000000000..988b6a6994d8
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am69-sk-csi2-v3link-fusion.dtso
@@ -0,0 +1,156 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DT Overlay for Arducam V3Link UC-A09 board
+ * https://www.arducam.com/fpd-link-3-cameras/
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+ clk_fusion_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+};
+
+&exp2 {
+ p01-hog {
+ /* P01 - CSI_MUX_SEL_2 */
+ gpio-hog;
+ gpios = <1 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "CSI_MUX_SEL_2";
+ };
+};
+
+&pca9543 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CAM0 I2C */
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x30>;
+
+ clock-names = "refclk";
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ ds90ub960_0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ clock-lanes = <0>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+
+ /* CAM1 I2C */
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x30>;
+
+ clock-names = "refclk";
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>;
+
+ ds90ub960_1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_1_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ clock-lanes = <0>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy1>;
+ };
+ };
+ };
+
+ ds90ub960_1_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+};
+
+&cdns_csi2rx0 {
+ ports {
+ port@0 {
+ status = "okay";
+
+ csi2_phy0: endpoint {
+ remote-endpoint = <&ds90ub960_0_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+}; };
+
+&cdns_csi2rx1 {
+ ports {
+ port@0 {
+ status = "okay";
+
+ csi2_phy1: endpoint {
+ remote-endpoint = <&ds90ub960_1_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&ti_csi2rx0 {
+ status = "okay";
+};
+
+&ti_csi2rx1 {
+ status = "okay";
+};
+
+&dphy_rx0 {
+ status = "okay";
+};
+
+&dphy_rx1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso
new file mode 100644
index 000000000000..e3cc0bc36703
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-am69-sk-fpdlink-fusion-auxport.dtso
@@ -0,0 +1,81 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DT Overlay for Fusion (FPD-Link III) board on AM69 SK CSI2 Aux Port
+ * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+&{/} {
+ clk_fusion1_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+};
+
+&pca9543 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ deser@3d {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x3d>;
+ clocks = <&clk_fusion1_25M_fixed>;
+ clock-names = "refclk";
+ i2c-alias-pool = <0x6a 0x6b 0x6c 0x6d 0x6e 0x6f>;
+
+ ds90ub960_2_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX*/
+ port@4 {
+ reg = <4>;
+ ds90ub960_2_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy2>;
+ };
+ };
+ };
+
+ ds90ub960_2_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+};
+
+&cdns_csi2rx2 {
+ ports {
+ port@0 {
+ status = "okay";
+
+ csi2_phy2: endpoint {
+ remote-endpoint = <&ds90ub960_2_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&ti_csi2rx2 {
+ status = "okay";
+};
+
+&dphy_rx2 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso
new file mode 100644
index 000000000000..3fc888a0d2fd
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-0.dtso
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/
+ *
+ * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&ds90ub960_2_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 0 */
+ port@0 {
+ reg = <0>;
+
+ ub960_fpd3_1_in: endpoint {
+ remote-endpoint = <&ub953_1_out>;
+ };
+ };
+};
+
+&ds90ub960_2_links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ link@0 {
+ reg = <0>;
+ i2c-alias = <0x64>;
+
+ ti,rx-mode = <3>;
+
+ serializer: serializer {
+ compatible = "ti,ds90ub953-q1";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_1_in: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&sensor_1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_1_out: endpoint {
+ remote-endpoint = <&ub960_fpd3_1_in>;
+ };
+ };
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&serializer>;
+ clock-names = "inck";
+ assigned-clocks = <&serializer>;
+ assigned-clock-rates = <27000000>;
+
+ 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_1_out: endpoint {
+ remote-endpoint = <&ub953_1_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso
new file mode 100644
index 000000000000..dc4d4ef71964
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-1.dtso
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/
+ *
+ * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&ds90ub960_2_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 1 */
+ port@1 {
+ reg = <1>;
+
+ ub960_fpd3_1_in: endpoint {
+ remote-endpoint = <&ub953_1_out>;
+ };
+ };
+};
+
+&ds90ub960_2_links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ link@1 {
+ reg = <1>;
+ i2c-alias = <0x65>;
+
+ ti,rx-mode = <3>;
+
+ serializer: serializer {
+ compatible = "ti,ds90ub953-q1";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_1_in: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&sensor_1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_1_out: endpoint {
+ remote-endpoint = <&ub960_fpd3_1_in>;
+ };
+ };
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&serializer>;
+ clock-names = "inck";
+ assigned-clocks = <&serializer>;
+ assigned-clock-rates = <27000000>;
+
+ 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_1_out: endpoint {
+ remote-endpoint = <&ub953_1_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso
new file mode 100644
index 000000000000..486b1fabe018
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-2.dtso
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/
+ *
+ * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&ds90ub960_2_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 2 */
+ port@2 {
+ reg = <2>;
+
+ ub960_fpd3_1_in: endpoint {
+ remote-endpoint = <&ub953_1_out>;
+ };
+ };
+};
+
+&ds90ub960_2_links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ link@2 {
+ reg = <2>;
+ i2c-alias = <0x66>;
+
+ ti,rx-mode = <3>;
+
+ serializer: serializer {
+ compatible = "ti,ds90ub953-q1";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_1_in: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&sensor_1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_1_out: endpoint {
+ remote-endpoint = <&ub960_fpd3_1_in>;
+ };
+ };
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&serializer>;
+ clock-names = "inck";
+ assigned-clocks = <&serializer>;
+ assigned-clock-rates = <27000000>;
+
+ 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_1_out: endpoint {
+ remote-endpoint = <&ub953_1_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso
new file mode 100644
index 000000000000..6b47107efba8
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-fpdlink-imx390-rcm-2-3.dtso
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * IMX390 FPD-Link 3 Camera Module
+ * https://www.d3engineering.co/product/designcore-d3rcm-imx390-953-rugged-camera-module/
+ *
+ * Copyright (c) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&ds90ub960_2_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* FPDLink RX 3 */
+ port@3 {
+ reg = <3>;
+
+ ub960_fpd3_1_in: endpoint {
+ remote-endpoint = <&ub953_1_out>;
+ };
+ };
+};
+
+&ds90ub960_2_links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ link@3 {
+ reg = <3>;
+ i2c-alias = <0x67>;
+
+ ti,rx-mode = <3>;
+
+ serializer: serializer {
+ compatible = "ti,ds90ub953-q1";
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ ub953_1_in: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&sensor_1_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ ub953_1_out: endpoint {
+ remote-endpoint = <&ub960_fpd3_1_in>;
+ };
+ };
+ };
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@1a {
+ compatible = "sony,imx390";
+ reg = <0x1a>;
+
+ clocks = <&serializer>;
+ clock-names = "inck";
+ assigned-clocks = <&serializer>;
+ assigned-clock-rates = <27000000>;
+
+ 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_1_out: endpoint {
+ remote-endpoint = <&ub953_1_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso
new file mode 100644
index 000000000000..65a7e54f0884
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j721e-common-proc-board-infotainment.dtso
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Infotainment Expansion Board for j721e-evm
+ * User Guide: <https://www.ti.com/lit/ug/spruit0a/spruit0a.pdf>
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - https://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "k3-pinctrl.h"
+
+&{/} {
+ hdmi-connector {
+ compatible = "hdmi-connector";
+ label = "hdmi";
+ type = "a";
+ ddc-i2c-bus = <&main_i2c1>;
+ digital;
+ /* P12 - HDMI_HPD */
+ hpd-gpios = <&exp6 10 GPIO_ACTIVE_HIGH>;
+
+ port {
+ hdmi_connector_in: endpoint {
+ remote-endpoint = <&tfp410_out>;
+ };
+ };
+ };
+
+ dvi-bridge {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "ti,tfp410";
+ /* P10 - HDMI_PDn */
+ powerdown-gpios = <&exp6 8 GPIO_ACTIVE_LOW>;
+
+ port@0 {
+ reg = <0>;
+
+ tfp410_in: endpoint {
+ remote-endpoint = <&dpi_out0>;
+ pclk-sample = <1>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tfp410_out: endpoint {
+ remote-endpoint =
+ <&hdmi_connector_in>;
+ };
+ };
+ };
+};
+
+&main_pmx0 {
+ main_i2c1_exp6_pins_default: main-i2c1-exp6-default-pins {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x264, PIN_INPUT, 7) /* (T29) MMC2_DAT2.GPIO1_24 */
+ >;
+ };
+
+ dss_vout0_pins_default: dss-vout0-default-pins {
+ pinctrl-single,pins = <
+ J721E_IOPAD(0x58, PIN_OUTPUT, 10) /* (AE22) PRG1_PRU1_GPO0.VOUT0_DATA0 */
+ J721E_IOPAD(0x5c, PIN_OUTPUT, 10) /* (AG23) PRG1_PRU1_GPO1.VOUT0_DATA1 */
+ J721E_IOPAD(0x60, PIN_OUTPUT, 10) /* (AF23) PRG1_PRU1_GPO2.VOUT0_DATA2 */
+ J721E_IOPAD(0x64, PIN_OUTPUT, 10) /* (AD23) PRG1_PRU1_GPO3.VOUT0_DATA3 */
+ J721E_IOPAD(0x68, PIN_OUTPUT, 10) /* (AH24) PRG1_PRU1_GPO4.VOUT0_DATA4 */
+ J721E_IOPAD(0x6c, PIN_OUTPUT, 10) /* (AG21) PRG1_PRU1_GPO5.VOUT0_DATA5 */
+ J721E_IOPAD(0x70, PIN_OUTPUT, 10) /* (AE23) PRG1_PRU1_GPO6.VOUT0_DATA6 */
+ J721E_IOPAD(0x74, PIN_OUTPUT, 10) /* (AC21) PRG1_PRU1_GPO7.VOUT0_DATA7 */
+ J721E_IOPAD(0x78, PIN_OUTPUT, 10) /* (Y23) PRG1_PRU1_GPO8.VOUT0_DATA8 */
+ J721E_IOPAD(0x7c, PIN_OUTPUT, 10) /* (AF21) PRG1_PRU1_GPO9.VOUT0_DATA9 */
+ J721E_IOPAD(0x80, PIN_OUTPUT, 10) /* (AB23) PRG1_PRU1_GPO10.VOUT0_DATA10 */
+ J721E_IOPAD(0x84, PIN_OUTPUT, 10) /* (AJ25) PRG1_PRU1_GPO11.VOUT0_DATA11 */
+ J721E_IOPAD(0x88, PIN_OUTPUT, 10) /* (AH25) PRG1_PRU1_GPO12.VOUT0_DATA12 */
+ J721E_IOPAD(0x8c, PIN_OUTPUT, 10) /* (AG25) PRG1_PRU1_GPO13.VOUT0_DATA13 */
+ J721E_IOPAD(0x90, PIN_OUTPUT, 10) /* (AH26) PRG1_PRU1_GPO14.VOUT0_DATA14 */
+ J721E_IOPAD(0x94, PIN_OUTPUT, 10) /* (AJ27) PRG1_PRU1_GPO15.VOUT0_DATA15 */
+ J721E_IOPAD(0x30, PIN_OUTPUT, 10) /* (AF24) PRG1_PRU0_GPO11.VOUT0_DATA16 */
+ J721E_IOPAD(0x34, PIN_OUTPUT, 10) /* (AJ24) PRG1_PRU0_GPO12.VOUT0_DATA17 */
+ J721E_IOPAD(0x38, PIN_OUTPUT, 10) /* (AG24) PRG1_PRU0_GPO13.VOUT0_DATA18 */
+ J721E_IOPAD(0x3c, PIN_OUTPUT, 10) /* (AD24) PRG1_PRU0_GPO14.VOUT0_DATA19 */
+ J721E_IOPAD(0x40, PIN_OUTPUT, 10) /* (AC24) PRG1_PRU0_GPO15.VOUT0_DATA20 */
+ J721E_IOPAD(0x44, PIN_OUTPUT, 10) /* (AE24) PRG1_PRU0_GPO16.VOUT0_DATA21 */
+ J721E_IOPAD(0x24, PIN_OUTPUT, 10) /* (AJ20) PRG1_PRU0_GPO8.VOUT0_DATA22 */
+ J721E_IOPAD(0x28, PIN_OUTPUT, 10) /* (AG20) PRG1_PRU0_GPO9.VOUT0_DATA23 */
+ J721E_IOPAD(0x9c, PIN_OUTPUT, 10) /* (AC22) PRG1_PRU1_GPO17.VOUT0_DE */
+ J721E_IOPAD(0x98, PIN_OUTPUT, 10) /* (AJ26) PRG1_PRU1_GPO16.VOUT0_HSYNC */
+ J721E_IOPAD(0xa4, PIN_OUTPUT, 10) /* (AH22) PRG1_PRU1_GPO19.VOUT0_PCLK */
+ J721E_IOPAD(0xa0, PIN_OUTPUT, 10) /* (AJ22) PRG1_PRU1_GPO18.VOUT0_VSYNC */
+ >;
+ };
+};
+
+&exp1 {
+ p14-hog {
+ /* P14 - VINOUT_MUX_SEL0 */
+ gpio-hog;
+ gpios = <12 GPIO_ACTIVE_HIGH>;
+ output-low;
+ line-name = "VINOUT_MUX_SEL0";
+ };
+
+ p15-hog {
+ /* P15 - VINOUT_MUX_SEL1 */
+ gpio-hog;
+ gpios = <13 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "VINOUT_MUX_SEL1";
+ };
+};
+
+&main_i2c1 {
+ /* i2c1 is used for DVI DDC, so we need to use 100kHz */
+ clock-frequency = <100000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ exp6: gpio@21 {
+ compatible = "ti,tca6416";
+ reg = <0x21>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&main_i2c1_exp6_pins_default>;
+ interrupt-parent = <&main_gpio1>;
+ interrupts = <24 IRQ_TYPE_EDGE_FALLING>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+
+ p11-hog {
+ /* P11 - HDMI_DDC_OE */
+ gpio-hog;
+ gpios = <9 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "HDMI_DDC_OE";
+ };
+ };
+};
+
+&dss {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dss_vout0_pins_default>;
+};
+
+&dss_ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@1 {
+ reg = <1>;
+
+ dpi_out0: endpoint {
+ remote-endpoint = <&tfp410_in>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso
new file mode 100644
index 000000000000..380a4171ee50
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-fpdlink-fusion.dtso
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DT Overlay for Fusion (FPD-Link III) board on J721E EVM
+ * https://svtronics.com/portfolio/evm577pfusion-v1-0-fusion/
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+ clk_fusion_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+};
+
+
+&pca9543_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ deser@3d {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x3d>;
+ clocks = <&clk_fusion_25M_fixed>;
+ clock-names = "refclk";
+ i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ ds90ub960_0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ deser@36 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x36>;
+ clocks = <&clk_fusion_25M_fixed>;
+ clock-names = "refclk";
+ i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>;
+
+ ds90ub960_1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_1_csi_out: endpoint {
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy1>;
+ };
+ };
+ };
+
+ ds90ub960_1_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+
+ };
+};
+
+&cdns_csi2rx0 {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi0_port0: port@0 {
+ reg = <0>;
+ status = "okay";
+
+ csi2_phy0: endpoint {
+ remote-endpoint = <&ds90ub960_0_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&cdns_csi2rx1 {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi1_port0: port@0 {
+ reg = <0>;
+ status = "okay";
+
+ csi2_phy1: endpoint {
+ remote-endpoint = <&ds90ub960_1_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&ti_csi2rx0 {
+ status = "okay";
+};
+
+&dphy0 {
+ status = "okay";
+};
+
+&ti_csi2rx1 {
+ status = "okay";
+};
+
+&dphy1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso
new file mode 100644
index 000000000000..614198ca334c
--- /dev/null
+++ b/arch/arm64/boot/dts/ti/k3-j722s-evm-v3link-fusion.dtso
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * DT Overlay for Arducam V3Link UC-A09 board
+ * https://www.arducam.com/fpd-link-3-cameras/
+ *
+ * Copyright (C) 2024 Texas Instruments Incorporated - http://www.ti.com/
+ */
+
+/dts-v1/;
+/plugin/;
+
+#include <dt-bindings/gpio/gpio.h>
+
+&{/} {
+ clk_fusion_25M_fixed: fixed-clock-25M {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
+};
+
+&exp1 {
+ p06-hog {
+ /* P06 - CSI01_MUX_SEL_2 */
+ gpio-hog;
+ gpios = <6 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "CSI01_MUX_SEL_2";
+ };
+
+ p07-hog {
+ /* P01 - CSI23_MUX_SEL_2 */
+ gpio-hog;
+ gpios = <7 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "CSI23_MUX_SEL_2";
+ };
+};
+
+&pca9543_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CAM0 I2C */
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x30>;
+
+ clock-names = "refclk";
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+ ds90ub960_0_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_0_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ clock-lanes = <0>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy0>;
+ };
+ };
+ };
+
+ ds90ub960_0_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+
+ /* CAM1 I2C */
+ i2c@1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ deser@30 {
+ compatible = "ti,ds90ub960-q1";
+ reg = <0x30>;
+
+ clock-names = "refclk";
+ clocks = <&clk_fusion_25M_fixed>;
+
+ i2c-alias-pool = <0x5a 0x5b 0x5c 0x5d 0x5e 0x5f>;
+
+ ds90ub960_1_ports: ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ /* CSI-2 TX */
+ port@4 {
+ reg = <4>;
+ ds90ub960_1_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ clock-lanes = <0>;
+ link-frequencies = /bits/ 64 <800000000>;
+ remote-endpoint = <&csi2_phy1>;
+ };
+ };
+ };
+
+ ds90ub960_1_links: links {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+ };
+ };
+};
+
+&cdns_csi2rx0 {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi0_port0: port@0 {
+ reg = <0>;
+ status = "okay";
+
+ csi2_phy0: endpoint {
+ remote-endpoint = <&ds90ub960_0_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&cdns_csi2rx1 {
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ csi1_port0: port@0 {
+ reg = <0>;
+ status = "okay";
+
+ csi2_phy1: endpoint {
+ remote-endpoint = <&ds90ub960_1_csi_out>;
+ clock-lanes = <0>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <800000000>;
+ };
+ };
+ };
+};
+
+&ti_csi2rx0 {
+ status = "okay";
+};
+
+&dphy0 {
+ status = "okay";
+};
+
+&ti_csi2rx1 {
+ status = "okay";
+};
+
+&dphy1 {
+ status = "okay";
+};
diff --git a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
index 85340a77fef6..26257e7989f4 100644
--- a/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
+++ b/arch/arm64/boot/dts/ti/k3-j722s-evm.dts
@@ -231,6 +231,7 @@
&main_pmx0 {
+ /delete-property/ interrupts;
main_i2c0_pins_default: main-i2c0-default-pins {
pinctrl-single,pins = <
J722S_IOPAD(0x01e0, PIN_INPUT_PULLUP, 0) /* (D23) I2C0_SCL */
@@ -525,6 +526,14 @@
output-low;
line-name = "GPIO_OLDI_RSTn";
};
+
+ p05-hog {
+ /* P05 - HDMI_LS_OE */
+ gpio-hog;
+ gpios = <5 GPIO_ACTIVE_HIGH>;
+ output-high;
+ line-name = "HDMI_LS_OE";
+ };
};
sii9022: bridge-hdmi@3b {
diff --git a/arch/arm64/boot/dts/ti/k3-j722s.dtsi b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
index 9a1ba152901f..93c62289cebb 100644
--- a/arch/arm64/boot/dts/ti/k3-j722s.dtsi
+++ b/arch/arm64/boot/dts/ti/k3-j722s.dtsi
@@ -519,6 +519,17 @@
status = "disabled";
};
+ e5010: e5010@fd20000 {
+ compatible = "img,e5010-jpeg-enc";
+ reg = <0x00 0xfd20000 0x00 0x100>,
+ <0x00 0xfd20200 0x00 0x200>;
+ reg-names = "regjasper", "regmmu";
+ clocks = <&k3_clks 201 0>;
+ clock-names = "core_clk";
+ power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
};
/* MCU domain overrides */
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index e1a1100b1ce1..9e971106ddd3 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -790,6 +790,7 @@ CONFIG_VIDEO_IMX390=m
CONFIG_VIDEO_OV2312=m
CONFIG_VIDEO_OV5640=m
CONFIG_VIDEO_OV5645=m
+CONFIG_VIDEO_OX05B1S=m
CONFIG_VIDEO_DS90UB953=m
CONFIG_VIDEO_DS90UB960=m
CONFIG_DRM=m
diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c
index bc48919b0a16..cf2af687dda3 100644
--- a/drivers/gpu/drm/bridge/sii902x.c
+++ b/drivers/gpu/drm/bridge/sii902x.c
@@ -163,6 +163,10 @@
#define SII902X_AUDIO_PORT_INDEX 3
+/* drm_display_mode clock is in kHz */
+#define SII902X_MIN_PIXEL_CLOCK 25000
+#define SII902X_MAX_PIXEL_CLOCK 165000
+
struct sii902x {
struct i2c_client *i2c;
struct regmap *regmap;
@@ -322,7 +326,11 @@ static int sii902x_get_modes(struct drm_connector *connector)
static enum drm_mode_status sii902x_mode_valid(struct drm_connector *connector,
struct drm_display_mode *mode)
{
- /* TODO: check mode */
+ if (mode->clock < SII902X_MIN_PIXEL_CLOCK)
+ return MODE_CLOCK_LOW;
+
+ if (mode->clock > SII902X_MAX_PIXEL_CLOCK)
+ return MODE_CLOCK_HIGH;
return MODE_OK;
}
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 3410f5093a9b..d97cd1924e19 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -720,6 +720,19 @@ config VIDEO_OV9734
To compile this driver as a module, choose M here: the
module's name is ov9734.
+config VIDEO_OX05B1S
+ tristate "OmniVision OX05B1S sensor support"
+ depends on OF_GPIO
+ depends on I2C && VIDEO_DEV
+ select MEDIA_CONTROLLER
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ This is a Video4Linux2 sensor driver for the OmniVision
+ OX05B1S camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called OX05B1S.
+
config VIDEO_RDACM20
tristate "IMI RDACM20 camera support"
depends on I2C
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index 0b1e811b4c13..aea3f7e03bfe 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -105,6 +105,7 @@ obj-$(CONFIG_VIDEO_OV9282) += ov9282.o
obj-$(CONFIG_VIDEO_OV9640) += ov9640.o
obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
obj-$(CONFIG_VIDEO_OV9734) += ov9734.o
+obj-$(CONFIG_VIDEO_OX05B1S) += ox05b1s.o
obj-$(CONFIG_VIDEO_RDACM20) += rdacm20.o
obj-$(CONFIG_VIDEO_RDACM21) += rdacm21.o
obj-$(CONFIG_VIDEO_RJ54N1) += rj54n1cb0c.o
diff --git a/drivers/media/i2c/ox05b1s.c b/drivers/media/i2c/ox05b1s.c
new file mode 100644
index 000000000000..ab0c828e3948
--- /dev/null
+++ b/drivers/media/i2c/ox05b1s.c
@@ -0,0 +1,1139 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OmniVision OX05B1S RGB-IR Image Sensor driver
+ *
+ * Copyright (c) 2023-2024 Abhishek Sharma <abhishek.sharma@ti.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/types.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-ctrls.h>
+
+#include <linux/media-bus-format.h>
+
+#define OX05B_CHIP_ID 0x0558
+#define OX05B_FRAMERATE_DEFAULT 60
+
+#define OX05B_OUT_WIDTH 2592
+#define OX05B_OUT_HEIGHT 1944
+
+#define OX05B_SYS_MODE_SEL 0x0100
+#define OX05B_SC_CHIP_ID_HI 0x300a
+#define OX05B_AEC_PK_EXPO_HI 0x3501
+#define OX05B_AEC_PK_EXPO_LO 0x3502
+#define OX05B_AEC_PK_AGAIN_HI 0x3508
+#define OX05B_AEC_PK_AGAIN_LO 0x3509
+#define OX05B_AEC_PK_DGAIN_HI 0x350a
+#define OX05B_AEC_PK_DGAIN_LO 0x350b
+#define OX05B_DEFAULT_LINK_FREQ 480000000
+
+/*
+ * Exposure control
+ * Set max value as 0x850 (frame length = 2128) - 30 = 0x0832 for 16.66 ms exposure
+ * Set default value to be 1000 (0x03E8).
+ */
+#define OX05B_EXPOSURE_MAX 0x0832
+#define OX05B_EXPOSURE_DEFAULT 0x03E8
+
+/* Analog gain control */
+#define OX05B_AGAIN_MAX 0x0F80
+#define OX05B_AGAIN_DEFAULT 0x010
+
+/* Digital gain control */
+#define OX05B_DGAIN_MAX 0x0FFF
+#define OX05B_DGAIN_DEFAULT 0x0100
+
+static const struct v4l2_area ox05b_framesizes[] = {
+ {
+ .width = OX05B_OUT_WIDTH,
+ .height = OX05B_OUT_HEIGHT,
+ },
+};
+
+static const u32 ox05b_mbus_formats[] = {
+ MEDIA_BUS_FMT_SBGGI10_1X10,
+};
+
+static const struct regmap_config ox05b_regmap_config = {
+ .reg_bits = 16,
+ .val_bits = 8,
+};
+
+static const s64 ox05b_link_freq_menu[] = {
+ OX05B_DEFAULT_LINK_FREQ,
+};
+
+static const struct reg_sequence ox05b_linear_2592x1944[] = {
+ {0x0107, 0x01}, {0x0104, 0x00}, {0x0301, 0x1a}, {0x0304, 0x01},
+ {0x0305, 0xe0}, {0x0306, 0x04}, {0x0307, 0x01}, {0x0321, 0x03},
+ {0x0324, 0x01}, {0x0325, 0x80}, {0x0341, 0x03}, {0x0344, 0x01},
+ {0x0345, 0xb0}, {0x0347, 0x07}, {0x034b, 0x06}, {0x0360, 0x80},
+ {0x040b, 0x5c}, {0x040c, 0xcd}, {0x2805, 0xff}, {0x2806, 0x0f},
+ {0x3000, 0x00}, {0x3001, 0x00}, {0x3002, 0x10}, {0x3004, 0x00},
+ {0x3009, 0x2e}, {0x3010, 0x41}, {0x3015, 0xf0}, {0x3016, 0xf0},
+ {0x3017, 0xf0}, {0x3018, 0xf0}, {0x301a, 0x78}, {0x301b, 0xb4},
+ {0x301f, 0xe9}, {0x3024, 0x80}, {0x302b, 0x00}, {0x3039, 0x00},
+ {0x3044, 0x70}, {0x3101, 0x32}, {0x3182, 0x10}, {0x3187, 0xff},
+ {0x320a, 0x00}, {0x320b, 0x00}, {0x320c, 0x00}, {0x320d, 0x00},
+ {0x320e, 0x00}, {0x320f, 0x00}, {0x3211, 0x61}, {0x3212, 0x00},
+ {0x3215, 0xcc}, {0x3218, 0x06}, {0x3251, 0x00}, {0x3252, 0xe4},
+ {0x3253, 0x00}, {0x3304, 0x11}, {0x3305, 0x00}, {0x3306, 0x01},
+ {0x3307, 0x00}, {0x3308, 0x02}, {0x3309, 0x00}, {0x330a, 0x02},
+ {0x330b, 0x00}, {0x330c, 0x02}, {0x330d, 0x00}, {0x330e, 0x02},
+ {0x330f, 0x00}, {0x3310, 0x02}, {0x3311, 0x00}, {0x3312, 0x02},
+ {0x3313, 0x00}, {0x3314, 0x02}, {0x3315, 0x00}, {0x3316, 0x02},
+ {0x3317, 0x11}, {0x3400, 0x0c}, {0x3421, 0x00}, {0x3422, 0x00},
+ {0x3423, 0x00}, {0x3424, 0x00}, {0x3425, 0x00}, {0x3426, 0x00},
+ {0x3427, 0x00}, {0x3428, 0x00}, {0x3429, 0x00}, {0x342a, 0x00},
+ {0x342b, 0x00}, {0x342c, 0x00}, {0x342d, 0x00}, {0x342e, 0x00},
+ {0x3500, 0x00}, {0x3501, 0x00}, {0x3502, 0x08}, {0x3503, 0xa8},
+ {0x3504, 0x08}, {0x3505, 0x00}, {0x3506, 0x00}, {0x3507, 0x00},
+ {0x3508, 0x01}, {0x3509, 0x00}, {0x350a, 0x01}, {0x350b, 0x00},
+ {0x350c, 0x00}, {0x351e, 0x00}, {0x351f, 0x00}, {0x3541, 0x00},
+ {0x3542, 0x08}, {0x3603, 0x65}, {0x3604, 0x24}, {0x3608, 0x08},
+ {0x3610, 0x00}, {0x3612, 0x00}, {0x3619, 0x09}, {0x361a, 0x27},
+ {0x3620, 0x40}, {0x3622, 0x15}, {0x3623, 0x0e}, {0x3624, 0x1f},
+ {0x3625, 0x1f}, {0x362a, 0x01}, {0x362b, 0x00}, {0x3633, 0x88},
+ {0x3634, 0x86}, {0x3636, 0x80}, {0x3638, 0x5b}, {0x363b, 0x22},
+ {0x363c, 0x07}, {0x363d, 0x11}, {0x363e, 0x21}, {0x363f, 0x24},
+ {0x3640, 0xd3}, {0x3641, 0x00}, {0x3650, 0xe4}, {0x3651, 0x80},
+ {0x3652, 0xff}, {0x3653, 0x00}, {0x3654, 0x05}, {0x3655, 0xf8},
+ {0x3656, 0x00}, {0x3660, 0x00}, {0x3664, 0x00}, {0x366a, 0x80},
+ {0x366b, 0x00}, {0x3670, 0x00}, {0x3674, 0x00}, {0x3684, 0x6d},
+ {0x3685, 0x6d}, {0x3686, 0x6d}, {0x3687, 0x6d}, {0x368c, 0x07},
+ {0x368d, 0x07}, {0x368e, 0x07}, {0x368f, 0x07}, {0x3690, 0x04},
+ {0x3691, 0x04}, {0x3692, 0x04}, {0x3693, 0x04}, {0x3698, 0x00},
+ {0x369e, 0x1f}, {0x369f, 0x19}, {0x36a0, 0x05}, {0x36a2, 0x19},
+ {0x36a3, 0x05}, {0x36a4, 0x07}, {0x36a5, 0x27}, {0x36a6, 0x00},
+ {0x36a7, 0x80}, {0x36e3, 0x09}, {0x3700, 0x07}, {0x3701, 0x1b},
+ {0x3702, 0x0a}, {0x3703, 0x21}, {0x3704, 0x19}, {0x3705, 0x07},
+ {0x3706, 0x36}, {0x370a, 0x1c}, {0x370b, 0x02}, {0x370c, 0x00},
+ {0x370d, 0x6e}, {0x370f, 0x80}, {0x3710, 0x10}, {0x3712, 0x09},
+ {0x3714, 0x42}, {0x3715, 0x00}, {0x3716, 0x02}, {0x3717, 0xa2},
+ {0x3718, 0x41}, {0x371a, 0x80}, {0x371b, 0x0a}, {0x371c, 0x0a},
+ {0x371d, 0x08}, {0x371e, 0x01}, {0x371f, 0x20}, {0x3720, 0x0e},
+ {0x3721, 0x22}, {0x3722, 0x0c}, {0x3727, 0x84}, {0x3728, 0x03},
+ {0x3729, 0x64}, {0x372a, 0x0c}, {0x372b, 0x14}, {0x372d, 0x50},
+ {0x372e, 0x14}, {0x3731, 0x11}, {0x3732, 0x24}, {0x3733, 0x00},
+ {0x3734, 0x00}, {0x3735, 0x12}, {0x3736, 0x00}, {0x373b, 0x0b},
+ {0x373c, 0x14}, {0x373f, 0x3e}, {0x3740, 0x12}, {0x3741, 0x12},
+ {0x3753, 0x80}, {0x3754, 0x01}, {0x3756, 0x11}, {0x375c, 0x0f},
+ {0x375d, 0x35}, {0x375e, 0x0f}, {0x375f, 0x37}, {0x3760, 0x0f},
+ {0x3761, 0x27}, {0x3762, 0x3f}, {0x3763, 0x5d}, {0x3764, 0x01},
+ {0x3765, 0x17}, {0x3766, 0x02}, {0x3768, 0x52}, {0x376a, 0x30},
+ {0x376b, 0x02}, {0x376c, 0x08}, {0x376d, 0x2a}, {0x376e, 0x00},
+ {0x376f, 0x18}, {0x3770, 0x2c}, {0x3771, 0x0c}, {0x3776, 0xc0},
+ {0x3778, 0x00}, {0x3779, 0x80}, {0x377a, 0x00}, {0x377d, 0x14},
+ {0x377e, 0x0c}, {0x379f, 0x00}, {0x37a3, 0x40}, {0x37a4, 0x03},
+ {0x37a5, 0x10}, {0x37a6, 0x02}, {0x37a7, 0x0e}, {0x37a9, 0x00},
+ {0x37aa, 0x08}, {0x37ab, 0x08}, {0x37ac, 0x36}, {0x37ad, 0x40},
+ {0x37b0, 0x48}, {0x37d0, 0x00}, {0x37d1, 0x0b}, {0x37d2, 0x0c},
+ {0x37d3, 0x10}, {0x37d4, 0x10}, {0x37d5, 0x10}, {0x37d8, 0x0e},
+ {0x37d9, 0x0e}, {0x37da, 0x3c}, {0x37db, 0x52}, {0x37dc, 0x50},
+ {0x37dd, 0x00}, {0x37de, 0x55}, {0x37df, 0x7d}, {0x37e5, 0x88},
+ {0x37e7, 0x68}, {0x37e8, 0x07}, {0x37f0, 0x00}, {0x37f1, 0x0e},
+ {0x37f2, 0x35}, {0x37f3, 0x14}, {0x37f4, 0x0c}, {0x37f5, 0x14},
+ {0x37f6, 0x0c}, {0x37f7, 0x35}, {0x37f8, 0x35}, {0x37f9, 0x37},
+ {0x37fa, 0x37}, {0x37fb, 0x37}, {0x3800, 0x00}, {0x3801, 0x00},
+ {0x3802, 0x00}, {0x3803, 0x00}, {0x3804, 0x0a}, {0x3805, 0x2f},
+ {0x3806, 0x07}, {0x3807, 0xa7}, {0x3808, 0x0a}, {0x3809, 0x20},
+ {0x380a, 0x07}, {0x380b, 0x98}, {0x380c, 0x01}, {0x380d, 0x78},
+ {0x380e, 0x08}, {0x380f, 0x50}, {0x3810, 0x00}, {0x3811, 0x05},
+ {0x3812, 0x00}, {0x3813, 0x08}, {0x3814, 0x11}, {0x3815, 0x11},
+ {0x3820, 0x40}, {0x3821, 0x04}, {0x3822, 0x10}, {0x3823, 0x00},
+ {0x3826, 0x00}, {0x3827, 0x00}, {0x382b, 0x03}, {0x382c, 0x0c},
+ {0x382d, 0x15}, {0x382e, 0x01}, {0x3830, 0x00}, {0x3838, 0x00},
+ {0x383b, 0x00}, {0x3840, 0x00}, {0x384a, 0xa2}, {0x3858, 0x00},
+ {0x3859, 0x00}, {0x3860, 0x00}, {0x3861, 0x00}, {0x3866, 0x10},
+ {0x3867, 0x07}, {0x3868, 0x01}, {0x3869, 0x01}, {0x386a, 0x01},
+ {0x386b, 0x01}, {0x386c, 0x46}, {0x386d, 0x07}, {0x386e, 0xd2},
+ {0x3871, 0x01}, {0x3872, 0x01}, {0x3873, 0x01}, {0x3874, 0x01},
+ {0x3880, 0x00}, {0x3881, 0x00}, {0x3882, 0x00}, {0x3883, 0x00},
+ {0x3884, 0x00}, {0x3885, 0x00}, {0x3886, 0x00}, {0x3887, 0x00},
+ {0x3888, 0x00}, {0x3889, 0x00}, {0x3900, 0x13}, {0x3901, 0x19},
+ {0x3902, 0x05}, {0x3903, 0x00}, {0x3904, 0x00}, {0x3908, 0x00},
+ {0x3909, 0x18}, {0x390a, 0x00}, {0x390b, 0x11}, {0x390c, 0x15},
+ {0x390d, 0x84}, {0x390f, 0x88}, {0x3910, 0x00}, {0x3911, 0x00},
+ {0x3912, 0x03}, {0x3913, 0x62}, {0x3914, 0x00}, {0x3915, 0x06},
+ {0x3916, 0x0c}, {0x3917, 0x81}, {0x3918, 0xc8}, {0x3919, 0x94},
+ {0x391a, 0x17}, {0x391b, 0x05}, {0x391c, 0x81}, {0x391d, 0x05},
+ {0x391e, 0x81}, {0x391f, 0x05}, {0x3920, 0x81}, {0x3921, 0x14},
+ {0x3922, 0x0b}, {0x3929, 0x00}, {0x392a, 0x00}, {0x392b, 0xc8},
+ {0x392c, 0x81}, {0x392f, 0x00}, {0x3930, 0x00}, {0x3931, 0x00},
+ {0x3932, 0x00}, {0x3933, 0x00}, {0x3934, 0x1b}, {0x3935, 0xc0},
+ {0x3936, 0x1c}, {0x3937, 0x21}, {0x3938, 0x0d}, {0x3939, 0x92},
+ {0x393a, 0x85}, {0x393b, 0x8a}, {0x393c, 0x06}, {0x393d, 0x8b},
+ {0x393e, 0x0f}, {0x393f, 0x14}, {0x3940, 0x0f}, {0x3941, 0x14},
+ {0x3945, 0xc0}, {0x3946, 0x05}, {0x3947, 0xc0}, {0x3948, 0x01},
+ {0x3949, 0x00}, {0x394a, 0x00}, {0x394b, 0x0b}, {0x394c, 0x0c},
+ {0x394d, 0x0b}, {0x394e, 0x09}, {0x3951, 0xc7}, {0x3952, 0x0f},
+ {0x3953, 0x0f}, {0x3954, 0x0f}, {0x3955, 0x00}, {0x3956, 0x27},
+ {0x3957, 0x27}, {0x3958, 0x27}, {0x3959, 0x01}, {0x395a, 0x02},
+ {0x395b, 0x14}, {0x395c, 0x36}, {0x395e, 0xc0}, {0x3964, 0x55},
+ {0x3965, 0x55}, {0x3966, 0x88}, {0x3967, 0x88}, {0x3968, 0x66},
+ {0x3969, 0x66}, {0x396d, 0x80}, {0x396e, 0xff}, {0x396f, 0x10},
+ {0x3970, 0x80}, {0x3971, 0x80}, {0x3972, 0x00}, {0x397a, 0x55},
+ {0x397b, 0x10}, {0x397c, 0x10}, {0x397d, 0x10}, {0x397e, 0x10},
+ {0x3980, 0xfc}, {0x3981, 0xfc}, {0x3982, 0x66}, {0x3983, 0xfc},
+ {0x3984, 0xfc}, {0x3985, 0x66}, {0x3986, 0x00}, {0x3987, 0x00},
+ {0x3988, 0x00}, {0x3989, 0x00}, {0x398a, 0x00}, {0x398b, 0x00},
+ {0x398c, 0x00}, {0x398d, 0x00}, {0x398e, 0x00}, {0x398f, 0x00},
+ {0x3990, 0x00}, {0x3991, 0x00}, {0x3992, 0x00}, {0x3993, 0x00},
+ {0x3994, 0x00}, {0x3995, 0x00}, {0x3996, 0x00}, {0x3997, 0x0f},
+ {0x3998, 0x0c}, {0x3999, 0x0c}, {0x399a, 0x0c}, {0x399b, 0xf0},
+ {0x399c, 0x14}, {0x399d, 0x0d}, {0x399e, 0x00}, {0x399f, 0x0c},
+ {0x39a0, 0x0c}, {0x39a1, 0x0c}, {0x39a2, 0x00}, {0x39a3, 0x0f},
+ {0x39a4, 0x0c}, {0x39a5, 0x0c}, {0x39a6, 0x0c}, {0x39a7, 0x0c},
+ {0x39a8, 0x0f}, {0x39a9, 0xff}, {0x39aa, 0xbf}, {0x39ab, 0x3f},
+ {0x39ac, 0x7e}, {0x39ad, 0xff}, {0x39ae, 0x00}, {0x39af, 0x00},
+ {0x39b0, 0x00}, {0x39b1, 0x00}, {0x39b2, 0x00}, {0x39b3, 0x00},
+ {0x39b4, 0x00}, {0x39b5, 0x00}, {0x39b6, 0x00}, {0x39b7, 0x00},
+ {0x39b8, 0x00}, {0x39b9, 0x00}, {0x39ba, 0x00}, {0x39bb, 0x00},
+ {0x39bc, 0x00}, {0x39c2, 0x00}, {0x39c3, 0x00}, {0x39c4, 0x00},
+ {0x39c5, 0x00}, {0x39c7, 0x00}, {0x39c8, 0x00}, {0x39c9, 0x00},
+ {0x39ca, 0x01}, {0x39cb, 0x00}, {0x39cc, 0x85}, {0x39cd, 0x09},
+ {0x39cf, 0x04}, {0x39d0, 0x85}, {0x39d1, 0x09}, {0x39d2, 0x04},
+ {0x39d4, 0x02}, {0x39d5, 0x0e}, {0x39db, 0x00}, {0x39dc, 0x01},
+ {0x39dd, 0x0c}, {0x39e5, 0xff}, {0x39e6, 0xff}, {0x39fa, 0x38},
+ {0x39fb, 0x07}, {0x39ff, 0x00}, {0x3a05, 0x00}, {0x3a06, 0x07},
+ {0x3a07, 0x0d}, {0x3a08, 0x08}, {0x3a09, 0xb2}, {0x3a0a, 0x0a},
+ {0x3a0b, 0x3c}, {0x3a0c, 0x0b}, {0x3a0d, 0xe1}, {0x3a0e, 0x03},
+ {0x3a0f, 0x85}, {0x3a10, 0x0b}, {0x3a11, 0xff}, {0x3a12, 0x00},
+ {0x3a13, 0x01}, {0x3a14, 0x0c}, {0x3a15, 0x04}, {0x3a17, 0x09},
+ {0x3a18, 0x20}, {0x3a19, 0x09}, {0x3a1a, 0x9d}, {0x3a1b, 0x09},
+ {0x3a1e, 0x34}, {0x3a1f, 0x09}, {0x3a20, 0x89}, {0x3a21, 0x09},
+ {0x3a48, 0xbe}, {0x3a52, 0x00}, {0x3a53, 0x01}, {0x3a54, 0x0c},
+ {0x3a55, 0x04}, {0x3a58, 0x0c}, {0x3a59, 0x04}, {0x3a5a, 0x01},
+ {0x3a5b, 0x00}, {0x3a5c, 0x01}, {0x3a5d, 0xe8}, {0x3a62, 0x03},
+ {0x3a63, 0x86}, {0x3a64, 0x0b}, {0x3a65, 0xbe}, {0x3a6a, 0xdc},
+ {0x3a6b, 0x0b}, {0x3a6c, 0x1a}, {0x3a6d, 0x06}, {0x3a6e, 0x01},
+ {0x3a6f, 0x04}, {0x3a70, 0xdc}, {0x3a71, 0x0b}, {0x3a83, 0x10},
+ {0x3a84, 0x00}, {0x3a85, 0x08}, {0x3a87, 0x00}, {0x3a88, 0x6b},
+ {0x3a89, 0x01}, {0x3a8a, 0x53}, {0x3a8f, 0x00}, {0x3a90, 0x00},
+ {0x3a91, 0x00}, {0x3a92, 0x00}, {0x3a93, 0x60}, {0x3a94, 0xea},
+ {0x3a98, 0x00}, {0x3a99, 0x31}, {0x3a9a, 0x01}, {0x3a9b, 0x04},
+ {0x3a9c, 0xdc}, {0x3a9d, 0x0b}, {0x3aa4, 0x0f}, {0x3aad, 0x00},
+ {0x3aae, 0x3e}, {0x3aaf, 0x02}, {0x3ab0, 0x77}, {0x3ab2, 0x00},
+ {0x3ab3, 0x08}, {0x3ab6, 0x0b}, {0x3ab7, 0xff}, {0x3aba, 0x0b},
+ {0x3abb, 0xfa}, {0x3abd, 0x05}, {0x3abe, 0x09}, {0x3abf, 0x1e},
+ {0x3ac0, 0x00}, {0x3ac1, 0x63}, {0x3ac2, 0x01}, {0x3ac3, 0x55},
+ {0x3ac8, 0x00}, {0x3ac9, 0x2a}, {0x3aca, 0x01}, {0x3acb, 0x36},
+ {0x3acc, 0x00}, {0x3acd, 0x6f}, {0x3ad0, 0x00}, {0x3ad1, 0x79},
+ {0x3ad2, 0x02}, {0x3ad3, 0x59}, {0x3ad4, 0x06}, {0x3ad5, 0x5a},
+ {0x3ad6, 0x08}, {0x3ad7, 0x3a}, {0x3ad8, 0x00}, {0x3ad9, 0x79},
+ {0x3ada, 0x02}, {0x3adb, 0x59}, {0x3adc, 0x09}, {0x3add, 0x89},
+ {0x3ade, 0x0b}, {0x3adf, 0x69}, {0x3ae0, 0x03}, {0x3ae1, 0xc1},
+ {0x3ae2, 0x0b}, {0x3ae3, 0xaf}, {0x3ae4, 0x00}, {0x3ae5, 0x3e},
+ {0x3ae6, 0x02}, {0x3ae7, 0x77}, {0x3ae8, 0x00}, {0x3aea, 0x0b},
+ {0x3aeb, 0xbe}, {0x3aee, 0x08}, {0x3aef, 0x80}, {0x3af0, 0x09},
+ {0x3af1, 0x70}, {0x3af2, 0x08}, {0x3af3, 0x94}, {0x3af4, 0x09},
+ {0x3af5, 0x5c}, {0x3af6, 0x03}, {0x3af7, 0x85}, {0x3af8, 0x08},
+ {0x3af9, 0x80}, {0x3afa, 0x0b}, {0x3afb, 0xaf}, {0x3afc, 0x01},
+ {0x3afd, 0x5a}, {0x3b1e, 0x00}, {0x3b20, 0xa5}, {0x3b21, 0x00},
+ {0x3b22, 0x00}, {0x3b23, 0x00}, {0x3b24, 0x05}, {0x3b25, 0x00},
+ {0x3b26, 0x00}, {0x3b27, 0x00}, {0x3b28, 0x1a}, {0x3b2f, 0x40},
+ {0x3b40, 0x08}, {0x3b41, 0x70}, {0x3b42, 0x05}, {0x3b43, 0xf0},
+ {0x3b44, 0x01}, {0x3b45, 0x54}, {0x3b46, 0x01}, {0x3b47, 0x54},
+ {0x3b56, 0x08}, {0x3b80, 0x00}, {0x3b81, 0x00}, {0x3b82, 0x64},
+ {0x3b83, 0x00}, {0x3b84, 0x00}, {0x3b85, 0x64}, {0x3b9d, 0x61},
+ {0x3ba8, 0x38}, {0x3c11, 0x33}, {0x3c12, 0x3d}, {0x3c13, 0x00},
+ {0x3c14, 0xbe}, {0x3c15, 0x0b}, {0x3c16, 0xa8}, {0x3c17, 0x03},
+ {0x3c18, 0x9c}, {0x3c19, 0x0b}, {0x3c1a, 0x0f}, {0x3c1b, 0x97},
+ {0x3c1c, 0x00}, {0x3c1d, 0x3c}, {0x3c1e, 0x02}, {0x3c1f, 0x78},
+ {0x3c20, 0x06}, {0x3c21, 0x80}, {0x3c22, 0x08}, {0x3c23, 0x0f},
+ {0x3c24, 0x97}, {0x3c25, 0x00}, {0x3c26, 0x3c}, {0x3c27, 0x02},
+ {0x3c28, 0xa7}, {0x3c29, 0x09}, {0x3c2a, 0xaf}, {0x3c2b, 0x0b},
+ {0x3c2c, 0x38}, {0x3c2d, 0xf9}, {0x3c2e, 0x0b}, {0x3c2f, 0xfd},
+ {0x3c30, 0x05}, {0x3c35, 0x8c}, {0x3c3e, 0xc3}, {0x3c43, 0xcb},
+ {0x3c44, 0x00}, {0x3c45, 0xff}, {0x3c46, 0x0b}, {0x3c48, 0x3b},
+ {0x3c49, 0x40}, {0x3c4a, 0x00}, {0x3c4b, 0x5b}, {0x3c4c, 0x02},
+ {0x3c4d, 0x02}, {0x3c4e, 0x00}, {0x3c4f, 0x04}, {0x3c50, 0x0c},
+ {0x3c51, 0x00}, {0x3c52, 0x3b}, {0x3c53, 0x3a}, {0x3c54, 0x07},
+ {0x3c55, 0x9e}, {0x3c56, 0x07}, {0x3c57, 0x9e}, {0x3c58, 0x07},
+ {0x3c59, 0xe8}, {0x3c5a, 0x03}, {0x3c5b, 0x33}, {0x3c5c, 0xa8},
+ {0x3c5d, 0x07}, {0x3c5e, 0xd0}, {0x3c5f, 0x07}, {0x3c60, 0x32},
+ {0x3c61, 0x00}, {0x3c62, 0xd0}, {0x3c63, 0x07}, {0x3c64, 0x80},
+ {0x3c65, 0x80}, {0x3c66, 0x3f}, {0x3c67, 0x01}, {0x3c68, 0x00},
+ {0x3c69, 0xd0}, {0x3c6a, 0x07}, {0x3c6b, 0x01}, {0x3c6c, 0x00},
+ {0x3c6d, 0xcd}, {0x3c6e, 0x07}, {0x3c6f, 0xd1}, {0x3c70, 0x07},
+ {0x3c71, 0x01}, {0x3c72, 0x00}, {0x3c73, 0xc3}, {0x3c74, 0x01},
+ {0x3c75, 0x00}, {0x3c76, 0xcd}, {0x3c77, 0x07}, {0x3c78, 0xea},
+ {0x3c79, 0x03}, {0x3c7a, 0xcd}, {0x3c7b, 0x07}, {0x3c7c, 0x08},
+ {0x3c7d, 0x06}, {0x3c7e, 0x03}, {0x3c85, 0x3a}, {0x3c86, 0x08},
+ {0x3c87, 0x69}, {0x3c88, 0x0b}, {0x3c8f, 0xb2}, {0x3c90, 0x08},
+ {0x3c91, 0xe1}, {0x3c92, 0x0b}, {0x3c93, 0x06}, {0x3c94, 0x03},
+ {0x3c9b, 0x35}, {0x3c9c, 0x08}, {0x3c9d, 0x64}, {0x3c9e, 0x0b},
+ {0x3ca5, 0xb7}, {0x3ca6, 0x08}, {0x3ca7, 0xe6}, {0x3ca8, 0x0b},
+ {0x3ca9, 0x83}, {0x3caa, 0x3c}, {0x3cab, 0x01}, {0x3cac, 0x00},
+ {0x3cad, 0x9e}, {0x3cae, 0x07}, {0x3caf, 0x85}, {0x3cb0, 0x03},
+ {0x3cb1, 0xbc}, {0x3cb2, 0x0b}, {0x3cb7, 0x3c}, {0x3cb8, 0x01},
+ {0x3cb9, 0x00}, {0x3cba, 0xbc}, {0x3cbb, 0x07}, {0x3cbc, 0xa3},
+ {0x3cbd, 0x03}, {0x3cbe, 0x9e}, {0x3cbf, 0x0b}, {0x3cc4, 0x99},
+ {0x3cc5, 0xe9}, {0x3cc6, 0x99}, {0x3cc7, 0xe9}, {0x3cc8, 0x33},
+ {0x3cc9, 0x03}, {0x3cca, 0x33}, {0x3ccb, 0x03}, {0x3cce, 0x66},
+ {0x3ccf, 0x66}, {0x3cd0, 0x00}, {0x3cd1, 0x04}, {0x3cd2, 0xf4},
+ {0x3cd3, 0xb7}, {0x3cd4, 0x03}, {0x3cd5, 0x10}, {0x3cd6, 0x06},
+ {0x3cd7, 0x30}, {0x3cd8, 0x08}, {0x3cd9, 0x5f}, {0x3cda, 0x0b},
+ {0x3cdd, 0x44}, {0x3cde, 0x44}, {0x3cdf, 0x04}, {0x3ce0, 0x00},
+ {0x3ce1, 0x00}, {0x3ce3, 0x00}, {0x3ce4, 0x00}, {0x3ce5, 0x00},
+ {0x3ce6, 0x00}, {0x3ce7, 0x00}, {0x3ce8, 0x00}, {0x3ce9, 0x00},
+ {0x3cea, 0x00}, {0x3ceb, 0x00}, {0x3cec, 0x00}, {0x3ced, 0x00},
+ {0x3cee, 0x00}, {0x3cef, 0x85}, {0x3cf0, 0x03}, {0x3cf1, 0xaf},
+ {0x3cf2, 0x0b}, {0x3cf3, 0x03}, {0x3cf4, 0x2c}, {0x3cf5, 0x00},
+ {0x3cf6, 0x42}, {0x3cf7, 0x00}, {0x3cf8, 0x03}, {0x3cf9, 0x2c},
+ {0x3cfa, 0x00}, {0x3cfb, 0x42}, {0x3cfc, 0x00}, {0x3cfd, 0x03},
+ {0x3cfe, 0x01}, {0x3d81, 0x00}, {0x3e94, 0x0f}, {0x3e95, 0x5f},
+ {0x3e96, 0x02}, {0x3e97, 0x3c}, {0x3e98, 0x00}, {0x3e9f, 0x00},
+ {0x3f00, 0x00}, {0x3f05, 0x03}, {0x3f07, 0x01}, {0x3f08, 0x55},
+ {0x3f09, 0x25}, {0x3f0a, 0x35}, {0x3f0b, 0x20}, {0x3f11, 0x05},
+ {0x3f12, 0x05}, {0x3f40, 0x00}, {0x3f41, 0x03}, {0x3f43, 0x10},
+ {0x3f44, 0x02}, {0x3f45, 0xe6}, {0x4000, 0xf9}, {0x4001, 0x2b},
+ {0x4008, 0x04}, {0x4009, 0x1b}, {0x400a, 0x03}, {0x400e, 0x10},
+ {0x4010, 0x04}, {0x4011, 0xf7}, {0x4032, 0x3e}, {0x4033, 0x02},
+ {0x4050, 0x02}, {0x4051, 0x0d}, {0x40f9, 0x00}, {0x4200, 0x00},
+ {0x4204, 0x00}, {0x4205, 0x00}, {0x4206, 0x00}, {0x4207, 0x00},
+ {0x4208, 0x00}, {0x4244, 0x00}, {0x4300, 0x00}, {0x4301, 0xff},
+ {0x4302, 0xf0}, {0x4303, 0x00}, {0x4304, 0xff}, {0x4305, 0xf0},
+ {0x4306, 0x00}, {0x4308, 0x00}, {0x430a, 0x90}, {0x430b, 0x11},
+ {0x4310, 0x00}, {0x4316, 0x00}, {0x431c, 0x00}, {0x431e, 0x00},
+ {0x4410, 0x08}, {0x4433, 0x08}, {0x4434, 0xf8}, {0x4508, 0x80},
+ {0x4509, 0x10}, {0x450b, 0x83}, {0x4511, 0x00}, {0x4580, 0x09},
+ {0x4587, 0x00}, {0x458c, 0x00}, {0x4640, 0x00}, {0x4641, 0xc1},
+ {0x4642, 0x00}, {0x4643, 0x00}, {0x4649, 0x00}, {0x4681, 0x04},
+ {0x4682, 0x10}, {0x4683, 0xa0}, {0x4698, 0x07}, {0x4699, 0xf0},
+ {0x4710, 0x00}, {0x4802, 0x00}, {0x481b, 0x3c}, {0x4837, 0x10},
+ {0x4860, 0x00}, {0x4883, 0x00}, {0x4884, 0x09}, {0x4885, 0x80},
+ {0x4886, 0x00}, {0x4888, 0x10}, {0x488b, 0x00}, {0x488c, 0x10},
+ {0x4980, 0x03}, {0x4981, 0x06}, {0x4984, 0x00}, {0x4985, 0x00},
+ {0x4a14, 0x04}, {0x4b01, 0x44}, {0x4b03, 0x80}, {0x4d06, 0xc8},
+ {0x4d09, 0xdf}, {0x4d15, 0x7d}, {0x4d34, 0x7d}, {0x4d3c, 0x7d},
+ {0x4f00, 0x7f}, {0x4f01, 0xff}, {0x4f03, 0x00}, {0x4f04, 0x18},
+ {0x4f05, 0x13}, {0x5000, 0x6e}, {0x5001, 0x00}, {0x500a, 0x00},
+ {0x5080, 0x00}, {0x5081, 0x00}, {0x5082, 0x00}, {0x5083, 0x00},
+ {0x5100, 0x00}, {0x5103, 0x00}, {0x5180, 0x70}, {0x5181, 0x70},
+ {0x5182, 0x73}, {0x5183, 0xff}, {0x5249, 0x06}, {0x524f, 0x06},
+ {0x5281, 0x18}, {0x5282, 0x08}, {0x5283, 0x08}, {0x5284, 0x18},
+ {0x5285, 0x18}, {0x5286, 0x08}, {0x5287, 0x08}, {0x5288, 0x18},
+ {0x5289, 0x2d}, {0x6000, 0x40}, {0x6001, 0x40}, {0x6002, 0x00},
+ {0x6003, 0x00}, {0x6004, 0x00}, {0x6005, 0x00}, {0x6006, 0x00},
+ {0x6007, 0x00}, {0x6008, 0x00}, {0x6009, 0x00}, {0x600a, 0x00},
+ {0x600b, 0x00}, {0x600c, 0x02}, {0x600d, 0x00}, {0x600e, 0x04},
+ {0x600f, 0x00}, {0x6010, 0x06}, {0x6011, 0x00}, {0x6012, 0x00},
+ {0x6013, 0x00}, {0x6014, 0x02}, {0x6015, 0x00}, {0x6016, 0x04},
+ {0x6017, 0x00}, {0x6018, 0x06}, {0x6019, 0x00}, {0x601a, 0x01},
+ {0x601b, 0x00}, {0x601c, 0x01}, {0x601d, 0x00}, {0x601e, 0x01},
+ {0x601f, 0x00}, {0x6020, 0x01}, {0x6021, 0x00}, {0x6022, 0x01},
+ {0x6023, 0x00}, {0x6024, 0x01}, {0x6025, 0x00}, {0x6026, 0x01},
+ {0x6027, 0x00}, {0x6028, 0x01}, {0x6029, 0x00}, {0x3501, 0x08},
+ {0x3502, 0x32}, {0x320a, 0x01}, {0x320b, 0x01}, {0x320c, 0x00},
+ {0x320d, 0x00},
+};
+
+struct ox05b {
+ struct device *dev;
+ struct clk *clk;
+ unsigned long clk_rate;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct gpio_desc *pwdn_gpio;
+ struct v4l2_subdev subdev;
+ struct media_pad pad;
+ struct v4l2_mbus_framefmt format;
+ struct v4l2_ctrl_handler handler;
+ /* Added for RGB dominant stream */
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *again;
+ struct v4l2_ctrl *dgain;
+ /* Added for IR dominant stream */
+ struct v4l2_ctrl *ir_exposure;
+ struct v4l2_ctrl *ir_again;
+ struct v4l2_ctrl *ir_dgain;
+ u32 fps;
+ struct mutex lock; /* For streaming status */
+ bool streaming;
+ struct v4l2_ctrl *link_freq;
+};
+
+static inline struct ox05b *to_ox05b(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct ox05b, subdev);
+}
+
+static int ox05b_read(struct ox05b *ox05b, u16 addr, u32 *val, size_t nbytes)
+{
+ int ret;
+ __le32 val_le = 0;
+
+ ret = regmap_bulk_read(ox05b->regmap, addr, &val_le, nbytes);
+ if (ret < 0) {
+ dev_err(ox05b->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 ox05b_write(struct ox05b *ox05b, u16 addr, u32 val, size_t nbytes)
+{
+ int ret;
+ __le32 val_le = cpu_to_le32(val);
+
+ ret = regmap_bulk_write(ox05b->regmap, addr, &val_le, nbytes);
+ if (ret < 0) {
+ dev_err(ox05b->dev, "%s: failed to write reg 0x%04x: %d\n",
+ __func__, addr, ret);
+ }
+ return ret;
+}
+
+static int ox05b_write_table(struct ox05b *ox05b,
+ const struct reg_sequence *regs,
+ unsigned int nr_regs)
+{
+ int ret;
+
+ ret = regmap_multi_reg_write(ox05b->regmap, regs, nr_regs);
+ if (ret < 0) {
+ dev_err(ox05b->dev, "%s: failed to write reg table (%d)!\n",
+ __func__, ret);
+ }
+ return ret;
+}
+
+static void ox05b_init_formats(struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *format;
+ int i;
+
+ for (i = 0; i < 2; ++i) {
+ format = v4l2_subdev_state_get_stream_format(state, 0, i);
+ format->code = ox05b_mbus_formats[0];
+ format->width = ox05b_framesizes[0].width;
+ format->height = ox05b_framesizes[0].height;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_SRGB;
+ }
+}
+
+static int ox05b_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct ox05b *ox05b = to_ox05b(sd);
+ struct v4l2_mbus_framefmt *format;
+ const struct v4l2_area *fsize;
+ u32 code;
+ int ret = 0;
+
+ if (fmt->pad != 0)
+ return -EINVAL;
+
+ if (fmt->stream != 0)
+ return -EINVAL;
+
+ /* Sensor only supports a single format. */
+ code = ox05b_mbus_formats[0];
+
+ /* Find the nearest supported frame size. */
+ fsize = v4l2_find_nearest_size(ox05b_framesizes,
+ ARRAY_SIZE(ox05b_framesizes), width,
+ height, fmt->format.width,
+ fmt->format.height);
+
+ format = v4l2_subdev_state_get_stream_format(state, fmt->pad, fmt->stream);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && ox05b->streaming)
+ ret = -EBUSY;
+
+ format->code = code;
+ format->width = fsize->width;
+ format->height = fsize->height;
+
+ fmt->format = *format;
+
+ return ret;
+}
+
+static int _ox05b_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_ACTIVE,
+ },
+ {
+ .source_pad = 0,
+ .source_stream = 1,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ };
+
+ 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;
+
+ ox05b_init_formats(state);
+
+ return 0;
+}
+
+static int ox05b_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;
+ unsigned int i;
+
+ if (pad != 0)
+ return -EINVAL;
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ fmt = v4l2_subdev_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 - 2 virtual channels*/
+
+ bpp = 10;
+
+ for (i = 0; i < 2; ++i) {
+ fd->entry[fd->num_entries].stream = i;
+
+ 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 = i;
+ fd->entry[fd->num_entries].bus.csi2.dt = 0x2b; /* RAW10 */
+
+ fd->num_entries++;
+ }
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int ox05b_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 > 2)
+ return -EINVAL;
+
+ v4l2_subdev_lock_state(state);
+
+ ret = _ox05b_set_routing(sd, state);
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static int ox05b_init_cfg(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ int ret;
+
+ ret = _ox05b_set_routing(sd, state);
+
+ return ret;
+}
+
+static int ox05b_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(ox05b_mbus_formats))
+ return -EINVAL;
+
+ code->code = ox05b_mbus_formats[code->index];
+
+ return 0;
+}
+
+static int ox05b_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(ox05b_mbus_formats); ++i) {
+ if (ox05b_mbus_formats[i] == fse->code)
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ox05b_mbus_formats))
+ return -EINVAL;
+
+ if (fse->index >= ARRAY_SIZE(ox05b_framesizes))
+ return -EINVAL;
+
+ fse->min_width = ox05b_framesizes[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->max_height = ox05b_framesizes[fse->index].height;
+ fse->min_height = fse->max_height;
+
+ return 0;
+}
+
+static int ox05b_get_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct ox05b *ox05b = to_ox05b(sd);
+
+ fi->interval.numerator = 1;
+ fi->interval.denominator = ox05b->fps;
+ return 0;
+}
+
+static int ox05b_set_frame_interval(struct v4l2_subdev *sd,
+ struct v4l2_subdev_frame_interval *fi)
+{
+ struct ox05b *ox05b = to_ox05b(sd);
+
+ dev_dbg(ox05b->dev, "%s: Set framerate %dfps\n", __func__,
+ fi->interval.denominator / fi->interval.numerator);
+ if ((fi->interval.denominator / fi->interval.numerator) != ox05b->fps) {
+ dev_err(ox05b->dev, "%s: Framerate can only be %dfps\n",
+ __func__, ox05b->fps);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int ox05b_detect(struct ox05b *ox05b)
+{
+ int ret;
+ u32 id;
+
+ ret = ox05b_read(ox05b, OX05B_SC_CHIP_ID_HI, &id, 2);
+ if (ret < 0)
+ return ret;
+
+ if (id != OX05B_CHIP_ID) {
+ dev_err(ox05b->dev,
+ "%s: unknown chip ID 0x%04x\n", __func__, id);
+ return -ENODEV;
+ }
+
+ dev_info(ox05b->dev, "%s: detected chip ID 0x%04x\n", __func__, id);
+ return 0;
+}
+
+static int ox05b_set_groupA(struct ox05b *ox05b)
+{
+ int i, ret;
+ u32 exposure = ox05b->ir_exposure->val;
+ u32 again = ox05b->ir_again->val;
+ u32 dgain = ox05b->ir_dgain->val;
+ struct reg_sequence ox05b_groupA[] = {
+ {0x3208, 0x01}, /* Group 1 (IR Dominant VC0) hold start */
+ {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */
+ {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */
+ {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */
+ {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */
+ {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */
+ {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */
+ {0x4813, 0x01}, /* VC=1. This register takes effect from next frame. */
+ {0x3208, 0x11}, /* Group 1 (IR Dominant VC0) hold end*/
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ox05b_groupA); i++) {
+ ret = regmap_write(ox05b->regmap, ox05b_groupA[i].reg, ox05b_groupA[i].def);
+ if (ret < 0) {
+ dev_err(ox05b->dev,
+ "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n",
+ __func__, i, ox05b_groupA[i].reg, ox05b_groupA[i].def, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ox05b_set_groupB(struct ox05b *ox05b)
+{
+ int i, ret;
+ u32 exposure = ox05b->exposure->val;
+ u32 again = ox05b->again->val;
+ u32 dgain = ox05b->dgain->val;
+ struct reg_sequence ox05b_groupB[] = {
+ {0x3208, 0x00}, /* Group 0 (RGB Dominant VC1) hold start */
+ {OX05B_AEC_PK_EXPO_HI, (exposure >> 8) & 0xff}, /* Exposure time Hi */
+ {OX05B_AEC_PK_EXPO_LO, exposure & 0xff}, /* Exposure time Low */
+ {OX05B_AEC_PK_AGAIN_HI, (again >> 4) & 0xff}, /* Analog gain Hi */
+ {OX05B_AEC_PK_AGAIN_LO, (again & 0x0f) << 4}, /* Analog gain Low */
+ {OX05B_AEC_PK_DGAIN_HI, (dgain >> 8) & 0xff}, /* Digital gain Hi */
+ {OX05B_AEC_PK_DGAIN_LO, dgain & 0xff}, /* Digital gain Lo */
+ {0x4813, 0x00}, /* VC=0. This register takes effect from next frame. */
+ {0x3208, 0x10}, /* Group 0 (RGB Dominant VC1) hold end*/
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ox05b_groupB); i++) {
+ ret = regmap_write(ox05b->regmap, ox05b_groupB[i].reg, ox05b_groupB[i].def);
+ if (ret < 0) {
+ dev_err(ox05b->dev,
+ "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n",
+ __func__, i, ox05b_groupB[i].reg, ox05b_groupB[i].def, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ox05b_set_AB_mode_regs(struct ox05b *ox05b)
+{
+ int i, ret;
+ struct reg_sequence ox5b_AB_mode_regs[] = {
+ {0x3211, 0xF1}, /* AB mode enable */
+ {0x3212, 0x21}, /* Enable sync between holds of group 0 and group 1*/
+ {0x3208, 0xA0}, /* Always use for repeat launch */
+ };
+
+ for (i = 0; i < ARRAY_SIZE(ox5b_AB_mode_regs); i++) {
+ ret = regmap_write(ox05b->regmap, ox5b_AB_mode_regs[i].reg,
+ ox5b_AB_mode_regs[i].def);
+ if (ret < 0) {
+ dev_err(ox05b->dev,
+ "%s: failed to write reg[%d] 0x%04x = 0x%02x (%d)!\n",
+ __func__, i, ox5b_AB_mode_regs[i].reg,
+ ox5b_AB_mode_regs[i].def, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int ox05b_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct ox05b *ox05b = container_of(ctrl->handler, struct ox05b, handler);
+ int ret;
+
+ dev_dbg(ox05b->dev, "%s: %s, value: %d\n", __func__,
+ ctrl->name, ctrl->val);
+
+ /*
+ * If the device is not powered up by the host driver do
+ * not apply any controls to H/W at this time. Instead
+ * the controls will be restored right after power-up.
+ */
+ if (pm_runtime_suspended(ox05b->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ case V4L2_CID_ANALOGUE_GAIN:
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = ox05b_set_groupB(ox05b);
+ break;
+ case V4L2_CID_IR_EXPOSURE:
+ case V4L2_CID_IR_ANALOGUE_GAIN:
+ case V4L2_CID_IR_DIGITAL_GAIN:
+ ret = ox05b_set_groupA(ox05b);
+ break;
+ case V4L2_CID_HFLIP:
+ case V4L2_CID_VFLIP:
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int ox05b_power_on(struct ox05b *ox05b)
+{
+ int ret;
+
+ ret = clk_prepare_enable(ox05b->clk);
+ if (ret < 0)
+ return ret;
+
+ if (ox05b->pwdn_gpio) {
+ gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1);
+ usleep_range(100, 1000);
+ gpiod_set_value_cansleep(ox05b->pwdn_gpio, 0);
+ msleep(30);
+ }
+ return 0;
+}
+
+static int ox05b_power_off(struct ox05b *ox05b)
+{
+ if (ox05b->pwdn_gpio) {
+ gpiod_set_value_cansleep(ox05b->pwdn_gpio, 1);
+ usleep_range(1, 10);
+ }
+
+ clk_disable_unprepare(ox05b->clk);
+
+ return 0;
+}
+
+static int ox05b_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ox05b *ox05b = to_ox05b(sd);
+
+ return ox05b_power_on(ox05b);
+}
+
+static int ox05b_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ox05b *ox05b = to_ox05b(sd);
+
+ return ox05b_power_off(ox05b);
+}
+
+static int ox05b_start_stream(struct ox05b *ox05b)
+{
+ int ret;
+
+ ret = ox05b_write_table(ox05b, ox05b_linear_2592x1944,
+ ARRAY_SIZE(ox05b_linear_2592x1944));
+ if (ret < 0)
+ return ret;
+
+ msleep(20);
+
+ /* set registers for IR frame */
+ ret = ox05b_set_groupA(ox05b);
+ if (ret < 0)
+ return ret;
+
+ /* set registers for RGB frame */
+ ret = ox05b_set_groupB(ox05b);
+ if (ret < 0)
+ return ret;
+
+ /* set registers specific to AB mode */
+ ret = ox05b_set_AB_mode_regs(ox05b);
+
+ /* Set active */
+ ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0x01, 1);
+ if (ret < 0)
+ return ret;
+
+ /* No communication is possible for a while after exiting standby.
+ * we want the sensor to have sufficient time to process
+ * the new configurations. The same type of delays have been programmed
+ * in the OV2312 driver.
+ * TODO: check if there is a status register to poll for sensor readiness.
+ */
+ msleep(20);
+
+ return 0;
+}
+
+static int ox05b_stop_stream(struct ox05b *ox05b)
+{
+ int ret;
+
+ /* Set standby */
+ ret = ox05b_write(ox05b, OX05B_SYS_MODE_SEL, 0, 1);
+ if (ret < 0)
+ return ret;
+
+ /* No communication is possible for a while after entering standby */
+ usleep_range(10000, 20000);
+ return 0;
+}
+
+static int ox05b_set_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct ox05b *ox05b = to_ox05b(sd);
+ int ret;
+
+ mutex_lock(&ox05b->lock);
+ if (ox05b->streaming == enable) {
+ mutex_unlock(&ox05b->lock);
+ return 0;
+ }
+
+ if (enable) {
+ ret = pm_runtime_resume_and_get(ox05b->dev);
+ if (ret < 0)
+ goto err_unlock;
+
+ ret = ox05b_start_stream(ox05b);
+ if (ret < 0)
+ goto err_runtime_put;
+
+ } else {
+ ret = ox05b_stop_stream(ox05b);
+ if (ret < 0)
+ goto err_runtime_put;
+ pm_runtime_put(ox05b->dev);
+ }
+
+ ox05b->streaming = enable;
+
+ mutex_unlock(&ox05b->lock);
+ return 0;
+
+err_runtime_put:
+ pm_runtime_put(ox05b->dev);
+
+err_unlock:
+ mutex_unlock(&ox05b->lock);
+ dev_err(ox05b->dev,
+ "%s: failed to setup streaming %d\n", __func__, ret);
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops ox05b_subdev_video_ops = {
+ .g_frame_interval = ox05b_get_frame_interval,
+ .s_frame_interval = ox05b_set_frame_interval,
+ .s_stream = ox05b_set_stream,
+};
+
+static const struct v4l2_subdev_pad_ops ox05b_subdev_pad_ops = {
+ .init_cfg = ox05b_init_cfg,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = ox05b_set_fmt,
+ .enum_mbus_code = ox05b_enum_mbus_code,
+ .enum_frame_size = ox05b_enum_frame_sizes,
+ .set_routing = ox05b_set_routing,
+ .get_frame_desc = ox05b_get_frame_desc,
+};
+
+static const struct v4l2_subdev_ops ox05b_subdev_ops = {
+ .video = &ox05b_subdev_video_ops,
+ .pad = &ox05b_subdev_pad_ops,
+};
+
+static const struct v4l2_ctrl_ops ox05b_ctrl_ops = {
+ .s_ctrl = ox05b_set_ctrl,
+};
+
+static const struct dev_pm_ops ox05b_pm_ops = {
+ SET_RUNTIME_PM_OPS(ox05b_suspend, ox05b_resume, NULL)
+};
+
+static int ox05b_probe(struct i2c_client *client)
+{
+ struct ox05b *ox05b;
+ struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *ctrl_hdr;
+ int ret;
+ /* Allocate internal struct */
+ ox05b = devm_kzalloc(&client->dev, sizeof(*ox05b), GFP_KERNEL);
+ if (!ox05b)
+ return -ENOMEM;
+ ox05b->dev = &client->dev;
+
+ /* Initialize I2C Regmap */
+ ox05b->regmap = devm_regmap_init_i2c(client, &ox05b_regmap_config);
+ if (IS_ERR(ox05b->regmap))
+ return PTR_ERR(ox05b->regmap);
+
+ /* Initialize Powerdown GPIO */
+ ox05b->pwdn_gpio = devm_gpiod_get_optional(ox05b->dev, "pwdn", GPIOD_OUT_LOW);
+ if (IS_ERR(ox05b->pwdn_gpio))
+ return PTR_ERR(ox05b->pwdn_gpio);
+
+ ox05b->clk = devm_clk_get(ox05b->dev, "inck");
+ if (IS_ERR(ox05b->clk))
+ return PTR_ERR(ox05b->clk);
+
+ ox05b->clk_rate = clk_get_rate(ox05b->clk);
+
+ if (ox05b->clk_rate < 6000000 || ox05b->clk_rate > 27000000)
+ return -EINVAL;
+
+ /* Power on */
+ ret = ox05b_power_on(ox05b);
+ if (ret < 0)
+ return ret;
+
+ /* Detect sensor */
+ ret = ox05b_detect(ox05b);
+ if (ret < 0)
+ return ret;
+
+ /* Initialize the subdev and its controls. */
+ sd = &ox05b->subdev;
+ v4l2_i2c_subdev_init(sd, client, &ox05b_subdev_ops);
+
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS |
+ V4L2_SUBDEV_FL_STREAMS;
+
+ /* Initialize the media entity. */
+ ox05b->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ ret = media_entity_pads_init(&sd->entity, 1, &ox05b->pad);
+ if (ret < 0) {
+ dev_err(ox05b->dev,
+ "%s: media entity init failed %d\n", __func__, ret);
+ return ret;
+ }
+
+ ox05b->fps = OX05B_FRAMERATE_DEFAULT;
+ mutex_init(&ox05b->lock);
+ /* Initialize controls */
+ ctrl_hdr = &ox05b->handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdr, 7);
+ if (ret < 0) {
+ dev_err(ox05b->dev,
+ "%s: ctrl handler init failed: %d\n", __func__, ret);
+ goto err_media_cleanup;
+ }
+
+ ox05b->handler.lock = &ox05b->lock;
+
+ /* Add new controls */
+ ox05b->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(ox05b_link_freq_menu) - 1, 0,
+ ox05b_link_freq_menu);
+ if (ox05b->link_freq)
+ ox05b->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ ox05b->exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_EXPOSURE, 0,
+ OX05B_EXPOSURE_MAX,
+ 1, OX05B_EXPOSURE_DEFAULT);
+
+ ox05b->again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, 0,
+ OX05B_AGAIN_MAX, 1,
+ OX05B_AGAIN_DEFAULT);
+ ox05b->dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_DIGITAL_GAIN, 0,
+ OX05B_DGAIN_MAX, 1,
+ OX05B_DGAIN_DEFAULT);
+
+ /* Added new control for IR frames. */
+ ox05b->ir_exposure = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_IR_EXPOSURE, 0,
+ OX05B_EXPOSURE_MAX,
+ 1, OX05B_EXPOSURE_DEFAULT);
+
+ ox05b->ir_again = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_IR_ANALOGUE_GAIN, 0,
+ OX05B_AGAIN_MAX, 1,
+ OX05B_AGAIN_DEFAULT);
+
+ ox05b->ir_dgain = v4l2_ctrl_new_std(ctrl_hdr, &ox05b_ctrl_ops,
+ V4L2_CID_IR_DIGITAL_GAIN, 0,
+ OX05B_DGAIN_MAX, 1,
+ OX05B_DGAIN_DEFAULT);
+
+ ox05b->subdev.ctrl_handler = ctrl_hdr;
+ if (ox05b->handler.error) {
+ ret = ox05b->handler.error;
+ dev_err(ox05b->dev,
+ "%s: failed to add the ctrls: %d\n", __func__, ret);
+ goto err_ctrl_free;
+ }
+
+ /* PM Runtime */
+ pm_runtime_enable(ox05b->dev);
+ pm_runtime_set_suspended(ox05b->dev);
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret < 0) {
+ dev_err(ox05b->dev, "%s: failed to init subdev: %d\n", __func__, ret);
+ goto err_pm_disable;
+ }
+
+ /* Finally, register the subdev. */
+ ret = v4l2_async_register_subdev(sd);
+ if (ret < 0) {
+ dev_err(ox05b->dev,
+ "%s: v4l2 subdev register failed %d\n", __func__, ret);
+ goto err_subdev_cleanup;
+ }
+
+ dev_info(ox05b->dev, "ox05b1s probed!\n");
+ return 0;
+
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(&ox05b->subdev);
+
+err_pm_disable:
+ pm_runtime_disable(ox05b->dev);
+
+err_ctrl_free:
+ v4l2_ctrl_handler_free(ctrl_hdr);
+ mutex_destroy(&ox05b->lock);
+
+err_media_cleanup:
+ media_entity_cleanup(&ox05b->subdev.entity);
+
+ return ret;
+}
+
+static void ox05b_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ox05b *ox05b = to_ox05b(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&ox05b->handler);
+ v4l2_subdev_cleanup(&ox05b->subdev);
+ media_entity_cleanup(&sd->entity);
+ mutex_destroy(&ox05b->lock);
+
+ pm_runtime_disable(ox05b->dev);
+}
+
+static const struct of_device_id ox05b_of_match[] = {
+ { .compatible = "ovti,ox05b" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, ox05b_of_match);
+
+static struct i2c_driver ox05b_i2c_driver = {
+ .driver = {
+ .name = "ox05b",
+ .of_match_table = ox05b_of_match,
+ .pm = &ox05b_pm_ops,
+ },
+ .probe_new = ox05b_probe,
+ .remove = ox05b_remove,
+};
+
+module_i2c_driver(ox05b_i2c_driver);
+
+MODULE_AUTHOR("Abhishek Sharma <abhishek.sharma@ti.com>");
+MODULE_DESCRIPTION("OX05B1S RGB-IR Image Sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/img/e5010/e5010-jpeg-enc.c b/drivers/media/platform/img/e5010/e5010-jpeg-enc.c
index 34491939ce0b..ed60d82041a6 100644
--- a/drivers/media/platform/img/e5010/e5010-jpeg-enc.c
+++ b/drivers/media/platform/img/e5010/e5010-jpeg-enc.c
@@ -1674,6 +1674,12 @@ static int e5010_resume(struct device *dev)
if (ret < 0)
return ret;
+ ret = e5010_init_device(e5010_dev);
+ if (ret) {
+ dev_err(dev, "Failed to re-enable e5010 device\n");
+ return ret;
+ }
+
v4l2_m2m_resume(e5010_dev->m2m_dev);
return ret;
}
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index e22921e7ea61..33c786eb1d90 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -793,6 +793,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_ALPHA_COMPONENT: return "Alpha Component";
case V4L2_CID_COLORFX_CBCR: return "Color Effects, CbCr";
case V4L2_CID_COLORFX_RGB: return "Color Effects, RGB";
+ case V4L2_CID_IR_EXPOSURE: return "Exposure, IR";
/*
* Codec controls
@@ -1111,6 +1112,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_TEST_PATTERN_BLUE: return "Blue Pixel Value";
case V4L2_CID_TEST_PATTERN_GREENB: return "Green (Blue) Pixel Value";
case V4L2_CID_NOTIFY_GAINS: return "Notify Gains";
+ case V4L2_CID_IR_ANALOGUE_GAIN: return "Analogue Gain, IR";
/* Image processing controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
@@ -1120,6 +1122,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_TEST_PATTERN: return "Test Pattern";
case V4L2_CID_DEINTERLACING_MODE: return "Deinterlacing Mode";
case V4L2_CID_DIGITAL_GAIN: return "Digital Gain";
+ case V4L2_CID_IR_DIGITAL_GAIN: return "Digital Gain, IR";
/* DV controls */
/* Keep the order of the 'case's the same as in v4l2-controls.h! */
diff --git a/drivers/mtd/spi-nor/core.c b/drivers/mtd/spi-nor/core.c
index 6267753bf2b0..5adf607b2a90 100644
--- a/drivers/mtd/spi-nor/core.c
+++ b/drivers/mtd/spi-nor/core.c
@@ -1697,6 +1697,82 @@ static const struct flash_info *spi_nor_detect(struct spi_nor *nor)
return info;
}
+/*
+ * On Octal DTR capable flashes like Micron Xcella reads cannot start or
+ * end at an odd address in Octal DTR mode. Extra bytes need to be read
+ * at the start or end to make sure both the start address and length
+ * remain even.
+ */
+static int spi_nor_octal_dtr_read(struct spi_nor *nor, loff_t from, size_t len,
+ u_char *buf)
+{
+ u_char *tmp_buf;
+ size_t tmp_len;
+ loff_t start, end;
+ int ret, bytes_read;
+
+ if (IS_ALIGNED(from, 2) && IS_ALIGNED(len, 2))
+ return spi_nor_read_data(nor, from, len, buf);
+ else if (IS_ALIGNED(from, 2) && len > PAGE_SIZE)
+ return spi_nor_read_data(nor, from, round_down(len, PAGE_SIZE),
+ buf);
+
+ tmp_buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!tmp_buf)
+ return -ENOMEM;
+
+ start = round_down(from, 2);
+ end = round_up(from + len, 2);
+
+ /*
+ * Avoid allocating too much memory. The requested read length might be
+ * quite large. Allocating a buffer just as large (slightly bigger, in
+ * fact) would put unnecessary memory pressure on the system.
+ *
+ * For example if the read is from 3 to 1M, then this will read from 2
+ * to 4098. The reads from 4098 to 1M will then not need a temporary
+ * buffer so they can proceed as normal.
+ */
+ tmp_len = min_t(size_t, end - start, PAGE_SIZE);
+
+ ret = spi_nor_read_data(nor, start, tmp_len, tmp_buf);
+ if (ret == 0) {
+ ret = -EIO;
+ goto out;
+ }
+ if (ret < 0)
+ goto out;
+
+ /*
+ * More bytes are read than actually requested, but that number can't be
+ * reported to the calling function or it will confuse its calculations.
+ * Calculate how many of the _requested_ bytes were read.
+ */
+ bytes_read = ret;
+
+ if (from != start)
+ ret -= from - start;
+
+ /*
+ * Only account for extra bytes at the end if they were actually read.
+ * For example, if the total length was truncated because of temporary
+ * buffer size limit then the adjustment for the extra bytes at the end
+ * is not needed.
+ */
+ if (start + bytes_read == end)
+ ret -= end - (from + len);
+
+ if (ret < 0) {
+ ret = -EIO;
+ goto out;
+ }
+
+ memcpy(buf, tmp_buf + (from - start), ret);
+out:
+ kfree(tmp_buf);
+ return ret;
+}
+
static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
@@ -1714,7 +1790,10 @@ static int spi_nor_read(struct mtd_info *mtd, loff_t from, size_t len,
addr = spi_nor_convert_addr(nor, addr);
- ret = spi_nor_read_data(nor, addr, len, buf);
+ if (nor->read_proto == SNOR_PROTO_8_8_8_DTR)
+ ret = spi_nor_octal_dtr_read(nor, addr, len, buf);
+ else
+ ret = spi_nor_read_data(nor, addr, len, buf);
if (ret == 0) {
/* We shouldn't see 0-length reads */
ret = -EIO;
@@ -1737,6 +1816,71 @@ read_err:
}
/*
+ * On Octal DTR capable flashes like Micron Xcella the writes cannot start or
+ * end at an odd address in Octal DTR mode. Extra 0xff bytes need to be appended
+ * or prepended to make sure the start address and end address are even. 0xff is
+ * used because on NOR flashes a program operation can only flip bits from 1 to
+ * 0, not the other way round. 0 to 1 flip needs to happen via erases.
+ */
+static int spi_nor_octal_dtr_write(struct spi_nor *nor, loff_t to, size_t len,
+ const u8 *buf)
+{
+ u8 *tmp_buf;
+ size_t bytes_written;
+ loff_t start, end;
+ int ret;
+
+ if (IS_ALIGNED(to, 2) && IS_ALIGNED(len, 2))
+ return spi_nor_write_data(nor, to, len, buf);
+
+ tmp_buf = kmalloc(nor->params->page_size, GFP_KERNEL);
+ if (!tmp_buf)
+ return -ENOMEM;
+
+ memset(tmp_buf, 0xff, nor->params->page_size);
+
+ start = round_down(to, 2);
+ end = round_up(to + len, 2);
+
+ memcpy(tmp_buf + (to - start), buf, len);
+
+ ret = spi_nor_write_data(nor, start, end - start, tmp_buf);
+ if (ret == 0) {
+ ret = -EIO;
+ goto out;
+ }
+ if (ret < 0)
+ goto out;
+
+ /*
+ * More bytes are written than actually requested, but that number can't
+ * be reported to the calling function or it will confuse its
+ * calculations. Calculate how many of the _requested_ bytes were
+ * written.
+ */
+ bytes_written = ret;
+
+ if (to != start)
+ ret -= to - start;
+
+ /*
+ * Only account for extra bytes at the end if they were actually
+ * written. For example, if for some reason the controller could only
+ * complete a partial write then the adjustment for the extra bytes at
+ * the end is not needed.
+ */
+ if (start + bytes_written == end)
+ ret -= end - (to + len);
+
+ if (ret < 0)
+ ret = -EIO;
+
+out:
+ kfree(tmp_buf);
+ return ret;
+}
+
+/*
* Write an address range to the nor chip. Data must be written in
* FLASH_PAGESIZE chunks. The address range may be any size provided
* it is within the physical boundaries.
@@ -1780,7 +1924,12 @@ static int spi_nor_write(struct mtd_info *mtd, loff_t to, size_t len,
if (ret)
goto write_err;
- ret = spi_nor_write_data(nor, addr, page_remain, buf + i);
+ if (nor->write_proto == SNOR_PROTO_8_8_8_DTR)
+ ret = spi_nor_octal_dtr_write(nor, addr, page_remain,
+ buf + i);
+ else
+ ret = spi_nor_write_data(nor, addr, page_remain,
+ buf + i);
if (ret < 0)
goto write_err;
written = ret;
diff --git a/drivers/net/ethernet/ti/am65-cpsw-nuss.c b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
index cf76bade4ace..684c6e120e1c 100644
--- a/drivers/net/ethernet/ti/am65-cpsw-nuss.c
+++ b/drivers/net/ethernet/ti/am65-cpsw-nuss.c
@@ -92,10 +92,14 @@
#define AM65_CPSW_PORT_REG_PRI_CTL_RX_PTYPE_RROBIN BIT(8)
/* AM65_CPSW_PN_TS_CTL register fields */
+#define AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN BIT(0)
+#define AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN BIT(1)
+#define AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN BIT(3)
#define AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN BIT(4)
#define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN BIT(5)
#define AM65_CPSW_PN_TS_CTL_TX_VLAN_LT2_EN BIT(6)
#define AM65_CPSW_PN_TS_CTL_TX_ANX_D_EN BIT(7)
+#define AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN BIT(9)
#define AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN BIT(10)
#define AM65_CPSW_PN_TS_CTL_TX_HOST_TS_EN BIT(11)
#define AM65_CPSW_PN_TS_CTL_MSG_TYPE_EN_SHIFT 16
@@ -123,6 +127,11 @@
AM65_CPSW_PN_TS_CTL_TX_ANX_E_EN | \
AM65_CPSW_PN_TS_CTL_TX_ANX_F_EN)
+#define AM65_CPSW_TS_RX_ANX_ALL_EN \
+ (AM65_CPSW_PN_TS_CTL_RX_ANX_D_EN | \
+ AM65_CPSW_PN_TS_CTL_RX_ANX_E_EN | \
+ AM65_CPSW_PN_TS_CTL_RX_ANX_F_EN)
+
#define AM65_CPSW_ALE_AGEOUT_DEFAULT 30
/* Number of TX/RX descriptors */
#define AM65_CPSW_MAX_TX_DESC 500
@@ -677,18 +686,6 @@ static void am65_cpsw_nuss_rx_cleanup(void *data, dma_addr_t desc_dma)
dev_kfree_skb_any(skb);
}
-static void am65_cpsw_nuss_rx_ts(struct sk_buff *skb, u32 *psdata)
-{
- struct skb_shared_hwtstamps *ssh;
- u64 ns;
-
- ns = ((u64)psdata[1] << 32) | psdata[0];
-
- ssh = skb_hwtstamps(skb);
- memset(ssh, 0, sizeof(*ssh));
- ssh->hwtstamp = ns_to_ktime(ns);
-}
-
/* RX psdata[2] word format - checksum information */
#define AM65_CPSW_RX_PSD_CSUM_ADD GENMASK(15, 0)
#define AM65_CPSW_RX_PSD_CSUM_ERR BIT(16)
@@ -769,9 +766,6 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common,
skb->dev = ndev;
psdata = cppi5_hdesc_get_psdata(desc_rx);
- /* add RX timestamp */
- if (port->rx_ts_enabled)
- am65_cpsw_nuss_rx_ts(skb, psdata);
csum_info = psdata[2];
dev_dbg(dev, "%s rx csum_info:%#x\n", __func__, csum_info);
@@ -784,6 +778,8 @@ static int am65_cpsw_nuss_rx_packets(struct am65_cpsw_common *common,
ndev_priv = netdev_priv(ndev);
am65_cpsw_nuss_set_offload_fwd_mark(skb, ndev_priv->offload_fwd_mark);
skb_put(skb, pkt_len);
+ if (port->rx_ts_enabled)
+ am65_cpts_rx_timestamp(common->cpts, skb);
skb->protocol = eth_type_trans(skb, ndev);
am65_cpsw_nuss_rx_csum(skb, csum_info);
napi_gro_receive(&common->napi_rx, skb);
@@ -1312,7 +1308,6 @@ static int am65_cpsw_nuss_ndo_slave_set_mac_address(struct net_device *ndev,
static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
struct ifreq *ifr)
{
- struct am65_cpsw_common *common = am65_ndev_to_common(ndev);
struct am65_cpsw_port *port = am65_ndev_to_port(ndev);
u32 ts_ctrl, seq_id, ts_ctrl_ltype2, ts_vlan_ltype;
struct hwtstamp_config cfg;
@@ -1336,11 +1331,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
case HWTSTAMP_FILTER_NONE:
port->rx_ts_enabled = false;
break;
- case HWTSTAMP_FILTER_ALL:
- case HWTSTAMP_FILTER_SOME:
- case HWTSTAMP_FILTER_PTP_V1_L4_EVENT:
- case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
- case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
case HWTSTAMP_FILTER_PTP_V2_L4_EVENT:
case HWTSTAMP_FILTER_PTP_V2_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V2_L4_DELAY_REQ:
@@ -1350,10 +1340,13 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
case HWTSTAMP_FILTER_PTP_V2_EVENT:
case HWTSTAMP_FILTER_PTP_V2_SYNC:
case HWTSTAMP_FILTER_PTP_V2_DELAY_REQ:
- case HWTSTAMP_FILTER_NTP_ALL:
port->rx_ts_enabled = true;
- cfg.rx_filter = HWTSTAMP_FILTER_ALL;
+ cfg.rx_filter = HWTSTAMP_FILTER_PTP_V2_EVENT;
break;
+ case HWTSTAMP_FILTER_ALL:
+ case HWTSTAMP_FILTER_SOME:
+ case HWTSTAMP_FILTER_NTP_ALL:
+ return -EOPNOTSUPP;
default:
return -ERANGE;
}
@@ -1383,6 +1376,10 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
ts_ctrl |= AM65_CPSW_TS_TX_ANX_ALL_EN |
AM65_CPSW_PN_TS_CTL_TX_VLAN_LT1_EN;
+ if (port->rx_ts_enabled)
+ ts_ctrl |= AM65_CPSW_TS_RX_ANX_ALL_EN |
+ AM65_CPSW_PN_TS_CTL_RX_VLAN_LT1_EN;
+
writel(seq_id, port->port_base + AM65_CPSW_PORTN_REG_TS_SEQ_LTYPE_REG);
writel(ts_vlan_ltype, port->port_base +
AM65_CPSW_PORTN_REG_TS_VLAN_LTYPE_REG);
@@ -1390,9 +1387,6 @@ static int am65_cpsw_nuss_hwtstamp_set(struct net_device *ndev,
AM65_CPSW_PORTN_REG_TS_CTL_LTYPE2);
writel(ts_ctrl, port->port_base + AM65_CPSW_PORTN_REG_TS_CTL);
- /* en/dis RX timestamp */
- am65_cpts_rx_enable(common->cpts, port->rx_ts_enabled);
-
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
@@ -1409,7 +1403,7 @@ static int am65_cpsw_nuss_hwtstamp_get(struct net_device *ndev,
cfg.tx_type = port->tx_ts_enabled ?
HWTSTAMP_TX_ON : HWTSTAMP_TX_OFF;
cfg.rx_filter = port->rx_ts_enabled ?
- HWTSTAMP_FILTER_ALL : HWTSTAMP_FILTER_NONE;
+ HWTSTAMP_FILTER_PTP_V2_EVENT : HWTSTAMP_FILTER_NONE;
return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
}
diff --git a/drivers/net/ethernet/ti/am65-cpts.c b/drivers/net/ethernet/ti/am65-cpts.c
index c66618d91c28..29e0b9ff23bf 100644
--- a/drivers/net/ethernet/ti/am65-cpts.c
+++ b/drivers/net/ethernet/ti/am65-cpts.c
@@ -859,29 +859,6 @@ static long am65_cpts_ts_work(struct ptp_clock_info *ptp)
return delay;
}
-/**
- * am65_cpts_rx_enable - enable rx timestamping
- * @cpts: cpts handle
- * @en: enable
- *
- * This functions enables rx packets timestamping. The CPTS can timestamp all
- * rx packets.
- */
-void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en)
-{
- u32 val;
-
- mutex_lock(&cpts->ptp_clk_lock);
- val = am65_cpts_read32(cpts, control);
- if (en)
- val |= AM65_CPTS_CONTROL_TSTAMP_EN;
- else
- val &= ~AM65_CPTS_CONTROL_TSTAMP_EN;
- am65_cpts_write32(cpts, val, control);
- mutex_unlock(&cpts->ptp_clk_lock);
-}
-EXPORT_SYMBOL_GPL(am65_cpts_rx_enable);
-
static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid)
{
unsigned int ptp_class = ptp_classify_raw(skb);
@@ -906,6 +883,68 @@ static int am65_skb_get_mtype_seqid(struct sk_buff *skb, u32 *mtype_seqid)
return 1;
}
+static u64 am65_cpts_get_rx_ts(struct am65_cpts *cpts, struct sk_buff *skb,
+ u32 skb_mtype_seqid)
+{
+ struct list_head *this, *next;
+ struct am65_cpts_event *event;
+ unsigned long flags;
+ u32 mtype_seqid;
+ u64 ns = 0;
+
+ am65_cpts_fifo_read(cpts);
+ spin_lock_irqsave(&cpts->lock, flags);
+ list_for_each_safe(this, next, &cpts->events) {
+ event = list_entry(this, struct am65_cpts_event, list);
+ if (time_after(jiffies, event->tmo)) {
+ list_del_init(&event->list);
+ list_add(&event->list, &cpts->pool);
+ continue;
+ }
+
+ mtype_seqid = event->event1 &
+ (AM65_CPTS_EVENT_1_MESSAGE_TYPE_MASK |
+ AM65_CPTS_EVENT_1_SEQUENCE_ID_MASK |
+ AM65_CPTS_EVENT_1_EVENT_TYPE_MASK);
+
+ if (mtype_seqid == skb_mtype_seqid) {
+ ns = event->timestamp;
+ list_del_init(&event->list);
+ list_add(&event->list, &cpts->pool);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&cpts->lock, flags);
+
+ return ns;
+}
+
+void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb)
+{
+ struct am65_cpts_skb_cb_data *skb_cb = (struct am65_cpts_skb_cb_data *)skb->cb;
+ struct skb_shared_hwtstamps *ssh;
+ int ret;
+ u64 ns;
+
+ skb_reset_mac_header(skb);
+ ret = am65_skb_get_mtype_seqid(skb, &skb_cb->skb_mtype_seqid);
+ if (!ret)
+ return; /* if not PTP class packet */
+
+ skb_cb->skb_mtype_seqid |= (AM65_CPTS_EV_RX << AM65_CPTS_EVENT_1_EVENT_TYPE_SHIFT);
+
+ dev_dbg(cpts->dev, "%s mtype seqid %08x\n", __func__, skb_cb->skb_mtype_seqid);
+
+ ns = am65_cpts_get_rx_ts(cpts, skb, skb_cb->skb_mtype_seqid);
+ if (!ns)
+ return;
+
+ ssh = skb_hwtstamps(skb);
+ memset(ssh, 0, sizeof(*ssh));
+ ssh->hwtstamp = ns_to_ktime(ns);
+}
+EXPORT_SYMBOL_GPL(am65_cpts_rx_timestamp);
+
/**
* am65_cpts_tx_timestamp - save tx packet for timestamping
* @cpts: cpts handle
diff --git a/drivers/net/ethernet/ti/am65-cpts.h b/drivers/net/ethernet/ti/am65-cpts.h
index 6e14df0be113..6099d772799d 100644
--- a/drivers/net/ethernet/ti/am65-cpts.h
+++ b/drivers/net/ethernet/ti/am65-cpts.h
@@ -22,9 +22,9 @@ void am65_cpts_release(struct am65_cpts *cpts);
struct am65_cpts *am65_cpts_create(struct device *dev, void __iomem *regs,
struct device_node *node);
int am65_cpts_phc_index(struct am65_cpts *cpts);
+void am65_cpts_rx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb);
void am65_cpts_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb);
void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts, struct sk_buff *skb);
-void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en);
u64 am65_cpts_ns_gettime(struct am65_cpts *cpts);
int am65_cpts_estf_enable(struct am65_cpts *cpts, int idx,
struct am65_cpts_estf_cfg *cfg);
@@ -48,17 +48,18 @@ static inline int am65_cpts_phc_index(struct am65_cpts *cpts)
return -1;
}
-static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts,
+static inline void am65_cpts_rx_timestamp(struct am65_cpts *cpts,
struct sk_buff *skb)
{
}
-static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts,
- struct sk_buff *skb)
+static inline void am65_cpts_tx_timestamp(struct am65_cpts *cpts,
+ struct sk_buff *skb)
{
}
-static inline void am65_cpts_rx_enable(struct am65_cpts *cpts, bool en)
+static inline void am65_cpts_prep_tx_timestamp(struct am65_cpts *cpts,
+ struct sk_buff *skb)
{
}
diff --git a/drivers/net/ethernet/ti/icss_iep.c b/drivers/net/ethernet/ti/icss_iep.c
index 49652b1d005f..f8faba257a25 100644
--- a/drivers/net/ethernet/ti/icss_iep.c
+++ b/drivers/net/ethernet/ti/icss_iep.c
@@ -54,78 +54,6 @@
#define IEP_CAP_CFG_CAPNF_1ST_EVENT_EN(n) BIT(LATCH_INDEX(n) + 1)
#define IEP_CAP_CFG_CAP_ASYNC_EN(n) BIT(LATCH_INDEX(n) + 10)
-enum {
- ICSS_IEP_GLOBAL_CFG_REG,
- ICSS_IEP_GLOBAL_STATUS_REG,
- ICSS_IEP_COMPEN_REG,
- ICSS_IEP_SLOW_COMPEN_REG,
- ICSS_IEP_COUNT_REG0,
- ICSS_IEP_COUNT_REG1,
- ICSS_IEP_CAPTURE_CFG_REG,
- ICSS_IEP_CAPTURE_STAT_REG,
-
- ICSS_IEP_CAP6_RISE_REG0,
- ICSS_IEP_CAP6_RISE_REG1,
-
- ICSS_IEP_CAP7_RISE_REG0,
- ICSS_IEP_CAP7_RISE_REG1,
-
- ICSS_IEP_CMP_CFG_REG,
- ICSS_IEP_CMP_STAT_REG,
- ICSS_IEP_CMP0_REG0,
- ICSS_IEP_CMP0_REG1,
- ICSS_IEP_CMP1_REG0,
- ICSS_IEP_CMP1_REG1,
-
- ICSS_IEP_CMP8_REG0,
- ICSS_IEP_CMP8_REG1,
- ICSS_IEP_SYNC_CTRL_REG,
- ICSS_IEP_SYNC0_STAT_REG,
- ICSS_IEP_SYNC1_STAT_REG,
- ICSS_IEP_SYNC_PWIDTH_REG,
- ICSS_IEP_SYNC0_PERIOD_REG,
- ICSS_IEP_SYNC1_DELAY_REG,
- ICSS_IEP_SYNC_START_REG,
- ICSS_IEP_MAX_REGS,
-};
-
-/**
- * struct icss_iep_plat_data - Plat data to handle SoC variants
- * @config: Regmap configuration data
- * @reg_offs: register offsets to capture offset differences across SoCs
- * @flags: Flags to represent IEP properties
- */
-struct icss_iep_plat_data {
- struct regmap_config *config;
- u32 reg_offs[ICSS_IEP_MAX_REGS];
- u32 flags;
-};
-
-struct icss_iep {
- struct device *dev;
- void __iomem *base;
- const struct icss_iep_plat_data *plat_data;
- struct regmap *map;
- struct device_node *client_np;
- unsigned long refclk_freq;
- int clk_tick_time; /* one refclk tick time in ns */
- struct ptp_clock_info ptp_info;
- struct ptp_clock *ptp_clock;
- struct mutex ptp_clk_mutex; /* PHC access serializer */
- spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */
- u32 def_inc;
- s16 slow_cmp_inc;
- u32 slow_cmp_count;
- const struct icss_iep_clockops *ops;
- void *clockops_data;
- u32 cycle_time_ns;
- u32 perout_enabled;
- bool pps_enabled;
- int cap_cmp_irq;
- u64 period;
- u32 latch_enable;
-};
-
static u32 icss_iep_readl(struct icss_iep *iep, int reg)
{
return readl(iep->base + iep->plat_data->reg_offs[reg]);
diff --git a/drivers/net/ethernet/ti/icss_iep.h b/drivers/net/ethernet/ti/icss_iep.h
index 7aae5ede47c0..7df995bcbbb2 100644
--- a/drivers/net/ethernet/ti/icss_iep.h
+++ b/drivers/net/ethernet/ti/icss_iep.h
@@ -12,7 +12,77 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/regmap.h>
-struct icss_iep;
+enum {
+ ICSS_IEP_GLOBAL_CFG_REG,
+ ICSS_IEP_GLOBAL_STATUS_REG,
+ ICSS_IEP_COMPEN_REG,
+ ICSS_IEP_SLOW_COMPEN_REG,
+ ICSS_IEP_COUNT_REG0,
+ ICSS_IEP_COUNT_REG1,
+ ICSS_IEP_CAPTURE_CFG_REG,
+ ICSS_IEP_CAPTURE_STAT_REG,
+
+ ICSS_IEP_CAP6_RISE_REG0,
+ ICSS_IEP_CAP6_RISE_REG1,
+
+ ICSS_IEP_CAP7_RISE_REG0,
+ ICSS_IEP_CAP7_RISE_REG1,
+
+ ICSS_IEP_CMP_CFG_REG,
+ ICSS_IEP_CMP_STAT_REG,
+ ICSS_IEP_CMP0_REG0,
+ ICSS_IEP_CMP0_REG1,
+ ICSS_IEP_CMP1_REG0,
+ ICSS_IEP_CMP1_REG1,
+
+ ICSS_IEP_CMP8_REG0,
+ ICSS_IEP_CMP8_REG1,
+ ICSS_IEP_SYNC_CTRL_REG,
+ ICSS_IEP_SYNC0_STAT_REG,
+ ICSS_IEP_SYNC1_STAT_REG,
+ ICSS_IEP_SYNC_PWIDTH_REG,
+ ICSS_IEP_SYNC0_PERIOD_REG,
+ ICSS_IEP_SYNC1_DELAY_REG,
+ ICSS_IEP_SYNC_START_REG,
+ ICSS_IEP_MAX_REGS,
+};
+
+/**
+ * struct icss_iep_plat_data - Plat data to handle SoC variants
+ * @config: Regmap configuration data
+ * @reg_offs: register offsets to capture offset differences across SoCs
+ * @flags: Flags to represent IEP properties
+ */
+struct icss_iep_plat_data {
+ struct regmap_config *config;
+ u32 reg_offs[ICSS_IEP_MAX_REGS];
+ u32 flags;
+};
+
+struct icss_iep {
+ struct device *dev;
+ void __iomem *base;
+ const struct icss_iep_plat_data *plat_data;
+ struct regmap *map;
+ struct device_node *client_np;
+ unsigned long refclk_freq;
+ int clk_tick_time; /* one refclk tick time in ns */
+ struct ptp_clock_info ptp_info;
+ struct ptp_clock *ptp_clock;
+ struct mutex ptp_clk_mutex; /* PHC access serializer */
+ spinlock_t irq_lock; /* CMP IRQ vs icss_iep_ptp_enable access */
+ u32 def_inc;
+ s16 slow_cmp_inc;
+ u32 slow_cmp_count;
+ const struct icss_iep_clockops *ops;
+ void *clockops_data;
+ u32 cycle_time_ns;
+ u32 perout_enabled;
+ bool pps_enabled;
+ int cap_cmp_irq;
+ u64 period;
+ u32 latch_enable;
+};
/* Firmware specific clock operations */
struct icss_iep_clockops {
diff --git a/drivers/net/ethernet/ti/icssg_config.c b/drivers/net/ethernet/ti/icssg_config.c
index aea2ae8a3ae9..88dc611f0fc6 100644
--- a/drivers/net/ethernet/ti/icssg_config.c
+++ b/drivers/net/ethernet/ti/icssg_config.c
@@ -551,7 +551,9 @@ static const struct icssg_r30_cmd emac_r32_bitmask[] = {
{{EMAC_NONE, 0xffff4000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx ENABLE*/
{{EMAC_NONE, 0xbfff0000, EMAC_NONE, EMAC_NONE}}, /* Preemption on Tx DISABLE*/
{{0xffff0010, EMAC_NONE, 0xffff0010, EMAC_NONE}}, /* VLAN AWARE*/
- {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}} /* VLAN UNWARE*/
+ {{0xffef0000, EMAC_NONE, 0xffef0000, EMAC_NONE}}, /* VLAN UNWARE*/
+ {{0xffff2000, EMAC_NONE, EMAC_NONE, EMAC_NONE}}, /* HSR_RX_OFFLOAD_ENABLE */
+ {{0xdfff0000, EMAC_NONE, EMAC_NONE, EMAC_NONE}} /* HSR_RX_OFFLOAD_DISABLE */
};
int emac_set_port_state(struct prueth_emac *emac,
@@ -769,7 +771,10 @@ void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
{
struct prueth *prueth = emac->prueth;
struct prueth_vlan_tbl *tbl = prueth->vlan_tbl;
- u8 fid_c1 = tbl[vid].fid_c1;
+ u8 fid_c1;
+
+ spin_lock(&prueth->vtbl_lock);
+ fid_c1 = tbl[vid].fid_c1;
/* FID_C1: bit0..2 port membership mask,
* bit3..5 tagging mask for each port
@@ -784,6 +789,7 @@ void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask,
}
tbl[vid].fid_c1 = fid_c1;
+ spin_unlock(&prueth->vtbl_lock);
}
u16 icssg_get_pvid(struct prueth_emac *emac)
@@ -846,15 +852,18 @@ int emac_fdb_erase_all(struct prueth_emac *emac)
int emac_fdb_flush_multicast(struct prueth_emac *emac)
{
struct prueth *prueth = emac->prueth;
+ u8 port_mask = BIT(emac->port_id);
int ret = 0;
int i;
ret = emac_fdb_erase_all(emac);
+ spin_lock(&prueth->vtbl_lock);
for (i = 0; i < SZ_4K - 1; i++) {
prueth->vlan_tbl[i].fid = i;
- prueth->vlan_tbl[i].fid_c1 = 0;
+ prueth->vlan_tbl[i].fid_c1 &= ~(port_mask | port_mask << 3);
}
+ spin_unlock(&prueth->vtbl_lock);
return ret;
}
diff --git a/drivers/net/ethernet/ti/icssg_config.h b/drivers/net/ethernet/ti/icssg_config.h
index ff61c66cec60..1f318884fa1b 100644
--- a/drivers/net/ethernet/ti/icssg_config.h
+++ b/drivers/net/ethernet/ti/icssg_config.h
@@ -81,6 +81,8 @@ enum icssg_port_state_cmd {
ICSSG_EMAC_PORT_PREMPT_TX_DISABLE,
ICSSG_EMAC_PORT_VLAN_AWARE_ENABLE,
ICSSG_EMAC_PORT_VLAN_AWARE_DISABLE,
+ ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE,
+ ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE,
ICSSG_EMAC_PORT_MAX_COMMANDS
};
diff --git a/drivers/net/ethernet/ti/icssg_prueth.c b/drivers/net/ethernet/ti/icssg_prueth.c
index 6ad92f40c71c..f3d033723857 100644
--- a/drivers/net/ethernet/ti/icssg_prueth.c
+++ b/drivers/net/ethernet/ti/icssg_prueth.c
@@ -67,7 +67,9 @@
#define DEFAULT_UNTAG_MASK 1
#define NETIF_PRUETH_HSR_OFFLOAD (NETIF_F_HW_HSR_FWD | \
- NETIF_F_HW_HSR_DUP)
+ NETIF_F_HW_HSR_DUP | \
+ NETIF_F_HW_HSR_TAG_INS | \
+ NETIF_F_HW_HSR_TAG_RM)
/* CTRLMMR_ICSSG_RGMII_CTRL register bits */
#define ICSSG_CTRL_RGMII_ID_MODE BIT(24)
@@ -75,6 +77,7 @@
#define IEP_DEFAULT_CYCLE_TIME_NS 1000000 /* 1 ms */
#define PRUETH_UNDIRECTED_PKT_DST_TAG 0
+#define PRUETH_UNDIRECTED_PKT_TAG_INS BIT(30)
static void prueth_cleanup_rx_chns(struct prueth_emac *emac,
struct prueth_rx_chn *rx_chn,
@@ -875,6 +878,9 @@ static enum netdev_tx emac_ndo_start_xmit(struct sk_buff *skb, struct net_device
if (prueth->is_hsr_offload_mode && (ndev->features & NETIF_F_HW_HSR_DUP))
dst_tag_id = PRUETH_UNDIRECTED_PKT_DST_TAG;
+ if (prueth->is_hsr_offload_mode && (ndev->features & NETIF_F_HW_HSR_TAG_INS))
+ epib[1] |= PRUETH_UNDIRECTED_PKT_TAG_INS;
+
cppi5_desc_set_tags_ids(&first_desc->hdr, 0, dst_tag_id);
k3_udma_glue_tx_dma_to_cppi5_addr(tx_chn->tx_chn, &buf_dma);
cppi5_hdesc_attach_buf(first_desc, buf_dma, pkt_len, buf_dma, pkt_len);
@@ -1486,7 +1492,8 @@ static void prueth_iep_settime(void *clockops_data, u64 ns)
sc_desc.cyclecounter0_set = cyclecount & GENMASK(31, 0);
sc_desc.cyclecounter1_set = (cyclecount & GENMASK(63, 32)) >> 32;
sc_desc.iepcount_set = ns % cycletime;
- sc_desc.CMP0_current = cycletime - 4; //Count from 0 to (cycle time)-4
+ /* Count from 0 to (cycle time)- emac->iep->def_inc */
+ sc_desc.CMP0_current = cycletime - emac->iep->def_inc;
memcpy_toio(sc_descp, &sc_desc, sizeof(sc_desc));
@@ -1677,6 +1684,13 @@ static int emac_ndo_open(struct net_device *ndev)
}
}
+ if (prueth->is_hsr_offload_mode) {
+ if (ndev->features & NETIF_F_HW_HSR_TAG_RM)
+ emac_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_ENABLE);
+ else
+ emac_set_port_state(emac, ICSSG_EMAC_HSR_RX_OFFLOAD_DISABLE);
+ }
+
flow_cfg = emac->dram.va + ICSSG_CONFIG_OFFSET + PSI_L_REGULAR_FLOW_ID_BASE_OFFSET;
writew(emac->rx_flow_id_base, &flow_cfg->rx_base_flow);
ret = emac_fdb_flow_id_updated(emac);
@@ -2688,16 +2702,20 @@ static int prueth_netdevice_event(struct notifier_block *unused,
if ((ndev->features & NETIF_PRUETH_HSR_OFFLOAD) &&
is_hsr_master(info->upper_dev)) {
- if (!prueth->hsr_dev) {
- prueth->hsr_dev = info->upper_dev;
-
- icssg_class_set_host_mac_addr(prueth->miig_rt,
- prueth->hsr_dev->dev_addr);
- } else {
- if (prueth->hsr_dev != info->upper_dev) {
- dev_err(prueth->dev, "Both interfaces must be linked to same upper device\n");
- return -EOPNOTSUPP;
+ if (info->linking) {
+ if (!prueth->hsr_dev) {
+ prueth->hsr_dev = info->upper_dev;
+
+ icssg_class_set_host_mac_addr(prueth->miig_rt,
+ prueth->hsr_dev->dev_addr);
+ } else {
+ if (prueth->hsr_dev != info->upper_dev) {
+ dev_err(prueth->dev, "Both interfaces must be linked to same upper device\n");
+ return -EOPNOTSUPP;
+ }
}
+ } else {
+ prueth->hsr_dev = NULL;
}
}
@@ -3280,6 +3298,7 @@ static int prueth_probe(struct platform_device *pdev)
icss_iep_init_fw(prueth->iep1);
}
+ spin_lock_init(&prueth->vtbl_lock);
/* setup netdev interfaces */
if (eth0_node) {
ret = prueth_netdev_init(prueth, eth0_node);
diff --git a/drivers/net/ethernet/ti/icssg_prueth.h b/drivers/net/ethernet/ti/icssg_prueth.h
index 03ec5b8438c2..0534c3b256ea 100644
--- a/drivers/net/ethernet/ti/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg_prueth.h
@@ -330,6 +330,7 @@ struct prueth {
unsigned char switch_id[MAX_PHYS_ITEM_ID_LEN];
int default_vlan;
struct devlink *devlink;
+ spinlock_t vtbl_lock; /* Lock for vtbl in shared memory */
};
struct emac_tx_ts_response {
diff --git a/drivers/net/ethernet/ti/icssg_qos.c b/drivers/net/ethernet/ti/icssg_qos.c
index 67551e3ffa86..811205f916c7 100644
--- a/drivers/net/ethernet/ti/icssg_qos.c
+++ b/drivers/net/ethernet/ti/icssg_qos.c
@@ -142,7 +142,8 @@ static int tas_set_trigger_list_change(struct prueth_emac *emac)
u64 base_time;
u64 cur_time;
- cycle_time = admin_list->cycle_time - 4; /* -4ns to compensate for IEP wraparound time */
+ /* subtract emac->iep->def_inc ns to compensate for IEP wrap around time */
+ cycle_time = admin_list->cycle_time - emac->iep->def_inc;
base_time = admin_list->base_time;
cur_time = prueth_iep_gettime(emac, &sts);
diff --git a/drivers/spi/spi-cadence-quadspi.c b/drivers/spi/spi-cadence-quadspi.c
index 77c3c017b0d6..b3f5a4e3577d 100644
--- a/drivers/spi/spi-cadence-quadspi.c
+++ b/drivers/spi/spi-cadence-quadspi.c
@@ -29,6 +29,7 @@
#include <linux/sched.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi-mem.h>
+#include <linux/sys_soc.h>
#include <linux/timer.h>
#define CQSPI_NAME "cadence-qspi"
@@ -617,7 +618,7 @@ static int cqspi_phy_calibrate(struct cqspi_flash_pdata *f_pdata,
rxhigh.tx = rxlow.tx;
rxhigh.read_delay = rxlow.read_delay;
- cqspi_find_rx_high(f_pdata, mem, &rxhigh);
+ ret = cqspi_find_rx_high(f_pdata, mem, &rxhigh);
if (ret)
goto out;
dev_dbg(dev, "rxhigh: RX: %d TX: %d RD: %d\n", rxhigh.rx, rxhigh.tx,
@@ -1275,6 +1276,7 @@ static int cqspi_read_setup(struct cqspi_flash_pdata *f_pdata,
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (op->addr.nbytes - 1);
writel(reg, reg_base + CQSPI_REG_SIZE);
+ readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */
return 0;
}
@@ -1314,6 +1316,7 @@ static int cqspi_indirect_read_execute(struct cqspi_flash_pdata *f_pdata,
reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTRD_START_MASK,
reg_base + CQSPI_REG_INDIRECTRD);
+ readl(reg_base + CQSPI_REG_INDIRECTRD); /* Flush posted write. */
while (remaining > 0) {
if (!wait_for_completion_timeout(&cqspi->transfer_complete,
@@ -1569,6 +1572,7 @@ static int cqspi_write_setup(struct cqspi_flash_pdata *f_pdata,
reg &= ~CQSPI_REG_SIZE_ADDRESS_MASK;
reg |= (op->addr.nbytes - 1);
writel(reg, reg_base + CQSPI_REG_SIZE);
+ readl(reg_base + CQSPI_REG_SIZE); /* Flush posted write. */
return 0;
}
@@ -1594,6 +1598,8 @@ static int cqspi_indirect_write_execute(struct cqspi_flash_pdata *f_pdata,
reinit_completion(&cqspi->transfer_complete);
writel(CQSPI_REG_INDIRECTWR_START_MASK,
reg_base + CQSPI_REG_INDIRECTWR);
+ readl(reg_base + CQSPI_REG_INDIRECTWR); /* Flush posted write. */
+
/*
* As per 66AK2G02 TRM SPRUHY8F section 11.15.5.3 Indirect Access
* Controller programming sequence, couple of cycles of
@@ -2006,6 +2012,46 @@ err_unmap:
return ret;
}
+static void cqspi_memcpy_fromio(const struct spi_mem_op *op, void *to,
+ const void __iomem *from, size_t count)
+{
+ if (op->data.buswidth == 8 && op->data.dtr) {
+ /*
+ * 8D-8D-8D ops with odd length should be rejected by
+ * supports_op() so no need to worry about that.
+ */
+ while (count && !IS_ALIGNED((unsigned long)from, 4)) {
+ *(u16 *)to = __raw_readw(from);
+ from += 2;
+ to += 2;
+ count -= 2;
+ }
+
+ /*
+ * The controller can work with both 32-bit and 64-bit
+ * platforms. 32-bit platforms won't have a readq. So use a
+ * readl instead.
+ */
+ while (count >= 4) {
+ *(u32 *)to = __raw_readl(from);
+ from += 4;
+ to += 4;
+ count -= 4;
+ }
+
+ while (count) {
+ *(u16 *)to = __raw_readw(from);
+ from += 2;
+ to += 2;
+ count -= 2;
+ }
+
+ return;
+ }
+
+ memcpy_fromio(to, from, count);
+}
+
static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
const struct spi_mem_op *op)
{
@@ -2017,8 +2063,8 @@ static int cqspi_direct_read_execute(struct cqspi_flash_pdata *f_pdata,
u_char *buf = op->data.buf.in;
int ret;
- if (!cqspi->rx_chan || !virt_addr_valid(buf)) {
- memcpy_fromio(buf, cqspi->ahb_base + from, len);
+ if (!cqspi->rx_chan || !virt_addr_valid(buf) || len <= 16) {
+ cqspi_memcpy_fromio(op, buf, cqspi->ahb_base + from, len);
return 0;
}
@@ -2412,6 +2458,11 @@ static int cqspi_setup_flash(struct cqspi_st *cqspi)
return 0;
}
+static const struct soc_device_attribute k3_soc_devices[] = {
+ { .family = "AM64X", .revision = "SR1.0" },
+ { /* sentinel */ }
+};
+
static int cqspi_probe(struct platform_device *pdev)
{
const struct cqspi_driver_platdata *ddata;
@@ -2566,7 +2617,7 @@ static int cqspi_probe(struct platform_device *pdev)
goto probe_setup_failed;
}
- if (cqspi->use_direct_mode) {
+ if (cqspi->use_direct_mode && !soc_device_match(k3_soc_devices)) {
ret = cqspi_request_mmap_dma(cqspi);
if (ret == -EPROBE_DEFER)
goto probe_setup_failed;
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index d4a4e3cab3c2..1164694b12c1 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -148,8 +148,10 @@ enum v4l2_colorfx {
#define V4L2_CID_COLORFX_CBCR (V4L2_CID_BASE+42)
#define V4L2_CID_COLORFX_RGB (V4L2_CID_BASE+43)
+#define V4L2_CID_IR_EXPOSURE (V4L2_CID_BASE+44)
+
/* last CID + 1 */
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+44)
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+45)
/* USER-class private control IDs */
@@ -1143,6 +1145,7 @@ enum v4l2_jpeg_chroma_subsampling {
#define V4L2_CID_TEST_PATTERN_GREENB (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 7)
#define V4L2_CID_UNIT_CELL_SIZE (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 8)
#define V4L2_CID_NOTIFY_GAINS (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 9)
+#define V4L2_CID_IR_ANALOGUE_GAIN (V4L2_CID_IMAGE_SOURCE_CLASS_BASE + 10)
/* Image processing controls */
@@ -1155,6 +1158,7 @@ enum v4l2_jpeg_chroma_subsampling {
#define V4L2_CID_TEST_PATTERN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 3)
#define V4L2_CID_DEINTERLACING_MODE (V4L2_CID_IMAGE_PROC_CLASS_BASE + 4)
#define V4L2_CID_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 5)
+#define V4L2_CID_IR_DIGITAL_GAIN (V4L2_CID_IMAGE_PROC_CLASS_BASE + 6)
/* DV-class control IDs defined by V4L2 */
#define V4L2_CID_DV_CLASS_BASE (V4L2_CTRL_CLASS_DV | 0x900)
diff --git a/net/hsr/hsr_slave.c b/net/hsr/hsr_slave.c
index fa81035321ae..1b6457f357bd 100644
--- a/net/hsr/hsr_slave.c
+++ b/net/hsr/hsr_slave.c
@@ -157,7 +157,7 @@ static int hsr_portdev_setup(struct hsr_priv *hsr, struct net_device *dev,
fail_rx_handler:
netdev_upper_dev_unlink(dev, hsr_dev);
fail_upper_dev_link:
- if (port->hsr->fwd_offloaded)
+ if (!port->hsr->fwd_offloaded)
dev_set_promiscuity(dev, -1);
return res;
@@ -220,7 +220,8 @@ void hsr_del_port(struct hsr_port *port)
netdev_update_features(master->dev);
dev_set_mtu(master->dev, hsr_get_max_mtu(hsr));
netdev_rx_handler_unregister(port->dev);
- dev_set_promiscuity(port->dev, -1);
+ if (!port->hsr->fwd_offloaded)
+ dev_set_promiscuity(port->dev, -1);
netdev_upper_dev_unlink(port->dev, master->dev);
}