From 0426bfc39b1d6a343fa13bbd9081ddbad92ba3b6 Mon Sep 17 00:00:00 2001 From: Mingwei Yan Date: Wed, 19 Jun 2024 18:46:38 +0800 Subject: [PATCH 01/50] media: rockchip: vpss: fix switch scl params irq wrong Signed-off-by: Mingwei Yan Change-Id: I68bdd03f6bff412a131099eaba8d160e89a0b6fa --- drivers/media/platform/rockchip/vpss/stream.c | 28 ++++++++++++++++++- .../platform/rockchip/vpss/vpss_offline.c | 15 +++++++++- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rockchip/vpss/stream.c b/drivers/media/platform/rockchip/vpss/stream.c index 5b650357399c..97ccd297fa5b 100644 --- a/drivers/media/platform/rockchip/vpss/stream.c +++ b/drivers/media/platform/rockchip/vpss/stream.c @@ -1050,6 +1050,13 @@ static void poly_phase_scale(struct rkvpss_stream *stream, bool on, bool sync) return; } + /*config scl clk gate*/ + if (in_w == out_w && in_h == out_h) + rkvpss_unite_clear_bits(dev, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS); + else + rkvpss_unite_set_bits(dev, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS, + RKVPSS_SCL0_CKG_DIS); + /* TODO diff for input and output format */ if (yuv420_in) { in_div = 2; @@ -1275,7 +1282,7 @@ static void bilinear_scale(struct rkvpss_stream *stream, bool on, bool sync) u32 in_w = stream->crop.width; u32 in_h = stream->crop.height; u32 in_div, out_div; - u32 reg, val, ctrl = 0; + u32 reg, val, ctrl = 0, clk_mask = 0; bool yuv420_in = false, yuv422_to_420 = false; if (!on) { @@ -1284,6 +1291,25 @@ static void bilinear_scale(struct rkvpss_stream *stream, bool on, bool sync) return; } + /*config scl clk gate*/ + switch (stream->id) { + case RKVPSS_OUTPUT_CH1: + clk_mask = RKVPSS_SCL1_CKG_DIS; + break; + case RKVPSS_OUTPUT_CH2: + clk_mask = RKVPSS_SCL2_CKG_DIS; + break; + case RKVPSS_OUTPUT_CH3: + clk_mask = RKVPSS_SCL3_CKG_DIS; + break; + default: + return; + } + if (in_w == out_w && in_h == out_h) + rkvpss_unite_clear_bits(dev, RKVPSS_SCL0_CKG_DIS, clk_mask); + else + rkvpss_unite_set_bits(dev, RKVPSS_SCL0_CKG_DIS, clk_mask, clk_mask); + if (!dev->unite_mode) { /* TODO diff for input and output format */ if (yuv420_in) { diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.c b/drivers/media/platform/rockchip/vpss/vpss_offline.c index 0f77c29744f6..f19e8e20e50b 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.c @@ -268,7 +268,11 @@ static void poly_phase_scale(struct rkvpss_frame_cfg *frame_cfg, if (in_w == out_w && in_h == out_w) { rkvpss_hw_write(hw, RKVPSS_ZME_Y_SCL_CTRL, 0); rkvpss_hw_write(hw, RKVPSS_ZME_UV_SCL_CTRL, 0); + rkvpss_hw_clear_bits(hw, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS); goto end; + } else { + rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CLK_GATE, RKVPSS_SCL0_CKG_DIS, + RKVPSS_SCL0_CKG_DIS); } /* TODO diff for input and output format */ @@ -422,23 +426,32 @@ static void bilinear_scale(struct rkvpss_frame_cfg *frame_cfg, struct rkvpss_hw_dev *hw = ofl->hw; u32 in_w = cfg->crop_width, in_h = cfg->crop_height; u32 out_w = cfg->scl_width, out_h = cfg->scl_height; - u32 reg_base, in_div, out_div, val, ctrl = 0; + u32 reg_base, in_div, out_div, val, ctrl = 0, clk_mask = 0; bool yuv420_in = false, yuv422_to_420 = false; switch (idx) { case RKVPSS_OUTPUT_CH1: reg_base = RKVPSS_SCALE1_BASE; + clk_mask = RKVPSS_SCL1_CKG_DIS; break; case RKVPSS_OUTPUT_CH2: reg_base = RKVPSS_SCALE2_BASE; + clk_mask = RKVPSS_SCL2_CKG_DIS; break; case RKVPSS_OUTPUT_CH3: reg_base = RKVPSS_SCALE3_BASE; + clk_mask = RKVPSS_SCL3_CKG_DIS; break; default: return; } + /*config scl clk gate*/ + if (in_w == out_w && in_h == out_h) + rkvpss_hw_clear_bits(hw, RKVPSS_VPSS_CLK_GATE, clk_mask); + else + rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CLK_GATE, clk_mask, clk_mask); + if (!unite) { if (in_w == out_w && in_h == out_w) goto end; From 743c5b92abb44db59dd9d5db36e0d9b7893c0945 Mon Sep 17 00:00:00 2001 From: Lin Jinhan Date: Wed, 26 Jun 2024 11:29:45 +0800 Subject: [PATCH 02/50] crypto: rockchip: add ECC/SM2 support Add support for the following algorithms: 1. ecdsa-nist-p192 2. ecdsa-nist-p224 3. ecdsa-nist-p256 4. sm2 Signed-off-by: Lin Jinhan Change-Id: Id58c7755a78293ccb6bfba2a781587922876d5bc --- drivers/crypto/rockchip/Makefile | 10 + drivers/crypto/rockchip/rk_crypto_bignum.c | 88 ++++ drivers/crypto/rockchip/rk_crypto_bignum.h | 12 + drivers/crypto/rockchip/rk_crypto_core.c | 2 +- drivers/crypto/rockchip/rk_crypto_core.h | 46 +- drivers/crypto/rockchip/rk_crypto_ecc.c | 469 ++++++++++++++++++ drivers/crypto/rockchip/rk_crypto_ecc.h | 152 ++++++ .../crypto/rockchip/rk_crypto_v2_akcipher.c | 251 +++++++++- drivers/crypto/rockchip/rk_crypto_v2_pka.c | 1 + drivers/crypto/rockchip/rk_crypto_v3.c | 23 +- drivers/crypto/rockchip/rk_crypto_v3.h | 4 + drivers/crypto/rockchip/rk_crypto_v3_reg.h | 2 + .../crypto/rockchip/rk_ecdsasignature.asn1 | 8 + drivers/crypto/rockchip/rk_sm2signature.asn1 | 8 + 14 files changed, 1068 insertions(+), 8 deletions(-) create mode 100644 drivers/crypto/rockchip/rk_crypto_ecc.c create mode 100644 drivers/crypto/rockchip/rk_crypto_ecc.h create mode 100644 drivers/crypto/rockchip/rk_ecdsasignature.asn1 create mode 100644 drivers/crypto/rockchip/rk_sm2signature.asn1 diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile index 53e34aa47bc1..f11277ee6c00 100644 --- a/drivers/crypto/rockchip/Makefile +++ b/drivers/crypto/rockchip/Makefile @@ -11,12 +11,19 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V1) += \ rk_crypto_v1_ahash.o \ rk_crypto_v1_skcipher.o +$(obj)/rk_sm2signature.asn1.o: $(obj)/rk_sm2signature.asn1.c $(obj)/rk_sm2signature.asn1.h +$(obj)/rk_ecdsasignature.asn1.o: $(obj)/rk_ecdsasignature.asn1.c $(obj)/rk_ecdsasignature.asn1.h +$(obj)/rk_crypto_ecc.o: $(obj)/rk_sm2signature.asn1.h $(obj)/rk_ecdsasignature.asn1.h + rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V2) += \ rk_crypto_v2.o \ rk_crypto_v2_ahash.o \ rk_crypto_v2_skcipher.o \ rk_crypto_v2_akcipher.o \ rk_crypto_v2_pka.o \ + rk_crypto_ecc.o \ + rk_sm2signature.asn1.o \ + rk_ecdsasignature.asn1.o \ rk_crypto_bignum.o rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \ @@ -25,6 +32,9 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V3) += \ rk_crypto_v3_skcipher.o \ rk_crypto_v2_akcipher.o \ rk_crypto_v2_pka.o \ + rk_crypto_ecc.o \ + rk_sm2signature.asn1.o \ + rk_ecdsasignature.asn1.o \ rk_crypto_bignum.o obj-$(CONFIG_CRYPTO_DEV_ROCKCHIP_DEV) += cryptodev_linux/ diff --git a/drivers/crypto/rockchip/rk_crypto_bignum.c b/drivers/crypto/rockchip/rk_crypto_bignum.c index 690c2fdf58ba..6ff1808974d2 100644 --- a/drivers/crypto/rockchip/rk_crypto_bignum.c +++ b/drivers/crypto/rockchip/rk_crypto_bignum.c @@ -128,3 +128,91 @@ int rk_bn_highest_bit(const struct rk_bignum *bn) return (int)(bn->n_words - 1) * RK_WORD_SIZE + b; } + +void rk_ecc_free_point(struct rk_ecp_point *point) +{ + if (!point) + return; + + rk_bn_free(point->x); + rk_bn_free(point->y); + + kfree(point); +} + +struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size) +{ + struct rk_ecp_point *point = NULL; + + point = kzalloc(sizeof(*point), GFP_KERNEL); + if (!point) + return NULL; + + point->x = rk_bn_alloc(max_size); + if (!point->x) + goto error; + + point->y = rk_bn_alloc(max_size); + if (!point->y) + goto error; + + return point; + +error: + rk_ecc_free_point(point); + + return NULL; +} + +struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len, + const uint8_t *y, uint32_t y_len, + enum bignum_endian endian, u32 max_size) +{ + struct rk_ecp_point *point = NULL; + + point = kzalloc(sizeof(*point), GFP_KERNEL); + if (!point) + return NULL; + + point->x = rk_bn_alloc(max_size); + if (!point->x) + goto error; + + if (rk_bn_set_data(point->x, x, x_len, endian) != 0) + goto error; + + point->y = rk_bn_alloc(max_size); + if (!point->y) + goto error; + + if (rk_bn_set_data(point->y, y, y_len, endian) != 0) + goto error; + + return point; + +error: + rk_ecc_free_point(point); + + return NULL; +} + +bool rk_ecp_point_is_zero(struct rk_ecp_point *point) +{ + uint32_t i; + bool ret = true; + + if (!point || !point->x || !point->y) + return false; + + for (i = 0; i < point->x->n_words; i++) { + if (point->x->data[i] != 0) + ret = false; + } + + for (i = 0; i < point->y->n_words; i++) { + if (point->y->data[i] != 0) + ret = false; + } + + return ret; +} diff --git a/drivers/crypto/rockchip/rk_crypto_bignum.h b/drivers/crypto/rockchip/rk_crypto_bignum.h index 780aa87661eb..845eeddc5d84 100644 --- a/drivers/crypto/rockchip/rk_crypto_bignum.h +++ b/drivers/crypto/rockchip/rk_crypto_bignum.h @@ -17,6 +17,11 @@ struct rk_bignum { u32 *data; }; +struct rk_ecp_point { + struct rk_bignum *x; /*!< the point's X coordinate */ + struct rk_bignum *y; /*!< the point's Y coordinate */ +}; + struct rk_bignum *rk_bn_alloc(u32 max_size); void rk_bn_free(struct rk_bignum *bn); int rk_bn_set_data(struct rk_bignum *bn, const u8 *data, u32 size, enum bignum_endian endian); @@ -24,4 +29,11 @@ int rk_bn_get_data(const struct rk_bignum *bn, u8 *data, u32 size, enum bignum_e u32 rk_bn_get_size(const struct rk_bignum *bn); int rk_bn_highest_bit(const struct rk_bignum *src); +struct rk_ecp_point *rk_ecc_alloc_point_zero(u32 max_size); +struct rk_ecp_point *rk_ecc_alloc_point(const uint8_t *x, uint32_t x_len, + const uint8_t *y, uint32_t y_len, + enum bignum_endian endian, u32 max_size); +void rk_ecc_free_point(struct rk_ecp_point *point); +bool rk_ecp_point_is_zero(struct rk_ecp_point *point); + #endif diff --git a/drivers/crypto/rockchip/rk_crypto_core.c b/drivers/crypto/rockchip/rk_crypto_core.c index 7b1c6ed81c45..4a75519d214f 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.c +++ b/drivers/crypto/rockchip/rk_crypto_core.c @@ -672,7 +672,7 @@ static char *crypto_full_algs_name[] = { "ecb(des3_ede)", "cbc(des3_ede)", "cfb(des3_ede)", "ofb(des3_ede)", "sha1", "sha224", "sha256", "sha384", "sha512", "md5", "sm3", "hmac(sha1)", "hmac(sha256)", "hmac(sha512)", "hmac(md5)", "hmac(sm3)", - "rsa" + "rsa", "ecc-192", "ecc-224", "ecc-256", "sm2", }; static const struct rk_crypto_soc_data px30_soc_data = diff --git a/drivers/crypto/rockchip/rk_crypto_core.h b/drivers/crypto/rockchip/rk_crypto_core.h index a2d4fbd14f78..aba37a9cc1b0 100644 --- a/drivers/crypto/rockchip/rk_crypto_core.h +++ b/drivers/crypto/rockchip/rk_crypto_core.h @@ -213,9 +213,19 @@ struct rk_cipher_ctx { struct rk_rsa_ctx { struct rk_alg_ctx algs_ctx; - struct rk_bignum *n; - struct rk_bignum *e; - struct rk_bignum *d; + struct rk_bignum *n; + struct rk_bignum *e; + struct rk_bignum *d; + + struct rk_crypto_dev *rk_dev; +}; + +struct rk_ecc_ctx { + struct rk_alg_ctx algs_ctx; + uint32_t group_id; + uint32_t nbits; + bool pub_key_set; + struct rk_ecp_point *point_Q; struct rk_crypto_dev *rk_dev; }; @@ -245,6 +255,15 @@ struct rk_crypto_algt { bool valid_flag; }; +enum rk_asym_algo { + ASYM_ALGO_RSA, + ASYM_ALGO_ECC_P192, + ASYM_ALGO_ECC_P224, + ASYM_ALGO_ECC_P256, + ASYM_ALGO_SM2, + ASYM_ALGO_MAX, +}; + enum rk_hash_algo { HASH_ALGO_MD5, HASH_ALGO_SHA1, @@ -439,6 +458,27 @@ enum rk_cipher_mode { } \ } +#define RK_ASYM_ECC_INIT(key_bits) {\ + .name = "ecc-" #key_bits, \ + .type = ALG_TYPE_ASYM, \ + .algo = ASYM_ALGO_ECC_P##key_bits, \ + .alg.asym = { \ + .verify = rk_ecc_verify, \ + .set_pub_key = rk_ecc_set_pub_key, \ + .max_size = rk_ecc_max_size, \ + .init = rk_ecc_init_tfm, \ + .exit = rk_ecc_exit_tfm, \ + .reqsize = 64, \ + .base = { \ + .cra_name = "ecdsa-nist-p" #key_bits, \ + .cra_driver_name = "ecdsa-nist-p" #key_bits "-rk", \ + .cra_priority = RK_CRYPTO_PRIORITY, \ + .cra_module = THIS_MODULE, \ + .cra_ctxsize = sizeof(struct rk_ecc_ctx), \ + },\ + } \ +} + #define CRYPTO_MAJOR_VER(ver) ((ver) & 0x0f000000) #define CRYPTO_MAJOR_VER_3 0x03000000 diff --git a/drivers/crypto/rockchip/rk_crypto_ecc.c b/drivers/crypto/rockchip/rk_crypto_ecc.c new file mode 100644 index 000000000000..050df55882e7 --- /dev/null +++ b/drivers/crypto/rockchip/rk_crypto_ecc.c @@ -0,0 +1,469 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024 Rockchip Electronics Co., Ltd. + * + * Author: Lin Jinhan + * + */ + +#include + +#include "rk_crypto_core.h" +#include "rk_crypto_v2.h" +#include "rk_crypto_v2_reg.h" +#include "rk_crypto_ecc.h" + +static void __iomem *ecc_base; + +#define WORDS2BYTES(words) ((words) * 4) + +#define RK_ECP_POLL_PERIOD_US 10000 +#define RK_ECP_POLL_TIMEOUT_US 500000 + +#define RK_LOAD_GROUP_A(G) do { \ + grp->curve_name = #G; \ + grp->wide = G ## _wide;\ + grp->p = G ## _p; \ + grp->p_len = sizeof(G ## _p); \ + grp->a = G ## _a; \ + grp->a_len = sizeof(G ## _a); \ + grp->n = G ## _n; \ + grp->n_len = sizeof(G ## _n); \ + grp->gx = G ## _gx; \ + grp->gx_len = sizeof(G ## _gx); \ + grp->gy = G ## _gy; \ + grp->gy_len = sizeof(G ## _gy); \ + } while (0) + +/* + * Domain parameters for secp192r1 + */ +static const uint32_t secp192r1_wide = RK_ECC_CURVE_WIDE_192; + +static const uint8_t secp192r1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp192r1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp192r1_gx[] = { + 0x12, 0x10, 0xFF, 0x82, 0xFD, 0x0A, 0xFF, 0xF4, + 0x00, 0x88, 0xA1, 0x43, 0xEB, 0x20, 0xBF, 0x7C, + 0xF6, 0x90, 0x30, 0xB0, 0x0E, 0xA8, 0x8D, 0x18, +}; + +static const uint8_t secp192r1_gy[] = { + 0x11, 0x48, 0x79, 0x1E, 0xA1, 0x77, 0xF9, 0x73, + 0xD5, 0xCD, 0x24, 0x6B, 0xED, 0x11, 0x10, 0x63, + 0x78, 0xDA, 0xC8, 0xFF, 0x95, 0x2B, 0x19, 0x07, +}; + +static const uint8_t secp192r1_n[] = { + 0x31, 0x28, 0xD2, 0xB4, 0xB1, 0xC9, 0x6B, 0x14, + 0x36, 0xF8, 0xDE, 0x99, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for secp224r1 + */ +static const uint32_t secp224r1_wide = RK_ECC_CURVE_WIDE_224; + +static const uint8_t secp224r1_p[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t secp224r1_a[] = { + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, +}; + +static const uint8_t secp224r1_gx[] = { + 0x21, 0x1D, 0x5C, 0x11, 0xD6, 0x80, 0x32, 0x34, + 0x22, 0x11, 0xC2, 0x56, 0xD3, 0xC1, 0x03, 0x4A, + 0xB9, 0x90, 0x13, 0x32, 0x7F, 0xBF, 0xB4, 0x6B, + 0xBD, 0x0C, 0x0E, 0xB7, +}; + +static const uint8_t secp224r1_gy[] = { + 0x34, 0x7E, 0x00, 0x85, 0x99, 0x81, 0xD5, 0x44, + 0x64, 0x47, 0x07, 0x5A, 0xA0, 0x75, 0x43, 0xCD, + 0xE6, 0xDF, 0x22, 0x4C, 0xFB, 0x23, 0xF7, 0xB5, + 0x88, 0x63, 0x37, 0xBD, +}; + +static const uint8_t secp224r1_n[] = { + 0x3D, 0x2A, 0x5C, 0x5C, 0x45, 0x29, 0xDD, 0x13, + 0x3E, 0xF0, 0xB8, 0xE0, 0xA2, 0x16, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for secp256r1 + */ +static const uint32_t secp256r1_wide = RK_ECC_CURVE_WIDE_256; + +static const uint8_t secp256r1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp256r1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t secp256r1_gx[] = { + 0x96, 0xC2, 0x98, 0xD8, 0x45, 0x39, 0xA1, 0xF4, + 0xA0, 0x33, 0xEB, 0x2D, 0x81, 0x7D, 0x03, 0x77, + 0xF2, 0x40, 0xA4, 0x63, 0xE5, 0xE6, 0xBC, 0xF8, + 0x47, 0x42, 0x2C, 0xE1, 0xF2, 0xD1, 0x17, 0x6B, +}; + +static const uint8_t secp256r1_gy[] = { + 0xF5, 0x51, 0xBF, 0x37, 0x68, 0x40, 0xB6, 0xCB, + 0xCE, 0x5E, 0x31, 0x6B, 0x57, 0x33, 0xCE, 0x2B, + 0x16, 0x9E, 0x0F, 0x7C, 0x4A, 0xEB, 0xE7, 0x8E, + 0x9B, 0x7F, 0x1A, 0xFE, 0xE2, 0x42, 0xE3, 0x4F, +}; + +static const uint8_t secp256r1_n[] = { + 0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, + 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, +}; + +/* + * Domain parameters for sm2p256v1_p + */ +static const uint32_t sm2p256v1_wide = RK_ECC_CURVE_WIDE_256; + +static const uint8_t sm2p256v1_p[] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t sm2p256v1_a[] = { + 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static const uint8_t sm2p256v1_gx[] = { + 0xC7, 0x74, 0x4C, 0x33, 0x89, 0x45, 0x5A, 0x71, + 0xE1, 0x0B, 0x66, 0xF2, 0xBF, 0x0B, 0xE3, 0x8F, + 0x94, 0xC9, 0x39, 0x6A, 0x46, 0x04, 0x99, 0x5F, + 0x19, 0x81, 0x19, 0x1F, 0x2C, 0xAE, 0xC4, 0x32, +}; + +static const uint8_t sm2p256v1_gy[] = { + 0xA0, 0xF0, 0x39, 0x21, 0xE5, 0x32, 0xDF, 0x02, + 0x40, 0x47, 0x2A, 0xC6, 0x7C, 0x87, 0xA9, 0xD0, + 0x53, 0x21, 0x69, 0x6B, 0xE3, 0xCE, 0xBD, 0x59, + 0x9C, 0x77, 0xF6, 0xF4, 0xA2, 0x36, 0x37, 0xBC, +}; + +static const uint8_t sm2p256v1_n[] = { + 0x23, 0x41, 0xD5, 0x39, 0x09, 0xF4, 0xBB, 0x53, + 0x2B, 0x05, 0xC6, 0x21, 0x6B, 0xDF, 0x03, 0x72, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, +}; + +static void dump_ecc_sram(void) +{ +#ifdef DEBUG + int i; + uint32_t len = 0x300; + uint32_t *buffer; + + buffer = kzalloc(len, GFP_KERNEL); + + for (i = 0; i < len / 4; i++) + buffer[i] = ((uint32_t *)SM2_RAM_BASE)[i]; + + CRYPTO_DUMPHEX("ECC SRAM ", buffer, len); + + kfree(buffer); +#endif +} + +static void ecc_word_memcpy(uint32_t *dst, uint32_t *src, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++, dst++) + writel_relaxed(src[i], (void *)dst); +} + +static void ecc_word_memset(uint32_t *buff, uint32_t val, uint32_t size) +{ + uint32_t i; + + for (i = 0; i < size; i++, buff++) + writel_relaxed(val, (void *)buff); +} + +static void rk_reverse_buf(uint8_t *buff, uint32_t size) +{ + uint8_t *buf_h_swap, *buf_l_swap; + uint32_t i; + uint32_t temp; + + buf_h_swap = buff + size - 1; + buf_l_swap = buff; + + for (i = 0 ; i < (size / 2) ; i++) { + temp = *buf_h_swap; + *(buf_h_swap--) = *buf_l_swap; + *(buf_l_swap++) = temp; + } +} + +static int rk_word_cmp_zero(uint32_t *buf1, uint32_t n_words) +{ + int ret = 0; + uint32_t i; + + for (i = 0 ; i < n_words; i++) { + if (buf1[i] != 0) + ret = -EINVAL; + } + + return ret; +} + +static int rk_load_hash_bn(struct rk_ecp_group *grp, struct rk_bignum *bn, + uint8_t *hash, uint32_t hash_len) +{ + if (grp == NULL || RK_ECP_IS_BIGNUM_INVALID(bn)) + return -EINVAL; + + hash_len = hash_len > grp->p_len ? grp->p_len : hash_len; + + memset(bn->data, 0x00, WORDS2BYTES(bn->n_words)); + memcpy(bn->data, hash, hash_len); + + rk_reverse_buf((void *)bn->data, hash_len); + + return 0; +} + +/* + * Set a group using well-known domain parameters + */ +static int rk_ecp_group_load(struct rk_ecp_group *grp, enum rk_ecp_group_id id) +{ + memset(grp, 0x00, sizeof(*grp)); + + grp->id = id; + grp->endian = RK_BG_LITTILE_ENDIAN; + + switch (id) { + case RK_ECP_DP_SECP192R1: + RK_LOAD_GROUP_A(secp192r1); + return 0; + + case RK_ECP_DP_SECP224R1: + RK_LOAD_GROUP_A(secp224r1); + return 0; + + case RK_ECP_DP_SECP256R1: + RK_LOAD_GROUP_A(secp256r1); + return 0; + + case RK_ECP_DP_SM2P256V1: + RK_LOAD_GROUP_A(sm2p256v1); + return 0; + + default: + return -EINVAL; + } +} + +static int rockchip_ecc_request_set(uint32_t ecc_ctl, uint32_t wide) +{ + RK_ECP_WRITE_REG(RK_ECC_CURVE_WIDE, wide); + + RK_ECP_WRITE_REG(RK_ECC_INT_EN, 0); + RK_ECP_WRITE_REG(RK_ECC_INT_ST, RK_ECP_READ_REG(RK_ECC_INT_ST)); + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl); + + return 0; +} + +static int rockchip_ecc_request_wait_done(void) +{ + int ret; + u32 reg_val = 0; + + ret = readx_poll_timeout(RK_ECP_READ_REG, RK_ECC_INT_ST, reg_val, + reg_val != 0, RK_ECP_POLL_PERIOD_US, RK_ECP_POLL_TIMEOUT_US); + if (ret) { + CRYPTO_TRACE("rk ecp poll RK_ECC_INT_ST timeout.\ns"); + goto exit; + } + + if (RK_ECP_READ_REG(RK_ECC_ABN_ST)) { + ret = -EFAULT; + goto exit; + } + +exit: + if (ret) { + CRYPTO_TRACE("RK_ECC_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_CTL)); + CRYPTO_TRACE("RK_ECC_INT_EN = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_EN)); + CRYPTO_TRACE("RK_ECC_CURVE_WIDE = %08x\n", RK_ECP_READ_REG(RK_ECC_CURVE_WIDE)); + CRYPTO_TRACE("RK_ECC_RAM_CTL = %08x\n", RK_ECP_READ_REG(RK_ECC_RAM_CTL)); + CRYPTO_TRACE("RK_ECC_INT_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_INT_ST)); + CRYPTO_TRACE("RK_ECC_ABN_ST = %08x\n", RK_ECP_READ_REG(RK_ECC_ABN_ST)); + } + + RK_ECP_WRITE_REG(RK_ECC_CTL, 0); + RK_ECP_RAM_FOR_CPU(); + + return ret; +} + +static int rockchip_ecc_request_trigger(void) +{ + uint32_t ecc_ctl = RK_ECP_READ_REG(RK_ECC_CTL); + + RK_ECP_RAM_FOR_ECC(); + + RK_ECP_WRITE_REG(RK_ECC_CTL, ecc_ctl | RK_ECC_CTL_REQ_ECC); + + return rockchip_ecc_request_wait_done(); +} + +int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign) +{ + int ret; + uint32_t curve_sel = 0; + struct rk_bignum *bn_hash = NULL; + struct rk_ecp_group grp; + struct rk_ecc_verify *ecc_st = (struct rk_ecc_verify *)SM2_RAM_BASE; + + CRYPTO_TRACE("ecc_st = %p, ecc_base = %p\n", ecc_st, ecc_base); + + if (!hash || + RK_ECP_IS_POINT_INVALID(point_P) || + RK_ECP_IS_POINT_INVALID(point_sign)) { + ret = -EINVAL; + goto exit; + } + + ret = rk_ecp_group_load(&grp, group_id); + if (ret) + goto exit; + + bn_hash = rk_bn_alloc(RK_ECP_MAX_BYTES); + if (!bn_hash) { + ret = -ENOMEM; + goto exit; + } + + curve_sel = group_id == RK_ECP_DP_SM2P256V1 ? + RK_ECC_CTL_FUNC_SM2_CURVER : RK_ECC_CTL_FUNC_ECC_CURVER; + + rk_load_hash_bn(&grp, bn_hash, hash, hash_len); + + RK_ECP_LOAD_DATA(ecc_st->e, bn_hash); + RK_ECP_LOAD_DATA(ecc_st->r_, point_sign->x); + RK_ECP_LOAD_DATA(ecc_st->s_, point_sign->y); + RK_ECP_LOAD_DATA(ecc_st->p_x, point_P->x); + RK_ECP_LOAD_DATA(ecc_st->p_y, point_P->y); + + RK_ECP_LOAD_DATA_EXT(ecc_st->A, grp.a, grp.a_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->P, grp.p, grp.p_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->N, grp.n, grp.n_len); + + RK_ECP_LOAD_DATA_EXT(ecc_st->G_x, grp.gx, grp.gx_len); + RK_ECP_LOAD_DATA_EXT(ecc_st->G_y, grp.gy, grp.gy_len); + + rockchip_ecc_request_set(curve_sel | RK_ECC_CTL_FUNC_SEL_VERIFY, grp.wide); + + ret = rockchip_ecc_request_trigger(); +exit: + if (ret || rk_word_cmp_zero(ecc_st->v, RK_ECP_MAX_WORDS)) { + ret = -EKEYREJECTED; + dump_ecc_sram(); + } + + rk_bn_free(bn_hash); + + return ret; +} + +void rockchip_ecc_init(void __iomem *base) +{ + ecc_base = base - RK_ECC_BASE_OFFSET; + + RK_ECP_WRITE_REG(RK_ECC_DATA_ENDIAN, RK_ECC_DATA_ENDIAN_LITTLE); +} + +void rockchip_ecc_deinit(void) +{ + +} + +uint32_t rockchip_ecc_get_max_size(void) +{ + return RK_ECP_MAX_BYTES; +} + +uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id) +{ + switch (group_id) { + case RK_ECP_DP_SECP192R1: + return 192; + + case RK_ECP_DP_SECP224R1: + return 224; + + case RK_ECP_DP_SECP256R1: + case RK_ECP_DP_SM2P256V1: + return 256; + + default: + return 0; + } +} + +uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo) +{ + + switch (asym_algo) { + case ASYM_ALGO_ECC_P192: + return RK_ECP_DP_SECP192R1; + case ASYM_ALGO_ECC_P224: + return RK_ECP_DP_SECP224R1; + case ASYM_ALGO_ECC_P256: + return RK_ECP_DP_SECP256R1; + case ASYM_ALGO_SM2: + return RK_ECP_DP_SM2P256V1; + default: + return RK_ECP_DP_NONE; + } +} diff --git a/drivers/crypto/rockchip/rk_crypto_ecc.h b/drivers/crypto/rockchip/rk_crypto_ecc.h new file mode 100644 index 000000000000..645c160cf8e9 --- /dev/null +++ b/drivers/crypto/rockchip/rk_crypto_ecc.h @@ -0,0 +1,152 @@ +/* SPDX-License-Identifier: GPL-2.0 */ + +/* Copyright (c) 2024 Rockchip Electronics Co. Ltd. */ + +#ifndef __RK_CRYPTO_ECC_H__ +#define __RK_CRYPTO_ECC_H__ + +#include "rk_crypto_bignum.h" + +#define RK_ECP_MAX_BITS 256 +#define RK_ECP_MAX_BYTES ((RK_ECP_MAX_BITS) / 8) +#define RK_ECP_MAX_WORDS ((RK_ECP_MAX_BITS) / 32) +#define RK_ECP_MAX_WORDS_ALL (512 / 32) + +/*************************************************************/ +/* Macros for waiting PKA machine ready states */ +/*************************************************************/ +#define RK_ECP_WRITE_REG(offset, val) writel_relaxed((val), (ecc_base) + (offset)) +#define RK_ECP_READ_REG(offset) readl_relaxed((ecc_base) + (offset)) + +#define RK_ECP_RAM_FOR_ECC() \ + RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_ECC) + +#define RK_ECP_RAM_FOR_CPU() \ + RK_ECP_WRITE_REG(RK_ECC_RAM_CTL, RK_ECC_RAM_CTL_SEL_MASK | RK_ECC_RAM_CTL_CPU) + +#define RK_ECP_LOAD_DATA(dst, big_src) \ + do { \ + ecc_word_memset((dst), 0, RK_ECP_MAX_WORDS);\ + ecc_word_memcpy((dst), (big_src->data), (big_src->n_words)); \ + } while (0) + +#define RK_ECP_LOAD_DATA_EXT(dst, src, n_bytes) \ + do { \ + ecc_word_memset((void *)(dst), 0, RK_ECP_MAX_WORDS);\ + ecc_word_memcpy((void *)(dst), (void *)(src), (n_bytes) / 4); \ + } while (0) + +#define RK_ECC_BASE_OFFSET 0x0480 + +#define RK_ECC_CTL 0x03F0 +#define RK_ECC_CTL_RAND_K_SRC_SOFT _SBF(12, 0) +#define RK_ECC_CTL_RAND_K_SRC_HARD _SBF(12, 1) +#define RK_ECC_CTL_FUNC_SM2_CURVER _SBF(8, 0x0) +#define RK_ECC_CTL_FUNC_ECC_CURVER _SBF(8, 0x1) + +#define RK_ECC_CTL_FUNC_SEL_MUL _SBF(4, 0x0) +#define RK_ECC_CTL_FUNC_SEL_KG _SBF(4, 0x1) +#define RK_ECC_CTL_FUNC_SEL_SIGN _SBF(4, 0x2) +#define RK_ECC_CTL_FUNC_SEL_VERIFY _SBF(4, 0x3) +#define RK_ECC_CTL_FUNC_SEL_MUL_MOD _SBF(4, 0x4) +#define RK_ECC_CTL_FUNC_SEL_ADD_MOD _SBF(4, 0x5) +#define RK_ECC_CTL_FUNC_SEL_DOUBLE_POINT _SBF(4, 0x6) +#define RK_ECC_CTL_FUNC_SEL_ADD_POINT _SBF(4, 0x7) +#define RK_ECC_CTL_FUNC_SEL_KP _SBF(4, 0x8) +#define RK_ECC_CTL_FUNC_SEL_KP_KG _SBF(4, 0xa) +#define RK_ECC_CTL_REQ_ECC _SBF(0, 1) + +#define RK_ECC_INT_EN 0x03F4 +#define RK_ECC_INT_EN_DONE _BIT(0) + +#define RK_ECC_INT_ST 0x03F8 +#define RK_ECC_INT_ST_DONE _BIT(0) + +#define RK_ECC_ABN_ST 0x03FC +#define RK_ECC_ABN_ST_BAD_INV_OUT _BIT(8) +#define RK_ECC_ABN_ST_BAD_K_IN _BIT(7) +#define RK_ECC_ABN_ST_BAD_R_IN _BIT(6) +#define RK_ECC_ABN_ST_BAD_S_IN _BIT(5) +#define RK_ECC_ABN_ST_BAD_R_K_MID _BIT(4) +#define RK_ECC_ABN_ST_BAD_R_OUT _BIT(3) +#define RK_ECC_ABN_ST_BAD_S_OUT _BIT(2) +#define RK_ECC_ABN_ST_BAD_T_OUT _BIT(1) +#define RK_ECC_ABN_ST_BAD_POINT_OUT _BIT(0) + +#define RK_ECC_CURVE_WIDE 0x0400 +#define RK_ECC_CURVE_WIDE_192 192 +#define RK_ECC_CURVE_WIDE_224 224 +#define RK_ECC_CURVE_WIDE_256 256 + +#define RK_ECC_MAX_CURVE_WIDE 0x0404 + +#define RK_ECC_DATA_ENDIAN 0x0408 +#define RK_ECC_DATA_ENDIAN_LITTLE 0x0 +#define RK_ECC_DATA_ENDIAN_BIG 0x1 + +#define RK_ECC_RAM_CTL 0x0480 +#define RK_ECC_RAM_CTL_SEL_MASK _SBF(16, 3) +#define RK_ECC_RAM_CTL_CPU _SBF(0, 0) +#define RK_ECC_RAM_CTL_PKA _SBF(0, 1) +#define RK_ECC_RAM_CTL_ECC _SBF(0, 2) + +#define SM2_RAM_BASE ((ecc_base) + 0x1000) + +enum rk_ecp_group_id { + RK_ECP_DP_NONE = 0, + RK_ECP_DP_SECP192R1, /*!< 192-bits NIST curve */ + RK_ECP_DP_SECP224R1, /*!< 224-bits NIST curve */ + RK_ECP_DP_SECP256R1, /*!< 256-bits NIST curve */ + RK_ECP_DP_SM2P256V1, /*!< */ +}; + +#define RK_ECP_IS_BIGNUM_INVALID(b) (!b || !b->data || b->n_words < RK_ECP_MAX_WORDS) +#define RK_ECP_IS_POINT_INVALID(p) (RK_ECP_IS_BIGNUM_INVALID(p->x) && \ + RK_ECP_IS_BIGNUM_INVALID(p->y)) + +struct rk_ecp_group { + enum rk_ecp_group_id id; /*!< internal group identifier */ + const char *curve_name; + uint32_t wide; + const uint8_t *p; /*!< prime modulus of the base field */ + const uint8_t *a; /*!< 1. A in the equation, or 2. (A + 2) / 4 */ + const uint8_t *n; + const uint8_t *gx; + const uint8_t *gy; + size_t p_len; + size_t a_len; + size_t n_len; + size_t gx_len; + size_t gy_len; + enum bignum_endian endian; +}; + +struct rk_ecc_verify { + uint32_t e[RK_ECP_MAX_WORDS_ALL]; // 0x00 + uint32_t r_[RK_ECP_MAX_WORDS_ALL]; // 0x40 + uint32_t s_[RK_ECP_MAX_WORDS_ALL]; // 0x80 + uint32_t p_x[RK_ECP_MAX_WORDS_ALL]; // 0xC0 + uint32_t p_y[RK_ECP_MAX_WORDS_ALL]; // 0x100 + uint32_t A[RK_ECP_MAX_WORDS_ALL]; // 0x140 + uint32_t P[RK_ECP_MAX_WORDS_ALL]; // 0x180 + uint32_t N[RK_ECP_MAX_WORDS_ALL]; // 0x1C0 + uint32_t G_x[RK_ECP_MAX_WORDS_ALL]; // 0x200 + uint32_t G_y[RK_ECP_MAX_WORDS_ALL]; // 0x240 + uint32_t r[RK_ECP_MAX_WORDS_ALL]; // 0x280 + uint32_t v[RK_ECP_MAX_WORDS_ALL]; // 0x2C0 +}; + +int rockchip_ecc_verify(int group_id, uint8_t *hash, uint32_t hash_len, + struct rk_ecp_point *point_P, struct rk_ecp_point *point_sign); + +void rockchip_ecc_init(void __iomem *base); + +void rockchip_ecc_deinit(void); + +uint32_t rockchip_ecc_get_max_size(void); + +uint32_t rockchip_ecc_get_curve_nbits(uint32_t group_id); + +uint32_t rockchip_ecc_get_group_id(uint32_t asym_algo); + +#endif diff --git a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c index 1311ea3d4eac..bea5e3f006d3 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_akcipher.c @@ -8,13 +8,18 @@ * * Some ideas are from marvell/cesa.c and s5p-sss.c driver. */ - +#include +#include #include +#include #include "rk_crypto_core.h" #include "rk_crypto_v2.h" #include "rk_crypto_v2_reg.h" #include "rk_crypto_v2_pka.h" +#include "rk_crypto_ecc.h" +#include "rk_sm2signature.asn1.h" +#include "rk_ecdsasignature.asn1.h" #define BG_WORDS2BYTES(words) ((words) * sizeof(u32)) #define BG_BYTES2WORDS(bytes) (((bytes) + sizeof(u32) - 1) / sizeof(u32)) @@ -294,12 +299,16 @@ static void rk_rsa_exit_tfm(struct crypto_akcipher *tfm) rk_rsa_clear_ctx(ctx); - ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa"); + if (ctx->rk_dev && ctx->rk_dev->release_crypto) + ctx->rk_dev->release_crypto(ctx->rk_dev, "rsa"); + + memset(ctx, 0x00, sizeof(*ctx)); } struct rk_crypto_algt rk_v2_asym_rsa = { .name = "rsa", .type = ALG_TYPE_ASYM, + .algo = ASYM_ALGO_RSA, .alg.asym = { .encrypt = rk_rsa_enc, .decrypt = rk_rsa_dec, @@ -319,3 +328,241 @@ struct rk_crypto_algt rk_v2_asym_rsa = { }, }; +int rk_ecc_get_signature_r(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct rk_ecp_point *sig = context; + const uint8_t *tmp_value = value; + + if (!value || !vlen) + return -EINVAL; + + /* skip first zero */ + if (tmp_value[0] == 0x00) { + tmp_value += 1; + vlen -= 1; + } + + return rk_bn_set_data(sig->x, tmp_value, vlen, RK_BG_BIG_ENDIAN); +} + +int rk_ecc_get_signature_s(void *context, size_t hdrlen, unsigned char tag, + const void *value, size_t vlen) +{ + struct rk_ecp_point *sig = context; + const uint8_t *tmp_value = value; + + if (!value || !vlen) + return -EINVAL; + + /* skip first zero */ + if (tmp_value[0] == 0x00) { + tmp_value += 1; + vlen -= 1; + } + + return rk_bn_set_data(sig->y, tmp_value, vlen, RK_BG_BIG_ENDIAN); +} + +static int rk_ecc_verify(struct akcipher_request *req) +{ + struct crypto_akcipher *tfm = crypto_akcipher_reqtfm(req); + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + size_t keylen = ctx->nbits / 8; + struct rk_ecp_point *sig_point = NULL; + u8 rawhash[RK_ECP_MAX_BYTES]; + unsigned char *buffer; + ssize_t diff; + int ret; + + if (unlikely(!ctx->pub_key_set)) + return -EINVAL; + + buffer = kmalloc(req->src_len + req->dst_len, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + sig_point = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES); + if (!sig_point) { + ret = -ENOMEM; + goto exit; + } + + sg_pcopy_to_buffer(req->src, sg_nents_for_len(req->src, req->src_len + req->dst_len), + buffer, req->src_len + req->dst_len, 0); + + CRYPTO_DUMPHEX("total signture:", buffer, req->src_len); + + if (ctx->group_id == RK_ECP_DP_SM2P256V1) + ret = asn1_ber_decoder(&rk_sm2signature_decoder, sig_point, buffer, req->src_len); + else + ret = asn1_ber_decoder(&rk_ecdsasignature_decoder, sig_point, buffer, req->src_len); + if (ret < 0) + goto exit; + + CRYPTO_DUMPHEX("bn r value = ", sig_point->x->data, BG_WORDS2BYTES(sig_point->x->n_words)); + CRYPTO_DUMPHEX("bn s value = ", sig_point->y->data, BG_WORDS2BYTES(sig_point->y->n_words)); + + /* if the hash is shorter then we will add leading zeros to fit to ndigits */ + memset(rawhash, 0x00, sizeof(rawhash)); + diff = keylen - req->dst_len; + if (diff >= 0) { + if (diff) + memset(rawhash, 0, diff); + memcpy(&rawhash[diff], buffer + req->src_len, req->dst_len); + } else if (diff < 0) { + /* given hash is longer, we take the left-most bytes */ + memcpy(&rawhash, buffer + req->src_len, keylen); + } + + CRYPTO_DUMPHEX("rawhash:", rawhash, sizeof(rawhash)); + + mutex_lock(&akcipher_mutex); + + ret = rockchip_ecc_verify(ctx->group_id, rawhash, keylen, ctx->point_Q, sig_point); + + mutex_unlock(&akcipher_mutex); +exit: + kfree(buffer); + rk_ecc_free_point(sig_point); + + CRYPTO_TRACE("ret = %d\n", ret); + + return ret; +} + +/* + * Set the public key given the raw uncompressed key data from an X509 + * certificate. The key data contain the concatenated X and Y coordinates of + * the public key. + */ +static int rk_ecc_set_pub_key(struct crypto_akcipher *tfm, const void *key, unsigned int keylen) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct rk_ecp_point *pub_Q = ctx->point_Q; + const unsigned char *d = key; + uint32_t nbytes; + + CRYPTO_TRACE(); + + CRYPTO_DUMPHEX("key = ", key, keylen); + + if (keylen < 1 || (((keylen - 1) >> 1) % sizeof(u32)) != 0) + return -EINVAL; + + /* we only accept uncompressed format indicated by '4' */ + if (d[0] != 4) + return -EINVAL; + + keylen--; + d++; + + nbytes = keylen / 2; + + CRYPTO_TRACE("keylen = %u, nbytes = %u, group_id = %u, curve_byte = %u\n", + keylen, nbytes, ctx->group_id, + rockchip_ecc_get_curve_nbits(ctx->group_id) / 8); + + if (nbytes != rockchip_ecc_get_curve_nbits(ctx->group_id) / 8) + return -EINVAL; + + rk_bn_set_data(pub_Q->x, d, nbytes, RK_BG_BIG_ENDIAN); + rk_bn_set_data(pub_Q->y, d + nbytes, nbytes, RK_BG_BIG_ENDIAN); + + CRYPTO_DUMPHEX("Qx = ", pub_Q->x->data, BG_WORDS2BYTES(pub_Q->x->n_words)); + CRYPTO_DUMPHEX("Qy = ", pub_Q->y->data, BG_WORDS2BYTES(pub_Q->y->n_words)); + + if (rk_ecp_point_is_zero(pub_Q)) + return -EINVAL; + + ctx->pub_key_set = true; + + return 0; +} + +static unsigned int rk_ecc_max_size(struct crypto_akcipher *tfm) +{ + CRYPTO_TRACE(); + + return rockchip_ecc_get_max_size(); +} + +static int rk_ecc_init_tfm(struct crypto_akcipher *tfm) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg); + struct rk_crypto_algt *algt; + struct rk_crypto_dev *rk_dev; + + CRYPTO_TRACE(); + + if (!ctx) + return -EINVAL; + + memset(ctx, 0x00, sizeof(*ctx)); + + algt = container_of(alg, struct rk_crypto_algt, alg.asym); + rk_dev = algt->rk_dev; + + if (!rk_dev->request_crypto) + return -EFAULT; + + rk_dev->request_crypto(rk_dev, algt->name); + + ctx->rk_dev = rk_dev; + ctx->group_id = rockchip_ecc_get_group_id(algt->algo); + ctx->nbits = rockchip_ecc_get_curve_nbits(ctx->group_id); + ctx->point_Q = rk_ecc_alloc_point_zero(RK_ECP_MAX_BYTES); + + rockchip_ecc_init(ctx->rk_dev->pka_reg); + + return 0; +} + +static void rk_ecc_exit_tfm(struct crypto_akcipher *tfm) +{ + struct rk_ecc_ctx *ctx = akcipher_tfm_ctx(tfm); + struct akcipher_alg *alg = __crypto_akcipher_alg(tfm->base.__crt_alg); + struct rk_crypto_algt *algt; + + CRYPTO_TRACE(); + + if (!ctx) + return; + + rk_ecc_free_point(ctx->point_Q); + + rockchip_ecc_deinit(); + + algt = container_of(alg, struct rk_crypto_algt, alg.asym); + + if (ctx->rk_dev && ctx->rk_dev->release_crypto) + ctx->rk_dev->release_crypto(ctx->rk_dev, algt->name); + + memset(ctx, 0x00, sizeof(*ctx)); +} + +struct rk_crypto_algt rk_asym_ecc_p192 = RK_ASYM_ECC_INIT(192); +struct rk_crypto_algt rk_asym_ecc_p224 = RK_ASYM_ECC_INIT(224); +struct rk_crypto_algt rk_asym_ecc_p256 = RK_ASYM_ECC_INIT(256); + +struct rk_crypto_algt rk_asym_sm2 = { + .name = "sm2", + .type = ALG_TYPE_ASYM, + .algo = ASYM_ALGO_SM2, + .alg.asym = { + .verify = rk_ecc_verify, + .set_pub_key = rk_ecc_set_pub_key, + .max_size = rk_ecc_max_size, + .init = rk_ecc_init_tfm, + .exit = rk_ecc_exit_tfm, + .reqsize = 64, + .base = { + .cra_name = "sm2", + .cra_driver_name = "sm2-rk", + .cra_priority = RK_CRYPTO_PRIORITY, + .cra_module = THIS_MODULE, + .cra_ctxsize = sizeof(struct rk_ecc_ctx), + }, + } +}; diff --git a/drivers/crypto/rockchip/rk_crypto_v2_pka.c b/drivers/crypto/rockchip/rk_crypto_v2_pka.c index d2c0a265b3ad..569800857f75 100644 --- a/drivers/crypto/rockchip/rk_crypto_v2_pka.c +++ b/drivers/crypto/rockchip/rk_crypto_v2_pka.c @@ -434,6 +434,7 @@ exit: static void pka_finish(void) { RK_PKA_TERMINATE(); + PKA_RAM_FOR_CPU(); PKA_CLK_DISABLE(); } diff --git a/drivers/crypto/rockchip/rk_crypto_v3.c b/drivers/crypto/rockchip/rk_crypto_v3.c index 7cd728599d88..eb7d4e0a5e20 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3.c +++ b/drivers/crypto/rockchip/rk_crypto_v3.c @@ -94,6 +94,10 @@ static struct rk_crypto_algt *crypto_v3_algs[] = { /* Shared v2 version implementation */ &rk_v2_asym_rsa, /* rsa */ + &rk_asym_ecc_p192, /* ecc nist p192 */ + &rk_asym_ecc_p224, /* ecc nist p224 */ + &rk_asym_ecc_p256, /* ecc nist p256 */ + &rk_asym_sm2, /* sm2 */ }; static bool rk_is_cipher_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 mode, u32 key_len) @@ -161,6 +165,21 @@ static bool rk_is_hash_support(struct rk_crypto_dev *rk_dev, u32 algo, u32 type) return version & mask; } +static bool rk_is_asym_support(struct rk_crypto_dev *rk_dev, u32 algo) +{ + switch (algo) { + case ASYM_ALGO_RSA: + return !!CRYPTO_READ(rk_dev, CRYPTO_PKA_VERSION); + case ASYM_ALGO_ECC_P192: + case ASYM_ALGO_ECC_P224: + case ASYM_ALGO_ECC_P256: + case ASYM_ALGO_SM2: + return !!CRYPTO_READ(rk_dev, CRYPTO_ECC_MAX_CURVE_WIDE); + default: + return false; + } +} + int rk_hw_crypto_v3_init(struct device *dev, void *hw_info) { struct rk_hw_crypto_v3_info *info = @@ -208,8 +227,8 @@ bool rk_hw_crypto_v3_algo_valid(struct rk_crypto_dev *rk_dev, struct rk_crypto_a CRYPTO_TRACE("HASH/HMAC"); return rk_is_hash_support(rk_dev, aglt->algo, aglt->type); } else if (aglt->type == ALG_TYPE_ASYM) { - CRYPTO_TRACE("RSA"); - return true; + CRYPTO_TRACE("ASYM"); + return rk_is_asym_support(rk_dev, aglt->algo); } else { return false; } diff --git a/drivers/crypto/rockchip/rk_crypto_v3.h b/drivers/crypto/rockchip/rk_crypto_v3.h index a4b181416300..bc75c1bf99b2 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3.h +++ b/drivers/crypto/rockchip/rk_crypto_v3.h @@ -72,6 +72,10 @@ extern struct rk_crypto_algt rk_v3_hmac_sm3; /* Shared v2 version implementation */ extern struct rk_crypto_algt rk_v2_asym_rsa; +extern struct rk_crypto_algt rk_asym_ecc_p192; +extern struct rk_crypto_algt rk_asym_ecc_p224; +extern struct rk_crypto_algt rk_asym_ecc_p256; +extern struct rk_crypto_algt rk_asym_sm2; int rk_hw_crypto_v3_init(struct device *dev, void *hw_info); void rk_hw_crypto_v3_deinit(struct device *dev, void *hw_info); diff --git a/drivers/crypto/rockchip/rk_crypto_v3_reg.h b/drivers/crypto/rockchip/rk_crypto_v3_reg.h index 1c4c45317a28..d271ed81eb47 100644 --- a/drivers/crypto/rockchip/rk_crypto_v3_reg.h +++ b/drivers/crypto/rockchip/rk_crypto_v3_reg.h @@ -20,6 +20,8 @@ #define CRYPTO_BC_MID_IS_VALID BIT(0) #define CRYPTO_HASH_MID_IS_VALID BIT(1) +#define CRYPTO_ECC_MAX_CURVE_WIDE 0x0404 + #define CRYPTO_KEY_SEL 0x0610 #define CRYPTO_MID_VALID_SWITCH 0x0630 diff --git a/drivers/crypto/rockchip/rk_ecdsasignature.asn1 b/drivers/crypto/rockchip/rk_ecdsasignature.asn1 new file mode 100644 index 000000000000..aef4ac16985d --- /dev/null +++ b/drivers/crypto/rockchip/rk_ecdsasignature.asn1 @@ -0,0 +1,8 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (c) 2024 Rockchip Electronics Co., Ltd. + +ECDSASignature ::= SEQUENCE { + x INTEGER ({ rk_ecc_get_signature_r }), + y INTEGER ({ rk_ecc_get_signature_s }) +} diff --git a/drivers/crypto/rockchip/rk_sm2signature.asn1 b/drivers/crypto/rockchip/rk_sm2signature.asn1 new file mode 100644 index 000000000000..49d1178d713d --- /dev/null +++ b/drivers/crypto/rockchip/rk_sm2signature.asn1 @@ -0,0 +1,8 @@ +-- SPDX-License-Identifier: BSD-3-Clause +-- +-- Copyright (c) 2024 Rockchip Electronics Co., Ltd. + +Sm2Signature ::= SEQUENCE { + x INTEGER ({ rk_ecc_get_signature_r }), + y INTEGER ({ rk_ecc_get_signature_s }) +} From db7fd2993d285205db909855da6d726fb9086618 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Wed, 26 Jun 2024 19:45:16 +0800 Subject: [PATCH 03/50] drm/rockchip: vop2: fbc vir height should aligned as block height Signed-off-by: Sandy Huang Change-Id: I144728c4a98b64709aaf5ccb5fda9dd43062204b --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 23 +++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index d7f6f40a7c19..95955ed4fe07 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -2620,14 +2620,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 +2644,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); From 8449b4d2c28a311299486a713d600c69ac3f720a Mon Sep 17 00:00:00 2001 From: Elon Zhang Date: Sat, 29 Jun 2024 15:18:15 +0800 Subject: [PATCH 04/50] crypto: rockchip: fix asn1 files dependence error rk_crypto_v2_akcipher.c require asn1 files but not rk_crypto_ecc.c, avoid compile errors like below: drivers/crypto/rockchip/rk_crypto_v2_akcipher.c:21:10: fatal error: rk_sm2signature.asn1.h: No such file or directory 21 | #include "rk_sm2signature.asn1.h" | ^~~~~~~~~~~~~~~~~~~~~~~~ compilation terminated. make[5]: *** [scripts/Makefile.build:250: drivers/crypto/rockchip/rk_crypto_v2_akcipher.o] Error 1 make[4]: *** [scripts/Makefile.build:500: drivers/crypto/rockchip] Error 2 make[3]: *** [scripts/Makefile.build:500: drivers/crypto] Error 2 Fixes: 743c5b92abb4 ("crypto: rockchip: add ECC/SM2 support") Signed-off-by: Elon Zhang Change-Id: Id28fa9fdc21ea9cd56a73ece2baef512dc304925 --- drivers/crypto/rockchip/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/crypto/rockchip/Makefile b/drivers/crypto/rockchip/Makefile index f11277ee6c00..d629bbb38948 100644 --- a/drivers/crypto/rockchip/Makefile +++ b/drivers/crypto/rockchip/Makefile @@ -13,7 +13,7 @@ rk_crypto-$(CONFIG_CRYPTO_DEV_ROCKCHIP_V1) += \ $(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_ecc.o: $(obj)/rk_sm2signature.asn1.h $(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 \ From cdc9ee05882d3e8d1f596f74522554f0a4fe8eb7 Mon Sep 17 00:00:00 2001 From: Xueman Ruan Date: Mon, 1 Jul 2024 09:31:40 +0800 Subject: [PATCH 05/50] video: rockchip: mpp: fix iep2 page-fault issue The issue occurs when mode is I1O1T in 1080p. Change-Id: I3ac5167d1bf0eb13dd4b48056f38bee3cf0dedf1 Signed-off-by: Xueman Ruan --- drivers/video/rockchip/mpp/mpp_iep2.c | 89 +++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) diff --git a/drivers/video/rockchip/mpp/mpp_iep2.c b/drivers/video/rockchip/mpp/mpp_iep2.c index 8e4a0050384e..275c76524c79 100644 --- a/drivers/video/rockchip/mpp/mpp_iep2.c +++ b/drivers/video/rockchip/mpp/mpp_iep2.c @@ -36,6 +36,9 @@ #define MVL 28 #define MVR 27 +#define IOMMU_GET_BUS_ID(x) (((x) >> 6) & 0x1f) +#define AUX_PAGE_SIZE SZ_4K + enum rockchip_iep2_fmt { ROCKCHIP_IEP2_FMT_YUV422 = 2, ROCKCHIP_IEP2_FMT_YUV420 @@ -193,6 +196,12 @@ struct iep2_output { u32 y_end[8]; }; +struct iep2_session_priv { + /* workaround for pagefault */ + unsigned long aux_iova; + struct page *aux_page; +}; + struct iep_task { struct mpp_task mpp_task; struct mpp_hw_info *hw_info; @@ -247,6 +256,8 @@ static int iep2_process_reg_fd(struct mpp_session *session, ARRAY_SIZE(task->params.dst) * 3 + 2; u32 *paddr = &task->params.src[0].y; + struct mpp_dev *mpp = session->mpp; + struct iep2_session_priv *priv = session->priv; for (i = 0; i < addr_num; ++i) { int usr_fd; @@ -279,6 +290,27 @@ static int iep2_process_reg_fd(struct mpp_session *session, mpp_debug(DEBUG_IOMMU, "reg[%3d]: %3d => %pad + offset %u\n", iep2_addr_rnum[i], usr_fd, &mem_region->iova, offset); paddr[i] = mem_region->iova + offset; + + /* workaround for invalid access to src image */ + if (task->params.dil_mode == ROCKCHIP_IEP2_DIL_MODE_I1O1T && + iep2_addr_rnum[i] == 24 && priv->aux_page) { + int ret = 0; + unsigned long page_iova = mem_region->iova + mem_region->len; + + if (priv->aux_iova != -1) { + iommu_unmap(mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE); + priv->aux_iova = -1; + } + + page_iova = round_down(page_iova, AUX_PAGE_SIZE); + ret = iommu_map(mpp->iommu_info->domain, page_iova, + page_to_phys(priv->aux_page), AUX_PAGE_SIZE, + IOMMU_READ); + if (!ret) { + priv->aux_iova = page_iova; + mpp_debug(DEBUG_IOMMU, "aux iova %lx\n", page_iova); + } + } } return 0; @@ -765,6 +797,12 @@ static int iep2_free_task(struct mpp_session *session, struct mpp_task *mpp_task) { struct iep_task *task = to_iep_task(mpp_task); + struct iep2_session_priv *priv = session->priv; + + if (priv->aux_iova != -1) { + iommu_unmap(session->mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE); + priv->aux_iova = -1; + } mpp_task_finalize(session, mpp_task); kfree(task); @@ -928,6 +966,55 @@ static int iep2_reset(struct mpp_dev *mpp) return 0; } +static int iep2_init_session(struct mpp_session *session) +{ + struct iep2_session_priv *priv; + + if (!session) { + mpp_err("session is null\n"); + return -EINVAL; + } + + priv = kzalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + /* warkaround for mmu pagefault */ + priv->aux_iova = -1; + priv->aux_page = alloc_page(GFP_KERNEL); + if (!priv->aux_page) { + dev_err(session->mpp->dev, "allocate a page for auxiliary usage\n"); + priv->aux_page = NULL; + } + + session->priv = priv; + + return 0; +} + +static int iep2_free_session(struct mpp_session *session) +{ + if (session && session->priv) { + struct iep2_session_priv *priv = session->priv; + struct mpp_dev *mpp = session->mpp; + + if (priv->aux_iova != -1) { + iommu_unmap(mpp->iommu_info->domain, priv->aux_iova, AUX_PAGE_SIZE); + priv->aux_iova = -1; + } + + if (priv->aux_page) { + __free_page(priv->aux_page); + priv->aux_page = NULL; + } + + kfree(session->priv); + session->priv = NULL; + } + + return 0; +} + static struct mpp_hw_ops iep_v2_hw_ops = { .init = iep2_init, .clk_on = iep2_clk_on, @@ -944,6 +1031,8 @@ static struct mpp_dev_ops iep_v2_dev_ops = { .finish = iep2_finish, .result = iep2_result, .free_task = iep2_free_task, + .init_session = iep2_init_session, + .free_session = iep2_free_session, }; static struct mpp_hw_info iep2_hw_info = { From b054d2c7683c204abe8bacefee1caab5ca35c8c5 Mon Sep 17 00:00:00 2001 From: Damon Ding Date: Mon, 1 Jul 2024 19:06:26 +0800 Subject: [PATCH 06/50] arm64: dts: rockchip: rk3568: disable lvds1_in_vp1/lvds1_in_vp2 by default Fixes: 5f0fc285ff32 ("arm64: dts: rockchip: add dual lvds support for rk3567/rk3568") Change-Id: Ie2c7ea76bdfcc29c5a28ed373ead0a00dde911a1 Signed-off-by: Damon Ding Signed-off-by: Chaoyi Chen --- arch/arm64/boot/dts/rockchip/rk3568.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3568.dtsi b/arch/arm64/boot/dts/rockchip/rk3568.dtsi index 65f4ea699266..7897f302b2e8 100644 --- a/arch/arm64/boot/dts/rockchip/rk3568.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3568.dtsi @@ -350,11 +350,13 @@ lvds1_in_vp1: endpoint@0 { reg = <0>; remote-endpoint = <&vp1_out_lvds1>; + status = "disabled"; }; lvds1_in_vp2: endpoint@1 { reg = <1>; remote-endpoint = <&vp2_out_lvds1>; + status = "disabled"; }; }; }; From 907e477376e272d8db1bd92fccc01f3c6134be41 Mon Sep 17 00:00:00 2001 From: Cody Xie Date: Tue, 2 Jul 2024 09:59:53 +0800 Subject: [PATCH 07/50] gpio: nca9539: Add Runtime PM APIs Change-Id: If4c20ead4a2273ec281f8ea69ed5306f18e72f5d Signed-off-by: Cody Xie Signed-off-by: Cai Wenzhong --- drivers/gpio/gpio-nca9539.c | 85 +++++++++++++++++++++++++++++++++++-- 1 file changed, 82 insertions(+), 3 deletions(-) diff --git a/drivers/gpio/gpio-nca9539.c b/drivers/gpio/gpio-nca9539.c index afeccd30c369..7c9acf889873 100644 --- a/drivers/gpio/gpio-nca9539.c +++ b/drivers/gpio/gpio-nca9539.c @@ -31,11 +31,14 @@ #define NCA9539_REG_CONFIG_PORT0 (NCA9539_REG_CONFIG_BASE + 0x0) #define NCA9539_REG_CONFIG_PORT1 (NCA9539_REG_CONFIG_BASE + 0x1) +#define NCA9539_MAX_REGS 8 + struct nca9539_chip { struct gpio_chip gpio_chip; struct regmap *regmap; struct regulator *regulator; unsigned int ngpio; + u8 backup_regs[NCA9539_MAX_REGS]; }; static int nca9539_gpio_get_direction(struct gpio_chip *gc, unsigned int offset) @@ -78,8 +81,7 @@ static int nca9539_gpio_direction_input(struct gpio_chip *gc, unsigned int offse return ret; } -static int nca9539_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, - int val) +static int nca9539_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int val) { struct nca9539_chip *priv = gpiochip_get_data(gc); unsigned int port = offset / 8; @@ -233,11 +235,82 @@ 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 = { + .suspend = nca9539_suspend, + .resume = nca9539_resume, + .freeze = nca9539_suspend, + .restore = 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 +322,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 +394,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); From f2d24b9d545a7533e29afd2546c8ecf63b7a4a19 Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Tue, 2 Jul 2024 18:40:42 +0800 Subject: [PATCH 08/50] gpio: nca9539: suspend and resume using SET_LATE_SYSTEM_SLEEP_PM_OPS Signed-off-by: Cai Wenzhong Change-Id: I5dc1d2ad9b80d5aa5245866759902328d805f531 --- drivers/gpio/gpio-nca9539.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/gpio/gpio-nca9539.c b/drivers/gpio/gpio-nca9539.c index 7c9acf889873..201ffef034a2 100644 --- a/drivers/gpio/gpio-nca9539.c +++ b/drivers/gpio/gpio-nca9539.c @@ -298,10 +298,7 @@ static int nca9539_resume(struct device *dev) } static const struct dev_pm_ops nca9539_dev_pm_ops = { - .suspend = nca9539_suspend, - .resume = nca9539_resume, - .freeze = nca9539_suspend, - .restore = nca9539_resume, + SET_LATE_SYSTEM_SLEEP_PM_OPS(nca9539_suspend, nca9539_resume) }; #endif From c7c244ff39c0f4c082767c6cca3728d73374ead3 Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Thu, 27 Jun 2024 17:06:17 +0800 Subject: [PATCH 09/50] media: rockchip: vicap fixes set stream order error when suspend 1. suspend: sditf sensor off, then terminal sensor off 2. resume: terminal sensor on, then sditf sensor on Signed-off-by: Cai Wenzhong Change-Id: I762a2b66e17f4d4016e9d4fd8f0289a3c287f519 --- drivers/media/platform/rockchip/cif/capture.c | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/rockchip/cif/capture.c b/drivers/media/platform/rockchip/cif/capture.c index db6a7ca3f237..d853c40c915b 100644 --- a/drivers/media/platform/rockchip/cif/capture.c +++ b/drivers/media/platform/rockchip/cif/capture.c @@ -12179,11 +12179,10 @@ static void rkcif_sensor_quick_streaming_cb(void *data) RKMODULE_SET_QUICK_STREAM, &on); } -static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) +static int rkcif_terminal_sensor_set_stream(struct rkcif_device *cif_dev, int on) { struct rkcif_pipeline *p = &cif_dev->pipe; struct rkcif_sensor_info *terminal_sensor = &cif_dev->terminal_sensor; - struct sditf_priv *priv = cif_dev->sditf[0]; int i = 0; int ret = 0; @@ -12214,6 +12213,15 @@ static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) } } + return ret; +} + +static int rkcif_sditf_sensor_set_stream(struct rkcif_device *cif_dev, int on) +{ + struct sditf_priv *priv = cif_dev->sditf[0]; + int i = 0; + int ret = 0; + if (priv && cif_dev->sditf_cnt > 1) { if (cif_dev->is_camera_over_bridge) { for (i = 0; i < cif_dev->sditf_cnt; i++) { @@ -12241,6 +12249,22 @@ static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) } } } + + return ret; +} + +static int rkcif_subdevs_set_stream(struct rkcif_device *cif_dev, int on) +{ + int ret = 0; + + if (on) { + ret |= rkcif_terminal_sensor_set_stream(cif_dev, on); + ret |= rkcif_sditf_sensor_set_stream(cif_dev, on); + } else { + ret |= rkcif_sditf_sensor_set_stream(cif_dev, on); + ret |= rkcif_terminal_sensor_set_stream(cif_dev, on); + } + return ret; } From 121d6e9be070efbb8537fc3fb345877341411f57 Mon Sep 17 00:00:00 2001 From: Cai Wenzhong Date: Mon, 17 Jun 2024 15:54:41 +0800 Subject: [PATCH 10/50] media: i2c: maxim: driver version v3.07.00 Signed-off-by: Cai Wenzhong Change-Id: Idfd53c2055d8496efd4624f1aaaa6fda0397cfcf --- .../i2c/maxim/local/maxim2c/maxim2c_drv.c | 40 ++++++++++++++++++- .../i2c/maxim/local/maxim2c/maxim2c_v4l2.c | 20 ++++++++++ .../i2c/maxim/local/maxim4c/maxim4c_drv.c | 40 ++++++++++++++++++- .../i2c/maxim/local/maxim4c/maxim4c_v4l2.c | 20 ++++++++++ 4 files changed, 118 insertions(+), 2 deletions(-) diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c index ae4ebd53c28d..1023f607886a 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_drv.c @@ -52,6 +52,10 @@ * 2. mode vc initialization when vc-array isn't configured * 3. fix the issue of mutex deadlock during hot plug * + * V3.07.00 + * 1. v4l2 ioctl add command to support quick stream setting + * 2. dev_pm_ops add suspend and resume for system sleep + * */ #include #include @@ -79,7 +83,7 @@ #include "maxim2c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x07, 0x00) #define MAXIM2C_NAME "maxim2c" @@ -420,9 +424,43 @@ static int maxim2c_runtime_suspend(struct device *dev) #endif /* MAXIM2C_LOCAL_DES_ON_OFF_EN */ } +static int __maybe_unused maxim2c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + maxim2c_t *maxim2c = v4l2_get_subdevdata(sd); + int ret = 0; + + dev_info(dev, "maxim2c resume\n"); + +#if (MAXIM2C_LOCAL_DES_ON_OFF_EN == 0) +#if MAXIM2C_TEST_PATTERN + ret = maxim2c_pattern_hw_init(maxim2c); + if (ret) { + dev_err(dev, "test pattern hw init error\n"); + return ret; + } +#else + ret = maxim2c_module_hw_init(maxim2c); + if (ret) { + dev_err(dev, "maxim2c module hw init error\n"); + return ret; + } +#endif /* MAXIM2C_TEST_PATTERN */ +#endif /* MAXIM2C_LOCAL_DES_ON_OFF_EN */ + + return 0; +} + +static int __maybe_unused maxim2c_suspend(struct device *dev) +{ + return 0; +} + static const struct dev_pm_ops maxim2c_pm_ops = { SET_RUNTIME_PM_OPS( maxim2c_runtime_suspend, maxim2c_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(maxim2c_suspend, maxim2c_resume) }; static void maxim2c_module_data_init(maxim2c_t *maxim2c) diff --git a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c index 09f46e9db148..9c6d53e3e5be 100644 --- a/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c +++ b/drivers/media/i2c/maxim/local/maxim2c/maxim2c_v4l2.c @@ -436,6 +436,7 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; dev_dbg(&maxim2c->client->dev, "ioctl cmd = 0x%08x\n", cmd); @@ -473,6 +474,17 @@ static long maxim2c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ch_info = (struct rkmodule_channel_info *)arg; ret = maxim2c_get_channel_info(maxim2c, ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + stream = *((u32 *)arg); + + if (stream) + ret = maxim2c_mipi_csi_output(maxim2c, true); + else + ret = maxim2c_mipi_csi_output(maxim2c, false); + + dev_info(&maxim2c->client->dev, + "set quick stream = %d: mipi csi output ret = %ld\n", stream, ret); + break; default: ret = -ENOIOCTLCMD; break; @@ -491,6 +503,7 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; switch (cmd) { @@ -598,6 +611,13 @@ static long maxim2c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, } kfree(ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + ret = copy_from_user(&stream, up, sizeof(u32)); + if (!ret) + ret = maxim2c_ioctl(sd, cmd, &stream); + else + ret = -EFAULT; + break; default: ret = -ENOIOCTLCMD; break; diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c index 11a2c49324d8..6e15578fb1d9 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_drv.c @@ -75,6 +75,10 @@ * 2. mode vc initialization when vc-array isn't configured * 3. fix the issue of mutex deadlock during hot plug * + * V3.07.00 + * 1. v4l2 ioctl add command to support quick stream setting + * 2. dev_pm_ops add suspend and resume for system sleep + * */ #include #include @@ -102,7 +106,7 @@ #include "maxim4c_api.h" -#define DRIVER_VERSION KERNEL_VERSION(3, 0x06, 0x00) +#define DRIVER_VERSION KERNEL_VERSION(3, 0x07, 0x00) #define MAXIM4C_NAME "maxim4c" @@ -495,9 +499,43 @@ static int maxim4c_runtime_suspend(struct device *dev) #endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ } +static int __maybe_unused maxim4c_resume(struct device *dev) +{ + struct i2c_client *client = to_i2c_client(dev); + struct v4l2_subdev *sd = i2c_get_clientdata(client); + maxim4c_t *maxim4c = v4l2_get_subdevdata(sd); + int ret = 0; + + dev_info(dev, "maxim4c resume\n"); + +#if (MAXIM4C_LOCAL_DES_ON_OFF_EN == 0) +#if MAXIM4C_TEST_PATTERN + ret = maxim4c_pattern_hw_init(maxim4c); + if (ret) { + dev_err(dev, "test pattern hw init error\n"); + return ret; + } +#else + ret = maxim4c_module_hw_init(maxim4c); + if (ret) { + dev_err(dev, "maxim4c module hw init error\n"); + return ret; + } +#endif /* MAXIM4C_TEST_PATTERN */ +#endif /* MAXIM4C_LOCAL_DES_ON_OFF_EN */ + + return 0; +} + +static int __maybe_unused maxim4c_suspend(struct device *dev) +{ + return 0; +} + static const struct dev_pm_ops maxim4c_pm_ops = { SET_RUNTIME_PM_OPS( maxim4c_runtime_suspend, maxim4c_runtime_resume, NULL) + SET_LATE_SYSTEM_SLEEP_PM_OPS(maxim4c_suspend, maxim4c_resume) }; static void maxim4c_module_data_init(maxim4c_t *maxim4c) diff --git a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c index c0906470039b..0b87827f14f9 100644 --- a/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c +++ b/drivers/media/i2c/maxim/local/maxim4c/maxim4c_v4l2.c @@ -436,6 +436,7 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; dev_dbg(&maxim4c->client->dev, "ioctl cmd = 0x%08x\n", cmd); @@ -473,6 +474,17 @@ static long maxim4c_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg) ch_info = (struct rkmodule_channel_info *)arg; ret = maxim4c_get_channel_info(maxim4c, ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + stream = *((u32 *)arg); + + if (stream) + ret = maxim4c_mipi_csi_output(maxim4c, true); + else + ret = maxim4c_mipi_csi_output(maxim4c, false); + + dev_info(&maxim4c->client->dev, + "set quick stream = %d: mipi csi output ret = %ld\n", stream, ret); + break; default: ret = -ENOIOCTLCMD; break; @@ -491,6 +503,7 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, struct rkmodule_csi_dphy_param *dphy_param; struct rkmodule_capture_info *capture_info; struct rkmodule_channel_info *ch_info; + u32 stream = 0; long ret = 0; switch (cmd) { @@ -598,6 +611,13 @@ static long maxim4c_compat_ioctl32(struct v4l2_subdev *sd, unsigned int cmd, } kfree(ch_info); break; + case RKMODULE_SET_QUICK_STREAM: + ret = copy_from_user(&stream, up, sizeof(u32)); + if (!ret) + ret = maxim4c_ioctl(sd, cmd, &stream); + else + ret = -EFAULT; + break; default: ret = -ENOIOCTLCMD; break; From 67c888e2816c82b16c0af436246efc3aec925454 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Fri, 22 Mar 2024 10:27:13 +0800 Subject: [PATCH 11/50] drm/rockchip: debugfs: Use DRM plane info to implement the buffer dump This patch deprecates the plane list record method used in the previous plane buffer dump. There is no need to record these information additionally now, as they are already accessible in DRM. Signed-off-by: Chaoyi Chen Change-Id: Id638a7309ab2ae3f7820d1779e922d008cba7e6d --- .../gpu/drm/rockchip/rockchip_drm_debugfs.c | 112 +++++++++++++----- .../gpu/drm/rockchip/rockchip_drm_debugfs.h | 34 +----- 2 files changed, 87 insertions(+), 59 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c index f43c588b76f3..b857227b43bf 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -25,6 +26,29 @@ #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; + /* @fbc_enable: indicate fbc is enabled */ + bool fbc_enable; + /* @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; + /* @fb: DRM frame buffer */ + struct drm_framebuffer *fb; +}; + static int temp_pow(int sum, int n) { int i; @@ -53,8 +77,12 @@ static int get_afbc_size(uint32_t width, uint32_t height, uint32_t bpp) 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; @@ -62,7 +90,7 @@ int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_co 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; @@ -88,21 +116,25 @@ int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_co } 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"); + snprintf(file_name, 100, "%s/%s_%dx%d_%s%s%d.%s", + DUMP_BUF_PATH, dump_info->win_name, width, dump_info->height, + format_name, dump_info->fbc_enable ? + "_FBC_" : "_", 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) + 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; + } + + kvaddr = data[0].vaddr; + + if (dump_info->fbc_enable) size = get_afbc_size(width, dump_info->height, bpp); else size = (width * dump_info->height * bpp >> 3) + uv_size; @@ -116,7 +148,41 @@ int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_co } 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 drm_rect *psrc; + struct vop_dump_info dump_info; + + drm_atomic_crtc_for_each_plane(plane, crtc) { + pstate = plane->state; + psrc = &pstate->src; + fb = pstate->fb; + if (!fb) + continue; + + dump_info.fbc_enable = rockchip_drm_is_afbc(plane, fb->modifier) || + rockchip_drm_is_rfbc(plane, fb->modifier); + dump_info.win_name = plane->name; + dump_info.yuv_format = fb->format->is_yuv; + dump_info.fb = fb; + dump_info.pitches = fb->pitches[0]; + dump_info.height = drm_rect_height(psrc) >> 16; + dump_info.format = fb->format; + + rockchip_drm_dump_plane_buffer(&dump_info, rockchip_crtc->frame_count); + } return 0; } @@ -148,13 +214,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,14 +238,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); - } - drm_modeset_unlock_all(crtc->dev); + rockchip_drm_crtc_dump_plane_buffer(crtc); rockchip_crtc->frame_count++; + drm_modeset_unlock_all(crtc->dev); } } else if (strncmp(buf, "enable", 6) == 0) { rockchip_crtc->vop_dump_status = DUMP_ENABLE; @@ -211,7 +268,6 @@ 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; ent = debugfs_create_file("dump", 0644, vop_dump_root, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h index ec104feab808..3134d851cc0e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h @@ -7,34 +7,7 @@ #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_info; /** * struct vop_dump_list - store all buffer info per frame @@ -44,7 +17,6 @@ struct vop_dump_info { */ struct vop_dump_list { struct list_head entry; - struct vop_dump_info dump_info; }; /** @@ -60,7 +32,7 @@ enum vop_dump_status { #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 +42,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; } From 9a9306f9cee21742f3f58fd93986d36652c0d3a4 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Fri, 22 Mar 2024 10:39:04 +0800 Subject: [PATCH 12/50] drm/rockchip: vop2: Use DRM plane info to implement the buffer dump This patch deprecates the plane list record method used in the previous plane buffer dump. There is no need to record these information additionally now, as they are already accessible in DRM. Signed-off-by: Chaoyi Chen Change-Id: Iaebf639bcc0759b0f1aa3c9a3888b964a8a6f35b --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 87 ++------------------ 1 file changed, 8 insertions(+), 79 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 95955ed4fe07..d50d6ac88492 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -382,7 +382,6 @@ struct vop2_plane_state { unsigned long offset; int pdaf_data_type; bool async_commit; - struct vop_dump_list *planlist; struct drm_property_blob *dci_data; }; @@ -5625,10 +5624,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); @@ -5653,11 +5648,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); } @@ -6292,29 +6282,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. */ @@ -6366,34 +6333,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 = { @@ -7754,28 +7693,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++; @@ -11770,6 +11691,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); From a607e5fabf5fed918e1e462f33c4774ce4ee5065 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Mon, 25 Mar 2024 14:17:32 +0800 Subject: [PATCH 13/50] drm/rockchip: vop: Use DRM plane info to implement the buffer dump This patch deprecates the plane list record method used in the previous plane buffer dump. There is no need to record these information additionally now, as they are already accessible in DRM. Signed-off-by: Chaoyi Chen Change-Id: I965f42cc7372c4314aa8cd4de2a8a811b41badaf --- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 82 ++------------------- 1 file changed, 8 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c index ad8cf09685e9..9f972b4ad46d 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c @@ -189,7 +189,6 @@ struct vop_plane_state { unsigned long offset; int pdaf_data_type; bool async_commit; - struct vop_dump_list *planlist; }; struct vop_win { @@ -1973,10 +1972,6 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, plane); struct vop_win *win = to_vop_win(plane); struct vop *vop = to_vop(old_state->crtc); -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_plane_state *vop_plane_state = - to_vop_plane_state(plane->state); -#endif if (!old_state->crtc) return; @@ -1997,11 +1992,6 @@ static void vop_plane_atomic_disable(struct drm_plane *plane, win->win_id == 2) VOP_WIN_SET(vop, win, yrgb_mst, 0); -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - kfree(vop_plane_state->planlist); - vop_plane_state->planlist = NULL; -#endif - spin_unlock(&vop->reg_lock); } @@ -2093,23 +2083,6 @@ static void vop_plane_atomic_update(struct drm_plane *plane, int is_yuv = fb->format->is_yuv; bool afbc_en = false; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_dump_list *planlist; - unsigned long num_pages; - struct page **pages; - struct drm_gem_object *obj; - struct rockchip_gem_object *rk_obj; - - num_pages = 0; - pages = NULL; - obj = fb->obj[0]; - rk_obj = to_rockchip_obj(obj); - if (rk_obj) { - num_pages = rk_obj->num_pages; - pages = rk_obj->pages; - } -#endif - /* * can't update plane when vop is disabled. */ @@ -2267,35 +2240,6 @@ static void vop_plane_atomic_update(struct drm_plane *plane, * actual_w, actual_h) */ vop->is_iommu_needed = true; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - kfree(vop_plane_state->planlist); - vop_plane_state->planlist = NULL; - - planlist = kmalloc(sizeof(*planlist), GFP_KERNEL); - if (planlist) { - planlist->dump_info.AFBC_flag = afbc_en; - planlist->dump_info.area_id = win->area_id; - planlist->dump_info.win_id = win->win_id; - planlist->dump_info.yuv_format = - is_yuv_support(fb->format->format); - planlist->dump_info.num_pages = num_pages; - planlist->dump_info.pages = pages; - planlist->dump_info.offset = vop_plane_state->offset; - planlist->dump_info.pitches = fb->pitches[0]; - planlist->dump_info.height = actual_h; - planlist->dump_info.format = fb->format; - list_add_tail(&planlist->entry, &vop->rockchip_crtc.vop_dump_list_head); - vop_plane_state->planlist = planlist; - } else { - DRM_ERROR("can't alloc a node of planlist %p\n", planlist); - return; - } - if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || - vop->rockchip_crtc.vop_dump_times > 0) { - rockchip_drm_dump_plane_buffer(&planlist->dump_info, vop->rockchip_crtc.frame_count); - vop->rockchip_crtc.vop_dump_times--; - } -#endif } static int vop_plane_atomic_async_check(struct drm_plane *plane, @@ -3060,28 +3004,10 @@ static size_t vop_crtc_bandwidth(struct drm_crtc *crtc, u64 line_bw_mbyte = 0; int cnt = 0, plane_num = 0; struct drm_atomic_state *state = crtc_state->state; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - struct vop_dump_list *pos, *n; - struct vop *vop = to_vop(crtc); -#endif if (!htotal || !vdisplay) return 0; -#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) - if (!vop->rockchip_crtc.vop_dump_list_init_flag) { - INIT_LIST_HEAD(&vop->rockchip_crtc.vop_dump_list_head); - vop->rockchip_crtc.vop_dump_list_init_flag = true; - } - list_for_each_entry_safe(pos, n, &vop->rockchip_crtc.vop_dump_list_head, entry) { - list_del(&pos->entry); - } - if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || - vop->rockchip_crtc.vop_dump_times > 0) { - vop->rockchip_crtc.frame_count++; - } -#endif - drm_atomic_crtc_state_for_each_plane(plane, crtc_state) plane_num++; @@ -4294,6 +4220,14 @@ static void vop_crtc_atomic_flush(struct drm_crtc *crtc, struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc->state); +#if defined(CONFIG_ROCKCHIP_DRM_DEBUG) + if (vop->rockchip_crtc.vop_dump_status == DUMP_KEEP || + vop->rockchip_crtc.vop_dump_times > 0) { + rockchip_drm_crtc_dump_plane_buffer(crtc); + vop->rockchip_crtc.vop_dump_times--; + } +#endif + vop_cfg_update(crtc, old_crtc_state); if (!vop->is_iommu_enabled && vop->is_iommu_needed) { From 8a5680ba811f17478f686fda7ba224e77112204f Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Sat, 29 Jun 2024 18:09:37 +0800 Subject: [PATCH 14/50] drm/rockchip: drv: move modifier_to_string() to rockchip_drm_drv and rename modifier_to_string() maybe used by vop/vop2/rockchip_drm_debugfs.c and rename modifier_to_string() to rockchip_drm_modifier_to_string() Signed-off-by: Sandy Huang Change-Id: I427d5f499d98315632bb91c56da37d9c014df75d --- drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 15 +++++++++++++++ drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 1 + drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 20 +++----------------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index b8d06d221c4a..44fdad4bbf9e 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -136,6 +136,21 @@ bool rockchip_drm_is_rfbc(struct drm_plane *plane, u64 modifier) } EXPORT_SYMBOL(rockchip_drm_is_rfbc); +const char *rockchip_drm_modifier_to_string(uint64_t modifier) +{ + switch (modifier) { + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_8x8): + return "_TILE-8x8"; + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE0): + return "_TILE-4x4-M0"; + case DRM_FORMAT_MOD_ROCKCHIP_TILED(ROCKCHIP_TILED_BLOCK_SIZE_4x4_MODE1): + return "_TILE-4x4-M1"; + default: + return drm_is_afbc(modifier) ? "_AFBC" : IS_ROCKCHIP_RFBC_MOD(modifier) ? "_RFBC" : ""; + } +} +EXPORT_SYMBOL(rockchip_drm_modifier_to_string); + /** * rockchip_drm_wait_vact_end * @crtc: CRTC to enable line flag diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 1e32e72769cf..0ae5b9e7b150 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -643,6 +643,7 @@ long rockchip_drm_dclk_round_rate(u32 version, struct clk *dclk, unsigned long r int rockchip_drm_dclk_set_rate(u32 version, struct clk *dclk, unsigned long rate); bool rockchip_drm_is_afbc(struct drm_plane *plane, u64 modifier); bool rockchip_drm_is_rfbc(struct drm_plane *plane, u64 modifier); +const char *rockchip_drm_modifier_to_string(uint64_t modifier); __printf(3, 4) void rockchip_drm_dbg(const struct device *dev, enum rockchip_drm_debug_category category, diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index d50d6ac88492..bbf50ff4f5d2 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -5802,20 +5802,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; @@ -6065,7 +6051,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) @@ -6319,7 +6305,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); @@ -7110,7 +7096,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, From c1c9524d3f8a2b08fe83d4b81160a508bf019946 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Tue, 2 Jul 2024 15:01:13 +0800 Subject: [PATCH 15/50] drm/rockchip: debugfs: optimize dump buffer file name and size 1. for rfbc/afbc format we need to dump all buffer at fb even userspace set src buffer offset; 2. optimize dump buffer name, so we can get buffer info correctly from file name, the following is an example of a dump file: old file name: video1920_1080_NV12.bin new file name: Cluster0-win0_fb-1920x1088_stride-1920_offset-0x0_act-1920x1080_NV12_0.bin Cluster0-win0_fb-3840x2160_stride-5760_offset-0x0_act-3840x2160_YU08_AFBC_1.bin Signed-off-by: Sandy Huang Change-Id: I96c3af65fdbe37629d408bb09a8ee9aed78a7f7f --- .../gpu/drm/rockchip/rockchip_drm_debugfs.c | 90 ++++--------------- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 2 +- 2 files changed, 18 insertions(+), 74 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c index b857227b43bf..47314b616fda 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c @@ -35,18 +35,10 @@ struct vop_dump_info { /* @win_name human readable vop win name */ const char *win_name; - /* @fbc_enable: indicate fbc is enabled */ - bool fbc_enable; - /* @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; /* @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) @@ -61,22 +53,6 @@ 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; -} - static int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int frame_count) { struct iosys_map map[DRM_FORMAT_MAX_PLANES]; @@ -84,43 +60,24 @@ static int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int f 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; 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; - } - - 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/%s_%dx%d_%s%s%d.%s", - DUMP_BUF_PATH, dump_info->win_name, width, dump_info->height, - format_name, dump_info->fbc_enable ? - "_FBC_" : "_", frame_count, "bin"); - } + 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) @@ -133,16 +90,10 @@ static int rockchip_drm_dump_plane_buffer(struct vop_dump_info *dump_info, int f } kvaddr = data[0].vaddr; - - if (dump_info->fbc_enable) - size = get_afbc_size(width, dump_info->height, bpp); - else - size = (width * dump_info->height * bpp >> 3) + uv_size; - 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 { @@ -162,27 +113,21 @@ int rockchip_drm_crtc_dump_plane_buffer(struct drm_crtc *crtc) struct drm_plane *plane; struct drm_plane_state *pstate; struct drm_framebuffer *fb; - struct drm_rect *psrc; struct vop_dump_info dump_info; drm_atomic_crtc_for_each_plane(plane, crtc) { pstate = plane->state; - psrc = &pstate->src; fb = pstate->fb; if (!fb) continue; - dump_info.fbc_enable = rockchip_drm_is_afbc(plane, fb->modifier) || - rockchip_drm_is_rfbc(plane, fb->modifier); dump_info.win_name = plane->name; - dump_info.yuv_format = fb->format->is_yuv; dump_info.fb = fb; - dump_info.pitches = fb->pitches[0]; - dump_info.height = drm_rect_height(psrc) >> 16; - dump_info.format = fb->format; + dump_info.src = &pstate->src; - rockchip_drm_dump_plane_buffer(&dump_info, rockchip_crtc->frame_count); + rockchip_drm_dump_plane_buffer(&dump_info, rockchip_crtc->vop_dump_frame_count); } + rockchip_crtc->vop_dump_frame_count++; return 0; } @@ -239,7 +184,6 @@ rockchip_drm_dump_buffer_write(struct file *file, const char __user *ubuf, } else { drm_modeset_lock_all(crtc->dev); rockchip_drm_crtc_dump_plane_buffer(crtc); - rockchip_crtc->frame_count++; drm_modeset_unlock_all(crtc->dev); } } else if (strncmp(buf, "enable", 6) == 0) { @@ -269,7 +213,7 @@ 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_times = 0; - rockchip_crtc->frame_count = 0; + rockchip_crtc->vop_dump_frame_count = 0; ent = debugfs_create_file("dump", 0644, vop_dump_root, crtc, &rockchip_drm_dump_buffer_fops); if (!ent) { diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index 0ae5b9e7b150..b2bfebdfe6a7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -177,7 +177,7 @@ struct rockchip_crtc { 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 }; From f483fa940554a8af518b113d2d2bafe424be931d Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Mon, 25 Mar 2024 17:00:42 +0800 Subject: [PATCH 16/50] drm/rockchip: debugfs: Remove unused vop_dump_list* structure vop_dump_list* is no longer used and this patch removes this structure. Signed-off-by: Chaoyi Chen Signed-off-by: Sandy Huang Change-Id: I9f32dfd707a1b7633479f2f2f8fee12ad69a96b1 --- drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h | 10 ---------- drivers/gpu/drm/rockchip/rockchip_drm_drv.h | 6 +----- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h index 3134d851cc0e..e4aace25fe31 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h @@ -9,16 +9,6 @@ struct vop_dump_info; -/** - * 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; -}; - /** * @DUMP_DISABLE: Disable dump and do not record plane info into list. * @DUMP_ENABLE: Record plane info into list. diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h index b2bfebdfe6a7..42e194b24574 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h @@ -168,14 +168,10 @@ 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 vop_dump_frame_count; #endif From 59d943019ccb392bd4a482fb07a8ac3ad28cd99b Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Wed, 20 Mar 2024 16:25:54 +0800 Subject: [PATCH 17/50] drm/rockchip: Enable ROCKCHIP_DRM_DEBUG feature by default Signed-off-by: Chaoyi Chen Change-Id: I78e1ffc660c0c735aff2e2a5cc272549ee8dd4a5 --- drivers/gpu/drm/rockchip/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 3c39856f234a..7db8abfd4174 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -23,6 +23,7 @@ if DRM_ROCKCHIP config ROCKCHIP_DRM_DEBUG bool "Rockchip DRM debug" + default y if !ROCKCHIP_MINI_KERNEL depends on DEBUG_FS help This option add a debug node to dump buf from userspace From fc4f9d2685e38e2be366ab143273ce7d1fb692d2 Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Tue, 5 Mar 2024 20:31:48 +0800 Subject: [PATCH 18/50] drm/rockchip: vop2: make sure dsc pd off take effect after close dsc pd, the following function will set vop enter standby immediately, this will lead to dsc pd close failed, so we use vop2_power_domain_put_sync() instead of vop2_power_domain_put(). Signed-off-by: Sandy Huang Change-Id: I9120e46ec2047e8358b28a3f153b54b4825a5e60 --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index bbf50ff4f5d2..0ab8bdf1a9c7 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -1972,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. @@ -4997,12 +5003,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; } From 32062f68cc72c1d4f8264675d4a355ee42f5a71d Mon Sep 17 00:00:00 2001 From: Sandy Huang Date: Sun, 28 Apr 2024 09:43:15 +0800 Subject: [PATCH 19/50] drm/rockchip: vop2: update dsc pd status when show logo with dsc In normal case, dsc power domain will enable when crtc enable and disabled when crtc disable. When enable dsc in uboot to show logo, the dsc in kernel driver can't know the real power domain status, which will trigger something wrong when disable/endale dsc power domain. To avoid this issue, we check the dsc power domain status when vop_initial. the dsc power domain get in vop_initial function is enabled only when dsc is enabled in uboot and enter into kernel driver. It need to update dsc power domain status in this case. Signed-off-by: Sandy Huang Change-Id: I9641373c2c8facc17ff90d4141909bcc3ac6b13d --- drivers/gpu/drm/rockchip/rockchip_drm_vop2.c | 35 ++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c index 0ab8bdf1a9c7..353fdd521f61 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop2.c @@ -4398,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; From baf08b1852390114ca8e1284828517d2c79f6622 Mon Sep 17 00:00:00 2001 From: David Wu Date: Wed, 3 Jul 2024 18:43:52 +0800 Subject: [PATCH 20/50] i2c: rk3x: Fix unregister restart handler error When i2c drivers probe failed, unregister_restart_handler() should be done before leave probe(). Fixes: 497e7bd6e1f7 ("i2c: rk3x: Make sure the i2c transfer to be finished before system reboot") Change-Id: I6587bd15b63315c173339c26dccf4388741d4286 Signed-off-by: David Wu --- drivers/i2c/busses/i2c-rk3x.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c index a935e62e0914..927d9ea6c597 100644 --- a/drivers/i2c/busses/i2c-rk3x.c +++ b/drivers/i2c/busses/i2c-rk3x.c @@ -1593,14 +1593,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev) spin_lock_init(&i2c->lock); init_waitqueue_head(&i2c->wait); - i2c->i2c_restart_nb.notifier_call = rk3x_i2c_restart_notify; - i2c->i2c_restart_nb.priority = 255; - ret = register_restart_handler(&i2c->i2c_restart_nb); - if (ret) { - dev_err(&pdev->dev, "failed to setup i2c restart handler.\n"); - return ret; - } - i2c->regs = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(i2c->regs)) return PTR_ERR(i2c->regs); @@ -1720,12 +1712,22 @@ static int rk3x_i2c_probe(struct platform_device *pdev) i2c->autostop_supported = true; } + i2c->i2c_restart_nb.notifier_call = rk3x_i2c_restart_notify; + i2c->i2c_restart_nb.priority = 255; + ret = register_restart_handler(&i2c->i2c_restart_nb); + if (ret) { + dev_err(&pdev->dev, "failed to setup i2c restart handler.\n"); + goto err_clk_notifier; + } + ret = i2c_add_numbered_adapter(&i2c->adap); if (ret < 0) - goto err_clk_notifier; + goto err_register_restart_handler; return 0; +err_register_restart_handler: + unregister_restart_handler(&i2c->i2c_restart_nb); err_clk_notifier: clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); err_pclk: @@ -1741,8 +1743,8 @@ static int rk3x_i2c_remove(struct platform_device *pdev) i2c_del_adapter(&i2c->adap); - clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); unregister_restart_handler(&i2c->i2c_restart_nb); + clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb); clk_unprepare(i2c->pclk); clk_unprepare(i2c->clk); From e77b6ebce245a9a7d05f73f9b0a531708066e3fb Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 27 Mar 2024 13:35:51 +0800 Subject: [PATCH 21/50] ASoC: rockchip: i2s-tdm: Optimize pm_runtime_forbid 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. Signed-off-by: Sugar Zhang Change-Id: I759e5c8c0602b380c7f50d80d8f564316beea632 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 86ccfadb8d80..d2c6b9669bed 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -2823,8 +2823,6 @@ static int rockchip_i2s_tdm_keep_clk_always_on(struct rk_i2s_tdm_dev *i2s_tdm) 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); @@ -3203,6 +3201,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; From 75d401b731c3ef1bd21dd6e6d243bce18bf7476e Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 27 Mar 2024 13:39:15 +0800 Subject: [PATCH 22/50] ASoC: rockchip: i2s-tdm: Fix register sync failed on ALWAYS-ON XFER must be placed after all registers sync done, because a lots of registers depends on the XFER-Disabled. Use regcache_sync_region to spilt the sync operation to address the XFER in the final step. And also fix for system suspend/resume by using the force one. Signed-off-by: Sugar Zhang Change-Id: I4c5c48496940b2f20edf7a5fa65ad004a5ac9a55 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 39 +++++++++------------------ 1 file changed, 12 insertions(+), 27 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index d2c6b9669bed..18d7f11db3b6 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -2929,9 +2929,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 @@ -3267,34 +3276,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 = { From bcbbd20069a34e436b64275c4d6758435defc66d Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 22 Mar 2024 18:56:46 +0800 Subject: [PATCH 23/50] ASoC: rockchip: i2s-tdm: Fix config for stage set_fmt on ALWAYS-ON Enable the xfer in the last card init stage to fix the config failed on set_tdm_slot/set_fmt. Signed-off-by: Sugar Zhang Change-Id: Ie456b08d11eef5356036a431f5fd6117e0df3823 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 18d7f11db3b6..aed50dd9751a 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -1285,6 +1285,14 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai, } } + /* Enable the xfer in the last card init stage. */ + if (i2s_tdm->quirks & QUIRK_ALWAYS_ON) { + 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); + } + err_pm_put: pm_runtime_put(cpu_dai->dev); @@ -2818,11 +2826,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); - dev_info(i2s_tdm->dev, "CLK-ALWAYS-ON: mclk: %d, bclk: %d, fsync: %d\n", mclk_rate, bclk_rate, DEFAULT_FS); From 15ec253f3c19688187cae16e58cffba38826a32c Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Fri, 29 Mar 2024 21:46:15 +0800 Subject: [PATCH 24/50] ASoC: rockchip: i2s-tdm: Init Valid Width for TDM from DT e.g. simple-audio-card,cpu { sound-dai = <&i2s0_8ch>; dai-tdm-slot-num = <8>; dai-tdm-slot-width = <32>; }; Signed-off-by: Sugar Zhang Change-Id: I55c3849d87e17145db6b4ce4af202303b5563080 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 33 +++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index aed50dd9751a..3ee692c9853c 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -2229,10 +2229,35 @@ 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 | I2S_TXCR_CSR_MASK; + val = I2S_TXCR_VDW(slot_width); + + if (!i2s_tdm->tdm_fsync_half_frame) { + switch (slots) { + case 16: + val |= I2S_CHN_8; + break; + case 12: + val |= I2S_CHN_6; + break; + case 8: + val |= I2S_CHN_4; + break; + case 4: + val |= I2S_CHN_2; + break; + default: + val |= I2S_CHN_2; + break; + } + } + + 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; From f190480867b162b7e4874760317d96355692a7cc Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Sat, 30 Mar 2024 16:53:50 +0800 Subject: [PATCH 25/50] ASoC: rockchip: i2s-tdm: Optimize the dma guard flow - Move dma guard initialize into trcm block - Move trcm always on into trcm block Signed-off-by: Sugar Zhang Change-Id: I49f7efbc52235fc87adc01a21ca2747c4c8d86b1 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 27 ++++++++------------------- 1 file changed, 8 insertions(+), 19 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 3ee692c9853c..494eb2194982 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -137,7 +137,6 @@ struct rk_i2s_tdm_dev { bool tdm_mode; bool tdm_fsync_half_frame; bool is_dma_active[SNDRV_PCM_STREAM_LAST + 1]; - bool dma_guard_initialized; unsigned int mclk_rx_freq; unsigned int mclk_tx_freq; unsigned int mclk_root0_freq; @@ -1035,13 +1034,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 +1053,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); } @@ -1286,12 +1282,8 @@ static int rockchip_i2s_tdm_set_fmt(struct snd_soc_dai *cpu_dai, } /* Enable the xfer in the last card init stage. */ - if (i2s_tdm->quirks & QUIRK_ALWAYS_ON) { - 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); - } + 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); @@ -1651,9 +1643,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; } From cb6e47fce720c00e6086237bb9a014e5aafa9b10 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Sat, 30 Mar 2024 17:05:31 +0800 Subject: [PATCH 26/50] ASoC: rockchip: trcm: Add support for always-on Initialize the dma guard and trigger run for always-on. Use the max-16w to cover all 2^n cases, maybe better per channels and fmt, at the moment, we use the simple way. Signed-off-by: Sugar Zhang Change-Id: Ia4b9ba06a9cb1385f4cda7125f7f4680e6ebe6e0 --- sound/soc/rockchip/rockchip_trcm.c | 38 ++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/sound/soc/rockchip/rockchip_trcm.c b/sound/soc/rockchip/rockchip_trcm.c index 79be9419a3f3..73f60f6f1016 100644 --- a/sound/soc/rockchip/rockchip_trcm.c +++ b/sound/soc/rockchip/rockchip_trcm.c @@ -36,6 +36,7 @@ struct dmaengine_trcm { struct dma_chan *chan[SNDRV_PCM_STREAM_LAST + 1]; struct dmaengine_dma_guard guard[SNDRV_PCM_STREAM_LAST + 1]; struct snd_soc_component component; + bool always_on; }; struct dmaengine_trcm_runtime_data { @@ -340,6 +341,7 @@ static int dmaengine_trcm_dma_guard_new(struct snd_soc_component *component, struct dmaengine_trcm *trcm = soc_component_to_trcm(component); struct snd_dmaengine_dai_dma_data *dma_data; struct snd_pcm_substream *substream; + struct snd_soc_dai *dai; struct dma_chan *chan; struct dma_slave_config slave_config; struct device *dev; @@ -350,6 +352,8 @@ static int dmaengine_trcm_dma_guard_new(struct snd_soc_component *component, for_each_pcm_streams(i) { substream = rtd->pcm->streams[i].substream; + if (!substream) + continue; dev = dmaengine_dma_dev(trcm, substream); chan = trcm->chan[i]; @@ -370,11 +374,43 @@ static int dmaengine_trcm_dma_guard_new(struct snd_soc_component *component, snd_dmaengine_pcm_set_config_from_dai_data(substream, dma_data, &slave_config); + /* + * Use the max-16w to cover all 2^n cases, maybe better + * per channels and fmt, at the moment, we use the simple + * way. + */ + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + slave_config.direction = DMA_MEM_TO_DEV; + slave_config.dst_maxburst = 16; + } else { + slave_config.direction = DMA_DEV_TO_MEM; + slave_config.src_maxburst = 16; + } + ret = dmaengine_slave_config(chan, &slave_config); if (ret) return ret; } + if (trcm->always_on) { + /* Start the first one will auto trigger bstream guard. */ + for_each_pcm_streams(i) { + substream = rtd->pcm->streams[i].substream; + if (!substream) + continue; + dai = asoc_rtd_to_cpu(rtd, 0); + if (!dai) + continue; + + dmaengine_trcm_dma_guard_ctrl(component, substream->stream, 1); + ret = dai->driver->ops->trigger(substream, + SNDRV_PCM_TRIGGER_START, + dai); + if (ret) + return ret; + } + } + return 0; } @@ -492,6 +528,8 @@ static int snd_dmaengine_trcm_register(struct device *dev) trcm->dev = dev; + trcm->always_on = device_property_read_bool(dev, "rockchip,always-on"); + #ifdef CONFIG_DEBUG_FS trcm->component.debugfs_prefix = "dma"; #endif From 5fe0d0e4afe4fdb4cef4d66002b5b4ba9552ecd8 Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 3 Apr 2024 11:46:02 +0800 Subject: [PATCH 27/50] ASoC: rockchip: i2s-tdm: Fix tdm channels init for ALWAYS-ON Init tdm slots on ALWAYS-ON situation to achieve the real always-on clk, no need to do one call on sound card. Signed-off-by: Sugar Zhang Change-Id: I75840f9072c66a8a42fcbd65781ee0f0d1612c36 --- sound/soc/rockchip/rockchip_i2s_tdm.c | 194 +++++++++++++------------- 1 file changed, 98 insertions(+), 96 deletions(-) diff --git a/sound/soc/rockchip/rockchip_i2s_tdm.c b/sound/soc/rockchip/rockchip_i2s_tdm.c index 494eb2194982..5c30ab2971ff 100644 --- a/sound/soc/rockchip/rockchip_i2s_tdm.c +++ b/sound/soc/rockchip/rockchip_i2s_tdm.c @@ -149,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 */ @@ -1123,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) { @@ -1279,6 +1360,18 @@ 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. */ @@ -1699,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, @@ -2209,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,29 +2243,9 @@ static int rockchip_dai_tdm_slot(struct snd_soc_dai *dai, 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 | I2S_TXCR_CSR_MASK; + mask = I2S_TXCR_VDW_MASK; val = I2S_TXCR_VDW(slot_width); - if (!i2s_tdm->tdm_fsync_half_frame) { - switch (slots) { - case 16: - val |= I2S_CHN_8; - break; - case 12: - val |= I2S_CHN_6; - break; - case 8: - val |= I2S_CHN_4; - break; - case 4: - val |= I2S_CHN_2; - break; - default: - val |= I2S_CHN_2; - break; - } - } - regmap_update_bits(i2s_tdm->regmap, I2S_TXCR, mask, val); regmap_update_bits(i2s_tdm->regmap, I2S_RXCR, mask, val); From 3d6aa3c10fbc9244c5be49b9dfd2e18ab0a143cb Mon Sep 17 00:00:00 2001 From: Sugar Zhang Date: Wed, 27 Mar 2024 18:23:24 +0800 Subject: [PATCH 28/50] ASoC: rockchip: multi_dais: Fix fifo count for SAI Signed-off-by: Sugar Zhang Change-Id: I60fc1848494efaa2b68ac46caa7b665237bf327d --- sound/soc/rockchip/rockchip_multi_dais_pcm.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/sound/soc/rockchip/rockchip_multi_dais_pcm.c b/sound/soc/rockchip/rockchip_multi_dais_pcm.c index 0feab27b477d..b83b3a2bed95 100644 --- a/sound/soc/rockchip/rockchip_multi_dais_pcm.c +++ b/sound/soc/rockchip/rockchip_multi_dais_pcm.c @@ -915,10 +915,12 @@ static int dmaengine_mpcm_get_fifo_count(struct device *dev, } else if (strstr(dev_driver_string(component->dev), "sai")) { reg = substream->stream ? SAI_RXFIFOLR : SAI_TXFIFOLR; - val = SAI_FIFOLR_XFL3(reg) + - SAI_FIFOLR_XFL2(reg) + - SAI_FIFOLR_XFL1(reg) + - SAI_FIFOLR_XFL0(reg); + val = snd_soc_component_read(component, reg); + + val = SAI_FIFOLR_XFL3(val) + + SAI_FIFOLR_XFL2(val) + + SAI_FIFOLR_XFL1(val) + + SAI_FIFOLR_XFL0(val); } return val; From 749d4847fd6716cb96cc7cb1a7ee005118b3d933 Mon Sep 17 00:00:00 2001 From: Jianwei Fan Date: Fri, 5 Jul 2024 15:07:35 +0800 Subject: [PATCH 29/50] media: i2c: rk628: support mode add max res to 4096x2160 Signed-off-by: Jianwei Fan Change-Id: I29e5031dd180da3427717c636f66556ed95a980a --- drivers/media/i2c/rk628/rk628_csi_v4l2.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/media/i2c/rk628/rk628_csi_v4l2.c b/drivers/media/i2c/rk628/rk628_csi_v4l2.c index 6e626eda25f5..dcd060ee4106 100644 --- a/drivers/media/i2c/rk628/rk628_csi_v4l2.c +++ b/drivers/media/i2c/rk628/rk628_csi_v4l2.c @@ -274,6 +274,15 @@ static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { static const struct rk628_csi_mode supported_modes[] = { { + .width = 4096, + .height = 2160, + .max_fps = { + .numerator = 10000, + .denominator = 600000, + }, + .hts_def = 4400, + .vts_def = 2250, + }, { .width = 3840, .height = 2160, .max_fps = { From 8bc85589943cfc50109bfc34e527837ff907ea82 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Fri, 5 Jul 2024 16:21:38 +0800 Subject: [PATCH 30/50] media: rockchip: isp: fix isp39 resume Change-Id: I8a6b60e4171563065d4efaf1ed444399a9ea94b7 Signed-off-by: Cai YiWei --- drivers/media/platform/rockchip/isp/hw.c | 56 +++++++++++-------- .../platform/rockchip/isp/isp_params_v39.c | 4 +- 2 files changed, 34 insertions(+), 26 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/hw.c b/drivers/media/platform/rockchip/isp/hw.c index df9d2602c806..cdb7d4e97d69 100644 --- a/drivers/media/platform/rockchip/isp/hw.c +++ b/drivers/media/platform/rockchip/isp/hw.c @@ -417,21 +417,6 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) }, { .base = MI_WR_CTRL, .shd = MI_WR_CTRL_SHD, - }, { - .base = ISP39_W3A_AEBIG_ADDR, - .shd = ISP39_W3A_AEBIG_ADDR_SHD, - }, { - .base = ISP39_W3A_AE0_ADDR, - .shd = ISP39_W3A_AE0_ADDR_SHD, - }, { - .base = ISP39_W3A_AF_ADDR, - .shd = ISP39_W3A_AF_ADDR_SHD, - }, { - .base = ISP39_W3A_AWB_ADDR, - .shd = ISP39_W3A_AWB_ADDR_SHD, - }, { - .base = ISP39_W3A_PDAF_ADDR, - .shd = ISP39_W3A_PDAF_ADDR_SHD, } }; @@ -546,14 +531,6 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) reg = reg_buf + ISP32_BP_RESIZE_CTRL; if (*reg & 0xf) writel(*reg | CIF_RSZ_CTRL_CFG_UPD, base + ISP32_BP_RESIZE_CTRL); - if (dev->isp_ver == ISP_V39) { - reg = reg_buf + ISP39_W3A_CTRL0; - if (*reg) - writel(*reg | ISP39_W3A_FORCE_UPD, base + ISP39_W3A_CTRL0); - reg = reg_buf + ISP39_VI3A_CTRL0; - if (*reg) - writel(*reg | ISP39_W3A_FORCE_UPD, base + ISP39_VI3A_CTRL0); - } /* update mi and isp, base_reg will update to shd_reg */ writel(CIF_MI_INIT_SOFT_UPD, base + MI_WR_INIT); @@ -583,6 +560,26 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) if (dev->is_single) { rkisp_params_cfgsram(&isp->params_vdev, false, true); + if (dev->isp_ver == ISP_V39) { + reg = reg_buf + ISP3X_ISP_CTRL1; + *reg |= ISP3X_DHAZ_FST_FRAME; + writel(*reg, dev->base_addr + ISP3X_ISP_CTRL1); + reg = reg_buf + ISP3X_BAY3D_CTRL; + if (*reg & 1) + writel(*reg | BIT(31), dev->base_addr + ISP3X_BAY3D_CTRL); + /* w3a addr will update by ISP_CFG_UPD */ + reg = reg_buf + ISP39_W3A_AEBIG_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AEBIG_ADDR); + reg = reg_buf + ISP39_W3A_AE0_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AE0_ADDR); + reg = reg_buf + ISP39_W3A_AF_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AF_ADDR); + reg = reg_buf + ISP39_W3A_AWB_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_AWB_ADDR); + reg = reg_buf + ISP39_W3A_PDAF_ADDR_SHD; + writel(*reg, dev->base_addr + ISP39_W3A_PDAF_ADDR); + } + reg = reg_buf + ISP_CTRL; *reg |= CIF_ISP_CTRL_ISP_ENABLE | CIF_ISP_CTRL_ISP_CFG_UPD | @@ -590,6 +587,19 @@ void rkisp_hw_reg_restore(struct rkisp_hw_dev *dev) writel(*reg, dev->base_addr + ISP_CTRL); if (dev->unite == ISP_UNITE_TWO) writel(*reg, dev->base_next_addr + ISP_CTRL); + + if (dev->isp_ver == ISP_V39) { + reg = reg_buf + ISP39_W3A_AEBIG_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AEBIG_ADDR); + reg = reg_buf + ISP39_W3A_AE0_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AE0_ADDR); + reg = reg_buf + ISP39_W3A_AF_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AF_ADDR); + reg = reg_buf + ISP39_W3A_AWB_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_AWB_ADDR); + reg = reg_buf + ISP39_W3A_PDAF_ADDR; + writel(*reg, dev->base_addr + ISP39_W3A_PDAF_ADDR); + } } } diff --git a/drivers/media/platform/rockchip/isp/isp_params_v39.c b/drivers/media/platform/rockchip/isp/isp_params_v39.c index a812103612de..574b80164236 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v39.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v39.c @@ -2367,9 +2367,7 @@ isp_dhaz_cfg_sram(struct rkisp_isp_params_vdev *params_vdev, if (arg->hist_iir_wr) { for (i = 0; i < priv_val->dhaz_blk_num; i++) { - val = ISP39_DHAZ_IIR_WR_ID(i); - if (!i) - val |= ISP39_DHAZ_IIR_WR_CLEAR; + val = ISP39_DHAZ_IIR_WR_ID(i) | ISP39_DHAZ_IIR_WR_CLEAR; isp3_param_write_direct(params_vdev, val, ISP39_DHAZ_HIST_RW); for (j = 0; j < ISP39_DHAZ_HIST_IIR_NUM / 2; j++) { val = ISP_PACK_2SHORT(arg->hist_iir[i][2 * j], arg->hist_iir[i][2 * j + 1]); From e81248fd15505bdb73ee980f29668812deaf06e6 Mon Sep 17 00:00:00 2001 From: Cai YiWei Date: Fri, 31 May 2024 16:16:21 +0800 Subject: [PATCH 31/50] media: rockchip: isp: fix aiisp config gain write auto control by hardware Change-Id: I5ebd0eb3a3ac942f3247a2ef624d4e775b16e9ed Signed-off-by: Cai YiWei --- .../media/platform/rockchip/isp/isp_params_v39.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/media/platform/rockchip/isp/isp_params_v39.c b/drivers/media/platform/rockchip/isp/isp_params_v39.c index 574b80164236..6ae6ce0b6d0e 100644 --- a/drivers/media/platform/rockchip/isp/isp_params_v39.c +++ b/drivers/media/platform/rockchip/isp/isp_params_v39.c @@ -3381,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; @@ -3636,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; @@ -3972,8 +3973,6 @@ void __isp_isr_other_en(struct rkisp_isp_params_vdev *params_vdev, mask = ISP39_MODULE_YNR | ISP39_MODULE_CNR | ISP39_MODULE_SHARP; if ((module_ens & mask) && ((module_ens & mask) != mask)) dev_err(params_vdev->dev->dev, "ynr cnr sharp no enable together\n"); - if (module_ens & ISP39_MODULE_YUVME && !(module_ens & ISP39_MODULE_BAY3D)) - dev_err(params_vdev->dev->dev, "yuvme need bay3d enable together\n"); v4l2_dbg(4, rkisp_debug, ¶ms_vdev->dev->v4l2_dev, "%s id:%d seq:%d module_en_update:0x%llx module_ens:0x%llx\n", __func__, id, new_params->frame_id, module_en_update, module_ens); @@ -5103,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)) From f5a4e5e984c32f65fe4eb52848974b35cb479ee2 Mon Sep 17 00:00:00 2001 From: Liang Chen Date: Thu, 4 Jul 2024 20:16:48 +0800 Subject: [PATCH 32/50] arm64: dts: rockchip: rk3562: auto select opps for rk3562j Also set the minimus voltage to 0.9V for rk3562j Signed-off-by: Liang Chen Change-Id: Ia30b1c3fd42f0d4d8eac18ee9ec3f93a7c6204d9 --- arch/arm64/boot/dts/rockchip/rk3562.dtsi | 153 ++++++++++++++++++++-- arch/arm64/boot/dts/rockchip/rk3562j.dtsi | 82 ------------ 2 files changed, 145 insertions(+), 90 deletions(-) diff --git a/arch/arm64/boot/dts/rockchip/rk3562.dtsi b/arch/arm64/boot/dts/rockchip/rk3562.dtsi index 3ed54f3a7859..f77cc830a61e 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562.dtsi @@ -252,9 +252,12 @@ opp-shared; mbist-vmin = <825000 900000 975000>; - nvmem-cells = <&cpu_leakage>, <&cpu_opp_info>, <&mbist_vmin>, <&cpu_pvtpll>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm"; + nvmem-cells = <&cpu_leakage>, <&cpu_opp_info>, <&mbist_vmin>, <&cpu_pvtpll>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm", + "specification_serial_number"; + rockchip,supported-hw; rockchip,pvtm-voltage-sel = < 0 1280 0 1281 1350 1 @@ -276,22 +279,26 @@ rockchip,low-temp-min-volt = <1050000>; opp-408000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <408000000>; opp-microvolt = <825000 825000 1150000>; clock-latency-ns = <40000>; opp-suspend; }; opp-600000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <600000000>; opp-microvolt = <825000 825000 1150000>; clock-latency-ns = <40000>; }; opp-816000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <816000000>; opp-microvolt = <825000 825000 1150000>; clock-latency-ns = <40000>; }; opp-1008000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1008000000>; opp-microvolt = <850000 850000 1150000>; opp-microvolt-L0 = <850000 850000 1150000>; @@ -302,6 +309,7 @@ clock-latency-ns = <40000>; }; opp-1200000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1200000000>; opp-microvolt = <925000 925000 1150000>; opp-microvolt-L0 = <925000 925000 1150000>; @@ -312,6 +320,7 @@ clock-latency-ns = <40000>; }; opp-1416000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1416000000>; opp-microvolt = <1000000 1000000 1150000>; opp-microvolt-L0 = <1000000 1000000 1150000>; @@ -322,6 +331,7 @@ clock-latency-ns = <40000>; }; opp-1608000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1608000000>; opp-microvolt = <1037500 1037500 1150000>; opp-microvolt-L0 = <1037500 1037500 1150000>; @@ -332,6 +342,7 @@ clock-latency-ns = <40000>; }; opp-1800000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1800000000>; opp-microvolt = <1125000 1125000 1150000>; opp-microvolt-L0 = <1125000 1125000 1150000>; @@ -342,6 +353,7 @@ clock-latency-ns = <40000>; }; opp-2016000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <2016000000>; opp-microvolt = <1150000 1150000 1150000>; opp-microvolt-L0 = <1150000 1150000 1150000>; @@ -351,6 +363,39 @@ opp-microvolt-L4 = <1075000 1075000 1150000>; clock-latency-ns = <40000>; }; + + /* RK3562J cpu OPPs */ + opp-j-408000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <408000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-600000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-816000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <816000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-1008000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <1008000000>; + opp-microvolt = <900000 900000 1150000>; + clock-latency-ns = <40000>; + }; + opp-j-1200000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <1200000000>; + opp-microvolt = <900000 900000 1150000>; + opp-microvolt-L0 = <925000 925000 1150000>; + clock-latency-ns = <40000>; + }; }; arm_pmu: arm-pmu { @@ -496,13 +541,16 @@ compatible = "operating-points-v2"; mbist-vmin = <850000 900000 925000>; - nvmem-cells = <&log_leakage>, <&dmc_opp_info>, <&log_mbist_vmin>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin"; + nvmem-cells = <&log_leakage>, <&dmc_opp_info>, <&log_mbist_vmin>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", + "specification_serial_number"; rockchip,temp-hysteresis = <5000>; rockchip,low-temp = <10000>; rockchip,low-temp-min-volt = <950000>; + rockchip,supported-hw; rockchip,leakage-voltage-sel = < 1 15 0 16 20 1 @@ -510,12 +558,20 @@ >; opp-1560000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1560000000>; opp-microvolt = <900000 900000 950000>; opp-microvolt-L0 = <900000 900000 950000>; opp-microvolt-L1 = <875000 875000 950000>; opp-microvolt-L2 = <850000 850000 950000>; }; + + /* RK3562J dmc OPPs */ + opp-j-1560000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <1560000000>; + opp-microvolt = <900000 900000 900000>; + }; }; firmware { @@ -1482,9 +1538,12 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 975000>; - nvmem-cells = <&npu_leakage>, <&npu_opp_info>, <&mbist_vmin>, <&npu_pvtpll>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm"; + nvmem-cells = <&npu_leakage>, <&npu_opp_info>, <&mbist_vmin>, <&npu_pvtpll>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm", + "specification_serial_number"; + rockchip,supported-hw; rockchip,pvtm-voltage-sel = < 0 760 0 761 800 1 @@ -1506,18 +1565,22 @@ rockchip,low-temp-min-volt = <925000>; opp-300000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <300000000>; opp-microvolt = <825000 825000 1000000>; }; opp-400000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <400000000>; opp-microvolt = <825000 825000 1000000>; }; opp-500000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <500000000>; opp-microvolt = <825000 825000 1000000>; }; opp-600000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <600000000>; opp-microvolt = <875000 875000 1000000>; opp-microvolt-L0 = <875000 875000 1000000>; @@ -1527,6 +1590,7 @@ opp-microvolt-L4 = <825000 825000 1000000>; }; opp-700000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <700000000>; opp-microvolt = <925000 925000 1000000>; opp-microvolt-L0 = <925000 925000 1000000>; @@ -1536,6 +1600,7 @@ opp-microvolt-L4 = <825000 825000 1000000>; }; opp-800000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <800000000>; opp-microvolt = <975000 975000 1000000>; opp-microvolt-L0 = <975000 975000 1000000>; @@ -1545,6 +1610,7 @@ opp-microvolt-L4 = <875000 875000 1000000>; }; opp-900000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; @@ -1554,6 +1620,7 @@ opp-microvolt-L4 = <925000 925000 1000000>; }; opp-1000000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <1000000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; @@ -1562,6 +1629,35 @@ opp-microvolt-L3 = <975000 975000 1000000>; opp-microvolt-L4 = <950000 950000 1000000>; }; + + /* RK3562J npu OPPs */ + opp-j-300000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-400000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-500000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-600000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-700000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <925000 925000 1000000>; + opp-microvolt-L0 = <925000 925000 1000000>; + status = "disabled"; + }; }; rknpu_mmu: iommu@ff30a000 { @@ -1603,9 +1699,12 @@ compatible = "operating-points-v2"; mbist-vmin = <825000 900000 975000>; - nvmem-cells = <&gpu_leakage>, <&gpu_opp_info>, <&mbist_vmin>, <&gpu_pvtpll>; - nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm"; + nvmem-cells = <&gpu_leakage>, <&gpu_opp_info>, <&mbist_vmin>, <&gpu_pvtpll>, + <&specification_serial_number>; + nvmem-cell-names = "leakage", "opp-info", "mbist-vmin", "pvtm", + "specification_serial_number"; + rockchip,supported-hw; rockchip,pvtm-voltage-sel = < 0 780 0 781 820 1 @@ -1627,22 +1726,27 @@ rockchip,low-temp-min-volt = <925000>; opp-300000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <300000000>; opp-microvolt = <825000 825000 1000000>; }; opp-400000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <400000000>; opp-microvolt = <825000 825000 1000000>; }; opp-500000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <500000000>; opp-microvolt = <825000 825000 1000000>; }; opp-600000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <600000000>; opp-microvolt = <825000 825000 1000000>; }; opp-700000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <700000000>; opp-microvolt = <900000 900000 1000000>; opp-microvolt-L0 = <900000 900000 1000000>; @@ -1652,6 +1756,7 @@ opp-microvolt-L4 = <825000 825000 1000000>; }; opp-800000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <800000000>; opp-microvolt = <950000 950000 1000000>; opp-microvolt-L0 = <950000 950000 1000000>; @@ -1661,6 +1766,7 @@ opp-microvolt-L4 = <850000 850000 1000000>; }; opp-900000000 { + opp-supported-hw = <0xf9 0xffff>; opp-hz = /bits/ 64 <900000000>; opp-microvolt = <1000000 1000000 1000000>; opp-microvolt-L0 = <1000000 1000000 1000000>; @@ -1669,6 +1775,33 @@ opp-microvolt-L3 = <925000 925000 1000000>; opp-microvolt-L4 = <900000 900000 1000000>; }; + + /* RK3562J gpu OPPs */ + opp-j-300000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <300000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-400000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <400000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-500000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <500000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-600000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <600000000>; + opp-microvolt = <900000 900000 1000000>; + }; + opp-j-700000000 { + opp-supported-hw = <0x04 0xffff>; + opp-hz = /bits/ 64 <700000000>; + opp-microvolt = <900000 900000 1000000>; + }; }; rkvdec: rkvdec@ff340100 { @@ -2632,6 +2765,10 @@ cpu_code: cpu-code@2 { reg = <0x02 0x2>; }; + specification_serial_number: specification-serial-number@7 { + reg = <0x07 0x1>; + bits = <0 5>; + }; otp_cpu_version: cpu-version@8 { reg = <0x08 0x1>; bits = <3 3>; diff --git a/arch/arm64/boot/dts/rockchip/rk3562j.dtsi b/arch/arm64/boot/dts/rockchip/rk3562j.dtsi index b2ec94fccda0..5b660f7f4a5d 100644 --- a/arch/arm64/boot/dts/rockchip/rk3562j.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3562j.dtsi @@ -28,85 +28,3 @@ status = "disabled"; }; }; - -&cpu0_opp_table { - /delete-node/ mbist-vmin; - /* - * Max CPU frequency is 1.8GHz for the overdrive mode, - * but it will reduce chip lifetime. - */ - /delete-node/ opp-1416000000; - /delete-node/ opp-1608000000; - /delete-node/ opp-1800000000; - /delete-node/ opp-2016000000; - opp-408000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-600000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-816000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-1008000000 { - opp-microvolt = <850000 850000 1150000>; - }; - opp-1200000000 { - opp-microvolt-L4 = <850000 850000 1150000>; - }; -}; - -&gpu_opp_table { - /delete-node/ mbist-vmin; - /* - * Max GPU frequency is 900MHz for the overdrive mode, - * but it will reduce chip lifetime. - */ - /delete-node/ opp-800000000; - /delete-node/ opp-900000000; - opp-300000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-400000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-500000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-600000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-700000000 { - opp-microvolt-L3 = <850000 850000 1000000>; - opp-microvolt-L4 = <850000 850000 1000000>; - }; -}; - -&npu_opp_table { - /delete-node/ mbist-vmin; - /* - * Max NPU frequency is 900MHz for the overdrive mode, - * but it will reduce chip lifetime. - */ - /delete-node/ opp-800000000; - /delete-node/ opp-900000000; - /delete-node/ opp-1000000000; - opp-300000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-400000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-500000000 { - opp-microvolt = <850000 850000 1000000>; - }; - opp-600000000 { - opp-microvolt-L2 = <850000 850000 1000000>; - opp-microvolt-L3 = <850000 850000 1000000>; - opp-microvolt-L4 = <850000 850000 1000000>; - }; - opp-700000000 { - opp-microvolt-L4 = <850000 850000 1000000>; - status = "disabled"; - }; -}; From 6f97ed5a56ff58fea2a98447cf3076fc34d73dd5 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Mon, 8 Jul 2024 20:12:24 +0800 Subject: [PATCH 33/50] drm/rockchip: Only enable ROCKCHIP_DRM_DEBUG when not use GKI Fixes: 59d943019ccb ("drm/rockchip: Enable ROCKCHIP_DRM_DEBUG feature by default") Change-Id: I70a845a1796ba420220bc2eca7c7d66cd698f314 Signed-off-by: Chaoyi Chen --- drivers/gpu/drm/rockchip/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig index 7db8abfd4174..34932688d467 100644 --- a/drivers/gpu/drm/rockchip/Kconfig +++ b/drivers/gpu/drm/rockchip/Kconfig @@ -24,7 +24,7 @@ if DRM_ROCKCHIP config ROCKCHIP_DRM_DEBUG bool "Rockchip DRM debug" default y if !ROCKCHIP_MINI_KERNEL - depends on DEBUG_FS + depends on DEBUG_FS && NO_GKI help This option add a debug node to dump buf from userspace dump buffer store at: /data From 88f19f9178b50d18671a0eb0165e560648bfcb72 Mon Sep 17 00:00:00 2001 From: Mingwei Yan Date: Mon, 8 Jul 2024 16:56:36 +0800 Subject: [PATCH 34/50] media: rockchip: vpss: fix offline 8k params calc error Signed-off-by: Mingwei Yan Change-Id: I1b67b838940a8e2eba1080a8ed96d65ccf9d0105 --- drivers/media/platform/rockchip/vpss/vpss_offline.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/media/platform/rockchip/vpss/vpss_offline.c b/drivers/media/platform/rockchip/vpss/vpss_offline.c index f19e8e20e50b..09f3e448e0af 100644 --- a/drivers/media/platform/rockchip/vpss/vpss_offline.c +++ b/drivers/media/platform/rockchip/vpss/vpss_offline.c @@ -1573,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 @@ -1977,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"); From f42fc973289010ca843bc6403be6713635157651 Mon Sep 17 00:00:00 2001 From: Mingwei Yan Date: Mon, 8 Jul 2024 17:12:49 +0800 Subject: [PATCH 35/50] media: rockchip: vpss: fix online mul_sensor affect offline Signed-off-by: Mingwei Yan Change-Id: I65e0608fe410baee2d8008b3823bd8322edd7c4d --- drivers/media/platform/rockchip/vpss/common.c | 2 ++ drivers/media/platform/rockchip/vpss/hw.c | 3 ++- drivers/media/platform/rockchip/vpss/regs.h | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/rockchip/vpss/common.c b/drivers/media/platform/rockchip/vpss/common.c index b73b71ee5d1d..49fad005b8fd 100644 --- a/drivers/media/platform/rockchip/vpss/common.c +++ b/drivers/media/platform/rockchip/vpss/common.c @@ -111,6 +111,8 @@ void rkvpss_update_regs(struct rkvpss_device *dev, u32 start, u32 end) mask |= (RKVPSS_ISP2VPSS_CHN0_SEL(3) << j * 2); } *val |= (readl(base + i) & mask); + } else { + *val |= readl(base + i); } } writel(*val, base + i); diff --git a/drivers/media/platform/rockchip/vpss/hw.c b/drivers/media/platform/rockchip/vpss/hw.c index 6be54c704596..bd974b17cfeb 100644 --- a/drivers/media/platform/rockchip/vpss/hw.c +++ b/drivers/media/platform/rockchip/vpss/hw.c @@ -519,7 +519,8 @@ void rkvpss_soft_reset(struct rkvpss_hw_dev *hw) rockchip_iommu_enable(hw->dev); } - rkvpss_hw_write(hw, RKVPSS_VPSS_CTRL, RKVPSS_ACK_FRM_PRO_DIS); + rkvpss_hw_set_bits(hw, RKVPSS_VPSS_CTRL, RKVPSS_ACK_FRM_PRO_DIS, + RKVPSS_ACK_FRM_PRO_DIS); rkvpss_hw_write(hw, RKVPSS_VPSS_IRQ_CFG, 0x3fff); rkvpss_hw_write(hw, RKVPSS_MI_IMSC, 0xd0000000); rkvpss_hw_set_bits(hw, RKVPSS_VPSS_ONLINE, RKVPSS_ONLINE_MODE_MASK, diff --git a/drivers/media/platform/rockchip/vpss/regs.h b/drivers/media/platform/rockchip/vpss/regs.h index 5d9442cbb720..d73d6db5addd 100644 --- a/drivers/media/platform/rockchip/vpss/regs.h +++ b/drivers/media/platform/rockchip/vpss/regs.h @@ -1179,8 +1179,10 @@ #define IS_SYNC_REG(x) ({ \ typeof(x) __x = (x); \ (__x == RKVPSS_VPSS_CTRL || __x == RKVPSS_VPSS_ONLINE || \ - __x == RKVPSS_VPSS_UPDATE || __x == RKVPSS_MI_WR_INIT || \ - __x == RKVPSS_MI_WR_WRAP_CTRL || __x == RKVPSS_MI_WR_VFLIP_CTRL); \ + __x == RKVPSS_VPSS_UPDATE || __x == RKVPSS_VPSS_CLK_GATE || \ + __x == RKVPSS_VPSS_IMSC || __x == RKVPSS_MI_WR_CTRL || \ + __x == RKVPSS_MI_WR_INIT || __x == RKVPSS_MI_WR_WRAP_CTRL || \ + __x == RKVPSS_MI_WR_VFLIP_CTRL); \ }) #endif From 373239c6c8df0e82f1fb73760515089f452dd61a Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Fri, 29 Mar 2024 11:16:00 +0800 Subject: [PATCH 36/50] soc: rockchip: Add CPU_RV1103B config Signed-off-by: Tao Huang Change-Id: Ifb03f352c0624a13548394dcecf59d09f3579ce8 --- drivers/soc/rockchip/Kconfig.cpu | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/soc/rockchip/Kconfig.cpu b/drivers/soc/rockchip/Kconfig.cpu index c1ecd2daf338..b3c014ec5618 100644 --- a/drivers/soc/rockchip/Kconfig.cpu +++ b/drivers/soc/rockchip/Kconfig.cpu @@ -27,6 +27,10 @@ config CPU_RK322X bool "RK3228/9" depends on ARM +config CPU_RV1103B + bool "RV1103B" + depends on ARM + config CPU_RV1106 bool "RV1103/6" depends on ARM From 054daf6edc4ee16274d930d34337a8a0a2b7e7c0 Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Tue, 4 Jun 2024 09:43:31 +0800 Subject: [PATCH 37/50] soc: rockchip: ROCKCHIP_MINI_KERNEL default y if CPU_RV1103B Signed-off-by: Tao Huang Change-Id: I245ee2575fb9f8c6b4c02e79a97900aabcb9a750 --- drivers/soc/rockchip/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig index 4067e7273992..11b9b204291f 100644 --- a/drivers/soc/rockchip/Kconfig +++ b/drivers/soc/rockchip/Kconfig @@ -255,7 +255,7 @@ config ROCKCHIP_DEBUG config ROCKCHIP_MINI_KERNEL bool "Rockchip Mini Kernel support" select NO_GKI - default y if CPU_RV1106 || CPU_RV1126 + default y if CPU_RV1103B || CPU_RV1106 || CPU_RV1126 help Say y here to enable Rockchip mini kernel support. This option make the kernel size smaller. From 32b44fe5500ae6956aa1d2abcfba8e9e03ff1fb7 Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Tue, 4 Jun 2024 09:53:59 +0800 Subject: [PATCH 38/50] video: rockchip: mpp_osal: ROCKCHIP_MPP_OSAL depends on CPU_RV1103B Signed-off-by: Tao Huang Change-Id: Ieddb8123fbe06f1ebbc65e23f0a1140a55ce61da --- drivers/video/rockchip/mpp_osal/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/video/rockchip/mpp_osal/Kconfig b/drivers/video/rockchip/mpp_osal/Kconfig index 75cd7028615f..b8ad041c2e6b 100644 --- a/drivers/video/rockchip/mpp_osal/Kconfig +++ b/drivers/video/rockchip/mpp_osal/Kconfig @@ -2,7 +2,7 @@ config ROCKCHIP_MPP_OSAL bool "mpp osal" - depends on CPU_RV1106 + depends on CPU_RV1103B || CPU_RV1106 default y help rockchip mpp osal adapt for kmpp From 74c68a1e8ac2c5cafcbb935043c814e8b919f7a6 Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Tue, 4 Jun 2024 09:44:55 +0800 Subject: [PATCH 39/50] clk: rockchip: Disable CLK_INV/CLK_PVTM on CPU_RV1103B Signed-off-by: Tao Huang Change-Id: I5bc5e2e9b12cadb07bc8a31a00a21deb36b88916 --- drivers/clk/rockchip/Kconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/clk/rockchip/Kconfig b/drivers/clk/rockchip/Kconfig index 150a479bbd86..e486b27cc0b0 100644 --- a/drivers/clk/rockchip/Kconfig +++ b/drivers/clk/rockchip/Kconfig @@ -162,7 +162,7 @@ config ROCKCHIP_CLK_BOOST config ROCKCHIP_CLK_INV bool "Rockchip Clk Inverter" - depends on !CPU_RV1126 && !CPU_RV1106 + depends on !CPU_RV1126 && !CPU_RV1106 && !CPU_RV1103B default y help Say y here to enable clk Inverter. @@ -175,7 +175,7 @@ config ROCKCHIP_CLK_OUT config ROCKCHIP_CLK_PVTM bool "Rockchip Clk Pvtm" - depends on !CPU_RV1126 && !CPU_RV1106 + depends on !CPU_RV1126 && !CPU_RV1106 && !CPU_RV1103B default y help Say y here to enable clk pvtm. From 49807b47177bacf9ccace6d5d374a61919a81e1e Mon Sep 17 00:00:00 2001 From: Tao Huang Date: Tue, 25 Jun 2024 20:42:00 +0800 Subject: [PATCH 40/50] soc: rockchip: fiq_debugger: Fix console sleep too long usleep_range() will take too long on !CONFIG_HIGH_RES_TIMERS, replace with schedule() and nice. Change-Id: I2dc6e4620fe4c56f491f1700e7d6c1f54d1c36e9 Signed-off-by: Tao Huang --- .../rockchip/fiq_debugger/rk_fiq_debugger.c | 26 ++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c b/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c index e5421e4515d2..8902c5153ce0 100644 --- a/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c +++ b/drivers/soc/rockchip/fiq_debugger/rk_fiq_debugger.c @@ -243,6 +243,28 @@ static int write_room(struct platform_device *pdev) return (TTY_FIFO_SIZE - kfifo_len(&tty_fifo)); } +#define console_poll(cond, count, us) \ +do { \ + if (!IS_ENABLED(CONFIG_HIGH_RES_TIMERS) && CONFIG_HZ < 1000 && us < 1000) { \ + if (!(cond)) { \ + ktime_t timeout = ktime_add_us(ktime_get(), us * count); \ + int oldnice = task_nice(current); \ + if (!(cond)) { \ + set_user_nice(current, MAX_NICE); \ + while (!(cond)) { \ + if (ktime_compare(ktime_get(), timeout) > 0) \ + break; \ + schedule(); \ + } \ + set_user_nice(current, oldnice); \ + } \ + } \ + } else { \ + while (!(cond) && count--) \ + usleep_range(us, us + us / 20); \ + } \ +} while (0) + static void console_putc(struct platform_device *pdev, unsigned int c) { struct rk_fiq_debugger *t; @@ -254,9 +276,7 @@ static void console_putc(struct platform_device *pdev, unsigned int c) if (t->baudrate == 115200) us = 5160; /* the time to send 60 byte for baudrate 115200 */ - while (!(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL) && - count--) - usleep_range(us, us + us / 20); + console_poll(rk_fiq_read(t, UART_USR) & UART_USR_TX_FIFO_NOT_FULL, count, us); rk_fiq_write(t, c, UART_TX); } From 6e5641b33318b4e402836188970d6640c50e6596 Mon Sep 17 00:00:00 2001 From: Yu Qiaowei Date: Thu, 28 Mar 2024 17:35:02 +0800 Subject: [PATCH 41/50] video: rockchip: rga3: support RV1103B Signed-off-by: Yu Qiaowei Change-Id: I7a4fda6fd994418c6d2e4dea825f03017abdcf5a --- .../rockchip/rga3/include/rga_hw_config.h | 1 + drivers/video/rockchip/rga3/rga_drv.c | 2 + drivers/video/rockchip/rga3/rga_hw_config.c | 48 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/drivers/video/rockchip/rga3/include/rga_hw_config.h b/drivers/video/rockchip/rga3/include/rga_hw_config.h index 6679c599af42..61390902175a 100644 --- a/drivers/video/rockchip/rga3/include/rga_hw_config.h +++ b/drivers/video/rockchip/rga3/include/rga_hw_config.h @@ -78,6 +78,7 @@ extern const struct rga_hw_data rga2e_data; extern const struct rga_hw_data rga2e_1106_data; extern const struct rga_hw_data rga2e_iommu_data; extern const struct rga_hw_data rga2p_iommu_data; +extern const struct rga_hw_data rga2p_lite_1103b_data; #define rga_hw_has_issue(scheduler, issue) test_bit(issue, &((scheduler)->hw_issues_mask)) #define rga_hw_set_issue_mask(scheduler, issue) set_bit(issue, &((scheduler)->hw_issues_mask)) diff --git a/drivers/video/rockchip/rga3/rga_drv.c b/drivers/video/rockchip/rga3/rga_drv.c index e4e70def194e..ac74808581e7 100644 --- a/drivers/video/rockchip/rga3/rga_drv.c +++ b/drivers/video/rockchip/rga3/rga_drv.c @@ -1374,6 +1374,8 @@ static int rga_drv_probe(struct platform_device *pdev) } else if (!strcmp(scheduler->version.str, "3.e.19357")) { scheduler->data = &rga2p_iommu_data; rga_hw_set_issue_mask(scheduler, RGA_HW_ISSUE_DIS_AUTO_RST); + } else if (!strcmp(scheduler->version.str, "3.f.23690")) { + scheduler->data = &rga2p_lite_1103b_data; } else { scheduler->data = &rga2e_data; } diff --git a/drivers/video/rockchip/rga3/rga_hw_config.c b/drivers/video/rockchip/rga3/rga_hw_config.c index 18c4eacd03ac..f1d1bc8da799 100644 --- a/drivers/video/rockchip/rga3/rga_hw_config.c +++ b/drivers/video/rockchip/rga3/rga_hw_config.c @@ -442,6 +442,30 @@ const struct rga_win_data rga2p_win_data[] = { }, }; +const struct rga_win_data rga2p_lite_win_data[] = { + { + .name = "rga2e-src0", + .formats[RGA_RASTER_INDEX] = rga2e_input_raster_format, + .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_input_raster_format), + .supported_rotations = RGA_MODE_ROTATE_MASK, + .scale_up_mode = RGA_SCALE_UP_BIC, + .scale_down_mode = RGA_SCALE_DOWN_AVG, + .rd_mode = RGA_RASTER_MODE, + + }, + + { + .name = "rga2-dst", + .formats[RGA_RASTER_INDEX] = rga2e_output_raster_format, + .formats_count[RGA_RASTER_INDEX] = ARRAY_SIZE(rga2e_output_raster_format), + .supported_rotations = 0, + .scale_up_mode = RGA_SCALE_UP_NONE, + .scale_down_mode = RGA_SCALE_DOWN_NONE, + .rd_mode = RGA_RASTER_MODE, + + }, +}; + const struct rga_hw_data rga3_data = { .version = 0, .input_range = {{68, 2}, {8176, 8176}}, @@ -564,3 +588,27 @@ const struct rga_hw_data rga2p_iommu_data = { RGA_MODE_CSC_BT709, .mmu = RGA_IOMMU, }; + +const struct rga_hw_data rga2p_lite_1103b_data = { + .version = 0, + .input_range = {{2, 2}, {2880, 1620}}, + .output_range = {{2, 2}, {2880, 1620}}, + + .win = rga2p_lite_win_data, + .win_size = ARRAY_SIZE(rga2p_lite_win_data), + /* 1 << factor mean real factor */ + .max_upscale_factor = 4, + .max_downscale_factor = 4, + + .byte_stride_align = 4, + .max_byte_stride = WORD_TO_BYTE(8192), + + .feature = RGA_COLOR_FILL | RGA_DITHER | RGA_YIN_YOUT | + RGA_YUV_HDS | RGA_YUV_VDS | + RGA_PRE_INTR | RGA_FULL_CSC, + .csc_r2y_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | + RGA_MODE_CSC_BT709, + .csc_y2r_mode = RGA_MODE_CSC_BT601L | RGA_MODE_CSC_BT601F | + RGA_MODE_CSC_BT709, + .mmu = RGA_NONE_MMU, +}; From daf6d9c8c5b103627799ed02d59918618dbdd9a2 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Tue, 9 Jul 2024 11:35:56 +0800 Subject: [PATCH 42/50] drm/rockchip: debugfs: Remove unused enable option for vop buffer dump The vop buffer dump feature no longer needs to be explicitly enabled via debugfs, removing the code associated with it. Change-Id: I73581514fc69616c97047adb4967d488261cee86 Signed-off-by: Chaoyi Chen --- drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c | 3 --- drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h | 2 -- 2 files changed, 5 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c index 47314b616fda..8b7551864c80 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c @@ -134,7 +134,6 @@ int rockchip_drm_crtc_dump_plane_buffer(struct drm_crtc *crtc) 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, " 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"); @@ -186,8 +185,6 @@ rockchip_drm_dump_buffer_write(struct file *file, const char __user *ubuf, rockchip_drm_crtc_dump_plane_buffer(crtc); drm_modeset_unlock_all(crtc->dev); } - } else if (strncmp(buf, "enable", 6) == 0) { - rockchip_crtc->vop_dump_status = DUMP_ENABLE; } else { return -EINVAL; } diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h index e4aace25fe31..fbd3b66d11c4 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.h @@ -11,12 +11,10 @@ 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 }; From 6913ee05a383c019693f087d91734e75d4cbbb42 Mon Sep 17 00:00:00 2001 From: Chaoyi Chen Date: Thu, 4 Jul 2024 15:02:17 +0800 Subject: [PATCH 43/50] drm/rockchip: debugfs: Add vop dump buffer version output prompt Change-Id: Ia5afee51ce86224d14eb15c6662e500ae91d1075 Signed-off-by: Chaoyi Chen --- drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c index 8b7551864c80..f95ffb6c69a1 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_debugfs.c @@ -134,6 +134,7 @@ int rockchip_drm_crtc_dump_plane_buffer(struct drm_crtc *crtc) static int rockchip_drm_dump_buffer_show(struct seq_file *m, void *data) { + 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"); From 010bf504791344f832118890f129a4ebdab5a49b Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Wed, 19 Jun 2024 19:16:14 +0800 Subject: [PATCH 44/50] phy: rockchip: usbdp: don't access vo grf in phy power on The power domain for vo grf may not enable when phy power on. To access vo grf in other callback function to ensure the power domain enable before access vo grf. Change-Id: Iba5f8e6b62670bc01084616506ce146fb22d8e3c Signed-off-by: Zhang Yubing --- drivers/phy/rockchip/phy-rockchip-usbdp.c | 26 +++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index 47f15df5d47b..d84339bfec64 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -581,9 +581,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; } @@ -1118,8 +1128,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 +1248,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 +1316,18 @@ 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); + + return udphy_dpaux_select(udphy); +} + 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, }; From b41a87b16cf58d116145dcd2f0aa1b6aec011361 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Wed, 19 Jun 2024 19:32:37 +0800 Subject: [PATCH 45/50] drm/rockchip: dw-dp: support dynamic control power domain Change-Id: I8692e967d2873a10385bec5d6998ad73cf8f4fa7 Signed-off-by: Zhang Yubing --- drivers/gpu/drm/rockchip/dw-dp.c | 82 +++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index a53d405e74e7..2917dad6f386 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -449,6 +449,7 @@ struct dw_dp { struct work_struct hpd_work; struct gpio_desc *hpd_gpio; bool force_hpd; + bool dynamic_pd_ctrl; struct dw_dp_hotplug hotplug; struct mutex irq_lock; @@ -1126,7 +1127,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; @@ -1145,6 +1146,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,7 +2855,7 @@ 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) { regmap_update_bits(dp->regmap, DPTX_CCTL, FORCE_HPD, @@ -3077,19 +3092,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 +3122,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 +3138,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 +3716,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 +3876,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 +4334,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 +4353,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 +5118,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 +5126,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 +5188,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 +5198,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 +5210,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 +5496,11 @@ 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); enable_irq(dp->irq); if (dp->hpd_gpio) @@ -5472,7 +5523,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); @@ -5718,6 +5771,9 @@ static int dw_dp_probe(struct platform_device *pdev) if (ret) return ret; + if (dp->hpd_gpio || dp->force_hpd) + dp->dynamic_pd_ctrl = true; + dp->irq = platform_get_irq(pdev, 0); if (dp->irq < 0) return dp->irq; From 09d452118bfb51fa977dd57826fc687649b1fda5 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Fri, 21 Jun 2024 14:55:28 +0800 Subject: [PATCH 46/50] phy: rockchip: usbdp: support not trigger dp hpd If a mux device in DPTX driver, usbdp phy should not trigger dp hpd. DPTX driver will call phy_set_mode to transfer this info. Change-Id: I1d13858a9115a688bd9560eb41a2f86c76e73316 Signed-off-by: Zhang Yubing --- drivers/phy/rockchip/phy-rockchip-usbdp.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/phy/rockchip/phy-rockchip-usbdp.c b/drivers/phy/rockchip/phy-rockchip-usbdp.c index d84339bfec64..a1072d584c33 100644 --- a/drivers/phy/rockchip/phy-rockchip-usbdp.c +++ b/drivers/phy/rockchip/phy-rockchip-usbdp.c @@ -181,6 +181,7 @@ struct rockchip_udphy { u32 dp_aux_din_sel; bool dp_sink_hpd_sel; bool dp_sink_hpd_cfg; + bool dp_hpd_disabled; u8 bw; int id; int dp_lanes; @@ -625,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; } @@ -1319,8 +1321,20 @@ static int rockchip_dp_phy_configure(struct phy *phy, 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; - return udphy_dpaux_select(udphy); + 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 = { From 9553deccf2a38e54fc9ec652c591773689ffd489 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Fri, 21 Jun 2024 14:51:52 +0800 Subject: [PATCH 47/50] drm/rockchip: dw-dp: support get hpd status from Type-C interface Change-Id: I92f30af67c9c5c1e8720d2cdd8a8e1e5c85618a7 Signed-off-by: Zhang Yubing --- drivers/gpu/drm/rockchip/dw-dp.c | 83 +++++++++++++++++++++++++++++++- 1 file changed, 81 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/rockchip/dw-dp.c b/drivers/gpu/drm/rockchip/dw-dp.c index 2917dad6f386..79e2a3e8a697 100644 --- a/drivers/gpu/drm/rockchip/dw-dp.c +++ b/drivers/gpu/drm/rockchip/dw-dp.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include @@ -449,6 +451,7 @@ 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; @@ -501,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 { @@ -1135,6 +1139,9 @@ static bool dw_dp_detect_no_power(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); @@ -2857,7 +2864,7 @@ static void dw_dp_hpd_init(struct dw_dp *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; @@ -5501,6 +5508,8 @@ static int dw_dp_bind(struct device *dev, struct device *master, void *data) pm_runtime_enable(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) @@ -5650,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; @@ -5771,7 +5839,18 @@ static int dw_dp_probe(struct platform_device *pdev) if (ret) return ret; - if (dp->hpd_gpio || dp->force_hpd) + 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); From 68caa7651d11297640c09e356605a0050ad7249d Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Fri, 21 Jun 2024 15:04:47 +0800 Subject: [PATCH 48/50] arm64: dts: rockchip: rk3588-evb1: add mux node for dp Change-Id: I23fd7869e6f1c8f23655fbb315a38c685962c909 Signed-off-by: Zhang Yubing --- arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi index 438721090ebc..ea7c8ea9d2ea 100644 --- a/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3588-evb1-lp4.dtsi @@ -256,6 +256,7 @@ &dp0 { status = "okay"; + svid = <0xff01>; }; &dp0_in_vp2 { @@ -436,6 +437,7 @@ ; source-pdos = ; + mode-switch = <&dp0>; altmodes { #address-cells = <1>; From 302af18f8007a8f9e43a0fa70604b3a11aa8ed51 Mon Sep 17 00:00:00 2001 From: Zhang Yubing Date: Wed, 3 Jul 2024 20:05:04 +0800 Subject: [PATCH 49/50] arm64: dts: rockchip: rk3576-evb1: add mux node for dp Change-Id: I5896df25268af73003d4baf1ac400a06ca769bfa Signed-off-by: Zhang Yubing --- arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi index bf63d06c109e..ef9e9679f63a 100644 --- a/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi +++ b/arch/arm64/boot/dts/rockchip/rk3576-evb1.dtsi @@ -205,6 +205,7 @@ &dp { status = "okay"; + svid = <0xff01>; }; &dp0 { @@ -330,6 +331,7 @@ ; source-pdos = ; + mode-switch = <&dp>; altmodes { #address-cells = <1>; From 79977533751854377382278c86afd0a1c0281bad Mon Sep 17 00:00:00 2001 From: Zhibin Huang Date: Tue, 9 Jul 2024 11:09:17 +0800 Subject: [PATCH 50/50] drm/rockchip: panel-notifier: avoid duplicate register notifier If user mistakenly registers the notifier repeatedly, a panic occurs at the following location: pc : __list_add_valid+0x68/0xb8 lr : __list_add_valid+0x68/0xb8 sp : ffffffc00abe3a00 x29: ffffffc00abe3a00 x28: ffffff8003048020 x27: ffffff8003048028 x26: ffffff800324d3d0 x25: 0000000000000002 x24: 000000000000000a x23: ffffffc00a663040 x22: ffffff80032da350 x21: ffffff8004930940 x20: ffffff80032da350 x19: ffffff80047be010 x18: ffffffc00aab1088 x17: 3035336164323330 x16: ffffffffffffffff x15: 0000000000000004 x14: ffffffc00a00d6e0 x13: 000000000000ffff x12: 0000000000000003 x11: 00000000fffeffff x10: c0000000fffeffff x9 : 55386e6b9a94b100 x8 : 55386e6b9a94b100 x7 : 205b5d3836393437 x6 : 382e33202020205b x5 : ffffffc00a9e3617 x4 : ffffffc00abe3757 x3 : 0000000000000000 x2 : 0000000000000000 x1 : ffffffc00abe37c0 x0 : 0000000000000058 Call trace: __list_add_valid+0x68/0xb8 devm_rockchip_panel_notifier_register+0x9c/0xfc panel_simple_probe+0x458/0x514 panel_simple_platform_probe+0x88/0xc8 platform_probe+0xa8/0xd0 really_probe+0x174/0x350 __driver_probe_device+0xa0/0x128 driver_probe_device+0x44/0x210 __device_attach_driver+0x12c/0x154 bus_for_each_drv+0x84/0xd0 __device_attach+0xf0/0x170 device_initial_probe+0x14/0x20 bus_probe_device+0x34/0x98 deferred_probe_work_func+0x7c/0xd8 process_one_work+0x1a8/0x3b8 worker_thread+0x300/0x430 kthread+0xec/0x1b8 ret_from_fork+0x10/0x20 Type: Fix Redmine ID: #494152 Associated modifications: N/A Test: N/A Signed-off-by: Zhibin Huang Change-Id: If2bb65ed80d79d9d930d8bf6e82c45a43fd123b1 --- .../drm/rockchip/rockchip_panel_notifier.c | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c b/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c index 455a9be63124..a6e87dab69b9 100644 --- a/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c +++ b/drivers/gpu/drm/rockchip/rockchip_panel_notifier.c @@ -133,18 +133,28 @@ EXPORT_SYMBOL(devm_rockchip_panel_notifier_unregister_client); static int rockchip_panel_notifier_register(struct drm_panel *panel, struct rockchip_panel_notifier *pn) { + struct rockchip_panel_notifier *panel_notifier, *next; + int ret = 0; + if (!panel || !pn) return -EINVAL; - pn->panel = panel; - - BLOCKING_INIT_NOTIFIER_HEAD(&pn->nh); - mutex_lock(¬ifier_list_lock); - list_add_tail(&pn->list, ¬ifier_list); + list_for_each_entry_safe(panel_notifier, next, ¬ifier_list, list) { + if (panel_notifier->panel != panel) + continue; + + ret = -EEXIST; + } + if (!ret) { + pn->panel = panel; + BLOCKING_INIT_NOTIFIER_HEAD(&pn->nh); + + list_add_tail(&pn->list, ¬ifier_list); + } mutex_unlock(¬ifier_list_lock); - return 0; + return ret; } static void rockchip_panel_notifier_unregister(struct rockchip_panel_notifier *pn)