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:
Tao Huang
2024-07-09 18:17:14 +08:00
56 changed files with 2286 additions and 620 deletions

View File

@@ -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>;

View File

@@ -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";
};
};

View File

@@ -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";
};
};
};

View File

@@ -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>;

View File

@@ -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>;

View File

@@ -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.

View File

@@ -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/

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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 =

View File

@@ -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

View 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;
}
}

View 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

View File

@@ -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),
},
}
};

View File

@@ -434,6 +434,7 @@ exit:
static void pka_finish(void)
{
RK_PKA_TERMINATE();
PKA_RAM_FOR_CPU();
PKA_CLK_DISABLE();
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View 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 })
}

View 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 })
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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,

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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(&notifier_list_lock);
list_add_tail(&pn->list, &notifier_list);
list_for_each_entry_safe(panel_notifier, next, &notifier_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, &notifier_list);
}
mutex_unlock(&notifier_list_lock);
return 0;
return ret;
}
static void rockchip_panel_notifier_unregister(struct rockchip_panel_notifier *pn)

View File

@@ -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);

View File

@@ -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)

View File

@@ -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;

View File

@@ -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)

View File

@@ -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;

View File

@@ -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 = {

View File

@@ -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;
}

View File

@@ -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);
}
}
}

View File

@@ -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, &params_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))

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

View File

@@ -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) {

View File

@@ -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");

View File

@@ -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,
};

View File

@@ -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.

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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 = {

View File

@@ -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

View File

@@ -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))

View File

@@ -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;
}

View File

@@ -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,
};

View File

@@ -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 = {

View File

@@ -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;

View File

@@ -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