Merge commit 'e3f7d79af1b514a182765d6d95e65d88aba6f94f'

* commit 'e3f7d79af1b514a182765d6d95e65d88aba6f94f': (84 commits)
  media: i2c: rk628: Compatible with both kernel-5.10 and kernel-6.1
  media: i2c: rk628: fix audio fs in large offset
  media: i2c: rk628: check for overflow when i2c operation
  media: i2c: rk628: add register debugfs node
  media: i2c: rk628: Auto derepeat
  media: i2c: rk628: allows the PHY to lock to a low control period
  media: i2c: rk628: update driver for dsi mode
  media: i2c: rk628: fix hdmi1.4 change format not recognized
  media: i2c: rk628: fix i2c timeout
  media: i2c: rk628: fix display error
  media: i2c: rk628: fix combtxphy mipi lp-tx output slew-rate
  media: i2c: rk628: set default timing when driver probe
  media: i2c: rk628: add support for rk628f hdmirx audio
  media: i2c: rk628: cru: add hdmirx aud apll support
  media: i2c: rk628: add apll regmap_range
  media: i2c: rk628: cru: Add rk628f APLL
  media: i2c: rk628: read raw state must delay some time when clear interrupt
  media: i2c: rk628: move some function to rk628_mipi_dphy.c
  media: i2c: rk628: add csc matrix support
  media: i2c: rk628: add csi1 support and dual mipi mode for rk628f
  ...

Change-Id: If91f3e03071c93d46cdff8afbf9e45da420bb9f2

Conflicts:
	drivers/media/i2c/rk628/rk628_bt1120_v4l2.c
	drivers/media/i2c/rk628/rk628_csi_v4l2.c
This commit is contained in:
Tao Huang
2024-01-19 21:10:47 +08:00
58 changed files with 10274 additions and 1638 deletions

View File

@@ -159,6 +159,17 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-dual-channel-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-one-vp-two-single-channel-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-single-channel-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3567-evb2-lp4x-v10-two-vp-two-separate-single-channel-lvds.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-hdmi2bt1120-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-hdmi2dsi-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-hdmi2dsi-dual-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-hdmi2gvi-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-hdmi2lvds-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-hdmi2lvds-dual-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-rgb2dsi-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-rgb2gvi-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-rgb2hdmi-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-rgb2lvds-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb-rk628-rgb2lvds-dual-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-dual-camera.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3568-evb1-ddr4-v10-one-vp-two-single-channel-lvds.dtb
@@ -257,6 +268,7 @@ dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-lp4-v10-rk1608-ipc-8x-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-lp4-v11-linux-ipc.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-v11.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-v11-linux.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-evb7-v11-rk628-hdmi2csi.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nvr-demo-v10.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nvr-demo-v10-android.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += rk3588-nvr-demo-v10-ipc-4x-linux.dtb

View File

@@ -0,0 +1,169 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include "rk3568.dtsi"
#include "rk3568-evb.dtsi"
/ {
model = "Rockchip RK3568 EVB RK628 DDR4 V10 Board";
compatible = "rockchip,rk3568-evb-rk628-ddr4-v10", "rockchip,rk3568";
rk628_sound: rk628-sound {
compatible = "simple-audio-card";
simple-audio-card,format = "i2s";
simple-audio-card,mclk-fs = <128>;
simple-audio-card,name = "rockchip,hdmi-rk628";
status = "disabled";
simple-audio-card,cpu {
sound-dai = <&i2s2_2ch>;
};
simple-audio-card,codec {
sound-dai = <&i2c2_rk628>;
};
};
};
&i2c2 {
clock-frequency = <400000>;
status = "okay";
i2c2_rk628: rk628@50 {
compatible = "rockchip,rk628";
reg = <0x50>;
interrupt-parent = <&gpio0>;
interrupts = <20 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&gpio0 RK_PC1 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio2 RK_PA2 GPIO_ACTIVE_LOW>;
#sound-dai-cells = <0>;
pinctrl-names = "default";
pinctrl-0 = <&rk628_reset>;
status = "okay";
};
};
&i2c3 {
clock-frequency = <400000>;
status = "okay";
i2c3_rk628: rk628@51 {
compatible = "rockchip,rk628";
reg = <0x51>;
/* external test board
* rk628_int1: gpio1_a5
* rk628_reset1: gpio1_a6
* rk628_int2: gpio1_a7
* rk628_reset2: gpio1_b0
*/
interrupt-parent = <&gpio1>;
interrupts = <5 IRQ_TYPE_LEVEL_HIGH>;
reset-gpios = <&gpio1 RK_PA6 GPIO_ACTIVE_LOW>;
status = "disabled";
};
};
&i2c4 {
pinctrl-names = "default";
pinctrl-0 = <&i2c4m1_xfer>;
clock-frequency = <400000>;
status = "okay";
i2c4_rk628: rk628@50 {
compatible = "rockchip,rk628";
reg = <0x50>;
interrupt-parent = <&gpio2>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>;
status = "disabled";
};
};
&i2c5 {
status = "disabled";
};
&i2s1_8ch {
status = "disabled";
};
&pinctrl {
rk628 {
rk628_reset: rk628-reset {
rockchip,pins = <2 RK_PA2 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};
&pwm5 {
status = "disabled";
};
&pwm7 {
status = "disabled";
};
&pmu_io_domains {
status = "okay";
pmuio1-supply = <&vcc3v3_pmu>;
pmuio2-supply = <&vcc3v3_pmu>;
vccio1-supply = <&vcc_3v3>;
vccio3-supply = <&vcc_3v3>;
vccio4-supply = <&vcc_3v3>;
vccio5-supply = <&vcc_3v3>;
vccio6-supply = <&vcc_3v3>;
vccio7-supply = <&vcc_3v3>;
};
&sdmmc0 {
status = "disabled";
};
&spdif_8ch {
status = "disabled";
};
&spdif_out {
status = "disabled";
};
&u2phy0_otg {
/delete-property/ vbus-supply;
status = "okay";
};
&usbdrd_dwc3 {
dr_mode = "otg";
phys = <&u2phy0_otg>;
phy-names = "usb2-phy";
extcon = <&usb2phy0>;
maximum-speed = "high-speed";
snps,dis_u2_susphy_quirk;
status = "okay";
};
&vcc3v3_lcd0_n {
gpio = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
enable-active-high;
};
&vcc3v3_lcd1_n {
status = "disabled";
};
&wireless_wlan {
status = "disabled";
};
&wireless_bluetooth {
status = "disabled";
};

View File

@@ -0,0 +1,60 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2023 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
&i2c4 {
pinctrl-names = "default";
pinctrl-0 = <&i2c4m1_xfer>;
clock-frequency = <400000>;
status = "okay";
rk628_bt1120: rk628_bt1120@50 {
compatible = "rockchip,rk628-bt1120-v4l2";
reg = <0x50>;
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&cif_dvp_clk &cif_dvp_bus16 &cif_dvp_bus8>;
interrupt-parent = <&gpio2>;
interrupts = <15 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&gpio2 RK_PC0 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio2 RK_PB0 GPIO_ACTIVE_LOW>;
plugin-det-gpios = <&gpio1 RK_PA2 GPIO_ACTIVE_LOW>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "RK628-BT1120";
rockchip,camera-module-lens-name = "NC";
dual-edge = <1>;
port {
lt8619c_out: endpoint {
remote-endpoint = <&cif_para_in>;
bus-width = <16>;
pclk-sample = <1>;
};
};
};
};
&rkcif_dvp {
status = "okay";
port {
/* Parallel bus endpoint */
cif_para_in: endpoint {
remote-endpoint = <&lt8619c_out>;
};
};
};
&rkcif {
status = "okay";
};
&rkcif_mmu {
status = "okay";
};

View File

@@ -0,0 +1,397 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
#include <dt-bindings/display/media-bus-format.h>
&gt1x {
status = "okay";
power-supply = <&vcc3v3_lcd0_n>;
goodix,rst-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
goodix,irq-gpio = <&gpio0 RK_PA4 IRQ_TYPE_LEVEL_LOW>;
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <10>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
rk628,hdmi-in;
rk628-dsi {
//rockchip,dual-channel;
dsi,eotp;
dsi,video-mode;
dsi,format = "rgb888";
dsi,lanes = <4>;
status = "okay";
rk628-panel {
panel-init-sequence = [
23 00 02 FE 21
23 00 02 04 00
23 00 02 00 64
23 00 02 2A 00
23 00 02 26 64
23 00 02 54 00
23 00 02 50 64
23 00 02 7B 00
23 00 02 77 64
23 00 02 A2 00
23 00 02 9D 64
23 00 02 C9 00
23 00 02 C5 64
23 00 02 01 71
23 00 02 27 71
23 00 02 51 71
23 00 02 78 71
23 00 02 9E 71
23 00 02 C6 71
23 00 02 02 89
23 00 02 28 89
23 00 02 52 89
23 00 02 79 89
23 00 02 9F 89
23 00 02 C7 89
23 00 02 03 9E
23 00 02 29 9E
23 00 02 53 9E
23 00 02 7A 9E
23 00 02 A0 9E
23 00 02 C8 9E
23 00 02 09 00
23 00 02 05 B0
23 00 02 31 00
23 00 02 2B B0
23 00 02 5A 00
23 00 02 55 B0
23 00 02 80 00
23 00 02 7C B0
23 00 02 A7 00
23 00 02 A3 B0
23 00 02 CE 00
23 00 02 CA B0
23 00 02 06 C0
23 00 02 2D C0
23 00 02 56 C0
23 00 02 7D C0
23 00 02 A4 C0
23 00 02 CB C0
23 00 02 07 CF
23 00 02 2F CF
23 00 02 58 CF
23 00 02 7E CF
23 00 02 A5 CF
23 00 02 CC CF
23 00 02 08 DD
23 00 02 30 DD
23 00 02 59 DD
23 00 02 7F DD
23 00 02 A6 DD
23 00 02 CD DD
23 00 02 0E 15
23 00 02 0A E9
23 00 02 36 15
23 00 02 32 E9
23 00 02 5F 15
23 00 02 5B E9
23 00 02 85 15
23 00 02 81 E9
23 00 02 AD 15
23 00 02 A9 E9
23 00 02 D3 15
23 00 02 CF E9
23 00 02 0B 14
23 00 02 33 14
23 00 02 5C 14
23 00 02 82 14
23 00 02 AA 14
23 00 02 D0 14
23 00 02 0C 36
23 00 02 34 36
23 00 02 5D 36
23 00 02 83 36
23 00 02 AB 36
23 00 02 D1 36
23 00 02 0D 6B
23 00 02 35 6B
23 00 02 5E 6B
23 00 02 84 6B
23 00 02 AC 6B
23 00 02 D2 6B
23 00 02 13 5A
23 00 02 0F 94
23 00 02 3B 5A
23 00 02 37 94
23 00 02 64 5A
23 00 02 60 94
23 00 02 8A 5A
23 00 02 86 94
23 00 02 B2 5A
23 00 02 AE 94
23 00 02 D8 5A
23 00 02 D4 94
23 00 02 10 D1
23 00 02 38 D1
23 00 02 61 D1
23 00 02 87 D1
23 00 02 AF D1
23 00 02 D5 D1
23 00 02 11 04
23 00 02 39 04
23 00 02 62 04
23 00 02 88 04
23 00 02 B0 04
23 00 02 D6 04
23 00 02 12 05
23 00 02 3A 05
23 00 02 63 05
23 00 02 89 05
23 00 02 B1 05
23 00 02 D7 05
23 00 02 18 AA
23 00 02 14 36
23 00 02 42 AA
23 00 02 3D 36
23 00 02 69 AA
23 00 02 65 36
23 00 02 8F AA
23 00 02 8B 36
23 00 02 B7 AA
23 00 02 B3 36
23 00 02 DD AA
23 00 02 D9 36
23 00 02 15 74
23 00 02 3F 74
23 00 02 66 74
23 00 02 8C 74
23 00 02 B4 74
23 00 02 DA 74
23 00 02 16 9F
23 00 02 40 9F
23 00 02 67 9F
23 00 02 8D 9F
23 00 02 B5 9F
23 00 02 DB 9F
23 00 02 17 DC
23 00 02 41 DC
23 00 02 68 DC
23 00 02 8E DC
23 00 02 B6 DC
23 00 02 DC DC
23 00 02 1D FF
23 00 02 19 03
23 00 02 47 FF
23 00 02 43 03
23 00 02 6E FF
23 00 02 6A 03
23 00 02 94 FF
23 00 02 90 03
23 00 02 BC FF
23 00 02 B8 03
23 00 02 E2 FF
23 00 02 DE 03
23 00 02 1A 35
23 00 02 44 35
23 00 02 6B 35
23 00 02 91 35
23 00 02 B9 35
23 00 02 DF 35
23 00 02 1B 45
23 00 02 45 45
23 00 02 6C 45
23 00 02 92 45
23 00 02 BA 45
23 00 02 E0 45
23 00 02 1C 55
23 00 02 46 55
23 00 02 6D 55
23 00 02 93 55
23 00 02 BB 55
23 00 02 E1 55
23 00 02 22 FF
23 00 02 1E 68
23 00 02 4C FF
23 00 02 48 68
23 00 02 73 FF
23 00 02 6F 68
23 00 02 99 FF
23 00 02 95 68
23 00 02 C1 FF
23 00 02 BD 68
23 00 02 E7 FF
23 00 02 E3 68
23 00 02 1F 7E
23 00 02 49 7E
23 00 02 70 7E
23 00 02 96 7E
23 00 02 BE 7E
23 00 02 E4 7E
23 00 02 20 97
23 00 02 4A 97
23 00 02 71 97
23 00 02 97 97
23 00 02 BF 97
23 00 02 E5 97
23 00 02 21 B5
23 00 02 4B B5
23 00 02 72 B5
23 00 02 98 B5
23 00 02 C0 B5
23 00 02 E6 B5
23 00 02 25 F0
23 00 02 23 E8
23 00 02 4F F0
23 00 02 4D E8
23 00 02 76 F0
23 00 02 74 E8
23 00 02 9C F0
23 00 02 9A E8
23 00 02 C4 F0
23 00 02 C2 E8
23 00 02 EA F0
23 00 02 E8 E8
23 00 02 24 FF
23 00 02 4E FF
23 00 02 75 FF
23 00 02 9B FF
23 00 02 C3 FF
23 00 02 E9 FF
23 00 02 FE 3D
23 00 02 00 04
23 00 02 FE 23
23 00 02 08 82
23 00 02 0A 00
23 00 02 0B 00
23 00 02 0C 01
23 00 02 16 00
23 00 02 18 02
23 00 02 1B 04
23 00 02 19 04
23 00 02 1C 81
23 00 02 1F 00
23 00 02 20 03
23 00 02 23 04
23 00 02 21 01
23 00 02 54 63
23 00 02 55 54
23 00 02 6E 45
23 00 02 6D 36
23 00 02 FE 3D
23 00 02 55 78
23 00 02 FE 20
23 00 02 26 30
23 00 02 FE 3D
23 00 02 20 71
23 00 02 50 8F
23 00 02 51 8F
23 00 02 FE 00
23 00 02 35 00
05 78 01 11
05 00 01 29
];
panel-exit-sequence = [
05 00 01 28
05 00 01 10
];
};
};
display-timings {
src-timing {
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hback-porch = <30>;
hfront-porch = <60>;
vback-porch = <10>;
vfront-porch = <10>;
hsync-len = <40>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hback-porch = <30>;
hfront-porch = <60>;
vback-porch = <10>;
vfront-porch = <10>;
hsync-len = <40>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hback-porch = <30>;
hfront-porch = <60>;
vback-porch = <10>;
vfront-porch = <10>;
hsync-len = <40>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&hdmi_in_vp0 {
status = "okay";
};
&hdmi_in_vp1 {
status = "disabled";
};
&route_hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hback-porch = <30>;
hfront-porch = <60>;
vback-porch = <10>;
vfront-porch = <10>;
hsync-len = <40>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&touch_gpio {
rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
};

View File

@@ -0,0 +1,239 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
#include <dt-bindings/display/media-bus-format.h>
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <240>;
panel-enable-delay-ms = <240>;
panel-prepare-delay-ms = <240>;
panel-unprepare-delay-ms = <240>;
panel-disable-delay-ms = <240>;
panel-init-delay-ms = <240>;
rk628,hdmi-in;
rk628-dsi {
rockchip,lane-mbps = <1100>;
rockchip,dual-channel;
dsi,eotp;
dsi,video-mode;
dsi,format = "rgb888";
dsi,lanes = <4>;
status = "okay";
rk628-panel {
panel-init-sequence = [
29 00 05 ff aa 55 a5 80
23 00 02 6f 31
23 00 02 fa 00
23 00 02 6f 13
23 00 02 f4 00
23 00 02 fa 00
29 00 05 ff aa 55 a5 00
29 00 06 f0 55 aa 52 08 00
23 00 02 b1 21
29 00 03 b2 10 82
29 00 03 b2 87 22
29 00 04 b4 25 02 8c
29 00 03 b5 0a 00
29 00 04 b8 00 04 02
29 00 0a b9 03 00 18 11 31 44 03 51 00
29 00 03 ba 00 32
29 00 03 bc 4f 00
29 00 05 bd 00 b6 10 10
29 00 03 c6 11 10
29 00 06 f0 55 aa 52 08 01
29 00 03 b1 11 11
29 00 07 b2 08 08 08 08 08 08
29 00 07 b3 0f 19 0f 19 0f 19
29 00 07 b6 15 14 15 14 15 14
29 00 03 bc 5f 00
29 00 03 bd 5f 00
29 00 03 be 00 db
23 00 02 ca 0f
29 00 06 f0 55 aa 52 08 02
29 00 0f b0 00 0e 29 36 3f 48 51 3b 37
3c 3c 51 61 60
29 00 0f b1 59 6a 81 81 94 9b a8 a8 af
b6 bd c4 cc ff
29 00 0f b2 00 0e 29 36 3f 48 51 3b 37
3c 3c 51 61 60
29 00 10 b3 59 6a 81 81 94 9b a8 a8 af
b6 bd c4 ca cc ff
29 00 0f b4 00 0e 29 36 3f 48 51 3b 37
3c 3c 51 61 60
29 00 10 b5 59 6a 81 81 94 9b a8 a8 af
b6 bd c4 ca cc ff
29 00 0f b6 00 0e 29 36 3f 48 51 3b 37
3c 3c 51 61 60
29 00 10 b7 59 6a 81 81 94 9b a8 a8 af
b6 bd c4 ca cc ff
29 00 0f b8 00 0e 29 36 3f 48 51 3b 37
3c 3c 51 61 60
29 00 10 b9 59 6a 81 81 94 9b a8 a8 af
b6 bd c4 ca cc ff
29 00 0f ba 00 0e 29 36 3f 48 51 3b 37
3c 3c 51 61 60
29 00 10 bb 59 6a 81 81 94 9b a8 a8 af
b6 bd c4 ca cc ff
29 00 06 f0 55 aa 52 08 03
29 00 05 b0 00 00 00 00
29 00 05 b1 03 00 00 03
29 00 08 b2 00 00 64 00 64 05 02
29 00 03 b4 00 08
29 00 05 b5 12 28 06 06
29 00 06 ba 31 00 01 00 09
29 00 06 bb 31 00 01 00 09
29 00 06 f0 55 aa 52 08 05
29 00 04 b0 03 11 3f
29 00 03 b2 06 60
29 00 03 b3 10 33
23 00 02 b4 26
29 00 04 b5 06 20 00
29 00 04 b6 86 e0 00
29 00 06 ba 8e 00 00 a4 00
29 00 06 bb 06 00 00 20 00
29 00 06 bc 8e 00 00 a4 00
29 00 06 bd 2e 00 00 a4 00
29 00 06 be 8e 00 00 a0 00
29 00 06 bf 06 00 00 24 00
23 00 02 c1 00
29 00 03 c8 05 10
29 00 03 c9 03 10
29 00 04 d0 00 0a 02
29 00 04 d1 00 0a 04
23 00 02 ec 12
23 00 02 ed 00
29 00 03 ee 03 00
29 00 06 f0 55 aa 52 08 06
29 00 06 b0 00 04 08 11 12
29 00 06 b1 1f 15 16 1f 1f
29 00 06 b2 1f 13 1f 1f 1f
29 00 06 b3 1f 19 19 19 19
29 00 06 b4 1b 1b 1b 1b 1d
29 00 04 b5 1d 1d 1d
29 00 06 b6 00 05 09 11 12
29 00 06 b7 1f 15 16 1f 1f
29 00 06 b8 1f 13 1f 1f 1f
29 00 06 b9 1f 19 19 19 19
29 00 06 ba 1b 1b 1b 1b 1d
29 00 04 bb 1d 1d 1d
29 00 06 c0 00 09 05 12 11
29 00 06 c1 1f 15 16 1f 1f
29 00 06 c2 1f 13 1f 1f 1f
29 00 06 c3 1f 19 19 19 19
29 00 06 c4 1b 1b 1b 1b 1d
29 00 04 c5 1d 1d 1d
29 00 06 c6 00 08 04 12 11
29 00 06 c7 1f 15 16 1f 1f
29 00 06 c8 1f 13 1f 1f 1f
29 00 06 c9 1f 19 19 19 19
29 00 06 ca 1b 1b 1b 1b 1d
29 00 04 cb 1d 1d 1d
29 78 04 d0 00 aa 0a
05 78 01 11
05 78 01 29
];
panel-exit-sequence = [
05 00 01 28
05 00 01 10
];
};
};
display-timings {
src-timing {
clock-frequency = <264000000>;
hactive = <1440>;
vactive = <2560>;
hfront-porch = <150>;
hsync-len = <30>;
hback-porch = <60>;
vfront-porch = <20>;
vsync-len = <20>;
vback-porch = <20>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <264000000>;
hactive = <1440>;
vactive = <2560>;
hfront-porch = <150>;
hsync-len = <30>;
hback-porch = <60>;
vfront-porch = <20>;
vsync-len = <20>;
vback-porch = <20>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <264000000>;
hactive = <1440>;
vactive = <2560>;
hfront-porch = <150>;
hsync-len = <30>;
hback-porch = <60>;
vfront-porch = <20>;
vsync-len = <20>;
vback-porch = <20>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&hdmi_in_vp0 {
status = "okay";
};
&hdmi_in_vp1 {
status = "disabled";
};
&route_hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing {
clock-frequency = <264000000>;
hactive = <1440>;
vactive = <2560>;
hfront-porch = <150>;
hsync-len = <30>;
hback-porch = <60>;
vfront-porch = <20>;
vsync-len = <20>;
vback-porch = <20>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};

View File

@@ -0,0 +1,137 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
&backlight {
enable-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
};
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <150>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
pinctrl-names = "default";
pinctrl-0 = <&rk628_reset &refclk_pins>;
assigned-clocks = <&pmucru CLK_WIFI>;
assigned-clock-rates = <24000000>;
clocks = <&pmucru CLK_WIFI>;
clock-names = "soc_24M";
rk628,hdmi-in;
rk628-gvi {
/* "rgb666"
* "rgb888"
* "rgb101010"
* "yuyv8"
* "yuyv10"
*/
bus-format = "rgb888";
gvi,lanes = <8>;
//"rockchip,division-mode";
//"rockchip, gvi-frm-rst";
status = "okay";
};
display-timings {
src-timing {
clock-frequency = <594000000>;
hactive = <3840>;
vactive = <2160>;
hback-porch = <296>;
hfront-porch = <176>;
vback-porch = <72>;
vfront-porch = <8>;
hsync-len = <88>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <594000000>;
hactive = <3840>;
vactive = <2160>;
hback-porch = <296>;
hfront-porch = <176>;
vback-porch = <72>;
vfront-porch = <8>;
hsync-len = <88>;
vsync-len = <10>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing {
clock-frequency = <594000000>;
hactive = <3840>;
vactive = <2160>;
hback-porch = <296>;
hfront-porch = <176>;
vback-porch = <72>;
vfront-porch = <8>;
hsync-len = <88>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&hdmi_in_vp0 {
status = "okay";
};
&hdmi_in_vp1 {
status = "disabled";
};
&route_hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing {
clock-frequency = <594000000>;
hactive = <3840>;
vactive = <2160>;
hback-porch = <296>;
hfront-porch = <176>;
vback-porch = <72>;
vfront-porch = <8>;
hsync-len = <88>;
vsync-len = <10>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&vcc3v3_lcd0_n {
gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View File

@@ -0,0 +1,122 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
#include <dt-bindings/display/media-bus-format.h>
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-enable-gpios = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <10>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
rk628,hdmi-in;
rk628-lvds {
/* "jeida_18","vesa_24","vesa_18" */
bus-format = "jeida_24";
/* "dual_link_odd_even_pixels"
* "dual_link_even_odd_pixels"
* "dual_link_left_right_pixels"
* "dual_link_right_left_pixels"
*/
link-type = "single_link";
status = "okay";
};
display-timings {
src-timing {
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <10>;
vsync-len = <2>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <10>;
vsync-len = <2>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <10>;
vsync-len = <2>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&hdmi_in_vp0 {
status = "okay";
};
&hdmi_in_vp1 {
status = "disabled";
};
&route_hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <10>;
vsync-len = <2>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};

View File

@@ -0,0 +1,130 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include <dt-bindings/display/media-bus-format.h>
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
&backlight {
enable-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
};
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <10>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
rk628,hdmi-in;
rk628-lvds {
/* "jeida_18","vesa_24","vesa_18" */
bus-format = "vesa_24";
/* "dual_link_odd_even_pixels"
* "dual_link_even_odd_pixels"
* "dual_link_left_right_pixels"
* "dual_link_right_left_pixels"
*/
link-type = "dual_link_even_odd_pixels";
status = "okay";
};
display-timings {
src-timing {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <148>;
hfront-porch = <88>;
vback-porch = <36>;
vfront-porch = <4>;
hsync-len = <44>;
vsync-len = <5>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <148>;
hfront-porch = <88>;
vback-porch = <36>;
vfront-porch = <4>;
hsync-len = <44>;
vsync-len = <5>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <148>;
hfront-porch = <88>;
vback-porch = <36>;
vfront-porch = <4>;
hsync-len = <44>;
vsync-len = <5>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&hdmi_in_vp0 {
status = "okay";
};
&hdmi_in_vp1 {
status = "disabled";
};
&route_hdmi {
status = "okay";
force-bus-format = <MEDIA_BUS_FMT_RGB888_1X24>;
force-output;
force_timing{
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <148>;
hfront-porch = <88>;
vback-porch = <36>;
vfront-porch = <4>;
hsync-len = <44>;
vsync-len = <5>;
hsync-active = <1>;
vsync-active = <1>;
de-active = <0>;
pixelclk-active = <0>;
};
};
&vcc3v3_lcd0_n {
gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View File

@@ -0,0 +1,399 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
/ {
panel@0 {
compatible = "simple-panel";
disp_timings3: display-timings {
native-mode = <&rgb2dsi_timing>;
rgb2dsi_timing: timing0 {
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hfront-porch = <15>;
hsync-len = <2>;
hback-porch = <30>;
vfront-porch = <15>;
vsync-len = <2>;
vback-porch = <15>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <1>;
};
};
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
};
};
};
};
&gt1x {
status = "okay";
power-supply = <&vcc3v3_lcd0_n>;
goodix,rst-gpio = <&gpio0 RK_PB0 GPIO_ACTIVE_HIGH>;
goodix,irq-gpio = <&gpio0 RK_PA4 IRQ_TYPE_LEVEL_LOW>;
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <10>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
rk628,rgb-in;
rk628-dsi {
//rockchip,dual-channel;
dsi,eotp;
dsi,video-mode;
dsi,format = "rgb888";
dsi,lanes = <4>;
status = "okay";
rk628-panel {
panel-init-sequence = [
23 00 02 FE 21
23 00 02 04 00
23 00 02 00 64
23 00 02 2A 00
23 00 02 26 64
23 00 02 54 00
23 00 02 50 64
23 00 02 7B 00
23 00 02 77 64
23 00 02 A2 00
23 00 02 9D 64
23 00 02 C9 00
23 00 02 C5 64
23 00 02 01 71
23 00 02 27 71
23 00 02 51 71
23 00 02 78 71
23 00 02 9E 71
23 00 02 C6 71
23 00 02 02 89
23 00 02 28 89
23 00 02 52 89
23 00 02 79 89
23 00 02 9F 89
23 00 02 C7 89
23 00 02 03 9E
23 00 02 29 9E
23 00 02 53 9E
23 00 02 7A 9E
23 00 02 A0 9E
23 00 02 C8 9E
23 00 02 09 00
23 00 02 05 B0
23 00 02 31 00
23 00 02 2B B0
23 00 02 5A 00
23 00 02 55 B0
23 00 02 80 00
23 00 02 7C B0
23 00 02 A7 00
23 00 02 A3 B0
23 00 02 CE 00
23 00 02 CA B0
23 00 02 06 C0
23 00 02 2D C0
23 00 02 56 C0
23 00 02 7D C0
23 00 02 A4 C0
23 00 02 CB C0
23 00 02 07 CF
23 00 02 2F CF
23 00 02 58 CF
23 00 02 7E CF
23 00 02 A5 CF
23 00 02 CC CF
23 00 02 08 DD
23 00 02 30 DD
23 00 02 59 DD
23 00 02 7F DD
23 00 02 A6 DD
23 00 02 CD DD
23 00 02 0E 15
23 00 02 0A E9
23 00 02 36 15
23 00 02 32 E9
23 00 02 5F 15
23 00 02 5B E9
23 00 02 85 15
23 00 02 81 E9
23 00 02 AD 15
23 00 02 A9 E9
23 00 02 D3 15
23 00 02 CF E9
23 00 02 0B 14
23 00 02 33 14
23 00 02 5C 14
23 00 02 82 14
23 00 02 AA 14
23 00 02 D0 14
23 00 02 0C 36
23 00 02 34 36
23 00 02 5D 36
23 00 02 83 36
23 00 02 AB 36
23 00 02 D1 36
23 00 02 0D 6B
23 00 02 35 6B
23 00 02 5E 6B
23 00 02 84 6B
23 00 02 AC 6B
23 00 02 D2 6B
23 00 02 13 5A
23 00 02 0F 94
23 00 02 3B 5A
23 00 02 37 94
23 00 02 64 5A
23 00 02 60 94
23 00 02 8A 5A
23 00 02 86 94
23 00 02 B2 5A
23 00 02 AE 94
23 00 02 D8 5A
23 00 02 D4 94
23 00 02 10 D1
23 00 02 38 D1
23 00 02 61 D1
23 00 02 87 D1
23 00 02 AF D1
23 00 02 D5 D1
23 00 02 11 04
23 00 02 39 04
23 00 02 62 04
23 00 02 88 04
23 00 02 B0 04
23 00 02 D6 04
23 00 02 12 05
23 00 02 3A 05
23 00 02 63 05
23 00 02 89 05
23 00 02 B1 05
23 00 02 D7 05
23 00 02 18 AA
23 00 02 14 36
23 00 02 42 AA
23 00 02 3D 36
23 00 02 69 AA
23 00 02 65 36
23 00 02 8F AA
23 00 02 8B 36
23 00 02 B7 AA
23 00 02 B3 36
23 00 02 DD AA
23 00 02 D9 36
23 00 02 15 74
23 00 02 3F 74
23 00 02 66 74
23 00 02 8C 74
23 00 02 B4 74
23 00 02 DA 74
23 00 02 16 9F
23 00 02 40 9F
23 00 02 67 9F
23 00 02 8D 9F
23 00 02 B5 9F
23 00 02 DB 9F
23 00 02 17 DC
23 00 02 41 DC
23 00 02 68 DC
23 00 02 8E DC
23 00 02 B6 DC
23 00 02 DC DC
23 00 02 1D FF
23 00 02 19 03
23 00 02 47 FF
23 00 02 43 03
23 00 02 6E FF
23 00 02 6A 03
23 00 02 94 FF
23 00 02 90 03
23 00 02 BC FF
23 00 02 B8 03
23 00 02 E2 FF
23 00 02 DE 03
23 00 02 1A 35
23 00 02 44 35
23 00 02 6B 35
23 00 02 91 35
23 00 02 B9 35
23 00 02 DF 35
23 00 02 1B 45
23 00 02 45 45
23 00 02 6C 45
23 00 02 92 45
23 00 02 BA 45
23 00 02 E0 45
23 00 02 1C 55
23 00 02 46 55
23 00 02 6D 55
23 00 02 93 55
23 00 02 BB 55
23 00 02 E1 55
23 00 02 22 FF
23 00 02 1E 68
23 00 02 4C FF
23 00 02 48 68
23 00 02 73 FF
23 00 02 6F 68
23 00 02 99 FF
23 00 02 95 68
23 00 02 C1 FF
23 00 02 BD 68
23 00 02 E7 FF
23 00 02 E3 68
23 00 02 1F 7E
23 00 02 49 7E
23 00 02 70 7E
23 00 02 96 7E
23 00 02 BE 7E
23 00 02 E4 7E
23 00 02 20 97
23 00 02 4A 97
23 00 02 71 97
23 00 02 97 97
23 00 02 BF 97
23 00 02 E5 97
23 00 02 21 B5
23 00 02 4B B5
23 00 02 72 B5
23 00 02 98 B5
23 00 02 C0 B5
23 00 02 E6 B5
23 00 02 25 F0
23 00 02 23 E8
23 00 02 4F F0
23 00 02 4D E8
23 00 02 76 F0
23 00 02 74 E8
23 00 02 9C F0
23 00 02 9A E8
23 00 02 C4 F0
23 00 02 C2 E8
23 00 02 EA F0
23 00 02 E8 E8
23 00 02 24 FF
23 00 02 4E FF
23 00 02 75 FF
23 00 02 9B FF
23 00 02 C3 FF
23 00 02 E9 FF
23 00 02 FE 3D
23 00 02 00 04
23 00 02 FE 23
23 00 02 08 82
23 00 02 0A 00
23 00 02 0B 00
23 00 02 0C 01
23 00 02 16 00
23 00 02 18 02
23 00 02 1B 04
23 00 02 19 04
23 00 02 1C 81
23 00 02 1F 00
23 00 02 20 03
23 00 02 23 04
23 00 02 21 01
23 00 02 54 63
23 00 02 55 54
23 00 02 6E 45
23 00 02 6D 36
23 00 02 FE 3D
23 00 02 55 78
23 00 02 FE 20
23 00 02 26 30
23 00 02 FE 3D
23 00 02 20 71
23 00 02 50 8F
23 00 02 51 8F
23 00 02 FE 00
23 00 02 35 00
05 78 01 11
05 00 01 29
];
panel-exit-sequence = [
05 00 01 28
05 00 01 10
];
};
};
display-timings {
src-timing {
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hback-porch = <30>;
hfront-porch = <15>;
vback-porch = <15>;
vfront-porch = <15>;
hsync-len = <2>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <132000000>;
hactive = <1080>;
vactive = <1920>;
hback-porch = <30>;
hfront-porch = <15>;
vback-porch = <15>;
vfront-porch = <15>;
hsync-len = <2>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&route_rgb {
status = "okay";
};
&rgb_in_vp2 {
status = "okay";
};
&rgb {
status = "okay";
ports {
port@1 {
reg = <1>;
rgb_out_panel: endpoint {
remote-endpoint = <&panel_in_rgb>;
};
};
};
};
&touch_gpio {
rockchip,pins = <0 RK_PA4 RK_FUNC_GPIO &pcfg_pull_up>,
<0 RK_PB0 RK_FUNC_GPIO &pcfg_pull_none>;
};

View File

@@ -0,0 +1,140 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
/ {
panel@0 {
compatible = "simple-panel";
disp_timings3: display-timings {
native-mode = <&rgb2lvds_timing>;
rgb2lvds_timing: timing0 {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <148>;
hfront-porch = <88>;
vback-porch = <36>;
vfront-porch = <4>;
hsync-len = <44>;
vsync-len = <5>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
};
};
};
};
&backlight {
enable-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
};
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <100>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
pinctrl-names = "default";
pinctrl-0 = <&rk628_reset &refclk_pins>;
assigned-clocks = <&pmucru CLK_WIFI>;
assigned-clock-rates = <24000000>;
clocks = <&pmucru CLK_WIFI>;
clock-names = "soc_24M";
rk628,rgb-in;
rk628-gvi {
/* "rgb666"
* "rgb888"
* "rgb101010"
* "yuyv8"
* "yuyv10"
*/
bus-format = "rgb888";
gvi,lanes = <8>;
//"rockchip,division-mode";
//"rockchip, gvi-frm-rst";
status = "okay";
};
display-timings {
src-timing {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <148>;
hfront-porch = <88>;
vback-porch = <36>;
vfront-porch = <4>;
hsync-len = <44>;
vsync-len = <5>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <594000000>;
hactive = <3840>;
vactive = <2160>;
hback-porch = <296>;
hfront-porch = <176>;
vback-porch = <72>;
vfront-porch = <8>;
hsync-len = <88>;
vsync-len = <10>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&route_rgb {
status = "okay";
};
&rgb_in_vp2 {
status = "okay";
};
&rgb {
status = "okay";
ports {
port@1 {
reg = <1>;
rgb_out_panel: endpoint {
remote-endpoint = <&panel_in_rgb>;
};
};
};
};
&vcc3v3_lcd0_n {
gpio = <&gpio1 RK_PA3 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View File

@@ -0,0 +1,69 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
&backlight {
enable-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
};
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
assigned-clocks = <&pmucru CLK_WIFI>;
assigned-clock-rates = <24000000>;
clocks = <&pmucru CLK_WIFI>;
clock-names = "soc_24M";
pinctrl-names = "default";
pinctrl-0 = <&rk628_reset &refclk_pins>;
rk628,rgb-in;
rk628,hdmi-out;
status = "okay";
port {
rgb_in_hdmi: endpoint {
remote-endpoint = <&rgb_out_hdmi>;
};
};
};
&i2c5 {
status = "disabled";
};
&i2s2_2ch {
status = "okay";
};
&route_rgb {
status = "disabled";
};
&rgb_in_vp2 {
status = "okay";
};
&rgb {
status = "okay";
ports {
port@1 {
reg = <1>;
rgb_out_hdmi: endpoint {
remote-endpoint = <&rgb_in_hdmi>;
};
};
};
};
&rk628_sound {
status = "okay";
};

View File

@@ -0,0 +1,128 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
/ {
panel@0 {
compatible = "simple-panel";
disp_timings3: display-timings {
native-mode = <&rgb2lvds_timing>;
rgb2lvds_timing: timing0 {
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <4>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
};
};
};
};
&backlight {
pwms = <&pwm4 0 25000 PWM_POLARITY_INVERTED>;
};
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <10>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
rk628,rgb-in;
rk628-lvds {
/* "jeida_18","vesa_24","vesa_18" */
bus-format = "jeida_24";
/* "dual_link_odd_even_pixels"
* "dual_link_even_odd_pixels"
* "dual_link_left_right_pixels"
* "dual_link_right_left_pixels"
*/
link-type = "single_link";
status = "okay";
};
display-timings {
src-timing {
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <4>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <66000000>;
hactive = <800>;
vactive = <1280>;
hback-porch = <30>;
hfront-porch = <30>;
vback-porch = <3>;
vfront-porch = <3>;
hsync-len = <4>;
vsync-len = <2>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&route_rgb {
status = "okay";
};
&rgb_in_vp2 {
status = "okay";
};
&rgb {
status = "okay";
ports {
port@1 {
reg = <1>;
rgb_out_panel: endpoint {
remote-endpoint = <&panel_in_rgb>;
};
};
};
};

View File

@@ -0,0 +1,134 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2020 Rockchip Electronics Co., Ltd.
*
*/
#include "rk3568-evb-rk628-ddr4-v10.dtsi"
#include "rk3568-android.dtsi"
/ {
panel@0 {
compatible = "simple-panel";
disp_timings3: display-timings {
native-mode = <&rgb2lvds_timing>;
rgb2lvds_timing: timing0 {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <96>;
hfront-porch = <120>;
vback-porch = <8>;
vfront-porch = <33>;
hsync-len = <64>;
vsync-len = <4>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
port {
panel_in_rgb: endpoint {
remote-endpoint = <&rgb_out_panel>;
};
};
};
};
&backlight {
enable-gpios = <&gpio2 RK_PA4 GPIO_ACTIVE_HIGH>;
pwms = <&pwm4 0 25000 PWM_POLARITY_INVERTED>;
};
&gt1x {
status = "disabled";
};
&i2c2_rk628 {
panel-backlight = <&backlight>;
panel-power-supply = <&vcc3v3_lcd0_n>;
panel-reset-delay-ms = <10>;
panel-enable-delay-ms = <10>;
panel-prepare-delay-ms = <60>;
panel-unprepare-delay-ms = <10>;
panel-disable-delay-ms = <60>;
rk628,rgb-in;
rk628-lvds {
/* "jeida_18","vesa_24","vesa_18" */
bus-format = "vesa_24";
/* "dual_link_odd_even_pixels"
* "dual_link_even_odd_pixels"
* "dual_link_left_right_pixels"
* "dual_link_right_left_pixels"
*/
link-type = "dual_link_even_odd_pixels";
status = "okay";
};
display-timings {
src-timing {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <96>;
hfront-porch = <120>;
vback-porch = <8>;
vfront-porch = <33>;
hsync-len = <64>;
vsync-len = <4>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
dst-timing {
clock-frequency = <148500000>;
hactive = <1920>;
vactive = <1080>;
hback-porch = <96>;
hfront-porch = <120>;
vback-porch = <8>;
vfront-porch = <33>;
hsync-len = <64>;
vsync-len = <4>;
hsync-active = <0>;
vsync-active = <0>;
de-active = <0>;
pixelclk-active = <0>;
};
};
};
&route_rgb {
status = "okay";
};
&rgb_in_vp2 {
status = "okay";
};
&rgb {
status = "okay";
ports {
port@1 {
reg = <1>;
rgb_out_panel: endpoint {
remote-endpoint = <&panel_in_rgb>;
};
};
};
};
&vcc3v3_lcd0_n {
gpio = <&gpio2 RK_PC6 GPIO_ACTIVE_HIGH>;
enable-active-high;
};

View File

@@ -31,40 +31,6 @@
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
hdmi_mipi2_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&hdmiin_out1>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi2_csi2_input>;
};
};
};
};
&csi2_dphy0_hw {
status = "okay";
};
&csi2_dcphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
@@ -92,7 +58,46 @@
};
};
&csi2_dphy0_hw {
status = "okay";
};
&csi2_dphy1 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
hdmi_mipi2_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&hdmiin_out1>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi2_csi2_input>;
};
};
};
};
&csi2_dphy1_hw {
status = "okay";
};
&i2c3 {
clock-frequency = <400000>;
status = "okay";
rk628_csi_1: rk628_csi_1@50 {
@@ -113,6 +118,15 @@
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "HDMI-MIPI2";
rockchip,camera-module-lens-name = "RK628-CSI";
multi-dev-info {
dev-idx-l = <2>;
dev-idx-r = <4>;
combine-idx = <2>;
pixel-offset = <0>;
dev-num = <2>;
};
port {
hdmiin_out1: endpoint {
remote-endpoint = <&hdmi_mipi2_in>;
@@ -123,6 +137,7 @@
};
&i2c5 {
clock-frequency = <400000>;
status = "okay";
rk628_csi: rk628_csi@50 {
@@ -143,6 +158,15 @@
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "HDMI-MIPI";
rockchip,camera-module-lens-name = "RK628-CSI";
multi-dev-info {
dev-idx-l = <0>;
dev-idx-r = <1>;
combine-idx = <0>;
pixel-offset = <0>;
dev-num = <2>;
};
port {
hdmiin_out0: endpoint {
remote-endpoint = <&hdmi_mipi0_in>;
@@ -156,6 +180,10 @@
status = "okay";
};
&mipi_dcphy1 {
status = "okay";
};
&mipi0_csi2 {
status = "okay";

View File

@@ -0,0 +1,175 @@
// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
* Copyright (c) 2022 Rockchip Electronics Co., Ltd.
*
*/
/dts-v1/;
#include "rk3588-evb7-v11.dtsi"
#include "rk3588-android.dtsi"
/ {
model = "Rockchip RK3588 EVB7 V11 Board + Rockchip RK628 HDMI to MIPI Extboard";
compatible = "rockchip,rk3588-evb7-v11", "rockchip,rk3588";
vcc_mipicsi0: vcc-mipicsi0-regulator {
/delete-property/ gpio;
/delete-property/ pinctrl-0;
};
vcc_mipicsi1: vcc-mipicsi1-regulator {
/delete-property/ gpio;
/delete-property/ pinctrl-0;
};
vcc_mipidcphy0: vcc-mipidcphy0-regulator {
/delete-property/ gpio;
/delete-property/ pinctrl-0;
};
};
&csi2_dphy0 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
hdmi_mipi2_in: endpoint@1 {
reg = <1>;
remote-endpoint = <&hdmiin_out1>;
data-lanes = <1 2 3 4>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
csidphy0_out: endpoint@0 {
reg = <0>;
remote-endpoint = <&mipi2_csi2_input>;
};
};
};
};
&csi2_dphy0_hw {
status = "okay";
};
&csi2_dphy1_hw {
status = "okay";
};
&i2c3 {
status = "okay";
clock-frequency = <400000>;
rk628_csi: rk628_csi@50 {
reg = <0x50>;
compatible = "rockchip,rk628-csi-v4l2";
status = "okay";
power-domains = <&power RK3588_PD_VI>;
pinctrl-names = "default";
pinctrl-0 = <&rk628_pin>;
interrupt-parent = <&gpio1>;
interrupts = <RK_PB2 IRQ_TYPE_LEVEL_HIGH>;
enable-gpios = <&gpio1 RK_PA7 GPIO_ACTIVE_HIGH>;
reset-gpios = <&gpio1 RK_PB1 GPIO_ACTIVE_HIGH>;
plugin-det-gpios = <&gpio2 RK_PB6 GPIO_ACTIVE_LOW>;
continues-clk = <1>;
rockchip,camera-module-index = <0>;
rockchip,camera-module-facing = "back";
rockchip,camera-module-name = "HDMI-MIPI2";
rockchip,camera-module-lens-name = "RK628-CSI";
multi-dev-info {
dev-idx-l = <2>;
dev-idx-r = <4>;
combine-idx = <2>;
pixel-offset = <0>;
dev-num = <2>;
};
port {
hdmiin_out1: endpoint {
remote-endpoint = <&hdmi_mipi2_in>;
data-lanes = <1 2 3 4>;
};
};
};
};
&mipi_dcphy0 {
status = "okay";
};
&mipi_dcphy1 {
status = "okay";
};
&mipi2_csi2 {
status = "okay";
ports {
#address-cells = <1>;
#size-cells = <0>;
port@0 {
reg = <0>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_input: endpoint@1 {
reg = <1>;
remote-endpoint = <&csidphy0_out>;
};
};
port@1 {
reg = <1>;
#address-cells = <1>;
#size-cells = <0>;
mipi2_csi2_output: endpoint@0 {
reg = <0>;
remote-endpoint = <&cif_mipi_in2>;
};
};
};
};
&rkcif {
status = "okay";
};
&rkcif_mipi_lvds2 {
status = "okay";
port {
cif_mipi_in2: endpoint {
remote-endpoint = <&mipi2_csi2_output>;
};
};
};
&rkcif_mmu {
status = "okay";
};
&pinctrl {
hdmiin {
rk628_pin: rk628-pin {
rockchip,pins = <1 RK_PB2 RK_FUNC_GPIO &pcfg_pull_none>,
<1 RK_PA7 RK_FUNC_GPIO &pcfg_pull_none>,
<1 RK_PB1 RK_FUNC_GPIO &pcfg_pull_none>,
<2 RK_PB6 RK_FUNC_GPIO &pcfg_pull_none>;
};
};
};

View File

@@ -293,6 +293,8 @@ CONFIG_BLK_DEV_LOOP_MIN_COUNT=16
CONFIG_BLK_DEV_RAM=y
CONFIG_BLK_DEV_RAM_SIZE=8192
CONFIG_BLK_DEV_NVME=y
CONFIG_RK628_MISC=y
CONFIG_RK628_MISC_HDMITX=y
CONFIG_LT7911D_FB_NOTIFIER=y
CONFIG_SRAM=y
CONFIG_UID_SYS_STATS=y
@@ -556,7 +558,6 @@ CONFIG_ROCKCHIP_THERMAL=y
CONFIG_WATCHDOG=y
CONFIG_DW_WATCHDOG=y
CONFIG_MFD_RK618=y
CONFIG_MFD_RK628=y
CONFIG_MFD_RK630_I2C=y
CONFIG_MFD_RK806_I2C=y
CONFIG_MFD_RK806_SPI=y
@@ -639,7 +640,6 @@ CONFIG_ROCKCHIP_LVDS=y
CONFIG_ROCKCHIP_RGB=y
CONFIG_ROCKCHIP_DW_HDCP2=y
CONFIG_DRM_ROCKCHIP_RK618=y
CONFIG_DRM_ROCKCHIP_RK628=y
CONFIG_DRM_PANEL_SIMPLE=y
CONFIG_DRM_PANEL_MAXIM_MAX96752F=y
CONFIG_DRM_PANEL_MAXIM_MAX96772=y

View File

@@ -2,7 +2,8 @@
#
# Makefile for the Rockchip RK628 display bridge driver.
#
video-rk628-objs := rk628.o rk628_cru.o rk628_hdmirx.o rk628_dsi.o rk628_combrxphy.o rk628_combtxphy.o
video-rk628-objs := rk628.o rk628_cru.o rk628_hdmirx.o rk628_dsi.o rk628_combrxphy.o \
rk628_combtxphy.o rk628_mipi_dphy.o rk628_post_process.o
obj-$(CONFIG_VIDEO_RK628) += video-rk628.o
rk628-csi-objs := rk628_csi_v4l2.o

View File

@@ -22,6 +22,7 @@
static const struct regmap_range rk628_cru_readable_ranges[] = {
regmap_reg_range(CRU_CPLL_CON0, CRU_CPLL_CON4),
regmap_reg_range(CRU_GPLL_CON0, CRU_GPLL_CON4),
regmap_reg_range(CRU_APLL_CON0, CRU_APLL_CON4),
regmap_reg_range(CRU_MODE_CON00, CRU_MODE_CON00),
regmap_reg_range(CRU_CLKSEL_CON00, CRU_CLKSEL_CON21),
regmap_reg_range(CRU_GATE_CON00, CRU_GATE_CON05),
@@ -46,12 +47,12 @@ static const struct regmap_access_table rk628_combrxphy_readable_table = {
};
static const struct regmap_range rk628_hdmirx_readable_ranges[] = {
regmap_reg_range(HDMI_RX_HDMI_SETUP_CTRL, HDMI_RX_HDMI_SETUP_CTRL),
regmap_reg_range(HDMI_RX_HDMI_SETUP_CTRL, HDMI_RX_HDMI_TIMER_CTRL),
regmap_reg_range(HDMI_RX_HDMI_PCB_CTRL, HDMI_RX_HDMI_PCB_CTRL),
regmap_reg_range(HDMI_RX_HDMI_MODE_RECOVER, HDMI_RX_HDMI_ERROR_PROTECT),
regmap_reg_range(HDMI_RX_HDMI_SYNC_CTRL, HDMI_RX_HDMI_CKM_RESULT),
regmap_reg_range(HDMI_RX_HDMI_RESMPL_CTRL, HDMI_RX_HDMI_RESMPL_CTRL),
regmap_reg_range(HDMI_VM_CFG_CH2, HDMI_VM_CFG_CH2),
regmap_reg_range(HDMI_VM_CFG_CH0_1, HDMI_VM_CFG_CH2),
regmap_reg_range(HDMI_RX_HDCP_CTRL, HDMI_RX_HDCP_SETTINGS),
regmap_reg_range(HDMI_RX_HDCP_KIDX, HDMI_RX_HDCP_KIDX),
regmap_reg_range(HDMI_RX_HDCP_DBG, HDMI_RX_HDCP_AN0),
@@ -67,6 +68,7 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = {
regmap_reg_range(HDMI_RX_AUD_CHEXTR_CTRL, HDMI_RX_AUD_PAO_CTRL),
regmap_reg_range(HDMI_RX_AUD_FIFO_STS, HDMI_RX_AUD_FIFO_STS),
regmap_reg_range(HDMI_RX_AUDPLL_GEN_CTS, HDMI_RX_AUDPLL_GEN_N),
regmap_reg_range(HDMI_RX_I2CM_PHYG3_DATAI, HDMI_RX_I2CM_PHYG3_DATAI),
regmap_reg_range(HDMI_RX_PDEC_CTRL, HDMI_RX_PDEC_CTRL),
regmap_reg_range(HDMI_RX_PDEC_AUDIODET_CTRL, HDMI_RX_PDEC_AUDIODET_CTRL),
regmap_reg_range(HDMI_RX_PDEC_ERR_FILTER, HDMI_RX_PDEC_ASP_CTRL),
@@ -76,8 +78,9 @@ static const struct regmap_range rk628_hdmirx_readable_ranges[] = {
regmap_reg_range(HDMI_RX_PDEC_AIF_CTRL, HDMI_RX_PDEC_AIF_PB0),
regmap_reg_range(HDMI_RX_PDEC_AVI_PB, HDMI_RX_PDEC_AVI_PB),
regmap_reg_range(HDMI_RX_HDMI20_CONTROL, HDMI_RX_CHLOCK_CONFIG),
regmap_reg_range(HDMI_RX_SCDC_REGS1, HDMI_RX_SCDC_REGS2),
regmap_reg_range(HDMI_RX_SCDC_REGS0, HDMI_RX_SCDC_REGS2),
regmap_reg_range(HDMI_RX_SCDC_WRDATA0, HDMI_RX_SCDC_WRDATA0),
regmap_reg_range(HDMI_RX_HDMI20_STATUS, HDMI_RX_HDMI20_STATUS),
regmap_reg_range(HDMI_RX_PDEC_ISTS, HDMI_RX_PDEC_IEN),
regmap_reg_range(HDMI_RX_AUD_FIFO_ISTS, HDMI_RX_AUD_FIFO_IEN),
regmap_reg_range(HDMI_RX_MD_ISTS, HDMI_RX_MD_IEN),
@@ -112,6 +115,7 @@ static const struct regmap_range rk628_csi_readable_ranges[] = {
regmap_reg_range(CSITX_CONFIG_DONE, CSITX_CSITX_VERSION),
regmap_reg_range(CSITX_SYS_CTRL0_IMD, CSITX_TIMING_HPW_PADDING_NUM),
regmap_reg_range(CSITX_VOP_PATH_CTRL, CSITX_VOP_PATH_CTRL),
regmap_reg_range(CSITX_VOP_FILTER_CTRL, CSITX_VOP_FILTER_CTRL),
regmap_reg_range(CSITX_VOP_PATH_PKT_CTRL, CSITX_VOP_PATH_PKT_CTRL),
regmap_reg_range(CSITX_CSITX_STATUS0, CSITX_LPDT_DATA_IMD),
regmap_reg_range(CSITX_DPHY_CTRL, CSITX_DPHY_CTRL),
@@ -122,6 +126,21 @@ static const struct regmap_access_table rk628_csi_readable_table = {
.n_yes_ranges = ARRAY_SIZE(rk628_csi_readable_ranges),
};
static const struct regmap_range rk628_csi1_readable_ranges[] = {
regmap_reg_range(CSITX1_CONFIG_DONE, CSITX1_CSITX_VERSION),
regmap_reg_range(CSITX1_SYS_CTRL0_IMD, CSITX1_TIMING_HPW_PADDING_NUM),
regmap_reg_range(CSITX1_VOP_PATH_CTRL, CSITX1_VOP_PATH_CTRL),
regmap_reg_range(CSITX1_VOP_FILTER_CTRL, CSITX1_VOP_FILTER_CTRL),
regmap_reg_range(CSITX1_VOP_PATH_PKT_CTRL, CSITX1_VOP_PATH_PKT_CTRL),
regmap_reg_range(CSITX1_CSITX_STATUS0, CSITX1_LPDT_DATA_IMD),
regmap_reg_range(CSITX1_DPHY_CTRL, CSITX1_DPHY_CTRL),
};
static const struct regmap_access_table rk628_csi1_readable_table = {
.yes_ranges = rk628_csi1_readable_ranges,
.n_yes_ranges = ARRAY_SIZE(rk628_csi1_readable_ranges),
};
static const struct regmap_range rk628_dsi0_readable_ranges[] = {
regmap_reg_range(DSI0_BASE, DSI0_BASE + DSI_MAX_REGISTER),
};
@@ -231,8 +250,192 @@ static const struct regmap_config rk628_regmap_config[RK628_DEV_MAX] = {
.val_format_endian = REGMAP_ENDIAN_LITTLE,
.rd_table = &rk628_csi_readable_table,
},
[RK628_DEV_CSI1] = {
.name = "csi1",
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = CSI1_MAX_REGISTER,
.reg_format_endian = REGMAP_ENDIAN_LITTLE,
.val_format_endian = REGMAP_ENDIAN_LITTLE,
.rd_table = &rk628_csi1_readable_table,
},
};
int rk628_media_i2c_write(struct rk628 *rk628, u32 reg, u32 val)
{
int region = (reg >> 16) & 0xff;
int ret = 0;
if (region >= RK628_DEV_MAX) {
dev_err(rk628->dev,
"%s: i2c err: invalid arguments, out of register range\n", __func__);
return -EINVAL;
}
ret = regmap_write(rk628->regmap[region], reg, val);
if (ret < 0)
dev_err(rk628->dev,
"%s: i2c err reg=0x%x, val=0x%x, ret=%d\n", __func__, reg, val, ret);
return ret;
}
EXPORT_SYMBOL(rk628_media_i2c_write);
int rk628_media_i2c_read(struct rk628 *rk628, u32 reg, u32 *val)
{
int region = (reg >> 16) & 0xff;
int ret = 0;
if (region >= RK628_DEV_MAX) {
dev_err(rk628->dev,
"%s: i2c err: invalid arguments, out of register range\n", __func__);
return -EINVAL;
}
ret = regmap_read(rk628->regmap[region], reg, val);
if (ret < 0)
dev_err(rk628->dev,
"%s: i2c err reg=0x%x, val=0x%x ret=%d\n", __func__, reg, *val, ret);
return ret;
}
EXPORT_SYMBOL(rk628_media_i2c_read);
int rk628_media_i2c_update_bits(struct rk628 *rk628, u32 reg, u32 mask,
u32 val)
{
int region = (reg >> 16) & 0xff;
if (region >= RK628_DEV_MAX) {
dev_err(rk628->dev,
"%s: i2c err: invalid arguments, out of register range\n", __func__);
return -EINVAL;
}
return regmap_update_bits(rk628->regmap[region], reg, mask, val);
}
EXPORT_SYMBOL(rk628_media_i2c_update_bits);
static int rk628_reg_show(struct seq_file *s, void *v)
{
const struct regmap_config *reg;
struct rk628 *rk628 = s->private;
unsigned int i, j;
u32 val;
seq_printf(s, "rk628_%s:\n", file_dentry(s->file)->d_iname);
for (i = 0; i < ARRAY_SIZE(rk628_regmap_config); i++) {
reg = &rk628_regmap_config[i];
if (!reg->name)
continue;
if (!strcmp(reg->name, file_dentry(s->file)->d_iname))
break;
}
if (i == ARRAY_SIZE(rk628_regmap_config))
return -ENODEV;
/* grf */
if (!reg->rd_table) {
for (i = 0; i <= reg->max_register; i += 4) {
rk628_i2c_read(rk628, i, &val);
if (i % 16 == 0)
seq_printf(s, "\n0x%04x:", i);
seq_printf(s, " %08x", val);
}
} else {
const struct regmap_range *range_list = reg->rd_table->yes_ranges;
const struct regmap_range *range;
int range_list_len = reg->rd_table->n_yes_ranges;
for (i = 0; i < range_list_len; i++) {
range = &range_list[i];
for (j = range->range_min; j <= range->range_max; j += 4) {
rk628_i2c_read(rk628, j, &val);
if (j % 16 == 0 || j == range->range_min)
seq_printf(s, "\n0x%04x:", j);
seq_printf(s, " %08x", val);
}
}
seq_puts(s, "\n");
}
return 0;
}
static ssize_t rk628_reg_write(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
struct rk628 *rk628 = file->f_path.dentry->d_inode->i_private;
u32 addr;
u32 val;
char kbuf[25];
int ret;
if (count >= sizeof(kbuf))
return -ENOSPC;
if (copy_from_user(kbuf, buf, count))
return -EFAULT;
kbuf[count] = '\0';
ret = sscanf(kbuf, "%x%x", &addr, &val);
if (ret != 2)
return -EINVAL;
rk628_i2c_write(rk628, addr, val);
return count;
}
static int rk628_reg_open(struct inode *inode, struct file *file)
{
struct rk628 *rk628 = inode->i_private;
return single_open(file, rk628_reg_show, rk628);
}
static const struct file_operations rk628_reg_fops = {
.owner = THIS_MODULE,
.open = rk628_reg_open,
.read = seq_read,
.write = rk628_reg_write,
.llseek = seq_lseek,
.release = single_release,
};
static void rk628_debugfs_register_create(struct rk628 *rk628)
{
const struct regmap_config *reg;
struct dentry *dir;
int i;
dir = debugfs_create_dir("registers", rk628->debug_dir);
if (IS_ERR(dir))
return;
for (i = 0; i < ARRAY_SIZE(rk628_regmap_config); i++) {
reg = &rk628_regmap_config[i];
if (!reg->name)
continue;
debugfs_create_file(reg->name, 0600, dir, rk628, &rk628_reg_fops);
}
}
void rk628_debugfs_create(struct rk628 *rk628)
{
rk628->debug_dir = debugfs_create_dir(dev_name(rk628->dev), debugfs_lookup("rk628", NULL));
if (IS_ERR(rk628->debug_dir))
return;
rk628_debugfs_register_create(rk628);
}
EXPORT_SYMBOL(rk628_debugfs_create);
struct rk628 *rk628_i2c_register(struct i2c_client *client)
{
struct rk628 *rk628;
@@ -259,6 +462,7 @@ struct rk628 *rk628_i2c_register(struct i2c_client *client)
return NULL;
}
}
mutex_init(&rk628->rst_lock);
return rk628;
}
@@ -475,6 +679,29 @@ void rk628_post_process_en(struct rk628 *rk628,
}
EXPORT_SYMBOL(rk628_post_process_en);
static const char * const rk628_version[] = {
"UNKNOWN",
"RK628D",
"RK628F/H",
};
void rk628_version_parse(struct rk628 *rk628)
{
u32 version;
rk628_i2c_read(rk628, GRF_SOC_VERSION, &version);
if (version == 0x20200326)
rk628->version = RK628D_VERSION;
else if (version == 0x20230321)
rk628->version = RK628F_VERSION;
else
rk628->version = RK628_UNKNOWN;
dev_info(rk628->dev, "rk628 version is: %s (%x)\n",
rk628_version[rk628->version], version);
}
EXPORT_SYMBOL(rk628_version_parse);
MODULE_AUTHOR("Shunqing Chen <csq@rock-chips.com>");
MODULE_DESCRIPTION("Rockchip RK628 driver");
MODULE_LICENSE("GPL");

View File

@@ -34,6 +34,8 @@
#define SW_EFUSE_HDCP_EN(x) UPDATE(x, 8, 8)
#define SW_OUTPUT_MODE_MASK GENMASK(7, 3)
#define SW_OUTPUT_MODE(x) UPDATE(x, 7, 3)
#define SW_OUTPUT_COMBTX_MODE_MASK GENMASK(4, 3)
#define SW_OUTPUT_COMBTX_MODE(x) UPDATE(x, 4, 3)
#define SW_INPUT_MODE_MASK GENMASK(2, 0)
#define SW_INPUT_MODE(x) UPDATE(x, 2, 0)
#define GRF_SYSTEM_CON1 0x0004
@@ -45,6 +47,10 @@
#define GRF_GPIO_RXDDC_SDA_SEL(x) UPDATE(x, 6, 6)
#define GRF_GPIO_RXDDC_SCL_SEL_MASK BIT(5)
#define GRF_GPIO_RXDDC_SCL_SEL(x) UPDATE(x, 5, 5)
#define GRF_DPHY_CH1_EN_MASK BIT(1)
#define GRF_DPHY_CH1_EN(x) UPDATE(x, 1, 1)
#define GRF_AS_DSIPHY_MASK BIT(0)
#define GRF_AS_DSIPHY(x) UPDATE(x, 0, 0)
#define GRF_SCALER_CON0 0x0010
#define SCL_VER_DOWN_MODE(x) HIWORD_UPDATE(x, 8, 8)
#define SCL_HOR_DOWN_MODE(x) HIWORD_UPDATE(x, 7, 7)
@@ -87,9 +93,13 @@
#define SW_SPLIT_MODE(x) UPDATE(x, 1, 1)
#define SW_SPLIT_EN BIT(0)
#define GRF_CSC_CTRL_CON 0x0038
#define SW_Y2R_MODE(x) HIWORD_UPDATE(x, 13, 12)
#define SW_FROM_CSC_MATRIX_EN(x) HIWORD_UPDATE(x, 11, 11)
#define SW_YUV2VYU_SWP(x) HIWORD_UPDATE(x, 8, 8)
#define SW_R2Y_EN(x) HIWORD_UPDATE(x, 4, 4)
#define SW_Y2R_EN(x) HIWORD_UPDATE(x, 0, 0)
#define SW_R2Y_CSC_MODE(x) HIWORD_UPDATE(x, 7, 6)
#define SW_Y2R_CSC_MODE(x) HIWORD_UPDATE(x, 3, 2)
#define GRF_LVDS_TX_CON 0x003c
#define SW_LVDS_CON_DUAL_SEL(x) HIWORD_UPDATE(x, 12, 12)
#define SW_LVDS_CON_DEN_POLARITY(x) HIWORD_UPDATE(x, 11, 11)
@@ -173,6 +183,17 @@
#define GRF_GPIO3A_D1_CON 0x00e4
#define GRF_GPIO3B_D_CON 0x00e8
#define GRF_GPIO_SR_CON 0x00ec
#define GRF_BG_CTRL 0x00f0
#define BG_ENABLE_MASK GENMASK(31, 31)
#define BG_ENABLE(x) UPDATE(x, 31, 31)
#define BG_R_OR_V_MASK GENMASK(29, 20)
#define BG_R_OR_V(x) UPDATE(x, 29, 20)
#define BG_G_OR_Y_MASK GENMASK(19, 10)
#define BG_G_OR_Y(x) UPDATE(x, 19, 10)
#define BG_B_OR_U_MASK GENMASK(9, 0)
#define BG_B_OR_U(x) UPDATE(x, 9, 0)
#define GRF_SW_HDMIRXPHY_CRTL 0x00f4
#define GRF_INTR0_EN 0x0100
#define GRF_INTR0_CLR_EN 0x0104
#define GRF_INTR0_STATUS 0x0108
@@ -190,7 +211,15 @@
#define GRF_OS_REG1 0x0144
#define GRF_OS_REG2 0x0148
#define GRF_OS_REG3 0x014c
#define GRF_SOC_VERSION 0x0150
#define GRF_CSC_MATRIX_COE01_COE00 0x01a0
#define GRF_CSC_MATRIX_COE10_COE02 0x01a4
#define GRF_CSC_MATRIX_COE12_COE11 0x01a8
#define GRF_CSC_MATRIX_COE21_COE20 0x01ac
#define GRF_CSC_MATRIX_COE22 0x01b0
#define GRF_CSC_MATRIX_OFFSET0 0x01b4
#define GRF_CSC_MATRIX_OFFSET1 0x01b8
#define GRF_CSC_MATRIX_OFFSET2 0x01bc
#define GRF_SOC_VERSION 0x0200
#define GRF_MAX_REGISTER GRF_SOC_VERSION
enum {
@@ -233,46 +262,58 @@ enum {
RK628_DEV_GPIO1,
RK628_DEV_GPIO2,
RK628_DEV_GPIO3,
RK628_DEV_CSI1 = 0x14,
RK628_DEV_MAX,
};
enum {
RK628_UNKNOWN,
RK628D_VERSION,
RK628F_VERSION,
};
struct mipi_timing {
u8 data_prepare;
u8 data_zero;
u8 data_trail;
u8 clk_prepare;
u8 clk_zero;
u8 clk_trail;
u8 clk_post;
};
struct rk628 {
struct device *dev;
struct i2c_client *client;
struct regmap *regmap[RK628_DEV_MAX];
u8 version;
void *txphy;
u8 dphy_lane_en;
bool dual_mipi;
struct mipi_timing mipi_timing[2];
struct mutex rst_lock;
int tx_mode;
struct dentry *debug_dir;
};
int rk628_media_i2c_write(struct rk628 *rk628, u32 reg, u32 val);
int rk628_media_i2c_read(struct rk628 *rk628, u32 reg, u32 *val);
int rk628_media_i2c_update_bits(struct rk628 *rk628, u32 reg, u32 mask, u32 val);
static inline int rk628_i2c_write(struct rk628 *rk628, u32 reg, u32 val)
{
int region = (reg >> 16) & 0xff;
int ret = 0;
ret = regmap_write(rk628->regmap[region], reg, val);
if (ret < 0)
pr_info("%s: i2c err reg=0x%x, val=0x%x, ret=%d\n", __func__, reg, val, ret);
return ret;
return rk628_media_i2c_write(rk628, reg, val);
}
static inline int rk628_i2c_read(struct rk628 *rk628, u32 reg, u32 *val)
{
int region = (reg >> 16) & 0xff;
int ret = 0;
ret = regmap_read(rk628->regmap[region], reg, val);
if (ret < 0)
pr_info("%s: i2c err reg=0x%x, val=0x%x ret=%d\n", __func__, reg, *val, ret);
return ret;
return rk628_media_i2c_read(rk628, reg, val);
}
static inline int rk628_i2c_update_bits(struct rk628 *rk628, u32 reg, u32 mask,
u32 val)
{
int region = (reg >> 16) & 0xff;
return regmap_update_bits(rk628->regmap[region], reg, mask, val);
return rk628_media_i2c_update_bits(rk628, reg, mask, val);
}
struct rk628 *rk628_i2c_register(struct i2c_client *client);
@@ -280,5 +321,7 @@ void rk628_post_process_en(struct rk628 *rk628,
struct videomode *src,
struct videomode *dst,
u64 *dst_pclk);
void rk628_version_parse(struct rk628 *rk628);
void rk628_debugfs_create(struct rk628 *rk628);
#endif

View File

@@ -44,27 +44,9 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-3)");
#define DRIVER_VERSION KERNEL_VERSION(0, 0x0, 0x1)
#define DRIVER_VERSION KERNEL_VERSION(0, 0x1, 0x0)
#define RK628_BT1120_NAME "rk628-bt1120"
#define EDID_NUM_BLOCKS_MAX 2
#define EDID_BLOCK_SIZE 128
#define RK628_CSI_LINK_FREQ_LOW 350000000
#define RK628_CSI_LINK_FREQ_HIGH 400000000
#define RK628_CSI_PIXEL_RATE_LOW 400000000
#define RK628_CSI_PIXEL_RATE_HIGH 600000000
#define MIPI_DATARATE_MBPS_LOW 750
#define MIPI_DATARATE_MBPS_HIGH 1250
#define POLL_INTERVAL_MS 1000
#define MODETCLK_CNT_NUM 1000
#define MODETCLK_HZ 49500000
#define RXPHY_CFG_MAX_TIMES 15
#define CSITX_ERR_RETRY_TIMES 3
#define USE_4_LANES 4
#define YUV422_8BIT 0x1e
/* Test Code: 0x44 (HS RX Control of Lane 0) */
#define HSFREQRANGE(x) UPDATE(x, 6, 1)
@@ -92,6 +74,7 @@ struct rk628_bt1120 {
struct clk *clk_rx_read;
struct delayed_work delayed_work_enable_hotplug;
struct delayed_work delayed_work_res_change;
struct work_struct work_isr;
struct timer_list timer;
struct work_struct work_i2c_poll;
struct mutex confctl_mutex;
@@ -246,14 +229,13 @@ static int rk628_bt1120_s_dv_timings(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
static int rk628_bt1120_s_edid(struct v4l2_subdev *sd,
struct v4l2_subdev_edid *edid);
static int rk628_hdmirx_phy_power_on(struct v4l2_subdev *sd);
static int rk628_hdmirx_phy_power_off(struct v4l2_subdev *sd);
static int rk628_hdmirx_inno_phy_power_on(struct v4l2_subdev *sd);
static int rk628_hdmirx_inno_phy_power_off(struct v4l2_subdev *sd);
static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd);
static void rk628_bt1120_format_change(struct v4l2_subdev *sd);
static void enable_stream(struct v4l2_subdev *sd, bool enable);
static void rk628_hdmirx_vid_enable(struct v4l2_subdev *sd, bool en);
static void rk628_hdmirx_hpd_ctrl(struct v4l2_subdev *sd, bool en);
static void rk628_hdmirx_controller_reset(struct v4l2_subdev *sd);
static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd);
static inline struct rk628_bt1120 *to_bt1120(struct v4l2_subdev *sd)
@@ -333,95 +315,12 @@ static int rk628_bt1120_get_detected_timings(struct v4l2_subdev *sd,
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
struct v4l2_bt_timings *bt = &timings->bt;
u32 hact, vact, htotal, vtotal, fps, status;
u32 val;
u32 modetclk_cnt_hs, modetclk_cnt_vs, hs, vs;
u32 hofs_pix, hbp, hfp, vbp, vfp;
u32 tmds_clk, tmdsclk_cnt;
u64 tmp_data;
int retry = 0;
int ret;
__retry:
memset(timings, 0, sizeof(struct v4l2_dv_timings));
timings->type = V4L2_DV_BT_656_1120;
rk628_i2c_read(bt1120->rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
ret = rk628_hdmirx_get_timings(bt1120->rk628, timings);
if (ret)
return ret;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_STS, &val);
bt->interlaced = val & ILACE_STS ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VTL, &val);
vtotal = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT1, &val);
hofs_pix = val & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VOL, &val);
vbp = (val & 0xffff) + 1;
rk628_i2c_read(bt1120->rk628, HDMI_RX_HDMI_CKM_RESULT, &val);
tmdsclk_cnt = val & 0xffff;
tmp_data = tmdsclk_cnt;
tmp_data = ((tmp_data * MODETCLK_HZ) + MODETCLK_CNT_NUM / 2);
do_div(tmp_data, MODETCLK_CNT_NUM);
tmds_clk = tmp_data;
if (!htotal || !vtotal) {
v4l2_err(&bt1120->sd, "timing err, htotal:%d, vtotal:%d\n",
htotal, vtotal);
if (retry++ < 5)
goto __retry;
goto TIMING_ERR;
}
fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal);
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT0, &val);
modetclk_cnt_hs = val & 0xffff;
hs = (tmdsclk_cnt * modetclk_cnt_hs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VSC, &val);
modetclk_cnt_vs = val & 0xffff;
vs = (tmdsclk_cnt * modetclk_cnt_vs + MODETCLK_CNT_NUM / 2) /
MODETCLK_CNT_NUM;
vs = (vs + htotal / 2) / htotal;
if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) ||
(vtotal < (vact + vs + vbp))) {
v4l2_err(sd, "timing err, total:%dx%d, act:%dx%d, hofs:%d, hs:%d, vs:%d, vbp:%d\n",
htotal, vtotal, hact, vact, hofs_pix, hs, vs, vbp);
goto TIMING_ERR;
}
hbp = hofs_pix - hs;
hfp = htotal - hact - hofs_pix;
vfp = vtotal - vact - vs - vbp;
v4l2_dbg(2, debug, sd, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n",
MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix);
bt->width = hact;
bt->height = vact;
bt->hfrontporch = hfp;
bt->hsync = hs;
bt->hbackporch = hbp;
bt->vfrontporch = vfp;
bt->vsync = vs;
bt->vbackporch = vbp;
bt->pixelclock = htotal * vtotal * fps;
if (bt->interlaced == V4L2_DV_INTERLACED) {
bt->height *= 2;
bt->il_vsync = bt->vsync + 1;
bt->pixelclock /= 2;
}
v4l2_dbg(1, debug, sd, "SCDC_REGS1:%#x, act:%dx%d, total:%dx%d, fps:%d, pixclk:%llu\n",
status, hact, vact, htotal, vtotal, fps, bt->pixelclock);
v4l2_dbg(1, debug, sd, "hfp:%d, hs:%d, hbp:%d, vfp:%d, vs:%d, vbp:%d, interlace:%d\n",
bt->hfrontporch, bt->hsync, bt->hbackporch, bt->vfrontporch,
bt->vsync, bt->vbackporch, bt->interlaced);
@@ -430,10 +329,21 @@ __retry:
if (bt1120->scaler_en)
*timings = bt1120->timings;
return 0;
return ret;
}
TIMING_ERR:
return -ENOLCK;
static void rk628_hdmirx_plugout(struct v4l2_subdev *sd)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
enable_stream(sd, false);
bt1120->nosignal = true;
rk628_bt1120_enable_interrupts(sd, false);
cancel_delayed_work(&bt1120->delayed_work_res_change);
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
rk628_hdmirx_hpd_ctrl(sd, false);
rk628_hdmirx_inno_phy_power_off(sd);
rk628_hdmirx_controller_reset(bt1120->rk628);
}
static void rk628_hdmirx_config_all(struct v4l2_subdev *sd)
@@ -441,12 +351,18 @@ static void rk628_hdmirx_config_all(struct v4l2_subdev *sd)
int ret;
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
rk628_hdmirx_controller_setup(bt1120->rk628);
ret = rk628_hdmirx_phy_setup(sd);
if (ret >= 0) {
if (ret >= 0 && !rk628_hdmirx_scdc_ced_err(bt1120->rk628)) {
rk628_bt1120_format_change(sd);
bt1120->nosignal = false;
return;
}
if (ret < 0 || rk628_hdmirx_scdc_ced_err(bt1120->rk628)) {
rk628_hdmirx_plugout(sd);
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug,
msecs_to_jiffies(800));
}
}
static void rk628_hdmirx_reset_regfile(struct v4l2_subdev *sd)
@@ -489,6 +405,7 @@ static void rk628_bt1120_delayed_work_enable_hotplug(struct work_struct *work)
bool plugin;
mutex_lock(&bt1120->confctl_mutex);
rk628_set_bg_enable(bt1120->rk628, false);
bt1120->avi_rcv_rdy = false;
plugin = tx_5v_power_present(sd);
v4l2_ctrl_s_ctrl(bt1120->detect_tx_5v_ctrl, plugin);
@@ -498,20 +415,15 @@ static void rk628_bt1120_delayed_work_enable_hotplug(struct work_struct *work)
rk628_bt1120_enable_interrupts(sd, false);
rk628_hdmirx_audio_setup(bt1120->audio_info);
rk628_hdmirx_set_hdcp(bt1120->rk628, &bt1120->hdcp, bt1120->enable_hdcp);
rk628_hdmirx_controller_setup(bt1120->rk628);
rk628_hdmirx_hpd_ctrl(sd, true);
rk628_hdmirx_config_all(sd);
rk628_bt1120_enable_interrupts(sd, true);
rk628_i2c_update_bits(bt1120->rk628, GRF_SYSTEM_CON0,
SW_I2S_DATA_OEN_MASK, SW_I2S_DATA_OEN(0));
} else {
rk628_bt1120_enable_interrupts(sd, false);
enable_stream(sd, false);
cancel_delayed_work(&bt1120->delayed_work_res_change);
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
rk628_hdmirx_hpd_ctrl(sd, false);
rk628_hdmirx_phy_power_off(sd);
rk628_hdmirx_controller_reset(sd);
bt1120->nosignal = true;
rk628_hdmirx_plugout(sd);
rk628_set_io_func_to_gpio(bt1120->rk628);
}
mutex_unlock(&bt1120->confctl_mutex);
@@ -525,6 +437,9 @@ static int rk628_check_resulotion_change(struct v4l2_subdev *sd)
u32 old_htotal, old_vtotal;
struct v4l2_bt_timings *bt = &bt1120->src_timings.bt;
if (bt1120->rk628->version >= RK628F_VERSION)
return 1;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VTL, &val);
@@ -551,6 +466,8 @@ static void rk628_delayed_work_res_change(struct work_struct *work)
bool plugin;
mutex_lock(&bt1120->confctl_mutex);
enable_stream(sd, false);
bt1120->nosignal = true;
bt1120->avi_rcv_rdy = false;
plugin = tx_5v_power_present(sd);
v4l2_dbg(1, debug, sd, "%s: 5v_det:%d\n", __func__, plugin);
@@ -558,18 +475,28 @@ static void rk628_delayed_work_res_change(struct work_struct *work)
if (rk628_check_resulotion_change(sd)) {
v4l2_dbg(1, debug, sd, "res change, recfg ctrler and phy!\n");
rk628_bt1120_enable_interrupts(sd, false);
enable_stream(sd, false);
cancel_delayed_work(&bt1120->delayed_work_res_change);
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
rk628_hdmirx_hpd_ctrl(sd, false);
rk628_hdmirx_phy_power_off(sd);
rk628_hdmirx_controller_reset(sd);
bt1120->nosignal = true;
rk628_hdmirx_reset_regfile(sd);
if (bt1120->rk628->version >= RK628F_VERSION) {
rk628_bt1120_enable_interrupts(sd, false);
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
rk628_hdmirx_hpd_ctrl(sd, false);
rk628_hdmirx_inno_phy_power_off(sd);
rk628_hdmirx_controller_reset(bt1120->rk628);
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug,
msecs_to_jiffies(800));
} else {
rk628_bt1120_enable_interrupts(sd, false);
enable_stream(sd, false);
cancel_delayed_work(&bt1120->delayed_work_res_change);
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
rk628_hdmirx_controller_setup(bt1120->rk628);
rk628_hdmirx_hpd_ctrl(sd, false);
rk628_hdmirx_inno_phy_power_off(sd);
rk628_hdmirx_controller_reset(bt1120->rk628);
bt1120->nosignal = true;
rk628_hdmirx_reset_regfile(sd);
}
} else {
rk628_bt1120_format_change(sd);
bt1120->nosignal = false;
rk628_bt1120_enable_interrupts(sd, true);
}
}
@@ -661,7 +588,7 @@ static void enable_bt1120tx(struct v4l2_subdev *sd)
/* rgb data: cfg SW_R2Y_EN */
rk628_i2c_write(bt1120->rk628, GRF_CSC_CTRL_CON,
SW_YUV2VYU_SWP(0) |
SW_R2Y_EN(1));
SW_R2Y_EN(1) | SW_R2Y_CSC_MODE(2));
}
/* if avi packet is not stable, reset ctrl*/
@@ -672,9 +599,19 @@ static void enable_bt1120tx(struct v4l2_subdev *sd)
static void enable_stream(struct v4l2_subdev *sd, bool en)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
u32 val;
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, en ? "en" : "dis");
if (en) {
if (bt1120->rk628->version >= RK628F_VERSION) {
rk628_i2c_read(bt1120->rk628, HDMI_RX_SCDC_REGS2, &val);
if (rk628_hdmirx_scdc_ced_err(bt1120->rk628)) {
rk628_hdmirx_plugout(sd);
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug,
msecs_to_jiffies(800));
return;
}
}
rk628_hdmirx_vid_enable(sd, true);
enable_bt1120tx(sd);
} else {
@@ -724,7 +661,7 @@ static void rk628_post_process_setup(struct v4l2_subdev *sd)
dst_bt->pixelclock = dst_pclk;
}
static int rk628_hdmirx_phy_power_on(struct v4l2_subdev *sd)
static int rk628_hdmirx_inno_phy_power_on(struct v4l2_subdev *sd)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
int ret, f;
@@ -765,10 +702,13 @@ static int rk628_hdmirx_phy_power_on(struct v4l2_subdev *sd)
return ret;
}
static int rk628_hdmirx_phy_power_off(struct v4l2_subdev *sd)
static int rk628_hdmirx_inno_phy_power_off(struct v4l2_subdev *sd)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
if (bt1120->rk628->version >= RK628F_VERSION)
return 0;
if (bt1120->rxphy_pwron) {
v4l2_dbg(1, debug, sd, "rxphy power off!\n");
rk628_rxphy_power_off(bt1120->rk628);
@@ -797,24 +737,14 @@ static void rk628_hdmirx_vid_enable(struct v4l2_subdev *sd, bool en)
}
}
static void rk628_hdmirx_controller_reset(struct v4l2_subdev *sd)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
rk628_control_assert(bt1120->rk628, RGU_HDMIRX_PON);
udelay(10);
rk628_control_deassert(bt1120->rk628, RGU_HDMIRX_PON);
udelay(10);
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_SW_RST, 0x000101ff);
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_DISABLE_IF, 0x00000000);
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_DISABLE_IF, 0x0000017f);
rk628_i2c_write(bt1120->rk628, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
}
static bool rk628_rcv_supported_res(struct v4l2_subdev *sd, u32 width,
u32 height)
{
u32 i;
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
if (bt1120->rk628->version >= RK628F_VERSION)
return true;
for (i = 0; i < ARRAY_SIZE(supported_modes); i++) {
if ((supported_modes[i].width == width) &&
@@ -836,10 +766,13 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd)
u32 i, cnt, val;
u32 width, height, frame_width, frame_height, status;
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
int ret;
int ret = 0;
for (i = 0; i < RXPHY_CFG_MAX_TIMES; i++) {
ret = rk628_hdmirx_phy_power_on(sd);
if (bt1120->rk628->version < RK628F_VERSION)
ret = rk628_hdmirx_inno_phy_power_on(sd);
else
rk628_hdmirx_verisyno_phy_power_on(bt1120->rk628);
if (ret < 0) {
msleep(50);
continue;
@@ -847,6 +780,7 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd)
cnt = 0;
do {
msleep(20);
cnt++;
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &val);
width = val & 0xffff;
@@ -862,7 +796,7 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd)
__func__, width, height, frame_width, frame_height, status, cnt);
rk628_i2c_read(bt1120->rk628, HDMI_RX_PDEC_STS, &val);
if (val & DVI_DET)
if (bt1120->rk628->version < RK628F_VERSION && (val & DVI_DET))
dev_info(bt1120->dev, "DVI mode detected\n");
if (!tx_5v_power_present(sd)) {
@@ -872,15 +806,17 @@ static int rk628_hdmirx_phy_setup(struct v4l2_subdev *sd)
if (cnt >= 15)
break;
} while (((status & 0xfff) != 0xf00) ||
} while (((status & 0xfff) < 0xf00) ||
(!rk628_rcv_supported_res(sd, width, height)));
if (((status & 0xfff) != 0xf00) ||
if (((status & 0xfff) < 0xf00) ||
(!rk628_rcv_supported_res(sd, width, height))) {
v4l2_err(sd, "%s hdmi rxphy lock failed, retry:%d\n",
__func__, i);
continue;
} else {
if (bt1120->rk628->version >= RK628F_VERSION)
rk628_hdmirx_phy_prepclk_cfg(bt1120->rk628);
break;
}
}
@@ -906,7 +842,10 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd)
/* I2SM0D0 */
rk628_i2c_write(bt1120->rk628, GRF_GPIO0AB_SEL_CON, HIWORD_UPDATE(0x1, 5, 4));
/* hdmirx int en */
rk628_i2c_write(bt1120->rk628, GRF_INTR0_EN, 0x01000100);
if (bt1120->rk628->version >= RK628F_VERSION)
rk628_i2c_write(bt1120->rk628, GRF_INTR0_EN, 0x02000200);
else
rk628_i2c_write(bt1120->rk628, GRF_INTR0_EN, 0x01000100);
udelay(10);
rk628_control_assert(bt1120->rk628, RGU_HDMIRX);
@@ -930,7 +869,7 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd)
SW_EFUSE_HDCP_EN(0) |
SW_HSYNC_POL(1) |
SW_VSYNC_POL(1));
rk628_hdmirx_controller_reset(sd);
rk628_hdmirx_controller_reset(bt1120->rk628);
def_edid.pad = 0;
def_edid.start_block = 0;
@@ -940,7 +879,7 @@ static void rk628_bt1120_initial_setup(struct v4l2_subdev *sd)
rk628_hdmirx_set_hdcp(bt1120->rk628, &bt1120->hdcp, false);
if (tx_5v_power_present(sd))
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, 1000);
schedule_delayed_work(&bt1120->delayed_work_enable_hotplug, 4000);
}
static void rk628_bt1120_format_change(struct v4l2_subdev *sd)
@@ -971,7 +910,7 @@ static void rk628_bt1120_enable_interrupts(struct v4l2_subdev *sd, bool en)
u32 pdec_mask = 0, md_mask = 0;
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
pdec_mask |= AVI_RCV_ENSET;
pdec_mask = AVI_RCV_ENSET | AVI_CKS_CHG_ICLR;
md_mask = VACT_LIN_ENSET | HACT_PIX_ENSET | HS_CLK_ENSET |
DE_ACTIVITY_ENSET | VS_ACT_ENSET | HS_ACT_ENSET;
v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, en ? "en" : "dis");
@@ -994,42 +933,56 @@ static void rk628_bt1120_enable_interrupts(struct v4l2_subdev *sd, bool en)
v4l2_dbg(1, debug, sd, "%s MD_IEN:%#x, PDEC_IEN:%#x\n", __func__, md_ien, pdec_ien);
}
static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
static void rk628_work_isr(struct work_struct *work)
{
struct rk628_bt1120 *bt1120 = container_of(work, struct rk628_bt1120, work_isr);
struct v4l2_subdev *sd = &bt1120->sd;
u32 md_ints, pdec_ints, fifo_ints, hact, vact;
bool plugin;
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
void *audio_info = bt1120->audio_info;
bool handled = false;
if (handled == NULL) {
v4l2_err(sd, "handled NULL, err return!\n");
return -EINVAL;
}
mutex_lock(&bt1120->rk628->rst_lock);
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_ISTS, &md_ints);
rk628_i2c_read(bt1120->rk628, HDMI_RX_PDEC_ISTS, &pdec_ints);
if (rk628_audio_ctsnints_enabled(audio_info)) {
if (pdec_ints & (ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR)) {
rk628_csi_isr_ctsn(audio_info, pdec_ints);
pdec_ints &= ~(ACR_CTS_CHG_ICLR | ACR_CTS_CHG_ICLR);
*handled = true;
}
if (bt1120->rk628->version >= RK628F_VERSION &&
(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS |
HS_CLK_ISTS | DE_ACTIVITY_ISTS |
VS_ACT_ISTS | HS_ACT_ISTS) ||
pdec_ints & AVI_CKS_CHG_ISTS))
rk628_set_bg_enable(bt1120->rk628, true);
plugin = tx_5v_power_present(sd);
if (!plugin) {
rk628_bt1120_enable_interrupts(sd, false);
goto __clear_int;
}
if (rk628_audio_fifoints_enabled(audio_info)) {
rk628_i2c_read(bt1120->rk628, HDMI_RX_AUD_FIFO_ISTS, &fifo_ints);
if (fifo_ints & 0x18) {
rk628_csi_isr_fifoints(audio_info, fifo_ints);
*handled = true;
if (bt1120->rk628->version < RK628F_VERSION) {
if (rk628_audio_ctsnints_enabled(audio_info)) {
if (pdec_ints & (ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR)) {
rk628_csi_isr_ctsn(audio_info, pdec_ints);
pdec_ints &= ~(ACR_CTS_CHG_ICLR | ACR_CTS_CHG_ICLR);
handled = true;
}
}
if (rk628_audio_fifoints_enabled(audio_info)) {
rk628_i2c_read(bt1120->rk628, HDMI_RX_AUD_FIFO_ISTS, &fifo_ints);
if (fifo_ints & 0x18) {
rk628_csi_isr_fifoints(audio_info, fifo_ints);
handled = true;
}
}
}
if (bt1120->vid_ints_en) {
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_ISTS, &md_ints);
plugin = tx_5v_power_present(sd);
v4l2_dbg(1, debug, sd, "%s: md_ints: %#x, pdec_ints:%#x, plugin: %d\n",
__func__, md_ints, pdec_ints, plugin);
if ((md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS |
HS_CLK_ISTS | DE_ACTIVITY_ISTS |
VS_ACT_ISTS | HS_ACT_ISTS))
&& plugin) {
VS_ACT_ISTS | HS_ACT_ISTS) ||
pdec_ints & AVI_CKS_CHG_ISTS)) {
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_HACT_PX, &hact);
rk628_i2c_read(bt1120->rk628, HDMI_RX_MD_VAL, &vact);
@@ -1037,13 +990,15 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
__func__, hact, vact);
rk628_bt1120_enable_interrupts(sd, false);
enable_stream(sd, false);
bt1120->nosignal = true;
if (bt1120->rk628->version < RK628F_VERSION) {
enable_stream(sd, false);
bt1120->nosignal = true;
}
schedule_delayed_work(&bt1120->delayed_work_res_change, HZ / 2);
v4l2_dbg(1, debug, sd, "%s: hact/vact change, md_ints: %#x\n",
__func__, (u32)(md_ints & (VACT_LIN_ISTS | HACT_PIX_ISTS)));
*handled = true;
handled = true;
}
if ((pdec_ints & AVI_RCV_ISTS) && plugin && !bt1120->avi_rcv_rdy) {
@@ -1052,16 +1007,34 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
/* After get the AVI_RCV interrupt state, disable interrupt. */
rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_IEN_CLR, AVI_RCV_ISTS);
*handled = true;
handled = true;
}
}
if (*handled != true)
if (!handled)
v4l2_dbg(1, debug, sd, "%s: unhandled interrupt!\n", __func__);
__clear_int:
/* clear interrupts */
rk628_i2c_write(bt1120->rk628, HDMI_RX_MD_ICLR, 0xffffffff);
rk628_i2c_write(bt1120->rk628, HDMI_RX_PDEC_ICLR, 0xffffffff);
rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x01000100);
if (bt1120->rk628->version >= RK628F_VERSION)
rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x02000200);
else
rk628_i2c_write(bt1120->rk628, GRF_INTR0_CLR_EN, 0x01000100);
mutex_unlock(&bt1120->rk628->rst_lock);
}
static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
if (handled == NULL) {
v4l2_err(sd, "handled NULL, err return!\n");
return -EINVAL;
}
schedule_work(&bt1120->work_isr);
return 0;
}
@@ -1069,7 +1042,7 @@ static int rk628_bt1120_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
static irqreturn_t rk628_bt1120_irq_handler(int irq, void *dev_id)
{
struct rk628_bt1120 *bt1120 = dev_id;
bool handled = false;
bool handled = true;
rk628_bt1120_isr(&bt1120->sd, 0, &handled);
@@ -1216,10 +1189,22 @@ static int rk628_bt1120_g_mbus_config(struct v4l2_subdev *sd,
unsigned int pad,
struct v4l2_mbus_config *cfg)
{
struct rk628_bt1120 *bt1120 = to_bt1120(sd);
cfg->type = V4L2_MBUS_BT656;
#if KERNEL_VERSION(5, 18, 0) <= LINUX_VERSION_CODE
cfg->bus.parallel.flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_PCLK_SAMPLE_RISING;
if (bt1120->dual_edge)
cfg->bus.parallel.flags |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
#else
cfg->flags = V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_VSYNC_ACTIVE_HIGH |
V4L2_MBUS_PCLK_SAMPLE_RISING;
if (bt1120->dual_edge)
cfg->flags |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
#endif
return 0;
}
@@ -1483,7 +1468,7 @@ static int rk628_bt1120_s_edid(struct v4l2_subdev *sd,
bt1120->edid_blocks_written = edid->blocks;
udelay(100);
if (tx_5v_power_present(sd))
if (tx_5v_power_present(sd) && bt1120->rk628->version < RK628F_VERSION)
rk628_hdmirx_hpd_ctrl(sd, true);
return 0;
@@ -1857,6 +1842,8 @@ static int rk628_bt1120_probe(struct i2c_client *client,
rk628_cru_initialize(rk628);
rk628_version_parse(rk628);
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
v4l2_i2c_subdev_init(sd, client, &rk628_bt1120_ops);
sd->internal_ops = &bt1120_subdev_internal_ops;
@@ -1931,6 +1918,7 @@ static int rk628_bt1120_probe(struct i2c_client *client,
rk628_bt1120_delayed_work_enable_hotplug);
INIT_DELAYED_WORK(&bt1120->delayed_work_res_change,
rk628_delayed_work_res_change);
INIT_WORK(&bt1120->work_isr, rk628_work_isr);
bt1120->audio_info = rk628_hdmirx_audioinfo_alloc(dev,
&bt1120->confctl_mutex,
rk628,
@@ -1995,6 +1983,7 @@ err_work_queues:
flush_work(&bt1120->work_i2c_poll);
cancel_delayed_work(&bt1120->delayed_work_enable_hotplug);
cancel_delayed_work(&bt1120->delayed_work_res_change);
cancel_work_sync(&bt1120->work_isr);
rk628_hdmirx_audio_destroy(bt1120->audio_info);
err_hdl:
mutex_destroy(&bt1120->confctl_mutex);
@@ -2013,6 +2002,7 @@ static void rk628_bt1120_remove(struct i2c_client *client)
}
cancel_delayed_work_sync(&bt1120->delayed_work_enable_hotplug);
cancel_delayed_work_sync(&bt1120->delayed_work_res_change);
cancel_work_sync(&bt1120->work_isr);
rk628_hdmirx_audio_cancel_work_audio(bt1120->audio_info, true);
rk628_hdmirx_audio_cancel_work_rate_change(bt1120->audio_info, true);

View File

@@ -49,8 +49,11 @@ static void rk628_combtxphy_dsi_power_on(struct rk628 *rk628)
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0, SW_PD_PLL, 0);
usleep_range(100, 200);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON9, SW_DSI_FSET_EN_MASK |
SW_DSI_RCAL_EN_MASK, SW_DSI_FSET_EN |
SW_DSI_RCAL_EN);
SW_DSI_RCAL_EN_MASK | SW_LPTX_SR_TRIM_MASK, SW_DSI_FSET_EN |
SW_DSI_RCAL_EN | SW_LPTX_SR_TRIM(7));
if (rk628->tx_mode && rk628->dual_mipi)
rk628_i2c_update_bits(rk628, COMBTXPHY_CON6, SW_PLL_CTRL0_MASK, SW_PLL_CTRL0(1));
usleep_range(100, 200);
}
@@ -111,7 +114,7 @@ void rk628_txphy_set_mode(struct rk628 *rk628, enum phy_mode mode)
unsigned int flags = bus_width & 0xff;
fhsc = fin * (fhsc / fin);
if (fhsc < 80 || fhsc > 1500)
if (fhsc < 80 || fhsc > 1800)
return;
else if (fhsc < 375)
txphy->rate_div = 4;

View File

@@ -41,6 +41,8 @@
#define SW_PLL_FB_DIV(x) UPDATE(x, 14, 10)
#define SW_PLL_FRAC_DIV(x) UPDATE(x, 9, 0)
#define COMBTXPHY_CON6 COMBTXPHY_REG(0x0018)
#define SW_PLL_CTRL0_MASK GENMASK(2, 0)
#define SW_PLL_CTRL0(x) UPDATE(x, 2, 0)
#define COMBTXPHY_CON7 COMBTXPHY_REG(0x001c)
#define SW_TX_RTERM_MASK GENMASK(22, 20)
#define SW_TX_RTERM(x) UPDATE(x, 22, 20)
@@ -52,6 +54,14 @@
#define SW_TX_CTL_CON4(x) UPDATE(x, 9, 8)
#define COMBTXPHY_CON8 COMBTXPHY_REG(0x0020)
#define COMBTXPHY_CON9 COMBTXPHY_REG(0x0024)
#define SW_HSTX_AMP_TRIM_MASK GENMASK(2, 0)
#define SW_HSTX_AMP_TRIM(x) UPDATE(x, 2, 0)
#define SW_LPTX_SR_TRIM_MASK GENMASK(6, 4)
#define SW_LPTX_SR_TRIM(x) UPDATE(x, 6, 4)
#define SW_DSI_RCAL_CTRL_MASK GENMASK(23, 16)
#define SW_DSI_RCAL_CTRL(x) UPDATE(x, 23, 16)
#define SW_DSI_RCAL_TRIM_MASK GENMASK(27, 24)
#define SW_DSI_RCAL_TRIM(x) UPDATE(x, 27, 24)
#define SW_DSI_FSET_EN_MASK BIT(29)
#define SW_DSI_FSET_EN BIT(29)
#define SW_DSI_RCAL_EN_MASK BIT(28)

View File

@@ -66,6 +66,9 @@ static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
u64 foutvco, foutpostdiv;
u32 offset, val;
if (id == CGU_CLK_APLL && rk628->version == RK628D_VERSION)
return 0;
rk628_i2c_read(rk628, CRU_MODE_CON00, &val);
if (id == CGU_CLK_CPLL) {
val &= CLK_CPLL_MODE_MASK;
@@ -74,15 +77,22 @@ static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
return parent_rate;
offset = 0x00;
} else {
} else if (id == CGU_CLK_GPLL) {
val &= CLK_GPLL_MODE_MASK;
val >>= CLK_GPLL_MODE_SHIFT;
if (val == CLK_GPLL_MODE_OSC)
return parent_rate;
offset = 0x20;
} else {
val &= CLK_APLL_MODE_MASK;
val >>= CLK_APLL_MODE_SHIFT;
if (val == CLK_APLL_MODE_OSC)
return parent_rate;
offset = 0x40;
}
rk628_i2c_read(rk628, offset + CRU_CPLL_CON0, &con0);
rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &con1);
rk628_i2c_read(rk628, offset + CRU_CPLL_CON2, &con2);
@@ -127,6 +137,9 @@ static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
u64 foutvco, foutpostdiv;
u32 offset, val;
if (id == CGU_CLK_APLL && rk628->version == RK628D_VERSION)
return 0;
/*
* FREF : 10MHz ~ 800MHz
* FREFDIV : 1MHz ~ 40MHz
@@ -141,8 +154,10 @@ static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
if (id == CGU_CLK_CPLL)
offset = 0x00;
else
else if (id == CGU_CLK_GPLL)
offset = 0x20;
else
offset = 0x40;
if (fin == fout) {
rk628_i2c_write(rk628, offset + CRU_CPLL_CON0, PLL_BYPASS(1));
@@ -282,17 +297,24 @@ static unsigned long rk628_cru_clk_set_rate_sclk_vop(struct rk628 *rk628,
}
static unsigned long rk628_cru_clk_set_rate_sclk_hdmirx_aud(struct rk628 *rk628,
unsigned long rate)
unsigned long rate)
{
u64 parent_rate;
u8 div;
parent_rate = rk628_cru_clk_set_rate_pll(rk628, CGU_CLK_GPLL, rate*4);
if (rk628->version >= RK628F_VERSION)
parent_rate = rk628_cru_clk_set_rate_pll(rk628, CGU_CLK_APLL, rate*4);
else
parent_rate = rk628_cru_clk_set_rate_pll(rk628, CGU_CLK_GPLL, rate*4);
div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate);
do_div(parent_rate, div);
rate = parent_rate;
rk628_i2c_write(rk628, CRU_CLKSEL_CON05, 0x3fc0 << 16 | ((div - 1) << 6) |
CLK_HDMIRX_AUD_SEL << 16 | CLK_HDMIRX_AUD_SEL);
if (rk628->version >= RK628F_VERSION)
rk628_i2c_write(rk628, CRU_CLKSEL_CON05, CLK_HDMIRX_AUD_DIV(div - 1) |
CLK_HDMIRX_AUD_SEL_V2(2));
else
rk628_i2c_write(rk628, CRU_CLKSEL_CON05, CLK_HDMIRX_AUD_DIV(div - 1) |
CLK_HDMIRX_AUD_SEL_V1(1));
return rate;
}
@@ -304,11 +326,17 @@ static unsigned long rk628_cru_clk_get_rate_sclk_hdmirx_aud(struct rk628 *rk628)
u32 val;
rk628_i2c_read(rk628, CRU_CLKSEL_CON05, &val);
if (val & CLK_HDMIRX_AUD_SEL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
div = ((val & CLK_HDMIRX_AUD_DIV_MASK) >> 6) + 1;
if (rk628->version >= RK628F_VERSION)
val = (val & CLK_HDMIRX_AUD_SEL_MASK_V2) >> 14;
else
val = (val & CLK_HDMIRX_AUD_SEL_MASK_V1) >> 15;
if (!val)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
div = ((val&0x3fc0) >> 6) + 1;
else if (val == 2)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_APLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
do_div(parent_rate, div);
rate = parent_rate;
return rate;
@@ -424,7 +452,11 @@ EXPORT_SYMBOL(rk628_clk_mux_testout);
int rk628_clk_set_rate(struct rk628 *rk628, unsigned int id,
unsigned long rate)
{
if (id == CGU_CLK_APLL && rk628->version == RK628D_VERSION)
return -EINVAL;
switch (id) {
case CGU_CLK_APLL:
case CGU_CLK_CPLL:
case CGU_CLK_GPLL:
rk628_cru_clk_set_rate_pll(rk628, id, rate);
@@ -442,7 +474,7 @@ int rk628_clk_set_rate(struct rk628 *rk628, unsigned int id,
rk628_cru_clk_set_rate_sclk_hdmirx_aud(rk628, rate);
break;
default:
return -1;
return -EINVAL;
}
return 0;
@@ -453,7 +485,11 @@ unsigned long rk628_clk_get_rate(struct rk628 *rk628, unsigned int id)
{
unsigned long rate;
if (id == CGU_CLK_APLL && rk628->version == RK628D_VERSION)
return 0;
switch (id) {
case CGU_CLK_APLL:
case CGU_CLK_CPLL:
case CGU_CLK_GPLL:
rate = rk628_cru_clk_get_rate_pll(rk628, id);
@@ -519,6 +555,7 @@ static const struct rk628_rgu_data rk628_rgu_data[] = {
RSTGEN(RGU_HDMIRX_PON, CRU_SOFTRST_CON02, 12),
RSTGEN(RGU_TXBYTEHS, CRU_SOFTRST_CON02, 13),
RSTGEN(RGU_TXESC, CRU_SOFTRST_CON02, 14),
RSTGEN(RGU_CSI1, CRU_SOFTRST_CON02, 15),
};
static int rk628_rgu_update(struct rk628 *rk628, unsigned long id, int assert)

View File

@@ -46,7 +46,16 @@
#define CRU_GPLL_CON2 CRU_REG(0x0028)
#define CRU_GPLL_CON3 CRU_REG(0x002c)
#define CRU_GPLL_CON4 CRU_REG(0x0030)
#define CRU_APLL_CON0 CRU_REG(0x0040)
#define CRU_APLL_CON1 CRU_REG(0x0044)
#define CRU_APLL_CON2 CRU_REG(0x0048)
#define CRU_APLL_CON3 CRU_REG(0x004c)
#define CRU_APLL_CON4 CRU_REG(0x0050)
#define CRU_MODE_CON00 CRU_REG(0x0060)
#define CLK_APLL_MODE_MASK BIT(4)
#define CLK_APLL_MODE_SHIFT 4
#define CLK_APLL_MODE_APLL 1
#define CLK_APLL_MODE_OSC 0
#define CLK_GPLL_MODE_MASK BIT(2)
#define CLK_GPLL_MODE_SHIFT 2
#define CLK_GPLL_MODE_GPLL 1
@@ -69,7 +78,12 @@
#define CRU_CLKSEL_CON03 CRU_REG(0x008c)
#define CRU_CLKSEL_CON04 CRU_REG(0x0090)
#define CRU_CLKSEL_CON05 CRU_REG(0x0094)
#define CLK_HDMIRX_AUD_SEL BIT(15)
#define CLK_HDMIRX_AUD_DIV_MASK GENMASK(13, 6)
#define CLK_HDMIRX_AUD_DIV(x) HIWORD_UPDATE(x, 13, 6)
#define CLK_HDMIRX_AUD_SEL_V1(x) HIWORD_UPDATE(x, 15, 15)
#define CLK_HDMIRX_AUD_SEL_MASK_V1 GENMASK(15, 15)
#define CLK_HDMIRX_AUD_SEL_V2(x) HIWORD_UPDATE(x, 15, 14)
#define CLK_HDMIRX_AUD_SEL_MASK_V2 GENMASK(15, 14)
#define CRU_CLKSEL_CON06 CRU_REG(0x0098)
#define SCLK_UART_SEL(x) HIWORD_UPDATE(x, 15, 14)
#define SCLK_UART_SEL_MASK GENMASK(15, 14)
@@ -146,6 +160,7 @@
#define CGU_I2S_MCLKOUT 36
#define CGU_BT1120DEC 37
#define CGU_SCLK_UART 38
#define CGU_CLK_APLL 39
#define RGU_LOGIC 0
#define RGU_CRU 1
@@ -178,6 +193,7 @@
#define RGU_HDMIRX_PON 28
#define RGU_TXBYTEHS 29
#define RGU_TXESC 30
#define RGU_CSI1 31
unsigned long rk628_clk_get_rate(struct rk628 *rk628, unsigned int id);
int rk628_clk_set_rate(struct rk628 *rk628, unsigned int id,

View File

@@ -19,6 +19,8 @@
#define VOP_YU_SWAP(x) UPDATE(x, 14, 14)
#define VOP_UV_SWAP_MASK BIT(13)
#define VOP_UV_SWAP(x) UPDATE(x, 13, 13)
#define VOP_YUV422_MODE_MASK GENMASK(11, 10)
#define VOP_YUV422_MODE(x) UPDATE(x, 11, 10)
#define VOP_YUV422_EN_MASK BIT(12)
#define VOP_YUV422_EN(x) UPDATE(x, 12, 12)
#define VOP_P2_EN_MASK BIT(8)
@@ -58,6 +60,11 @@
#define VOP_DT_USERDEFINE_EN(x) UPDATE(x, 1, 1)
#define VOP_PATH_EN_MASK BIT(0)
#define VOP_PATH_EN(x) UPDATE(x, 0, 0)
#define CSITX_VOP_FILTER_CTRL (CSITX_BASE + 0x0044)
#define VOP_FILTER_EN_MASK BIT(0)
#define VOP_FILTER_EN(x) UPDATE(x, 0, 0)
#define VOP_FILTER_MASK GENMASK(15, 8)
#define VOP_FILTER(x) UPDATE(x, 15, 8)
#define CSITX_VOP_PATH_PKT_CTRL (CSITX_BASE + 0x0050)
#define CSITX_CSITX_STATUS0 (CSITX_BASE + 0x0070)
#define CSITX_CSITX_STATUS1 (CSITX_BASE + 0x0074)
@@ -77,5 +84,27 @@
#define CSI_DPHY_EN(x) UPDATE(x, 7, 3)
#define DPHY_ENABLECLK BIT(3)
#define CSI_MAX_REGISTER CSITX_DPHY_CTRL
//for rk628f csi1
#define CSITX1_BASE 0x00140000
#define CSITX1_CONFIG_DONE (CSITX1_BASE + 0x0000)
#define CSITX1_CSITX_EN (CSITX1_BASE + 0x0004)
#define CSITX1_CSITX_VERSION (CSITX1_BASE + 0x0008)
#define CSITX1_SYS_CTRL0_IMD (CSITX1_BASE + 0x0010)
#define CSITX1_SYS_CTRL1 (CSITX1_BASE + 0x0014)
#define CSITX1_SYS_CTRL2 (CSITX1_BASE + 0x0018)
#define CSITX1_SYS_CTRL3_IMD (CSITX1_BASE + 0x001c)
#define CSITX1_TIMING_HPW_PADDING_NUM (CSITX1_BASE + 0x0030)
#define CSITX1_VOP_PATH_CTRL (CSITX1_BASE + 0x0040)
#define CSITX1_VOP_FILTER_CTRL (CSITX1_BASE + 0x0044)
#define CSITX1_VOP_PATH_PKT_CTRL (CSITX1_BASE + 0x0050)
#define CSITX1_CSITX_STATUS0 (CSITX1_BASE + 0x0070)
#define CSITX1_CSITX_STATUS1 (CSITX1_BASE + 0x0074)
#define CSITX1_ERR_INTR_EN_IMD (CSITX1_BASE + 0x0090)
#define CSITX1_ERR_INTR_CLR_IMD (CSITX1_BASE + 0x0094)
#define CSITX1_ERR_INTR_STATUS_IMD (CSITX1_BASE + 0x0098)
#define CSITX1_ERR_INTR_RAW_STATUS_IMD (CSITX1_BASE + 0x009c)
#define CSITX1_LPDT_DATA_IMD (CSITX1_BASE + 0x00a8)
#define CSITX1_DPHY_CTRL (CSITX1_BASE + 0x00b0)
#define CSI1_MAX_REGISTER CSITX1_DPHY_CTRL
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -58,7 +58,7 @@ static inline int dsi_update_bits(struct rk628 *rk628, int id,
return rk628_i2c_update_bits(rk628, dsi_base + reg, mask, val);
}
static void mipi_dphy_power_on_dsi(struct rk628_dsi *dsi)
static void mipi_dphy_power_on_dsi(struct rk628_dsi *dsi, uint8_t mipi_id)
{
int dev_id;
unsigned int dsi_base;
@@ -66,29 +66,38 @@ static void mipi_dphy_power_on_dsi(struct rk628_dsi *dsi)
int ret;
struct rk628 *rk628 = dsi->rk628;
dev_id = RK628_DEV_DSI0;
dsi_base = DSI0_BASE;
dev_id = mipi_id ? RK628_DEV_DSI1 : RK628_DEV_DSI0;
dsi_base = mipi_id ? DSI1_BASE : DSI0_BASE;
dsi_update_bits(rk628, 0, DSI_PHY_RSTZ, PHY_ENABLECLK, 0);
dsi_update_bits(rk628, 0, DSI_PHY_RSTZ, PHY_SHUTDOWNZ, 0);
dsi_update_bits(rk628, 0, DSI_PHY_RSTZ, PHY_RSTZ, 0);
testif_testclr_assert(dsi->rk628);
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ, PHY_ENABLECLK, 0);
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ, PHY_SHUTDOWNZ, 0);
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ, PHY_RSTZ, 0);
rk628_testif_testclr_assert(dsi->rk628, mipi_id);
/* Set all REQUEST inputs to zero */
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
FORCERXMODE_MASK | FORCETXSTOPMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
if (mipi_id)
rk628_i2c_update_bits(rk628, GRF_MIPI_TX1_CON,
FORCERXMODE_MASK | FORCETXSTOPMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
else
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
FORCERXMODE_MASK | FORCETXSTOPMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
udelay(1);
testif_testclr_deassert(dsi->rk628);
rk628_testif_testclr_deassert(dsi->rk628, mipi_id);
rk628_mipi_dphy_init_hsfreqrange(dsi->rk628, dsi->lane_mbps, mipi_id);
mipi_dphy_init_hsfreqrange(dsi->rk628, dsi->lane_mbps);
if (dsi->lane_mbps > 1100)
rk628_mipi_dphy_init_hsmanual(dsi->rk628, true, mipi_id);
else
rk628_mipi_dphy_init_hsmanual(dsi->rk628, false, mipi_id);
dsi_update_bits(rk628, 0, DSI_PHY_RSTZ,
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ,
PHY_ENABLECLK, PHY_ENABLECLK);
dsi_update_bits(rk628, 0, DSI_PHY_RSTZ,
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ,
PHY_SHUTDOWNZ, PHY_SHUTDOWNZ);
dsi_update_bits(rk628, 0, DSI_PHY_RSTZ, PHY_RSTZ, PHY_RSTZ);
dsi_update_bits(rk628, mipi_id, DSI_PHY_RSTZ, PHY_RSTZ, PHY_RSTZ);
usleep_range(1500, 2000);
rk628_txphy_power_on(rk628);
@@ -112,42 +121,42 @@ static void mipi_dphy_power_on_dsi(struct rk628_dsi *dsi)
udelay(10);
}
static void rk628_dsi_pre_enable(struct rk628_dsi *dsi)
static void rk628_dsi_pre_enable(struct rk628_dsi *dsi, uint8_t mipi_id)
{
u32 val;
struct rk628 *rk628 = dsi->rk628;
u32 lane_mbps = dsi->lane_mbps;
dsi_write(rk628, 0, DSI_PWR_UP, RESET);
dsi_write(rk628, 0, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
dsi_write(rk628, mipi_id, DSI_PWR_UP, RESET);
dsi_write(rk628, mipi_id, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
val = DIV_ROUND_UP(lane_mbps >> 3, 20);
dsi_write(rk628, 0, DSI_CLKMGR_CFG,
dsi_write(rk628, mipi_id, DSI_CLKMGR_CFG,
TO_CLK_DIVISION(10) | TX_ESC_CLK_DIVISION(val));
val = CRC_RX_EN | ECC_RX_EN | BTA_EN | EOTP_TX_EN;
if (dsi->mode_flags & MIPI_DSI_MODE_EOT_PACKET)
val &= ~EOTP_TX_EN;
dsi_write(rk628, 0, DSI_PCKHDL_CFG, val);
dsi_write(rk628, mipi_id, DSI_PCKHDL_CFG, val);
dsi_write(rk628, 0, DSI_TO_CNT_CFG,
dsi_write(rk628, mipi_id, DSI_TO_CNT_CFG,
HSTX_TO_CNT(1000) | LPRX_TO_CNT(1000));
dsi_write(rk628, 0, DSI_BTA_TO_CNT, 0xd00);
dsi_write(rk628, 0, DSI_PHY_TMR_CFG,
dsi_write(rk628, mipi_id, DSI_BTA_TO_CNT, 0xd00);
dsi_write(rk628, mipi_id, DSI_PHY_TMR_CFG,
PHY_HS2LP_TIME(0x14) | PHY_LP2HS_TIME(0x10) |
MAX_RD_TIME(10000));
dsi_write(rk628, 0, DSI_PHY_TMR_LPCLK_CFG,
dsi_write(rk628, mipi_id, DSI_PHY_TMR_LPCLK_CFG,
PHY_CLKHS2LP_TIME(0x40) | PHY_CLKLP2HS_TIME(0x40));
dsi_write(rk628, 0, DSI_PHY_IF_CFG,
dsi_write(rk628, mipi_id, DSI_PHY_IF_CFG,
PHY_STOP_WAIT_TIME(0x20) | N_LANES(4 - 1));
mipi_dphy_power_on_dsi(dsi);
mipi_dphy_power_on_dsi(dsi, mipi_id);
dsi_write(rk628, 0, DSI_PWR_UP, POWER_UP);
dsi_write(rk628, mipi_id, DSI_PWR_UP, POWER_UP);
}
static void rk628_dsi_set_vid_mode(struct rk628_dsi *dsi)
static void rk628_dsi_set_vid_mode(struct rk628_dsi *dsi, uint8_t mipi_id)
{
unsigned int lanebyteclk = (dsi->lane_mbps * 1000L) >> 3;
u64 dpipclk;
@@ -176,16 +185,16 @@ static void rk628_dsi_set_vid_mode(struct rk628_dsi *dsi)
else
val |= VID_MODE_TYPE_NON_BURST_SYNC_EVENTS;
dsi_write(rk628, 0, DSI_VID_MODE_CFG, val);
dsi_write(rk628, mipi_id, DSI_VID_MODE_CFG, val);
if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
dsi_update_bits(rk628, 0, DSI_LPCLK_CTRL,
dsi_update_bits(rk628, mipi_id, DSI_LPCLK_CTRL,
AUTO_CLKLANE_CTRL, AUTO_CLKLANE_CTRL);
pkt_size = VID_PKT_SIZE(bt->width);
pkt_size = rk628->dual_mipi ? VID_PKT_SIZE(bt->width) / 2 : VID_PKT_SIZE(bt->width);
dsi_write(rk628, 0, DSI_VID_PKT_SIZE, pkt_size);
dsi_write(rk628, mipi_id, DSI_VID_PKT_SIZE, pkt_size);
vactive = bt->height;
vs = bt->vsync;
@@ -202,43 +211,47 @@ static void rk628_dsi_set_vid_mode(struct rk628_dsi *dsi)
//hline_time = hline * lanebyteclk / dpipclk;
hline_time = DIV_ROUND_CLOSEST_ULL(hline * lanebyteclk, dpipclk);
dsi_write(rk628, 0, DSI_VID_HLINE_TIME,
dsi_write(rk628, mipi_id, DSI_VID_HLINE_TIME,
VID_HLINE_TIME(hline_time));
//hs_time = hs * lanebyteclk / dpipclk;
hs_time = DIV_ROUND_CLOSEST_ULL(hs * lanebyteclk, dpipclk);
dsi_write(rk628, 0, DSI_VID_HSA_TIME, VID_HSA_TIME(hs_time));
dsi_write(rk628, mipi_id, DSI_VID_HSA_TIME, VID_HSA_TIME(hs_time));
//hbp_time = hbp * lanebyteclk / dpipclk;
hbp_time = DIV_ROUND_CLOSEST_ULL(hbp * lanebyteclk, dpipclk);
dsi_write(rk628, 0, DSI_VID_HBP_TIME, VID_HBP_TIME(hbp_time));
dsi_write(rk628, mipi_id, DSI_VID_HBP_TIME, VID_HBP_TIME(hbp_time));
dsi_write(rk628, 0, DSI_VID_VACTIVE_LINES, vactive);
dsi_write(rk628, 0, DSI_VID_VSA_LINES, vs);
dsi_write(rk628, 0, DSI_VID_VFP_LINES, vfp);
dsi_write(rk628, 0, DSI_VID_VBP_LINES, vbp);
dsi_write(rk628, mipi_id, DSI_VID_VACTIVE_LINES, vactive);
dsi_write(rk628, mipi_id, DSI_VID_VSA_LINES, vs);
dsi_write(rk628, mipi_id, DSI_VID_VFP_LINES, vfp);
dsi_write(rk628, mipi_id, DSI_VID_VBP_LINES, vbp);
dsi_write(rk628, 0, DSI_MODE_CFG, CMD_VIDEO_MODE(VIDEO_MODE));
dsi_write(rk628, mipi_id, DSI_MODE_CFG, CMD_VIDEO_MODE(VIDEO_MODE));
}
static void rk628_dsi_set_cmd_mode(struct rk628_dsi *dsi)
static void rk628_dsi_set_cmd_mode(struct rk628_dsi *dsi, uint8_t mipi_id)
{
struct rk628 *rk628 = dsi->rk628;
dsi_update_bits(rk628, 0, DSI_CMD_MODE_CFG, DCS_LW_TX, 0);
dsi_write(rk628, 0, DSI_EDPI_CMD_SIZE,
EDPI_ALLOWED_CMD_SIZE(dsi->timings.bt.width));
dsi_write(rk628, 0, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
dsi_update_bits(rk628, mipi_id, DSI_CMD_MODE_CFG, DCS_LW_TX, 0);
if (rk628->dual_mipi)
dsi_write(rk628, mipi_id, DSI_EDPI_CMD_SIZE,
EDPI_ALLOWED_CMD_SIZE(dsi->timings.bt.width / 2));
else
dsi_write(rk628, mipi_id, DSI_EDPI_CMD_SIZE,
EDPI_ALLOWED_CMD_SIZE(dsi->timings.bt.width));
dsi_write(rk628, mipi_id, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
}
static void rk628_dsi_enable(struct rk628_dsi *dsi)
static void rk628_dsi_enable(struct rk628_dsi *dsi, uint8_t mipi_id)
{
u32 val;
struct rk628 *rk628 = dsi->rk628;
dsi_write(rk628, 0, DSI_PWR_UP, RESET);
dsi_write(rk628, mipi_id, DSI_PWR_UP, RESET);
val = DPI_COLOR_CODING(5);
dsi_write(rk628, 0, DSI_DPI_COLOR_CODING, val);
dsi_write(rk628, mipi_id, DSI_DPI_COLOR_CODING, val);
val = 0;
@@ -249,26 +262,27 @@ static void rk628_dsi_enable(struct rk628_dsi *dsi)
* val |= HSYNC_ACTIVE_LOW;
*/
dsi_write(rk628, 0, DSI_DPI_CFG_POL, val);
dsi_write(rk628, mipi_id, DSI_DPI_CFG_POL, val);
dsi_write(rk628, 0, DSI_DPI_VCID, DPI_VID(0));
dsi_write(rk628, 0, DSI_DPI_LP_CMD_TIM,
dsi_write(rk628, mipi_id, DSI_DPI_VCID, DPI_VID(0));
dsi_write(rk628, mipi_id, DSI_DPI_LP_CMD_TIM,
OUTVACT_LPCMD_TIME(4) | INVACT_LPCMD_TIME(4));
dsi_update_bits(rk628, 0, DSI_LPCLK_CTRL,
PHY_TXREQUESTCLKHS | AUTO_CLKLANE_CTRL,
PHY_TXREQUESTCLKHS | AUTO_CLKLANE_CTRL);
dsi_update_bits(rk628, mipi_id, DSI_LPCLK_CTRL,
PHY_TXREQUESTCLKHS,
PHY_TXREQUESTCLKHS);
if (dsi->vid_mode == VIDEO_MODE)
rk628_dsi_set_vid_mode(dsi);
rk628_dsi_set_vid_mode(dsi, mipi_id);
else
rk628_dsi_set_cmd_mode(dsi);
rk628_dsi_set_cmd_mode(dsi, mipi_id);
dsi_write(rk628, 0, DSI_PWR_UP, POWER_UP);
dsi_write(rk628, mipi_id, DSI_PWR_UP, POWER_UP);
}
static u32 rk628_dsi_get_lane_rate(struct rk628_dsi *dsi)
u32 rk628_dsi_get_lane_rate_mbps(struct rk628_dsi *dsi)
{
struct rk628 *rk628 = dsi->rk628;
u32 lane_rate;
u32 max_lane_rate = 1500;
u32 max_lane_rate = 1800;
u8 bpp, lanes;
u64 pixelclock = dsi->timings.bt.pixelclock;
@@ -278,33 +292,81 @@ static u32 rk628_dsi_get_lane_rate(struct rk628_dsi *dsi)
lane_rate = pixelclock * bpp;
lane_rate = div_u64(lane_rate, lanes);
lane_rate = DIV_ROUND_UP(lane_rate * 5, 4);
if (rk628->dual_mipi)
lane_rate /= 2;
if (lane_rate > max_lane_rate)
if (lane_rate > 1300)
lane_rate = max_lane_rate;
else if (lane_rate > 700 && lane_rate <= 1300)
lane_rate = 1300;
else
lane_rate = 700;
return lane_rate;
}
EXPORT_SYMBOL(rk628_dsi_get_lane_rate_mbps);
void rk628_mipi_dsi_power_on(struct rk628_dsi *dsi)
{
struct rk628 *rk628 = dsi->rk628;
u32 rate = rk628_dsi_get_lane_rate(dsi);
u32 rate = rk628_dsi_get_lane_rate_mbps(dsi);
int bus_width;
u32 mask = SW_OUTPUT_MODE_MASK;
u32 val = SW_OUTPUT_MODE(OUTPUT_MODE_DSI);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_DSI));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_SPLIT_EN, 0);
if (rk628->version == RK628F_VERSION) {
mask = SW_OUTPUT_COMBTX_MODE_MASK;
val = SW_OUTPUT_COMBTX_MODE(OUTPUT_MODE_DSI - 2);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON3,
GRF_AS_DSIPHY_MASK,
GRF_AS_DSIPHY(1));
}
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
dev_info(dsi->rk628->dev, "%s mipi mode, %sable dphy1 and split en\n",
rk628->dual_mipi ? "dual" : "single", rk628->dual_mipi ? "en" : "dis");
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON3, GRF_DPHY_CH1_EN_MASK,
rk628->dual_mipi ? GRF_DPHY_CH1_EN(1) : GRF_DPHY_CH1_EN(0));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_SPLIT_EN,
rk628->dual_mipi ? 1 : 0);
bus_width = rate << 8;
bus_width |= COMBTXPHY_MODULEA_EN;
if (rk628->dual_mipi)
bus_width |= COMBTXPHY_MODULEB_EN;
rk628_txphy_set_bus_width(dsi->rk628, bus_width);
rk628_txphy_set_mode(dsi->rk628, PHY_MODE_VIDEO_MIPI);
dsi->lane_mbps = rk628_txphy_get_bus_width(dsi->rk628);
dev_dbg(dsi->rk628->dev, "%s mipi bitrate:%llu mbps\n", __func__,
dev_info(dsi->rk628->dev, "%s mipi bitrate:%llu mbps\n", __func__,
dsi->lane_mbps);
rk628_dsi_pre_enable(dsi);
rk628_dsi_pre_enable(dsi, 0);
if (rk628->dual_mipi)
rk628_dsi_pre_enable(dsi, 1);
rk628_dsi_enable(dsi);
rk628_dsi_enable(dsi, 0);
if (rk628->dual_mipi)
rk628_dsi_enable(dsi, 1);
}
EXPORT_SYMBOL(rk628_mipi_dsi_power_on);
void rk628_dsi_disable_stream(struct rk628_dsi *dsi)
{
struct rk628 *rk628 = dsi->rk628;
dsi_write(rk628, 0, DSI_PWR_UP, RESET);
dsi_write(rk628, 0, DSI_LPCLK_CTRL, 0);
dsi_write(rk628, 0, DSI_EDPI_CMD_SIZE, 0);
dsi_write(rk628, 0, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
dsi_write(rk628, 0, DSI_PWR_UP, POWER_UP);
dsi_write(rk628, 1, DSI_PWR_UP, RESET);
dsi_write(rk628, 1, DSI_LPCLK_CTRL, 0);
dsi_write(rk628, 1, DSI_EDPI_CMD_SIZE, 0);
dsi_write(rk628, 1, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
dsi_write(rk628, 1, DSI_PWR_UP, POWER_UP);
rk628_txphy_power_off(rk628);
}
EXPORT_SYMBOL(rk628_dsi_disable_stream);

View File

@@ -166,8 +166,11 @@ struct rk628_dsi {
u64 lane_mbps;
int vid_mode;
int mode_flags;
uint8_t id;
};
void rk628_mipi_dsi_power_on(struct rk628_dsi *dsi);
void rk628_dsi_disable_stream(struct rk628_dsi *dsi);
u32 rk628_dsi_get_lane_rate_mbps(struct rk628_dsi *dsi);
#endif

View File

@@ -18,15 +18,6 @@
#define INIT_FIFO_STATE 64
#define is_validfs(x) (x == 32000 || \
x == 44100 || \
x == 48000 || \
x == 88200 || \
x == 96000 || \
x == 176400 || \
x == 192000 || \
x == 768000)
struct rk628_audiostate {
u32 hdmirx_aud_clkrate;
u32 fs_audio;
@@ -53,6 +44,25 @@ struct rk628_audioinfo {
struct device *dev;
};
struct hdmirx_tmdsclk_cnt {
u32 tmds_cnt;
u8 cnt;
};
#define HDMIRX_GET_TMDSCLK_TIME 21
static int supported_fs[] = {
32000,
44100,
48000,
88200,
96000,
176400,
192000,
768000,
-1
};
static int hdcp_load_keys_cb(struct rk628 *rk628, struct rk628_hdcp *hdcp)
{
int size;
@@ -168,11 +178,11 @@ EXPORT_SYMBOL(rk628_hdmirx_set_hdcp);
void rk628_hdmirx_controller_setup(struct rk628 *rk628)
{
rk628_i2c_write(rk628, HDMI_RX_HDMI20_CONTROL, 0x10000f10);
rk628_i2c_write(rk628, HDMI_RX_HDMI20_CONTROL, 0x10000f11);
rk628_i2c_write(rk628, HDMI_RX_HDMI_MODE_RECOVER, 0x00000021);
rk628_i2c_write(rk628, HDMI_RX_PDEC_CTRL, 0xbfff8011);
rk628_i2c_write(rk628, HDMI_RX_PDEC_ASP_CTRL, 0x00000040);
rk628_i2c_write(rk628, HDMI_RX_HDMI_RESMPL_CTRL, 0x00000001);
rk628_i2c_write(rk628, HDMI_RX_HDMI_RESMPL_CTRL, 0x00000000);
rk628_i2c_write(rk628, HDMI_RX_HDMI_SYNC_CTRL, 0x00000014);
rk628_i2c_write(rk628, HDMI_RX_PDEC_ERR_FILTER, 0x00000008);
rk628_i2c_write(rk628, HDMI_RX_SCDC_I2CCONFIG, 0x01000000);
@@ -181,7 +191,7 @@ void rk628_hdmirx_controller_setup(struct rk628 *rk628)
rk628_i2c_write(rk628, HDMI_RX_CHLOCK_CONFIG, 0x0030c15c);
rk628_i2c_write(rk628, HDMI_RX_HDMI_ERROR_PROTECT, 0x000d0c98);
rk628_i2c_write(rk628, HDMI_RX_MD_HCTRL1, 0x00000010);
rk628_i2c_write(rk628, HDMI_RX_MD_HCTRL2, 0x00001738);
rk628_i2c_write(rk628, HDMI_RX_MD_HCTRL2, 0x0000173a);
rk628_i2c_write(rk628, HDMI_RX_MD_VCTRL, 0x00000002);
rk628_i2c_write(rk628, HDMI_RX_MD_VTH, 0x0000073a);
rk628_i2c_write(rk628, HDMI_RX_MD_IL_POL, 0x00000004);
@@ -189,7 +199,7 @@ void rk628_hdmirx_controller_setup(struct rk628 *rk628)
rk628_i2c_write(rk628, HDMI_RX_HDMI_DCM_CTRL, 0x00040414);
rk628_i2c_write(rk628, HDMI_RX_HDMI_CKM_EVLTM, 0x00103e70);
rk628_i2c_write(rk628, HDMI_RX_HDMI_CKM_F, 0x0c1c0b54);
rk628_i2c_write(rk628, HDMI_RX_HDMI_RESMPL_CTRL, 0x00000001);
rk628_i2c_update_bits(rk628, HDMI_RX_HDMI_TIMER_CTRL, VIDEO_PERIOD_MASK, VIDEO_PERIOD(1));
rk628_i2c_update_bits(rk628, HDMI_RX_HDCP_SETTINGS,
HDMI_RESERVED_MASK |
@@ -203,6 +213,39 @@ void rk628_hdmirx_controller_setup(struct rk628 *rk628)
}
EXPORT_SYMBOL(rk628_hdmirx_controller_setup);
static bool is_validfs(int fs)
{
int i = 0;
int fs_t;
fs_t = supported_fs[i++];
while (fs_t > 0) {
if (fs == fs_t)
return true;
fs_t = supported_fs[i++];
};
return false;
}
static int rk628_hdmirx_audio_find_closest_fs(struct rk628_audioinfo *aif, int fs)
{
int i = 0;
int fs_t;
int difference;
fs_t = supported_fs[i++];
while (fs_t > 0) {
difference = abs(fs - fs_t);
if (difference <= 2000) {
if (fs != fs_t)
dev_dbg(aif->dev, "%s fix fs from %u to %u", __func__, fs, fs_t);
return fs_t;
}
fs_t = supported_fs[i++];
};
return fs_t;
}
static void rk628_hdmirx_audio_fifo_init(struct rk628_audioinfo *aif)
{
@@ -246,8 +289,7 @@ static u32 _rk628_hdmirx_audio_fs(struct rk628_audioinfo *aif)
if (cts_decoded != 0) {
fs_audio = div_u64((tmdsclk * n_decoded), cts_decoded);
fs_audio /= 128;
fs_audio = div_u64(fs_audio + 50, 100);
fs_audio *= 100;
fs_audio = rk628_hdmirx_audio_find_closest_fs(aif, fs_audio);
}
dev_dbg(aif->dev,
"%s: clkrate:%u tmdsclk:%llu, n_decoded:%u, cts_decoded:%u, fs_audio:%u\n",
@@ -306,6 +348,85 @@ static void rk628_hdmirx_audio_enable(struct rk628_audioinfo *aif)
AFIF_OVERFL_ISTS | AFIF_UNDERFL_ISTS);
}
static const char *audio_fifo_err(u32 fifo_status)
{
switch (fifo_status & (AFIF_UNDERFL_ISTS | AFIF_OVERFL_ISTS)) {
case AFIF_UNDERFL_ISTS:
return "underflow";
case AFIF_OVERFL_ISTS:
return "overflow";
case AFIF_UNDERFL_ISTS | AFIF_OVERFL_ISTS:
return "underflow and overflow";
}
return "underflow or overflow";
}
static void rk628_csi_delayed_work_audio_v2(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
struct rk628_audioinfo *aif = container_of(dwork, struct rk628_audioinfo,
delayed_work_audio);
struct rk628_audiostate *audio_state = &aif->audio_state;
struct rk628 *rk628 = aif->rk628;
u32 fs_audio;
int init_state, pre_state, fifo_status, fifo_ints;
unsigned long delay = 500;
fs_audio = _rk628_hdmirx_audio_fs(aif);
/* read fifo init status */
rk628_i2c_read(rk628, HDMI_RX_AUD_FIFO_ISTS, &fifo_ints);
dev_dbg(rk628->dev, "%s: HDMI_RX_AUD_FIFO_ISTS:%#x\r\n", __func__, fifo_ints);
if (fifo_ints & (AFIF_UNDERFL_ISTS | AFIF_OVERFL_ISTS)) {
dev_warn(rk628->dev, "%s: audio %s %#x, with fs %svalid %d\n",
__func__, audio_fifo_err(fifo_ints), fifo_ints,
is_validfs(fs_audio) ? "" : "in", fs_audio);
if (is_validfs(fs_audio))
rk628_hdmirx_audio_set_fs(aif, fs_audio);
rk628_hdmirx_audio_fifo_init(aif);
audio_state->pre_state = 0;
goto exit;
}
/* read fifo fill status */
init_state = audio_state->init_state;
pre_state = audio_state->pre_state;
rk628_i2c_read(rk628, HDMI_RX_AUD_FIFO_FILLSTS1, &fifo_status);
dev_dbg(rk628->dev,
"%s: HDMI_RX_AUD_FIFO_FILLSTS1:%#x, single offset:%d, total offset:%d\n",
__func__, fifo_status, fifo_status - pre_state, fifo_status - init_state);
if (!is_validfs(fs_audio)) {
dev_dbg(rk628->dev, "%s: no supported fs(%u), fifo_status %d\n",
__func__, fs_audio, fifo_status);
delay = 1000;
} else if (abs(fs_audio - audio_state->fs_audio) > 1000) {
dev_info(rk628->dev, "%s: restart audio fs(%d -> %d)\n",
__func__, audio_state->fs_audio, fs_audio);
rk628_hdmirx_audio_set_fs(aif, fs_audio);
rk628_hdmirx_audio_fifo_init(aif);
audio_state->pre_state = 0;
goto exit;
}
if (fifo_status != 0) {
if (!aif->audio_present) {
dev_info(rk628->dev, "audio on");
aif->audio_present = true;
}
if (fifo_status - init_state > 16 && fifo_status - pre_state > 0)
rk628_hdmirx_audio_clk_inc_rate(aif, 10);
else if (fifo_status - init_state < -16 && fifo_status - pre_state < 0)
rk628_hdmirx_audio_clk_inc_rate(aif, -10);
} else {
if (aif->audio_present) {
dev_info(rk628->dev, "audio off");
aif->audio_present = false;
}
}
audio_state->pre_state = fifo_status;
exit:
schedule_delayed_work(&aif->delayed_work_audio, msecs_to_jiffies(delay));
}
static void rk628_csi_delayed_work_audio(struct work_struct *work)
{
struct delayed_work *dwork = to_delayed_work(work);
@@ -395,10 +516,13 @@ HAUDINFO rk628_hdmirx_audioinfo_alloc(struct device *dev,
aif = devm_kzalloc(dev, sizeof(*aif), GFP_KERNEL);
if (!aif)
return NULL;
INIT_DELAYED_WORK(&aif->delayed_work_audio_rate_change,
rk628_csi_delayed_work_audio_rate_change);
INIT_DELAYED_WORK(&aif->delayed_work_audio,
rk628_csi_delayed_work_audio);
if (rk628->version >= RK628F_VERSION) {
INIT_DELAYED_WORK(&aif->delayed_work_audio, rk628_csi_delayed_work_audio_v2);
} else {
INIT_DELAYED_WORK(&aif->delayed_work_audio, rk628_csi_delayed_work_audio);
INIT_DELAYED_WORK(&aif->delayed_work_audio_rate_change,
rk628_csi_delayed_work_audio_rate_change);
}
aif->confctl_mutex = confctl_mutex;
aif->rk628 = rk628;
aif->i2s_enabled_default = en;
@@ -432,11 +556,14 @@ EXPORT_SYMBOL(rk628_hdmirx_audio_cancel_work_rate_change);
void rk628_hdmirx_audio_destroy(HAUDINFO info)
{
struct rk628_audioinfo *aif = (struct rk628_audioinfo *)info;
struct rk628 *rk628;
if (!aif)
return;
rk628 = aif->rk628;
rk628_hdmirx_audio_cancel_work_audio(aif, true);
rk628_hdmirx_audio_cancel_work_rate_change(aif, true);
if (rk628->version < RK628F_VERSION)
rk628_hdmirx_audio_cancel_work_rate_change(aif, true);
aif->confctl_mutex = NULL;
aif->rk628 = NULL;
}
@@ -485,6 +612,7 @@ EXPORT_SYMBOL(rk628_hdmirx_audio_i2s_ctrl);
void rk628_hdmirx_audio_setup(HAUDINFO info)
{
struct rk628_audioinfo *aif = (struct rk628_audioinfo *)info;
struct rk628 *rk628 = aif->rk628;
u32 audio_pll_n, audio_pll_cts;
dev_dbg(aif->dev, "%s: setup audio\n", __func__);
@@ -500,6 +628,9 @@ void rk628_hdmirx_audio_setup(HAUDINFO info)
aif->ctsn_ints_en = false;
aif->i2s_enabled = false;
if (rk628->version >= RK628F_VERSION)
rk628_i2c_write(rk628, CRU_MODE_CON00, HIWORD_UPDATE(1, 4, 4));
rk628_hdmirx_audio_clk_set_rate(aif, 5644800);
/* manual aud CTS */
rk628_i2c_write(aif->rk628, HDMI_RX_AUDPLL_GEN_CTS, audio_pll_cts);
@@ -544,11 +675,17 @@ void rk628_hdmirx_audio_setup(HAUDINFO info)
PAO_RATE(0));
rk628_i2c_write(aif->rk628, HDMI_RX_AUD_CHEXTR_CTRL,
AUD_LAYOUT_CTRL(1));
aif->ctsn_ints_en = true;
rk628_i2c_write(aif->rk628, HDMI_RX_PDEC_IEN_SET, ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR);
/* audio detect */
rk628_i2c_write(aif->rk628, HDMI_RX_PDEC_AUDIODET_CTRL,
AUDIODET_THRESHOLD(0));
if (rk628->version >= RK628F_VERSION) {
rk628_i2c_update_bits(aif->rk628, HDMI_RX_DMI_DISABLE_IF,
AUD_ENABLE_MASK, AUD_ENABLE(1));
schedule_delayed_work(&aif->delayed_work_audio, msecs_to_jiffies(1000));
} else {
aif->ctsn_ints_en = true;
rk628_i2c_write(aif->rk628, HDMI_RX_PDEC_IEN_SET,
ACR_N_CHG_ICLR | ACR_CTS_CHG_ICLR);
/* audio detect */
rk628_i2c_write(aif->rk628, HDMI_RX_PDEC_AUDIODET_CTRL, AUDIODET_THRESHOLD(0));
}
}
EXPORT_SYMBOL(rk628_hdmirx_audio_setup);
@@ -616,6 +753,9 @@ int rk628_is_avi_ready(struct rk628 *rk628, bool avi_rcv_rdy)
u8 cnt = 0, max_cnt = 2;
u32 hdcp_ctrl_val = 0;
if (rk628->version >= RK628F_VERSION)
return 1;
rk628_i2c_read(rk628, HDMI_RX_HDCP_CTRL, &val);
if ((val & HDCP_ENABLE_MASK))
max_cnt = 5;
@@ -646,3 +786,430 @@ int rk628_is_avi_ready(struct rk628 *rk628, bool avi_rcv_rdy)
return 1;
}
EXPORT_SYMBOL(rk628_is_avi_ready);
static void hdmirxphy_write(struct rk628 *rk628, u32 offset, u32 val)
{
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_ADDRESS, offset);
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_DATAO, val);
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_OPERATION, 1);
}
static __maybe_unused u32 hdmirxphy_read(struct rk628 *rk628, u32 offset)
{
u32 val;
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_ADDRESS, offset);
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_OPERATION, 2);
rk628_i2c_read(rk628, HDMI_RX_I2CM_PHYG3_DATAI, &val);
return val;
}
static void rk628_hdmirxphy_enable(struct rk628 *rk628, bool is_hdmi2, bool scramble_en)
{
hdmirxphy_write(rk628, 0x02, 0x1860);
hdmirxphy_write(rk628, 0x03, 0x0060);
if (!is_hdmi2 && scramble_en)
hdmirxphy_write(rk628, 0x0d, 0x00c0);
else
hdmirxphy_write(rk628, 0x0d, 0x0);
hdmirxphy_write(rk628, 0x27, 0x1c94);
hdmirxphy_write(rk628, 0x28, 0x3713);
hdmirxphy_write(rk628, 0x29, 0x24da);
hdmirxphy_write(rk628, 0x2a, 0x5492);
hdmirxphy_write(rk628, 0x2b, 0x4b0d);
hdmirxphy_write(rk628, 0x2d, 0x008c);
hdmirxphy_write(rk628, 0x2e, 0x0001);
if (is_hdmi2)
hdmirxphy_write(rk628, 0x0e, 0x0108);
else
hdmirxphy_write(rk628, 0x0e, 0x0008);
}
static void rk628_hdmirxphy_set_clrdpt(struct rk628 *rk628, bool is_8bit)
{
if (is_8bit)
hdmirxphy_write(rk628, 0x03, 0x0000);
else
hdmirxphy_write(rk628, 0x03, 0x0060);
}
void rk628_hdmirx_verisyno_phy_power_on(struct rk628 *rk628)
{
bool is_hdmi2 = false;
u32 val;
int i;
bool scramble = false;
/* wait tx to write scdc tmds ratio */
for (i = 0; i < 50; i++) {
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS0, &val);
if (val & SCDC_TMDSBITCLKRATIO)
break;
msleep(20);
}
if (val & SCDC_TMDSBITCLKRATIO)
is_hdmi2 = true;
rk628_i2c_read(rk628, HDMI_RX_HDMI20_STATUS, &val);
scramble = (val & SCRAMBDET_MASK) ? true : false;
dev_info(rk628->dev, "%s: %s, %s\n", __func__, is_hdmi2 ? "hdmi2.0" : "hdmi1.4",
scramble ? "Scramble" : "Descramble");
/* power down phy */
rk628_i2c_write(rk628, GRF_SW_HDMIRXPHY_CRTL, 0x17);
usleep_range(20, 30);
rk628_i2c_write(rk628, GRF_SW_HDMIRXPHY_CRTL, 0x15);
/* init phy i2c */
rk628_i2c_write(rk628, HDMI_RX_SNPS_PHYG3_CTRL, 0);
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_SS_CNTS, 0x018c01d2);
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_FS_HCNT, 0x003c0081);
rk628_i2c_write(rk628, HDMI_RX_I2CM_PHYG3_MODE, 1);
rk628_i2c_write(rk628, GRF_SW_HDMIRXPHY_CRTL, 0x11);
/* enable rx phy */
rk628_hdmirxphy_enable(rk628, is_hdmi2, scramble);
rk628_i2c_write(rk628, GRF_SW_HDMIRXPHY_CRTL, 0x14);
msleep(20);
}
EXPORT_SYMBOL(rk628_hdmirx_verisyno_phy_power_on);
void rk628_hdmirx_phy_prepclk_cfg(struct rk628 *rk628)
{
u32 format;
bool is_clrdpt_8bit = false;
usleep_range(20 * 1000, 30 * 1000);
rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &format);
format = (format & VIDEO_FORMAT_MASK) >> 5;
dev_info(rk628->dev, "%s: format = %d from AVI\n", __func__, format);
/* yuv420 should set phy color depth 8bit */
if (format == 3)
is_clrdpt_8bit = true;
rk628_i2c_read(rk628, HDMI_RX_PDEC_GCP_AVMUTE, &format);
format = (format & PKTDEC_GCP_CD_MASK) >> 4;
dev_info(rk628->dev, "%s: format = %d from GCP\n", __func__, format);
/* 10bit color depth should set phy color depth 8bit */
if (format == 5)
is_clrdpt_8bit = true;
rk628_hdmirxphy_set_clrdpt(rk628, is_clrdpt_8bit);
}
EXPORT_SYMBOL(rk628_hdmirx_phy_prepclk_cfg);
static const char * const bus_format_str[] = {
"RGB",
"YUV422",
"YUV444",
"YUV420",
"UNKNOWN",
};
u8 rk628_hdmirx_get_format(struct rk628 *rk628)
{
u32 val;
u8 video_fmt;
rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val);
video_fmt = (val & VIDEO_FORMAT_MASK) >> 5;
if (video_fmt > BUS_FMT_UNKNOWN)
video_fmt = BUS_FMT_UNKNOWN;
dev_info(rk628->dev, "%s: format = %s\n", __func__, bus_format_str[video_fmt]);
/*
* set avmute value to black
* RGB: R: CH2[15:0], G:CH0_1[31:16], B: CH0_1[15:0]
* YUV: Cr:CH2[15:0], Y:CH0_1[31:16], Cb:CH0_1[15:0]
*/
if (video_fmt == BUS_FMT_RGB) {
rk628_i2c_write(rk628, HDMI_VM_CFG_CH0_1, 0x0);
rk628_i2c_write(rk628, HDMI_VM_CFG_CH2, 0x0);
} else {
rk628_i2c_write(rk628, HDMI_VM_CFG_CH0_1, 0x00008000);
rk628_i2c_write(rk628, HDMI_VM_CFG_CH2, 0x8000);
}
return video_fmt;
}
EXPORT_SYMBOL(rk628_hdmirx_get_format);
void rk628_set_bg_enable(struct rk628 *rk628, bool en)
{
if (en) {
if (rk628->tx_mode)
rk628_i2c_write(rk628, GRF_BG_CTRL,
BG_R_OR_V(0) | BG_B_OR_U(0) | BG_G_OR_Y(0) | BG_ENABLE(1));
else
rk628_i2c_write(rk628, GRF_BG_CTRL,
BG_R_OR_V(512) | BG_B_OR_U(512) | BG_G_OR_Y(64) | BG_ENABLE(1));
return;
}
rk628_i2c_write(rk628, GRF_BG_CTRL, BG_ENABLE(0));
}
EXPORT_SYMBOL(rk628_set_bg_enable);
u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628)
{
int i, j;
u32 val, tmdsclk_cnt = 0;
struct hdmirx_tmdsclk_cnt tmdsclk[HDMIRX_GET_TMDSCLK_TIME] = {0};
for (i = 0; i < HDMIRX_GET_TMDSCLK_TIME; i++) {
rk628_i2c_read(rk628, HDMI_RX_HDMI_CKM_RESULT, &val);
tmdsclk_cnt = val & 0xffff;
for (j = 0; j < HDMIRX_GET_TMDSCLK_TIME; j++) {
if (tmdsclk_cnt == tmdsclk[j].tmds_cnt || !tmdsclk[j].tmds_cnt) {
tmdsclk[j].tmds_cnt = tmdsclk_cnt;
tmdsclk[j].cnt++;
break;
}
}
}
for (i = 0; i < HDMIRX_GET_TMDSCLK_TIME; i++) {
if (!tmdsclk[i].tmds_cnt)
return tmdsclk_cnt;
dev_info(rk628->dev, "tmdsclk_cnt: %d, cnt: %d\n",
tmdsclk[i].tmds_cnt, tmdsclk[i].cnt);
if (!i)
tmdsclk_cnt = tmdsclk[i].tmds_cnt;
else if (tmdsclk[i].cnt > tmdsclk[i - 1].cnt)
tmdsclk_cnt = tmdsclk[i].tmds_cnt;
}
return tmdsclk_cnt;
}
EXPORT_SYMBOL(rk628_hdmirx_get_tmdsclk_cnt);
static int rk628_hdmirx_read_timing(struct rk628 *rk628,
struct v4l2_dv_timings *timings)
{
struct v4l2_bt_timings *bt = &timings->bt;
u32 hact, vact, htotal, vtotal, fps, status;
u32 val;
u32 modetclk_cnt_hs, modetclk_cnt_vs, hs, vs;
u32 hofs_pix, hbp, hfp, vbp, vfp;
u32 tmds_clk, tmdsclk_cnt;
u64 tmp_data;
u8 video_fmt;
memset(timings, 0, sizeof(struct v4l2_dv_timings));
timings->type = V4L2_DV_BT_656_1120;
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val);
status = val;
rk628_i2c_read(rk628, HDMI_RX_MD_STS, &val);
bt->interlaced = val & ILACE_STS ?
V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
rk628_i2c_read(rk628, HDMI_RX_MD_HACT_PX, &val);
hact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VAL, &val);
vact = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
htotal = (val >> 16) & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VTL, &val);
vtotal = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_HT1, &val);
hofs_pix = val & 0xffff;
rk628_i2c_read(rk628, HDMI_RX_MD_VOL, &val);
vbp = (val & 0xffff) + 1;
tmdsclk_cnt = rk628_hdmirx_get_tmdsclk_cnt(rk628);
tmp_data = tmdsclk_cnt;
tmp_data = ((tmp_data * HDMIRX_MODETCLK_HZ) + HDMIRX_MODETCLK_CNT_NUM / 2);
do_div(tmp_data, HDMIRX_MODETCLK_CNT_NUM);
tmds_clk = tmp_data;
if (!htotal || !vtotal || bt->interlaced || vtotal > 3000) {
dev_err(rk628->dev, "timing err, %s htotal:%d, vtotal:%d\n",
bt->interlaced ? "interlaced is not supported," : "",
htotal, vtotal);
goto TIMING_ERR;
}
if (rk628->version >= RK628F_VERSION)
fps = tmds_clk / (htotal * vtotal);
else
fps = (tmds_clk + (htotal * vtotal) / 2) / (htotal * vtotal);
rk628_i2c_read(rk628, HDMI_RX_MD_HT0, &val);
modetclk_cnt_hs = val & 0xffff;
hs = (tmdsclk_cnt * modetclk_cnt_hs + HDMIRX_MODETCLK_CNT_NUM / 2) /
HDMIRX_MODETCLK_CNT_NUM;
rk628_i2c_read(rk628, HDMI_RX_MD_VSC, &val);
modetclk_cnt_vs = val & 0xffff;
vs = (tmdsclk_cnt * modetclk_cnt_vs + HDMIRX_MODETCLK_CNT_NUM / 2) /
HDMIRX_MODETCLK_CNT_NUM;
vs = (vs + htotal / 2) / htotal;
if ((hofs_pix < hs) || (htotal < (hact + hofs_pix)) ||
(vtotal < (vact + vs + vbp)) || !vs) {
dev_err(rk628->dev, "timing err, total:%dx%d, act:%dx%d, hofs:%d, hs:%d, vs:%d, vbp:%d\n",
htotal, vtotal, hact, vact, hofs_pix, hs, vs, vbp);
goto TIMING_ERR;
}
hbp = hofs_pix - hs;
hfp = htotal - hact - hofs_pix;
vfp = vtotal - vact - vs - vbp;
video_fmt = rk628_hdmirx_get_format(rk628);
if (video_fmt == BUS_FMT_YUV420) {
htotal *= 2;
hact *= 2;
hfp *= 2;
hbp *= 2;
hs *= 2;
}
dev_info(rk628->dev, "cnt_num:%d, tmds_cnt:%d, hs_cnt:%d, vs_cnt:%d, hofs:%d\n",
HDMIRX_MODETCLK_CNT_NUM, tmdsclk_cnt, modetclk_cnt_hs, modetclk_cnt_vs, hofs_pix);
bt->width = hact;
bt->height = vact;
bt->hfrontporch = hfp;
bt->hsync = hs;
bt->hbackporch = hbp;
bt->vfrontporch = vfp;
bt->vsync = vs;
bt->vbackporch = vbp;
if (rk628->version >= RK628F_VERSION)
bt->pixelclock = tmds_clk;
else
bt->pixelclock = htotal * vtotal * fps;
if (bt->interlaced == V4L2_DV_INTERLACED) {
bt->height *= 2;
bt->il_vsync = bt->vsync + 1;
bt->pixelclock /= 2;
}
if (video_fmt == BUS_FMT_YUV420)
bt->pixelclock *= 2;
if (vact == 1080 && vtotal > 1500)
goto TIMING_ERR;
dev_info(rk628->dev, "SCDC_REGS1:%#x, act:%dx%d, total:%dx%d, fps:%d, pixclk:%llu\n",
status, hact, vact, htotal, vtotal, fps, bt->pixelclock);
return 0;
TIMING_ERR:
return -ENOLCK;
}
static int rk628_hdmirx_try_to_get_timing(struct rk628 *rk628,
struct v4l2_dv_timings *timings)
{
int ret, i;
for (i = 0; i < 5; i++) {
ret = rk628_hdmirx_read_timing(rk628, timings);
if (!ret)
return ret;
msleep(20);
}
return ret;
}
int rk628_hdmirx_get_timings(struct rk628 *rk628,
struct v4l2_dv_timings *timings)
{
int i, cnt = 0, ret = 0;
u32 last_w, last_h;
u8 last_fmt;
struct v4l2_bt_timings *bt = &timings->bt;
last_w = 0;
last_h = 0;
last_fmt = BUS_FMT_RGB;
for (i = 0; i < HDMIRX_GET_TIMING_CNT; i++) {
ret = rk628_hdmirx_try_to_get_timing(rk628, timings);
if ((last_w == 0) && (last_h == 0)) {
last_w = bt->width;
last_h = bt->height;
last_fmt = rk628_hdmirx_get_format(rk628);
}
if (ret || (last_w != bt->width) || (last_h != bt->height)
|| (last_fmt != rk628_hdmirx_get_format(rk628)))
cnt = 0;
else
cnt++;
if (cnt >= 8)
break;
last_w = bt->width;
last_h = bt->height;
last_fmt = rk628_hdmirx_get_format(rk628);
usleep_range(10*1000, 10*1100);
}
if (cnt < 8) {
dev_info(rk628->dev, "%s: res not stable!\n", __func__);
ret = -EINVAL;
}
return ret;
}
EXPORT_SYMBOL(rk628_hdmirx_get_timings);
u8 rk628_hdmirx_get_range(struct rk628 *rk628)
{
u32 val;
u8 color_range;
rk628_i2c_read(rk628, HDMI_RX_PDEC_AVI_PB, &val);
color_range = (val & RGB_COLORRANGE_MASK) >> 18;
if (color_range == 0x1)
color_range = CSC_LIMIT_RANGE;
else
color_range = CSC_FULL_RANGE;
return color_range;
}
EXPORT_SYMBOL(rk628_hdmirx_get_range);
void rk628_hdmirx_controller_reset(struct rk628 *rk628)
{
mutex_lock(&rk628->rst_lock);
rk628_control_assert(rk628, RGU_HDMIRX);
rk628_control_assert(rk628, RGU_HDMIRX_PON);
udelay(10);
rk628_control_deassert(rk628, RGU_HDMIRX);
rk628_control_deassert(rk628, RGU_HDMIRX_PON);
udelay(10);
rk628_i2c_write(rk628, HDMI_RX_DMI_SW_RST, 0x000101ff);
rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x00000000);
rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x0000017f);
rk628_i2c_write(rk628, HDMI_RX_DMI_DISABLE_IF, 0x0001017f);
mutex_unlock(&rk628->rst_lock);
}
EXPORT_SYMBOL(rk628_hdmirx_controller_reset);
bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628)
{
u32 val, val1;
if (rk628->version < RK628F_VERSION)
return false;
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS1, &val);
rk628_i2c_read(rk628, HDMI_RX_SCDC_REGS2, &val1);
if (((val >> 15) & SCDC_ERRDET_MASK) < SCDC_CED_ERR_CNT &&
((val1 >> 15) & SCDC_ERRDET_MASK) < SCDC_CED_ERR_CNT &&
(val1 & SCDC_ERRDET_MASK) < SCDC_CED_ERR_CNT)
return false;
dev_info(rk628->dev, "%s: Character Error(0x%x 0x%x)!\n", __func__, val, val1);
return true;
}
EXPORT_SYMBOL(rk628_hdmirx_scdc_ced_err);

View File

@@ -8,6 +8,7 @@
#ifndef __RK628_HDMIRX_H
#define __RK628_HDMIRX_H
#include <media/v4l2-dv-timings.h>
#include "rk628.h"
/* --------- EDID and HDCP KEY ------- */
@@ -32,6 +33,8 @@
#define HOT_PLUG_DETECT_MASK BIT(0)
#define HOT_PLUG_DETECT(x) UPDATE(x, 0, 0)
#define HDMI_RX_HDMI_TIMER_CTRL (HDMI_RX_BASE + 0x0008)
#define VIDEO_PERIOD_MASK BIT(11)
#define VIDEO_PERIOD(x) UPDATE(x, 11, 11)
#define HDMI_RX_HDMI_RES_OVR (HDMI_RX_BASE + 0x0010)
#define HDMI_RX_HDMI_PLL_FRQSET2 (HDMI_RX_BASE + 0x0020)
#define HDMI_RX_HDMI_PCB_CTRL (HDMI_RX_BASE + 0x0038)
@@ -81,6 +84,7 @@
#define DCM_COLOUR_DEPTH_SEL(x) UPDATE(x, 12, 12)
#define DCM_COLOUR_DEPTH(x) UPDATE(x, 11, 8)
#define DCM_GCP_ZERO_FIELDS(x) UPDATE(x, 5, 2)
#define HDMI_VM_CFG_CH0_1 (HDMI_RX_BASE + 0x00b0)
#define HDMI_VM_CFG_CH2 (HDMI_RX_BASE + 0x00b4)
#define HDMI_RX_HDCP_CTRL (HDMI_RX_BASE + 0x00c0)
#define HDCP_ENABLE_MASK BIT(24)
@@ -189,6 +193,15 @@
#define HDMI_RX_AUDPLL_GEN_N (HDMI_RX_BASE + 0x0284)
#define HDMI_RX_SNPS_PHYG3_CTRL (HDMI_RX_BASE + 0x02c0)
#define PORTSELECT(x) UPDATE(x, 3, 2)
#define HDMI_RX_I2CM_PHYG3_SLAVE (HDMI_RX_BASE + 0x02c4)
#define HDMI_RX_I2CM_PHYG3_ADDRESS (HDMI_RX_BASE + 0x02c8)
#define HDMI_RX_I2CM_PHYG3_DATAO (HDMI_RX_BASE + 0x02cc)
#define HDMI_RX_I2CM_PHYG3_DATAI (HDMI_RX_BASE + 0x02d0)
#define HDMI_RX_I2CM_PHYG3_OPERATION (HDMI_RX_BASE + 0x02d4)
#define HDMI_RX_I2CM_PHYG3_MODE (HDMI_RX_BASE + 0x02d8)
#define HDMI_RX_I2CM_PHYG3_SS_CNTS (HDMI_RX_BASE + 0x02e0)
#define HDMI_RX_I2CM_PHYG3_FS_HCNT (HDMI_RX_BASE + 0x02e4)
#define HDMI_RX_PDEC_CTRL (HDMI_RX_BASE + 0x0300)
#define PFIFO_STORE_FILTER_EN_MASK BIT(31)
#define PFIFO_STORE_FILTER_EN(x) UPDATE(x, 31, 31)
@@ -234,9 +247,12 @@
#define HDMI_RX_PDEC_STS (HDMI_RX_BASE + 0x0360)
#define DVI_DET BIT(28)
#define HDMI_RX_PDEC_GCP_AVMUTE (HDMI_RX_BASE + 0x0380)
#define PKTDEC_GCP_CD_MASK GENMASK(7, 4)
#define HDMI_RX_PDEC_AVI_PB (HDMI_RX_BASE + 0x03a4)
#define VIDEO_FORMAT_MASK GENMASK(6, 5)
#define VIDEO_FORMAT(x) UPDATE(x, 6, 5)
#define RGB_COLORRANGE_MASK GENMASK(19, 18)
#define RGB_COLORRANGE(x) UPDATE(x, 19, 18)
#define ACT_INFO_PRESENT_MASK BIT(4)
#define HDMI_RX_PDEC_ACR_CTS (HDMI_RX_BASE + 0x0390)
#define HDMI_RX_PDEC_ACR_N (HDMI_RX_BASE + 0x0394)
@@ -248,6 +264,7 @@
#define PVO1UNMUTE(x) UPDATE(x, 29, 29)
#define PIXELMODE(x) UPDATE(x, 28, 28)
#define CTRLCHECKEN(x) UPDATE(x, 8, 8)
#define SCDC_ENABLE_MASK BIT(4)
#define SCDC_ENABLE(x) UPDATE(x, 4, 4)
#define SCRAMBEN_SEL(x) UPDATE(x, 1, 0)
#define HDMI_RX_SCDC_I2CCONFIG (HDMI_RX_BASE + 0x0804)
@@ -259,16 +276,21 @@
#define MILISECTIMERLIMIT(x) UPDATE(x, 15, 0)
#define HDMI_RX_HDCP22_CONTROL (HDMI_RX_BASE + 0x081c)
#define HDMI_RX_SCDC_REGS0 (HDMI_RX_BASE + 0x0820)
#define SCDC_TMDSBITCLKRATIO BIT(17)
#define HDMI_RX_SCDC_REGS1 (HDMI_RX_BASE + 0x0824)
#define HDMI_RX_SCDC_REGS2 (HDMI_RX_BASE + 0x0828)
#define SCDC_ERRDET_MASK GENMASK(14, 0)
#define HDMI_RX_SCDC_REGS3 (HDMI_RX_BASE + 0x082c)
#define HDMI_RX_SCDC_WRDATA0 (HDMI_RX_BASE + 0x0860)
#define MANUFACTUREROUI(x) UPDATE(x, 31, 8)
#define SINKVERSION(x) UPDATE(x, 7, 0)
#define HDMI_RX_HDMI20_STATUS (HDMI_RX_BASE + 0x08e0)
#define SCRAMBDET_MASK BIT(0)
#define HDMI_RX_HDMI2_IEN_CLR (HDMI_RX_BASE + 0x0f60)
#define HDMI_RX_HDMI2_ISTS (HDMI_RX_BASE + 0x0f68)
#define HDMI_RX_PDEC_IEN_CLR (HDMI_RX_BASE + 0x0f78)
#define AVI_CKS_CHG_ICLR BIT(24)
#define ACR_N_CHG_ICLR BIT(23)
#define ACR_CTS_CHG_ICLR BIT(22)
#define GCP_AV_MUTE_CHG_ENCLR BIT(21)
@@ -284,6 +306,7 @@
#define GCP_RCV_ENSET BIT(16)
#define AMP_RCV_ENSET BIT(14)
#define HDMI_RX_PDEC_ISTS (HDMI_RX_BASE + 0x0f80)
#define AVI_CKS_CHG_ISTS BIT(24)
#define GCP_AV_MUTE_CHG_ISTS BIT(21)
#define AIF_RCV_ISTS BIT(19)
#define AVI_RCV_ISTS BIT(18)
@@ -359,6 +382,43 @@
#define HDMIRX_HDCP1X_ID 13
#define HDMIRX_GET_TIMING_CNT 20
#define HDMIRX_MODETCLK_CNT_NUM 1000
#define HDMIRX_MODETCLK_HZ 49500000
#define EDID_NUM_BLOCKS_MAX 2
#define EDID_BLOCK_SIZE 128
#define RK628_CSI_LINK_FREQ_LOW 350000000
#define RK628_CSI_LINK_FREQ_HIGH 650000000
#define RK628_CSI_LINK_FREQ_925M 925000000
#define RK628_CSI_PIXEL_RATE_LOW 400000000
#define RK628_CSI_PIXEL_RATE_HIGH 600000000
#define MIPI_DATARATE_MBPS_LOW 700
#define MIPI_DATARATE_MBPS_HIGH 1300
#define POLL_INTERVAL_MS 1000
#define RXPHY_CFG_MAX_TIMES 10
#define CSITX_ERR_RETRY_TIMES 3
#define USE_4_LANES 4
#define YUV422_8BIT 0x1e
#define SCDC_CED_ERR_CNT 0xfff
enum color_range {
CSC_LIMIT_RANGE,
CSC_FULL_RANGE,
};
enum bus_format {
BUS_FMT_RGB = 0,
BUS_FMT_YUV422 = 1,
BUS_FMT_YUV444 = 2,
BUS_FMT_YUV420 = 3,
BUS_FMT_UNKNOWN,
};
struct hdcp_keys {
u8 KSV[HDCP_KEY_KSV_SIZE];
u8 devicekey[HDCP_PRIVATE_KEY_SIZE];
@@ -392,5 +452,16 @@ bool rk628_audio_ctsnints_enabled(HAUDINFO info);
void rk628_csi_isr_ctsn(HAUDINFO info, u32 pdec_ints);
void rk628_csi_isr_fifoints(HAUDINFO info, u32 fifo_ints);
int rk628_is_avi_ready(struct rk628 *rk628, bool avi_rcv_rdy);
void rk628_hdmirx_verisyno_phy_power_on(struct rk628 *rk628);
void rk628_hdmirx_phy_prepclk_cfg(struct rk628 *rk628);
int rk628_hdmirx_verisyno_phy_init(struct rk628 *rk628);
u8 rk628_hdmirx_get_format(struct rk628 *rk628);
void rk628_set_bg_enable(struct rk628 *rk628, bool en);
u32 rk628_hdmirx_get_tmdsclk_cnt(struct rk628 *rk628);
int rk628_hdmirx_get_timings(struct rk628 *rk628,
struct v4l2_dv_timings *timings);
u8 rk628_hdmirx_get_range(struct rk628 *rk628);
void rk628_hdmirx_controller_reset(struct rk628 *rk628);
bool rk628_hdmirx_scdc_ced_err(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,279 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
*
*/
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include "rk628_csi.h"
#include "rk628_dsi.h"
#include "rk628_mipi_dphy.h"
static inline void testif_testclk_assert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTCLK, PHY_TESTCLK);
udelay(1);
}
static inline void testif_testclk_deassert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTCLK, 0);
udelay(1);
}
void rk628_testif_testclr_assert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTCLR, PHY_TESTCLR);
udelay(1);
}
EXPORT_SYMBOL(rk628_testif_testclr_assert);
void rk628_testif_testclr_deassert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTCLR, 0);
udelay(1);
}
EXPORT_SYMBOL(rk628_testif_testclr_deassert);
static inline void testif_testen_assert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTEN, PHY_TESTEN);
udelay(1);
}
static inline void testif_testen_deassert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTEN, 0);
udelay(1);
}
static inline void testif_set_data(struct rk628 *rk628, u8 data, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? GRF_MIPI_TX1_CON : GRF_MIPI_TX0_CON,
PHY_TESTDIN_MASK, PHY_TESTDIN(data));
udelay(1);
}
static inline u8 testif_get_data(struct rk628 *rk628, uint8_t mipi_id)
{
u32 data = 0;
rk628_i2c_read(rk628, mipi_id ? GRF_DPHY1_STATUS : GRF_DPHY0_STATUS, &data);
return data >> PHY_TESTDOUT_SHIFT;
}
static void testif_test_code_write(struct rk628 *rk628, u8 test_code, uint8_t mipi_id)
{
testif_testclk_assert(rk628, mipi_id);
testif_set_data(rk628, test_code, mipi_id);
testif_testen_assert(rk628, mipi_id);
testif_testclk_deassert(rk628, mipi_id);
testif_testen_deassert(rk628, mipi_id);
}
static void testif_test_data_write(struct rk628 *rk628, u8 test_data, uint8_t mipi_id)
{
testif_testclk_deassert(rk628, mipi_id);
testif_set_data(rk628, test_data, mipi_id);
testif_testclk_assert(rk628, mipi_id);
}
u8 rk628_testif_write(struct rk628 *rk628, u8 test_code, u8 test_data, uint8_t mipi_id)
{
u8 monitor_data;
testif_test_code_write(rk628, test_code, mipi_id);
testif_test_data_write(rk628, test_data, mipi_id);
monitor_data = testif_get_data(rk628, mipi_id);
dev_dbg(rk628->dev, "test_code=0x%02x, mipi dphy%x", test_code, mipi_id);
dev_dbg(rk628->dev, "test_data=0x%02x, mipi dphy%x", test_data, mipi_id);
dev_dbg(rk628->dev, "monitor_data=0x%02x, mipi dphy%x\n", monitor_data, mipi_id);
return monitor_data;
}
EXPORT_SYMBOL(rk628_testif_write);
u8 rk628_testif_read(struct rk628 *rk628, u8 test_code, uint8_t mipi_id)
{
u8 test_data;
testif_test_code_write(rk628, test_code, mipi_id);
test_data = testif_get_data(rk628, mipi_id);
testif_test_data_write(rk628, test_data, mipi_id);
return test_data;
}
EXPORT_SYMBOL(rk628_testif_read);
static inline void mipi_dphy_enablelane_assert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? CSITX1_DPHY_CTRL : CSITX_DPHY_CTRL,
CSI_DPHY_EN_MASK, CSI_DPHY_EN(rk628->dphy_lane_en));
udelay(1);
}
static inline void mipi_dphy_enablelane_deassert(struct rk628 *rk628, uint8_t mipi_id)
{
rk628_i2c_update_bits(rk628, mipi_id ? CSITX1_DPHY_CTRL : CSITX_DPHY_CTRL,
CSI_DPHY_EN_MASK, 0);
udelay(1);
}
static inline void mipi_dphy_shutdownz_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYSHUTDOWNZ, 0);
udelay(1);
}
static inline void mipi_dphy_shutdownz_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYSHUTDOWNZ,
CSI_PHYSHUTDOWNZ);
udelay(1);
}
static inline void mipi_dphy_rstz_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYRSTZ, 0);
udelay(1);
}
static inline void mipi_dphy_rstz_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYRSTZ,
CSI_PHYRSTZ);
udelay(1);
}
void rk628_mipi_dphy_init_hsfreqrange(struct rk628 *rk628, int lane_mbps, uint8_t mipi_id)
{
const struct {
unsigned long max_lane_mbps;
u8 hsfreqrange;
} hsfreqrange_table[] = {
{ 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
};
u8 hsfreqrange;
unsigned int index;
for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++)
if (lane_mbps <= hsfreqrange_table[index].max_lane_mbps)
break;
if (index == ARRAY_SIZE(hsfreqrange_table))
--index;
hsfreqrange = hsfreqrange_table[index].hsfreqrange;
rk628_testif_write(rk628, 0x44, HSFREQRANGE(hsfreqrange), mipi_id);
}
EXPORT_SYMBOL(rk628_mipi_dphy_init_hsfreqrange);
void rk628_mipi_dphy_init_hsmanual(struct rk628 *rk628, bool manual, uint8_t mipi_id)
{
dev_info(rk628->dev,
"mipi dphy%d hs config, manual: %s\n", mipi_id, manual ? "true" : "false");
//config mipi timing when mipi freq is 1250Mbps
rk628_testif_write(rk628, 0x71,
manual ? (HSTX(rk628->mipi_timing[mipi_id].data_prepare) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x72,
manual ? (HSZERO(rk628->mipi_timing[mipi_id].data_zero) | BIT(6)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x73,
manual ? (HSTX(rk628->mipi_timing[mipi_id].data_trail) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x61,
manual ? (HSTX(rk628->mipi_timing[mipi_id].clk_prepare) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x62,
manual ? (HSZERO(rk628->mipi_timing[mipi_id].clk_zero) | BIT(6)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x63,
manual ? (HSTX(rk628->mipi_timing[mipi_id].clk_trail) | BIT(7)) : 0, mipi_id);
usleep_range(1500, 2000);
rk628_testif_write(rk628, 0x65,
manual ? (HSPOST(rk628->mipi_timing[mipi_id].clk_post) | BIT(5)) : 0, mipi_id);
}
EXPORT_SYMBOL(rk628_mipi_dphy_init_hsmanual);
int rk628_mipi_dphy_reset(struct rk628 *rk628)
{
u32 val, mask;
int ret;
rk628_i2c_write(rk628, CSITX_SYS_CTRL0_IMD, 0x1);
if (rk628->version >= RK628F_VERSION)
rk628_i2c_write(rk628, CSITX1_SYS_CTRL0_IMD, 0x1);
mipi_dphy_enablelane_deassert(rk628, 0);
if (rk628->version >= RK628F_VERSION)
mipi_dphy_enablelane_deassert(rk628, 1);
mipi_dphy_shutdownz_assert(rk628);
mipi_dphy_rstz_assert(rk628);
rk628_testif_testclr_assert(rk628, 0);
if (rk628->version >= RK628F_VERSION)
rk628_testif_testclr_assert(rk628, 1);
/* Set all REQUEST inputs to zero */
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
FORCETXSTOPMODE_MASK | FORCERXMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
if (rk628->version >= RK628F_VERSION)
rk628_i2c_update_bits(rk628, GRF_MIPI_TX1_CON,
FORCETXSTOPMODE_MASK | FORCERXMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
udelay(1);
rk628_testif_testclr_deassert(rk628, 0);
if (rk628->version >= RK628F_VERSION)
rk628_testif_testclr_deassert(rk628, 1);
mipi_dphy_enablelane_assert(rk628, 0);
if (rk628->version >= RK628F_VERSION)
mipi_dphy_enablelane_assert(rk628, 1);
mipi_dphy_shutdownz_deassert(rk628);
mipi_dphy_rstz_deassert(rk628);
rk628_i2c_write(rk628, CSITX_SYS_CTRL0_IMD, 0x0);
if (rk628->version >= RK628F_VERSION)
rk628_i2c_write(rk628, CSITX1_SYS_CTRL0_IMD, 0x0);
usleep_range(10000, 11000);
mask = STOPSTATE_CLK | STOPSTATE_LANE0;
ret = regmap_read_poll_timeout(rk628->regmap[RK628_DEV_CSI],
CSITX_CSITX_STATUS1,
val, (val & mask) == mask,
0, 1000);
if (ret < 0)
dev_err(rk628->dev, "csi0 lane module is not in stop state, val: 0x%x\n", val);
if (rk628->version >= RK628F_VERSION) {
ret = regmap_read_poll_timeout(rk628->regmap[RK628_DEV_CSI1],
CSITX1_CSITX_STATUS1,
val, (val & mask) == mask,
0, 1000);
if (ret < 0)
dev_err(rk628->dev,
"csi1 lane module is not in stop state, val: 0x%x\n", val);
}
return 0;
}
EXPORT_SYMBOL(rk628_mipi_dphy_reset);

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
*
* Author: Shunqing Chen <csq@rock-chips.com>
*/
@@ -8,12 +8,6 @@
#ifndef _RK628_MIPI_DPHY_H
#define _RK628_MIPI_DPHY_H
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include "rk628_csi.h"
#include "rk628_dsi.h"
#include "rk628.h"
/* Test Code: 0x44 (HS RX Control of Lane 0) */
@@ -21,239 +15,14 @@
#define HSTX(x) UPDATE(x, 6, 0)
#define HSZERO(x) UPDATE(x, 5, 0)
#define HSPOST(x) UPDATE(x, 4, 0)
#define HSEXIT(x) UPDATE(x, 4, 0)
static inline void testif_testclk_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLK, PHY_TESTCLK);
udelay(1);
}
static inline void testif_testclk_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLK, 0);
udelay(1);
}
static inline void testif_testclr_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLR, PHY_TESTCLR);
udelay(1);
}
static inline void testif_testclr_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTCLR, 0);
udelay(1);
}
static inline void testif_testen_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTEN, PHY_TESTEN);
udelay(1);
}
static inline void testif_testen_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTEN, 0);
udelay(1);
}
static inline void testif_set_data(struct rk628 *rk628, u8 data)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
PHY_TESTDIN_MASK, PHY_TESTDIN(data));
udelay(1);
}
static inline u8 testif_get_data(struct rk628 *rk628)
{
u32 data = 0;
rk628_i2c_read(rk628, GRF_DPHY0_STATUS, &data);
return data >> PHY_TESTDOUT_SHIFT;
}
static void testif_test_code_write(struct rk628 *rk628, u8 test_code)
{
testif_testclk_assert(rk628);
testif_set_data(rk628, test_code);
testif_testen_assert(rk628);
testif_testclk_deassert(rk628);
testif_testen_deassert(rk628);
}
static void testif_test_data_write(struct rk628 *rk628, u8 test_data)
{
testif_testclk_deassert(rk628);
testif_set_data(rk628, test_data);
testif_testclk_assert(rk628);
}
static u8 testif_write(struct rk628 *rk628, u8 test_code, u8 test_data)
{
u8 monitor_data;
testif_test_code_write(rk628, test_code);
testif_test_data_write(rk628, test_data);
monitor_data = testif_get_data(rk628);
dev_dbg(rk628->dev, "test_code=0x%02x, ", test_code);
dev_dbg(rk628->dev, "test_data=0x%02x, ", test_data);
dev_dbg(rk628->dev, "monitor_data=0x%02x\n", monitor_data);
return monitor_data;
}
static inline u8 testif_read(struct rk628 *rk628, u8 test_code)
{
u8 test_data;
testif_test_code_write(rk628, test_code);
test_data = testif_get_data(rk628);
testif_test_data_write(rk628, test_data);
return test_data;
}
static inline void mipi_dphy_enableclk_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, CSITX_DPHY_CTRL, DPHY_ENABLECLK,
DPHY_ENABLECLK);
udelay(1);
}
static inline void mipi_dphy_enableclk_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, CSITX_DPHY_CTRL, DPHY_ENABLECLK, 0);
udelay(1);
}
static inline void mipi_dphy_shutdownz_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYSHUTDOWNZ, 0);
udelay(1);
}
static inline void mipi_dphy_shutdownz_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYSHUTDOWNZ,
CSI_PHYSHUTDOWNZ);
udelay(1);
}
static inline void mipi_dphy_rstz_assert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYRSTZ, 0);
udelay(1);
}
static inline void mipi_dphy_rstz_deassert(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON, CSI_PHYRSTZ,
CSI_PHYRSTZ);
udelay(1);
}
static inline void mipi_dphy_init_hsfreqrange(struct rk628 *rk628, int lane_mbps)
{
const struct {
unsigned long max_lane_mbps;
u8 hsfreqrange;
} hsfreqrange_table[] = {
{ 90, 0x00}, { 100, 0x10}, { 110, 0x20}, { 130, 0x01},
{ 140, 0x11}, { 150, 0x21}, { 170, 0x02}, { 180, 0x12},
{ 200, 0x22}, { 220, 0x03}, { 240, 0x13}, { 250, 0x23},
{ 270, 0x04}, { 300, 0x14}, { 330, 0x05}, { 360, 0x15},
{ 400, 0x25}, { 450, 0x06}, { 500, 0x16}, { 550, 0x07},
{ 600, 0x17}, { 650, 0x08}, { 700, 0x18}, { 750, 0x09},
{ 800, 0x19}, { 850, 0x29}, { 900, 0x39}, { 950, 0x0a},
{1000, 0x1a}, {1050, 0x2a}, {1100, 0x3a}, {1150, 0x0b},
{1200, 0x1b}, {1250, 0x2b}, {1300, 0x3b}, {1350, 0x0c},
{1400, 0x1c}, {1450, 0x2c}, {1500, 0x3c}
};
u8 hsfreqrange;
unsigned int index;
for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++)
if (lane_mbps <= hsfreqrange_table[index].max_lane_mbps)
break;
if (index == ARRAY_SIZE(hsfreqrange_table))
--index;
hsfreqrange = hsfreqrange_table[index].hsfreqrange;
testif_write(rk628, 0x44, HSFREQRANGE(hsfreqrange));
}
static void __maybe_unused mipi_dphy_init_hsmanual(struct rk628 *rk628, bool manual)
{
if (manual) {
//config mipi timing when mipi freq is 1250Mbps
testif_write(rk628, 0x71, HSTX(0x4a) | BIT(7));
usleep_range(1500, 2000);
testif_write(rk628, 0x72, HSZERO(0xf) | BIT(6));
usleep_range(1500, 2000);
testif_write(rk628, 0x73, HSTX(0x5d) | BIT(7));
usleep_range(1500, 2000);
testif_write(rk628, 0x61, HSTX(0x3a) | BIT(7));
usleep_range(1500, 2000);
testif_write(rk628, 0x62, HSZERO(0x3a) | BIT(6));
usleep_range(1500, 2000);
testif_write(rk628, 0x63, HSTX(0x5a) | BIT(7));
usleep_range(1500, 2000);
testif_write(rk628, 0x65, HSPOST(0x1f) | BIT(5));
} else {
testif_write(rk628, 0x71, 0);
usleep_range(1500, 2000);
testif_write(rk628, 0x72, 0);
usleep_range(1500, 2000);
testif_write(rk628, 0x73, 0);
usleep_range(1500, 2000);
testif_write(rk628, 0x61, 0);
usleep_range(1500, 2000);
testif_write(rk628, 0x62, 0);
usleep_range(1500, 2000);
testif_write(rk628, 0x63, 0);
usleep_range(1500, 2000);
testif_write(rk628, 0x65, 0);
}
}
static inline int mipi_dphy_reset(struct rk628 *rk628)
{
u32 val, mask;
mipi_dphy_enableclk_deassert(rk628);
mipi_dphy_shutdownz_assert(rk628);
mipi_dphy_rstz_assert(rk628);
testif_testclr_assert(rk628);
/* Set all REQUEST inputs to zero */
rk628_i2c_update_bits(rk628, GRF_MIPI_TX0_CON,
FORCETXSTOPMODE_MASK | FORCERXMODE_MASK,
FORCETXSTOPMODE(0) | FORCERXMODE(0));
udelay(1);
testif_testclr_deassert(rk628);
mipi_dphy_enableclk_assert(rk628);
mipi_dphy_shutdownz_deassert(rk628);
mipi_dphy_rstz_deassert(rk628);
usleep_range(1500, 2000);
mask = STOPSTATE_CLK | STOPSTATE_LANE0;
rk628_i2c_read(rk628, CSITX_CSITX_STATUS1, &val);
if ((val & mask) != mask) {
dev_err(rk628->dev, "lane module is not in stop state\n");
return -1;
}
return 0;
}
void rk628_testif_testclr_deassert(struct rk628 *rk628, uint8_t mipi_id);
void rk628_testif_testclr_assert(struct rk628 *rk628, uint8_t mipi_id);
u8 rk628_testif_write(struct rk628 *rk628, u8 test_code, u8 test_data, uint8_t mipi_id);
u8 rk628_testif_read(struct rk628 *rk628, u8 test_code, uint8_t mipi_id);
void rk628_mipi_dphy_init_hsfreqrange(struct rk628 *rk628, int lane_mbps, uint8_t mipi_id);
void rk628_mipi_dphy_init_hsmanual(struct rk628 *rk628, bool manual, uint8_t mipi_id);
int rk628_mipi_dphy_reset(struct rk628 *rk628);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,13 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2023 Rockchip Electronics Co. Ltd.
*
*/
#ifndef POST_PROCESS_H
#define POST_PROCESS_H
void rk628_post_process_csc_en(struct rk628 *rk628);
void rk628_post_process_csc_dis(struct rk628 *rk628);
#endif

View File

@@ -3,7 +3,7 @@
rk628_misc-$(CONFIG_RK628_MISC) += rk628.o rk628_cru.o rk628_config.o rk628_post_process.o \
rk628_combrxphy.o rk628_hdmirx.o rk628_combtxphy.o rk628_dsi.o \
panel.o rk628_lvds.o rk628_rgb.o rk628_gvi.o rk628_pinctrl.o \
rk628_csi.o
rk628_csi.o rk628_efuse.o
rk628_misc-$(CONFIG_RK628_MISC_HDMITX) += rk628_hdmitx.o

View File

@@ -132,16 +132,16 @@ init_err:
int rk628_panel_info_get(struct rk628 *rk628, struct device_node *np)
{
struct panel_simple *panel;
struct rk628_panel_simple *panel;
struct device *dev = rk628->dev;
struct device_node *backlight;
int ret;
panel = devm_kzalloc(dev, sizeof(struct panel_simple), GFP_KERNEL);
panel = devm_kzalloc(dev, sizeof(struct rk628_panel_simple), GFP_KERNEL);
if (!panel)
return -ENOMEM;
panel->supply = devm_regulator_get(dev, "power");
panel->supply = devm_regulator_get(dev, "panel-power");
if (IS_ERR(panel->supply)) {
ret = PTR_ERR(panel->supply);
dev_err(dev, "failed to get power regulator: %d\n", ret);
@@ -174,9 +174,16 @@ int rk628_panel_info_get(struct rk628 *rk628, struct device_node *np)
}
device_property_read_u32(dev, "panel-prepare-delay-ms", &panel->delay.prepare);
device_property_read_u32(dev, "panel-enable-delay-ms", &panel->delay.enable);
device_property_read_u32(dev, "panel-disable-delay-ms", &panel->delay.disable);
device_property_read_u32(dev, "panel-unprepare-delay-ms", &panel->delay.unprepare);
device_property_read_u32(dev, "panel-reset-delay-ms", &panel->delay.reset);
device_property_read_u32(dev, "panel-init-delay-ms", &panel->delay.init);
rk628->panel = panel;
if (rk628->output_mode == OUTPUT_MODE_DSI) {
if (rk628_output_is_dsi(rk628)) {
ret = dsi_panel_get_cmds(rk628, np);
if (ret) {
dev_err(dev, "failed to get cmds\n");
@@ -189,57 +196,75 @@ int rk628_panel_info_get(struct rk628 *rk628, struct device_node *np)
void rk628_panel_prepare(struct rk628 *rk628)
{
struct rk628_panel_simple *p = rk628->panel;
int ret;
if (rk628->panel->supply) {
ret = regulator_enable(rk628->panel->supply);
if (!p)
return;
if (p->supply) {
ret = regulator_enable(p->supply);
if (ret)
dev_info(rk628->dev, "failed to enable panel power supply\n");
}
if (rk628->panel->enable_gpio) {
gpiod_set_value(rk628->panel->enable_gpio, 0);
mdelay(120);
gpiod_set_value(rk628->panel->enable_gpio, 1);
mdelay(120);
}
gpiod_direction_output(p->enable_gpio, 1);
if (p->delay.prepare)
msleep(p->delay.prepare);
if (rk628->panel->reset_gpio) {
gpiod_set_value(rk628->panel->reset_gpio, 0);
mdelay(120);
gpiod_set_value(rk628->panel->reset_gpio, 1);
mdelay(120);
gpiod_set_value(rk628->panel->reset_gpio, 0);
mdelay(120);
}
gpiod_direction_output(p->reset_gpio, 1);
if (p->delay.reset)
msleep(p->delay.reset);
gpiod_direction_output(p->reset_gpio, 0);
if (p->delay.init)
msleep(p->delay.init);
}
void rk628_panel_enable(struct rk628 *rk628)
{
if (rk628->panel->backlight)
backlight_enable(rk628->panel->backlight);
struct rk628_panel_simple *p = rk628->panel;
if (!p)
return;
if (p->delay.enable)
msleep(p->delay.enable);
if (p->backlight)
backlight_enable(p->backlight);
}
void rk628_panel_unprepare(struct rk628 *rk628)
{
struct rk628_panel_simple *p = rk628->panel;
if (rk628->panel->reset_gpio) {
gpiod_set_value(rk628->panel->reset_gpio, 1);
mdelay(120);
}
if (!p)
return;
if (rk628->panel->enable_gpio) {
gpiod_set_value(rk628->panel->enable_gpio, 0);
mdelay(120);
}
gpiod_direction_output(p->reset_gpio, 1);
gpiod_direction_output(p->enable_gpio, 0);
if (rk628->panel->supply)
regulator_disable(rk628->panel->supply);
if (p->delay.unprepare)
msleep(p->delay.unprepare);
}
void rk628_panel_disable(struct rk628 *rk628)
{
if (rk628->panel->backlight)
backlight_disable(rk628->panel->backlight);
struct rk628_panel_simple *p = rk628->panel;
if (!p)
return;
if (p->backlight)
backlight_disable(p->backlight);
if (p->delay.disable)
msleep(p->delay.disable);
}

File diff suppressed because it is too large Load Diff

View File

@@ -11,6 +11,7 @@
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/notifier.h>
#include <linux/regmap.h>
#include <linux/version.h>
#include <linux/of.h>
@@ -18,7 +19,7 @@
#include <linux/workqueue.h>
#include <linux/regulator/consumer.h>
#define DRIVER_VERSION "0.0.1"
#define DRIVER_VERSION "0.1.0"
#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l)))
#define HIWORD_UPDATE(v, h, l) ((((v) << (l)) & GENMASK((h), (l))) | \
(GENMASK((h), (l)) << 16))
@@ -38,8 +39,16 @@
#define SW_BT_DATA_OEN BIT(9)
#define SW_EFUSE_HDCP_EN_MASK BIT(8)
#define SW_EFUSE_HDCP_EN(x) UPDATE(x, 8, 8)
#define SW_OUTPUT_MODE_MASK GENMASK(7, 3)
#define SW_OUTPUT_MODE(x) UPDATE(x, 7, 3)
#define SW_OUTPUT_MODE_MASK GENMASK(5, 3)
#define SW_OUTPUT_MODE(x) UPDATE(x, 5, 3)
/* compatible with rk628f */
#define SW_OUTPUT_RGB_MODE_MASK GENMASK(7, 6)
#define SW_OUTPUT_RGB_MODE(x) UPDATE(x, 7, 6)
#define SW_HDMITX_EN_MASK BIT(5)
#define SW_HDMITX_EN(x) UPDATE(x, 5, 5)
#define SW_OUTPUT_COMBTX_MODE_MASK GENMASK(4, 3)
#define SW_OUTPUT_COMBTX_MODE(x) UPDATE(x, 4, 3)
#define SW_INPUT_MODE_MASK GENMASK(2, 0)
#define SW_INPUT_MODE(x) UPDATE(x, 2, 0)
#define GRF_SYSTEM_CON1 0x0004
@@ -51,7 +60,14 @@
#define GRF_GPIO_RXDDC_SDA_SEL(x) UPDATE(x, 6, 6)
#define GRF_GPIO_RXDDC_SCL_SEL_MASK BIT(5)
#define GRF_GPIO_RXDDC_SCL_SEL(x) UPDATE(x, 5, 5)
#define GRF_DPHY_CH1_EN_MASK BIT(1)
#define GRF_DPHY_CH1_EN(x) UPDATE(x, 1, 1)
#define GRF_AS_DSIPHY_MASK BIT(0)
#define GRF_AS_DSIPHY(x) UPDATE(x, 0, 0)
#define GRF_SCALER_CON0 0x0010
#define SCL_8_PIXEL_ALIGN(x) HIWORD_UPDATE(x, 12, 12)
#define SCL_COLOR_VER_EN(x) HIWORD_UPDATE(x, 10, 10)
#define SCL_COLOR_BAR_EN(x) HIWORD_UPDATE(x, 9, 9)
#define SCL_VER_DOWN_MODE(x) HIWORD_UPDATE(x, 8, 8)
#define SCL_HOR_DOWN_MODE(x) HIWORD_UPDATE(x, 7, 7)
#define SCL_BIC_COE_SEL(x) HIWORD_UPDATE(x, 6, 5)
@@ -83,6 +99,8 @@
#define DSP_VBOR_ST(x) UPDATE(x, 28, 16)
#define DSP_VBOR_END(x) UPDATE(x, 12, 0)
#define GRF_POST_PROC_CON 0x0034
#define SW_HDMITX_VSYNC_POL BIT(17)
#define SW_HDMITX_HSYNC_POL BIT(16)
#define SW_DCLK_OUT_INV_EN BIT(9)
#define SW_DCLK_IN_INV_EN BIT(8)
#define SW_TXPHY_REFCLK_SEL_MASK GENMASK(6, 5)
@@ -93,6 +111,8 @@
#define SW_SPLIT_MODE(x) UPDATE(x, 1, 1)
#define SW_SPLIT_EN BIT(0)
#define GRF_CSC_CTRL_CON 0x0038
#define SW_Y2R_MODE(x) HIWORD_UPDATE(x, 13, 12)
#define SW_FROM_CSC_MATRIX_EN(x) HIWORD_UPDATE(x, 11, 11)
#define SW_YUV2VYU_SWP(x) HIWORD_UPDATE(x, 8, 8)
#define SW_R2Y_EN(x) HIWORD_UPDATE(x, 4, 4)
#define SW_Y2R_EN(x) HIWORD_UPDATE(x, 0, 0)
@@ -179,7 +199,10 @@
#define GRF_GPIO3A_D1_CON 0x00e4
#define GRF_GPIO3B_D_CON 0x00e8
#define GRF_GPIO_SR_CON 0x00ec
#define GRF_SW_HDMIRXPHY_CRTL 0x00f4
#define GRF_INTR0_EN 0x0100
#define RK628F_HDMIRX_IRQ_EN(x) HIWORD_UPDATE(x, 9, 9)
#define RK628D_HDMIRX_IRQ_EN(x) HIWORD_UPDATE(x, 8, 8)
#define GRF_INTR0_CLR_EN 0x0104
#define GRF_INTR0_STATUS 0x0108
#define GRF_INTR0_RAW_STATUS 0x010c
@@ -191,18 +214,53 @@
/* 0: i2c mode and mcu mode; 1: i2c mode only */
#define I2C_ONLY_FLAG BIT(6)
#define GRF_SYSTEM_STATUS3 0x012c
#define DECODER_1120_LAST_LINE_NUM_MASK GENMASK(12, 0)
#define GRF_SYSTEM_STATUS4 0x0130
#define DECODER_1120_LAST_PIX_NUM_MASK GENMASK(12, 0)
#define GRF_OS_REG0 0x0140
#define GRF_OS_REG1 0x0144
#define GRF_OS_REG2 0x0148
#define GRF_OS_REG3 0x014c
#define GRF_SOC_VERSION 0x0150
#define GRF_MAX_REGISTER GRF_SOC_VERSION
#define GRF_RGB_RX_DBG_MEAS0 0x0170
#define RGB_RX_EVAL_TIME_MASK GENMASK(27, 16)
#define RGB_RX_MODET_EN BIT(1)
#define RGB_RX_DCLK_EN BIT(0)
#define GRF_RGB_RX_DBG_MEAS2 0x0178
#define RGB_RX_CLKRATE_MASK GENMASK(15, 0)
#define GRF_RGB_RX_DBG_MEAS3 0x017c
#define RGB_RX_CNT_EN_MASK BIT(0)
#define RGB_RX_CNT_EN(x) UPDATE(x, 0, 0)
#define GRF_RGB_RX_DBG_MEAS4 0x0180
#define GRF_BT1120_TIMING_CTRL0 0x0190
#define BT1120_DSP_HS_END(x) UPDATE(x, 28, 16)
#define BT1120_DSP_HTOTAL(x) UPDATE(x, 12, 0)
#define GRF_BT1120_TIMING_CTRL1 0x0194
#define BT1120_DSP_HACT_ST(x) UPDATE(x, 28, 16)
#define GRF_BT1120_TIMING_CTRL2 0x0198
#define BT1120_DSP_VS_END(x) UPDATE(x, 28, 16)
#define BT1120_DSP_VTOTAL(x) UPDATE(x, 12, 0)
#define GRF_BT1120_TIMING_CTRL3 0x019c
#define BT1120_DSP_VACT_ST(x) UPDATE(x, 28, 16)
#define GRF_CSC_MATRIX_COE01_COE00 0x01a0
#define GRF_CSC_MATRIX_COE10_COE02 0x01a4
#define GRF_CSC_MATRIX_COE12_COE11 0x01a8
#define GRF_CSC_MATRIX_COE21_COE20 0x01ac
#define GRF_CSC_MATRIX_COE22 0x01b0
#define GRF_CSC_MATRIX_OFFSET0 0x01b4
#define GRF_CSC_MATRIX_OFFSET1 0x01b8
#define GRF_CSC_MATRIX_OFFSET2 0x01bc
#define GRF_SOC_VERSION 0x0200
#define GRF_OBS_REG 0X0300
#define GRF_MAX_REGISTER GRF_OBS_REG
#define DRM_MODE_FLAG_PHSYNC (1<<0)
#define DRM_MODE_FLAG_NHSYNC (1<<1)
#define DRM_MODE_FLAG_PVSYNC (1<<2)
#define DRM_MODE_FLAG_NVSYNC (1<<3)
#define DRM_MODE_FLAG_INTERLACE (1<<4)
#define RK628D_VERSION 0x20200326
#define RK628F_VERSION 0x20230321
enum {
COMBTXPHY_MODULEA_EN = BIT(0),
@@ -317,7 +375,63 @@ enum rk628_mode_sync_pol {
MODE_FLAG_PSYNC,
};
#undef BT1120_DUAL_EDGE
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
enum rk628_v4l2_colorspace {
/*
* Default colorspace, i.e. let the driver figure it out.
* Can only be used with video capture.
*/
V4L2_COLORSPACE_DEFAULT = 0,
/* SMPTE 170M: used for broadcast NTSC/PAL SDTV */
V4L2_COLORSPACE_SMPTE170M = 1,
/* Obsolete pre-1998 SMPTE 240M HDTV standard, superseded by Rec 709 */
V4L2_COLORSPACE_SMPTE240M = 2,
/* Rec.709: used for HDTV */
V4L2_COLORSPACE_REC709 = 3,
/*
* Deprecated, do not use. No driver will ever return this. This was
* based on a misunderstanding of the bt878 datasheet.
*/
V4L2_COLORSPACE_BT878 = 4,
/*
* NTSC 1953 colorspace. This only makes sense when dealing with
* really, really old NTSC recordings. Superseded by SMPTE 170M.
*/
V4L2_COLORSPACE_470_SYSTEM_M = 5,
/*
* EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when
* dealing with really old PAL/SECAM recordings. Superseded by
* SMPTE 170M.
*/
V4L2_COLORSPACE_470_SYSTEM_BG = 6,
/*
* Effectively shorthand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601
* and V4L2_QUANTIZATION_FULL_RANGE. To be used for (Motion-)JPEG.
*/
V4L2_COLORSPACE_JPEG = 7,
/* For RGB colorspaces such as produces by most webcams. */
V4L2_COLORSPACE_SRGB = 8,
/* opRGB colorspace */
V4L2_COLORSPACE_OPRGB = 9,
/* BT.2020 colorspace, used for UHDTV. */
V4L2_COLORSPACE_BT2020 = 10,
/* Raw colorspace: for RAW unprocessed images */
V4L2_COLORSPACE_RAW = 11,
/* DCI-P3 colorspace, used by cinema projectors */
V4L2_COLORSPACE_DCI_P3 = 12,
};
struct rk628_videomode {
u32 pixelclock; /* pixelclock in Hz */
@@ -366,7 +480,7 @@ struct panel_cmds {
int cmd_cnt;
};
struct panel_simple {
struct rk628_panel_simple {
struct backlight_device *backlight;
struct regulator *supply;
@@ -374,6 +488,15 @@ struct panel_simple {
struct gpio_desc *reset_gpio;
struct panel_cmds *on_cmds;
struct panel_cmds *off_cmds;
struct {
unsigned int prepare;
unsigned int enable;
unsigned int disable;
unsigned int unprepare;
unsigned int reset;
unsigned int init;
} delay;
};
struct rk628_dsi {
@@ -386,6 +509,7 @@ struct rk628_dsi {
uint8_t lanes;
uint8_t id; /* 0:dsi0 1:dsi1 */
struct rk628 *rk628;
unsigned int lane_mbps; /* per lane */
};
struct rk628_lvds {
@@ -396,6 +520,7 @@ struct rk628_lvds {
struct rk628_gvi {
enum gvi_bus_format bus_format;
enum gvi_color_depth color_depth;
int retry_times;
uint8_t lanes;
bool division_mode;
bool frm_rst;
@@ -413,6 +538,11 @@ struct rk628_combtxphy {
bool division_mode;
};
struct rk628_rgb {
struct regulator *vccio_rgb;
bool bt1120_dual_edge;
};
struct rk628 {
struct device *dev;
struct i2c_client *client;
@@ -425,13 +555,15 @@ struct rk628 {
struct clk *soc_24M;
struct workqueue_struct *monitor_wq;
struct delayed_work delay_work;
struct dentry *debug_dir;
struct workqueue_struct *dsi_wq;
struct delayed_work dsi_delay_work;
struct panel_simple *panel;
struct rk628_panel_simple *panel;
void *hdmirx;
void *hdmitx;
bool display_enabled;
enum rk628_input_mode input_mode;
enum rk628_output_mode output_mode;
u32 input_mode;
u32 output_mode;
struct rk628_display_mode src_mode;
struct rk628_display_mode dst_mode;
enum bus_format input_fmt;
@@ -443,8 +575,62 @@ struct rk628 {
struct rk628_combtxphy combtxphy;
int sync_pol;
void *csi;
struct notifier_block fb_nb;
u32 version;
struct rk628_rgb rgb;
int old_blank;
};
static inline bool rk628_input_is_hdmi(struct rk628 *rk628)
{
return rk628->input_mode & BIT(INPUT_MODE_HDMI);
}
static inline bool rk628_input_is_rgb(struct rk628 *rk628)
{
return rk628->input_mode & BIT(INPUT_MODE_RGB);
}
static inline bool rk628_input_is_bt1120(struct rk628 *rk628)
{
return rk628->input_mode & BIT(INPUT_MODE_BT1120);
}
static inline bool rk628_output_is_rgb(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_RGB);
}
static inline bool rk628_output_is_bt1120(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_BT1120);
}
static inline bool rk628_output_is_gvi(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_GVI);
}
static inline bool rk628_output_is_lvds(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_LVDS);
}
static inline bool rk628_output_is_dsi(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_DSI);
}
static inline bool rk628_output_is_csi(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_CSI);
}
static inline bool rk628_output_is_hdmi(struct rk628 *rk628)
{
return rk628->output_mode & BIT(OUTPUT_MODE_HDMI);
}
static inline int rk628_i2c_write(struct rk628 *rk628, u32 reg, u32 val)
{
int region = (reg >> 16) & 0xff;

View File

@@ -41,10 +41,20 @@ static void rk628_combtxphy_dsi_power_on(struct rk628 *rk628)
if (ret < 0)
dev_err(rk628->dev, "phy is not lock\n");
rk628_i2c_update_bits(rk628, COMBTXPHY_CON9,
SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK,
SW_DSI_FSET_EN | SW_DSI_RCAL_EN);
SW_DSI_FSET_EN_MASK | SW_DSI_RCAL_EN_MASK,
SW_DSI_FSET_EN | SW_DSI_RCAL_EN(1));
if (rk628->version == RK628F_VERSION) {
rk628_i2c_update_bits(rk628, COMBTXPHY_CON6,
SW_PLL_CTL_CON0_MASK,
SW_PLL_CTL_CON0(1));
rk628_i2c_update_bits(rk628, COMBTXPHY_CON9,
SW_DSI_LPTX_SR_TRIM_MASK |
SW_DSI_HSTX_AMP_TRIM_MASK,
SW_DSI_LPTX_SR_TRIM(0) |
SW_DSI_HSTX_AMP_TRIM(4));
}
usleep_range(200, 400);
}
@@ -57,11 +67,15 @@ static void rk628_combtxphy_lvds_power_on(struct rk628 *rk628)
int ret;
/* Adjust terminal resistance 133 ohm, bypass 0.95v ldo for driver. */
if (rk628->version == RK628F_VERSION)
val = TX_COM_VOLT_ADJ(3);
else
val = TX_COM_VOLT_ADJ(0);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON7,
SW_TX_RTERM_MASK | SW_TX_MODE_MASK |
BYPASS_095V_LDO_MASK | TX_COM_VOLT_ADJ_MASK,
SW_TX_RTERM(6) | SW_TX_MODE(3) |
BYPASS_095V_LDO(1) | TX_COM_VOLT_ADJ(0));
BYPASS_095V_LDO(1) | val);
rk628_i2c_write(rk628, COMBTXPHY_CON10, TX7_CKDRV_EN | TX2_CKDRV_EN);
rk628_i2c_update_bits(rk628, COMBTXPHY_CON0,
@@ -263,7 +277,9 @@ void rk628_combtxphy_set_mode(struct rk628 *rk628, enum phy_mode mode)
else
combtxphy->rate_div = 1;
fvco = bus_width * combtxphy->rate_div;
ref_clk = rk628_cru_clk_get_rate(rk628, CGU_SCLK_VOP) / 1000; /* khz */
ref_clk = rk628_cru_clk_get_rate(rk628, CGU_SCLK_VOP);
ref_clk = DIV_ROUND_CLOSEST_ULL(ref_clk, 1000); /* khz */
if (combtxphy->division_mode)
ref_clk /= 2;
/*
@@ -284,7 +300,7 @@ void rk628_combtxphy_set_mode(struct rk628 *rk628, enum phy_mode mode)
/*
* ref_clk / ref_div * 8 * fb_div = FVCO
*/
pre_clk = (unsigned long long)fvco / 8 * combtxphy->ref_div * 1024;
pre_clk = (unsigned long long)fvco * combtxphy->ref_div / 8 * 1024;
do_div(pre_clk, ref_clk);
fb_div = pre_clk / 1024;

View File

@@ -41,6 +41,8 @@
#define SW_PLL_FB_DIV(x) UPDATE(x, 14, 10)
#define SW_PLL_FRAC_DIV(x) UPDATE(x, 9, 0)
#define COMBTXPHY_CON6 REG(0x0018)
#define SW_PLL_CTL_CON0_MASK GENMASK(2, 0)
#define SW_PLL_CTL_CON0(x) UPDATE(x, 2, 0)
#define COMBTXPHY_CON7 REG(0x001c)
#define SW_TX_RTERM_MASK GENMASK(22, 20)
#define SW_TX_RTERM(x) UPDATE(x, 22, 20)
@@ -60,7 +62,13 @@
#define SW_DSI_FSET_EN_MASK BIT(29)
#define SW_DSI_FSET_EN BIT(29)
#define SW_DSI_RCAL_EN_MASK BIT(28)
#define SW_DSI_RCAL_EN BIT(28)
#define SW_DSI_RCAL_EN(x) UPDATE(x, 28, 28)
#define SW_DSI_RCAL_TRIM_MASK GENMASK(27, 24)
#define SW_DSI_RCAL_TRIM(x) UPDATE(x, 27, 24)
#define SW_DSI_LPTX_SR_TRIM_MASK GENMASK(6, 4)
#define SW_DSI_LPTX_SR_TRIM(x) UPDATE(x, 6, 4)
#define SW_DSI_HSTX_AMP_TRIM_MASK GENMASK(2, 0)
#define SW_DSI_HSTX_AMP_TRIM(x) UPDATE(x, 2, 0)
#define COMBTXPHY_CON10 REG(0x0028)
#define TX9_CKDRV_EN BIT(9)
#define TX8_CKDRV_EN BIT(8)

View File

@@ -5,6 +5,7 @@
* Author: Wyon Bi <bivvy.bi@rock-chips.com>
*/
#include "asm-generic/errno-base.h"
#include "rk628.h"
#include "rk628_cru.h"
@@ -65,6 +66,9 @@ static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
u64 foutvco, foutpostdiv;
u32 offset, val;
if (id == CGU_CLK_APLL && rk628->version < RK628F_VERSION)
return 0;
rk628_i2c_read(rk628, CRU_MODE_CON00, &val);
if (id == CGU_CLK_CPLL) {
val &= CLK_CPLL_MODE_MASK;
@@ -73,13 +77,20 @@ static unsigned long rk628_cru_clk_get_rate_pll(struct rk628 *rk628,
return parent_rate;
offset = 0x00;
} else {
} else if (id == CGU_CLK_GPLL) {
val &= CLK_GPLL_MODE_MASK;
val >>= CLK_GPLL_MODE_SHIFT;
if (val == CLK_GPLL_MODE_OSC)
return parent_rate;
offset = 0x20;
} else {
val &= CLK_APLL_MODE_MASK;
val >>= CLK_APLL_MODE_SHIFT;
if (val == CLK_APLL_MODE_OSC)
return parent_rate;
offset = 0x40;
}
rk628_i2c_read(rk628, offset + CRU_CPLL_CON0, &con0);
@@ -123,7 +134,7 @@ static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
u8 dsmpd = 1, postdiv1 = 0, postdiv2 = 0, refdiv = 0;
u16 fbdiv = 0;
u32 frac = 0;
u64 foutvco, foutpostdiv;
u64 foutvco, foutpostdiv, div1, div2;
u32 offset, val;
/*
@@ -140,10 +151,13 @@ static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
if (id == CGU_CLK_CPLL)
offset = 0x00;
else
else if (id == CGU_CLK_GPLL)
offset = 0x20;
else
offset = 0x40;
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(1));
if (id != CGU_CLK_APLL)
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(1));
if (fin == fout) {
rk628_i2c_write(rk628, offset + CRU_CPLL_CON0, PLL_BYPASS(1));
@@ -162,21 +176,24 @@ static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
max_refdiv = 64;
if (fout < MIN_FVCO_RATE) {
postdiv = MIN_FVCO_RATE / fout + 1;
for (postdiv2 = 1; postdiv2 < 8; postdiv2++) {
if (postdiv % postdiv2)
div1 = DIV_ROUND_UP(MIN_FVCO_RATE, fout);
div2 = DIV_ROUND_UP(MAX_FVCO_RATE, fout);
for (postdiv = div1; postdiv <= div2; postdiv++) {
/* fix prime number that can not find right div*/
for (postdiv2 = 1; postdiv2 < 8; postdiv2++) {
if (postdiv % postdiv2)
continue;
postdiv1 = postdiv / postdiv2;
if (postdiv1 > 0 && postdiv1 < 8)
break;
}
if (postdiv2 > 7)
continue;
postdiv1 = postdiv / postdiv2;
if (postdiv1 > 0 && postdiv1 < 8)
else
break;
}
if (postdiv2 > 7)
if (postdiv > div2)
return 0;
fout *= postdiv1 * postdiv2;
} else {
postdiv1 = 1;
@@ -244,7 +261,9 @@ static unsigned long rk628_cru_clk_set_rate_pll(struct rk628 *rk628,
PLL_REFDIV(refdiv));
rk628_i2c_write(rk628, offset + CRU_CPLL_CON2, PLL_FRAC(frac));
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
if (id != CGU_CLK_APLL)
rk628_i2c_write(rk628, offset + CRU_CPLL_CON1, PLL_PD(0));
while (1) {
rk628_i2c_read(rk628, offset + CRU_CPLL_CON1, &val);
if (val & PLL_LOCK)
@@ -297,6 +316,26 @@ static unsigned long rk628_cru_clk_get_rate_sclk_vop(struct rk628 *rk628)
return rate;
}
static unsigned long rk628_cru_clk_get_rate_clk_imodet(struct rk628 *rk628)
{
unsigned long rate, parent_rate, n;
u32 mux, div;
rk628_i2c_read(rk628, CRU_CLKSEL_CON05, &mux);
mux &= CLK_IMODET_SEL_MASK;
mux >>= CLK_IMODET_SEL_SHIFT;
if (mux == SCLK_VOP_SEL_GPLL)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
rk628_i2c_read(rk628, CRU_CLKSEL_CON05, &div);
n = div & 0x1f;
rate = parent_rate / (n + 1);
return rate;
}
static unsigned long rk628_cru_clk_set_rate_rx_read(struct rk628 *rk628,
unsigned long rate)
{
@@ -367,6 +406,51 @@ static unsigned long rk628_cru_clk_set_rate_sclk_uart(struct rk628 *rk628,
return rate;
}
static unsigned long rk628_cru_clk_set_rate_sclk_hdmirx_aud(struct rk628 *rk628, unsigned long rate)
{
u64 parent_rate;
u8 div;
if (rk628->version >= RK628F_VERSION)
parent_rate = rk628_cru_clk_set_rate_pll(rk628, CGU_CLK_APLL, rate*4);
else
parent_rate = rk628_cru_clk_set_rate_pll(rk628, CGU_CLK_GPLL, rate*4);
div = DIV_ROUND_CLOSEST_ULL(parent_rate, rate);
do_div(parent_rate, div);
rate = parent_rate;
if (rk628->version >= RK628F_VERSION)
rk628_i2c_write(rk628, CRU_CLKSEL_CON05, CLK_HDMIRX_AUD_DIV(div - 1) |
CLK_HDMIRX_AUD_SEL_V2(2));
else
rk628_i2c_write(rk628, CRU_CLKSEL_CON05, CLK_HDMIRX_AUD_DIV(div - 1) |
CLK_HDMIRX_AUD_SEL_V1(1));
return rate;
}
static unsigned long rk628_cru_clk_get_rate_sclk_hdmirx_aud(struct rk628 *rk628)
{
unsigned long rate;
u64 parent_rate;
u8 div;
u32 val;
rk628_i2c_read(rk628, CRU_CLKSEL_CON05, &val);
div = ((val & CLK_HDMIRX_AUD_DIV_MASK) >> 6) + 1;
if (rk628->version >= RK628F_VERSION)
val = (val & CLK_HDMIRX_AUD_SEL_MASK_V2) >> 14;
else
val = (val & CLK_HDMIRX_AUD_SEL_MASK_V1) >> 15;
if (!val)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_CPLL);
else if (val == 2)
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_APLL);
else
parent_rate = rk628_cru_clk_get_rate_pll(rk628, CGU_CLK_GPLL);
do_div(parent_rate, div);
rate = parent_rate;
return rate;
}
static unsigned long
rk628_cru_clk_get_rate_bt1120_dec_parent(struct rk628 *rk628)
{
@@ -399,7 +483,11 @@ static unsigned long rk628_cru_clk_set_rate_bt1120_dec(struct rk628 *rk628,
int rk628_cru_clk_set_rate(struct rk628 *rk628, unsigned int id,
unsigned long rate)
{
if (id == CGU_CLK_APLL && rk628->version < RK628F_VERSION)
return -EINVAL;
switch (id) {
case CGU_CLK_APLL:
case CGU_CLK_CPLL:
case CGU_CLK_GPLL:
rk628_cru_clk_set_rate_pll(rk628, id, rate);
@@ -416,8 +504,11 @@ int rk628_cru_clk_set_rate(struct rk628 *rk628, unsigned int id,
case CGU_BT1120DEC:
rk628_cru_clk_set_rate_bt1120_dec(rk628, rate);
break;
case CGU_CLK_HDMIRX_AUD:
rk628_cru_clk_set_rate_sclk_hdmirx_aud(rk628, rate);
break;
default:
return -1;
return -EINVAL;
}
return 0;
@@ -427,7 +518,11 @@ unsigned long rk628_cru_clk_get_rate(struct rk628 *rk628, unsigned int id)
{
unsigned long rate;
if (id == CGU_CLK_APLL && rk628->version < RK628F_VERSION)
return 0;
switch (id) {
case CGU_CLK_APLL:
case CGU_CLK_CPLL:
case CGU_CLK_GPLL:
rate = rk628_cru_clk_get_rate_pll(rk628, id);
@@ -435,6 +530,12 @@ unsigned long rk628_cru_clk_get_rate(struct rk628 *rk628, unsigned int id)
case CGU_SCLK_VOP:
rate = rk628_cru_clk_get_rate_sclk_vop(rk628);
break;
case CGU_CLK_IMODET:
rate = rk628_cru_clk_get_rate_clk_imodet(rk628);
break;
case CGU_CLK_HDMIRX_AUD:
rate = rk628_cru_clk_get_rate_sclk_hdmirx_aud(rk628);
break;
default:
return 0;
}
@@ -449,9 +550,10 @@ void rk628_cru_init(struct rk628 *rk628)
rk628_i2c_read(rk628, GRF_SYSTEM_STATUS0, &val);
mcu_mode = (val & I2C_ONLY_FLAG) ? 0 : 1;
if (mcu_mode)
if (mcu_mode || rk628->version >= RK628F_VERSION) {
rk628_i2c_write(rk628, CRU_MODE_CON00, HIWORD_UPDATE(1, 4, 4));
return;
}
rk628_i2c_write(rk628, CRU_GPLL_CON0, 0xffff701d);
mdelay(1);
rk628_i2c_write(rk628, CRU_MODE_CON00, 0xffff0004);

View File

@@ -46,7 +46,16 @@
#define CRU_GPLL_CON2 CRU_REG(0x0028)
#define CRU_GPLL_CON3 CRU_REG(0x002c)
#define CRU_GPLL_CON4 CRU_REG(0x0030)
#define CRU_APLL_CON0 CRU_REG(0x0040)
#define CRU_APLL_CON1 CRU_REG(0x0044)
#define CRU_APLL_CON2 CRU_REG(0x0048)
#define CRU_APLL_CON3 CRU_REG(0x004c)
#define CRU_APLL_CON4 CRU_REG(0x0050)
#define CRU_MODE_CON00 CRU_REG(0x0060)
#define CLK_APLL_MODE_MASK BIT(4)
#define CLK_APLL_MODE_SHIFT 4
#define CLK_APLL_MODE_GPLL 1
#define CLK_APLL_MODE_OSC 0
#define CLK_GPLL_MODE_MASK BIT(2)
#define CLK_GPLL_MODE_SHIFT 2
#define CLK_GPLL_MODE_GPLL 1
@@ -73,7 +82,19 @@
#define CLK_BT1120DEC_DIV(x) HIWORD_UPDATE(x, 4, 0)
#define CRU_CLKSEL_CON03 CRU_REG(0x008c)
#define CRU_CLKSEL_CON04 CRU_REG(0x0090)
#define CLK_HDMIRX_AUD_DIV_MASK GENMASK(13, 6)
#define CLK_HDMIRX_AUD_DIV(x) HIWORD_UPDATE(x, 13, 6)
#define CLK_HDMIRX_AUD_SEL_MASK GENMASK(15, 14)
#define CLK_HDMIRX_AUD_SEL(x) HIWORD_UPDATE(x, 15, 14)
#define CRU_CLKSEL_CON05 CRU_REG(0x0094)
#define CLK_HDMIRX_AUD_DIV_MASK GENMASK(13, 6)
#define CLK_HDMIRX_AUD_DIV(x) HIWORD_UPDATE(x, 13, 6)
#define CLK_HDMIRX_AUD_SEL_V1(x) HIWORD_UPDATE(x, 15, 15)
#define CLK_HDMIRX_AUD_SEL_MASK_V1 GENMASK(15, 15)
#define CLK_HDMIRX_AUD_SEL_V2(x) HIWORD_UPDATE(x, 15, 14)
#define CLK_HDMIRX_AUD_SEL_MASK_V2 GENMASK(15, 14)
#define CLK_IMODET_SEL_MASK BIT(5)
#define CLK_IMODET_SEL_SHIFT 5
#define CRU_CLKSEL_CON06 CRU_REG(0x0098)
#define SCLK_UART_SEL(x) HIWORD_UPDATE(x, 15, 14)
#define SCLK_UART_SEL_MASK GENMASK(15, 14)
@@ -150,6 +171,7 @@
#define CGU_I2S_MCLKOUT 36
#define CGU_BT1120DEC 37
#define CGU_SCLK_UART 38
#define CGU_CLK_APLL 39
unsigned long rk628_cru_clk_get_rate(struct rk628 *rk628, unsigned int id);
int rk628_cru_clk_set_rate(struct rk628 *rk628, unsigned int id,

View File

@@ -416,8 +416,15 @@ static void enable_stream(struct rk628 *rk628, bool en)
void rk628_csi_init(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_OUTPUT_MODE_MASK, SW_OUTPUT_MODE(OUTPUT_MODE_CSI));
u32 mask = SW_OUTPUT_MODE_MASK;
u32 val = SW_OUTPUT_MODE(OUTPUT_MODE_CSI);
if (rk628->version == RK628F_VERSION) {
mask = SW_OUTPUT_COMBTX_MODE_MASK;
val = SW_OUTPUT_COMBTX_MODE(OUTPUT_MODE_CSI - 1);
}
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
rk628_csi_get_detected_timings(rk628);
mipi_dphy_reset(rk628);
}

View File

@@ -6,6 +6,7 @@
*/
#include <asm/unaligned.h>
#include <linux/debugfs.h>
#include "rk628.h"
#include "rk628_cru.h"
#include "rk628_dsi.h"
@@ -21,8 +22,6 @@
/* use Low Power Mode to transmit message */
#define MIPI_DSI_MSG_USE_LPM BIT(1)
static u32 lane_mbps;
enum vid_mode_type {
VIDEO_MODE,
COMMAND_MODE,
@@ -237,7 +236,6 @@ int rk628_dsi_parse(struct rk628 *rk628, struct device_node *dsi_np)
if (!of_device_is_available(dsi_np))
return -EINVAL;
rk628->output_mode = OUTPUT_MODE_DSI;
rk628->dsi0.id = 0;
rk628->dsi0.channel = 0;
rk628->dsi0.rk628 = rk628;
@@ -254,6 +252,9 @@ int rk628_dsi_parse(struct rk628 *rk628, struct device_node *dsi_np)
if (of_property_read_bool(dsi_np, "dsi,eotp"))
rk628->dsi0.mode_flags |= MIPI_DSI_MODE_EOT_PACKET;
if (of_property_read_bool(dsi_np, "dsi,clk-non-continuous"))
rk628->dsi0.mode_flags |= MIPI_DSI_CLOCK_NON_CONTINUOUS;
if (!of_property_read_string(dsi_np, "dsi,format", &string)) {
if (!strcmp(string, "rgb666")) {
rk628->dsi0.bus_format = MIPI_DSI_FMT_RGB666;
@@ -697,8 +698,8 @@ static int rk628_dsi_transfer(struct rk628 *rk628, const struct rk628_dsi *dsi,
return msg->tx_len;
}
int rk628_mipi_dsi_generic_write(struct rk628 *rk628,
const void *payload, size_t size)
static int rk628_mipi_dsi_generic_write(struct rk628 *rk628,
const void *payload, size_t size)
{
const struct rk628_dsi *dsi = &rk628->dsi0;
struct mipi_dsi_msg msg;
@@ -731,8 +732,8 @@ int rk628_mipi_dsi_generic_write(struct rk628 *rk628,
return rk628_dsi_transfer(rk628, dsi, &msg);
}
int rk628_mipi_dsi_dcs_write_buffer(struct rk628 *rk628,
const void *data, size_t len)
static int rk628_mipi_dsi_dcs_write_buffer(struct rk628 *rk628,
const void *data, size_t len)
{
const struct rk628_dsi *dsi = &rk628->dsi0;
struct mipi_dsi_msg msg;
@@ -763,7 +764,8 @@ int rk628_mipi_dsi_dcs_write_buffer(struct rk628 *rk628,
return rk628_dsi_transfer(rk628, dsi, &msg);
}
int rk628_mipi_dsi_dcs_read(struct rk628 *rk628, u8 cmd, void *data, size_t len)
static __maybe_unused int rk628_mipi_dsi_dcs_read(struct rk628 *rk628, u8 cmd,
void *data, size_t len)
{
const struct rk628_dsi *dsi = &rk628->dsi0;
struct mipi_dsi_msg msg;
@@ -823,14 +825,20 @@ panel_simple_xfer_dsi_cmd_seq(struct rk628 *rk628, struct panel_cmds *cmds)
static u32 rk628_dsi_get_lane_rate(const struct rk628_dsi *dsi)
{
const struct rk628_display_mode *mode = &dsi->rk628->dst_mode;
u32 lane_rate;
struct device_node *dsi_np;
u32 lane_rate, value;
u32 max_lane_rate = 1500;
u8 bpp, lanes;
bpp = dsi->bpp;
lanes = dsi->slave ? dsi->lanes * 2 : dsi->lanes;
lane_rate = mode->clock / 1000 * bpp / lanes;
lane_rate = DIV_ROUND_UP(lane_rate * 5, 4);
dsi_np = of_find_node_by_name(dsi->rk628->dev->of_node, "rk628-dsi");
if (dsi_np && !of_property_read_u32(dsi_np, "rockchip,lane-mbps", &value)) {
lane_rate = value;
} else {
bpp = dsi->bpp;
lanes = dsi->slave ? dsi->lanes * 2 : dsi->lanes;
lane_rate = mode->clock / 1000 * bpp / lanes;
lane_rate = DIV_ROUND_UP(lane_rate * 5, 4);
}
if (lane_rate > max_lane_rate)
lane_rate = max_lane_rate;
@@ -939,6 +947,65 @@ static void testif_write(struct rk628 *rk628, const struct rk628_dsi *dsi,
dev_info(rk628->dev, "monitor_data: 0x%x\n", monitor_data);
}
static void testif_set_timing(const struct rk628_dsi *dsi, u8 addr,
u8 max, u8 val)
{
struct rk628 *rk628 = dsi->rk628;
if (val > max)
return;
testif_write(rk628, dsi, addr, (max + 1) | val);
}
static void mipi_dphy_set_timing(const struct rk628_dsi *dsi)
{
const struct {
unsigned int min_lane_mbps;
unsigned int max_lane_mbps;
u8 clk_lp;
u8 clk_hs_prepare;
u8 clk_hs_zero;
u8 clk_hs_trail;
u8 clk_post;
u8 data_lp;
u8 data_hs_prepare;
u8 data_hs_zero;
u8 data_hs_trail;
} timing_table[] = {
{800, 899, 0x07, 0x30, 0x25, 0x3c, 0x0f, 0x07, 0x40, 0x09, 0x40},
{1100, 1249, 0x0a, 0x43, 0x2c, 0x50, 0x0f, 0x0a, 0x43, 0x10, 0x55},
{1250, 1349, 0x0b, 0x43, 0x2c, 0x50, 0x0f, 0x0b, 0x53, 0x10, 0x5b},
{1350, 1449, 0x0c, 0x43, 0x36, 0x60, 0x0f, 0x0c, 0x53, 0x10, 0x65},
{1450, 1500, 0x0f, 0x60, 0x31, 0x60, 0x0f, 0x0e, 0x60, 0x11, 0x6a}
};
unsigned int index;
if (dsi->lane_mbps < timing_table[0].min_lane_mbps)
return;
for (index = 0; index < ARRAY_SIZE(timing_table); index++)
if (dsi->lane_mbps >= timing_table[index].min_lane_mbps &&
dsi->lane_mbps < timing_table[index].max_lane_mbps)
break;
if (index == ARRAY_SIZE(timing_table))
--index;
if (dsi->lane_mbps < timing_table[index].max_lane_mbps)
return;
testif_set_timing(dsi, 0x60, 0x3f, timing_table[index].clk_lp);
testif_set_timing(dsi, 0x61, 0x7f, timing_table[index].clk_hs_prepare);
testif_set_timing(dsi, 0x62, 0x3f, timing_table[index].clk_hs_zero);
testif_set_timing(dsi, 0x63, 0x7f, timing_table[index].clk_hs_trail);
testif_set_timing(dsi, 0x65, 0x0f, timing_table[index].clk_post);
testif_set_timing(dsi, 0x70, 0x3f, timing_table[index].data_lp);
testif_set_timing(dsi, 0x71, 0x7f, timing_table[index].data_hs_prepare);
testif_set_timing(dsi, 0x72, 0x3f, timing_table[index].data_hs_zero);
testif_set_timing(dsi, 0x73, 0x7f, timing_table[index].data_hs_trail);
}
static void mipi_dphy_init(struct rk628 *rk628, const struct rk628_dsi *dsi)
{
const struct {
@@ -960,7 +1027,7 @@ static void mipi_dphy_init(struct rk628 *rk628, const struct rk628_dsi *dsi)
unsigned int index;
for (index = 0; index < ARRAY_SIZE(hsfreqrange_table); index++)
if (lane_mbps <= hsfreqrange_table[index].max_lane_mbps)
if (dsi->lane_mbps <= hsfreqrange_table[index].max_lane_mbps)
break;
if (index == ARRAY_SIZE(hsfreqrange_table))
@@ -968,6 +1035,9 @@ static void mipi_dphy_init(struct rk628 *rk628, const struct rk628_dsi *dsi)
hsfreqrange = hsfreqrange_table[index].hsfreqrange;
testif_write(rk628, dsi, 0x44, HSFREQRANGE(hsfreqrange));
if (rk628->version == RK628F_VERSION)
mipi_dphy_set_timing(dsi);
}
static void mipi_dphy_power_on(struct rk628 *rk628, const struct rk628_dsi *dsi)
@@ -1024,35 +1094,35 @@ static void mipi_dphy_power_on(struct rk628 *rk628, const struct rk628_dsi *dsi)
udelay(10);
}
void rk628_dsi0_reset_control_assert(struct rk628 *rk628)
static void rk628_dsi0_reset_control_assert(struct rk628 *rk628)
{
rk628_i2c_write(rk628, CRU_SOFTRST_CON02, 0x400040);
}
void rk628_dsi0_reset_control_deassert(struct rk628 *rk628)
static void rk628_dsi0_reset_control_deassert(struct rk628 *rk628)
{
rk628_i2c_write(rk628, CRU_SOFTRST_CON02, 0x400000);
}
void rk628_dsi1_reset_control_assert(struct rk628 *rk628)
static void rk628_dsi1_reset_control_assert(struct rk628 *rk628)
{
rk628_i2c_write(rk628, CRU_SOFTRST_CON02, 0x800080);
}
void rk628_dsi1_reset_control_deassert(struct rk628 *rk628)
static void rk628_dsi1_reset_control_deassert(struct rk628 *rk628)
{
rk628_i2c_write(rk628, CRU_SOFTRST_CON02, 0x800000);
}
void rk628_dsi_bridge_pre_enable(struct rk628 *rk628,
const struct rk628_dsi *dsi)
static void rk628_dsi_bridge_pre_enable(struct rk628 *rk628,
const struct rk628_dsi *dsi)
{
u32 val;
dsi_write(rk628, dsi, DSI_PWR_UP, RESET);
dsi_write(rk628, dsi, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
val = DIV_ROUND_UP(lane_mbps >> 3, 20);
val = DIV_ROUND_UP(dsi->lane_mbps >> 3, 20);
dsi_write(rk628, dsi, DSI_CLKMGR_CFG,
TO_CLK_DIVISION(10) | TX_ESC_CLK_DIVISION(val));
@@ -1082,7 +1152,7 @@ static void rk628_dsi_set_vid_mode(struct rk628 *rk628,
const struct rk628_dsi *dsi,
const struct rk628_display_mode *mode)
{
unsigned int lanebyteclk = (lane_mbps * 1000L) >> 3;
unsigned int lanebyteclk = (dsi->lane_mbps * 1000L) >> 3;
unsigned int dpipclk = mode->clock;
u32 hline, hsa, hbp, hline_time, hsa_time, hbp_time;
u32 vactive, vsa, vfp, vbp;
@@ -1149,9 +1219,22 @@ static void rk628_dsi_set_cmd_mode(struct rk628 *rk628,
const struct rk628_dsi *dsi,
const struct rk628_display_mode *mode)
{
int cmd_size;
dsi_update_bits(rk628, dsi, DSI_CMD_MODE_CFG, DCS_LW_TX, 0);
dsi_write(rk628, dsi, DSI_EDPI_CMD_SIZE,
EDPI_ALLOWED_CMD_SIZE(mode->hdisplay));
/* rk628: The maximum capacity of dsi memory is 2048*32 bits */
if (mode->hdisplay > 2048)
cmd_size = EDPI_ALLOWED_CMD_SIZE(mode->hdisplay / 2);
else
cmd_size = EDPI_ALLOWED_CMD_SIZE(mode->hdisplay);
dsi_write(rk628, dsi, DSI_EDPI_CMD_SIZE, cmd_size);
if (dsi->mode_flags & MIPI_DSI_CLOCK_NON_CONTINUOUS)
dsi_update_bits(rk628, dsi, DSI_LPCLK_CTRL,
AUTO_CLKLANE_CTRL, AUTO_CLKLANE_CTRL);
dsi_write(rk628, dsi, DSI_MODE_CFG, CMD_VIDEO_MODE(COMMAND_MODE));
}
@@ -1204,15 +1287,86 @@ static void rk628_dsi_bridge_enable(struct rk628 *rk628,
dsi_write(rk628, dsi, DSI_PWR_UP, POWER_UP);
}
static int rk628_dsi_color_bar_show(struct seq_file *s, void *data)
{
seq_puts(s, " Enable color bar:\n");
seq_puts(s, " example: echo 1 > /sys/kernel/debug/rk628/2-0050/dsi_color_bar\n");
seq_puts(s, " Disable color bar:\n");
seq_puts(s, " example: echo 0 > /sys/kernel/debug/rk628/2-0050/dsi_color_bar\n");
return 0;
}
static int rk628_dsi_color_bar_open(struct inode *inode, struct file *file)
{
return single_open(file, rk628_dsi_color_bar_show, inode->i_private);
}
static ssize_t rk628_dsi_color_bar_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct rk628 *rk628 = ((struct seq_file *)file->private_data)->private;
struct rk628_dsi *dsi = &rk628->dsi0;
struct rk628_dsi *dsi1 = &rk628->dsi1;
u8 mode;
if (kstrtou8_from_user(ubuf, len, 0, &mode))
return -EFAULT;
dsi_update_bits(rk628, dsi, DSI_VID_MODE_CFG, VPG_EN, mode ? VPG_EN : 0);
if (!mode) {
dsi_write(rk628, dsi, DSI_PWR_UP, RESET);
dsi_write(rk628, dsi, DSI_PWR_UP, POWER_UP);
}
if (dsi->slave) {
dsi_update_bits(rk628, dsi1, DSI_VID_MODE_CFG, VPG_EN, mode ? VPG_EN : 0);
if (!mode) {
dsi_write(rk628, dsi1, DSI_PWR_UP, RESET);
dsi_write(rk628, dsi1, DSI_PWR_UP, POWER_UP);
}
}
return len;
}
static const struct file_operations rk628_dsi_color_bar_fops = {
.owner = THIS_MODULE,
.open = rk628_dsi_color_bar_open,
.read = seq_read,
.write = rk628_dsi_color_bar_write,
.llseek = seq_lseek,
.release = single_release,
};
void rk628_mipi_dsi_create_debugfs_file(struct rk628 *rk628)
{
if (rk628_output_is_dsi(rk628))
debugfs_create_file("dsi_color_bar", 0600, rk628->debug_dir,
rk628, &rk628_dsi_color_bar_fops);
}
void rk628_mipi_dsi_pre_enable(struct rk628 *rk628)
{
const struct rk628_dsi *dsi = &rk628->dsi0;
const struct rk628_dsi *dsi1 = &rk628->dsi1;
struct rk628_dsi *dsi = &rk628->dsi0;
struct rk628_dsi *dsi1 = &rk628->dsi1;
u32 rate = rk628_dsi_get_lane_rate(dsi);
int bus_width;
u32 mask = SW_OUTPUT_MODE_MASK;
u32 val = SW_OUTPUT_MODE(OUTPUT_MODE_DSI);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_DSI));
if (rk628->version == RK628F_VERSION) {
mask = SW_OUTPUT_COMBTX_MODE_MASK;
val = SW_OUTPUT_COMBTX_MODE(OUTPUT_MODE_DSI - 2);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON3,
GRF_DPHY_CH1_EN_MASK |
GRF_AS_DSIPHY_MASK,
(dsi->slave ? GRF_DPHY_CH1_EN(1) : 0) |
GRF_AS_DSIPHY(1));
}
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_SPLIT_EN,
dsi->slave ? SW_SPLIT_EN : 0);
@@ -1226,10 +1380,10 @@ void rk628_mipi_dsi_pre_enable(struct rk628 *rk628)
rk628_combtxphy_set_bus_width(rk628, bus_width);
rk628_combtxphy_set_mode(rk628, PHY_MODE_VIDEO_MIPI);
lane_mbps = rk628_combtxphy_get_bus_width(rk628);
dsi->lane_mbps = rk628_combtxphy_get_bus_width(rk628);
if (dsi->slave)
lane_mbps = rk628_combtxphy_get_bus_width(rk628);
if (dsi->slave && dsi1)
dsi1->lane_mbps = rk628_combtxphy_get_bus_width(rk628);
/* rst for dsi0 */
rk628_dsi0_reset_control_assert(rk628);
@@ -1262,7 +1416,7 @@ void rk628_mipi_dsi_pre_enable(struct rk628 *rk628)
#endif
dev_info(rk628->dev, "rk628_dsi final DSI-Link bandwidth: %d x %d\n",
lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes);
dsi->lane_mbps, dsi->slave ? dsi->lanes * 2 : dsi->lanes);
}
void rk628_mipi_dsi_enable(struct rk628 *rk628)

View File

@@ -155,4 +155,5 @@ int rk628_dsi_parse(struct rk628 *rk628, struct device_node *dsi_np);
void rk628_mipi_dsi_pre_enable(struct rk628 *rk628);
void rk628_mipi_dsi_enable(struct rk628 *rk628);
void rk628_dsi_disable(struct rk628 *rk628);
void rk628_mipi_dsi_create_debugfs_file(struct rk628 *rk628);
#endif

View File

@@ -0,0 +1,163 @@
// SPDX-License-Identifier: GPL-2.0
/*
* RK628 eFuse Driver
*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Weixin Zhou <zwx@rock-chips.com>
*/
#include <linux/gpio/consumer.h>
#include "rk628.h"
#define EFUSE_SIZE 64
#define T_CSB_P_S 0
#define T_PGENB_P_S (15 + 200)
#define T_LOAD_P_S 0
#define T_ADDR_P_S (15 + 200 + 5)
#define T_STROBE_P_S ((150 + 2000 + 100) / 9)
#define T_CSB_P_L 0
#define T_PGENB_P_L (15 + 200 + 10 + 200 + 190 + 10)
#define T_LOAD_P_L (15 + 200 + 200 + 190 + 10 + 100 + 15)
#define T_ADDR_P_L (15 + 200 + 5 + 200 + 5)
#define T_STROBE_P_L ((150 + 2000 + 100 + 2000) / 9)
#define T_CSB_R_S 0
#define T_PGENB_R_S 0
#define T_LOAD_R_S 15
#define T_ADDR_R_S (15 + 9)
#define T_STROBE_R_S ((150 + 100) / 9)
#define T_CSB_R_L 0
#define T_PGENB_R_L 0
#define T_LOAD_R_L (15 + 5 + 5 + 10 + 15)
#define T_ADDR_R_L (15 + 10 + 5 + 1)
#define T_STROBE_R_L ((150 + 100 + 50) / 8)
#define T_CSB_P 0x28
#define T_PGENB_P 0x2c
#define T_LOAD_P 0x30
#define T_ADDR_P 0x34
#define T_STROBE_P 0x38
#define T_CSB_R 0x3c
#define T_PGENB_R 0x40
#define T_LOAD_R 0x44
#define T_ADDR_R 0x48
#define T_STROBE_R 0x4c
#define RK628_EFUSE_BASE 0xb0000
#define RK628_MOD 0x00
#define RK628_INT_STATUS 0x0018
#define RK628_DOUT 0x0020
#define RK628_AUTO_CTRL 0x0024
#define RK628_USER_MODE BIT(0)
#define RK628_INT_FINISH BIT(0)
#define RK628_AUTO_ENB BIT(0)
#define RK628_AUTO_RD BIT(1)
#define RK628_ADDR_ROW 16
#define RK628_ADDR_COL 22
#define RK628_A_SHIFT 16
#define RK628_A_MASK 0x3ff
#define RK628_NBYTES 1
#define REG_EFUSE_CTRL 0x0000
#define REG_EFUSE_DOUT 0x0004
static inline u32 rk628_read(struct rk628 *rk628, u32 reg)
{
u32 val;
rk628_i2c_read(rk628, reg, &val);
return val;
}
static inline void rk628_write(struct rk628 *rk628, u32 val, u32 reg)
{
rk628_i2c_write(rk628, reg, val);
}
static inline void rk628_efuse_timing_init(struct rk628 *rk628)
{
u32 base = RK628_EFUSE_BASE;
/* enable auto mode */
rk628_write(rk628, rk628_read(rk628, base + RK628_MOD)
& (~RK628_USER_MODE), base + RK628_MOD);
/* setup efuse timing */
rk628_write(rk628, (T_CSB_P_S << 16) | T_CSB_P_L, base + T_CSB_P);
rk628_write(rk628, (T_PGENB_P_S << 16) | T_PGENB_P_L, base + T_PGENB_P);
rk628_write(rk628, (T_LOAD_P_S << 16) | T_LOAD_P_L, base + T_LOAD_P);
rk628_write(rk628, (T_ADDR_P_S << 16) | T_ADDR_P_L, base + T_ADDR_P);
rk628_write(rk628, (T_STROBE_P_S << 16) | T_STROBE_P_L, base + T_STROBE_P);
rk628_write(rk628, (T_CSB_R_S << 16) | T_CSB_R_L, base + T_CSB_R);
rk628_write(rk628, (T_PGENB_R_S << 16) | T_PGENB_R_L, base + T_PGENB_R);
rk628_write(rk628, (T_LOAD_R_S << 16) | T_LOAD_R_L, base + T_LOAD_R);
rk628_write(rk628, (T_ADDR_R_S << 16) | T_ADDR_R_L, base + T_ADDR_R);
rk628_write(rk628, (T_STROBE_R_S << 16) | T_STROBE_R_L, base + T_STROBE_R);
}
static inline void rk628_efuse_timing_deinit(struct rk628 *rk628)
{
u32 base = RK628_EFUSE_BASE;
/* disable auto mode */
rk628_write(rk628, rk628_read(rk628, base + RK628_MOD)
| RK628_USER_MODE, base + RK628_MOD);
/* clear efuse timing */
rk628_write(rk628, 0, base + T_CSB_P);
rk628_write(rk628, 0, base + T_PGENB_P);
rk628_write(rk628, 0, base + T_LOAD_P);
rk628_write(rk628, 0, base + T_ADDR_P);
rk628_write(rk628, 0, base + T_STROBE_P);
rk628_write(rk628, 0, base + T_CSB_R);
rk628_write(rk628, 0, base + T_PGENB_R);
rk628_write(rk628, 0, base + T_LOAD_R);
rk628_write(rk628, 0, base + T_ADDR_R);
rk628_write(rk628, 0, base + T_STROBE_R);
}
int rk628_efuse_read(struct rk628 *rk628, unsigned int offset,
void *val, size_t bytes)
{
unsigned int addr_start, addr_end, addr_offset, addr_len;
u32 out_value, status;
u8 *buf;
int ret = 0, i = 0;
addr_start = rounddown(offset, RK628_NBYTES) / RK628_NBYTES;
addr_end = roundup(offset + bytes, RK628_NBYTES) / RK628_NBYTES;
addr_offset = offset % RK628_NBYTES;
addr_len = addr_end - addr_start;
if (addr_len == 0 || addr_len > EFUSE_SIZE)
return -EINVAL;
buf = kzalloc(sizeof(*buf) * addr_len * RK628_NBYTES, GFP_KERNEL);
if (!buf)
return -ENOMEM;
rk628_efuse_timing_init(rk628);
while (addr_len--) {
rk628_write(rk628, RK628_AUTO_RD | RK628_AUTO_ENB |
((addr_start++ & RK628_A_MASK) << RK628_A_SHIFT),
RK628_EFUSE_BASE + RK628_AUTO_CTRL);
udelay(2);
status = rk628_read(rk628, RK628_EFUSE_BASE + RK628_INT_STATUS);
if (!(status & RK628_INT_FINISH)) {
ret = -EIO;
goto err;
}
out_value = rk628_read(rk628, RK628_EFUSE_BASE + RK628_DOUT);
rk628_write(rk628, RK628_INT_FINISH, RK628_EFUSE_BASE + RK628_INT_STATUS);
memcpy(&buf[i], &out_value, RK628_NBYTES);
i += RK628_NBYTES;
}
memcpy(val, buf + addr_offset, bytes);
err:
rk628_efuse_timing_deinit(rk628);
kfree(buf);
return ret;
}

View File

@@ -0,0 +1,17 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* Copyright (c) 2020 Rockchip Electronics Co. Ltd.
*
* Author: Weixin Zhou <zwx@rock-chips.com>
*/
#ifndef RK628_EFUSE_H
#define RK628_EFUSE_H
#define EFUSE_BASE 0xb0000
#define EFUSE_REVISION 0x50
int rk628_efuse_read(struct rk628 *rk628, unsigned int offset,
void *val, size_t bytes);
#endif

View File

@@ -5,6 +5,7 @@
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include <linux/debugfs.h>
#include "linux/printk.h"
#include "rk628.h"
#include "rk628_config.h"
@@ -12,6 +13,8 @@
#include "rk628_gvi.h"
#include "panel.h"
#define GVI_RETRY_TIMEOUT 10
int rk628_gvi_parse(struct rk628 *rk628, struct device_node *gvi_np)
{
const char *string;
@@ -21,8 +24,6 @@ int rk628_gvi_parse(struct rk628 *rk628, struct device_node *gvi_np)
if (!of_device_is_available(gvi_np))
return -EINVAL;
rk628->output_mode = OUTPUT_MODE_GVI;
if (!of_property_read_u32(gvi_np, "gvi,lanes", &val))
rk628->gvi.lanes = val;
@@ -89,10 +90,17 @@ static void rk628_gvi_get_info(struct rk628_gvi *gvi)
static unsigned int rk628_gvi_get_lane_rate(struct rk628 *rk628)
{
const struct rk628_display_mode *mode = &rk628->dst_mode;
struct rk628_gvi *gvi = &rk628->gvi;
u32 lane_bit_rate, min_lane_rate = 500000, max_lane_rate = 4000000;
u64 total_bw;
struct rk628_display_mode *src = &rk628->src_mode;
const struct rk628_display_mode *dst = &rk628->dst_mode;
u64 dst_rate, src_rate;
src_rate = src->clock * 1000;
dst_rate = src_rate * dst->vtotal * dst->htotal;
do_div(dst_rate, (src->vtotal * src->htotal));
do_div(dst_rate, 1000);
/**
* [ENCODER TOTAL BIT-RATE](bps) = [byte mode](byte) x 10 / [pixel clock](HZ)
@@ -101,7 +109,7 @@ static unsigned int rk628_gvi_get_lane_rate(struct rk628 *rk628)
*
* 500Mbps <= lane_bit_rate <= 4Gbps
*/
total_bw = (u64)gvi->byte_mode * 10 * mode->clock;/* Kbps */
total_bw = (u64)gvi->byte_mode * 10 * dst_rate;/* Kbps */
do_div(total_bw, gvi->lanes);
lane_bit_rate = total_bw;
@@ -122,6 +130,8 @@ static void rk628_gvi_pre_enable(struct rk628 *rk628, struct rk628_gvi *gvi)
rk628_i2c_update_bits(rk628, GVI_SYS_RST, SYS_RST_SOFT_RST, 0);
udelay(10);
rk628_i2c_write(rk628, GRF_SCALER_CON0, SCL_8_PIXEL_ALIGN(1));
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_LANE_NUM_MASK,
SYS_CTRL0_LANE_NUM(gvi->lanes - 1));
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_BYTE_MODE_MASK,
@@ -137,6 +147,9 @@ static void rk628_gvi_pre_enable(struct rk628 *rk628, struct rk628_gvi *gvi)
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL0, SYS_CTRL0_FRM_RST_EN,
gvi->frm_rst ? SYS_CTRL0_FRM_RST_EN : 0);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL1, SYS_CTRL1_LANE_ALIGN_EN, 0);
rk628_i2c_update_bits(rk628, GVI_SYS_CTRL1, SYS_CTRL1_COLOR_DEPTH_MASK,
SYS_CTRL1_COLOR_DEPTH(gvi->color_depth));
}
static void rk628_gvi_enable_color_bar(struct rk628 *rk628,
@@ -183,6 +196,50 @@ static void rk628_gvi_enable_color_bar(struct rk628 *rk628,
rk628_i2c_update_bits(rk628, GVI_COLOR_BAR_CTRL, COLOR_BAR_EN, 0);
}
static int rk628_gvi_color_bar_show(struct seq_file *s, void *data)
{
seq_puts(s, " Enable color bar:\n");
seq_puts(s, " example: echo 1 > /sys/kernel/debug/rk628/2-0050/gvi_color_bar\n");
seq_puts(s, " Disable color bar:\n");
seq_puts(s, " example: echo 0 > /sys/kernel/debug/rk628/2-0050/gvi_color_bar\n");
return 0;
}
static int rk628_gvi_color_bar_open(struct inode *inode, struct file *file)
{
return single_open(file, rk628_gvi_color_bar_show, inode->i_private);
}
static ssize_t rk628_gvi_color_bar_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct rk628 *rk628 = ((struct seq_file *)file->private_data)->private;
u8 mode;
if (kstrtou8_from_user(ubuf, len, 0, &mode))
return -EFAULT;
rk628_i2c_update_bits(rk628, GVI_COLOR_BAR_CTRL, COLOR_BAR_EN, mode ? 1 : 0);
return len;
}
static const struct file_operations rk628_gvi_color_bar_fops = {
.owner = THIS_MODULE,
.open = rk628_gvi_color_bar_open,
.read = seq_read,
.write = rk628_gvi_color_bar_write,
.llseek = seq_lseek,
.release = single_release,
};
void rk628_gvi_create_debugfs_file(struct rk628 *rk628)
{
if (rk628_output_is_gvi(rk628))
debugfs_create_file("gvi_color_bar", 0600, rk628->debug_dir,
rk628, &rk628_gvi_color_bar_fops);
}
static void rk628_gvi_post_enable(struct rk628 *rk628, struct rk628_gvi *gvi)
{
@@ -196,14 +253,22 @@ void rk628_gvi_enable(struct rk628 *rk628)
{
struct rk628_gvi *gvi = &rk628->gvi;
unsigned int rate;
u32 mask = SW_OUTPUT_MODE_MASK;
u32 val = SW_OUTPUT_MODE(OUTPUT_MODE_GVI);
int i = 0;
rk628_gvi_get_info(gvi);
rate = rk628_gvi_get_lane_rate(rk628);
/* set gvi_hpd and gvi_lock mux */
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x06000600);
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_GVI));
if (rk628->version == RK628F_VERSION) {
mask = SW_OUTPUT_COMBTX_MODE_MASK;
val = SW_OUTPUT_COMBTX_MODE(OUTPUT_MODE_GVI);
}
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
rk628_combtxphy_set_bus_width(rk628, rate);
rk628_combtxphy_set_gvi_division_mode(rk628, gvi->division_mode);
rk628_combtxphy_set_mode(rk628, PHY_MODE_VIDEO_GVI);
@@ -213,7 +278,30 @@ void rk628_gvi_enable(struct rk628 *rk628)
rk628_panel_prepare(rk628);
rk628_gvi_enable_color_bar(rk628, gvi);
rk628_gvi_post_enable(rk628, gvi);
for (i = 0; i < 100; i++) {
rk628_i2c_read(rk628, GVI_STATUS, &val);
if ((val & GVI_LOCKED_MASK) == GVI_LOCKED_STATUS)
break;
usleep_range(1000, 1100);
}
if (i == 100 && gvi->retry_times < GVI_RETRY_TIMEOUT) {
dev_info(rk628->dev, "GVI Lock failed: 0x%x, try again: %d\n", val, gvi->retry_times);
gvi->retry_times++;
rk628_gvi_disable(rk628);
usleep_range(50000, 51000);
rk628_gvi_enable(rk628);
}
if (gvi->retry_times >= GVI_RETRY_TIMEOUT && i == 100) {
dev_info(rk628->dev, "GVI Lock failed, please check hardware!\n");
return;
}
rk628_panel_enable(rk628);
if (i != 100)
gvi->retry_times = 0;
dev_info(rk628->dev,
"GVI-Link bandwidth: %d x %d Mbps, Byte mode: %d, Color Depty: %d, %s division mode\n",
rate, gvi->lanes, gvi->byte_mode, gvi->color_depth,

View File

@@ -20,6 +20,8 @@
#define GVI_SYS_RST HOSTREG(0x0014)
#define GVI_LINE_FLAG HOSTREG(0x0018)
#define GVI_STATUS HOSTREG(0x001c)
#define GVI_LOCKED_MASK 0x70
#define GVI_LOCKED_STATUS 0x40
#define GVI_PLL_LOCK_TIMEOUT HOSTREG(0x0030)
#define GVI_HTPDN_TIMEOUT HOSTREG(0x0034)
#define GVI_LOCKN_TIMEOUT HOSTREG(0x0038)
@@ -214,5 +216,5 @@
int rk628_gvi_parse(struct rk628 *rk628, struct device_node *gvi_np);
void rk628_gvi_enable(struct rk628 *rk628);
void rk628_gvi_disable(struct rk628 *rk628);
void rk628_gvi_create_debugfs_file(struct rk628 *rk628);
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -427,6 +427,7 @@
#define MILISECTIMERLIMIT(x) UPDATE(x, 15, 0)
#define HDMI_RX_HDCP22_CONTROL HDMIRX_REG(0x081c)
#define HDMI_RX_SCDC_REGS0 HDMIRX_REG(0x0820)
#define SCDC_TMDSBITCLKRATIO BIT(17)
#define HDMI_RX_SCDC_REGS1 HDMIRX_REG(0x0824)
#define HDMI_RX_SCDC_REGS2 HDMIRX_REG(0x0828)
#define HDMI_RX_SCDC_REGS3 HDMIRX_REG(0x082c)
@@ -482,6 +483,11 @@
#define HDMI_RX_AUD_CEC_ISET HDMIRX_REG(0x0fa4)
#define HDMI_RX_AUD_FIFO_IEN_CLR HDMIRX_REG(0x0fa8)
#define HDMI_RX_AUD_FIFO_IEN_SET HDMIRX_REG(0x0fac)
#define AFIF_OVERFL_ISTS BIT(4)
#define AFIF_UNDERFL_ISTS BIT(3)
#define AFIF_THS_PASS_ISTS BIT(2)
#define AFIF_TH_MAX_ISTS BIT(1)
#define AFIF_TH_MIN_ISTS BIT(0)
#define HDMI_RX_AUD_FIFO_ISTS HDMIRX_REG(0x0fb0)
#define HDMI_RX_AUD_FIFO_IEN HDMIRX_REG(0x0fb4)
#define HDMI_RX_AUD_FIFO_ICLR HDMIRX_REG(0x0fb8)

View File

@@ -462,6 +462,7 @@ static int rk628_hdmi_config_video_timing(struct rk628_hdmi *hdmi,
struct drm_display_mode *mode)
{
int value;
u32 hdmitx_sync_pol = 0;
/* Set detail external video timing polarity and interlace mode */
value = EXTERANL_VIDEO(1);
@@ -472,6 +473,12 @@ static int rk628_hdmi_config_video_timing(struct rk628_hdmi *hdmi,
value |= mode->flags & DRM_MODE_FLAG_INTERLACE ?
INETLACE(1) : INETLACE(0);
hdmi_writeb(hdmi, HDMI_VIDEO_TIMING_CTL, value);
hdmitx_sync_pol |= mode->flags & DRM_MODE_FLAG_PVSYNC ?
SW_HDMITX_VSYNC_POL : 0;
hdmitx_sync_pol |= mode->flags & DRM_MODE_FLAG_PHSYNC ?
SW_HDMITX_HSYNC_POL : 0;
rk628_i2c_update_bits(hdmi->rk628, GRF_POST_PROC_CON,
SW_HDMITX_VSYNC_POL | SW_HDMITX_HSYNC_POL, hdmitx_sync_pol);
/* Set detail external video timing */
value = mode->htotal;
@@ -604,7 +611,12 @@ static int rk628_hdmi_connector_get_modes(struct drm_connector *connector)
ret = rockchip_drm_add_modes_noedid(connector);
#if KERNEL_VERSION(5, 18, 0) <= LINUX_VERSION_CODE
info->edid_hdmi_ycbcr444_dc_modes = 0;
info->edid_hdmi_rgb444_dc_modes = 0;
#else
info->edid_hdmi_dc_modes = 0;
#endif
info->hdmi.y420_dc_modes = 0;
info->color_formats = 0;
@@ -709,13 +721,6 @@ static void rk628_hdmi_bridge_enable(struct drm_bridge *bridge)
rk628_hdmi_set_pwr_mode(hdmi, NORMAL);
}
static void rk628_hdmi_bridge_disable(struct drm_bridge *bridge)
{
struct rk628_hdmi *hdmi = bridge_to_hdmi(bridge);
rk628_hdmi_set_pwr_mode(hdmi, LOWER_PWR);
}
static int rk628_hdmi_bridge_attach(struct drm_bridge *bridge,
enum drm_bridge_attach_flags flags)
{
@@ -760,7 +765,6 @@ static const struct drm_bridge_funcs rk628_hdmi_bridge_funcs = {
.mode_set = rk628_hdmi_bridge_mode_set,
.mode_fixup = rk628_hdmi_bridge_mode_fixup,
.enable = rk628_hdmi_bridge_enable,
.disable = rk628_hdmi_bridge_disable,
};
static int
@@ -1091,13 +1095,127 @@ static struct i2c_adapter *rk628_hdmi_i2c_adapter(struct rk628_hdmi *hdmi)
return adap;
}
static int rk628_hdmitx_color_bar_show(struct seq_file *s, void *data)
{
seq_puts(s, " Enable normal color bar:\n");
seq_puts(s, " example: echo 1 > /sys/kernel/debug/rk628/2-0050/hdmitx_color_bar\n");
seq_puts(s, " Enable special color bar:\n");
seq_puts(s, " example: echo 2 > /sys/kernel/debug/rk628/2-0050/hdmitx_color_bar\n");
seq_puts(s, " Enable black color bar:\n");
seq_puts(s, " example: echo 3 > /sys/kernel/debug/rk628/2-0050/hdmitx_color_bar\n");
seq_puts(s, " Disable color bar:\n");
seq_puts(s, " example: echo 0 > /sys/kernel/debug/rk628/2-0050/hdmitx_color_bar\n");
return 0;
}
static int rk628_hdmitx_color_bar_open(struct inode *inode, struct file *file)
{
return single_open(file, rk628_hdmitx_color_bar_show, inode->i_private);
}
static ssize_t rk628_hdmitx_color_bar_write(struct file *file, const char __user *ubuf,
size_t len, loff_t *offp)
{
struct rk628 *rk628 = ((struct seq_file *)file->private_data)->private;
u8 mode;
if (kstrtou8_from_user(ubuf, len, 0, &mode))
return -EFAULT;
switch (mode) {
case 0:
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, DISABLE_COLORBAR_BIST_MASK,
DISABLE_COLORBAR_BIST(1));
break;
case 1:
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, DISABLE_COLORBAR_BIST_MASK,
DISABLE_COLORBAR_BIST(0));
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, VIDEO_BIST_MODE_MASK,
VIDEO_BIST_MODE(0));
break;
case 2:
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, DISABLE_COLORBAR_BIST_MASK,
DISABLE_COLORBAR_BIST(0));
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, VIDEO_BIST_MODE_MASK,
VIDEO_BIST_MODE(1));
break;
case 3:
default:
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, DISABLE_COLORBAR_BIST_MASK,
DISABLE_COLORBAR_BIST(0));
rk628_i2c_update_bits(rk628, HDMI_COLOR_BAR, VIDEO_BIST_MODE_MASK,
VIDEO_BIST_MODE(2));
}
return len;
}
static const struct file_operations rk628_hdmitx_color_bar_fops = {
.owner = THIS_MODULE,
.open = rk628_hdmitx_color_bar_open,
.read = seq_read,
.write = rk628_hdmitx_color_bar_write,
.llseek = seq_lseek,
.release = single_release,
};
void rk628_hdmitx_create_debugfs_file(struct rk628 *rk628)
{
if (rk628_output_is_hdmi(rk628))
debugfs_create_file("hdmitx_color_bar", 0600, rk628->debug_dir,
rk628, &rk628_hdmitx_color_bar_fops);
}
void rk628_hdmitx_disable(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, HDMI_SYS_CTRL, POWER_MASK, PWR_OFF(1));
rk628_i2c_write(rk628, HDMI_PHY_DRIVER, 0x00);
rk628_i2c_write(rk628, HDMI_PHY_PRE_EMPHASIS, 0x00);
rk628_i2c_write(rk628, HDMI_PHY_CHG_PWR, 0x00);
rk628_i2c_write(rk628, HDMI_PHY_SYS_CTL, 0x15);
}
int rk628_hdmitx_enable(struct rk628 *rk628)
{
struct device *dev = rk628->dev;
struct rk628_hdmi *hdmi;
u32 mask = SW_OUTPUT_MODE_MASK;
u32 val = SW_OUTPUT_MODE(OUTPUT_MODE_HDMI);
int irq;
int ret;
/* select int io function */
rk628_i2c_write(rk628, GRF_GPIO0AB_SEL_CON, 0x70007000);
rk628_i2c_write(rk628, GRF_GPIO0AB_SEL_CON, 0x055c055c);
/* hdmitx vclk pllref select Pin_vclk */
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_HDMITX_VCLK_PLLREF_SEL_MASK,
SW_HDMITX_VCLK_PLLREF_SEL(1));
if (rk628->version == RK628F_VERSION) {
mask = SW_HDMITX_EN_MASK;
val = SW_HDMITX_EN(1);
}
/* set output mode to HDMI */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
/* hdmitx int en */
rk628_i2c_write(rk628, GRF_INTR0_EN, 0x00040004);
if (rk628->hdmitx) {
hdmi = rk628->hdmitx;
rk628_hdmi_reset(hdmi);
rk628_hdmi_i2c_init(hdmi);
/* Unmute hotplug interrupt */
hdmi_modb(hdmi, HDMI_STATUS, MASK_INT_HOTPLUG_MASK,
MASK_INT_HOTPLUG(1));
return 0;
}
if (!of_device_is_available(dev->of_node))
return -ENODEV;
@@ -1108,24 +1226,13 @@ int rk628_hdmitx_enable(struct rk628 *rk628)
hdmi->dev = dev;
hdmi->rk628 = rk628;
rk628->hdmitx = hdmi;
irq = rk628->client->irq;
if (irq < 0)
return irq;
dev_set_drvdata(dev, hdmi);
/* selete int io function */
rk628_i2c_write(rk628, GRF_GPIO0AB_SEL_CON, 0x70007000);
rk628_i2c_write(rk628, GRF_GPIO0AB_SEL_CON, 0x055c055c);
/* hdmitx vclk pllref select Pin_vclk */
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_HDMITX_VCLK_PLLREF_SEL_MASK,
SW_HDMITX_VCLK_PLLREF_SEL(1));
/* set output mode to HDMI */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_HDMI));
rk628_hdmi_reset(hdmi);
hdmi->ddc = rk628_hdmi_i2c_adapter(hdmi);
@@ -1142,9 +1249,6 @@ int rk628_hdmitx_enable(struct rk628 *rk628)
* and reconfigure the DDC clock.
*/
hdmi->tmds_rate = 24000 * 1000;
/* hdmitx int en */
rk628_i2c_write(rk628, GRF_INTR0_EN, 0x00040004);
rk628_hdmi_i2c_init(hdmi);
rk628_hdmi_audio_codec_init(hdmi, dev);
@@ -1190,6 +1294,8 @@ int rk628_hdmitx_enable(struct rk628 *rk628)
return 0;
fail:
devm_kfree(dev, hdmi);
rk628->hdmitx = NULL;
return ret;
}

View File

@@ -342,9 +342,30 @@ enum {
#define HDMI_CEC_BUSFREETIME_L HDMITX_REG(0xdc)
#define HDMI_CEC_BUSFREETIME_H HDMITX_REG(0xdd)
#define HDMI_CEC_LOGICADDR HDMITX_REG(0xde)
#define HDMI_COLOR_BAR HDMITX_REG(0xc9)
#define VIDEO_BIST_MODE_MASK GENMASK(7, 6)
#define VIDEO_BIST_MODE(x) UPDATE(x, 7, 6)
#define DISABLE_COLORBAR_BIST_MASK BIT(4)
#define DISABLE_COLORBAR_BIST(x) UPDATE(x, 4, 4)
#define HDMI_MAX_REG HDMITX_REG(0xed)
#ifdef CONFIG_RK628_MISC_HDMITX
void rk628_hdmitx_disable(struct rk628 *rk628);
int rk628_hdmitx_enable(struct rk628 *rk628);
void rk628_hdmitx_create_debugfs_file(struct rk628 *rk628);
#else
static inline void rk628_hdmitx_disable(struct rk628 *rk628)
{
}
static inline int rk628_hdmitx_enable(struct rk628 *rk628)
{
return 0;
}
static inline void rk628_hdmitx_create_debugfs_file(struct rk628 *rk628)
{
}
#endif
#endif

View File

@@ -5,8 +5,9 @@
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include <linux/media-bus-format.h>
#include "rk628.h"
#include "rk628_lvds.h"
#include "rk628_combtxphy.h"
#include "rk628_config.h"
#include "panel.h"
@@ -24,14 +25,13 @@ static inline void lvds_update_bits(struct rk628 *rk628, u32 reg,
int rk628_lvds_parse(struct rk628 *rk628, struct device_node *lvds_np)
{
const char *string;
const char *string = NULL;
int ret;
u32 bus_format;
if (!of_device_is_available(lvds_np))
return -EINVAL;
rk628->output_mode = OUTPUT_MODE_LVDS;
if (!of_property_read_string(lvds_np, "bus-format", &string)) {
if (!strcmp(string, "jeida_24"))
rk628->lvds.format = LVDS_FORMAT_JEIDA_24BIT;
@@ -42,6 +42,24 @@ int rk628_lvds_parse(struct rk628 *rk628, struct device_node *lvds_np)
else
rk628->lvds.format = LVDS_FORMAT_VESA_24BIT;
}
/* fallback to u32 type */
if (!string || strlen(string) == 0) {
if (!of_property_read_u32(lvds_np, "bus-format", &bus_format)) {
switch (bus_format) {
case MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA:
rk628->lvds.format = LVDS_FORMAT_JEIDA_24BIT;
break;
case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
rk628->lvds.format = LVDS_FORMAT_JEIDA_18BIT;
break;
case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
rk628->lvds.format = LVDS_FORMAT_VESA_24BIT;
break;
default:
rk628->lvds.format = LVDS_FORMAT_VESA_18BIT;
}
}
}
if (!of_property_read_string(lvds_np, "link-type", &string)) {
if (!strcmp(string, "dual_link_odd_even_pixels"))
@@ -68,10 +86,17 @@ void rk628_lvds_enable(struct rk628 *rk628)
enum lvds_link_type link_type = rk628->lvds.link_type;
enum lvds_format format = rk628->lvds.format;
const struct rk628_display_mode *mode = &rk628->dst_mode;
u32 val, bus_width;
u32 val, mask, bus_width;
lvds_update_bits(rk628, GRF_SYSTEM_CON0, SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_LVDS));
mask = SW_OUTPUT_MODE_MASK;
val = SW_OUTPUT_MODE(OUTPUT_MODE_LVDS);
if (rk628->version == RK628F_VERSION) {
mask = SW_OUTPUT_COMBTX_MODE_MASK;
val = SW_OUTPUT_COMBTX_MODE(OUTPUT_MODE_LVDS);
}
lvds_update_bits(rk628, GRF_SYSTEM_CON0, mask, val);
switch (link_type) {
case LVDS_DUAL_LINK_ODD_EVEN_PIXELS:

File diff suppressed because it is too large Load Diff

View File

@@ -11,5 +11,5 @@
void rk628_post_process_init(struct rk628 *rk628);
void rk628_post_process_enable(struct rk628 *rk628);
void rk628_post_process_disable(struct rk628 *rk628);
void rk628_post_process_create_debugfs_file(struct rk628 *rk628);
#endif

View File

@@ -5,46 +5,185 @@
* Author: Guochun Huang <hero.huang@rock-chips.com>
*/
#include <linux/debugfs.h>
#include "rk628.h"
#include "rk628_cru.h"
#include "rk628_config.h"
#include "panel.h"
#include "rk628_rgb.h"
void rk628_rgb_decoder_enable(struct rk628 *rk628)
int rk628_rgb_parse(struct rk628 *rk628, struct device_node *rgb_np)
{
/* config sw_input_mode RGB */
int ret = 0;
rk628->rgb.vccio_rgb = devm_regulator_get_optional(rk628->dev, "vccio-rgb");
if (IS_ERR(rk628->rgb.vccio_rgb))
rk628->rgb.vccio_rgb = NULL;
if ((rk628_input_is_bt1120(rk628) || rk628_output_is_bt1120(rk628)) &&
of_property_read_bool(rk628->dev->of_node, "bt1120-dual-edge"))
rk628->rgb.bt1120_dual_edge = true;
if (rk628_output_is_bt1120(rk628) || rk628_output_is_rgb(rk628))
ret = rk628_panel_info_get(rk628, rgb_np);
return ret;
}
static int rk628_rgb_resolution_show(struct seq_file *s, void *data)
{
struct rk628 *rk628 = s->private;
u16 width = 0, height = 0;
u32 rgb_rx_eval_time, rgb_rx_clkrate;
u64 ref_clk, pixel_clk;
u32 val;
rk628_i2c_read(rk628, GRF_RGB_RX_DBG_MEAS0, &val);
rgb_rx_eval_time = (val & RGB_RX_EVAL_TIME_MASK) >> 16;
rk628_i2c_read(rk628, GRF_RGB_RX_DBG_MEAS2, &val);
rgb_rx_clkrate = val & RGB_RX_CLKRATE_MASK;
ref_clk = rk628_cru_clk_get_rate(rk628, CGU_CLK_IMODET);
pixel_clk = ref_clk * rgb_rx_clkrate / (rgb_rx_eval_time + 1);
if (rk628_input_is_rgb(rk628)) {
rk628_i2c_read(rk628, GRF_RGB_RX_DBG_MEAS4, &val);
height = (val >> 16) & 0xffff;
width = val & 0xffff;
} else if (rk628_input_is_bt1120(rk628)) {
rk628_i2c_read(rk628, GRF_SYSTEM_STATUS3, &val);
height = val & DECODER_1120_LAST_LINE_NUM_MASK;
rk628_i2c_read(rk628, GRF_SYSTEM_STATUS4, &val);
width = val & DECODER_1120_LAST_PIX_NUM_MASK;
}
seq_printf(s, "%dx%d pclk:%llu\n", width, height, pixel_clk);
return 0;
}
static int rk628_rgb_resolution_open(struct inode *inode, struct file *file)
{
return single_open(file, rk628_rgb_resolution_show, inode->i_private);
}
static const struct file_operations rk628_rgb_resolution_fops = {
.owner = THIS_MODULE,
.open = rk628_rgb_resolution_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
void rk628_rgb_decoder_create_debugfs_file(struct rk628 *rk628)
{
if (rk628->version == RK628D_VERSION)
return;
if (rk628_input_is_rgb(rk628) || rk628_input_is_bt1120(rk628))
debugfs_create_file("rgb_resolution", 0400, rk628->debug_dir,
rk628, &rk628_rgb_resolution_fops);
}
static void rk628_rgb_decoder_enable(struct rk628 *rk628)
{
/* config sw_input_mode RGB */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_INPUT_MODE_MASK,
SW_INPUT_MODE(INPUT_MODE_RGB));
if (rk628->version == RK628F_VERSION) {
rk628_i2c_update_bits(rk628, GRF_RGB_RX_DBG_MEAS0,
RGB_RX_MODET_EN | RGB_RX_DCLK_EN,
RGB_RX_MODET_EN | RGB_RX_DCLK_EN);
rk628_i2c_update_bits(rk628, GRF_RGB_RX_DBG_MEAS3,
RGB_RX_CNT_EN_MASK, RGB_RX_CNT_EN(1));
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
}
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
}
static void rk628_rgb_encoder_enable(struct rk628 *rk628)
{
int voltage = 0;
u32 d_strength, clk_strength;
u64 dclk_delay;
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_BT_DATA_OEN_MASK | SW_OUTPUT_RGB_MODE_MASK,
SW_OUTPUT_RGB_MODE(OUTPUT_MODE_RGB >> 3));
if (rk628->version != RK628F_VERSION)
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
/*
* Under the same drive strength and DCLK delay, the signal behaves
* differently under different voltage power domains. In order to
* center the eye diagram of the signal, have sufficient signal setup
* and hold time, and ensure that the signal does not overshoot, the
* drive strength and DCLK delay need to be set for the power domains
* of different voltages.
*/
if (rk628->rgb.vccio_rgb)
voltage = regulator_get_voltage(rk628->rgb.vccio_rgb);
switch (voltage) {
case 1800000:
d_strength = 3;
clk_strength = 3;
dclk_delay = 0x10000000;
break;
case 3300000:
d_strength = 1;
clk_strength = 2;
dclk_delay = 0x100000000;
break;
default:
d_strength = 1;
clk_strength = 2;
dclk_delay = 0x100000000;
}
/* rk628: modify IO drive strength for RGB */
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, 0xffff1011);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, 0x10001);
if (rk628->version == RK628F_VERSION)
d_strength = d_strength * 0x1111 | 0xffff0000;
else {
d_strength = 0xffff7777;
clk_strength = 7;
}
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, d_strength);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, d_strength);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, d_strength);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, d_strength);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, d_strength);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, d_strength);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, d_strength & 0xf0fff0ff);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, clk_strength | 0x000f0000);
/* rk628: modify DCLK delay for RGB */
if (rk628->version == RK628F_VERSION) {
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0,
dclk_delay & 0xffffffff);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1,
dclk_delay >> 32);
}
}
void rk628_rgb_encoder_enable(struct rk628 *rk628)
static void rk628_rgb_encoder_disable(struct rk628 *rk628)
{
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_RGB));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON, SW_DCLK_OUT_INV_EN,
SW_DCLK_OUT_INV_EN);
}
void rk628_rgb_encoder_disable(struct rk628 *rk628)
{
rk628_panel_disable(rk628);
rk628_panel_unprepare(rk628);
}
@@ -66,43 +205,90 @@ void rk628_rgb_tx_enable(struct rk628 *rk628)
void rk628_rgb_tx_disable(struct rk628 *rk628)
{
rk628_panel_disable(rk628);
rk628_panel_unprepare(rk628);
rk628_rgb_encoder_disable(rk628);
}
void rk628_bt1120_decoder_enable(struct rk628 *rk628)
static void rk628_bt1120_decoder_timing_cfg(struct rk628 *rk628)
{
u32 src_hsync_len, src_hback_porch, src_hfront_porch, src_hactive;
u32 src_vsync_len, src_vback_porch, src_vfront_porch, src_vactive;
u32 dsp_htotal, dsp_hs_end, dsp_hact_st;
u32 dsp_vtotal, dsp_vs_end, dsp_vact_st;
u32 dsp_hbor_st, dsp_vbor_st;
u16 bor_left = 0, bor_up = 0;
struct rk628_display_mode *src = &rk628->src_mode;
src_hactive = src->hdisplay;
src_hsync_len = src->hsync_end - src->hsync_start;
src_hback_porch = src->htotal - src->hsync_end;
src_hfront_porch = src->hsync_start - src->hdisplay;
src_vsync_len = src->vsync_end - src->vsync_start;
src_vback_porch = src->vtotal - src->vsync_end;
src_vfront_porch = src->vsync_start - src->vdisplay;
src_vactive = src->vdisplay;
dsp_htotal = src_hsync_len + src_hback_porch +
src_hactive + src_hfront_porch;
dsp_vtotal = src_vsync_len + src_vback_porch +
src_vactive + src_vfront_porch;
dsp_hs_end = src_hsync_len;
dsp_vs_end = src_vsync_len;
dsp_hbor_st = src_hsync_len + src_hback_porch;
dsp_vbor_st = src_vsync_len + src_vback_porch;
dsp_hact_st = dsp_hbor_st + bor_left;
dsp_vact_st = dsp_vbor_st + bor_up;
if (rk628->version == RK628F_VERSION)
rk628_i2c_update_bits(rk628, GRF_RGB_RX_DBG_MEAS0,
RGB_RX_MODET_EN | RGB_RX_DCLK_EN,
RGB_RX_MODET_EN | RGB_RX_DCLK_EN);
rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL0, BT1120_DSP_HS_END(dsp_hs_end) |
BT1120_DSP_HTOTAL(dsp_htotal));
rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL1, BT1120_DSP_HACT_ST(dsp_hact_st));
rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL2, BT1120_DSP_VS_END(dsp_vs_end) |
BT1120_DSP_VTOTAL(dsp_vtotal));
rk628_i2c_write(rk628, GRF_BT1120_TIMING_CTRL3, BT1120_DSP_VACT_ST(dsp_vact_st));
}
static void rk628_bt1120_decoder_enable(struct rk628 *rk628)
{
struct rk628_display_mode *mode = rk628_display_get_src_mode(rk628);
rk628_set_input_bus_format(rk628, BUS_FMT_YUV422);
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
/* rk628: modify IO drive strength for RGB */
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, 0xffff1011);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, 0x10001);
/* config sw_input_mode bt1120 */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0, SW_INPUT_MODE_MASK,
SW_INPUT_MODE(INPUT_MODE_BT1120));
if (rk628->version == RK628F_VERSION)
rk628_bt1120_decoder_timing_cfg(rk628);
/* operation resetn_bt1120dec */
rk628_i2c_write(rk628, CRU_SOFTRST_CON00, 0x10001000);
rk628_i2c_write(rk628, CRU_SOFTRST_CON00, 0x10000000);
rk628_cru_clk_set_rate(rk628, CGU_BT1120DEC, mode->clock * 1000);
#ifdef BT1120_DUAL_EDGE
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0,
DEC_DUALEDGE_EN, DEC_DUALEDGE_EN);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
#endif
if (rk628->rgb.bt1120_dual_edge) {
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON0,
DEC_DUALEDGE_EN, DEC_DUALEDGE_EN);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
} else {
if (rk628->version == RK628F_VERSION) {
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0,
0x10000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
}
}
rk628_i2c_update_bits(rk628, GRF_RGB_DEC_CON1, SW_SET_X_MASK,
SW_SET_X(mode->hdisplay));
@@ -118,38 +304,82 @@ void rk628_bt1120_decoder_enable(struct rk628 *rk628)
SW_CAP_EN_PSYNC | SW_CAP_EN_ASYNC | SW_PROGRESS_EN);
}
void rk628_bt1120_encoder_enable(struct rk628 *rk628)
static void rk628_bt1120_encoder_enable(struct rk628 *rk628)
{
u32 val = 0;
int voltage = 0;
u32 strength;
u64 dclk_delay;
rk628_set_output_bus_format(rk628, BUS_FMT_YUV422);
/* pinctrl for vop pin */
rk628_i2c_write(rk628, GRF_GPIO2AB_SEL_CON, 0xffffffff);
rk628_i2c_write(rk628, GRF_GPIO2C_SEL_CON, 0xffff5555);
rk628_i2c_write(rk628, GRF_GPIO3AB_SEL_CON, 0x10b010b);
/* rk628: modify IO drive strength for RGB */
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, 0xffff1111);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, 0xffff1011);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, 0x10001);
/* config sw_input_mode bt1120 */
rk628_i2c_update_bits(rk628, GRF_SYSTEM_CON0,
SW_BT_DATA_OEN_MASK | SW_OUTPUT_MODE_MASK,
SW_OUTPUT_MODE(OUTPUT_MODE_BT1120));
SW_BT_DATA_OEN_MASK | SW_OUTPUT_RGB_MODE_MASK,
SW_OUTPUT_RGB_MODE(OUTPUT_MODE_BT1120 >> 3));
rk628_i2c_write(rk628, GRF_CSC_CTRL_CON, SW_R2Y_EN(1));
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
if (rk628->version != RK628F_VERSION)
rk628_i2c_update_bits(rk628, GRF_POST_PROC_CON,
SW_DCLK_OUT_INV_EN, SW_DCLK_OUT_INV_EN);
/*
* Under the same drive strength and DCLK delay, the signal behaves
* differently under different voltage power domains. In order to
* center the eye diagram of the signal, have sufficient signal setup
* and hold time, and ensure that the signal does not overshoot, the
* drive strength and DCLK delay need to be set for the power domains
* of different voltages.
*/
if (rk628->rgb.vccio_rgb)
voltage = regulator_get_voltage(rk628->rgb.vccio_rgb);
switch (voltage) {
case 1800000:
strength = 3;
dclk_delay = 0x100000000;
break;
case 3300000:
strength = 1;
dclk_delay = 0x1000000000;
break;
default:
strength = 1;
dclk_delay = 0x1000000000;
}
/* rk628: modify IO drive strength for BT1120 */
if (rk628->version == RK628F_VERSION)
strength = strength * 0x1111 | 0xffff0000;
else
strength = 0xffff1111;
rk628_i2c_write(rk628, GRF_GPIO2A_D0_CON, strength);
rk628_i2c_write(rk628, GRF_GPIO2A_D1_CON, strength);
rk628_i2c_write(rk628, GRF_GPIO2B_D0_CON, strength);
rk628_i2c_write(rk628, GRF_GPIO2B_D1_CON, strength);
rk628_i2c_write(rk628, GRF_GPIO2C_D0_CON, strength);
rk628_i2c_write(rk628, GRF_GPIO2C_D1_CON, strength);
rk628_i2c_write(rk628, GRF_GPIO3A_D0_CON, strength & 0xf0fff0ff);
rk628_i2c_write(rk628, GRF_GPIO3B_D_CON, strength & 0x000f000f);
/* rk628: modify DCLK delay for BT1120 */
if (rk628->rgb.bt1120_dual_edge) {
val |= ENC_DUALEDGE_EN(1);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
} else {
if (rk628->version == RK628F_VERSION) {
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0,
dclk_delay & 0xffffffff);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1,
dclk_delay >> 32);
}
}
#ifdef BT1120_DUAL_EDGE
val |= ENC_DUALEDGE_EN(1);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON0, 0x10000000);
rk628_i2c_write(rk628, GRF_BT1120_DCLK_DELAY_CON1, 0);
#endif
val |= BT1120_UV_SWAP(1);
rk628_i2c_write(rk628, GRF_RGB_ENC_CON, val);
}
@@ -163,4 +393,3 @@ void rk628_bt1120_tx_enable(struct rk628 *rk628)
{
rk628_bt1120_encoder_enable(rk628);
}

View File

@@ -9,9 +9,11 @@
#define RK628_RGB_H
#include "rk628.h"
int rk628_rgb_parse(struct rk628 *rk628, struct device_node *rgb_np);
void rk628_rgb_rx_enable(struct rk628 *rk628);
void rk628_rgb_tx_enable(struct rk628 *rk628);
void rk628_rgb_tx_disable(struct rk628 *rk628);
void rk628_bt1120_rx_enable(struct rk628 *rk628);
void rk628_bt1120_tx_enable(struct rk628 *rk628);
void rk628_rgb_decoder_create_debugfs_file(struct rk628 *rk628);
#endif