mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-09 12:17:12 +09:00
Merge commit '79977533751854377382278c86afd0a1c0281bad'
* commit '79977533751854377382278c86afd0a1c0281bad': (50 commits) drm/rockchip: panel-notifier: avoid duplicate register notifier arm64: dts: rockchip: rk3576-evb1: add mux node for dp arm64: dts: rockchip: rk3588-evb1: add mux node for dp drm/rockchip: dw-dp: support get hpd status from Type-C interface phy: rockchip: usbdp: support not trigger dp hpd drm/rockchip: dw-dp: support dynamic control power domain phy: rockchip: usbdp: don't access vo grf in phy power on drm/rockchip: debugfs: Add vop dump buffer version output prompt drm/rockchip: debugfs: Remove unused enable option for vop buffer dump video: rockchip: rga3: support RV1103B soc: rockchip: fiq_debugger: Fix console sleep too long clk: rockchip: Disable CLK_INV/CLK_PVTM on CPU_RV1103B video: rockchip: mpp_osal: ROCKCHIP_MPP_OSAL depends on CPU_RV1103B soc: rockchip: ROCKCHIP_MINI_KERNEL default y if CPU_RV1103B soc: rockchip: Add CPU_RV1103B config media: rockchip: vpss: fix online mul_sensor affect offline media: rockchip: vpss: fix offline 8k params calc error drm/rockchip: Only enable ROCKCHIP_DRM_DEBUG when not use GKI arm64: dts: rockchip: rk3562: auto select opps for rk3562j media: rockchip: isp: fix aiisp config ... Change-Id: Iea102b1850c9f57dc127c54af9555d166944a143
This commit is contained in:
@@ -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>;
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
@@ -205,6 +205,7 @@
|
||||
|
||||
&dp {
|
||||
status = "okay";
|
||||
svid = <0xff01>;
|
||||
};
|
||||
|
||||
&dp0 {
|
||||
@@ -330,6 +331,7 @@
|
||||
<PDO_FIXED(5000, 1000, PDO_FIXED_USB_COMM)>;
|
||||
source-pdos =
|
||||
<PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
|
||||
mode-switch = <&dp>;
|
||||
|
||||
altmodes {
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -256,6 +256,7 @@
|
||||
|
||||
&dp0 {
|
||||
status = "okay";
|
||||
svid = <0xff01>;
|
||||
};
|
||||
|
||||
&dp0_in_vp2 {
|
||||
@@ -436,6 +437,7 @@
|
||||
<PDO_FIXED(5000, 1000, PDO_FIXED_USB_COMM)>;
|
||||
source-pdos =
|
||||
<PDO_FIXED(5000, 3000, PDO_FIXED_USB_COMM)>;
|
||||
mode-switch = <&dp0>;
|
||||
|
||||
altmodes {
|
||||
#address-cells = <1>;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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/
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
469
drivers/crypto/rockchip/rk_crypto_ecc.c
Normal file
469
drivers/crypto/rockchip/rk_crypto_ecc.c
Normal file
@@ -0,0 +1,469 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (c) 2024 Rockchip Electronics Co., Ltd.
|
||||
*
|
||||
* Author: Lin Jinhan <troy.lin@rock-chips.com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/iopoll.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
}
|
||||
152
drivers/crypto/rockchip/rk_crypto_ecc.h
Normal file
152
drivers/crypto/rockchip/rk_crypto_ecc.h
Normal file
@@ -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
|
||||
@@ -8,13 +8,18 @@
|
||||
*
|
||||
* Some ideas are from marvell/cesa.c and s5p-sss.c driver.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/asn1_decoder.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/scatterlist.h>
|
||||
|
||||
#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),
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
@@ -434,6 +434,7 @@ exit:
|
||||
static void pka_finish(void)
|
||||
{
|
||||
RK_PKA_TERMINATE();
|
||||
PKA_RAM_FOR_CPU();
|
||||
PKA_CLK_DISABLE();
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
8
drivers/crypto/rockchip/rk_ecdsasignature.asn1
Normal file
8
drivers/crypto/rockchip/rk_ecdsasignature.asn1
Normal file
@@ -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 })
|
||||
}
|
||||
8
drivers/crypto/rockchip/rk_sm2signature.asn1
Normal file
8
drivers/crypto/rockchip/rk_sm2signature.asn1
Normal file
@@ -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 })
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -39,6 +39,8 @@
|
||||
#include <linux/mfd/syscon.h>
|
||||
#include <linux/rockchip/rockchip_sip.h>
|
||||
#include <linux/soc/rockchip/rk_vendor_storage.h>
|
||||
#include <linux/usb/typec_dp.h>
|
||||
#include <linux/usb/typec_mux.h>
|
||||
|
||||
#include <sound/hdmi-codec.h>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <drm/drm_drv.h>
|
||||
#include <drm/drm_file.h>
|
||||
#include <drm/drm_gem_dma_helper.h>
|
||||
#include <drm/drm_gem_framebuffer_helper.h>
|
||||
#include <drm/drm_of.h>
|
||||
#include <drm/drm_probe_helper.h>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 <linux/clk.h>
|
||||
#include <linux/i2c.h>
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user