diff --git a/arch/arm64/boot/dts/rockchip/rk3562.dtsi b/arch/arm64/boot/dts/rockchip/rk3562.dtsi index 3ed54f3a7859..f77cc830a61e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562.dtsi @@ -252,9 +252,12 @@ opp-shared; mbist-vmin = <825000 900000 975000>; - nvmem-cells = <&cpu_leakage>, <&cpu_opp_info>, <&mbist_vmin>, <&cpu_pvtpll>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm"; + nvmem-cells = <&cpu_leakage>, <&cpu_opp_info>, <&mbist_vmin>, <&cpu_pvtpll>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm", + "specification_serial_number"; + rockchip,supported-hw; rockchip,pvtm-voltage-sel = < 0 1280 0 1281 1350 1 @@ -276,22 +279,26 @@ rockchip,low-temp-min-volt = <1050000>; opp-408000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <408000000>; opp-microvolt = <825000 825000 1150000>; clock-latency-ns = <40000>; opp-suspend; }; opp-600000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <600000000>; opp-microvolt = <825000 825000 1150000>; clock-latency-ns = <40000>; }; opp-816000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <816000000>; opp-microvolt = <825000 825000 1150000>; clock-latency-ns = <40000>; }; opp-1008000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1008000000>; opp-microvolt = <850000 850000 1150000>; opp-microvolt-L0 = <850000 850000 1150000>; @@ -302,6 +309,7 @@ clock-latency-ns = <40000>; }; opp-1200000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <925000 925000 1150000>; opp-microvolt-L0 = <925000 925000 1150000>; @@ -312,6 +320,7 @@ clock-latency-ns = <40000>; }; opp-1416000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1416000000>; opp-microvolt = <1000000 1000000 1150000>; opp-microvolt-L0 = <1000000 1000000 1150000>; @@ -322,6 +331,7 @@ clock-latency-ns = <40000>; }; opp-1608000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1608000000>; opp-microvolt = <1037500 1037500 1150000>; opp-microvolt-L0 = <1037500 1037500 1150000>; @@ -332,6 +342,7 @@ clock-latency-ns = <40000>; }; opp-1800000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1125000 1125000 1150000>; opp-microvolt-L0 = <1125000 1125000 1150000>; @@ -342,6 +353,7 @@ clock-latency-ns = <40000>; }; opp-2016000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <2016000000>; opp-microvolt = <1150000 1150000 1150000>; opp-microvolt-L0 = <1150000 1150000 1150000>; @@ -351,6 +363,39 @@ opp-microvolt-L4 = <1075000 1075000 1150000>; clock-latency-ns = <40000>; }; + + /* RK3562J cpu OPPs */ + opp-j-408000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-600000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-816000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-1008000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-1200000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <900000 900000 1150000>; + opp-microvolt-L0 = <925000 925000 1150000>; + clock-latency-ns = <40000>; + }; }; arm_pmu: arm-pmu { @@ -496,13 +541,16 @@ compatible = "operating-points-v2"; mbist-vmin = <850000 900000 925000>; - nvmem-cells = <&log_leakage>, <&dmc_opp_info>, <&log_mbist_vmin>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin"; + nvmem-cells = <&log_leakage>, <&dmc_opp_info>, <&log_mbist_vmin>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", + "specification_serial_number"; rockchip,temp-hysteresis = <5000>; rockchip,low-temp = <10000>; rockchip,low-temp-min-volt = <950000>; + rockchip,supported-hw; rockchip,leakage-voltage-sel = < 1 15 0 16 20 1 @@ -510,12 +558,20 @@ >; opp-1560000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1560000000>; opp-microvolt = <900000 900000 950000>; opp-microvolt-L0 = <900000 900000 950000>; opp-microvolt-L1 = <875000 875000 950000>; opp-microvolt-L2 = <850000 850000 950000>; }; + + /* RK3562J dmc OPPs */ + opp-j-1560000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <1560000000>; + opp-microvolt = <900000 900000 900000>; + }; }; firmware { @@ -1482,9 +1538,12 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 975000>; - nvmem-cells = <&npu_leakage>, <&npu_opp_info>, <&mbist_vmin>, <&npu_pvtpll>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm"; + nvmem-cells = <&npu_leakage>, <&npu_opp_info>, <&mbist_vmin>, <&npu_pvtpll>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm", + "specification_serial_number"; + rockchip,supported-hw; rockchip,pvtm-voltage-sel = < 0 760 0 761 800 1 @@ -1506,18 +1565,22 @@ rockchip,low-temp-min-volt = <925000>; opp-300000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <300000000>; opp-microvolt = <825000 825000 1000000>; }; opp-400000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <400000000>; opp-microvolt = <825000 825000 1000000>; }; opp-500000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <500000000>; opp-microvolt = <825000 825000 1000000>; }; opp-600000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <600000000>; opp-microvolt = <875000 875000 1000000>; opp-microvolt-L0 = <875000 875000 1000000>; @@ -1527,6 +1590,7 @@ opp-microvolt-L4 = <825000 825000 1000000>; }; opp-700000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <700000000>; opp-microvolt = <925000 925000 1000000>; opp-microvolt-L0 = <925000 925000 1000000>; @@ -1536,6 +1600,7 @@ opp-microvolt-L4 = <825000 825000 1000000>; }; opp-800000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <800000000>; opp-microvolt = <975000 975000 1000000>; opp-microvolt-L0 = <975000 975000 1000000>; @@ -1545,6 +1610,7 @@ opp-microvolt-L4 = <875000 875000 1000000>; }; opp-900000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; @@ -1554,6 +1620,7 @@ opp-microvolt-L4 = <925000 925000 1000000>; }; opp-1000000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; @@ -1562,6 +1629,35 @@ opp-microvolt-L3 = <975000 975000 1000000>; opp-microvolt-L4 = <950000 950000 1000000>; }; + + /* RK3562J npu OPPs */ + opp-j-300000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-400000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-500000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-600000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-700000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <925000 925000 1000000>; + opp-microvolt-L0 = <925000 925000 1000000>; + status = "disabled"; + }; }; rknpu_mmu: iommu@ff30a000 { @@ -1603,9 +1699,12 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 975000>; - nvmem-cells = <&gpu_leakage>, <&gpu_opp_info>, <&mbist_vmin>, <&gpu_pvtpll>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm"; + nvmem-cells = <&gpu_leakage>, <&gpu_opp_info>, <&mbist_vmin>, <&gpu_pvtpll>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm", + "specification_serial_number"; + rockchip,supported-hw; rockchip,pvtm-voltage-sel = < 0 780 0 781 820 1 @@ -1627,22 +1726,27 @@ rockchip,low-temp-min-volt = <925000>; opp-300000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <300000000>; opp-microvolt = <825000 825000 1000000>; }; opp-400000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <400000000>; opp-microvolt = <825000 825000 1000000>; }; opp-500000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <500000000>; opp-microvolt = <825000 825000 1000000>; }; opp-600000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <600000000>; opp-microvolt = <825000 825000 1000000>; }; opp-700000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <700000000>; opp-microvolt = <900000 900000 1000000>; opp-microvolt-L0 = <900000 900000 1000000>; @@ -1652,6 +1756,7 @@ opp-microvolt-L4 = <825000 825000 1000000>; }; opp-800000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <800000000>; opp-microvolt = <950000 950000 1000000>; opp-microvolt-L0 = <950000 950000 1000000>; @@ -1661,6 +1766,7 @@ opp-microvolt-L4 = <850000 850000 1000000>; }; opp-900000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; @@ -1669,6 +1775,33 @@ opp-microvolt-L3 = <925000 925000 1000000>; opp-microvolt-L4 = <900000 900000 1000000>; }; + + /* RK3562J gpu OPPs */ + opp-j-300000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-400000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-500000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-600000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-700000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <900000 900000 1000000>; + }; }; rkvdec: rkvdec@ff340100 { @@ -2632,6 +2765,10 @@ cpu_code: cpu-code@2 { reg = <0x02 0x2>; }; + specification_serial_number: specification-serial-number@7 { + reg = <0x07 0x1>; + bits = <0 5>; + }; otp_cpu_version: cpu-version@8 { reg = <0x08 0x1>; bits = <3 3>; diff --git a/arch/arm64/boot/dts/rockchip/rk3562j.dtsi b/arch/arm64/boot/dts/rockchip/rk3562j.dtsi index b2ec94fccda0..5b660f7f4a5d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562j.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562j.dtsi @@ -28,85 +28,3 @@ status = "disabled"; }; }; - -&cpu0_opp_table { - /delete-node/ mbist-vmin; - /* - * Max CPU frequency is 1.8GHz for the overdrive mode, - * but it will reduce chip lifetime. - */ - /delete-node/ opp-1416000000; - /delete-node/ opp-1608000000; - /delete-node/ opp-1800000000; - /delete-node/ opp-2016000000; - opp-408000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-600000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-816000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-1008000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-1200000000 { - opp-microvolt-L4 = <850000 850000 1150000>; - }; -}; - -&gpu_opp_table { - /delete-node/ mbist-vmin; - /* - * Max GPU frequency is 900MHz for the overdrive mode, - * but it will reduce chip lifetime. - */ - /delete-node/ opp-800000000; - /delete-node/ opp-900000000; - opp-300000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-400000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-500000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-600000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-700000000 { - opp-microvolt-L3 = <850000 850000 1000000>; - opp-microvolt-L4 = <850000 850000 1000000>; - }; -}; - -&npu_opp_table { - /delete-node/ mbist-vmin; - /* - * Max NPU frequency is 900MHz for the overdrive mode, - * but it will reduce chip lifetime. - */ - /delete-node/ opp-800000000; - /delete-node/ opp-900000000; - /delete-node/ opp-1000000000; - opp-300000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-400000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-500000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-600000000 { - opp-microvolt-L2 = <850000 850000 1000000>; - opp-microvolt-L3 = <850000 850000 1000000>; - opp-microvolt-L4 = <850000 850000 1000000>; - }; - opp-700000000 { - opp-microvolt-L4 = <850000 850000 1000000>; - status = "disabled"; - }; -}; diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 65f4ea699266..7897f302b2e8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -350,11 +350,13 @@ lvds1_in_vp1: endpoint@0 { reg = <0>; remote-endpoint = <&vp1_out_lvds1>; + status = "disabled"; }; lvds1_in_vp2: endpoint@1 { reg = <1>; remote-endpoint = <&vp2_out_lvds1>; + status = "disabled"; }; }; }; diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi index bf63d06c109e..ef9e9679f63a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi @@ -205,6 +205,7 @@ &dp { status = "okay"; + svid = <0xff01>; }; &dp0 { @@ -330,6 +331,7 @@ ; source-pdos = ; + mode-switch = <&dp>; altmodes { #address-cells = <1>; diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi index 438721090ebc..ea7c8ea9d2ea 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi @@ -256,6 +256,7 @@ &dp0 { status = "okay"; + svid = <0xff01>; }; &dp0_in_vp2 { @@ -436,6 +437,7 @@ ; source-pdos = ; + mode-switch = <&dp0>; altmodes { #address-cells = <1>; diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig index 150a479bbd86..e486b27cc0b0 100644 --- a/drivers/clk/rockchip/Kconfig +++ b/drivers/clk/rockchip/Kconfig @@ -162,7 +162,7 @@ config ROCKCHIP_CLK_BOOST config ROCKCHIP_CLK_INV bool "Rockchip Clk Inverter" - depends on !CPU_RV1126 && !CPU_RV1106 + depends on !CPU_RV1126 && !CPU_RV1106 && !CPU_RV1103B default y help Say y here to enable clk Inverter. @@ -175,7 +175,7 @@ config ROCKCHIP_CLK_OUT config ROCKCHIP_CLK_PVTM bool "Rockchip Clk Pvtm" - depends on !CPU_RV1126 && !CPU_RV1106 + depends on !CPU_RV1126 && !CPU_RV1106 && !CPU_RV1103B default y help Say y here to enable clk pvtm. diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile index 53e34aa47bc1..d629bbb38948 100644 --- a/drivers/crypto/rockchip/Makefile +++ b/drivers/crypto/rockchip/Makefile @@ -11,12 +11,19 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V1) += \ rk_crypto_v1_ahash.o \ rk_crypto_v1_skcipher.o +$(obj)/rk_sm2signature.asn1.o: $(obj)/rk_sm2signature.asn1.c $(obj)/rk_sm2signature.asn1.h +$(obj)/rk_ecdsasignature.asn1.o: $(obj)/rk_ecdsasignature.asn1.c $(obj)/rk_ecdsasignature.asn1.h +$(obj)/rk_crypto_v2_akcipher.o: $(obj)/rk_sm2signature.asn1.h $(obj)/rk_ecdsasignature.asn1.h + rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V2) += \ rk_crypto_v2.o \ rk_crypto_v2_ahash.o \ rk_crypto_v2_skcipher.o \ rk_crypto_v2_akcipher.o \ rk_crypto_v2_pka.o \ + rk_crypto_ecc.o \ + rk_sm2signature.asn1.o \ + rk_ecdsasignature.asn1.o \ rk_crypto_bignum.o rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \ @@ -25,6 +32,9 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \ rk_crypto_v3_skcipher.o \ rk_crypto_v2_akcipher.o \ rk_crypto_v2_pka.o \ + rk_crypto_ecc.o \ + rk_sm2signature.asn1.o \ + rk_ecdsasignature.asn1.o \ rk_crypto_bignum.o obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP_DEV) += cryptodev_linux/ diff --git a/drivers/crypto/rockchip/rk_crypto_bignum.c b/drivers/crypto/rockchip/rk_crypto_bignum.c index 690c2fdf58ba..6ff1808974d2 100644 --- a/drivers/crypto/rockchip/rk_crypto_bignum.c +++ b/drivers/crypto/rockchip/rk_crypto_bignum.c @@ -128,3 +128,91 @@ int rk_bn_highest_bit(const struct rk_bignum *bn) return (int)(bn->n_words - 1) * RK_WORD_SIZE + b; } + +void rk_ecc_free_point(struct rk_ecp_point *point) +{ + if (!point) + return; + + rk_bn_free(point->x); + rk_bn_free(point->y); + + kfree(point); +} + +struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size) +{ + struct rk_ecp_point *point = NULL; + + point = kzalloc(sizeof(*point), GFP_KERNEL); + if (!point) + return NULL; + + point->x = rk_bn_alloc(max_size); + if (!point->x) + goto error; + + point->y = rk_bn_alloc(max_size); + if (!point->y) + goto error; + + return point; + +error: + rk_ecc_free_point(point); + + return NULL; +} + +struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len, + const uint8_t *y, uint32_t y_len, + enum bignum_endian endian, u32 max_size) +{ + struct rk_ecp_point *point = NULL; + + point = kzalloc(sizeof(*point), GFP_KERNEL); + if (!point) + return NULL; + + point->x = rk_bn_alloc(max_size); + if (!point->x) + goto error; + + if (rk_bn_set_data(point->x, x, x_len, endian) != 0) + goto error; + + point->y = rk_bn_alloc(max_size); + if (!point->y) + goto error; + + if (rk_bn_set_data(point->y, y, y_len, endian) != 0) + goto error; + + return point; + +error: + rk_ecc_free_point(point); + + return NULL; +} + +bool rk_ecp_point_is_zero(struct rk_ecp_point *point) +{ + uint32_t i; + bool ret = true; + + if (!point || !point->x || !point->y) + return false; + + for (i = 0; i < point->x->n_words; i++) { + if (point->x->data[i] != 0) + ret = false; + } + + for (i = 0; i < point->y->n_words; i++) { + if (point->y->data[i] != 0) + ret = false; + } + + return ret; +} diff --git a/drivers/crypto/rockchip/rk_crypto_bignum.h b/drivers/crypto/rockchip/rk_crypto_bignum.h index 780aa87661eb..845eeddc5d84 100644 --- a/drivers/crypto/rockchip/rk_crypto_bignum.h +++ b/drivers/crypto/rockchip/rk_crypto_bignum.h @@ -17,6 +17,11 @@ struct rk_bignum { u32 *data; }; +struct rk_ecp_point { + struct rk_bignum *x; /*!< the point's X coordinate */ + struct rk_bignum *y; /*!< the point's Y coordinate */ +}; + struct rk_bignum *rk_bn_alloc(u32 max_size); void rk_bn_free(struct rk_bignum *bn); int rk_bn_set_data(struct rk_bignum *bn, const u8 *data, u32 size, enum bignum_endian endian); @@ -24,4 +29,11 @@ int rk_bn_get_data(const struct rk_bignum *bn, u8 *data, u32 size, enum bignum_e u32 rk_bn_get_size(const struct rk_bignum *bn); int rk_bn_highest_bit(const struct rk_bignum *src); +struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size); +struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len, + const uint8_t *y, uint32_t y_len, + enum bignum_endian endian, u32 max_size); +void rk_ecc_free_point(struct rk_ecp_point *point); +bool rk_ecp_point_is_zero(struct rk_ecp_point *point); + #endif diff --git a/drivers/crypto/rockchip/rk_crypto_core.c b/drivers/crypto/rockchip/rk_crypto_core.c index 7b1c6ed81c45..4a75519d214f 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.c +++ b/drivers/crypto/rockchip/rk_crypto_core.c @@ -672,7 +672,7 @@ static char *crypto_full_algs_name[] = { "ecb(des3_ede)", "cbc(des3_ede)", "cfb(des3_ede)", "ofb(des3_ede)", "sha1", "sha224", "sha256", "sha384", "sha512", "md5", "sm3", "hmac(sha1)", "hmac(sha256)", "hmac(sha512)", "hmac(md5)", "hmac(sm3)", - "rsa" + "rsa", "ecc-192", "ecc-224", "ecc-256", "sm2", }; static const struct rk_crypto_soc_data px30_soc_data = diff --git a/drivers/crypto/rockchip/rk_crypto_core.h b/drivers/crypto/rockchip/rk_crypto_core.h index a2d4fbd14f78..aba37a9cc1b0 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.h +++ b/drivers/crypto/rockchip/rk_crypto_core.h @@ -213,9 +213,19 @@ struct rk_cipher_ctx { struct rk_rsa_ctx { struct rk_alg_ctx algs_ctx; - struct rk_bignum *n; - struct rk_bignum *e; - struct rk_bignum *d; + struct rk_bignum *n; + struct rk_bignum *e; + struct rk_bignum *d; + + struct rk_crypto_dev *rk_dev; +}; + +struct rk_ecc_ctx { + struct rk_alg_ctx algs_ctx; + uint32_t group_id; + uint32_t nbits; + bool pub_key_set; + struct rk_ecp_point *point_Q; struct rk_crypto_dev *rk_dev; }; @@ -245,6 +255,15 @@ struct rk_crypto_algt { bool valid_flag; }; +enum rk_asym_algo { + ASYM_ALGO_RSA, + ASYM_ALGO_ECC_P192, + ASYM_ALGO_ECC_P224, + ASYM_ALGO_ECC_P256, + ASYM_ALGO_SM2, + ASYM_ALGO_MAX, +}; + enum rk_hash_algo { HASH_ALGO_MD5, HASH_ALGO_SHA1, @@ -439,6 +458,27 @@ enum rk_cipher_mode { } \ } +#define RK_ASYM_ECC_INIT(key_bits) {\ + .name = "ecc-" #key_bits, \ + .type = ALG_TYPE_ASYM, \ + .algo = ASYM_ALGO_ECC_P##key_bits, \ + .alg.asym = { \ + .verify = rk_ecc_verify, \ + .set_pub_key = rk_ecc_set_pub_key, \ + .max_size = rk_ecc_max_size, \ + .init = rk_ecc_init_tfm, \ + .exit = rk_ecc_exit_tfm, \ + .reqsize = 64, \ + .base = { \ + .cra_name = "ecdsa-nist-p" #key_bits, \ + .cra_driver_name = "ecdsa-nist-p" #key_bits "-rk", \ + .cra_priority = RK_CRYPTO_PRIORITY, \ + .cra_module = THIS_MODULE, \ + .cra_ctxsize = sizeof(struct rk_ecc_ctx), \ + },\ + } \ +} + #define CRYPTO_MAJOR_VER(ver) ((ver) & 0x0f000000) #define CRYPTO_MAJOR_VER_3 0x03000000 diff --git a/drivers/crypto/rockchip/rk_crypto_ecc.c b/drivers/crypto/rockchip/rk_crypto_ecc.c new file mode 100644 index 000000000000..050df55882e7 --- /dev/null +++ b/drivers/crypto/rockchip/rk_crypto_ecc.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + * Author: Lin Jinhan + * + */ + +#include + +#include "rk_crypto_core.h" +#include "rk_crypto_v2.h" +#include "rk_crypto_v2_reg.h" +#include "rk_crypto_ecc.h" + +static void __iomem *ecc_base; + +#define WORDS2BYTES(words) ((words) * 4) + +#define RK_ECP_POLL_PERIOD_US 10000 +#define RK_ECP_POLL_TIMEOUT_US 500000 + +#define RK_LOAD_GROUP_A(G) do { \ + grp->curve_name = #G; \ + grp->wide = G ## _wide;\ + grp->p = G ## _p; \ + grp->p_len = sizeof(G ## _p); \ + grp->a = G ## _a; \ + grp->a_len = sizeof(G ## _a); \ + grp->n = G ## _n; \ + grp->n_len = sizeof(G ## _n); \ + grp->gx = G ## _gx; \ + grp->gx_len = sizeof(G ## _gx); \ + grp->gy = G ## _gy; \ + grp->gy_len = sizeof(G ## _gy); \ + } while (0) + +/* + * Domain parameters for secp192r1 + */ +static const uint32_t secp192r1_wide = RK_ECC_CURVE_WIDE_192; + +static const uint8_t secp192r1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp192r1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp192r1_gx[] = { + 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, + 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, + 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18, +}; + +static const uint8_t secp192r1_gy[] = { + 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, + 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, + 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07, +}; + +static const uint8_t secp192r1_n[] = { + 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, + 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for secp224r1 + */ +static const uint32_t secp224r1_wide = RK_ECC_CURVE_WIDE_224; + +static const uint8_t secp224r1_p[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t secp224r1_a[] = { + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t secp224r1_gx[] = { + 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, + 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, + 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, + 0xBD, 0x0C, 0x0E, 0xB7, +}; + +static const uint8_t secp224r1_gy[] = { + 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, + 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, + 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, + 0x88, 0x63, 0x37, 0xBD, +}; + +static const uint8_t secp224r1_n[] = { + 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, + 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for secp256r1 + */ +static const uint32_t secp256r1_wide = RK_ECC_CURVE_WIDE_256; + +static const uint8_t secp256r1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp256r1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp256r1_gx[] = { + 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, + 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, + 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, + 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B, +}; + +static const uint8_t secp256r1_gy[] = { + 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, + 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, + 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, + 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F, +}; + +static const uint8_t secp256r1_n[] = { + 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, + 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for sm2p256v1_p + */ +static const uint32_t sm2p256v1_wide = RK_ECC_CURVE_WIDE_256; + +static const uint8_t sm2p256v1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t sm2p256v1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t sm2p256v1_gx[] = { + 0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71, + 0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F, + 0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F, + 0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32, +}; + +static const uint8_t sm2p256v1_gy[] = { + 0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02, + 0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0, + 0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59, + 0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC, +}; + +static const uint8_t sm2p256v1_n[] = { + 0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53, + 0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static void dump_ecc_sram(void) +{ +#ifdef DEBUG + int i; + uint32_t len = 0x300; + uint32_t *buffer; + + buffer = kzalloc(len, GFP_KERNEL); + + for (i = 0; i < len / 4; i++) + buffer[i] = ((uint32_t *)SM2_RAM_BASE)[i]; + + CRYPTO_DUMPHEX("ECC SRAM ", buffer, len); + + kfree(buffer); +#endif +} + +static void ecc_word_memcpy(uint32_t *dst, uint32_t *src, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++, dst++) + writel_relaxed(src[i], (void *)dst); +} + +static void ecc_word_memset(uint32_t *buff, uint32_t val, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++, buff++) + writel_relaxed(val, (void *)buff); +} + +static void rk_reverse_buf(uint8_t *buff, uint32_t size) +{ + uint8_t *buf_h_swap, *buf_l_swap; + uint32_t i; + uint32_t temp; + + buf_h_swap = buff + size - 1; + buf_l_swap = buff; + + for (i = 0 ; i < (size / 2) ; i++) { + temp = *buf_h_swap; + *(buf_h_swap--) = *buf_l_swap; + *(buf_l_swap++) = temp; + } +} + +static int rk_word_cmp_zero(uint32_t *buf1, uint32_t n_words) +{ + int ret = 0; + uint32_t i; + + for (i = 0 ; i < n_words; i++) { + if (buf1[i] != 0) + ret = -EINVAL; + } + + return ret; +} + +static int rk_load_hash_bn(struct rk_ecp_group *grp, struct rk_bignum *bn, + uint8_t *hash, uint32_t hash_len) +{ + if (grp == NULL || RK_ECP_IS_BIGNUM_INVALID(bn)) + return -EINVAL; + + hash_len = hash_len > grp->p_len ? grp->p_len : hash_len; + + memset(bn->data, 0x00, WORDS2BYTES(bn->n_words)); + memcpy(bn->data, hash, hash_len); + + rk_reverse_buf((void *)bn->data, hash_len); + + return 0; +} + +/* + * Set a group using well-known domain parameters + */ +static int rk_ecp_group_load(struct rk_ecp_group *grp, enum rk_ecp_group_id id) +{ + memset(grp, 0x00, sizeof(*grp)); + + grp->id = id; + grp->endian = RK_BG_LITTILE_ENDIAN; + + switch (id) { + case RK_ECP_DP_SECP192R1: + RK_LOAD_GROUP_A(secp192r1); + return 0; + + case RK_ECP_DP_SECP224R1: + RK_LOAD_GROUP_A(secp224r1); + return 0; + + case RK_ECP_DP_SECP256R1: + RK_LOAD_GROUP_A(secp256r1); + return 0; + + case RK_ECP_DP_SM2P256V1: + RK_LOAD_GROUP_A(sm2p256v1); + return 0; + + default: + return -EINVAL; + } +} + +static int rockchip_ecc_request_set(uint32_t ecc_ctl, uint32_t wide) +{ + RK_ECP_WRITE_REG(RK_ECC_CURVE_WIDE, wide); + + RK_ECP_WRITE_REG(RK_ECC_INT_EN, 0); + RK_ECP_WRITE_REG(RK_ECC_INT_ST, RK_ECP_READ_REG(RK_ECC_INT_ST)); + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl); + + return 0; +} + +static int rockchip_ecc_request_wait_done(void) +{ + int ret; + u32 reg_val = 0; + + ret = readx_poll_timeout(RK_ECP_READ_REG, RK_ECC_INT_ST, reg_val, + reg_val != 0, RK_ECP_POLL_PERIOD_US, RK_ECP_POLL_TIMEOUT_US); + if (ret) { + CRYPTO_TRACE("rk ecp poll RK_ECC_INT_ST timeout.\ns"); + goto exit; + } + + if (RK_ECP_READ_REG(RK_ECC_ABN_ST)) { + ret = -EFAULT; + goto exit; + } + +exit: + if (ret) { + CRYPTO_TRACE("RK_ECC_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_CTL)); + CRYPTO_TRACE("RK_ECC_INT_EN = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_EN)); + CRYPTO_TRACE("RK_ECC_CURVE_WIDE = %08x\n", RK_ECP_READ_REG(RK_ECC_CURVE_WIDE)); + CRYPTO_TRACE("RK_ECC_RAM_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_RAM_CTL)); + CRYPTO_TRACE("RK_ECC_INT_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_ST)); + CRYPTO_TRACE("RK_ECC_ABN_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_ABN_ST)); + } + + RK_ECP_WRITE_REG(RK_ECC_CTL, 0); + RK_ECP_RAM_FOR_CPU(); + + return ret; +} + +static int rockchip_ecc_request_trigger(void) +{ + uint32_t ecc_ctl = RK_ECP_READ_REG(RK_ECC_CTL); + + RK_ECP_RAM_FOR_ECC(); + + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl | RK_ECC_CTL_REQ_ECC); + + return rockchip_ecc_request_wait_done(); +} + +int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign) +{ + int ret; + uint32_t curve_sel = 0; + struct rk_bignum *bn_hash = NULL; + struct rk_ecp_group grp; + struct rk_ecc_verify *ecc_st = (struct rk_ecc_verify *)SM2_RAM_BASE; + + CRYPTO_TRACE("ecc_st = %p, ecc_base = %p\n", ecc_st, ecc_base); + + if (!hash || + RK_ECP_IS_POINT_INVALID(point_P) || + RK_ECP_IS_POINT_INVALID(point_sign)) { + ret = -EINVAL; + goto exit; + } + + ret = rk_ecp_group_load(&grp, group_id); + if (ret) + goto exit; + + bn_hash = rk_bn_alloc(RK_ECP_MAX_BYTES); + if (!bn_hash) { + ret = -ENOMEM; + goto exit; + } + + curve_sel = group_id == RK_ECP_DP_SM2P256V1 ? + RK_ECC_CTL_FUNC_SM2_CURVER : RK_ECC_CTL_FUNC_ECC_CURVER; + + rk_load_hash_bn(&grp, bn_hash, hash, hash_len); + + RK_ECP_LOAD_DATA(ecc_st->e, bn_hash); + RK_ECP_LOAD_DATA(ecc_st->r_, point_sign->x); + RK_ECP_LOAD_DATA(ecc_st->s_, point_sign->y); + RK_ECP_LOAD_DATA(ecc_st->p_x, point_P->x); + RK_ECP_LOAD_DATA(ecc_st->p_y, point_P->y); + + RK_ECP_LOAD_DATA_EXT(ecc_st->A, grp.a, grp.a_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->P, grp.p, grp.p_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->N, grp.n, grp.n_len); + + RK_ECP_LOAD_DATA_EXT(ecc_st->G_x, grp.gx, grp.gx_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->G_y, grp.gy, grp.gy_len); + + rockchip_ecc_request_set(curve_sel | RK_ECC_CTL_FUNC_SEL_VERIFY, grp.wide); + + ret = rockchip_ecc_request_trigger(); +exit: + if (ret || rk_word_cmp_zero(ecc_st->v, RK_ECP_MAX_WORDS)) { + ret = -EKEYREJECTED; + dump_ecc_sram(); + } + + rk_bn_free(bn_hash); + + return ret; +} + +void rockchip_ecc_init(void __iomem *base) +{ + ecc_base = base - RK_ECC_BASE_OFFSET; + + RK_ECP_WRITE_REG(RK_ECC_DATA_ENDIAN, RK_ECC_DATA_ENDIAN_LITTLE); +} + +void rockchip_ecc_deinit(void) +{ + +} + +uint32_t rockchip_ecc_get_max_size(void) +{ + return RK_ECP_MAX_BYTES; +} + +uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id) +{ + switch (group_id) { + case RK_ECP_DP_SECP192R1: + return 192; + + case RK_ECP_DP_SECP224R1: + return 224; + + case RK_ECP_DP_SECP256R1: + case RK_ECP_DP_SM2P256V1: + return 256; + + default: + return 0; + } +} + +uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo) +{ + + switch (asym_algo) { + case ASYM_ALGO_ECC_P192: + return RK_ECP_DP_SECP192R1; + case ASYM_ALGO_ECC_P224: + return RK_ECP_DP_SECP224R1; + case ASYM_ALGO_ECC_P256: + return RK_ECP_DP_SECP256R1; + case ASYM_ALGO_SM2: + return RK_ECP_DP_SM2P256V1; + default: + return RK_ECP_DP_NONE; + } +} diff --git a/drivers/crypto/rockchip/rk_crypto_ecc.h b/drivers/crypto/rockchip/rk_crypto_ecc.h new file mode 100644 index 000000000000..645c160cf8e9 --- /dev/null +++ b/drivers/crypto/rockchip/rk_crypto_ecc.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Copyright (c) 2024 Rockchip Electronics Co. Ltd. */ + +#ifndef __RK_CRYPTO_ECC_H__ +#define __RK_CRYPTO_ECC_H__ + +#include "rk_crypto_bignum.h" + +#define RK_ECP_MAX_BITS 256 +#define RK_ECP_MAX_BYTES ((RK_ECP_MAX_BITS) / 8) +#define RK_ECP_MAX_WORDS ((RK_ECP_MAX_BITS) / 32) +#define RK_ECP_MAX_WORDS_ALL (512 / 32) + +/*************************************************************/ +/* Macros for waiting PKA machine ready states */ +/*************************************************************/ +#define RK_ECP_WRITE_REG(offset, val) writel_relaxed((val), (ecc_base) + (offset)) +#define RK_ECP_READ_REG(offset) readl_relaxed((ecc_base) + (offset)) + +#define RK_ECP_RAM_FOR_ECC() \ + RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_ECC) + +#define RK_ECP_RAM_FOR_CPU() \ + RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_CPU) + +#define RK_ECP_LOAD_DATA(dst, big_src) \ + do { \ + ecc_word_memset((dst), 0, RK_ECP_MAX_WORDS);\ + ecc_word_memcpy((dst), (big_src->data), (big_src->n_words)); \ + } while (0) + +#define RK_ECP_LOAD_DATA_EXT(dst, src, n_bytes) \ + do { \ + ecc_word_memset((void *)(dst), 0, RK_ECP_MAX_WORDS);\ + ecc_word_memcpy((void *)(dst), (void *)(src), (n_bytes) / 4); \ + } while (0) + +#define RK_ECC_BASE_OFFSET 0x0480 + +#define RK_ECC_CTL 0x03F0 +#define RK_ECC_CTL_RAND_K_SRC_SOFT _SBF(12, 0) +#define RK_ECC_CTL_RAND_K_SRC_HARD _SBF(12, 1) +#define RK_ECC_CTL_FUNC_SM2_CURVER _SBF(8, 0x0) +#define RK_ECC_CTL_FUNC_ECC_CURVER _SBF(8, 0x1) + +#define RK_ECC_CTL_FUNC_SEL_MUL _SBF(4, 0x0) +#define RK_ECC_CTL_FUNC_SEL_KG _SBF(4, 0x1) +#define RK_ECC_CTL_FUNC_SEL_SIGN _SBF(4, 0x2) +#define RK_ECC_CTL_FUNC_SEL_VERIFY _SBF(4, 0x3) +#define RK_ECC_CTL_FUNC_SEL_MUL_MOD _SBF(4, 0x4) +#define RK_ECC_CTL_FUNC_SEL_ADD_MOD _SBF(4, 0x5) +#define RK_ECC_CTL_FUNC_SEL_DOUBLE_POINT _SBF(4, 0x6) +#define RK_ECC_CTL_FUNC_SEL_ADD_POINT _SBF(4, 0x7) +#define RK_ECC_CTL_FUNC_SEL_KP _SBF(4, 0x8) +#define RK_ECC_CTL_FUNC_SEL_KP_KG _SBF(4, 0xa) +#define RK_ECC_CTL_REQ_ECC _SBF(0, 1) + +#define RK_ECC_INT_EN 0x03F4 +#define RK_ECC_INT_EN_DONE _BIT(0) + +#define RK_ECC_INT_ST 0x03F8 +#define RK_ECC_INT_ST_DONE _BIT(0) + +#define RK_ECC_ABN_ST 0x03FC +#define RK_ECC_ABN_ST_BAD_INV_OUT _BIT(8) +#define RK_ECC_ABN_ST_BAD_K_IN _BIT(7) +#define RK_ECC_ABN_ST_BAD_R_IN _BIT(6) +#define RK_ECC_ABN_ST_BAD_S_IN _BIT(5) +#define RK_ECC_ABN_ST_BAD_R_K_MID _BIT(4) +#define RK_ECC_ABN_ST_BAD_R_OUT _BIT(3) +#define RK_ECC_ABN_ST_BAD_S_OUT _BIT(2) +#define RK_ECC_ABN_ST_BAD_T_OUT _BIT(1) +#define RK_ECC_ABN_ST_BAD_POINT_OUT _BIT(0) + +#define RK_ECC_CURVE_WIDE 0x0400 +#define RK_ECC_CURVE_WIDE_192 192 +#define RK_ECC_CURVE_WIDE_224 224 +#define RK_ECC_CURVE_WIDE_256 256 + +#define RK_ECC_MAX_CURVE_WIDE 0x0404 + +#define RK_ECC_DATA_ENDIAN 0x0408 +#define RK_ECC_DATA_ENDIAN_LITTLE 0x0 +#define RK_ECC_DATA_ENDIAN_BIG 0x1 + +#define RK_ECC_RAM_CTL 0x0480 +#define RK_ECC_RAM_CTL_SEL_MASK _SBF(16, 3) +#define RK_ECC_RAM_CTL_CPU _SBF(0, 0) +#define RK_ECC_RAM_CTL_PKA _SBF(0, 1) +#define RK_ECC_RAM_CTL_ECC _SBF(0, 2) + +#define SM2_RAM_BASE ((ecc_base) + 0x1000) + +enum rk_ecp_group_id { + RK_ECP_DP_NONE = 0, + RK_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + RK_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + RK_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + RK_ECP_DP_SM2P256V1, /*!< */ +}; + +#define RK_ECP_IS_BIGNUM_INVALID(b) (!b || !b->data || b->n_words < RK_ECP_MAX_WORDS) +#define RK_ECP_IS_POINT_INVALID(p) (RK_ECP_IS_BIGNUM_INVALID(p->x) && \ + RK_ECP_IS_BIGNUM_INVALID(p->y)) + +struct rk_ecp_group { + enum rk_ecp_group_id id; /*!< internal group identifier */ + const char *curve_name; + uint32_t wide; + const uint8_t *p; /*!< prime modulus of the base field */ + const uint8_t *a; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + const uint8_t *n; + const uint8_t *gx; + const uint8_t *gy; + size_t p_len; + size_t a_len; + size_t n_len; + size_t gx_len; + size_t gy_len; + enum bignum_endian endian; +}; + +struct rk_ecc_verify { + uint32_t e[RK_ECP_MAX_WORDS_ALL]; // 0x00 + uint32_t r_[RK_ECP_MAX_WORDS_ALL]; // 0x40 + uint32_t s_[RK_ECP_MAX_WORDS_ALL]; // 0x80 + uint32_t p_x[RK_ECP_MAX_WORDS_ALL]; // 0xC0 + uint32_t p_y[RK_ECP_MAX_WORDS_ALL]; // 0x100 + uint32_t A[RK_ECP_MAX_WORDS_ALL]; // 0x140 + uint32_t P[RK_ECP_MAX_WORDS_ALL]; // 0x180 + uint32_t N[RK_ECP_MAX_WORDS_ALL]; // 0x1C0 + uint32_t G_x[RK_ECP_MAX_WORDS_ALL]; // 0x200 + uint32_t G_y[RK_ECP_MAX_WORDS_ALL]; // 0x240 + uint32_t r[RK_ECP_MAX_WORDS_ALL]; // 0x280 + uint32_t v[RK_ECP_MAX_WORDS_ALL]; // 0x2C0 +}; + +int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign); + +void rockchip_ecc_init(void __iomem *base); + +void rockchip_ecc_deinit(void); + +uint32_t rockchip_ecc_get_max_size(void); + +uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id); + +uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo); + +#endif diff --git a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c index 1311ea3d4eac..bea5e3f006d3 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c @@ -8,13 +8,18 @@ * * Some ideas are from marvell/cesa.c and s5p-sss.c driver. */ - +#include +#include #include +#include #include "rk_crypto_core.h" #include "rk_crypto_v2.h" #include "rk_crypto_v2_reg.h" #include "rk_crypto_v2_pka.h" +#include "rk_crypto_ecc.h" +#include "rk_sm2signature.asn1.h" +#include "rk_ecdsasignature.asn1.h" #define BG_WORDS2BYTES(words) ((words) * sizeof(u32)) #define BG_BYTES2WORDS(bytes) (((bytes) + sizeof(u32) - 1) / sizeof(u32)) @@ -294,12 +299,16 @@ static void rk_rsa_exit_tfm(struct crypto_akcipher *tfm) rk_rsa_clear_ctx(ctx); - ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa"); + if (ctx->rk_dev && ctx->rk_dev->release_crypto) + ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa"); + + memset(ctx, 0x00, sizeof(*ctx)); } struct rk_crypto_algt rk_v2_asym_rsa = { .name = "rsa", .type = ALG_TYPE_ASYM, + .algo = ASYM_ALGO_RSA, .alg.asym = { .encrypt = rk_rsa_enc, .decrypt = rk_rsa_dec, @@ -319,3 +328,241 @@ struct rk_crypto_algt rk_v2_asym_rsa = { }, }; +int rk_ecc_get_signature_r(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct rk_ecp_point *sig = context; + const uint8_t *tmp_value = value; + + if (!value || !vlen) + return -EINVAL; + + /* skip first zero */ + if (tmp_value[0] == 0x00) { + tmp_value += 1; + vlen -= 1; + } + + return rk_bn_set_data(sig->x, tmp_value, vlen, RK_BG_BIG_ENDIAN); +} + +int rk_ecc_get_signature_s(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct rk_ecp_point *sig = context; + const uint8_t *tmp_value = value; + + if (!value || !vlen) + return -EINVAL; + + /* skip first zero */ + if (tmp_value[0] == 0x00) { + tmp_value += 1; + vlen -= 1; + } + + return rk_bn_set_data(sig->y, tmp_value, vlen, RK_BG_BIG_ENDIAN); +} + +static int rk_ecc_verify(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + size_t keylen = ctx->nbits / 8; + struct rk_ecp_point *sig_point = NULL; + u8 rawhash[RK_ECP_MAX_BYTES]; + unsigned char *buffer; + ssize_t diff; + int ret; + + if (unlikely(!ctx->pub_key_set)) + return -EINVAL; + + buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + sig_point = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES); + if (!sig_point) { + ret = -ENOMEM; + goto exit; + } + + sg_pcopy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len + req->dst_len), + buffer, req->src_len + req->dst_len, 0); + + CRYPTO_DUMPHEX("total signture:", buffer, req->src_len); + + if (ctx->group_id == RK_ECP_DP_SM2P256V1) + ret = asn1_ber_decoder(&rk_sm2signature_decoder, sig_point, buffer, req->src_len); + else + ret = asn1_ber_decoder(&rk_ecdsasignature_decoder, sig_point, buffer, req->src_len); + if (ret < 0) + goto exit; + + CRYPTO_DUMPHEX("bn r value = ", sig_point->x->data, BG_WORDS2BYTES(sig_point->x->n_words)); + CRYPTO_DUMPHEX("bn s value = ", sig_point->y->data, BG_WORDS2BYTES(sig_point->y->n_words)); + + /* if the hash is shorter then we will add leading zeros to fit to ndigits */ + memset(rawhash, 0x00, sizeof(rawhash)); + diff = keylen - req->dst_len; + if (diff >= 0) { + if (diff) + memset(rawhash, 0, diff); + memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); + } else if (diff < 0) { + /* given hash is longer, we take the left-most bytes */ + memcpy(&rawhash, buffer + req->src_len, keylen); + } + + CRYPTO_DUMPHEX("rawhash:", rawhash, sizeof(rawhash)); + + mutex_lock(&akcipher_mutex); + + ret = rockchip_ecc_verify(ctx->group_id, rawhash, keylen, ctx->point_Q, sig_point); + + mutex_unlock(&akcipher_mutex); +exit: + kfree(buffer); + rk_ecc_free_point(sig_point); + + CRYPTO_TRACE("ret = %d\n", ret); + + return ret; +} + +/* + * Set the public key given the raw uncompressed key data from an X509 + * certificate. The key data contain the concatenated X and Y coordinates of + * the public key. + */ +static int rk_ecc_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct rk_ecp_point *pub_Q = ctx->point_Q; + const unsigned char *d = key; + uint32_t nbytes; + + CRYPTO_TRACE(); + + CRYPTO_DUMPHEX("key = ", key, keylen); + + if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u32)) != 0) + return -EINVAL; + + /* we only accept uncompressed format indicated by '4' */ + if (d[0] != 4) + return -EINVAL; + + keylen--; + d++; + + nbytes = keylen / 2; + + CRYPTO_TRACE("keylen = %u, nbytes = %u, group_id = %u, curve_byte = %u\n", + keylen, nbytes, ctx->group_id, + rockchip_ecc_get_curve_nbits(ctx->group_id) / 8); + + if (nbytes != rockchip_ecc_get_curve_nbits(ctx->group_id) / 8) + return -EINVAL; + + rk_bn_set_data(pub_Q->x, d, nbytes, RK_BG_BIG_ENDIAN); + rk_bn_set_data(pub_Q->y, d + nbytes, nbytes, RK_BG_BIG_ENDIAN); + + CRYPTO_DUMPHEX("Qx = ", pub_Q->x->data, BG_WORDS2BYTES(pub_Q->x->n_words)); + CRYPTO_DUMPHEX("Qy = ", pub_Q->y->data, BG_WORDS2BYTES(pub_Q->y->n_words)); + + if (rk_ecp_point_is_zero(pub_Q)) + return -EINVAL; + + ctx->pub_key_set = true; + + return 0; +} + +static unsigned int rk_ecc_max_size(struct crypto_akcipher *tfm) +{ + CRYPTO_TRACE(); + + return rockchip_ecc_get_max_size(); +} + +static int rk_ecc_init_tfm(struct crypto_akcipher *tfm) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg); + struct rk_crypto_algt *algt; + struct rk_crypto_dev *rk_dev; + + CRYPTO_TRACE(); + + if (!ctx) + return -EINVAL; + + memset(ctx, 0x00, sizeof(*ctx)); + + algt = container_of(alg, struct rk_crypto_algt, alg.asym); + rk_dev = algt->rk_dev; + + if (!rk_dev->request_crypto) + return -EFAULT; + + rk_dev->request_crypto(rk_dev, algt->name); + + ctx->rk_dev = rk_dev; + ctx->group_id = rockchip_ecc_get_group_id(algt->algo); + ctx->nbits = rockchip_ecc_get_curve_nbits(ctx->group_id); + ctx->point_Q = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES); + + rockchip_ecc_init(ctx->rk_dev->pka_reg); + + return 0; +} + +static void rk_ecc_exit_tfm(struct crypto_akcipher *tfm) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg); + struct rk_crypto_algt *algt; + + CRYPTO_TRACE(); + + if (!ctx) + return; + + rk_ecc_free_point(ctx->point_Q); + + rockchip_ecc_deinit(); + + algt = container_of(alg, struct rk_crypto_algt, alg.asym); + + if (ctx->rk_dev && ctx->rk_dev->release_crypto) + ctx->rk_dev->release_crypto(ctx->rk_dev, algt->name); + + memset(ctx, 0x00, sizeof(*ctx)); +} + +struct rk_crypto_algt rk_asym_ecc_p192 = RK_ASYM_ECC_INIT(192); +struct rk_crypto_algt rk_asym_ecc_p224 = RK_ASYM_ECC_INIT(224); +struct rk_crypto_algt rk_asym_ecc_p256 = RK_ASYM_ECC_INIT(256); + +struct rk_crypto_algt rk_asym_sm2 = { + .name = "sm2", + .type = ALG_TYPE_ASYM, + .algo = ASYM_ALGO_SM2, + .alg.asym = { + .verify = rk_ecc_verify, + .set_pub_key = rk_ecc_set_pub_key, + .max_size = rk_ecc_max_size, + .init = rk_ecc_init_tfm, + .exit = rk_ecc_exit_tfm, + .reqsize = 64, + .base = { + .cra_name = "sm2", + .cra_driver_name = "sm2-rk", + .cra_priority = RK_CRYPTO_PRIORITY, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct rk_ecc_ctx), + }, + } +}; diff --git a/drivers/crypto/rockchip/rk_crypto_v2_pka.c b/drivers/crypto/rockchip/rk_crypto_v2_pka.c index d2c0a265b3ad..569800857f75 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_pka.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_pka.c @@ -434,6 +434,7 @@ exit: static void pka_finish(void) { RK_PKA_TERMINATE(); + PKA_RAM_FOR_CPU(); PKA_CLK_DISABLE(); } diff --git a/drivers/crypto/rockchip/rk_crypto_v3.c b/drivers/crypto/rockchip/rk_crypto_v3.c index 7cd728599d88..eb7d4e0a5e20 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3.c +++ b/drivers/crypto/rockchip/rk_crypto_v3.c @@ -94,6 +94,10 @@ static struct rk_crypto_algt *crypto_v3_algs[] = { /* Shared v2 version implementation */ &rk_v2_asym_rsa, /* rsa */ + &rk_asym_ecc_p192, /* ecc nist p192 */ + &rk_asym_ecc_p224, /* ecc nist p224 */ + &rk_asym_ecc_p256, /* ecc nist p256 */ + &rk_asym_sm2, /* sm2 */ }; static bool rk_is_cipher_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 mode, u32 key_len) @@ -161,6 +165,21 @@ static bool rk_is_hash_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 type) return version & mask; } +static bool rk_is_asym_support(struct rk_crypto_dev *rk_dev, u32 algo) +{ + switch (algo) { + case ASYM_ALGO_RSA: + return !!CRYPTO_READ(rk_dev, CRYPTO_PKA_VERSION); + case ASYM_ALGO_ECC_P192: + case ASYM_ALGO_ECC_P224: + case ASYM_ALGO_ECC_P256: + case ASYM_ALGO_SM2: + return !!CRYPTO_READ(rk_dev, CRYPTO_ECC_MAX_CURVE_WIDE); + default: + return false; + } +} + int rk_hw_crypto_v3_init(struct device *dev, void *hw_info) { struct rk_hw_crypto_v3_info *info = @@ -208,8 +227,8 @@ bool rk_hw_crypto_v3_algo_valid(struct rk_crypto_dev *rk_dev, struct rk_crypto_a CRYPTO_TRACE("HASH/HMAC"); return rk_is_hash_support(rk_dev, aglt->algo, aglt->type); } else if (aglt->type == ALG_TYPE_ASYM) { - CRYPTO_TRACE("RSA"); - return true; + CRYPTO_TRACE("ASYM"); + return rk_is_asym_support(rk_dev, aglt->algo); } else { return false; } diff --git a/drivers/crypto/rockchip/rk_crypto_v3.h b/drivers/crypto/rockchip/rk_crypto_v3.h index a4b181416300..bc75c1bf99b2 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3.h +++ b/drivers/crypto/rockchip/rk_crypto_v3.h @@ -72,6 +72,10 @@ extern struct rk_crypto_algt rk_v3_hmac_sm3; /* Shared v2 version implementation */ extern struct rk_crypto_algt rk_v2_asym_rsa; +extern struct rk_crypto_algt rk_asym_ecc_p192; +extern struct rk_crypto_algt rk_asym_ecc_p224; +extern struct rk_crypto_algt rk_asym_ecc_p256; +extern struct rk_crypto_algt rk_asym_sm2; int rk_hw_crypto_v3_init(struct device *dev, void *hw_info); void rk_hw_crypto_v3_deinit(struct device *dev, void *hw_info); diff --git a/drivers/crypto/rockchip/rk_crypto_v3_reg.h b/drivers/crypto/rockchip/rk_crypto_v3_reg.h index 1c4c45317a28..d271ed81eb47 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3_reg.h +++ b/drivers/crypto/rockchip/rk_crypto_v3_reg.h @@ -20,6 +20,8 @@ #define CRYPTO_BC_MID_IS_VALID BIT(0) #define CRYPTO_HASH_MID_IS_VALID BIT(1) +#define CRYPTO_ECC_MAX_CURVE_WIDE 0x0404 + #define CRYPTO_KEY_SEL 0x0610 #define CRYPTO_MID_VALID_SWITCH 0x0630 diff --git a/drivers/crypto/rockchip/rk_ecdsasignature.asn1 b/drivers/crypto/rockchip/rk_ecdsasignature.asn1 new file mode 100644 index 000000000000..aef4ac16985d --- /dev/null +++ b/drivers/crypto/rockchip/rk_ecdsasignature.asn1 @@ -0,0 +1,8 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (c) 2024 Rockchip Electronics Co., Ltd. + +ECDSASignature ::= SEQUENCE { + x INTEGER ({ rk_ecc_get_signature_r }), + y INTEGER ({ rk_ecc_get_signature_s }) +} diff --git a/drivers/crypto/rockchip/rk_sm2signature.asn1 b/drivers/crypto/rockchip/rk_sm2signature.asn1 new file mode 100644 index 000000000000..49d1178d713d --- /dev/null +++ b/drivers/crypto/rockchip/rk_sm2signature.asn1 @@ -0,0 +1,8 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (c) 2024 Rockchip Electronics Co., Ltd. + +Sm2Signature ::= SEQUENCE { + x INTEGER ({ rk_ecc_get_signature_r }), + y INTEGER ({ rk_ecc_get_signature_s }) +} diff --git a/drivers/gpio/gpio-nca9539.c b/drivers/gpio/gpio-nca9539.c index afeccd30c369..201ffef034a2 100644 --- a/drivers/gpio/gpio-nca9539.c +++ b/drivers/gpio/gpio-nca9539.c @@ -31,11 +31,14 @@ #define NCA9539_REG_CONFIG_PORT0 (NCA9539_REG_CONFIG_BASE + 0x0) #define NCA9539_REG_CONFIG_PORT1 (NCA9539_REG_CONFIG_BASE + 0x1) +#define NCA9539_MAX_REGS 8 + struct nca9539_chip { struct gpio_chip gpio_chip; struct regmap *regmap; struct regulator *regulator; unsigned int ngpio; + u8 backup_regs[NCA9539_MAX_REGS]; }; static int nca9539_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) @@ -78,8 +81,7 @@ static int nca9539_gpio_direction_input(struct gpio_chip *gc, unsigned int offse return ret; } -static int nca9539_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, - int val) +static int nca9539_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int val) { struct nca9539_chip *priv = gpiochip_get_data(gc); unsigned int port = offset / 8; @@ -233,11 +235,79 @@ static const struct gpio_chip template_chip = { .can_sleep = true, }; +#ifdef CONFIG_PM +static int nca9539_suspend(struct device *dev) +{ + struct nca9539_chip *priv = dev_get_drvdata(dev); + unsigned int offset = 0; + unsigned int value = 0; + int ret = 0; + + dev_info(dev, "%s: registers backup", __func__); + + for (offset = 0; offset < priv->gpio_chip.ngpio / 2; offset++) { + value = nca9539_regmap_default[offset].def; + ret = regmap_read(priv->regmap, offset, &value); + if (ret < 0) { + dev_err(dev, "%s offset(%d) read reg failed", + __func__, offset); + } + priv->backup_regs[offset] = (u8)(value); + } + + return 0; +} + +static int nca9539_resume(struct device *dev) +{ + struct nca9539_chip *priv = dev_get_drvdata(dev); + unsigned int offset = 0; + unsigned int value = 0; + int ret = 0; + + dev_info(dev, "%s: registers recovery", __func__); + + for (offset = 0; offset < 2; offset++) { + value = priv->backup_regs[NCA9539_REG_CONFIG_BASE + offset]; + ret = regmap_write(priv->regmap, + NCA9539_REG_CONFIG_BASE + offset, value); + if (ret < 0) { + dev_err(dev, "%s offset(%d) write reg %d failed", + __func__, offset, value); + } + + value = priv->backup_regs[NCA9539_REG_POLARITY_BASE + offset]; + ret = regmap_write(priv->regmap, + NCA9539_REG_POLARITY_BASE + offset, value); + if (ret < 0) { + dev_err(dev, "%s offset(%d) write reg %d failed", + __func__, offset, value); + } + + value = priv->backup_regs[NCA9539_REG_OUTPUT_PORT_BASE + offset]; + ret = regmap_write(priv->regmap, + NCA9539_REG_OUTPUT_PORT_BASE + offset, + value); + if (ret < 0) { + dev_err(dev, "%s offset(%d) write reg %d failed", + __func__, offset, value); + } + } + + return 0; +} + +static const struct dev_pm_ops nca9539_dev_pm_ops = { + SET_LATE_SYSTEM_SLEEP_PM_OPS(nca9539_suspend, nca9539_resume) +}; +#endif + static int nca9539_probe(struct i2c_client *client) { struct nca9539_chip *chip; struct regulator *reg; int ret; + int i; chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL); if (!chip) @@ -249,6 +319,9 @@ static int nca9539_probe(struct i2c_client *client) chip->ngpio = (uintptr_t)of_device_get_match_data(&client->dev); chip->gpio_chip.ngpio = chip->ngpio; + for (i = 0; i < NCA9539_MAX_REGS; i++) + chip->backup_regs[i] = nca9539_regmap_default[i].def; + reg = devm_regulator_get(&client->dev, "vdd"); if (IS_ERR(reg)) return dev_err_probe(&client->dev, PTR_ERR(reg), @@ -318,9 +391,12 @@ static struct i2c_driver nca9539_driver = { .driver = { .name = "nca9539-gpio", .of_match_table = nca9539_gpio_of_match_table, +#ifdef CONFIG_PM + .pm = &nca9539_dev_pm_ops, +#endif }, .probe_new = nca9539_probe, - .remove = nca9539_remove, + .remove = nca9539_remove, .id_table = nca9539_gpio_id_table, }; module_i2c_driver(nca9539_driver); diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 7917ac8f7100..a46992b65a32 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,7 +23,8 @@ if DRM_ROCKCHIP config ROCKCHIP_DRM_DEBUG bool "Rockchip DRM debug" - depends on DEBUG_FS + default y if !ROCKCHIP_MINI_KERNEL + depends on DEBUG_FS && NO_GKI help This option add a debug node to dump buf from userspace dump buffer store at: /data diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index a53d405e74e7..79e2a3e8a697 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include @@ -449,6 +451,8 @@ struct dw_dp { struct work_struct hpd_work; struct gpio_desc *hpd_gpio; bool force_hpd; + bool usbdp_hpd; + bool dynamic_pd_ctrl; struct dw_dp_hotplug hotplug; struct mutex irq_lock; @@ -500,6 +504,7 @@ struct dw_dp { struct rockchip_dp_aux_client *aux_client; struct drm_info_list *debugfs_files; + struct typec_mux_dev *mux; }; struct dw_dp_state { @@ -1126,7 +1131,7 @@ static bool dw_dp_bandwidth_ok(struct dw_dp *dp, return true; } -static bool dw_dp_detect(struct dw_dp *dp) +static bool dw_dp_detect_no_power(struct dw_dp *dp) { u32 value; int ret; @@ -1134,6 +1139,9 @@ static bool dw_dp_detect(struct dw_dp *dp) if (dp->hpd_gpio) return gpiod_get_value_cansleep(dp->hpd_gpio); + if (dp->usbdp_hpd) + return dp->hotplug.status; + ret = regmap_read_poll_timeout(dp->regmap, DPTX_HPD_STATUS, value, FIELD_GET(HPD_STATE, value) != SOURCE_STATE_UNPLUG, 100, 3000); @@ -1145,6 +1153,20 @@ static bool dw_dp_detect(struct dw_dp *dp) return FIELD_GET(HPD_STATE, value) == SOURCE_STATE_PLUG; } +static bool dw_dp_detect(struct dw_dp *dp) +{ + bool detected; + + pm_runtime_get_sync(dp->dev); + + detected = dw_dp_detect_no_power(dp); + + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); + + return detected; +} + static enum drm_connector_status dw_dp_connector_detect(struct drm_connector *connector, bool force) { @@ -2840,9 +2862,9 @@ static irqreturn_t dw_dp_hpd_irq_handler(int irq, void *arg) static void dw_dp_hpd_init(struct dw_dp *dp) { - dp->hotplug.status = dw_dp_detect(dp); + dp->hotplug.status = dw_dp_detect_no_power(dp); - if (dp->hpd_gpio || dp->force_hpd) { + if (dp->hpd_gpio || dp->force_hpd || dp->usbdp_hpd) { regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD, FIELD_PREP(FORCE_HPD, 1)); return; @@ -3077,19 +3099,23 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, if (WARN_ON(msg->size > 16)) return -E2BIG; + pm_runtime_get_sync(dp->dev); + phy_set_mode_ext(dp->phy, PHY_MODE_DP, 0); + switch (msg->request & ~DP_AUX_I2C_MOT) { case DP_AUX_NATIVE_WRITE: case DP_AUX_I2C_WRITE: case DP_AUX_I2C_WRITE_STATUS_UPDATE: ret = dw_dp_aux_write_data(dp, msg->buffer, msg->size); if (ret < 0) - return ret; + goto out; break; case DP_AUX_NATIVE_READ: case DP_AUX_I2C_READ: break; default: - return -EINVAL; + ret = -EINVAL; + goto out; } if (msg->size > 0) @@ -3103,12 +3129,15 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, status = wait_for_completion_timeout(&dp->complete, timeout); if (!status) { dev_dbg(dp->dev, "timeout waiting for AUX reply\n"); - return -ETIMEDOUT; + ret = -ETIMEDOUT; + goto out; } regmap_read(dp->regmap, DPTX_AUX_STATUS, &value); - if (value & AUX_TIMEOUT) - return -ETIMEDOUT; + if (value & AUX_TIMEOUT) { + ret = -ETIMEDOUT; + goto out; + } msg->reply = FIELD_GET(AUX_STATUS, value); @@ -3116,15 +3145,21 @@ static ssize_t dw_dp_aux_transfer(struct drm_dp_aux *aux, if (msg->request & DP_AUX_I2C_READ) { size_t count = FIELD_GET(AUX_BYTES_READ, value) - 1; - if (count != msg->size) - return -EBUSY; + if (count != msg->size) { + ret = -EBUSY; + goto out; + } ret = dw_dp_aux_read_data(dp, msg->buffer, count); if (ret < 0) - return ret; + goto out; } } +out: + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); + return ret; } @@ -3688,6 +3723,8 @@ static void dw_dp_mst_encoder_atomic_enable(struct drm_encoder *encoder, int ret; bool first_mst_stream; + pm_runtime_get_sync(dp->dev); + drm_mode_copy(m, &crtc_state->adjusted_mode); first_mst_stream = dp->active_mst_links == 0; @@ -3846,6 +3883,8 @@ static void dw_dp_mst_encoder_atomic_disable(struct drm_encoder *encoder, dw_dp_reset(dp); } + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); } static int dw_dp_mst_encoder_atomic_check(struct drm_encoder *encoder, @@ -4302,6 +4341,8 @@ static void dw_dp_bridge_atomic_pre_enable(struct drm_bridge *bridge, struct drm_crtc_state *crtc_state = bridge->encoder->crtc->state; struct drm_display_mode *m = &video->mode; + pm_runtime_get_sync(dp->dev); + drm_mode_copy(m, &crtc_state->adjusted_mode); if (dp->split_mode || dp->dual_connector_split) @@ -4319,6 +4360,9 @@ dw_dp_bridge_atomic_post_disable(struct drm_bridge *bridge, if (dp->panel) drm_panel_unprepare(dp->panel); + + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); } static bool dw_dp_needs_link_retrain(struct dw_dp *dp) @@ -5081,6 +5125,7 @@ static int dw_dp_audio_hw_params(struct device *dev, void *data, clk_prepare_enable(audio->spdif_clk); clk_prepare_enable(audio->i2s_clk); + pm_runtime_get_sync(dp->dev); regmap_update_bits(dp->regmap, DPTX_AUD_CONFIG1_N(audio->id), AUDIO_DATA_IN_EN | NUM_CHANNELS | AUDIO_DATA_WIDTH | AUDIO_INF_SELECT, @@ -5088,6 +5133,8 @@ static int dw_dp_audio_hw_params(struct device *dev, void *data, FIELD_PREP(NUM_CHANNELS, num_channels) | FIELD_PREP(AUDIO_DATA_WIDTH, params->sample_width) | FIELD_PREP(AUDIO_INF_SELECT, audio_inf_select)); + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); /* Wait for inf switch */ usleep_range(20, 40); @@ -5148,7 +5195,9 @@ static int dw_dp_audio_startup(struct device *dev, void *data) { struct dw_dp *dp = dev_get_drvdata(dev); struct dw_dp_audio *audio = (struct dw_dp_audio *)data; + int ret = 0; + pm_runtime_get_sync(dp->dev); regmap_update_bits(dp->regmap, DPTX_SDP_VERTICAL_CTRL_N(audio->id), EN_AUDIO_STREAM_SDP | EN_AUDIO_TIMESTAMP_SDP, FIELD_PREP(EN_AUDIO_STREAM_SDP, 1) | @@ -5156,8 +5205,11 @@ static int dw_dp_audio_startup(struct device *dev, void *data) regmap_update_bits(dp->regmap, DPTX_SDP_HORIZONTAL_CTRL_N(audio->id), EN_AUDIO_STREAM_SDP, FIELD_PREP(EN_AUDIO_STREAM_SDP, 1)); + ret = dw_dp_audio_infoframe_send(dp, audio); + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); - return dw_dp_audio_infoframe_send(dp, audio); + return ret; } static void dw_dp_audio_shutdown(struct device *dev, void *data) @@ -5165,8 +5217,11 @@ static void dw_dp_audio_shutdown(struct device *dev, void *data) struct dw_dp *dp = dev_get_drvdata(dev); struct dw_dp_audio *audio = (struct dw_dp_audio *)data; + pm_runtime_get_sync(dp->dev); regmap_update_bits(dp->regmap, DPTX_AUD_CONFIG1_N(audio->id), AUDIO_DATA_IN_EN, FIELD_PREP(AUDIO_DATA_IN_EN, 0)); + pm_runtime_mark_last_busy(dp->dev); + pm_runtime_put_autosuspend(dp->dev); if (audio->format == AFMT_SPDIF) clk_disable_unprepare(audio->spdif_clk); @@ -5448,8 +5503,13 @@ static int dw_dp_bind(struct device *dev, struct device *master, void *data) dp->aux.transfer = dw_dp_sim_aux_transfer; } + pm_runtime_use_autosuspend(dp->dev); + pm_runtime_set_autosuspend_delay(dp->dev, 500); pm_runtime_enable(dp->dev); - pm_runtime_get_sync(dp->dev); + if (!dp->dynamic_pd_ctrl) + pm_runtime_get_sync(dp->dev); + else + phy_set_mode_ext(dp->phy, PHY_MODE_DP, 1); enable_irq(dp->irq); if (dp->hpd_gpio) @@ -5472,7 +5532,9 @@ static void dw_dp_unbind(struct device *dev, struct device *master, void *data) disable_irq(dp->hpd_irq); disable_irq(dp->irq); - pm_runtime_put(dp->dev); + if (!dp->dynamic_pd_ctrl) + pm_runtime_put(dp->dev); + pm_runtime_dont_use_autosuspend(dp->dev); pm_runtime_disable(dp->dev); drm_encoder_cleanup(&dp->encoder); @@ -5597,6 +5659,65 @@ static int dw_dp_get_port_node(struct dw_dp *dp) return 0; } +static int dw_dp_typec_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) +{ + struct dw_dp *dp = typec_mux_get_drvdata(mux); + + mutex_lock(&dp->irq_lock); + if (state->alt && state->alt->svid == USB_TYPEC_DP_SID) { + struct typec_displayport_data *data = state->data; + + if (!data) { + dev_dbg(dp->dev, "hotunplug from the usbdp\n"); + dp->hotplug.long_hpd = true; + dp->hotplug.status = false; + schedule_work(&dp->hpd_work); + } else if (data->status & DP_STATUS_IRQ_HPD) { + dev_dbg(dp->dev, "IRQ from the usbdp\n"); + dp->hotplug.long_hpd = false; + dp->hotplug.status = true; + schedule_work(&dp->hpd_work); + } else if (data->status & DP_STATUS_HPD_STATE) { + dev_dbg(dp->dev, "hotplug from the usbdp\n"); + dp->hotplug.long_hpd = true; + dp->hotplug.status = true; + schedule_work(&dp->hpd_work); + } else { + dev_dbg(dp->dev, "hotunplug from the usbdp\n"); + dp->hotplug.long_hpd = true; + dp->hotplug.status = false; + schedule_work(&dp->hpd_work); + } + } + mutex_unlock(&dp->irq_lock); + + return 0; +} + +static int dw_dp_setup_typec_mux(struct dw_dp *dp) +{ + struct typec_mux_desc mux_desc = {}; + + mux_desc.drvdata = dp; + mux_desc.fwnode = dev_fwnode(dp->dev); + mux_desc.set = dw_dp_typec_mux_set; + + dp->mux = typec_mux_register(dp->dev, &mux_desc); + if (IS_ERR(dp->mux)) { + dev_err(dp->dev, "Error register typec mux: %ld\n", PTR_ERR(dp->mux)); + return PTR_ERR(dp->mux); + } + + return 0; +} + +static void dw_dp_typec_mux_unregister(void *data) +{ + struct dw_dp *dp = data; + + typec_mux_unregister(dp->mux); +} + static int dw_dp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; @@ -5718,6 +5839,20 @@ static int dw_dp_probe(struct platform_device *pdev) if (ret) return ret; + if (device_property_present(dev, "svid")) { + ret = dw_dp_setup_typec_mux(dp); + if (ret) + return ret; + + ret = devm_add_action_or_reset(dev, dw_dp_typec_mux_unregister, dp); + if (ret) + return ret; + dp->usbdp_hpd = true; + } + + if (dp->hpd_gpio || dp->force_hpd || dp->usbdp_hpd) + dp->dynamic_pd_ctrl = true; + dp->irq = platform_get_irq(pdev, 0); if (dp->irq < 0) return dp->irq; diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c index f43c588b76f3..f95ffb6c69a1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,21 @@ #define to_rockchip_crtc(x) container_of(x, struct rockchip_crtc, crtc) +/** + * struct vop_dump_info - vop dump plane info structure + * + * Store plane info used to write display data to /data/vop_buf/ + * + */ +struct vop_dump_info { + /* @win_name human readable vop win name */ + const char *win_name; + /* @fb: DRM frame buffer */ + struct drm_framebuffer *fb; + /* @src: source coordinates of the plane (in 16.16)*/ + struct drm_rect *src; +}; + static int temp_pow(int sum, int n) { int i; @@ -37,93 +53,88 @@ static int temp_pow(int sum, int n) return sum; } -static int get_afbc_size(uint32_t width, uint32_t height, uint32_t bpp) -{ - uint32_t h_alignment = 16; - uint32_t n_blocks; - uint32_t hdr_size; - uint32_t size; - - height = ALIGN(height, h_alignment); - n_blocks = width * height / AFBC_SUPERBLK_PIXELS; - hdr_size = ALIGN(n_blocks * AFBC_HEADER_SIZE, AFBC_HDR_ALIGN); - - size = hdr_size + n_blocks * ALIGN(bpp * AFBC_SUPERBLK_PIXELS / 8, AFBC_SUPERBLK_ALIGNMENT); - - return size; -} - -int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_count) +static int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_count) { + struct iosys_map map[DRM_FORMAT_MAX_PLANES]; + struct iosys_map data[DRM_FORMAT_MAX_PLANES]; + struct drm_framebuffer *fb = dump_info->fb; + int ret; int flags; - int bpp; const char *ptr; - char file_name[100]; + char file_name[128]; char format_name[5]; - int width; - size_t size, uv_size = 0; - void *kvaddr, *kvaddr_origin; + void *kvaddr; struct file *file; loff_t pos = 0; + struct drm_gem_object *obj = dump_info->fb->obj[0]; + struct rockchip_gem_object *rk_obj = to_rockchip_obj(obj); - snprintf(file_name, sizeof(file_name), "%p4cc", &dump_info->format->format); + snprintf(file_name, sizeof(file_name), "%p4cc", &dump_info->fb->format->format); strscpy(format_name, file_name, 5); - bpp = rockchip_drm_get_bpp(dump_info->format); - if (!bpp) { - DRM_WARN("invalid bpp %d\n", bpp); - return 0; + flags = O_RDWR | O_CREAT; + snprintf(file_name, 100, "%s/%s_fb-%dx%d_stride-%d_offset-%dx%d_act-%dx%d_%s%s_%d.bin", + DUMP_BUF_PATH, dump_info->win_name, dump_info->fb->width, dump_info->fb->height, + dump_info->fb->pitches[0], dump_info->src->x1 >> 16, dump_info->src->y1 >> 16, + drm_rect_width(dump_info->src) >> 16, drm_rect_height(dump_info->src) >> 16, + format_name, rockchip_drm_modifier_to_string(dump_info->fb->modifier), frame_count); + + ret = drm_gem_fb_begin_cpu_access(fb, DMA_FROM_DEVICE); + if (ret) + return ret; + + ret = drm_gem_fb_vmap(fb, map, data); + if (ret) { + DRM_ERROR("Failed to vmap() buffer\n"); + goto out_drm_gem_fb_end_cpu_access; } - if (dump_info->yuv_format) { - u8 hsub = dump_info->format->hsub; - u8 vsub = dump_info->format->vsub; - - width = dump_info->pitches * 8 / bpp; - flags = O_RDWR | O_CREAT | O_APPEND; - uv_size = (width * dump_info->height * bpp >> 3) * 2 / hsub / vsub; - snprintf(file_name, 100, "%s/video%d_%d_%s.%s", DUMP_BUF_PATH, - width, dump_info->height, format_name, - "bin"); - } else { - width = dump_info->pitches * 8 / bpp; - flags = O_RDWR | O_CREAT; - snprintf(file_name, 100, "%s/win%d_area%d_%dx%d_%s%s%d.%s", - DUMP_BUF_PATH, dump_info->win_id, - dump_info->area_id, width, dump_info->height, - format_name, dump_info->AFBC_flag ? - "_AFBC_" : "_", frame_count, "bin"); - } - kvaddr = vmap(dump_info->pages, dump_info->num_pages, VM_MAP, - pgprot_writecombine(PAGE_KERNEL)); - kvaddr_origin = kvaddr; - if (!kvaddr) - DRM_ERROR("failed to vmap() buffer\n"); - else - kvaddr += dump_info->offset; - - if (dump_info->AFBC_flag) - size = get_afbc_size(width, dump_info->height, bpp); - else - size = (width * dump_info->height * bpp >> 3) + uv_size; - + kvaddr = data[0].vaddr; ptr = file_name; file = filp_open(ptr, flags, 0644); if (!IS_ERR(file)) { - kernel_write(file, kvaddr, size, &pos); + kernel_write(file, kvaddr, rk_obj->size, &pos); DRM_INFO("dump file name is:%s\n", file_name); fput(file); } else { DRM_INFO("open %s failed\n", ptr); } - vunmap(kvaddr_origin); + + drm_gem_fb_vunmap(fb, map); +out_drm_gem_fb_end_cpu_access: + drm_gem_fb_end_cpu_access(fb, DMA_FROM_DEVICE); + + return 0; +} + +int rockchip_drm_crtc_dump_plane_buffer(struct drm_crtc *crtc) +{ + struct rockchip_crtc *rockchip_crtc = container_of(crtc, struct rockchip_crtc, crtc); + struct drm_plane *plane; + struct drm_plane_state *pstate; + struct drm_framebuffer *fb; + struct vop_dump_info dump_info; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + pstate = plane->state; + fb = pstate->fb; + if (!fb) + continue; + + dump_info.win_name = plane->name; + dump_info.fb = fb; + dump_info.src = &pstate->src; + + rockchip_drm_dump_plane_buffer(&dump_info, rockchip_crtc->vop_dump_frame_count); + } + rockchip_crtc->vop_dump_frame_count++; return 0; } static int rockchip_drm_dump_buffer_show(struct seq_file *m, void *data) { - seq_puts(m, " echo enable > Enable dump feature\n"); + seq_puts(m, "VOP dump buffer version: v2.0.0\n"); seq_puts(m, " echo dump > Immediately dump the current frame\n"); seq_puts(m, " echo dumpon > dump to start vop keep dumping\n"); seq_puts(m, " echo dumpoff > Disable dump feature and stop keep dumping\n"); @@ -148,13 +159,9 @@ rockchip_drm_dump_buffer_write(struct file *file, const char __user *ubuf, struct drm_crtc *crtc = m->private; char buf[14] = {}; int dump_times = 0; - struct vop_dump_list *pos, *n; int i = 0; struct rockchip_crtc *rockchip_crtc = to_rockchip_crtc(crtc); - if (!rockchip_crtc->vop_dump_list_init_flag) - return -EPERM; - if (len > sizeof(buf) - 1) return -EINVAL; if (copy_from_user(buf, ubuf, len)) @@ -176,17 +183,9 @@ rockchip_drm_dump_buffer_write(struct file *file, const char __user *ubuf, rockchip_crtc->vop_dump_times = dump_times; } else { drm_modeset_lock_all(crtc->dev); - list_for_each_entry_safe(pos, n, - &rockchip_crtc->vop_dump_list_head, - entry) { - rockchip_drm_dump_plane_buffer(&pos->dump_info, - rockchip_crtc->frame_count); - } + rockchip_drm_crtc_dump_plane_buffer(crtc); drm_modeset_unlock_all(crtc->dev); - rockchip_crtc->frame_count++; } - } else if (strncmp(buf, "enable", 6) == 0) { - rockchip_crtc->vop_dump_status = DUMP_ENABLE; } else { return -EINVAL; } @@ -211,9 +210,8 @@ int rockchip_drm_add_dump_buffer(struct drm_crtc *crtc, struct dentry *root) vop_dump_root = debugfs_create_dir("vop_dump", root); rockchip_crtc->vop_dump_status = DUMP_DISABLE; - rockchip_crtc->vop_dump_list_init_flag = false; rockchip_crtc->vop_dump_times = 0; - rockchip_crtc->frame_count = 0; + rockchip_crtc->vop_dump_frame_count = 0; ent = debugfs_create_file("dump", 0644, vop_dump_root, crtc, &rockchip_drm_dump_buffer_fops); if (!ent) { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h index ec104feab808..fbd3b66d11c4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h @@ -7,60 +7,20 @@ #ifndef ROCKCHIP_DRM_DEBUGFS_H #define ROCKCHIP_DRM_DEBUGFS_H -/** - * struct vop_dump_info - vop dump plane info structure - * - * Store plane info used to write display data to /data/vop_buf/ - * - */ -struct vop_dump_info { - /* @win_id: vop hard win index */ - u8 win_id; - /* @area_id: vop hard area index inside win */ - u8 area_id; - /* @AFBC_flag: indicate the buffer compress by gpu or not */ - bool AFBC_flag; - /* @yuv_format: indicate yuv format or not */ - bool yuv_format; - /* @pitches: the buffer pitch size */ - u32 pitches; - /* @height: the buffer pitch height */ - u32 height; - /* @info: DRM format info */ - const struct drm_format_info *format; - /* @offset: the buffer offset */ - unsigned long offset; - /* @num_pages: the pages number */ - unsigned long num_pages; - /* @pages: store the buffer all pages */ - struct page **pages; -}; - -/** - * struct vop_dump_list - store all buffer info per frame - * - * one frame maybe multiple buffer, all will be stored here. - * - */ -struct vop_dump_list { - struct list_head entry; - struct vop_dump_info dump_info; -}; +struct vop_dump_info; /** * @DUMP_DISABLE: Disable dump and do not record plane info into list. - * @DUMP_ENABLE: Record plane info into list. * @DUMP_KEEP: Record plane info into list and keep to dump plane. */ enum vop_dump_status { DUMP_DISABLE = 0, - DUMP_ENABLE, DUMP_KEEP }; #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) int rockchip_drm_add_dump_buffer(struct drm_crtc *crtc, struct dentry *root); -int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_count); +int rockchip_drm_crtc_dump_plane_buffer(struct drm_crtc *crtc); int rockchip_drm_debugfs_add_color_bar(struct drm_crtc *crtc, struct dentry *root); #else static inline int @@ -70,7 +30,7 @@ rockchip_drm_add_dump_buffer(struct drm_crtc *crtc, struct dentry *root) } static inline int -rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_count) +rockchip_drm_crtc_dump_plane_buffer(struct drm_crtc *crtc) { return 0; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 85a38ab55f91..b94008ad65fb 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -136,6 +136,21 @@ bool rockchip_drm_is_rfbc(struct drm_plane *plane, u64 modifier) } EXPORT_SYMBOL(rockchip_drm_is_rfbc); +const char *rockchip_drm_modifier_to_string(uint64_t modifier) +{ + switch (modifier) { + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_8x8): + return "_TILE-8x8"; + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE0): + return "_TILE-4x4-M0"; + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE1): + return "_TILE-4x4-M1"; + default: + return drm_is_afbc(modifier) ? "_AFBC" : IS_ROCKCHIP_RFBC_MOD(modifier) ? "_RFBC" : ""; + } +} +EXPORT_SYMBOL(rockchip_drm_modifier_to_string); + /** * rockchip_drm_wait_vact_end * @crtc: CRTC to enable line flag diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 1e32e72769cf..42e194b24574 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -168,16 +168,12 @@ struct rockchip_crtc { #if defined(CONFIG_ROCKCHIP_DRM_DEBUG) /** * @vop_dump_status the status of vop dump control - * @vop_dump_list_head the list head of vop dump list - * @vop_dump_list_init_flag init once * @vop_dump_times control the dump times - * @frme_count the frame of dump buf + * @vop_dump_frame_count the frame of dump buf */ enum vop_dump_status vop_dump_status; - struct list_head vop_dump_list_head; - bool vop_dump_list_init_flag; int vop_dump_times; - int frame_count; + int vop_dump_frame_count; #endif }; @@ -643,6 +639,7 @@ long rockchip_drm_dclk_round_rate(u32 version, struct clk *dclk, unsigned long r int rockchip_drm_dclk_set_rate(u32 version, struct clk *dclk, unsigned long rate); bool rockchip_drm_is_afbc(struct drm_plane *plane, u64 modifier); bool rockchip_drm_is_rfbc(struct drm_plane *plane, u64 modifier); +const char *rockchip_drm_modifier_to_string(uint64_t modifier); __printf(3, 4) void rockchip_drm_dbg(const struct device *dev, enum rockchip_drm_debug_category category, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ad8cf09685e9..9f972b4ad46d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -189,7 +189,6 @@ struct vop_plane_state { unsigned long offset; int pdaf_data_type; bool async_commit; - struct vop_dump_list *planlist; }; struct vop_win { @@ -1973,10 +1972,6 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, plane); struct vop_win *win = to_vop_win(plane); struct vop *vop = to_vop(old_state->crtc); -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_plane_state *vop_plane_state = - to_vop_plane_state(plane->state); -#endif if (!old_state->crtc) return; @@ -1997,11 +1992,6 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, win->win_id == 2) VOP_WIN_SET(vop, win, yrgb_mst, 0); -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - kfree(vop_plane_state->planlist); - vop_plane_state->planlist = NULL; -#endif - spin_unlock(&vop->reg_lock); } @@ -2093,23 +2083,6 @@ static void vop_plane_atomic_update(struct drm_plane *plane, int is_yuv = fb->format->is_yuv; bool afbc_en = false; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_dump_list *planlist; - unsigned long num_pages; - struct page **pages; - struct drm_gem_object *obj; - struct rockchip_gem_object *rk_obj; - - num_pages = 0; - pages = NULL; - obj = fb->obj[0]; - rk_obj = to_rockchip_obj(obj); - if (rk_obj) { - num_pages = rk_obj->num_pages; - pages = rk_obj->pages; - } -#endif - /* * can't update plane when vop is disabled. */ @@ -2267,35 +2240,6 @@ static void vop_plane_atomic_update(struct drm_plane *plane, * actual_w, actual_h) */ vop->is_iommu_needed = true; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - kfree(vop_plane_state->planlist); - vop_plane_state->planlist = NULL; - - planlist = kmalloc(sizeof(*planlist), GFP_KERNEL); - if (planlist) { - planlist->dump_info.AFBC_flag = afbc_en; - planlist->dump_info.area_id = win->area_id; - planlist->dump_info.win_id = win->win_id; - planlist->dump_info.yuv_format = - is_yuv_support(fb->format->format); - planlist->dump_info.num_pages = num_pages; - planlist->dump_info.pages = pages; - planlist->dump_info.offset = vop_plane_state->offset; - planlist->dump_info.pitches = fb->pitches[0]; - planlist->dump_info.height = actual_h; - planlist->dump_info.format = fb->format; - list_add_tail(&planlist->entry, &vop->rockchip_crtc.vop_dump_list_head); - vop_plane_state->planlist = planlist; - } else { - DRM_ERROR("can't alloc a node of planlist %p\n", planlist); - return; - } - if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || - vop->rockchip_crtc.vop_dump_times > 0) { - rockchip_drm_dump_plane_buffer(&planlist->dump_info, vop->rockchip_crtc.frame_count); - vop->rockchip_crtc.vop_dump_times--; - } -#endif } static int vop_plane_atomic_async_check(struct drm_plane *plane, @@ -3060,28 +3004,10 @@ static size_t vop_crtc_bandwidth(struct drm_crtc *crtc, u64 line_bw_mbyte = 0; int cnt = 0, plane_num = 0; struct drm_atomic_state *state = crtc_state->state; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_dump_list *pos, *n; - struct vop *vop = to_vop(crtc); -#endif if (!htotal || !vdisplay) return 0; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - if (!vop->rockchip_crtc.vop_dump_list_init_flag) { - INIT_LIST_HEAD(&vop->rockchip_crtc.vop_dump_list_head); - vop->rockchip_crtc.vop_dump_list_init_flag = true; - } - list_for_each_entry_safe(pos, n, &vop->rockchip_crtc.vop_dump_list_head, entry) { - list_del(&pos->entry); - } - if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || - vop->rockchip_crtc.vop_dump_times > 0) { - vop->rockchip_crtc.frame_count++; - } -#endif - drm_atomic_crtc_state_for_each_plane(plane, crtc_state) plane_num++; @@ -4294,6 +4220,14 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); +#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) + if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || + vop->rockchip_crtc.vop_dump_times > 0) { + rockchip_drm_crtc_dump_plane_buffer(crtc); + vop->rockchip_crtc.vop_dump_times--; + } +#endif + vop_cfg_update(crtc, old_crtc_state); if (!vop->is_iommu_enabled && vop->is_iommu_needed) { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index d7f6f40a7c19..353fdd521f61 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -382,7 +382,6 @@ struct vop2_plane_state { unsigned long offset; int pdaf_data_type; bool async_commit; - struct vop_dump_list *planlist; struct drm_property_blob *dci_data; }; @@ -1973,6 +1972,12 @@ static void vop2_power_domain_put(struct vop2_power_domain *pd) vop2_power_domain_put(pd->parent); } +static void vop2_power_domain_put_sync(struct vop2_power_domain *pd) +{ + vop2_power_domain_put(pd); + vop2_wait_power_domain_off(pd); +} + /* * Called if the pd ref_count reach 0 after 2.5 * seconds. @@ -2620,14 +2625,22 @@ static uint32_t vop2_afbc_transform_offset(struct vop2 *vop2, struct vop2_plane_ if (is_vop3(vop2) && vop2->version != VOP_VERSION_RK3528) { uint32_t vir_height = fb->height; - u8 block_w; + u8 block_w, block_h; - if (IS_ROCKCHIP_RFBC_MOD(fb->modifier)) + if (IS_ROCKCHIP_RFBC_MOD(fb->modifier)) { block_w = 64; - else if (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) + block_h = 4; + } else if (fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8) { block_w = 32; - else + block_h = 8; + } else { block_w = 16; + block_h = 16; + } + if (!IS_ALIGNED(vir_height, block_h)) { + DRM_WARN("FBC fb vir height[%d] should aligned as block height[%d]", vir_height, block_h); + vir_height = ALIGN(vir_height, block_h); + } if (vpstate->xmirror_en) { transform_tmp = ALIGN(act_xoffset + width, block_w); @@ -2636,11 +2649,14 @@ static uint32_t vop2_afbc_transform_offset(struct vop2 *vop2, struct vop2_plane_ transform_xoffset = act_xoffset % block_w; } + if (vpstate->afbc_half_block_en) + block_h /= 2; + if (vpstate->ymirror_en) { transform_tmp = vir_height - act_yoffset - height; - transform_yoffset = transform_tmp % 4; + transform_yoffset = transform_tmp % block_h; } else { - transform_yoffset = act_yoffset % 4; + transform_yoffset = act_yoffset % block_h; } return (transform_xoffset & 0x3f) | ((transform_yoffset & 0x3f) << 16); @@ -4382,6 +4398,41 @@ static void vop2_initial(struct drm_crtc *crtc) * immediately. */ VOP_CTRL_SET(vop2, if_ctrl_cfg_done_imd, 1); + + /* Close dynamic turn on/off rk3588 PD_ESMART and keep esmart pd on when enable */ + if (vop2->version == VOP_VERSION_RK3588) { + struct vop2_power_domain *esmart_pd = vop2_find_pd_by_id(vop2, VOP2_PD_ESMART); + + if (vop2_power_domain_status(esmart_pd)) + esmart_pd->on = true; + else + vop2_power_domain_on(esmart_pd); + + if (vop2->data->nr_dscs) { + struct vop2_dsc *dsc; + int i = 0; + + for (i = 0; i < vop2->data->nr_dscs; i++) { + dsc = &vop2->dscs[i]; + + if (!dsc->pd) + continue; + + if (!vop2_power_domain_status(dsc->pd)) + continue; + + dsc->enabled = VOP_MODULE_GET(vop2, dsc, dsc_en); + + if (dsc->enabled) { + dsc->attach_vp_id = VOP_MODULE_GET(vop2, dsc, + dsc_port_sel); + dsc->pd->vp_mask = BIT(dsc->attach_vp_id); + dsc->pd->on = true; + dsc->pd->ref_count++; + } + } + } + } vop2_layer_map_initial(vop2, current_vp_id); vop2_axi_irqs_enable(vop2); vop2->is_enabled = true; @@ -4987,12 +5038,14 @@ static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, if (dual_channel) { vop2_power_domain_put(vop2->dscs[0].pd); vop2_power_domain_put(vop2->dscs[1].pd); + vop2_wait_power_domain_off(vop2->dscs[0].pd); + vop2_wait_power_domain_off(vop2->dscs[1].pd); vop2->dscs[0].pd->vp_mask = 0; vop2->dscs[1].pd->vp_mask = 0; vop2->dscs[0].attach_vp_id = -1; vop2->dscs[1].attach_vp_id = -1; } else { - vop2_power_domain_put(vop2->dscs[vcstate->dsc_id].pd); + vop2_power_domain_put_sync(vop2->dscs[vcstate->dsc_id].pd); vop2->dscs[vcstate->dsc_id].pd->vp_mask = 0; vop2->dscs[vcstate->dsc_id].attach_vp_id = -1; } @@ -5614,10 +5667,6 @@ static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic struct drm_crtc *crtc; struct vop2_video_port *vp; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop2_plane_state *vpstate = to_vop2_plane_state(plane->state); -#endif - rockchip_drm_dbg(vop2->dev, VOP_DEBUG_PLANE, "%s disable %s\n", win->name, current->comm); @@ -5642,11 +5691,6 @@ static void vop2_plane_atomic_disable(struct drm_plane *plane, struct drm_atomic vp->enabled_win_mask &= ~BIT(win->splice_win->phys_id); } -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - kfree(vpstate->planlist); - vpstate->planlist = NULL; -#endif - spin_unlock(&vop2->reg_lock); } @@ -5801,20 +5845,6 @@ static void rk3588_vop2_win_cfg_axi(struct vop2_win *win) VOP_WIN_SET(vop2, win, axi_uv_id, win->axi_uv_id); } -static const char *modifier_to_string(uint64_t modifier) -{ - switch (modifier) { - case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_8x8): - return "[TILE_8x8]"; - case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE0): - return "[TILE_4x4_M0]"; - case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE1): - return "[TILE_4x4_M1]"; - default: - return drm_is_afbc(modifier) ? "[AFBC]" : IS_ROCKCHIP_RFBC_MOD(modifier) ? "[RFBC]" : ""; - } -} - static void vop3_dci_config(struct vop2_win *win, struct vop2_plane_state *vpstate) { struct drm_plane_state *pstate = &vpstate->base; @@ -6064,7 +6094,7 @@ static void vop2_win_atomic_update(struct vop2_win *win, struct drm_rect *src, s vp->id, win->name, actual_w, actual_h, src->x1 >> 16, src->y1 >> 16, dsp_w, dsp_h, dsp_stx, dsp_sty, vpstate->zpos, - &fb->format->format, modifier_to_string(fb->modifier), + &fb->format->format, rockchip_drm_modifier_to_string(fb->modifier), &vpstate->yrgb_mst, vpstate->fb_size, current->comm); if (vop2->version != VOP_VERSION_RK3568) @@ -6281,29 +6311,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_ struct drm_rect right_wsrc; struct drm_rect right_wdst; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct drm_rect *psrc = &vpstate->src; - bool AFBC_flag = false; - struct vop_dump_list *planlist; - unsigned long num_pages; - struct page **pages; - struct drm_gem_object *obj; - struct rockchip_gem_object *rk_obj; - - num_pages = 0; - pages = NULL; - obj = fb->obj[0]; - rk_obj = to_rockchip_obj(obj); - if (rk_obj) { - num_pages = rk_obj->num_pages; - pages = rk_obj->pages; - } - if (rockchip_afbc(plane, fb->modifier)) - AFBC_flag = true; - else - AFBC_flag = false; -#endif - /* * can't update plane when vop2 is disabled. */ @@ -6341,7 +6348,7 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_ drm_rect_width(&vpstate->dest), drm_rect_height(&vpstate->dest), vpstate->dest.x1, vpstate->dest.y1, vpstate->zpos, &fb->format->format, - modifier_to_string(fb->modifier), &vpstate->yrgb_mst, + rockchip_drm_modifier_to_string(fb->modifier), &vpstate->yrgb_mst, vpstate->fb_size, current->comm); vop2_calc_drm_rect_for_splice(vpstate, &wsrc, &wdst, &right_wsrc, &right_wdst); @@ -6355,34 +6362,6 @@ static void vop2_plane_atomic_update(struct drm_plane *plane, struct drm_atomic_ vop2_win_atomic_update(win, &wsrc, &wdst, pstate); vop2->is_iommu_needed = true; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - kfree(vpstate->planlist); - vpstate->planlist = NULL; - - planlist = kmalloc(sizeof(*planlist), GFP_KERNEL); - if (planlist) { - planlist->dump_info.AFBC_flag = AFBC_flag; - planlist->dump_info.area_id = win->area_id; - planlist->dump_info.win_id = win->win_id; - planlist->dump_info.yuv_format = fb->format->is_yuv; - planlist->dump_info.num_pages = num_pages; - planlist->dump_info.pages = pages; - planlist->dump_info.offset = vpstate->offset; - planlist->dump_info.pitches = fb->pitches[0]; - planlist->dump_info.height = drm_rect_height(psrc) >> 16; - planlist->dump_info.format = fb->format; - list_add_tail(&planlist->entry, &vp->rockchip_crtc.vop_dump_list_head); - vpstate->planlist = planlist; - } else { - DRM_ERROR("can't alloc a node of planlist %p\n", planlist); - return; - } - if (vp->rockchip_crtc.vop_dump_status == DUMP_KEEP || - vp->rockchip_crtc.vop_dump_times > 0) { - rockchip_drm_dump_plane_buffer(&planlist->dump_info, vp->rockchip_crtc.frame_count); - vp->rockchip_crtc.vop_dump_times--; - } -#endif } static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = { @@ -7160,7 +7139,7 @@ static int vop2_plane_info_dump(struct seq_file *s, struct drm_plane *plane) DEBUG_PRINT("\twin_id: %d\n", win->win_id); DEBUG_PRINT("\tformat: %p4cc%s pixel_blend_mode[%d] glb_alpha[0x%x]\n", - &fb->format->format, modifier_to_string(fb->modifier), + &fb->format->format, rockchip_drm_modifier_to_string(fb->modifier), pstate->pixel_blend_mode, vpstate->global_alpha); DEBUG_PRINT("\tcolor: %s[%d] color-encoding[%s] color-range[%s]\n", vpstate->eotf ? "HDR" : "SDR", vpstate->eotf, @@ -7743,28 +7722,10 @@ static size_t vop2_crtc_bandwidth(struct drm_crtc *crtc, u64 line_bw_mbyte = 0; int8_t cnt = 0, plane_num = 0; int i = 0; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_dump_list *pos, *n; - struct vop2_video_port *vp = to_vop2_video_port(crtc); -#endif if (!htotal || !vdisplay) return 0; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - if (!vp->rockchip_crtc.vop_dump_list_init_flag) { - INIT_LIST_HEAD(&vp->rockchip_crtc.vop_dump_list_head); - vp->rockchip_crtc.vop_dump_list_init_flag = true; - } - list_for_each_entry_safe(pos, n, &vp->rockchip_crtc.vop_dump_list_head, entry) { - list_del(&pos->entry); - } - if (vp->rockchip_crtc.vop_dump_status == DUMP_KEEP || - vp->rockchip_crtc.vop_dump_times > 0) { - vp->rockchip_crtc.frame_count++; - } -#endif - for_each_new_plane_in_state(state, plane, pstate, i) { if (pstate->crtc == crtc) plane_num++; @@ -11759,6 +11720,14 @@ static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, struct drm_atomic_stat struct drm_connector_state *conn_state = wb_conn->base.state; bool wb_oneframe_mode = VOP_MODULE_GET(vop2, wb, one_frame_mode); +#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) + if (vp->rockchip_crtc.vop_dump_status == DUMP_KEEP || + vp->rockchip_crtc.vop_dump_times > 0) { + rockchip_drm_crtc_dump_plane_buffer(crtc); + vp->rockchip_crtc.vop_dump_times--; + } +#endif + if (conn_state && conn_state->writeback_job && conn_state->writeback_job->fb && !wb_oneframe_mode) { u16 vtotal = VOP_MODULE_GET(vop2, vp, dsp_vtotal); u32 current_line = vop2_read_vcnt(vp); diff --git a/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c b/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c index 455a9be63124..a6e87dab69b9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c +++ b/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c @@ -133,18 +133,28 @@ EXPORT_SYMBOL(devm_rockchip_panel_notifier_unregister_client); static int rockchip_panel_notifier_register(struct drm_panel *panel, struct rockchip_panel_notifier *pn) { + struct rockchip_panel_notifier *panel_notifier, *next; + int ret = 0; + if (!panel || !pn) return -EINVAL; - pn->panel = panel; - - BLOCKING_INIT_NOTIFIER_HEAD(&pn->nh); - mutex_lock(¬ifier_list_lock); - list_add_tail(&pn->list, ¬ifier_list); + list_for_each_entry_safe(panel_notifier, next, ¬ifier_list, list) { + if (panel_notifier->panel != panel) + continue; + + ret = -EEXIST; + } + if (!ret) { + pn->panel = panel; + BLOCKING_INIT_NOTIFIER_HEAD(&pn->nh); + + list_add_tail(&pn->list, ¬ifier_list); + } mutex_unlock(¬ifier_list_lock); - return 0; + return ret; } static void rockchip_panel_notifier_unregister(struct rockchip_panel_notifier *pn) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index a935e62e0914..927d9ea6c597 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1593,14 +1593,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - i2c->i2c_restart_nb.notifier_call = rk3x_i2c_restart_notify; - i2c->i2c_restart_nb.priority = 255; - ret = register_restart_handler(&i2c->i2c_restart_nb); - if (ret) { - dev_err(&pdev->dev, "failed to setup i2c restart handler.\n"); - return ret; - } - i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); @@ -1720,12 +1712,22 @@ static int rk3x_i2c_probe(struct platform_device *pdev) i2c->autostop_supported = true; } + i2c->i2c_restart_nb.notifier_call = rk3x_i2c_restart_notify; + i2c->i2c_restart_nb.priority = 255; + ret = register_restart_handler(&i2c->i2c_restart_nb); + if (ret) { + dev_err(&pdev->dev, "failed to setup i2c restart handler.\n"); + goto err_clk_notifier; + } + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) - goto err_clk_notifier; + goto err_register_restart_handler; return 0; +err_register_restart_handler: + unregister_restart_handler(&i2c->i2c_restart_nb); err_clk_notifier: clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); err_pclk: @@ -1741,8 +1743,8 @@ static int rk3x_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); - clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); unregister_restart_handler(&i2c->i2c_restart_nb); + clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); clk_unprepare(i2c->pclk); clk_unprepare(i2c->clk); diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c index ae4ebd53c28d..1023f607886a 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c @@ -52,6 +52,10 @@ * 2. mode vc initialization when vc-array isn't configured * 3. fix the issue of mutex deadlock during hot plug * + * V3.07.00 + * 1. v4l2 ioctl add command to support quick stream setting + * 2. dev_pm_ops add suspend and resume for system sleep + * */ #include #include @@ -79,7 +83,7 @@ #include "maxim2c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x07, 0x00) #define MAXIM2C_NAME "maxim2c" @@ -420,9 +424,43 @@ static int maxim2c_runtime_suspend(struct device *dev) #endif /* MAXIM2C_LOCAL_DES_ON_OFF_EN */ } +static int __maybe_unused maxim2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + maxim2c_t *maxim2c = v4l2_get_subdevdata(sd); + int ret = 0; + + dev_info(dev, "maxim2c resume\n"); + +#if (MAXIM2C_LOCAL_DES_ON_OFF_EN == 0) +#if MAXIM2C_TEST_PATTERN + ret = maxim2c_pattern_hw_init(maxim2c); + if (ret) { + dev_err(dev, "test pattern hw init error\n"); + return ret; + } +#else + ret = maxim2c_module_hw_init(maxim2c); + if (ret) { + dev_err(dev, "maxim2c module hw init error\n"); + return ret; + } +#endif /* MAXIM2C_TEST_PATTERN */ +#endif /* MAXIM2C_LOCAL_DES_ON_OFF_EN */ + + return 0; +} + +static int __maybe_unused maxim2c_suspend(struct device *dev) +{ + return 0; +} + static const struct dev_pm_ops maxim2c_pm_ops = { SET_RUNTIME_PM_OPS( maxim2c_runtime_suspend, maxim2c_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(maxim2c_suspend, maxim2c_resume) }; static void maxim2c_module_data_init(maxim2c_t *maxim2c) diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c index 09f46e9db148..9c6d53e3e5be 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c @@ -436,6 +436,7 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; dev_dbg(&maxim2c->client->dev, "ioctl cmd = 0x%08x\n", cmd); @@ -473,6 +474,17 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ch_info = (struct rkmodule_channel_info *)arg; ret = maxim2c_get_channel_info(maxim2c, ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + stream = *((u32 *)arg); + + if (stream) + ret = maxim2c_mipi_csi_output(maxim2c, true); + else + ret = maxim2c_mipi_csi_output(maxim2c, false); + + dev_info(&maxim2c->client->dev, + "set quick stream = %d: mipi csi output ret = %ld\n", stream, ret); + break; default: ret = -ENOIOCTLCMD; break; @@ -491,6 +503,7 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; switch (cmd) { @@ -598,6 +611,13 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, } kfree(ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + ret = copy_from_user(&stream, up, sizeof(u32)); + if (!ret) + ret = maxim2c_ioctl(sd, cmd, &stream); + else + ret = -EFAULT; + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c index 11a2c49324d8..6e15578fb1d9 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c @@ -75,6 +75,10 @@ * 2. mode vc initialization when vc-array isn't configured * 3. fix the issue of mutex deadlock during hot plug * + * V3.07.00 + * 1. v4l2 ioctl add command to support quick stream setting + * 2. dev_pm_ops add suspend and resume for system sleep + * */ #include #include @@ -102,7 +106,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x07, 0x00) #define MAXIM4C_NAME "maxim4c" @@ -495,9 +499,43 @@ static int maxim4c_runtime_suspend(struct device *dev) #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ } +static int __maybe_unused maxim4c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + maxim4c_t *maxim4c = v4l2_get_subdevdata(sd); + int ret = 0; + + dev_info(dev, "maxim4c resume\n"); + +#if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0) +#if MAXIM4C_TEST_PATTERN + ret = maxim4c_pattern_hw_init(maxim4c); + if (ret) { + dev_err(dev, "test pattern hw init error\n"); + return ret; + } +#else + ret = maxim4c_module_hw_init(maxim4c); + if (ret) { + dev_err(dev, "maxim4c module hw init error\n"); + return ret; + } +#endif /* MAXIM4C_TEST_PATTERN */ +#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ + + return 0; +} + +static int __maybe_unused maxim4c_suspend(struct device *dev) +{ + return 0; +} + static const struct dev_pm_ops maxim4c_pm_ops = { SET_RUNTIME_PM_OPS( maxim4c_runtime_suspend, maxim4c_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(maxim4c_suspend, maxim4c_resume) }; static void maxim4c_module_data_init(maxim4c_t *maxim4c) diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c index c0906470039b..0b87827f14f9 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c @@ -436,6 +436,7 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; dev_dbg(&maxim4c->client->dev, "ioctl cmd = 0x%08x\n", cmd); @@ -473,6 +474,17 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ch_info = (struct rkmodule_channel_info *)arg; ret = maxim4c_get_channel_info(maxim4c, ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + stream = *((u32 *)arg); + + if (stream) + ret = maxim4c_mipi_csi_output(maxim4c, true); + else + ret = maxim4c_mipi_csi_output(maxim4c, false); + + dev_info(&maxim4c->client->dev, + "set quick stream = %d: mipi csi output ret = %ld\n", stream, ret); + break; default: ret = -ENOIOCTLCMD; break; @@ -491,6 +503,7 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; switch (cmd) { @@ -598,6 +611,13 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, } kfree(ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + ret = copy_from_user(&stream, up, sizeof(u32)); + if (!ret) + ret = maxim4c_ioctl(sd, cmd, &stream); + else + ret = -EFAULT; + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 6e626eda25f5..dcd060ee4106 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -274,6 +274,15 @@ static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { static const struct rk628_csi_mode supported_modes[] = { { + .width = 4096, + .height = 2160, + .max_fps = { + .numerator = 10000, + .denominator = 600000, + }, + .hts_def = 4400, + .vts_def = 2250, + }, { .width = 3840, .height = 2160, .max_fps = { diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index db6a7ca3f237..d853c40c915b 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -12179,11 +12179,10 @@ static void rkcif_sensor_quick_streaming_cb(void *data) RKMODULE_SET_QUICK_STREAM, &on); } -static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) +static int rkcif_terminal_sensor_set_stream(struct rkcif_device *cif_dev, int on) { struct rkcif_pipeline *p = &cif_dev->pipe; struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; - struct sditf_priv *priv = cif_dev->sditf[0]; int i = 0; int ret = 0; @@ -12214,6 +12213,15 @@ static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) } } + return ret; +} + +static int rkcif_sditf_sensor_set_stream(struct rkcif_device *cif_dev, int on) +{ + struct sditf_priv *priv = cif_dev->sditf[0]; + int i = 0; + int ret = 0; + if (priv && cif_dev->sditf_cnt > 1) { if (cif_dev->is_camera_over_bridge) { for (i = 0; i < cif_dev->sditf_cnt; i++) { @@ -12241,6 +12249,22 @@ static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) } } } + + return ret; +} + +static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) +{ + int ret = 0; + + if (on) { + ret |= rkcif_terminal_sensor_set_stream(cif_dev, on); + ret |= rkcif_sditf_sensor_set_stream(cif_dev, on); + } else { + ret |= rkcif_sditf_sensor_set_stream(cif_dev, on); + ret |= rkcif_terminal_sensor_set_stream(cif_dev, on); + } + return ret; } diff --git a/drivers/media/platform/rockchip/isp/hw.c b/drivers/media/platform/rockchip/isp/hw.c index df9d2602c806..cdb7d4e97d69 100644 --- a/drivers/media/platform/rockchip/isp/hw.c +++ b/drivers/media/platform/rockchip/isp/hw.c @@ -417,21 +417,6 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) }, { .base = MI_WR_CTRL, .shd = MI_WR_CTRL_SHD, - }, { - .base = ISP39_W3A_AEBIG_ADDR, - .shd = ISP39_W3A_AEBIG_ADDR_SHD, - }, { - .base = ISP39_W3A_AE0_ADDR, - .shd = ISP39_W3A_AE0_ADDR_SHD, - }, { - .base = ISP39_W3A_AF_ADDR, - .shd = ISP39_W3A_AF_ADDR_SHD, - }, { - .base = ISP39_W3A_AWB_ADDR, - .shd = ISP39_W3A_AWB_ADDR_SHD, - }, { - .base = ISP39_W3A_PDAF_ADDR, - .shd = ISP39_W3A_PDAF_ADDR_SHD, } }; @@ -546,14 +531,6 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) reg = reg_buf + ISP32_BP_RESIZE_CTRL; if (*reg & 0xf) writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + ISP32_BP_RESIZE_CTRL); - if (dev->isp_ver == ISP_V39) { - reg = reg_buf + ISP39_W3A_CTRL0; - if (*reg) - writel(*reg | ISP39_W3A_FORCE_UPD, base + ISP39_W3A_CTRL0); - reg = reg_buf + ISP39_VI3A_CTRL0; - if (*reg) - writel(*reg | ISP39_W3A_FORCE_UPD, base + ISP39_VI3A_CTRL0); - } /* update mi and isp, base_reg will update to shd_reg */ writel(CIF_MI_INIT_SOFT_UPD, base + MI_WR_INIT); @@ -583,6 +560,26 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) if (dev->is_single) { rkisp_params_cfgsram(&isp->params_vdev, false, true); + if (dev->isp_ver == ISP_V39) { + reg = reg_buf + ISP3X_ISP_CTRL1; + *reg |= ISP3X_DHAZ_FST_FRAME; + writel(*reg, dev->base_addr + ISP3X_ISP_CTRL1); + reg = reg_buf + ISP3X_BAY3D_CTRL; + if (*reg & 1) + writel(*reg | BIT(31), dev->base_addr + ISP3X_BAY3D_CTRL); + /* w3a addr will update by ISP_CFG_UPD */ + reg = reg_buf + ISP39_W3A_AEBIG_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AEBIG_ADDR); + reg = reg_buf + ISP39_W3A_AE0_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AE0_ADDR); + reg = reg_buf + ISP39_W3A_AF_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AF_ADDR); + reg = reg_buf + ISP39_W3A_AWB_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AWB_ADDR); + reg = reg_buf + ISP39_W3A_PDAF_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_PDAF_ADDR); + } + reg = reg_buf + ISP_CTRL; *reg |= CIF_ISP_CTRL_ISP_ENABLE | CIF_ISP_CTRL_ISP_CFG_UPD | @@ -590,6 +587,19 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) writel(*reg, dev->base_addr + ISP_CTRL); if (dev->unite == ISP_UNITE_TWO) writel(*reg, dev->base_next_addr + ISP_CTRL); + + if (dev->isp_ver == ISP_V39) { + reg = reg_buf + ISP39_W3A_AEBIG_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AEBIG_ADDR); + reg = reg_buf + ISP39_W3A_AE0_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AE0_ADDR); + reg = reg_buf + ISP39_W3A_AF_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AF_ADDR); + reg = reg_buf + ISP39_W3A_AWB_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AWB_ADDR); + reg = reg_buf + ISP39_W3A_PDAF_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_PDAF_ADDR); + } } } diff --git a/drivers/media/platform/rockchip/isp/isp_params_v39.c b/drivers/media/platform/rockchip/isp/isp_params_v39.c index a812103612de..6ae6ce0b6d0e 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v39.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v39.c @@ -2367,9 +2367,7 @@ isp_dhaz_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, if (arg->hist_iir_wr) { for (i = 0; i < priv_val->dhaz_blk_num; i++) { - val = ISP39_DHAZ_IIR_WR_ID(i); - if (!i) - val |= ISP39_DHAZ_IIR_WR_CLEAR; + val = ISP39_DHAZ_IIR_WR_ID(i) | ISP39_DHAZ_IIR_WR_CLEAR; isp3_param_write_direct(params_vdev, val, ISP39_DHAZ_HIST_RW); for (j = 0; j < ISP39_DHAZ_HIST_IIR_NUM / 2; j++) { val = ISP_PACK_2SHORT(arg->hist_iir[i][2 * j], arg->hist_iir[i][2 * j + 1]); @@ -3383,10 +3381,6 @@ isp_bay3d_enable(struct rkisp_isp_params_vdev *params_vdev, bool en, u32 id) value = priv_val->buf_gain.dma_addr + value * id; isp3_param_write(params_vdev, value, ISP3X_MI_GAIN_WR_BASE, id); isp3_param_write(params_vdev, value, ISP3X_MI_RAW0_RD_BASE, id); - - value = isp3_param_read_cache(params_vdev, ISP3X_GAIN_CTRL, id); - value |= ISP3X_GAIN_2DDR_MODE(1) | ISP3X_GAIN_2DDR_EN; - isp3_param_write(params_vdev, value, ISP3X_GAIN_CTRL, id); } bay3d_ctrl |= ISP39_MODULE_EN; @@ -3638,6 +3632,11 @@ isp_yuvme_enable(struct rkisp_isp_params_vdev *params_vdev, bool en, u32 id) return; if (en) { + value = isp3_param_read_cache(params_vdev, ISP3X_BAY3D_CTRL, id); + if (!(value & ISP39_MODULE_EN)) { + dev_err(ispdev->dev, "yuvme need bay3d enable together\n"); + return; + } if (!priv_val->buf_3dnr_cur.mem_priv) { dev_err(ispdev->dev, "no yuvme cur buffer available\n"); return; @@ -3974,8 +3973,6 @@ void __isp_isr_other_en(struct rkisp_isp_params_vdev *params_vdev, mask = ISP39_MODULE_YNR | ISP39_MODULE_CNR | ISP39_MODULE_SHARP; if ((module_ens & mask) && ((module_ens & mask) != mask)) dev_err(params_vdev->dev->dev, "ynr cnr sharp no enable together\n"); - if (module_ens & ISP39_MODULE_YUVME && !(module_ens & ISP39_MODULE_BAY3D)) - dev_err(params_vdev->dev->dev, "yuvme need bay3d enable together\n"); v4l2_dbg(4, rkisp_debug, ¶ms_vdev->dev->v4l2_dev, "%s id:%d seq:%d module_en_update:0x%llx module_ens:0x%llx\n", __func__, id, new_params->frame_id, module_en_update, module_ens); @@ -5105,7 +5102,7 @@ rkisp_params_isr_v39(struct rkisp_isp_params_vdev *params_vdev, u32 isp_mis) } } - if ((isp_mis & CIF_ISP_FRAME) && !params_vdev->rdbk_times) + if ((isp_mis & CIF_ISP_FRAME) && !params_vdev->rdbk_times && !dev->hw_dev->is_single) rkisp_params_clear_fstflg(params_vdev); if ((isp_mis & CIF_ISP_FRAME) && !IS_HDR_RDBK(dev->rd_mode)) diff --git a/drivers/media/platform/rockchip/vpss/common.c b/drivers/media/platform/rockchip/vpss/common.c index b73b71ee5d1d..49fad005b8fd 100644 --- a/drivers/media/platform/rockchip/vpss/common.c +++ b/drivers/media/platform/rockchip/vpss/common.c @@ -111,6 +111,8 @@ void rkvpss_update_regs(struct rkvpss_device *dev, u32 start, u32 end) mask |= (RKVPSS_ISP2VPSS_CHN0_SEL(3) << j * 2); } *val |= (readl(base + i) & mask); + } else { + *val |= readl(base + i); } } writel(*val, base + i); diff --git a/drivers/media/platform/rockchip/vpss/hw.c b/drivers/media/platform/rockchip/vpss/hw.c index 6be54c704596..bd974b17cfeb 100644 --- a/drivers/media/platform/rockchip/vpss/hw.c +++ b/drivers/media/platform/rockchip/vpss/hw.c @@ -519,7 +519,8 @@ void rkvpss_soft_reset(struct rkvpss_hw_dev *hw) rockchip_iommu_enable(hw->dev); } - rkvpss_hw_write(hw, RKVPSS_VPSS_CTRL, RKVPSS_ACK_FRM_PRO_DIS); + rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CTRL, RKVPSS_ACK_FRM_PRO_DIS, + RKVPSS_ACK_FRM_PRO_DIS); rkvpss_hw_write(hw, RKVPSS_VPSS_IRQ_CFG, 0x3fff); rkvpss_hw_write(hw, RKVPSS_MI_IMSC, 0xd0000000); rkvpss_hw_set_bits(hw, RKVPSS_VPSS_ONLINE, RKVPSS_ONLINE_MODE_MASK, diff --git a/drivers/media/platform/rockchip/vpss/regs.h b/drivers/media/platform/rockchip/vpss/regs.h index 5d9442cbb720..d73d6db5addd 100644 --- a/drivers/media/platform/rockchip/vpss/regs.h +++ b/drivers/media/platform/rockchip/vpss/regs.h @@ -1179,8 +1179,10 @@ #define IS_SYNC_REG(x) ({ \ typeof(x) __x = (x); \ (__x == RKVPSS_VPSS_CTRL || __x == RKVPSS_VPSS_ONLINE || \ - __x == RKVPSS_VPSS_UPDATE || __x == RKVPSS_MI_WR_INIT || \ - __x == RKVPSS_MI_WR_WRAP_CTRL || __x == RKVPSS_MI_WR_VFLIP_CTRL); \ + __x == RKVPSS_VPSS_UPDATE || __x == RKVPSS_VPSS_CLK_GATE || \ + __x == RKVPSS_VPSS_IMSC || __x == RKVPSS_MI_WR_CTRL || \ + __x == RKVPSS_MI_WR_INIT || __x == RKVPSS_MI_WR_WRAP_CTRL || \ + __x == RKVPSS_MI_WR_VFLIP_CTRL); \ }) #endif diff --git a/drivers/media/platform/rockchip/vpss/stream.c b/drivers/media/platform/rockchip/vpss/stream.c index 5b650357399c..97ccd297fa5b 100644 --- a/drivers/media/platform/rockchip/vpss/stream.c +++ b/drivers/media/platform/rockchip/vpss/stream.c @@ -1050,6 +1050,13 @@ static void poly_phase_scale(struct rkvpss_stream *stream, bool on, bool sync) return; } + /*config scl clk gate*/ + if (in_w == out_w && in_h == out_h) + rkvpss_unite_clear_bits(dev, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS); + else + rkvpss_unite_set_bits(dev, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS, + RKVPSS_SCL0_CKG_DIS); + /* TODO diff for input and output format */ if (yuv420_in) { in_div = 2; @@ -1275,7 +1282,7 @@ static void bilinear_scale(struct rkvpss_stream *stream, bool on, bool sync) u32 in_w = stream->crop.width; u32 in_h = stream->crop.height; u32 in_div, out_div; - u32 reg, val, ctrl = 0; + u32 reg, val, ctrl = 0, clk_mask = 0; bool yuv420_in = false, yuv422_to_420 = false; if (!on) { @@ -1284,6 +1291,25 @@ static void bilinear_scale(struct rkvpss_stream *stream, bool on, bool sync) return; } + /*config scl clk gate*/ + switch (stream->id) { + case RKVPSS_OUTPUT_CH1: + clk_mask = RKVPSS_SCL1_CKG_DIS; + break; + case RKVPSS_OUTPUT_CH2: + clk_mask = RKVPSS_SCL2_CKG_DIS; + break; + case RKVPSS_OUTPUT_CH3: + clk_mask = RKVPSS_SCL3_CKG_DIS; + break; + default: + return; + } + if (in_w == out_w && in_h == out_h) + rkvpss_unite_clear_bits(dev, RKVPSS_SCL0_CKG_DIS, clk_mask); + else + rkvpss_unite_set_bits(dev, RKVPSS_SCL0_CKG_DIS, clk_mask, clk_mask); + if (!dev->unite_mode) { /* TODO diff for input and output format */ if (yuv420_in) { diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.c b/drivers/media/platform/rockchip/vpss/vpss_offline.c index 0f77c29744f6..09f3e448e0af 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.c @@ -268,7 +268,11 @@ static void poly_phase_scale(struct rkvpss_frame_cfg *frame_cfg, if (in_w == out_w && in_h == out_w) { rkvpss_hw_write(hw, RKVPSS_ZME_Y_SCL_CTRL, 0); rkvpss_hw_write(hw, RKVPSS_ZME_UV_SCL_CTRL, 0); + rkvpss_hw_clear_bits(hw, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS); goto end; + } else { + rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS, + RKVPSS_SCL0_CKG_DIS); } /* TODO diff for input and output format */ @@ -422,23 +426,32 @@ static void bilinear_scale(struct rkvpss_frame_cfg *frame_cfg, struct rkvpss_hw_dev *hw = ofl->hw; u32 in_w = cfg->crop_width, in_h = cfg->crop_height; u32 out_w = cfg->scl_width, out_h = cfg->scl_height; - u32 reg_base, in_div, out_div, val, ctrl = 0; + u32 reg_base, in_div, out_div, val, ctrl = 0, clk_mask = 0; bool yuv420_in = false, yuv422_to_420 = false; switch (idx) { case RKVPSS_OUTPUT_CH1: reg_base = RKVPSS_SCALE1_BASE; + clk_mask = RKVPSS_SCL1_CKG_DIS; break; case RKVPSS_OUTPUT_CH2: reg_base = RKVPSS_SCALE2_BASE; + clk_mask = RKVPSS_SCL2_CKG_DIS; break; case RKVPSS_OUTPUT_CH3: reg_base = RKVPSS_SCALE3_BASE; + clk_mask = RKVPSS_SCL3_CKG_DIS; break; default: return; } + /*config scl clk gate*/ + if (in_w == out_w && in_h == out_h) + rkvpss_hw_clear_bits(hw, RKVPSS_VPSS_CLK_GATE, clk_mask); + else + rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CLK_GATE, clk_mask, clk_mask); + if (!unite) { if (in_w == out_w && in_h == out_w) goto end; @@ -1560,6 +1573,9 @@ static int rkvpss_ofl_run(struct file *file, struct rkvpss_frame_cfg *cfg, bool if (ret < 0) return ret; + if (unite && left) + calc_unite_scl_params(file, cfg); + if (unite && cfg->mirror) left_tmp = !left; else @@ -1964,7 +1980,6 @@ static int rkvpss_prepare_run(struct file *file, struct rkvpss_frame_cfg *cfg) if (ret < 0) goto end; } else { - calc_unite_scl_params(file, cfg); ret = rkvpss_ofl_run(file, cfg, true, true); if (ret < 0) { v4l2_err(&ofl->v4l2_dev, "unite left error\n"); diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 47f15df5d47b..a1072d584c33 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -181,6 +181,7 @@ struct rockchip_udphy { u32 dp_aux_din_sel; bool dp_sink_hpd_sel; bool dp_sink_hpd_cfg; + bool dp_hpd_disabled; u8 bw; int id; int dp_lanes; @@ -581,9 +582,19 @@ static int udphy_dplane_select(struct rockchip_udphy *udphy) } regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, - ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL | DP_LANE_SEL_ALL) << 16) | + (DP_LANE_SEL_ALL << 16) | value); + + return 0; +} + +static int udphy_dpaux_select(struct rockchip_udphy *udphy) +{ + const struct rockchip_udphy_cfg *cfg = udphy->cfgs; + + regmap_write(udphy->vogrf, cfg->vogrfcfg[udphy->id].dp_lane_reg, + ((DP_AUX_DIN_SEL | DP_AUX_DOUT_SEL) << 16) | FIELD_PREP(DP_AUX_DIN_SEL, udphy->dp_aux_din_sel) | - FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel) | value); + FIELD_PREP(DP_AUX_DOUT_SEL, udphy->dp_aux_dout_sel)); return 0; } @@ -615,7 +626,8 @@ static int udphy_dp_hpd_event_trigger(struct rockchip_udphy *udphy, bool hpd) udphy->dp_sink_hpd_sel = true; udphy->dp_sink_hpd_cfg = hpd; - grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd); + if (!udphy->dp_hpd_disabled) + grfreg_write(udphy->vogrf, &cfg->vogrfcfg[udphy->id].hpd_trigger, hpd); return 0; } @@ -1118,8 +1130,6 @@ static int rockchip_dp_phy_power_on(struct phy *phy) if (ret) goto unlock; - ret = udphy_dplane_select(udphy); - unlock: mutex_unlock(&udphy->mutex); /* @@ -1240,6 +1250,8 @@ static int rockchip_dp_phy_configure(struct phy *phy, if (ret) return ret; + udphy_dplane_select(udphy); + if (dp->set_rate) { regmap_update_bits(udphy->pma_regmap, CMN_DP_RSTN_OFFSET, CMN_DP_CMN_RSTN, FIELD_PREP(CMN_DP_CMN_RSTN, 0x0)); @@ -1306,10 +1318,30 @@ static int rockchip_dp_phy_configure(struct phy *phy, return 0; } +static int rockchip_dp_phy_set_mode(struct phy *phy, enum phy_mode mode, int submode) +{ + struct rockchip_udphy *udphy = phy_get_drvdata(phy); + int ret = 0; + + switch (submode) { + case 0: + ret = udphy_dpaux_select(udphy); + break; + case 1: + udphy->dp_hpd_disabled = true; + break; + default: + break; + } + + return ret; +} + static const struct phy_ops rockchip_dp_phy_ops = { .power_on = rockchip_dp_phy_power_on, .power_off = rockchip_dp_phy_power_off, .configure = rockchip_dp_phy_configure, + .set_mode = rockchip_dp_phy_set_mode, .owner = THIS_MODULE, }; diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig index 4067e7273992..11b9b204291f 100644 --- a/drivers/soc/rockchip/Kconfig +++ b/drivers/soc/rockchip/Kconfig @@ -255,7 +255,7 @@ config ROCKCHIP_DEBUG config ROCKCHIP_MINI_KERNEL bool "Rockchip Mini Kernel support" select NO_GKI - default y if CPU_RV1106 || CPU_RV1126 + default y if CPU_RV1103B || CPU_RV1106 || CPU_RV1126 help Say y here to enable Rockchip mini kernel support. This option make the kernel size smaller. diff --git a/drivers/soc/rockchip/Kconfig.cpu b/drivers/soc/rockchip/Kconfig.cpu index c1ecd2daf338..b3c014ec5618 100644 --- a/drivers/soc/rockchip/Kconfig.cpu +++ b/drivers/soc/rockchip/Kconfig.cpu @@ -27,6 +27,10 @@ config CPU_RK322X bool "RK3228/9" depends on ARM +config CPU_RV1103B + bool "RV1103B" + depends on ARM + config CPU_RV1106 bool "RV1103/6" depends on ARM diff --git a/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c b/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c index e5421e4515d2..8902c5153ce0 100644 --- a/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c +++ b/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c @@ -243,6 +243,28 @@ static int write_room(struct platform_device *pdev) return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo)); } +#define console_poll(cond, count, us) \ +do { \ + if (!IS_ENABLED(CONFIG_HIGH_RES_TIMERS) && CONFIG_HZ < 1000 && us < 1000) { \ + if (!(cond)) { \ + ktime_t timeout = ktime_add_us(ktime_get(), us * count); \ + int oldnice = task_nice(current); \ + if (!(cond)) { \ + set_user_nice(current, MAX_NICE); \ + while (!(cond)) { \ + if (ktime_compare(ktime_get(), timeout) > 0) \ + break; \ + schedule(); \ + } \ + set_user_nice(current, oldnice); \ + } \ + } \ + } else { \ + while (!(cond) && count--) \ + usleep_range(us, us + us / 20); \ + } \ +} while (0) + static void console_putc(struct platform_device *pdev, unsigned int c) { struct rk_fiq_debugger *t; @@ -254,9 +276,7 @@ static void console_putc(struct platform_device *pdev, unsigned int c) if (t->baudrate == 115200) us = 5160; /* the time to send 60 byte for baudrate 115200 */ - while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && - count--) - usleep_range(us, us + us / 20); + console_poll(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL, count, us); rk_fiq_write(t, c, UART_TX); } diff --git a/drivers/video/rockchip/mpp/mpp_iep2.c b/drivers/video/rockchip/mpp/mpp_iep2.c index 8e4a0050384e..275c76524c79 100644 --- a/drivers/video/rockchip/mpp/mpp_iep2.c +++ b/drivers/video/rockchip/mpp/mpp_iep2.c @@ -36,6 +36,9 @@ #define MVL 28 #define MVR 27 +#define IOMMU_GET_BUS_ID(x) (((x) >> 6) & 0x1f) +#define AUX_PAGE_SIZE SZ_4K + enum rockchip_iep2_fmt { ROCKCHIP_IEP2_FMT_YUV422 = 2, ROCKCHIP_IEP2_FMT_YUV420 @@ -193,6 +196,12 @@ struct iep2_output { u32 y_end[8]; }; +struct iep2_session_priv { + /* workaround for pagefault */ + unsigned long aux_iova; + struct page *aux_page; +}; + struct iep_task { struct mpp_task mpp_task; struct mpp_hw_info *hw_info; @@ -247,6 +256,8 @@ static int iep2_process_reg_fd(struct mpp_session *session, ARRAY_SIZE(task->params.dst) * 3 + 2; u32 *paddr = &task->params.src[0].y; + struct mpp_dev *mpp = session->mpp; + struct iep2_session_priv *priv = session->priv; for (i = 0; i < addr_num; ++i) { int usr_fd; @@ -279,6 +290,27 @@ static int iep2_process_reg_fd(struct mpp_session *session, mpp_debug(DEBUG_IOMMU, "reg[%3d]: %3d => %pad + offset %u\n", iep2_addr_rnum[i], usr_fd, &mem_region->iova, offset); paddr[i] = mem_region->iova + offset; + + /* workaround for invalid access to src image */ + if (task->params.dil_mode == ROCKCHIP_IEP2_DIL_MODE_I1O1T && + iep2_addr_rnum[i] == 24 && priv->aux_page) { + int ret = 0; + unsigned long page_iova = mem_region->iova + mem_region->len; + + if (priv->aux_iova != -1) { + iommu_unmap(mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE); + priv->aux_iova = -1; + } + + page_iova = round_down(page_iova, AUX_PAGE_SIZE); + ret = iommu_map(mpp->iommu_info->domain, page_iova, + page_to_phys(priv->aux_page), AUX_PAGE_SIZE, + IOMMU_READ); + if (!ret) { + priv->aux_iova = page_iova; + mpp_debug(DEBUG_IOMMU, "aux iova %lx\n", page_iova); + } + } } return 0; @@ -765,6 +797,12 @@ static int iep2_free_task(struct mpp_session *session, struct mpp_task *mpp_task) { struct iep_task *task = to_iep_task(mpp_task); + struct iep2_session_priv *priv = session->priv; + + if (priv->aux_iova != -1) { + iommu_unmap(session->mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE); + priv->aux_iova = -1; + } mpp_task_finalize(session, mpp_task); kfree(task); @@ -928,6 +966,55 @@ static int iep2_reset(struct mpp_dev *mpp) return 0; } +static int iep2_init_session(struct mpp_session *session) +{ + struct iep2_session_priv *priv; + + if (!session) { + mpp_err("session is null\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* warkaround for mmu pagefault */ + priv->aux_iova = -1; + priv->aux_page = alloc_page(GFP_KERNEL); + if (!priv->aux_page) { + dev_err(session->mpp->dev, "allocate a page for auxiliary usage\n"); + priv->aux_page = NULL; + } + + session->priv = priv; + + return 0; +} + +static int iep2_free_session(struct mpp_session *session) +{ + if (session && session->priv) { + struct iep2_session_priv *priv = session->priv; + struct mpp_dev *mpp = session->mpp; + + if (priv->aux_iova != -1) { + iommu_unmap(mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE); + priv->aux_iova = -1; + } + + if (priv->aux_page) { + __free_page(priv->aux_page); + priv->aux_page = NULL; + } + + kfree(session->priv); + session->priv = NULL; + } + + return 0; +} + static struct mpp_hw_ops iep_v2_hw_ops = { .init = iep2_init, .clk_on = iep2_clk_on, @@ -944,6 +1031,8 @@ static struct mpp_dev_ops iep_v2_dev_ops = { .finish = iep2_finish, .result = iep2_result, .free_task = iep2_free_task, + .init_session = iep2_init_session, + .free_session = iep2_free_session, }; static struct mpp_hw_info iep2_hw_info = { diff --git a/drivers/video/rockchip/mpp_osal/Kconfig b/drivers/video/rockchip/mpp_osal/Kconfig index 75cd7028615f..b8ad041c2e6b 100644 --- a/drivers/video/rockchip/mpp_osal/Kconfig +++ b/drivers/video/rockchip/mpp_osal/Kconfig @@ -2,7 +2,7 @@ config ROCKCHIP_MPP_OSAL bool "mpp osal" - depends on CPU_RV1106 + depends on CPU_RV1103B || CPU_RV1106 default y help rockchip mpp osal adapt for kmpp diff --git a/drivers/video/rockchip/rga3/include/rga_hw_config.h b/drivers/video/rockchip/rga3/include/rga_hw_config.h index 6679c599af42..61390902175a 100644 --- a/drivers/video/rockchip/rga3/include/rga_hw_config.h +++ b/drivers/video/rockchip/rga3/include/rga_hw_config.h @@ -78,6 +78,7 @@ extern const struct rga_hw_data rga2e_data; extern const struct rga_hw_data rga2e_1106_data; extern const struct rga_hw_data rga2e_iommu_data; extern const struct rga_hw_data rga2p_iommu_data; +extern const struct rga_hw_data rga2p_lite_1103b_data; #define rga_hw_has_issue(scheduler, issue) test_bit(issue, &((scheduler)->hw_issues_mask)) #define rga_hw_set_issue_mask(scheduler, issue) set_bit(issue, &((scheduler)->hw_issues_mask)) diff --git a/drivers/video/rockchip/rga3/rga_drv.c b/drivers/video/rockchip/rga3/rga_drv.c index e4e70def194e..ac74808581e7 100644 --- a/drivers/video/rockchip/rga3/rga_drv.c +++ b/drivers/video/rockchip/rga3/rga_drv.c @@ -1374,6 +1374,8 @@ static int rga_drv_probe(struct platform_device *pdev) } else if (!strcmp(scheduler->version.str, "3.e.19357")) { scheduler->data = &rga2p_iommu_data; rga_hw_set_issue_mask(scheduler, RGA_HW_ISSUE_DIS_AUTO_RST); + } else if (!strcmp(scheduler->version.str, "3.f.23690")) { + scheduler->data = &rga2p_lite_1103b_data; } else { scheduler->data = &rga2e_data; } diff --git a/drivers/video/rockchip/rga3/rga_hw_config.c b/drivers/video/rockchip/rga3/rga_hw_config.c index 18c4eacd03ac..f1d1bc8da799 100644 --- a/drivers/video/rockchip/rga3/rga_hw_config.c +++ b/drivers/video/rockchip/rga3/rga_hw_config.c @@ -442,6 +442,30 @@ const struct rga_win_data rga2p_win_data[] = { }, }; +const struct rga_win_data rga2p_lite_win_data[] = { + { + .name = "rga2e-src0", + .formats[RGA_RASTER_INDEX] = rga2e_input_raster_format, + .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_input_raster_format), + .supported_rotations = RGA_MODE_ROTATE_MASK, + .scale_up_mode = RGA_SCALE_UP_BIC, + .scale_down_mode = RGA_SCALE_DOWN_AVG, + .rd_mode = RGA_RASTER_MODE, + + }, + + { + .name = "rga2-dst", + .formats[RGA_RASTER_INDEX] = rga2e_output_raster_format, + .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_output_raster_format), + .supported_rotations = 0, + .scale_up_mode = RGA_SCALE_UP_NONE, + .scale_down_mode = RGA_SCALE_DOWN_NONE, + .rd_mode = RGA_RASTER_MODE, + + }, +}; + const struct rga_hw_data rga3_data = { .version = 0, .input_range = {{68, 2}, {8176, 8176}}, @@ -564,3 +588,27 @@ const struct rga_hw_data rga2p_iommu_data = { RGA_MODE_CSC_BT709, .mmu = RGA_IOMMU, }; + +const struct rga_hw_data rga2p_lite_1103b_data = { + .version = 0, + .input_range = {{2, 2}, {2880, 1620}}, + .output_range = {{2, 2}, {2880, 1620}}, + + .win = rga2p_lite_win_data, + .win_size = ARRAY_SIZE(rga2p_lite_win_data), + /* 1 << factor mean real factor */ + .max_upscale_factor = 4, + .max_downscale_factor = 4, + + .byte_stride_align = 4, + .max_byte_stride = WORD_TO_BYTE(8192), + + .feature = RGA_COLOR_FILL | RGA_DITHER | RGA_YIN_YOUT | + RGA_YUV_HDS | RGA_YUV_VDS | + RGA_PRE_INTR | RGA_FULL_CSC, + .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | + RGA_MODE_CSC_BT709, + .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | + RGA_MODE_CSC_BT709, + .mmu = RGA_NONE_MMU, +}; diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 86ccfadb8d80..5c30ab2971ff 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -137,7 +137,6 @@ struct rk_i2s_tdm_dev { bool tdm_mode; bool tdm_fsync_half_frame; bool is_dma_active[SNDRV_PCM_STREAM_LAST + 1]; - bool dma_guard_initialized; unsigned int mclk_rx_freq; unsigned int mclk_tx_freq; unsigned int mclk_root0_freq; @@ -150,6 +149,7 @@ struct rk_i2s_tdm_dev { unsigned int i2s_sdos[CH_GRP_MAX]; unsigned int quirks; unsigned int lrck_ratio; + unsigned int tdm_slots; int clk_ppm; int refcount; spinlock_t lock; /* xfer lock */ @@ -1035,13 +1035,11 @@ static void rockchip_i2s_tdm_xfer_trcm_start(struct rk_i2s_tdm_dev *i2s_tdm, spin_lock_irqsave(&i2s_tdm->lock, flags); if (++i2s_tdm->refcount == 1) { - if (i2s_tdm->dma_guard_initialized) { - regmap_read(i2s_tdm->regmap, I2S_DMACR, &val); - en = I2S_DMACR_RDE(1) | I2S_DMACR_TDE(1); - if ((val & en) != en) { - dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, bstream, 1); - rockchip_i2s_tdm_dma_ctrl(i2s_tdm, bstream, 1); - } + regmap_read(i2s_tdm->regmap, I2S_DMACR, &val); + en = I2S_DMACR_RDE(1) | I2S_DMACR_TDE(1); + if ((val & en) != en) { + dmaengine_trcm_dma_guard_ctrl(i2s_tdm->pcm_comp, bstream, 1); + rockchip_i2s_tdm_dma_ctrl(i2s_tdm, bstream, 1); } rockchip_i2s_tdm_xfer_start(i2s_tdm, 0); } @@ -1056,8 +1054,7 @@ static void rockchip_i2s_tdm_xfer_trcm_stop(struct rk_i2s_tdm_dev *i2s_tdm, spin_lock_irqsave(&i2s_tdm->lock, flags); if (--i2s_tdm->refcount == 0) rockchip_i2s_tdm_xfer_stop(i2s_tdm, 0, false); - if (i2s_tdm->dma_guard_initialized) - rockchip_i2s_tdm_dma_ctrl(i2s_tdm, stream, 1); + rockchip_i2s_tdm_dma_ctrl(i2s_tdm, stream, 1); spin_unlock_irqrestore(&i2s_tdm->lock, flags); } @@ -1127,6 +1124,86 @@ static void rockchip_i2s_tdm_stop(struct rk_i2s_tdm_dev *i2s_tdm, int stream) rockchip_i2s_tdm_xfer_stop(i2s_tdm, stream, false); } +static int rockchip_i2s_tdm_parse_channels(struct rk_i2s_tdm_dev *i2s_tdm, + int stream, int channels) +{ + unsigned int reg_fmt, fmt; + int ret = 0; + +#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES + if (i2s_tdm->is_tdm_multi_lanes) { + unsigned int lanes = rockchip_i2s_tdm_get_lanes(i2s_tdm, stream); + + switch (lanes) { + case 4: + ret = I2S_CHN_8; + break; + case 3: + ret = I2S_CHN_6; + break; + case 2: + ret = I2S_CHN_4; + break; + case 1: + ret = I2S_CHN_2; + break; + default: + ret = -EINVAL; + break; + } + + return ret; + } +#endif + if (stream == SNDRV_PCM_STREAM_PLAYBACK) + reg_fmt = I2S_TXCR; + else + reg_fmt = I2S_RXCR; + + regmap_read(i2s_tdm->regmap, reg_fmt, &fmt); + fmt &= I2S_TXCR_TFS_MASK; + + if (fmt == I2S_TXCR_TFS_TDM_I2S && !i2s_tdm->tdm_fsync_half_frame) { + switch (channels) { + case 16: + ret = I2S_CHN_8; + break; + case 12: + ret = I2S_CHN_6; + break; + case 8: + ret = I2S_CHN_4; + break; + case 4: + ret = I2S_CHN_2; + break; + default: + ret = -EINVAL; + break; + } + } else { + switch (channels) { + case 8: + ret = I2S_CHN_8; + break; + case 6: + ret = I2S_CHN_6; + break; + case 4: + ret = I2S_CHN_4; + break; + case 2: + ret = I2S_CHN_2; + break; + default: + ret = -EINVAL; + break; + } + } + + return ret; +} + static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { @@ -1283,8 +1360,24 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai, regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR, mask, tdm_val); } + + mask = I2S_TXCR_CSR_MASK; + ret = rockchip_i2s_tdm_parse_channels(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK, + i2s_tdm->tdm_slots); + if (ret < 0) { + dev_err(i2s_tdm->dev, "Invalid slots: %d\n", i2s_tdm->tdm_slots); + return ret; + } + + val = ret; + regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val); + regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val); } + /* Enable the xfer in the last card init stage. */ + if (i2s_tdm->quirks & QUIRK_ALWAYS_ON && !i2s_tdm->clk_trcm) + rockchip_i2s_tdm_xfer_start(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK); + err_pm_put: pm_runtime_put(cpu_dai->dev); @@ -1643,9 +1736,6 @@ static int rockchip_i2s_tdm_params_trcm(struct snd_pcm_substream *substream, rockchip_i2s_tdm_trcm_resume(substream, i2s_tdm); spin_unlock_irqrestore(&i2s_tdm->lock, flags); - if (comp && !i2s_tdm->dma_guard_initialized) - i2s_tdm->dma_guard_initialized = true; - return 0; } @@ -1702,82 +1792,9 @@ static int rockchip_i2s_tdm_params_channels(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct rk_i2s_tdm_dev *i2s_tdm = to_info(dai); - unsigned int reg_fmt, fmt; - int ret = 0; -#ifdef CONFIG_SND_SOC_ROCKCHIP_I2S_TDM_MULTI_LANES - if (i2s_tdm->is_tdm_multi_lanes) { - unsigned int lanes = rockchip_i2s_tdm_get_lanes(i2s_tdm, - substream->stream); - - switch (lanes) { - case 4: - ret = I2S_CHN_8; - break; - case 3: - ret = I2S_CHN_6; - break; - case 2: - ret = I2S_CHN_4; - break; - case 1: - ret = I2S_CHN_2; - break; - default: - ret = -EINVAL; - break; - } - - return ret; - } -#endif - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - reg_fmt = I2S_TXCR; - else - reg_fmt = I2S_RXCR; - - regmap_read(i2s_tdm->regmap, reg_fmt, &fmt); - fmt &= I2S_TXCR_TFS_MASK; - - if (fmt == I2S_TXCR_TFS_TDM_I2S && !i2s_tdm->tdm_fsync_half_frame) { - switch (params_channels(params)) { - case 16: - ret = I2S_CHN_8; - break; - case 12: - ret = I2S_CHN_6; - break; - case 8: - ret = I2S_CHN_4; - break; - case 4: - ret = I2S_CHN_2; - break; - default: - ret = -EINVAL; - break; - } - } else { - switch (params_channels(params)) { - case 8: - ret = I2S_CHN_8; - break; - case 6: - ret = I2S_CHN_6; - break; - case 4: - ret = I2S_CHN_4; - break; - case 2: - ret = I2S_CHN_2; - break; - default: - ret = -EINVAL; - break; - } - } - - return ret; + return rockchip_i2s_tdm_parse_channels(i2s_tdm, substream->stream, + params_channels(params)); } static void rockchip_i2s_tdm_get_performance(struct snd_pcm_substream *substream, @@ -2212,7 +2229,9 @@ static int rockchip_dai_tdm_slot(struct snd_soc_dai *dai, int ret; i2s_tdm->tdm_mode = true; + i2s_tdm->tdm_slots = slots; i2s_tdm->frame_width = slots * slot_width; + mask = TDM_SLOT_BIT_WIDTH_MSK | TDM_FRAME_WIDTH_MSK; val = TDM_SLOT_BIT_WIDTH(slot_width) | TDM_FRAME_WIDTH(slots * slot_width); @@ -2221,10 +2240,15 @@ static int rockchip_dai_tdm_slot(struct snd_soc_dai *dai, if (ret < 0 && ret != -EACCES) return ret; - regmap_update_bits(i2s_tdm->regmap, I2S_TDM_TXCR, - mask, val); - regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR, - mask, val); + regmap_update_bits(i2s_tdm->regmap, I2S_TDM_TXCR, mask, val); + regmap_update_bits(i2s_tdm->regmap, I2S_TDM_RXCR, mask, val); + + mask = I2S_TXCR_VDW_MASK; + val = I2S_TXCR_VDW(slot_width); + + regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val); + regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val); + pm_runtime_put(dai->dev); return 0; @@ -2818,13 +2842,6 @@ static int rockchip_i2s_tdm_keep_clk_always_on(struct rk_i2s_tdm_dev *i2s_tdm) I2S_CKR_RSD_MASK | I2S_CKR_TSD_MASK, I2S_CKR_RSD(div_lrck) | I2S_CKR_TSD(div_lrck)); - if (i2s_tdm->clk_trcm) - rockchip_i2s_tdm_xfer_trcm_start(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK); - else - rockchip_i2s_tdm_xfer_start(i2s_tdm, SNDRV_PCM_STREAM_PLAYBACK); - - pm_runtime_forbid(i2s_tdm->dev); - dev_info(i2s_tdm->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", mclk_rate, bclk_rate, DEFAULT_FS); @@ -2931,9 +2948,18 @@ static int __maybe_unused i2s_tdm_runtime_resume(struct device *dev) regcache_cache_only(i2s_tdm->regmap, false); regcache_mark_dirty(i2s_tdm->regmap); - ret = regcache_sync(i2s_tdm->regmap); - if (ret) + /* + * XFER must be placed after all registers sync done, + * because a lots of registers depends on the XFER-Disabled. + */ + ret = 0; + ret |= regcache_sync_region(i2s_tdm->regmap, I2S_TXCR, I2S_INTCR); + ret |= regcache_sync_region(i2s_tdm->regmap, I2S_TXDR, I2S_CLKDIV); + ret |= regcache_sync_region(i2s_tdm->regmap, I2S_XFER, I2S_XFER); + if (ret) { + dev_err(i2s_tdm->dev, "Failed to sync registers\n"); goto err_regcache; + } /* * should be placed after regcache sync done to back @@ -3203,6 +3229,14 @@ static int rockchip_i2s_tdm_probe(struct platform_device *pdev) */ pm_runtime_enable(&pdev->dev); + /* + * Should be placed after pm_runtime_enable to do + * rpm_resume at the moment. otherwise, it will make sense + * at the next pm_runtime_get. + */ + if (i2s_tdm->quirks & QUIRK_ALWAYS_ON) + pm_runtime_forbid(i2s_tdm->dev); + ret = rockchip_i2s_tdm_register_platform(&pdev->dev); if (ret) goto err_suspend; @@ -3261,34 +3295,10 @@ static void rockchip_i2s_tdm_platform_shutdown(struct platform_device *pdev) pm_runtime_put(i2s_tdm->dev); } -static int __maybe_unused rockchip_i2s_tdm_suspend(struct device *dev) -{ - struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); - - regcache_mark_dirty(i2s_tdm->regmap); - - return 0; -} - -static int __maybe_unused rockchip_i2s_tdm_resume(struct device *dev) -{ - struct rk_i2s_tdm_dev *i2s_tdm = dev_get_drvdata(dev); - int ret; - - ret = pm_runtime_resume_and_get(dev); - if (ret < 0) - return ret; - ret = regcache_sync(i2s_tdm->regmap); - pm_runtime_put(dev); - - return ret; -} - static const struct dev_pm_ops rockchip_i2s_tdm_pm_ops = { SET_RUNTIME_PM_OPS(i2s_tdm_runtime_suspend, i2s_tdm_runtime_resume, NULL) - SET_SYSTEM_SLEEP_PM_OPS(rockchip_i2s_tdm_suspend, - rockchip_i2s_tdm_resume) + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, pm_runtime_force_resume) }; static struct platform_driver rockchip_i2s_tdm_driver = { diff --git a/sound/soc/rockchip/rockchip_multi_dais_pcm.c b/sound/soc/rockchip/rockchip_multi_dais_pcm.c index 0feab27b477d..b83b3a2bed95 100644 --- a/sound/soc/rockchip/rockchip_multi_dais_pcm.c +++ b/sound/soc/rockchip/rockchip_multi_dais_pcm.c @@ -915,10 +915,12 @@ static int dmaengine_mpcm_get_fifo_count(struct device *dev, } else if (strstr(dev_driver_string(component->dev), "sai")) { reg = substream->stream ? SAI_RXFIFOLR : SAI_TXFIFOLR; - val = SAI_FIFOLR_XFL3(reg) + - SAI_FIFOLR_XFL2(reg) + - SAI_FIFOLR_XFL1(reg) + - SAI_FIFOLR_XFL0(reg); + val = snd_soc_component_read(component, reg); + + val = SAI_FIFOLR_XFL3(val) + + SAI_FIFOLR_XFL2(val) + + SAI_FIFOLR_XFL1(val) + + SAI_FIFOLR_XFL0(val); } return val; diff --git a/sound/soc/rockchip/rockchip_trcm.c b/sound/soc/rockchip/rockchip_trcm.c index 79be9419a3f3..73f60f6f1016 100644 --- a/sound/soc/rockchip/rockchip_trcm.c +++ b/sound/soc/rockchip/rockchip_trcm.c @@ -36,6 +36,7 @@ struct dmaengine_trcm { struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; struct dmaengine_dma_guard guard[SNDRV_PCM_STREAM_LAST + 1]; struct snd_soc_component component; + bool always_on; }; struct dmaengine_trcm_runtime_data { @@ -340,6 +341,7 @@ static int dmaengine_trcm_dma_guard_new(struct snd_soc_component *component, struct dmaengine_trcm *trcm = soc_component_to_trcm(component); struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; + struct snd_soc_dai *dai; struct dma_chan *chan; struct dma_slave_config slave_config; struct device *dev; @@ -350,6 +352,8 @@ static int dmaengine_trcm_dma_guard_new(struct snd_soc_component *component, for_each_pcm_streams(i) { substream = rtd->pcm->streams[i].substream; + if (!substream) + continue; dev = dmaengine_dma_dev(trcm, substream); chan = trcm->chan[i]; @@ -370,11 +374,43 @@ static int dmaengine_trcm_dma_guard_new(struct snd_soc_component *component, snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data, &slave_config); + /* + * Use the max-16w to cover all 2^n cases, maybe better + * per channels and fmt, at the moment, we use the simple + * way. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.direction = DMA_MEM_TO_DEV; + slave_config.dst_maxburst = 16; + } else { + slave_config.direction = DMA_DEV_TO_MEM; + slave_config.src_maxburst = 16; + } + ret = dmaengine_slave_config(chan, &slave_config); if (ret) return ret; } + if (trcm->always_on) { + /* Start the first one will auto trigger bstream guard. */ + for_each_pcm_streams(i) { + substream = rtd->pcm->streams[i].substream; + if (!substream) + continue; + dai = asoc_rtd_to_cpu(rtd, 0); + if (!dai) + continue; + + dmaengine_trcm_dma_guard_ctrl(component, substream->stream, 1); + ret = dai->driver->ops->trigger(substream, + SNDRV_PCM_TRIGGER_START, + dai); + if (ret) + return ret; + } + } + return 0; } @@ -492,6 +528,8 @@ static int snd_dmaengine_trcm_register(struct device *dev) trcm->dev = dev; + trcm->always_on = device_property_read_bool(dev, "rockchip,always-on"); + #ifdef CONFIG_DEBUG_FS trcm->component.debugfs_prefix = "dma"; #endif