diff --git a/recipes-kernel/linux/linux-stm32mp.inc b/recipes-kernel/linux/linux-stm32mp.inc index 6cd26d3..c3ed5db 100644 --- a/recipes-kernel/linux/linux-stm32mp.inc +++ b/recipes-kernel/linux/linux-stm32mp.inc @@ -39,7 +39,7 @@ python () { # #If the defconfig is contained on the kernel tree (arch/${ARCH}/configs) #you must use the following line -do_configure_prepend() { +do_configure_append() { unset CFLAGS CPPFLAGS CXXFLAGS LDFLAGS MACHINE if [ ! -z ${KERNEL_DEFCONFIG} ]; then @@ -50,7 +50,7 @@ do_configure_prepend() { then bbnote "Kernel customized: configuration of linux STM by using external DEFCONFIG" install -m 0644 ${WORKDIR}/${KERNEL_EXTERNAL_DEFCONFIG} ${B}/.config - oe_runmake -C ${S} O=${B} CC="${KERNEL_CC}" LD="${KERNEL_LD}" oldconfig + yes '' | oe_runmake -C ${S} O=${B} CC="${KERNEL_CC}" LD="${KERNEL_LD}" oldconfig else bbwarn "You must specify KERNEL_DEFCONFIG or KERNEL_EXTERNAL_DEFCONFIG" die "NO DEFCONFIG SPECIFIED" diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0004-ARM-5.10.10-stm32mp1-r1-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0004-ARM-5.10.10-stm32mp1-r1-CRYPTO.patch deleted file mode 100644 index 78a09cd..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0004-ARM-5.10.10-stm32mp1-r1-CRYPTO.patch +++ /dev/null @@ -1,778 +0,0 @@ -From 56442e69cbaf31555a9bb4f3311a0593a0c172cc Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 08:56:48 +0100 -Subject: [PATCH 04/22] ARM 5.10.10-stm32mp1-r1 CRYPTO - ---- - drivers/crypto/stm32/stm32-cryp.c | 300 +++++++++++++++++++++--------- - drivers/crypto/stm32/stm32-hash.c | 19 +- - 2 files changed, 228 insertions(+), 91 deletions(-) - -diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c -index 2670c30332fa..503428bf15cb 100644 ---- a/drivers/crypto/stm32/stm32-cryp.c -+++ b/drivers/crypto/stm32/stm32-cryp.c -@@ -144,10 +144,10 @@ struct stm32_cryp { - size_t authsize; - size_t hw_blocksize; - -+ size_t remain_in; - size_t total_in; -- size_t total_in_save; -+ size_t remain_out; - size_t total_out; -- size_t total_out_save; - - struct scatterlist *in_sg; - struct scatterlist *out_sg; -@@ -157,9 +157,6 @@ struct stm32_cryp { - struct scatterlist out_sgl; - bool sgs_copied; - -- int in_sg_len; -- int out_sg_len; -- - struct scatter_walk in_walk; - struct scatter_walk out_walk; - -@@ -322,28 +319,46 @@ static int stm32_cryp_check_io_aligned(struct stm32_cryp *cryp) - - ret = stm32_cryp_check_aligned(cryp->out_sg, cryp->total_out, - cryp->hw_blocksize); -+ if (ret) -+ return ret; -+ -+ if (is_gcm(cryp) || is_ccm(cryp)) -+ if (!IS_ALIGNED(cryp->areq->assoclen, sizeof(u32))) -+ ret = -EINVAL; - - return ret; - } - - static void sg_copy_buf(void *buf, struct scatterlist *sg, -- unsigned int start, unsigned int nbytes, int out) -+ unsigned int start, unsigned int first_len, -+ unsigned int zero_len, -+ unsigned int second_len, -+ int out) - { - struct scatter_walk walk; -+ unsigned int nbytes = first_len + zero_len + second_len; -+ u32 empty = 0; - - if (!nbytes) - return; - - scatterwalk_start(&walk, sg); - scatterwalk_advance(&walk, start); -- scatterwalk_copychunks(buf, &walk, nbytes, out); -+ if (first_len) -+ scatterwalk_copychunks(buf, &walk, first_len, out); -+ if (zero_len) -+ memcpy(buf+first_len, &empty, zero_len); -+ if (second_len) -+ scatterwalk_copychunks(buf + first_len + zero_len, &walk, -+ second_len, out); -+ - scatterwalk_done(&walk, out, 0); - } - - static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) - { - void *buf_in, *buf_out; -- int pages, total_in, total_out; -+ int pages_in, pages_out, total_in, total_out; - - if (!stm32_cryp_check_io_aligned(cryp)) { - cryp->sgs_copied = 0; -@@ -351,29 +366,37 @@ static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) - } - - total_in = ALIGN(cryp->total_in, cryp->hw_blocksize); -- pages = total_in ? get_order(total_in) : 1; -- buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages); -+ pages_in = total_in ? get_order(total_in) : 1; -+ buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages_in); - - total_out = ALIGN(cryp->total_out, cryp->hw_blocksize); -- pages = total_out ? get_order(total_out) : 1; -- buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages); -+ pages_out = total_out ? get_order(total_out) : 1; -+ buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages_out); - - if (!buf_in || !buf_out) { - dev_err(cryp->dev, "Can't allocate pages when unaligned\n"); -+ if (buf_in) -+ free_pages((unsigned long)buf_in, pages_in); - cryp->sgs_copied = 0; - return -EFAULT; - } - -- sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0); -+ -+ if ((is_gcm(cryp) || is_ccm(cryp)) && (!IS_ALIGNED(cryp->areq->assoclen, -+ sizeof(u32)))) { -+ sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->areq->assoclen, -+ ALIGN(cryp->areq->assoclen, sizeof(u32)) -+ - cryp->areq->assoclen, -+ cryp->areq->cryptlen, 0); -+ } else -+ sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0, 0, 0); - - sg_init_one(&cryp->in_sgl, buf_in, total_in); - cryp->in_sg = &cryp->in_sgl; -- cryp->in_sg_len = 1; - - sg_init_one(&cryp->out_sgl, buf_out, total_out); - cryp->out_sg_save = cryp->out_sg; - cryp->out_sg = &cryp->out_sgl; -- cryp->out_sg_len = 1; - - cryp->sgs_copied = 1; - -@@ -654,14 +677,14 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) - buf_in = sg_virt(&cryp->in_sgl); - buf_out = sg_virt(&cryp->out_sgl); - -- sg_copy_buf(buf_out, cryp->out_sg_save, 0, -- cryp->total_out_save, 1); -+ sg_copy_buf(buf_out, cryp->out_sg_save, 0, 0, 0, -+ cryp->total_out, 1); - -- len = ALIGN(cryp->total_in_save, cryp->hw_blocksize); -+ len = ALIGN(cryp->total_in, cryp->hw_blocksize); - pages = len ? get_order(len) : 1; - free_pages((unsigned long)buf_in, pages); - -- len = ALIGN(cryp->total_out_save, cryp->hw_blocksize); -+ len = ALIGN(cryp->total_out, cryp->hw_blocksize); - pages = len ? get_order(len) : 1; - free_pages((unsigned long)buf_out, pages); - } -@@ -801,7 +824,20 @@ static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key, - static int stm32_cryp_aes_gcm_setauthsize(struct crypto_aead *tfm, - unsigned int authsize) - { -- return authsize == AES_BLOCK_SIZE ? 0 : -EINVAL; -+ switch (authsize) { -+ case 4: -+ case 8: -+ case 12: -+ case 13: -+ case 14: -+ case 15: -+ case 16: -+ break; -+ default: -+ return -EINVAL; -+ } -+ -+ return 0; - } - - static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, -@@ -825,31 +861,61 @@ static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, - - static int stm32_cryp_aes_ecb_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_ecb_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_ECB); - } - - static int stm32_cryp_aes_cbc_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CBC | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_cbc_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % AES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CBC); - } - - static int stm32_cryp_aes_ctr_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CTR | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_ctr_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_AES | FLG_CTR); - } - -@@ -863,53 +929,122 @@ static int stm32_cryp_aes_gcm_decrypt(struct aead_request *req) - return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM); - } - -+static inline int crypto_ccm_check_iv(const u8 *iv) -+{ -+ /* 2 <= L <= 8, so 1 <= L' <= 7. */ -+ if (iv[0] < 1 || iv[0] > 7) -+ return -EINVAL; -+ -+ return 0; -+} -+ - static int stm32_cryp_aes_ccm_encrypt(struct aead_request *req) - { -+ int err; -+ -+ err = crypto_ccm_check_iv(req->iv); -+ if (err) -+ return err; -+ - return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM | FLG_ENCRYPT); - } - - static int stm32_cryp_aes_ccm_decrypt(struct aead_request *req) - { -+ int err; -+ -+ err = crypto_ccm_check_iv(req->iv); -+ if (err) -+ return err; -+ - return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM); - } - - static int stm32_cryp_des_ecb_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT); - } - - static int stm32_cryp_des_ecb_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_ECB); - } - - static int stm32_cryp_des_cbc_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_CBC | FLG_ENCRYPT); - } - - static int stm32_cryp_des_cbc_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_DES | FLG_CBC); - } - - static int stm32_cryp_tdes_ecb_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB | FLG_ENCRYPT); - } - - static int stm32_cryp_tdes_ecb_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB); - } - - static int stm32_cryp_tdes_cbc_encrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC | FLG_ENCRYPT); - } - - static int stm32_cryp_tdes_cbc_decrypt(struct skcipher_request *req) - { -+ if (req->cryptlen % DES_BLOCK_SIZE) -+ return -EINVAL; -+ -+ if (req->cryptlen == 0) -+ return 0; -+ - return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC); - } - -@@ -971,36 +1106,25 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req, - cryp->areq = areq; - cryp->req = NULL; - cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq)); -- cryp->total_in = areq->assoclen + areq->cryptlen; -+ cryp->total_in = ALIGN(areq->assoclen, sizeof(u32)) -+ + areq->cryptlen; - if (is_encrypt(cryp)) - /* Append auth tag to output */ -- cryp->total_out = cryp->total_in + cryp->authsize; -+ cryp->total_out = areq->assoclen + areq->cryptlen -+ + cryp->authsize; - else - /* No auth tag in output */ -- cryp->total_out = cryp->total_in - cryp->authsize; -+ cryp->total_out = areq->assoclen + areq->cryptlen -+ - cryp->authsize; - } - -- cryp->total_in_save = cryp->total_in; -- cryp->total_out_save = cryp->total_out; -+ cryp->remain_in = cryp->total_in; -+ cryp->remain_out = cryp->total_out; - - cryp->in_sg = req ? req->src : areq->src; - cryp->out_sg = req ? req->dst : areq->dst; - cryp->out_sg_save = cryp->out_sg; - -- cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in); -- if (cryp->in_sg_len < 0) { -- dev_err(cryp->dev, "Cannot get in_sg_len\n"); -- ret = cryp->in_sg_len; -- return ret; -- } -- -- cryp->out_sg_len = sg_nents_for_len(cryp->out_sg, cryp->total_out); -- if (cryp->out_sg_len < 0) { -- dev_err(cryp->dev, "Cannot get out_sg_len\n"); -- ret = cryp->out_sg_len; -- return ret; -- } -- - ret = stm32_cryp_copy_sgs(cryp); - if (ret) - return ret; -@@ -1011,7 +1135,7 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req, - if (is_gcm(cryp) || is_ccm(cryp)) { - /* In output, jump after assoc data */ - scatterwalk_advance(&cryp->out_walk, cryp->areq->assoclen); -- cryp->total_out -= cryp->areq->assoclen; -+ cryp->remain_out -= cryp->areq->assoclen; - } - - ret = stm32_cryp_hw_init(cryp); -@@ -1130,7 +1254,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_DIN, size_bit); - - size_bit = is_encrypt(cryp) ? cryp->areq->cryptlen : -- cryp->areq->cryptlen - AES_BLOCK_SIZE; -+ cryp->areq->cryptlen - cryp->authsize; - size_bit *= 8; - if (cryp->caps->swap_final) - size_bit = (__force u32)cpu_to_be32(size_bit); -@@ -1169,14 +1293,14 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - dst = sg_virt(cryp->out_sg) + _walked_out; - - for (i = 0; i < AES_BLOCK_32; i++) { -- if (cryp->total_out >= sizeof(u32)) { -+ if (cryp->remain_out >= sizeof(u32)) { - /* Read a full u32 */ - *dst = stm32_cryp_read(cryp, CRYP_DOUT); - - dst = stm32_cryp_next_out(cryp, dst, - sizeof(u32)); -- cryp->total_out -= sizeof(u32); -- } else if (!cryp->total_out) { -+ cryp->remain_out -= sizeof(u32); -+ } else if (!cryp->remain_out) { - /* Empty fifo out (data from input padding) */ - stm32_cryp_read(cryp, CRYP_DOUT); - } else { -@@ -1184,11 +1308,11 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - d32 = stm32_cryp_read(cryp, CRYP_DOUT); - d8 = (u8 *)&d32; - -- for (j = 0; j < cryp->total_out; j++) { -+ for (j = 0; j < cryp->remain_out; j++) { - *((u8 *)dst) = *(d8++); - dst = stm32_cryp_next_out(cryp, dst, 1); - } -- cryp->total_out = 0; -+ cryp->remain_out = 0; - } - } - } else { -@@ -1196,7 +1320,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) - u32 in_tag[AES_BLOCK_32], out_tag[AES_BLOCK_32]; - - scatterwalk_map_and_copy(in_tag, cryp->in_sg, -- cryp->total_in_save - cryp->authsize, -+ cryp->total_in - cryp->authsize, - cryp->authsize, 0); - - for (i = 0; i < AES_BLOCK_32; i++) -@@ -1256,13 +1380,13 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) - dst = sg_virt(cryp->out_sg) + _walked_out; - - for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { -- if (likely(cryp->total_out - tag_size >= sizeof(u32))) { -+ if (likely(cryp->remain_out - tag_size >= sizeof(u32))) { - /* Read a full u32 */ - *dst = stm32_cryp_read(cryp, CRYP_DOUT); - - dst = stm32_cryp_next_out(cryp, dst, sizeof(u32)); -- cryp->total_out -= sizeof(u32); -- } else if (cryp->total_out == tag_size) { -+ cryp->remain_out -= sizeof(u32); -+ } else if (cryp->remain_out == tag_size) { - /* Empty fifo out (data from input padding) */ - d32 = stm32_cryp_read(cryp, CRYP_DOUT); - } else { -@@ -1270,15 +1394,15 @@ static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) - d32 = stm32_cryp_read(cryp, CRYP_DOUT); - d8 = (u8 *)&d32; - -- for (j = 0; j < cryp->total_out - tag_size; j++) { -+ for (j = 0; j < cryp->remain_out - tag_size; j++) { - *((u8 *)dst) = *(d8++); - dst = stm32_cryp_next_out(cryp, dst, 1); - } -- cryp->total_out = tag_size; -+ cryp->remain_out = tag_size; - } - } - -- return !(cryp->total_out - tag_size) || !cryp->total_in; -+ return !(cryp->remain_out - tag_size) || !cryp->remain_in; - } - - static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) -@@ -1297,25 +1421,25 @@ static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) - src = sg_virt(cryp->in_sg) + _walked_in; - - for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { -- if (likely(cryp->total_in - tag_size >= sizeof(u32))) { -+ if (likely(cryp->remain_in - tag_size >= sizeof(u32))) { - /* Write a full u32 */ - stm32_cryp_write(cryp, CRYP_DIN, *src); - - src = stm32_cryp_next_in(cryp, src, sizeof(u32)); -- cryp->total_in -= sizeof(u32); -- } else if (cryp->total_in == tag_size) { -+ cryp->remain_in -= sizeof(u32); -+ } else if (cryp->remain_in == tag_size) { - /* Write padding data */ - stm32_cryp_write(cryp, CRYP_DIN, 0); - } else { - /* Write less than an u32 */ - memset(d8, 0, sizeof(u32)); -- for (j = 0; j < cryp->total_in - tag_size; j++) { -+ for (j = 0; j < cryp->remain_in - tag_size; j++) { - d8[j] = *((u8 *)src); - src = stm32_cryp_next_in(cryp, src, 1); - } - - stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); -- cryp->total_in = tag_size; -+ cryp->remain_in = tag_size; - } - } - } -@@ -1324,7 +1448,7 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - { - int err; - u32 cfg, tmp[AES_BLOCK_32]; -- size_t total_in_ori = cryp->total_in; -+ size_t remain_in_ori = cryp->remain_in; - struct scatterlist *out_sg_ori = cryp->out_sg; - unsigned int i; - -@@ -1350,7 +1474,7 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - - /* b) pad and write the last block */ - stm32_cryp_irq_write_block(cryp); -- cryp->total_in = total_in_ori; -+ cryp->remain_in = remain_in_ori; - err = stm32_cryp_wait_output(cryp); - if (err) { - dev_err(cryp->dev, "Timeout (write gcm header)\n"); -@@ -1360,8 +1484,8 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - /* c) get and store encrypted data */ - stm32_cryp_irq_read_data(cryp); - scatterwalk_map_and_copy(tmp, out_sg_ori, -- cryp->total_in_save - total_in_ori, -- total_in_ori, 0); -+ cryp->total_in - remain_in_ori, -+ remain_in_ori, 0); - - /* d) change mode back to AES GCM */ - cfg &= ~CR_ALGO_MASK; -@@ -1375,12 +1499,12 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) - - /* f) write padded data */ - for (i = 0; i < AES_BLOCK_32; i++) { -- if (cryp->total_in) -+ if (cryp->remain_in) - stm32_cryp_write(cryp, CRYP_DIN, tmp[i]); - else - stm32_cryp_write(cryp, CRYP_DIN, 0); - -- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); -+ cryp->remain_in -= min_t(size_t, sizeof(u32), cryp->remain_in); - } - - /* g) Empty fifo out */ -@@ -1406,8 +1530,8 @@ static void stm32_cryp_irq_set_npblb(struct stm32_cryp *cryp) - cfg &= ~CR_CRYPEN; - stm32_cryp_write(cryp, CRYP_CR, cfg); - -- payload_bytes = is_decrypt(cryp) ? cryp->total_in - cryp->authsize : -- cryp->total_in; -+ payload_bytes = is_decrypt(cryp) ? cryp->remain_in - cryp->authsize : -+ cryp->remain_in; - cfg |= (cryp->hw_blocksize - payload_bytes) << CR_NBPBL_SHIFT; - cfg |= CR_CRYPEN; - stm32_cryp_write(cryp, CRYP_CR, cfg); -@@ -1418,7 +1542,7 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - int err = 0; - u32 cfg, iv1tmp; - u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32], tmp[AES_BLOCK_32]; -- size_t last_total_out, total_in_ori = cryp->total_in; -+ size_t last_remain_out, remain_in_ori = cryp->remain_in; - struct scatterlist *out_sg_ori = cryp->out_sg; - unsigned int i; - -@@ -1453,7 +1577,7 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - - /* b) pad and write the last block */ - stm32_cryp_irq_write_block(cryp); -- cryp->total_in = total_in_ori; -+ cryp->remain_in = remain_in_ori; - err = stm32_cryp_wait_output(cryp); - if (err) { - dev_err(cryp->dev, "Timeout (wite ccm padded data)\n"); -@@ -1461,13 +1585,13 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - } - - /* c) get and store decrypted data */ -- last_total_out = cryp->total_out; -+ last_remain_out = cryp->remain_out; - stm32_cryp_irq_read_data(cryp); - - memset(tmp, 0, sizeof(tmp)); - scatterwalk_map_and_copy(tmp, out_sg_ori, -- cryp->total_out_save - last_total_out, -- last_total_out, 0); -+ cryp->total_out - last_remain_out, -+ last_remain_out, 0); - - /* d) Load again CRYP_CSGCMCCMxR */ - for (i = 0; i < ARRAY_SIZE(cstmp2); i++) -@@ -1501,12 +1625,12 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) - - static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) - { -- if (unlikely(!cryp->total_in)) { -+ if (unlikely(!cryp->remain_in)) { - dev_warn(cryp->dev, "No more data to process\n"); - return; - } - -- if (unlikely(cryp->total_in < AES_BLOCK_SIZE && -+ if (unlikely(cryp->remain_in < AES_BLOCK_SIZE && - (stm32_cryp_get_hw_mode(cryp) == CR_AES_GCM) && - is_encrypt(cryp))) { - /* Padding for AES GCM encryption */ -@@ -1518,7 +1642,7 @@ static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) - stm32_cryp_irq_set_npblb(cryp); - } - -- if (unlikely((cryp->total_in - cryp->authsize < AES_BLOCK_SIZE) && -+ if (unlikely((cryp->remain_in - cryp->authsize < AES_BLOCK_SIZE) && - (stm32_cryp_get_hw_mode(cryp) == CR_AES_CCM) && - is_decrypt(cryp))) { - /* Padding for AES CCM decryption */ -@@ -1548,10 +1672,10 @@ static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_DIN, *src); - - src = stm32_cryp_next_in(cryp, src, sizeof(u32)); -- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); -+ cryp->remain_in -= min_t(size_t, sizeof(u32), cryp->remain_in); - - /* Check if whole header written */ -- if ((cryp->total_in_save - cryp->total_in) == -+ if ((cryp->total_in - cryp->remain_in) >= - cryp->areq->assoclen) { - /* Write padding if needed */ - for (j = i + 1; j < AES_BLOCK_32; j++) -@@ -1583,7 +1707,7 @@ static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp) - break; - } - -- if (!cryp->total_in) -+ if (!cryp->remain_in) - break; - } - } -@@ -1611,7 +1735,7 @@ static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); - i++; - -- cryp->total_in -= min_t(size_t, 2, cryp->total_in); -+ cryp->remain_in -= min_t(size_t, 2, cryp->remain_in); - } else { - /* Build the two first u32 of B1 */ - d8[0] = 0xFF; -@@ -1632,7 +1756,7 @@ static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) - stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); - i++; - -- cryp->total_in -= min_t(size_t, 2, cryp->total_in); -+ cryp->remain_in -= min_t(size_t, 2, cryp->remain_in); - } - } - -@@ -1644,14 +1768,14 @@ static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) - d8[k] = *((u8 *)src); - src = stm32_cryp_next_in(cryp, src, 1); - -- cryp->total_in -= min_t(size_t, 1, cryp->total_in); -- if ((cryp->total_in_save - cryp->total_in) == alen) -+ cryp->remain_in -= min_t(size_t, 1, cryp->remain_in); -+ if ((cryp->total_in - cryp->remain_in) == alen) - break; - } - - stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); - -- if ((cryp->total_in_save - cryp->total_in) == alen) { -+ if ((cryp->total_in - cryp->remain_in) == alen) { - /* Write padding if needed */ - for (j = i + 1; j < AES_BLOCK_32; j++) - stm32_cryp_write(cryp, CRYP_DIN, 0); -@@ -1955,7 +2079,9 @@ static int stm32_cryp_probe(struct platform_device *pdev) - - cryp->clk = devm_clk_get(dev, NULL); - if (IS_ERR(cryp->clk)) { -- dev_err(dev, "Could not get clock\n"); -+ if (PTR_ERR(cryp->clk) != -EPROBE_DEFER) -+ dev_err(dev, "Could not get clock\n"); -+ - return PTR_ERR(cryp->clk); - } - -@@ -1973,7 +2099,11 @@ static int stm32_cryp_probe(struct platform_device *pdev) - pm_runtime_enable(dev); - - rst = devm_reset_control_get(dev, NULL); -- if (!IS_ERR(rst)) { -+ if (IS_ERR(rst)) { -+ ret = PTR_ERR(rst); -+ if (ret == -EPROBE_DEFER) -+ goto err_rst; -+ } else { - reset_control_assert(rst); - udelay(2); - reset_control_deassert(rst); -@@ -2024,7 +2154,7 @@ static int stm32_cryp_probe(struct platform_device *pdev) - spin_lock(&cryp_list.lock); - list_del(&cryp->list); - spin_unlock(&cryp_list.lock); -- -+err_rst: - pm_runtime_disable(dev); - pm_runtime_put_noidle(dev); - pm_runtime_disable(dev); -diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c -index e3e25278a970..da9c3e913e55 100644 ---- a/drivers/crypto/stm32/stm32-hash.c -+++ b/drivers/crypto/stm32/stm32-hash.c -@@ -925,15 +925,10 @@ static int stm32_hash_final(struct ahash_request *req) - static int stm32_hash_finup(struct ahash_request *req) - { - struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); -- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); -- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); - int err1, err2; - - rctx->flags |= HASH_FLAGS_FINUP; - -- if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) -- rctx->flags &= ~HASH_FLAGS_CPU; -- - err1 = stm32_hash_update(req); - - if (err1 == -EINPROGRESS || err1 == -EBUSY) -@@ -950,7 +945,19 @@ static int stm32_hash_finup(struct ahash_request *req) - - static int stm32_hash_digest(struct ahash_request *req) - { -- return stm32_hash_init(req) ?: stm32_hash_finup(req); -+ int ret; -+ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); -+ struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); -+ struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); -+ -+ ret = stm32_hash_init(req); -+ if (ret) -+ return ret; -+ -+ if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) -+ rctx->flags &= ~HASH_FLAGS_CPU; -+ -+ return stm32_hash_finup(req); - } - - static int stm32_hash_export(struct ahash_request *req, void *out) --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0012-ARM-5.10.10-stm32mp1-r1-MMC.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0012-ARM-5.10.10-stm32mp1-r1-MMC.patch deleted file mode 100644 index a544c1d..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0012-ARM-5.10.10-stm32mp1-r1-MMC.patch +++ /dev/null @@ -1,62 +0,0 @@ -From 83c3a690670bb23a4a1fb645cf980056b4f85f4d Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:12:53 +0100 -Subject: [PATCH 12/22] ARM 5.10.10-stm32mp1-r1 MMC - ---- - drivers/mmc/core/mmc_test.c | 2 +- - drivers/mmc/host/mmci.c | 13 +++++++++---- - 2 files changed, 10 insertions(+), 5 deletions(-) - -diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c -index 152e7525ed33..b1f0d04f9430 100644 ---- a/drivers/mmc/core/mmc_test.c -+++ b/drivers/mmc/core/mmc_test.c -@@ -2124,7 +2124,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, - if (mmc_can_erase(test->card) && - tdata->prepare & MMC_TEST_PREP_ERASE) { - ret = mmc_erase(test->card, dev_addr, -- size / 512, MMC_SECURE_ERASE_ARG); -+ size / 512, test->card->erase_arg); - if (ret) - ret = mmc_erase(test->card, dev_addr, - size / 512, MMC_ERASE_ARG); -diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c -index b5a41a7ce165..fa6d85190cdb 100644 ---- a/drivers/mmc/host/mmci.c -+++ b/drivers/mmc/host/mmci.c -@@ -1241,7 +1241,11 @@ mmci_start_command(struct mmci_host *host, struct mmc_command *cmd, u32 c) - if (!cmd->busy_timeout) - cmd->busy_timeout = 10 * MSEC_PER_SEC; - -- clks = (unsigned long long)cmd->busy_timeout * host->cclk; -+ if (cmd->busy_timeout > host->mmc->max_busy_timeout) -+ clks = (unsigned long long)host->mmc->max_busy_timeout * host->cclk; -+ else -+ clks = (unsigned long long)cmd->busy_timeout * host->cclk; -+ - do_div(clks, MSEC_PER_SEC); - writel_relaxed(clks, host->base + MMCIDATATIMER); - } -@@ -2091,14 +2095,15 @@ static int mmci_probe(struct amba_device *dev, - mmc->caps |= MMC_CAP_WAIT_WHILE_BUSY; - } - -+ /* Variants with mandatory busy timeout in HW needs R1B responses. */ -+ if (variant->busy_timeout) -+ mmc->caps |= MMC_CAP_NEED_RSP_BUSY; -+ - /* Prepare a CMD12 - needed to clear the DPSM on some variants. */ - host->stop_abort.opcode = MMC_STOP_TRANSMISSION; - host->stop_abort.arg = 0; - host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; - -- /* We support these PM capabilities. */ -- mmc->pm_caps |= MMC_PM_KEEP_POWER; -- - /* - * We can do SGIO - */ --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0016-ARM-5.10.10-stm32mp1-r1-PINCTRL-REGULATOR-SPI.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0016-ARM-5.10.10-stm32mp1-r1-PINCTRL-REGULATOR-SPI.patch deleted file mode 100644 index b2e36c6..0000000 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0016-ARM-5.10.10-stm32mp1-r1-PINCTRL-REGULATOR-SPI.patch +++ /dev/null @@ -1,1502 +0,0 @@ -From c74780d4cb41745849aaf03a9704a96ee9ae92ba Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:16:04 +0100 -Subject: [PATCH 16/22] ARM 5.10.10-stm32mp1-r1 PINCTRL-REGULATOR-SPI - -Signed-off-by: Romuald JEANNE ---- - drivers/pinctrl/stm32/pinctrl-stm32.c | 42 ++- - drivers/pinctrl/stm32/pinctrl-stm32.h | 17 +- - drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1 + - drivers/pwm/pwm-stm32.c | 4 + - drivers/regulator/stm32-pwr.c | 85 ++++- - drivers/regulator/stpmic1_regulator.c | 182 ++++++++++- - drivers/spi/spi-stm32-qspi.c | 18 +- - drivers/spi/spi-stm32.c | 345 +++++++++++--------- - include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + - 9 files changed, 508 insertions(+), 187 deletions(-) - -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c -index 7d9bdedcd71b..a20c06b06e19 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.c -@@ -73,6 +73,7 @@ static const char * const stm32_gpio_functions[] = { - "af8", "af9", "af10", - "af11", "af12", "af13", - "af14", "af15", "analog", -+ "reserved", - }; - - struct stm32_pinctrl_group { -@@ -115,6 +116,7 @@ struct stm32_pinctrl { - u32 pkg; - u16 irqmux_map; - spinlock_t irqmux_lock; -+ u32 pin_base_shift; - }; - - static inline int stm32_gpio_pin(int gpio) -@@ -513,7 +515,7 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) - static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, - u32 pin_num, u32 fnum) - { -- int i; -+ int i, k; - - for (i = 0; i < pctl->npins; i++) { - const struct stm32_desc_pin *pin = pctl->pins + i; -@@ -522,7 +524,10 @@ static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, - if (pin->pin.number != pin_num) - continue; - -- while (func && func->name) { -+ if (fnum == STM32_PIN_RSVD) -+ return true; -+ -+ for (k = 0; k < STM32_CONFIG_NUM; k++) { - if (func->num == fnum) - return true; - func++; -@@ -833,6 +838,11 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, - return -EINVAL; - } - -+ if (function == STM32_PIN_RSVD) { -+ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); -+ return 0; -+ } -+ - bank = gpiochip_get_data(range->gc); - pin = stm32_gpio_pin(g->pin); - -@@ -1147,10 +1157,27 @@ static int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, - return 0; - } - -+static struct stm32_desc_pin * -+stm32_pconf_get_pin_desc_by_pin_number(struct stm32_pinctrl *pctl, -+ unsigned int pin_number) -+{ -+ struct stm32_desc_pin *pins = pctl->pins; -+ int i; -+ -+ for (i = 0; i < pctl->npins; i++) { -+ if (pins->pin.number == pin_number) -+ return pins; -+ pins++; -+ } -+ return NULL; -+} -+ - static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, - struct seq_file *s, - unsigned int pin) - { -+ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); -+ const struct stm32_desc_pin *pin_desc; - struct pinctrl_gpio_range *range; - struct stm32_gpio_bank *bank; - int offset; -@@ -1200,7 +1227,12 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, - case 2: - drive = stm32_pconf_get_driving(bank, offset); - speed = stm32_pconf_get_speed(bank, offset); -- seq_printf(s, "%d - %s - %s - %s %s", alt, -+ pin_desc = stm32_pconf_get_pin_desc_by_pin_number(pctl, pin); -+ if (!pin_desc) -+ return; -+ -+ seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, -+ pin_desc->functions[alt + 1].name, - drive ? "open drain" : "push pull", - biasing[bias], - speeds[speed], "speed"); -@@ -1404,7 +1436,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, - if (pctl->pkg && !(pctl->pkg & p->pkg)) - continue; - pins->pin = p->pin; -- pins->functions = p->functions; -+ memcpy((struct stm32_desc_pin *)pins->functions, p->functions, -+ STM32_CONFIG_NUM * sizeof(struct stm32_desc_function)); - pins++; - nb_pins_available++; - } -@@ -1513,6 +1546,7 @@ int stm32_pctl_probe(struct platform_device *pdev) - pctl->pctl_desc.pctlops = &stm32_pctrl_ops; - pctl->pctl_desc.pmxops = &stm32_pmx_ops; - pctl->dev = &pdev->dev; -+ pctl->pin_base_shift = pctl->match_data->pin_base_shift; - - pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, - pctl); -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h -index b0882d120765..a7137fbff5d0 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32.h -+++ b/drivers/pinctrl/stm32/pinctrl-stm32.h -@@ -17,6 +17,8 @@ - #define STM32_PIN_GPIO 0 - #define STM32_PIN_AF(x) ((x) + 1) - #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) -+#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) -+#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) - - /* package information */ - #define STM32MP_PKG_AA BIT(0) -@@ -24,6 +26,8 @@ - #define STM32MP_PKG_AC BIT(2) - #define STM32MP_PKG_AD BIT(3) - -+#define STM32MP157_Z_BASE_SHIFT 400 -+ - struct stm32_desc_function { - const char *name; - const unsigned char num; -@@ -31,26 +35,26 @@ struct stm32_desc_function { - - struct stm32_desc_pin { - struct pinctrl_pin_desc pin; -- const struct stm32_desc_function *functions; -+ const struct stm32_desc_function functions[STM32_CONFIG_NUM]; - const unsigned int pkg; - }; - - #define STM32_PIN(_pin, ...) \ - { \ - .pin = _pin, \ -- .functions = (struct stm32_desc_function[]){ \ -- __VA_ARGS__, { } }, \ -+ .functions = { \ -+ __VA_ARGS__}, \ - } - - #define STM32_PIN_PKG(_pin, _pkg, ...) \ - { \ - .pin = _pin, \ - .pkg = _pkg, \ -- .functions = (struct stm32_desc_function[]){ \ -- __VA_ARGS__, { } }, \ -+ .functions = { \ -+ __VA_ARGS__}, \ - } - #define STM32_FUNCTION(_num, _name) \ -- { \ -+ [_num] = { \ - .num = _num, \ - .name = _name, \ - } -@@ -58,6 +62,7 @@ struct stm32_desc_pin { - struct stm32_pinctrl_match_data { - const struct stm32_desc_pin *pins; - const unsigned int npins; -+ const unsigned int pin_base_shift; - }; - - struct stm32_gpio_bank; -diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -index 2ccb99d64df8..86fe6d5ac54d 100644 ---- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -+++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c -@@ -2328,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { - static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { - .pins = stm32mp157_z_pins, - .npins = ARRAY_SIZE(stm32mp157_z_pins), -+ .pin_base_shift = STM32MP157_Z_BASE_SHIFT, - }; - - static const struct of_device_id stm32mp157_pctrl_match[] = { -diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c -index d3be944f2ae9..13f47e25572e 100644 ---- a/drivers/pwm/pwm-stm32.c -+++ b/drivers/pwm/pwm-stm32.c -@@ -207,6 +207,10 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, - regmap_write(priv->regmap, TIM_ARR, priv->max_arr); - regmap_write(priv->regmap, TIM_PSC, psc); - -+ /* Reset input selector to its default input and disable slave mode */ -+ regmap_write(priv->regmap, TIM_TISEL, 0x0); -+ regmap_write(priv->regmap, TIM_SMCR, 0x0); -+ - /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */ - regmap_update_bits(priv->regmap, - pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, -diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c -index 2a42acb7c24e..2b328b970b46 100644 ---- a/drivers/regulator/stm32-pwr.c -+++ b/drivers/regulator/stm32-pwr.c -@@ -3,12 +3,15 @@ - // Authors: Gabriel Fernandez - // Pascal Paillet . - -+#include - #include - #include -+#include - #include - #include - #include - #include -+#include - #include - #include - -@@ -24,6 +27,11 @@ - #define REG_1_1_EN BIT(30) - #define REG_1_1_RDY BIT(31) - -+#define STM32_SMC_PWR 0x82001001 -+#define STM32_WRITE 0x1 -+#define STM32_SMC_REG_SET 0x2 -+#define STM32_SMC_REG_CLEAR 0x3 -+ - /* list of supported regulators */ - enum { - PWR_REG11, -@@ -39,10 +47,18 @@ static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = { - }; - - struct stm32_pwr_reg { -+ int tzen; - void __iomem *base; - u32 ready_mask; - }; - -+#define SMC(class, op, address, val)\ -+ ({\ -+ struct arm_smccc_res res;\ -+ arm_smccc_smc(class, op, address, val,\ -+ 0, 0, 0, 0, &res);\ -+ }) -+ - static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev) - { - struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); -@@ -69,9 +85,15 @@ static int stm32_pwr_reg_enable(struct regulator_dev *rdev) - int ret; - u32 val; - -- val = readl_relaxed(priv->base + REG_PWR_CR3); -- val |= rdev->desc->enable_mask; -- writel_relaxed(val, priv->base + REG_PWR_CR3); -+ if (priv->tzen) { -+ SMC(STM32_SMC_PWR, STM32_SMC_REG_SET, REG_PWR_CR3, -+ rdev->desc->enable_mask); -+ } else { -+ val = readl_relaxed(priv->base + REG_PWR_CR3); -+ val |= rdev->desc->enable_mask; -+ writel_relaxed(val, priv->base + REG_PWR_CR3); -+ } -+ - - /* use an arbitrary timeout of 20ms */ - ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val, -@@ -88,9 +110,14 @@ static int stm32_pwr_reg_disable(struct regulator_dev *rdev) - int ret; - u32 val; - -- val = readl_relaxed(priv->base + REG_PWR_CR3); -- val &= ~rdev->desc->enable_mask; -- writel_relaxed(val, priv->base + REG_PWR_CR3); -+ if (priv->tzen) { -+ SMC(STM32_SMC_PWR, STM32_SMC_REG_CLEAR, REG_PWR_CR3, -+ rdev->desc->enable_mask); -+ } else { -+ val = readl_relaxed(priv->base + REG_PWR_CR3); -+ val &= ~rdev->desc->enable_mask; -+ writel_relaxed(val, priv->base + REG_PWR_CR3); -+ } - - /* use an arbitrary timeout of 20ms */ - ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val, -@@ -121,12 +148,50 @@ static const struct regulator_ops stm32_pwr_reg_ops = { - .supply_name = _supply, \ - } \ - --static const struct regulator_desc stm32_pwr_desc[] = { -+static struct regulator_desc stm32_pwr_desc[] = { - PWR_REG(PWR_REG11, "reg11", 1100000, REG_1_1_EN, "vdd"), - PWR_REG(PWR_REG18, "reg18", 1800000, REG_1_8_EN, "vdd"), - PWR_REG(PWR_USB33, "usb33", 3300000, USB_3_3_EN, "vdd_3v3_usbfs"), - }; - -+static int is_stm32_soc_secured(struct platform_device *pdev, int *val) -+{ -+ struct device_node *np = pdev->dev.of_node; -+ struct regmap *syscon; -+ u32 reg, mask; -+ int tzc_val = 0; -+ int err; -+ -+ syscon = syscon_regmap_lookup_by_phandle(np, "st,tzcr"); -+ if (IS_ERR(syscon)) { -+ if (PTR_ERR(syscon) != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "tzcr syscon required\n"); -+ return PTR_ERR(syscon); -+ } -+ -+ err = of_property_read_u32_index(np, "st,tzcr", 1, ®); -+ if (err) { -+ dev_err(&pdev->dev, "tzcr offset required !\n"); -+ return err; -+ } -+ -+ err = of_property_read_u32_index(np, "st,tzcr", 2, &mask); -+ if (err) { -+ dev_err(&pdev->dev, "tzcr mask required !\n"); -+ return err; -+ } -+ -+ err = regmap_read(syscon, reg, &tzc_val); -+ if (err) { -+ dev_err(&pdev->dev, "failed to read tzcr status !\n"); -+ return err; -+ } -+ -+ *val = tzc_val & mask; -+ -+ return 0; -+} -+ - static int stm32_pwr_regulator_probe(struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; -@@ -135,6 +200,11 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) - struct regulator_dev *rdev; - struct regulator_config config = { }; - int i, ret = 0; -+ int tzen = 0; -+ -+ ret = is_stm32_soc_secured(pdev, &tzen); -+ if (ret) -+ return ret; - - base = of_iomap(np, 0); - if (!base) { -@@ -149,6 +219,7 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) - GFP_KERNEL); - if (!priv) - return -ENOMEM; -+ priv->tzen = tzen; - priv->base = base; - priv->ready_mask = ready_mask_table[i]; - config.driver_data = priv; -diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c -index cf10fdb72e32..c5337a12a61a 100644 ---- a/drivers/regulator/stpmic1_regulator.c -+++ b/drivers/regulator/stpmic1_regulator.c -@@ -2,7 +2,9 @@ - // Copyright (C) STMicroelectronics 2018 - // Author: Pascal Paillet for STMicroelectronics. - -+#include - #include -+#include - #include - #include - #include -@@ -30,10 +32,26 @@ struct stpmic1_regulator_cfg { - u8 icc_mask; - }; - -+/** -+ * struct boost_data - this structure is used as driver data for the usb boost -+ * @boost_rdev: device for boost regulator -+ * @vbus_otg_rdev: device for vbus_otg regulator -+ * @sw_out_rdev: device for sw_out regulator -+ * @occ_timeout: overcurrent detection timeout -+ */ -+struct boost_data { -+ struct regulator_dev *boost_rdev; -+ struct regulator_dev *vbus_otg_rdev; -+ struct regulator_dev *sw_out_rdev; -+ ktime_t occ_timeout; -+}; -+ - static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); - static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); - static int stpmic1_set_icc(struct regulator_dev *rdev); - static unsigned int stpmic1_map_mode(unsigned int mode); -+static int regulator_enable_boost(struct regulator_dev *rdev); -+static int regulator_disable_boost(struct regulator_dev *rdev); - - enum { - STPMIC1_BUCK1 = 0, -@@ -181,8 +199,8 @@ static const struct regulator_ops stpmic1_vref_ddr_ops = { - - static const struct regulator_ops stpmic1_boost_regul_ops = { - .is_enabled = regulator_is_enabled_regmap, -- .enable = regulator_enable_regmap, -- .disable = regulator_disable_regmap, -+ .enable = regulator_enable_boost, -+ .disable = regulator_disable_boost, - .set_over_current_protection = stpmic1_set_icc, - }; - -@@ -513,6 +531,79 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) - return IRQ_HANDLED; - } - -+static int regulator_enable_boost(struct regulator_dev *rdev) -+{ -+ struct boost_data *usb_data = rdev_get_drvdata(rdev); -+ -+ usb_data->occ_timeout = ktime_add_us(ktime_get(), 100000); -+ -+ return regulator_enable_regmap(rdev); -+} -+ -+static int regulator_disable_boost(struct regulator_dev *rdev) -+{ -+ struct boost_data *usb_data = rdev_get_drvdata(rdev); -+ -+ usb_data->occ_timeout = 0; -+ -+ return regulator_disable_regmap(rdev); -+} -+ -+static void stpmic1_reset_boost(struct boost_data *usb_data) -+{ -+ int otg_on = 0; -+ int sw_out_on = 0; -+ -+ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "reset usb boost\n"); -+ -+ /* the boost was actually disabled by the over-current protection */ -+ regulator_disable_regmap(usb_data->boost_rdev); -+ -+ if (usb_data->vbus_otg_rdev) -+ otg_on = regulator_is_enabled_regmap(usb_data->vbus_otg_rdev); -+ if (otg_on) -+ regulator_disable_regmap(usb_data->vbus_otg_rdev); -+ -+ if (usb_data->sw_out_rdev) -+ sw_out_on = regulator_is_enabled_regmap(usb_data->sw_out_rdev); -+ if (sw_out_on) -+ regulator_disable_regmap(usb_data->sw_out_rdev); -+ -+ regulator_enable_regmap(usb_data->boost_rdev); -+ -+ /* sleep at least 5ms */ -+ usleep_range(5000, 10000); -+ -+ if (otg_on) -+ regulator_enable_regmap(usb_data->vbus_otg_rdev); -+ -+ if (sw_out_on) -+ regulator_enable_regmap(usb_data->sw_out_rdev); -+ -+} -+ -+static irqreturn_t stpmic1_boost_irq_handler(int irq, void *data) -+{ -+ struct boost_data *usb_data = (struct boost_data *)data; -+ -+ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "usb boost irq handler\n"); -+ -+ /* overcurrent detected on boost after timeout */ -+ if (usb_data->occ_timeout != 0 && -+ ktime_compare(ktime_get(), usb_data->occ_timeout) > 0) { -+ /* reset usb boost and usb power switches */ -+ stpmic1_reset_boost(usb_data); -+ return IRQ_HANDLED; -+ } -+ -+ /* Send an overcurrent notification */ -+ regulator_notifier_call_chain(usb_data->boost_rdev, -+ REGULATOR_EVENT_OVER_CURRENT, -+ NULL); -+ -+ return IRQ_HANDLED; -+} -+ - #define MATCH(_name, _id) \ - [STPMIC1_##_id] = { \ - .name = #_name, \ -@@ -536,9 +627,10 @@ static struct of_regulator_match stpmic1_matches[] = { - MATCH(pwr_sw2, SW_OUT), - }; - --static int stpmic1_regulator_register(struct platform_device *pdev, int id, -- struct of_regulator_match *match, -- const struct stpmic1_regulator_cfg *cfg) -+static struct regulator_dev * -+stpmic1_regulator_register(struct platform_device *pdev, int id, -+ struct of_regulator_match *match, -+ const struct stpmic1_regulator_cfg *cfg) - { - struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); - struct regulator_dev *rdev; -@@ -556,7 +648,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, - if (IS_ERR(rdev)) { - dev_err(&pdev->dev, "failed to register %s regulator\n", - cfg->desc.name); -- return PTR_ERR(rdev); -+ return rdev; - } - - /* set mask reset */ -@@ -568,7 +660,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, - cfg->mask_reset_mask); - if (ret) { - dev_err(&pdev->dev, "set mask reset failed\n"); -- return ret; -+ return ERR_PTR(ret); - } - } - -@@ -582,15 +674,60 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, - pdev->name, rdev); - if (ret) { - dev_err(&pdev->dev, "Request IRQ failed\n"); -- return ret; -+ return ERR_PTR(ret); - } - } -- return 0; -+ -+ return rdev; -+} -+ -+static struct regulator_dev * -+stpmic1_boost_register(struct platform_device *pdev, int id, -+ struct of_regulator_match *match, -+ const struct stpmic1_regulator_cfg *cfg, -+ struct boost_data *usb_data) -+{ -+ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); -+ struct regulator_dev *rdev; -+ struct regulator_config config = {}; -+ int ret = 0; -+ int irq; -+ -+ config.dev = &pdev->dev; -+ config.init_data = match->init_data; -+ config.of_node = match->of_node; -+ config.regmap = pmic_dev->regmap; -+ config.driver_data = (void *)usb_data; -+ -+ rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); -+ if (IS_ERR(rdev)) { -+ dev_err(&pdev->dev, "failed to register %s regulator\n", -+ cfg->desc.name); -+ return rdev; -+ } -+ -+ /* setup an irq handler for over-current detection */ -+ irq = of_irq_get(config.of_node, 0); -+ if (irq > 0) { -+ ret = devm_request_threaded_irq(&pdev->dev, -+ irq, NULL, -+ stpmic1_boost_irq_handler, -+ IRQF_ONESHOT, pdev->name, -+ usb_data); -+ if (ret) { -+ dev_err(&pdev->dev, "Request IRQ failed\n"); -+ return ERR_PTR(ret); -+ } -+ } -+ -+ return rdev; - } - - static int stpmic1_regulator_probe(struct platform_device *pdev) - { - int i, ret; -+ struct boost_data *usb_data; -+ struct regulator_dev *rdev; - - ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, - ARRAY_SIZE(stpmic1_matches)); -@@ -600,11 +737,30 @@ static int stpmic1_regulator_probe(struct platform_device *pdev) - return ret; - } - -+ usb_data = devm_kzalloc(&pdev->dev, sizeof(*usb_data), GFP_KERNEL); -+ if (!usb_data) -+ return -ENOMEM; -+ - for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { -- ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], -- &stpmic1_regulator_cfgs[i]); -- if (ret < 0) -- return ret; -+ if (i == STPMIC1_BOOST) { -+ rdev = -+ stpmic1_boost_register(pdev, i, &stpmic1_matches[i], -+ &stpmic1_regulator_cfgs[i], -+ usb_data); -+ -+ usb_data->boost_rdev = rdev; -+ } else { -+ rdev = -+ stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], -+ &stpmic1_regulator_cfgs[i]); -+ -+ if (i == STPMIC1_VBUS_OTG) -+ usb_data->vbus_otg_rdev = rdev; -+ else if (i == STPMIC1_SW_OUT) -+ usb_data->sw_out_rdev = rdev; -+ } -+ if (IS_ERR(rdev)) -+ return PTR_ERR(rdev); - } - - dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); -diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c -index 947e6b9dc9f4..2786470a5201 100644 ---- a/drivers/spi/spi-stm32-qspi.c -+++ b/drivers/spi/spi-stm32-qspi.c -@@ -727,21 +727,31 @@ static int __maybe_unused stm32_qspi_suspend(struct device *dev) - { - pinctrl_pm_select_sleep_state(dev); - -- return 0; -+ return pm_runtime_force_suspend(dev); - } - - static int __maybe_unused stm32_qspi_resume(struct device *dev) - { - struct stm32_qspi *qspi = dev_get_drvdata(dev); -+ int ret; -+ -+ ret = pm_runtime_force_resume(dev); -+ if (ret < 0) -+ return ret; - - pinctrl_pm_select_default_state(dev); -- clk_prepare_enable(qspi->clk); -+ -+ ret = pm_runtime_get_sync(dev); -+ if (ret < 0) { -+ pm_runtime_put_noidle(dev); -+ return ret; -+ } - - writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); - writel_relaxed(qspi->dcr_reg, qspi->io_base + QSPI_DCR); - -- pm_runtime_mark_last_busy(qspi->dev); -- pm_runtime_put_autosuspend(qspi->dev); -+ pm_runtime_mark_last_busy(dev); -+ pm_runtime_put_autosuspend(dev); - - return 0; - } -diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c -index 6017209c6d2f..23bf7d6eb23c 100644 ---- a/drivers/spi/spi-stm32.c -+++ b/drivers/spi/spi-stm32.c -@@ -5,6 +5,7 @@ - // Copyright (C) 2017, STMicroelectronics - All Rights Reserved - // Author(s): Amelie Delaunay for STMicroelectronics. - -+#include - #include - #include - #include -@@ -31,8 +32,8 @@ - #define STM32F4_SPI_CR1_CPHA BIT(0) - #define STM32F4_SPI_CR1_CPOL BIT(1) - #define STM32F4_SPI_CR1_MSTR BIT(2) --#define STM32F4_SPI_CR1_BR_SHIFT 3 - #define STM32F4_SPI_CR1_BR GENMASK(5, 3) -+#define STM32F4_SPI_CR1_BR_SHIFT 3 - #define STM32F4_SPI_CR1_SPE BIT(6) - #define STM32F4_SPI_CR1_LSBFRST BIT(7) - #define STM32F4_SPI_CR1_SSI BIT(8) -@@ -94,27 +95,22 @@ - #define STM32H7_SPI_CR1_SSI BIT(12) - - /* STM32H7_SPI_CR2 bit fields */ --#define STM32H7_SPI_CR2_TSIZE_SHIFT 0 - #define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0) -+#define STM32H7_SPI_TSIZE_MAX GENMASK(15, 0) - - /* STM32H7_SPI_CFG1 bit fields */ --#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0 - #define STM32H7_SPI_CFG1_DSIZE GENMASK(4, 0) --#define STM32H7_SPI_CFG1_FTHLV_SHIFT 5 - #define STM32H7_SPI_CFG1_FTHLV GENMASK(8, 5) - #define STM32H7_SPI_CFG1_RXDMAEN BIT(14) - #define STM32H7_SPI_CFG1_TXDMAEN BIT(15) --#define STM32H7_SPI_CFG1_MBR_SHIFT 28 - #define STM32H7_SPI_CFG1_MBR GENMASK(30, 28) -+#define STM32H7_SPI_CFG1_MBR_SHIFT 28 - #define STM32H7_SPI_CFG1_MBR_MIN 0 - #define STM32H7_SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) - - /* STM32H7_SPI_CFG2 bit fields */ --#define STM32H7_SPI_CFG2_MIDI_SHIFT 4 - #define STM32H7_SPI_CFG2_MIDI GENMASK(7, 4) --#define STM32H7_SPI_CFG2_COMM_SHIFT 17 - #define STM32H7_SPI_CFG2_COMM GENMASK(18, 17) --#define STM32H7_SPI_CFG2_SP_SHIFT 19 - #define STM32H7_SPI_CFG2_SP GENMASK(21, 19) - #define STM32H7_SPI_CFG2_MASTER BIT(22) - #define STM32H7_SPI_CFG2_LSBFRST BIT(23) -@@ -130,17 +126,15 @@ - #define STM32H7_SPI_IER_EOTIE BIT(3) - #define STM32H7_SPI_IER_TXTFIE BIT(4) - #define STM32H7_SPI_IER_OVRIE BIT(6) --#define STM32H7_SPI_IER_MODFIE BIT(9) - #define STM32H7_SPI_IER_ALL GENMASK(10, 0) - - /* STM32H7_SPI_SR bit fields */ - #define STM32H7_SPI_SR_RXP BIT(0) - #define STM32H7_SPI_SR_TXP BIT(1) - #define STM32H7_SPI_SR_EOT BIT(3) -+#define STM32H7_SPI_SR_TXTF BIT(4) - #define STM32H7_SPI_SR_OVR BIT(6) --#define STM32H7_SPI_SR_MODF BIT(9) - #define STM32H7_SPI_SR_SUSP BIT(11) --#define STM32H7_SPI_SR_RXPLVL_SHIFT 13 - #define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13) - #define STM32H7_SPI_SR_RXWNE BIT(15) - -@@ -167,8 +161,6 @@ - #define SPI_3WIRE_TX 3 - #define SPI_3WIRE_RX 4 - --#define SPI_1HZ_NS 1000000000 -- - /* - * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers - * without fifo buffers. -@@ -249,7 +241,7 @@ struct stm32_spi_cfg { - int (*set_mode)(struct stm32_spi *spi, unsigned int comm_type); - void (*set_data_idleness)(struct stm32_spi *spi, u32 length); - int (*set_number_of_data)(struct stm32_spi *spi, u32 length); -- void (*transfer_one_dma_start)(struct stm32_spi *spi); -+ int (*transfer_one_dma_start)(struct stm32_spi *spi); - void (*dma_rx_cb)(void *data); - void (*dma_tx_cb)(void *data); - int (*transfer_one_irq)(struct stm32_spi *spi); -@@ -268,7 +260,6 @@ struct stm32_spi_cfg { - * @base: virtual memory area - * @clk: hw kernel clock feeding the SPI clock generator - * @clk_rate: rate of the hw kernel clock feeding the SPI clock generator -- * @rst: SPI controller reset line - * @lock: prevent I/O concurrent access - * @irq: SPI controller interrupt line - * @fifo_size: size of the embedded fifo in bytes -@@ -285,7 +276,10 @@ struct stm32_spi_cfg { - * @rx_len: number of data to be read in bytes - * @dma_tx: dma channel for TX transfer - * @dma_rx: dma channel for RX transfer -+ * @dma_completion: completion to wait for end of DMA transfer - * @phys_addr: SPI registers physical base address -+ * @xfer_completion: completion to wait for end of transfer -+ * @xfer_status: current transfer status - */ - struct stm32_spi { - struct device *dev; -@@ -294,7 +288,6 @@ struct stm32_spi { - void __iomem *base; - struct clk *clk; - u32 clk_rate; -- struct reset_control *rst; - spinlock_t lock; /* prevent I/O concurrent access */ - int irq; - unsigned int fifo_size; -@@ -313,7 +306,10 @@ struct stm32_spi { - int rx_len; - struct dma_chan *dma_tx; - struct dma_chan *dma_rx; -+ struct completion dma_completion; - dma_addr_t phys_addr; -+ struct completion xfer_completion; -+ int xfer_status; - }; - - static const struct stm32_spi_regspec stm32f4_spi_regspec = { -@@ -417,9 +413,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) - stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE); - - cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1); -- max_bpw = (cfg1 & STM32H7_SPI_CFG1_DSIZE) >> -- STM32H7_SPI_CFG1_DSIZE_SHIFT; -- max_bpw += 1; -+ max_bpw = FIELD_GET(STM32H7_SPI_CFG1_DSIZE, cfg1) + 1; - - spin_unlock_irqrestore(&spi->lock, flags); - -@@ -599,30 +593,30 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) - /** - * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register - * @spi: pointer to the spi controller data structure -- * @flush: boolean indicating that FIFO should be flushed - * - * Write in rx_buf depends on remaining bytes to avoid to write beyond - * rx_buf end. - */ --static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) -+static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi) - { - u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); -- u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> -- STM32H7_SPI_SR_RXPLVL_SHIFT; -+ u32 rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); - - while ((spi->rx_len > 0) && - ((sr & STM32H7_SPI_SR_RXP) || -- (flush && ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { -+ ((sr & STM32H7_SPI_SR_EOT) && -+ ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { - u32 offs = spi->cur_xferlen - spi->rx_len; - - if ((spi->rx_len >= sizeof(u32)) || -- (flush && (sr & STM32H7_SPI_SR_RXWNE))) { -+ (sr & STM32H7_SPI_SR_RXWNE)) { - u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); - - *rx_buf32 = readl_relaxed(spi->base + STM32H7_SPI_RXDR); - spi->rx_len -= sizeof(u32); - } else if ((spi->rx_len >= sizeof(u16)) || -- (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { -+ (!(sr & STM32H7_SPI_SR_RXWNE) && -+ (rxplvl >= 2 || spi->cur_bpw > 8))) { - u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); - - *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); -@@ -635,12 +629,11 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) - } - - sr = readl_relaxed(spi->base + STM32H7_SPI_SR); -- rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> -- STM32H7_SPI_SR_RXPLVL_SHIFT; -+ rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); - } - -- dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, -- flush ? "(flush)" : "", spi->rx_len); -+ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n", -+ __func__, spi->rx_len, sr); - } - - /** -@@ -708,12 +701,7 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) - * @spi: pointer to the spi controller data structure - * - * RX-Fifo is flushed when SPI controller is disabled. To prevent any data -- * loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in -- * RX-Fifo. -- * Normally, if TSIZE has been configured, we should relax the hardware at the -- * reception of the EOT interrupt. But in case of error, EOT will not be -- * raised. So the subsystem unprepare_message call allows us to properly -- * complete the transfer from an hardware point of view. -+ * loss, use stm32_spi_read_rxfifo to read the remaining bytes in RX-Fifo. - */ - static void stm32h7_spi_disable(struct stm32_spi *spi) - { -@@ -748,7 +736,7 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) - } - - if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) -- stm32h7_spi_read_rxfifo(spi, true); -+ stm32h7_spi_read_rxfifo(spi); - - if (spi->cur_usedma && spi->dma_tx) - dmaengine_terminate_all(spi->dma_tx); -@@ -892,8 +880,7 @@ static irqreturn_t stm32f4_spi_irq_thread(int irq, void *dev_id) - struct spi_master *master = dev_id; - struct stm32_spi *spi = spi_master_get_devdata(master); - -- spi_finalize_current_transfer(master); -- stm32f4_spi_disable(spi); -+ complete(&spi->xfer_completion); - - return IRQ_HANDLED; - } -@@ -907,7 +894,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) - { - struct spi_master *master = dev_id; - struct stm32_spi *spi = spi_master_get_devdata(master); -- u32 sr, ier, mask; -+ u32 sr, ier, mask, ifcr; - unsigned long flags; - bool end = false; - -@@ -915,81 +902,78 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) - - sr = readl_relaxed(spi->base + STM32H7_SPI_SR); - ier = readl_relaxed(spi->base + STM32H7_SPI_IER); -+ ifcr = 0; - - mask = ier; -- /* EOTIE is triggered on EOT, SUSP and TXC events. */ -+ /* -+ * EOTIE enables irq from EOT, SUSP and TXC events. We need to set -+ * SUSP to acknowledge it later. TXC is automatically cleared -+ */ - mask |= STM32H7_SPI_SR_SUSP; - /* -- * When TXTF is set, DXPIE and TXPIE are cleared. So in case of -- * Full-Duplex, need to poll RXP event to know if there are remaining -- * data, before disabling SPI. -+ * DXPIE is set in Full-Duplex, one IT will be raised if TXP and RXP -+ * are set. So in case of Full-Duplex, need to poll TXP and RXP event. - */ -- if (spi->rx_buf && !spi->cur_usedma) -- mask |= STM32H7_SPI_SR_RXP; -+ if ((spi->cur_comm == SPI_FULL_DUPLEX) && (!spi->cur_usedma)) -+ mask |= STM32H7_SPI_SR_TXP | STM32H7_SPI_SR_RXP; - -- if (!(sr & mask)) { -- dev_dbg(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", -- sr, ier); -+ mask &= sr; -+ -+ if (!mask) { -+ dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", -+ sr, ier); - spin_unlock_irqrestore(&spi->lock, flags); - return IRQ_NONE; - } - -- if (sr & STM32H7_SPI_SR_SUSP) { -+ if (mask & STM32H7_SPI_SR_SUSP) { - static DEFINE_RATELIMIT_STATE(rs, - DEFAULT_RATELIMIT_INTERVAL * 10, - 1); - if (__ratelimit(&rs)) - dev_dbg_ratelimited(spi->dev, "Communication suspended\n"); - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, false); -- /* -- * If communication is suspended while using DMA, it means -- * that something went wrong, so stop the current transfer -- */ -- if (spi->cur_usedma) -- end = true; -+ stm32h7_spi_read_rxfifo(spi); -+ ifcr |= STM32H7_SPI_SR_SUSP; - } - -- if (sr & STM32H7_SPI_SR_MODF) { -- dev_warn(spi->dev, "Mode fault: transfer aborted\n"); -+ if (mask & STM32H7_SPI_SR_OVR) { -+ dev_err(spi->dev, "Overrun: RX data lost\n"); -+ spi->xfer_status = -EIO; - end = true; -+ ifcr |= STM32H7_SPI_SR_OVR; - } - -- if (sr & STM32H7_SPI_SR_OVR) { -- dev_warn(spi->dev, "Overrun: received value discarded\n"); -- if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, false); -- /* -- * If overrun is detected while using DMA, it means that -- * something went wrong, so stop the current transfer -- */ -- if (spi->cur_usedma) -- end = true; -- } -+ if (mask & STM32H7_SPI_SR_TXTF) -+ ifcr |= STM32H7_SPI_SR_TXTF; - -- if (sr & STM32H7_SPI_SR_EOT) { -+ if (mask & STM32H7_SPI_SR_EOT) { - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, true); -+ stm32h7_spi_read_rxfifo(spi); - end = true; -+ ifcr |= STM32H7_SPI_SR_EOT; - } - -- if (sr & STM32H7_SPI_SR_TXP) -+ if (mask & STM32H7_SPI_SR_TXP) - if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) - stm32h7_spi_write_txfifo(spi); - -- if (sr & STM32H7_SPI_SR_RXP) -+ if (mask & STM32H7_SPI_SR_RXP) - if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) -- stm32h7_spi_read_rxfifo(spi, false); -- -- writel_relaxed(sr & mask, spi->base + STM32H7_SPI_IFCR); -- -- spin_unlock_irqrestore(&spi->lock, flags); -+ stm32h7_spi_read_rxfifo(spi); - - if (end) { -- stm32h7_spi_disable(spi); -- spi_finalize_current_transfer(master); -+ /* Disable interrupts and clear status flags */ -+ writel_relaxed(0, spi->base + STM32H7_SPI_IER); -+ writel_relaxed(STM32H7_SPI_IFCR_ALL, -+ spi->base + STM32H7_SPI_IFCR); -+ -+ complete(&spi->xfer_completion); -+ } else { -+ writel_relaxed(ifcr, spi->base + STM32H7_SPI_IFCR); - } - -+ spin_unlock_irqrestore(&spi->lock, flags); - return IRQ_HANDLED; - } - -@@ -1033,6 +1017,20 @@ static int stm32_spi_prepare_msg(struct spi_master *master, - spi_dev->mode & SPI_LSB_FIRST, - spi_dev->mode & SPI_CS_HIGH); - -+ /* On STM32H7, messages should not exceed a maximum size setted -+ * afterward via the set_number_of_data function. In order to -+ * ensure that, split large messages into several messages -+ */ -+ if (spi->cfg->set_number_of_data) { -+ int ret; -+ -+ ret = spi_split_transfers_maxsize(master, msg, -+ STM32H7_SPI_TSIZE_MAX, -+ GFP_KERNEL | GFP_DMA); -+ if (ret) -+ return ret; -+ } -+ - spin_lock_irqsave(&spi->lock, flags); - - /* CPOL, CPHA and LSB FIRST bits have common register */ -@@ -1057,10 +1055,8 @@ static void stm32f4_spi_dma_tx_cb(void *data) - { - struct stm32_spi *spi = data; - -- if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) { -- spi_finalize_current_transfer(spi->master); -- stm32f4_spi_disable(spi); -- } -+ if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) -+ complete(&spi->xfer_completion); - } - - /** -@@ -1073,33 +1069,25 @@ static void stm32f4_spi_dma_rx_cb(void *data) - { - struct stm32_spi *spi = data; - -- spi_finalize_current_transfer(spi->master); -- stm32f4_spi_disable(spi); -+ complete(&spi->xfer_completion); - } - - /** - * stm32h7_spi_dma_cb - dma callback - * @data: pointer to the spi controller data structure - * -- * DMA callback is called when the transfer is complete or when an error -- * occurs. If the transfer is complete, EOT flag is raised. -+ * DMA callback is called when the transfer is complete. - */ - static void stm32h7_spi_dma_cb(void *data) - { - struct stm32_spi *spi = data; - unsigned long flags; -- u32 sr; - - spin_lock_irqsave(&spi->lock, flags); - -- sr = readl_relaxed(spi->base + STM32H7_SPI_SR); -+ complete(&spi->dma_completion); - - spin_unlock_irqrestore(&spi->lock, flags); -- -- if (!(sr & STM32H7_SPI_SR_EOT)) -- dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); -- -- /* Now wait for EOT, or SUSP or OVR in case of error */ - } - - /** -@@ -1156,9 +1144,6 @@ static void stm32_spi_dma_config(struct stm32_spi *spi, - * stm32f4_spi_transfer_one_irq - transfer a single spi_transfer using - * interrupts - * @spi: pointer to the spi controller data structure -- * -- * It must returns 0 if the transfer is finished or 1 if the transfer is still -- * in progress. - */ - static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) - { -@@ -1192,16 +1177,13 @@ static int stm32f4_spi_transfer_one_irq(struct stm32_spi *spi) - - spin_unlock_irqrestore(&spi->lock, flags); - -- return 1; -+ return 0; - } - - /** - * stm32h7_spi_transfer_one_irq - transfer a single spi_transfer using - * interrupts - * @spi: pointer to the spi controller data structure -- * -- * It must returns 0 if the transfer is finished or 1 if the transfer is still -- * in progress. - */ - static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) - { -@@ -1218,7 +1200,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) - - /* Enable the interrupts relative to the end of transfer */ - ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | -- STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; -+ STM32H7_SPI_IER_OVRIE; - - spin_lock_irqsave(&spi->lock, flags); - -@@ -1234,7 +1216,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) - - spin_unlock_irqrestore(&spi->lock, flags); - -- return 1; -+ return 0; - } - - /** -@@ -1242,8 +1224,12 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) - * transfer using DMA - * @spi: pointer to the spi controller data structure - */ --static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) -+static int stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) - { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&spi->lock, flags); -+ - /* In DMA mode end of transfer is handled by DMA TX or RX callback. */ - if (spi->cur_comm == SPI_SIMPLEX_RX || spi->cur_comm == SPI_3WIRE_RX || - spi->cur_comm == SPI_FULL_DUPLEX) { -@@ -1256,6 +1242,10 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) - } - - stm32_spi_enable(spi); -+ -+ spin_unlock_irqrestore(&spi->lock, flags); -+ -+ return 0; - } - - /** -@@ -1263,36 +1253,48 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) - * transfer using DMA - * @spi: pointer to the spi controller data structure - */ --static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) -+static int stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) - { -+ unsigned long flags; -+ -+ spin_lock_irqsave(&spi->lock, flags); -+ - /* Enable the interrupts relative to the end of transfer */ - stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | - STM32H7_SPI_IER_TXTFIE | -- STM32H7_SPI_IER_OVRIE | -- STM32H7_SPI_IER_MODFIE); -+ STM32H7_SPI_IER_OVRIE); - - stm32_spi_enable(spi); - - stm32_spi_set_bits(spi, STM32H7_SPI_CR1, STM32H7_SPI_CR1_CSTART); -+ -+ spin_unlock_irqrestore(&spi->lock, flags); -+ -+ return 0; - } - - /** - * stm32_spi_transfer_one_dma - transfer a single spi_transfer using DMA - * @spi: pointer to the spi controller data structure - * @xfer: pointer to the spi_transfer structure -- * -- * It must returns 0 if the transfer is finished or 1 if the transfer is still -- * in progress. - */ - static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - struct spi_transfer *xfer) - { -+ dma_async_tx_callback rx_done = NULL, tx_done = NULL; - struct dma_slave_config tx_dma_conf, rx_dma_conf; - struct dma_async_tx_descriptor *tx_dma_desc, *rx_dma_desc; - unsigned long flags; - - spin_lock_irqsave(&spi->lock, flags); - -+ if (spi->rx_buf) -+ rx_done = spi->cfg->dma_rx_cb; -+ else if (spi->tx_buf) -+ tx_done = spi->cfg->dma_tx_cb; -+ -+ reinit_completion(&spi->dma_completion); -+ - rx_dma_desc = NULL; - if (spi->rx_buf && spi->dma_rx) { - stm32_spi_dma_config(spi, &rx_dma_conf, DMA_DEV_TO_MEM); -@@ -1329,7 +1331,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - goto dma_desc_error; - - if (rx_dma_desc) { -- rx_dma_desc->callback = spi->cfg->dma_rx_cb; -+ rx_dma_desc->callback = rx_done; - rx_dma_desc->callback_param = spi; - - if (dma_submit_error(dmaengine_submit(rx_dma_desc))) { -@@ -1343,7 +1345,7 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - if (tx_dma_desc) { - if (spi->cur_comm == SPI_SIMPLEX_TX || - spi->cur_comm == SPI_3WIRE_TX) { -- tx_dma_desc->callback = spi->cfg->dma_tx_cb; -+ tx_dma_desc->callback = tx_done; - tx_dma_desc->callback_param = spi; - } - -@@ -1358,12 +1360,9 @@ static int stm32_spi_transfer_one_dma(struct stm32_spi *spi, - stm32_spi_set_bits(spi, spi->cfg->regs->dma_tx_en.reg, - spi->cfg->regs->dma_tx_en.mask); - } -- -- spi->cfg->transfer_one_dma_start(spi); -- - spin_unlock_irqrestore(&spi->lock, flags); - -- return 1; -+ return spi->cfg->transfer_one_dma_start(spi); - - dma_submit_error: - if (spi->dma_rx) -@@ -1405,15 +1404,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) - bpw = spi->cur_bpw - 1; - - cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; -- cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & -- STM32H7_SPI_CFG1_DSIZE; -+ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_DSIZE, bpw); - - spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen); - fthlv = spi->cur_fthlv - 1; - - cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; -- cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & -- STM32H7_SPI_CFG1_FTHLV; -+ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_FTHLV, fthlv); - - writel_relaxed( - (readl_relaxed(spi->base + STM32H7_SPI_CFG1) & -@@ -1431,8 +1428,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) - u32 clrb = 0, setb = 0; - - clrb |= spi->cfg->regs->br.mask; -- setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) & -- spi->cfg->regs->br.mask; -+ setb |= (mbrdiv << spi->cfg->regs->br.shift) & spi->cfg->regs->br.mask; - - writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) & - ~clrb) | setb, -@@ -1523,8 +1519,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) - } - - cfg2_clrb |= STM32H7_SPI_CFG2_COMM; -- cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & -- STM32H7_SPI_CFG2_COMM; -+ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_COMM, mode); - - writel_relaxed( - (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & -@@ -1546,15 +1541,16 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) - - cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; - if ((len > 1) && (spi->cur_midi > 0)) { -- u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); -- u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), -- (u32)STM32H7_SPI_CFG2_MIDI >> -- STM32H7_SPI_CFG2_MIDI_SHIFT); -+ u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed); -+ u32 midi = min_t(u32, -+ DIV_ROUND_UP(spi->cur_midi, sck_period_ns), -+ FIELD_GET(STM32H7_SPI_CFG2_MIDI, -+ STM32H7_SPI_CFG2_MIDI)); -+ - - dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", - sck_period_ns, midi, midi * sck_period_ns); -- cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) & -- STM32H7_SPI_CFG2_MIDI; -+ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_MIDI, midi); - } - - writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & -@@ -1569,14 +1565,8 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) - */ - static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) - { -- u32 cr2_clrb = 0, cr2_setb = 0; -- -- if (nb_words <= (STM32H7_SPI_CR2_TSIZE >> -- STM32H7_SPI_CR2_TSIZE_SHIFT)) { -- cr2_clrb |= STM32H7_SPI_CR2_TSIZE; -- cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT; -- writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) & -- ~cr2_clrb) | cr2_setb, -+ if (nb_words <= STM32H7_SPI_TSIZE_MAX) { -+ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, nb_words), - spi->base + STM32H7_SPI_CR2); - } else { - return -EMSGSIZE; -@@ -1675,8 +1665,16 @@ static int stm32_spi_transfer_one(struct spi_master *master, - struct spi_transfer *transfer) - { - struct stm32_spi *spi = spi_master_get_devdata(master); -+ u32 xfer_time, midi_delay_ns; -+ unsigned long timeout; - int ret; - -+ /* Don't do anything on 0 bytes transfers */ -+ if (transfer->len == 0) { -+ spi->xfer_status = 0; -+ goto finalize; -+ } -+ - spi->tx_buf = transfer->tx_buf; - spi->rx_buf = transfer->rx_buf; - spi->tx_len = spi->tx_buf ? transfer->len : 0; -@@ -1691,10 +1689,40 @@ static int stm32_spi_transfer_one(struct spi_master *master, - return ret; - } - -+ reinit_completion(&spi->xfer_completion); -+ spi->xfer_status = 0; -+ - if (spi->cur_usedma) -- return stm32_spi_transfer_one_dma(spi, transfer); -+ ret = stm32_spi_transfer_one_dma(spi, transfer); - else -- return spi->cfg->transfer_one_irq(spi); -+ ret = spi->cfg->transfer_one_irq(spi); -+ -+ if (ret) -+ return ret; -+ -+ /* Wait for transfer to complete */ -+ xfer_time = spi->cur_xferlen * 8 * MSEC_PER_SEC / spi->cur_speed; -+ midi_delay_ns = spi->cur_xferlen * 8 / spi->cur_bpw * spi->cur_midi; -+ xfer_time += DIV_ROUND_UP(midi_delay_ns, NSEC_PER_MSEC); -+ xfer_time = max(2 * xfer_time, 100U); -+ timeout = msecs_to_jiffies(xfer_time); -+ -+ timeout = wait_for_completion_timeout(&spi->xfer_completion, timeout); -+ if (timeout && spi->cur_usedma) -+ timeout = wait_for_completion_timeout(&spi->dma_completion, -+ timeout); -+ -+ if (!timeout) { -+ dev_err(spi->dev, "SPI transfer timeout (%u ms)\n", xfer_time); -+ spi->xfer_status = -ETIMEDOUT; -+ } -+ -+ spi->cfg->disable(spi); -+ -+finalize: -+ spi_finalize_current_transfer(master); -+ -+ return spi->xfer_status; - } - - /** -@@ -1831,6 +1859,7 @@ static int stm32_spi_probe(struct platform_device *pdev) - struct spi_master *master; - struct stm32_spi *spi; - struct resource *res; -+ struct reset_control *rst; - int ret; - - master = spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); -@@ -1844,6 +1873,8 @@ static int stm32_spi_probe(struct platform_device *pdev) - spi->dev = &pdev->dev; - spi->master = master; - spin_lock_init(&spi->lock); -+ init_completion(&spi->xfer_completion); -+ init_completion(&spi->dma_completion); - - spi->cfg = (const struct stm32_spi_cfg *) - of_match_device(pdev->dev.driver->of_match_table, -@@ -1892,11 +1923,19 @@ static int stm32_spi_probe(struct platform_device *pdev) - goto err_clk_disable; - } - -- spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); -- if (!IS_ERR(spi->rst)) { -- reset_control_assert(spi->rst); -+ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); -+ if (rst) { -+ if (IS_ERR(rst)) { -+ ret = PTR_ERR(rst); -+ if (ret != -EPROBE_DEFER) -+ dev_err(&pdev->dev, "reset get failed: %d\n", -+ ret); -+ goto err_clk_disable; -+ } -+ -+ reset_control_assert(rst); - udelay(2); -- reset_control_deassert(spi->rst); -+ reset_control_deassert(rst); - } - - if (spi->cfg->has_fifo) -@@ -1953,19 +1992,13 @@ static int stm32_spi_probe(struct platform_device *pdev) - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); - -- ret = devm_spi_register_master(&pdev->dev, master); -+ ret = spi_register_master(master); - if (ret) { - dev_err(&pdev->dev, "spi master registration failed: %d\n", - ret); - goto err_pm_disable; - } - -- if (!master->cs_gpiods) { -- dev_err(&pdev->dev, "no CS gpios available\n"); -- ret = -EINVAL; -- goto err_pm_disable; -- } -- - dev_info(&pdev->dev, "driver initialized\n"); - - return 0; -@@ -1990,6 +2023,9 @@ static int stm32_spi_remove(struct platform_device *pdev) - struct spi_master *master = platform_get_drvdata(pdev); - struct stm32_spi *spi = spi_master_get_devdata(master); - -+ pm_runtime_get_sync(&pdev->dev); -+ -+ spi_unregister_master(master); - spi->cfg->disable(spi); - - if (master->dma_tx) -@@ -1999,7 +2035,10 @@ static int stm32_spi_remove(struct platform_device *pdev) - - clk_disable_unprepare(spi->clk); - -+ pm_runtime_put_noidle(&pdev->dev); - pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_dont_use_autosuspend(&pdev->dev); - - pinctrl_pm_select_sleep_state(&pdev->dev); - -diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h -index e6fb8ada3f4d..370a25a9366c 100644 ---- a/include/dt-bindings/pinctrl/stm32-pinfunc.h -+++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h -@@ -26,6 +26,7 @@ - #define AF14 0xf - #define AF15 0x10 - #define ANALOG 0x11 -+#define RSVD 0x12 - - /* define Pins number*/ - #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) --- -2.17.1 - diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0001-ARM-5.10.10-stm32mp1-r1-MACHINE.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch similarity index 71% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0001-ARM-5.10.10-stm32mp1-r1-MACHINE.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch index 083bb15..0da8c6c 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0001-ARM-5.10.10-stm32mp1-r1-MACHINE.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch @@ -1,16 +1,15 @@ -From ac8315bbe1279affc860703a9062143e9eab9fa0 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 08:54:31 +0100 -Subject: [PATCH 01/22] ARM 5.10.10-stm32mp1-r1 MACHINE +From 291e33f627836085d320628794cbc836a3241965 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:41 +0200 +Subject: [PATCH 01/23] ARM 5.10.61-stm32mp1-r2 MACHINE -Signed-off-by: Romuald JEANNE --- arch/arm/mach-stm32/Kconfig | 2 ++ arch/arm/mach-stm32/board-dt.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/arch/arm/mach-stm32/Kconfig b/arch/arm/mach-stm32/Kconfig -index 57699bd8f107..d1f79bc2ccda 100644 +index 57699bd8f..d1f79bc2c 100644 --- a/arch/arm/mach-stm32/Kconfig +++ b/arch/arm/mach-stm32/Kconfig @@ -46,6 +46,8 @@ if ARCH_MULTI_V7 @@ -23,7 +22,7 @@ index 57699bd8f107..d1f79bc2ccda 100644 endif # ARMv7-A diff --git a/arch/arm/mach-stm32/board-dt.c b/arch/arm/mach-stm32/board-dt.c -index 011d57b488c2..8e06a94421d9 100644 +index 011d57b48..8e06a9442 100644 --- a/arch/arm/mach-stm32/board-dt.c +++ b/arch/arm/mach-stm32/board-dt.c @@ -17,6 +17,8 @@ static const char *const stm32_compat[] __initconst = { diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0002-ARM-5.10.10-stm32mp1-r1-CLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch similarity index 95% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0002-ARM-5.10.10-stm32mp1-r1-CLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch index b1cc72e..4d723fb 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0002-ARM-5.10.10-stm32mp1-r1-CLOCK.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch @@ -1,18 +1,18 @@ -From f2f9b8ceceeb143fd478d89126a475d26b11f488 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 08:58:27 +0100 -Subject: [PATCH 02/22] ARM 5.10.10-stm32mp1-r1 CLOCK +From 449ee632a4a7c7e93107d3c1ea502974d4c206f5 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:41 +0200 +Subject: [PATCH 02/23] ARM 5.10.61-stm32mp1-r2 CLOCK --- drivers/clk/clk-composite.c | 15 + - drivers/clk/clk-stm32mp1.c | 1081 ++++++++++++++++----- + drivers/clk/clk-stm32mp1.c | 1153 ++++++++++++++++----- drivers/clk/clk.c | 7 +- drivers/clocksource/timer-stm32-lp.c | 4 +- include/dt-bindings/clock/stm32mp1-clks.h | 33 + - 5 files changed, 873 insertions(+), 267 deletions(-) + 5 files changed, 945 insertions(+), 267 deletions(-) diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c -index 2ddb54f7d3ab..b49ecd1b9e56 100644 +index 2ddb54f7d..b49ecd1b9 100644 --- a/drivers/clk/clk-composite.c +++ b/drivers/clk/clk-composite.c @@ -41,6 +41,18 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw, @@ -45,7 +45,7 @@ index 2ddb54f7d3ab..b49ecd1b9e56 100644 clk_composite_ops->determine_rate = clk_composite_determine_rate; diff --git a/drivers/clk/clk-stm32mp1.c b/drivers/clk/clk-stm32mp1.c -index a875649df8b8..bf927befe97b 100644 +index a875649df..ddaf7dc9b 100644 --- a/drivers/clk/clk-stm32mp1.c +++ b/drivers/clk/clk-stm32mp1.c @@ -5,15 +5,28 @@ @@ -270,12 +270,12 @@ index a875649df8b8..bf927befe97b 100644 + struct clk_mux *mux = to_clk_mux(mux_hw); + struct stm32_clk_mmux *clk_mmux = to_clk_mmux(mux); + int i = 0; -+ + +-#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) + for (i = 0; i < clk_mmux->mmux->nbr_clk; i++) + if (__clk_is_enabled(clk_mmux->mmux->hws[i]->clk)) + return false; - --#define to_pll(_hw) container_of(_hw, struct stm32_pll_obj, hw) ++ + return true; +} @@ -380,24 +380,24 @@ index a875649df8b8..bf927befe97b 100644 - u32 reg; - unsigned long flags = 0; + struct clk_hw *composite_hw = __clk_get_hw(hw->clk); -+ -+ clk_mmux_restore_parent(composite_hw); -+ mp1_mgate_clk_enable(hw); -+ -+ return 0; -+} - spin_lock_irqsave(clk_elem->lock, flags); -+static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) -+{ -+ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); ++ clk_mmux_restore_parent(composite_hw); ++ mp1_mgate_clk_enable(hw); - reg = readl_relaxed(clk_elem->reg); - reg &= ~PLL_ON; - writel_relaxed(reg, clk_elem->reg); -+ mp1_mgate_clk_disable(hw); ++ return 0; ++} ++ ++static void mp1_mgate_clk_disable_safe(struct clk_hw *hw) ++{ ++ struct clk_hw *composite_hw = __clk_get_hw(hw->clk); - spin_unlock_irqrestore(clk_elem->lock, flags); ++ mp1_mgate_clk_disable(hw); ++ + if (is_all_clk_on_switch_are_off(composite_hw)) + clk_mmux_set_safe_position(composite_hw); } @@ -524,10 +524,10 @@ index a875649df8b8..bf927befe97b 100644 - } + if (bit_status) + udelay(120); ++ ++ } while (bit_status && --timeout); - return rate + rate_frac; -+ } while (bit_status && --timeout); -+ + return bit_status; } @@ -1216,20 +1216,20 @@ index a875649df8b8..bf927befe97b 100644 unsigned int maxbinding; + bool (*check_security)(const struct clock_config *cfg); + u32 clear_offset; - }; - --static struct stm32_clock_match_data stm32mp1_data = { -+static struct stm32_rcc_match_data stm32mp1_data = { - .cfg = stm32mp1_clock_cfg, - .num = ARRAY_SIZE(stm32mp1_clock_cfg), - .maxbinding = STM32MP1_LAST_CLK, -+ .clear_offset = RCC_CLR, +}; + -+static struct stm32_rcc_match_data stm32mp1_data_secure = { ++static struct stm32_rcc_match_data stm32mp1_data = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, ++ .clear_offset = RCC_CLR, + }; + +-static struct stm32_clock_match_data stm32mp1_data = { ++static struct stm32_rcc_match_data stm32mp1_data_secure = { + .cfg = stm32mp1_clock_cfg, + .num = ARRAY_SIZE(stm32mp1_clock_cfg), + .maxbinding = STM32MP1_LAST_CLK, + .check_security = &stm32_check_security, + .clear_offset = RCC_CLR, }; @@ -1249,7 +1249,7 @@ index a875649df8b8..bf927befe97b 100644 static int stm32_register_hw_clk(struct device *dev, struct clk_hw_onecell_data *clk_data, -@@ -2040,28 +2317,126 @@ static int stm32_register_hw_clk(struct device *dev, +@@ -2040,28 +2317,195 @@ static int stm32_register_hw_clk(struct device *dev, return 0; } @@ -1373,6 +1373,75 @@ index a875649df8b8..bf927befe97b 100644 + return reset_controller_register(&reset_data->rcdev); +} + ++static struct stm32_clk_boot_on { ++ struct clk **clks; ++ int nb; ++} *clk_boot_on; ++ ++static struct stm32_clk_boot_on *clk_boot_on; ++ ++static int stm32_clk_boot_on_enable(struct device_node *np, ++ struct clk_hw_onecell_data *clk_data) ++{ ++ struct of_phandle_args clkspec; ++ struct property *prop; ++ const __be32 *cur; ++ struct clk **clks; ++ int nb, count = 0; ++ ++ nb = of_property_count_u32_elems(np, "clocks-boot-on"); ++ if (!nb) ++ return 0; ++ ++ clks = kcalloc(nb, sizeof(struct clk_bulk_data *), GFP_KERNEL); ++ if (!clks) ++ return -ENOMEM; ++ ++ clk_boot_on = kzalloc(sizeof(*clk_boot_on), GFP_KERNEL); ++ if (!clk_boot_on) { ++ kfree(clks); ++ return -ENOMEM; ++ } ++ ++ of_property_for_each_u32(np, "clocks-boot-on", prop, cur, ++ clkspec.args[0]) { ++ struct clk_hw *hw; ++ ++ hw = of_clk_hw_onecell_get(&clkspec, clk_data); ++ if (IS_ERR(hw)) ++ continue; ++ ++ if (clk_prepare_enable(hw->clk)) { ++ pr_warn("can't enable clock %s !\n", ++ clk_hw_get_name(hw)); ++ continue; ++ } ++ ++ clks[count++] = hw->clk; ++ } ++ ++ clk_boot_on->clks = clks; ++ clk_boot_on->nb = count; ++ ++ return 0; ++} ++ ++static int stm32_clk_boot_on_disable(void) ++{ ++ int i; ++ ++ if (clk_boot_on) { ++ for (i = 0; i < clk_boot_on->nb; i++) ++ clk_disable_unprepare(clk_boot_on->clks[i]); ++ ++ kfree(clk_boot_on->clks); ++ kfree(clk_boot_on); ++ } ++ ++ return 0; ++} ++late_initcall_sync(stm32_clk_boot_on_disable); ++ +static int stm32_rcc_clock_init(struct device *dev, void __iomem *base, + const struct of_device_id *match) +{ @@ -1390,7 +1459,7 @@ index a875649df8b8..bf927befe97b 100644 if (!clk_data) return -ENOMEM; -@@ -2073,36 +2448,218 @@ static int stm32_rcc_init(struct device_node *np, +@@ -2073,36 +2517,221 @@ static int stm32_rcc_init(struct device_node *np, hws[n] = ERR_PTR(-ENOENT); for (n = 0; n < data->num; n++) { @@ -1413,8 +1482,11 @@ index a875649df8b8..bf927befe97b 100644 } - return of_clk_add_hw_provider(np, of_clk_hw_onecell_get, clk_data); -+ return of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, -+ clk_data); ++ err = of_clk_add_hw_provider(dev_of_node(dev), of_clk_hw_onecell_get, clk_data); ++ if (!err) ++ stm32_clk_boot_on_enable(dev_of_node(dev), clk_data); ++ ++ return err; } -static void stm32mp1_rcc_init(struct device_node *np) @@ -1441,11 +1513,8 @@ index a875649df8b8..bf927befe97b 100644 + if (err) { + pr_err("stm32mp1 reset failed to initialize\n"); + return err; - } - -- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { -- iounmap(base); -- of_node_put(np); ++ } ++ + /* RCC Clock Configuration */ + err = stm32_rcc_clock_init(dev, base, match); + if (err) { @@ -1467,7 +1536,7 @@ index a875649df8b8..bf927befe97b 100644 + if (!rcc_base) { + dev_err(dev, "%pOFn: unable to map resource", dev_of_node(dev)); + goto out; - } ++ } + + ret = stm32_rcc_init(dev, rcc_base, stm32mp1_match_data); + if (ret) @@ -1530,9 +1599,8 @@ index a875649df8b8..bf927befe97b 100644 + SMC(STM32_SVC_RCC, STM32_WRITE, RCC_CIFR, RCC_IRQ_FLAGS_MASK); + + return IRQ_HANDLED; - } - --CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); ++} ++ +static int stm32_rcc_init_pwr(struct device *dev, void __iomem *rcc_base) +{ + int irq; @@ -1544,8 +1612,11 @@ index a875649df8b8..bf927befe97b 100644 + if (irq <= 0) { + pr_err("%s: failed to get RCC generic IRQ\n", __func__); + return irq ? irq : -ENXIO; -+ } -+ + } + +- if (stm32_rcc_init(np, base, stm32mp1_match_data)) { +- iounmap(base); +- of_node_put(np); + ret = devm_request_irq(dev, irq, stm32mp1_rcc_irq_handler, IRQF_ONESHOT, + "rcc irq", NULL); + if (ret) { @@ -1585,11 +1656,12 @@ index a875649df8b8..bf927befe97b 100644 + clk_deps[i] = devm_clk_get(dev, __clk_get_name(clk)); + clk_put(clk); + } -+ } + } + + return 0; -+} -+ + } + +-CLK_OF_DECLARE_DRIVER(stm32mp1_rcc, "st,stm32mp1-rcc", stm32mp1_rcc_init); +static int stm32mp1_rcc_clocks_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; @@ -1627,7 +1699,7 @@ index a875649df8b8..bf927befe97b 100644 +} +core_initcall(stm32mp1_clocks_init); diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c -index f83dac54ed85..6939ea978868 100644 +index 61c78714c..9b9a17695 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -1743,6 +1743,7 @@ static void clk_reparent(struct clk_core *core, struct clk_core *new_parent) @@ -1659,7 +1731,7 @@ index f83dac54ed85..6939ea978868 100644 } diff --git a/drivers/clocksource/timer-stm32-lp.c b/drivers/clocksource/timer-stm32-lp.c -index db2841d0beb8..90c10f378df2 100644 +index db2841d0b..90c10f378 100644 --- a/drivers/clocksource/timer-stm32-lp.c +++ b/drivers/clocksource/timer-stm32-lp.c @@ -168,9 +168,7 @@ static int stm32_clkevent_lp_probe(struct platform_device *pdev) @@ -1674,7 +1746,7 @@ index db2841d0beb8..90c10f378df2 100644 ret = dev_pm_set_wake_irq(&pdev->dev, irq); if (ret) diff --git a/include/dt-bindings/clock/stm32mp1-clks.h b/include/dt-bindings/clock/stm32mp1-clks.h -index 4cdaf135829c..ec7b1a93200f 100644 +index 4cdaf1358..ec7b1a932 100644 --- a/include/dt-bindings/clock/stm32mp1-clks.h +++ b/include/dt-bindings/clock/stm32mp1-clks.h @@ -179,6 +179,12 @@ diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0003-ARM-5.10.10-stm32mp1-r1-CPUFREQ.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch similarity index 91% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0003-ARM-5.10.10-stm32mp1-r1-CPUFREQ.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch index e697216..ddbe24d 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0003-ARM-5.10.10-stm32mp1-r1-CPUFREQ.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch @@ -1,7 +1,7 @@ -From 147c507542ee7feb5bd85212669eeaec2c0420b1 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 08:56:21 +0100 -Subject: [PATCH 03/22] ARM 5.10.10-stm32mp1-r1 CPUFREQ +From f425522a8000b8fe201de2db79367a1a7e7b7fdb Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:41 +0200 +Subject: [PATCH 03/23] ARM 5.10.61-stm32mp1-r2 CPUFREQ --- drivers/cpufreq/Kconfig.arm | 7 ++ @@ -12,7 +12,7 @@ Subject: [PATCH 03/22] ARM 5.10.10-stm32mp1-r1 CPUFREQ create mode 100644 drivers/cpufreq/stm32-cpufreq.c diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm -index 1f73fa75b1a0..56b210670b50 100644 +index 1f73fa75b..56b210670 100644 --- a/drivers/cpufreq/Kconfig.arm +++ b/drivers/cpufreq/Kconfig.arm @@ -289,6 +289,13 @@ config ARM_STI_CPUFREQ @@ -30,7 +30,7 @@ index 1f73fa75b1a0..56b210670b50 100644 bool depends on CPUFREQ_DT && ARCH_TANGO diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile -index f1b7e3dd6e5d..b373f97f26a2 100644 +index f1b7e3dd6..b373f97f2 100644 --- a/drivers/cpufreq/Makefile +++ b/drivers/cpufreq/Makefile @@ -78,6 +78,7 @@ obj-$(CONFIG_ARM_SCMI_CPUFREQ) += scmi-cpufreq.o @@ -42,10 +42,10 @@ index f1b7e3dd6e5d..b373f97f26a2 100644 obj-$(CONFIG_ARM_TANGO_CPUFREQ) += tango-cpufreq.o obj-$(CONFIG_ARM_TEGRA20_CPUFREQ) += tegra20-cpufreq.o diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c -index 3776d960f405..86fcbb6fa5b8 100644 +index 1c192a42f..4d72dbb3a 100644 --- a/drivers/cpufreq/cpufreq-dt-platdev.c +++ b/drivers/cpufreq/cpufreq-dt-platdev.c -@@ -138,6 +138,9 @@ static const struct of_device_id blacklist[] __initconst = { +@@ -140,6 +140,9 @@ static const struct of_device_id blacklist[] __initconst = { { .compatible = "st,stih407", }, { .compatible = "st,stih410", }, { .compatible = "st,stih418", }, @@ -57,7 +57,7 @@ index 3776d960f405..86fcbb6fa5b8 100644 diff --git a/drivers/cpufreq/stm32-cpufreq.c b/drivers/cpufreq/stm32-cpufreq.c new file mode 100644 -index 000000000000..35fb3520d48d +index 000000000..35fb3520d --- /dev/null +++ b/drivers/cpufreq/stm32-cpufreq.c @@ -0,0 +1,101 @@ diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch new file mode 100644 index 0000000..6fcd755 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch @@ -0,0 +1,1596 @@ +From 06c6f8f73cdc2be580cb20926507696234053bfc Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:42 +0200 +Subject: [PATCH 04/23] ARM 5.10.61-stm32mp1-r2 CRYPTO + +--- + drivers/crypto/stm32/stm32-cryp.c | 993 +++++++++++++----------------- + drivers/crypto/stm32/stm32-hash.c | 19 +- + 2 files changed, 429 insertions(+), 583 deletions(-) + +diff --git a/drivers/crypto/stm32/stm32-cryp.c b/drivers/crypto/stm32/stm32-cryp.c +index 7999b26a1..361b99e9c 100644 +--- a/drivers/crypto/stm32/stm32-cryp.c ++++ b/drivers/crypto/stm32/stm32-cryp.c +@@ -37,7 +37,6 @@ + /* Mode mask = bits [15..0] */ + #define FLG_MODE_MASK GENMASK(15, 0) + /* Bit [31..16] status */ +-#define FLG_CCM_PADDED_WA BIT(16) + + /* Registers */ + #define CRYP_CR 0x00000000 +@@ -105,8 +104,6 @@ + /* Misc */ + #define AES_BLOCK_32 (AES_BLOCK_SIZE / sizeof(u32)) + #define GCM_CTR_INIT 2 +-#define _walked_in (cryp->in_walk.offset - cryp->in_sg->offset) +-#define _walked_out (cryp->out_walk.offset - cryp->out_sg->offset) + #define CRYP_AUTOSUSPEND_DELAY 50 + + struct stm32_cryp_caps { +@@ -144,26 +141,16 @@ struct stm32_cryp { + size_t authsize; + size_t hw_blocksize; + +- size_t total_in; +- size_t total_in_save; +- size_t total_out; +- size_t total_out_save; ++ size_t payload_in; ++ size_t header_in; ++ size_t payload_out; + +- struct scatterlist *in_sg; + struct scatterlist *out_sg; +- struct scatterlist *out_sg_save; +- +- struct scatterlist in_sgl; +- struct scatterlist out_sgl; +- bool sgs_copied; +- +- int in_sg_len; +- int out_sg_len; + + struct scatter_walk in_walk; + struct scatter_walk out_walk; + +- u32 last_ctr[4]; ++ __be32 last_ctr[4]; + u32 gcm_ctr; + }; + +@@ -245,6 +232,11 @@ static inline int stm32_cryp_wait_busy(struct stm32_cryp *cryp) + !(status & SR_BUSY), 10, 100000); + } + ++static inline void stm32_cryp_enable(struct stm32_cryp *cryp) ++{ ++ writel_relaxed(readl_relaxed(cryp->regs + CRYP_CR) | CR_CRYPEN, cryp->regs + CRYP_CR); ++} ++ + static inline int stm32_cryp_wait_enable(struct stm32_cryp *cryp) + { + u32 status; +@@ -262,6 +254,7 @@ static inline int stm32_cryp_wait_output(struct stm32_cryp *cryp) + } + + static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp); ++static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err); + + static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx) + { +@@ -283,103 +276,6 @@ static struct stm32_cryp *stm32_cryp_find_dev(struct stm32_cryp_ctx *ctx) + return cryp; + } + +-static int stm32_cryp_check_aligned(struct scatterlist *sg, size_t total, +- size_t align) +-{ +- int len = 0; +- +- if (!total) +- return 0; +- +- if (!IS_ALIGNED(total, align)) +- return -EINVAL; +- +- while (sg) { +- if (!IS_ALIGNED(sg->offset, sizeof(u32))) +- return -EINVAL; +- +- if (!IS_ALIGNED(sg->length, align)) +- return -EINVAL; +- +- len += sg->length; +- sg = sg_next(sg); +- } +- +- if (len != total) +- return -EINVAL; +- +- return 0; +-} +- +-static int stm32_cryp_check_io_aligned(struct stm32_cryp *cryp) +-{ +- int ret; +- +- ret = stm32_cryp_check_aligned(cryp->in_sg, cryp->total_in, +- cryp->hw_blocksize); +- if (ret) +- return ret; +- +- ret = stm32_cryp_check_aligned(cryp->out_sg, cryp->total_out, +- cryp->hw_blocksize); +- +- return ret; +-} +- +-static void sg_copy_buf(void *buf, struct scatterlist *sg, +- unsigned int start, unsigned int nbytes, int out) +-{ +- struct scatter_walk walk; +- +- if (!nbytes) +- return; +- +- scatterwalk_start(&walk, sg); +- scatterwalk_advance(&walk, start); +- scatterwalk_copychunks(buf, &walk, nbytes, out); +- scatterwalk_done(&walk, out, 0); +-} +- +-static int stm32_cryp_copy_sgs(struct stm32_cryp *cryp) +-{ +- void *buf_in, *buf_out; +- int pages, total_in, total_out; +- +- if (!stm32_cryp_check_io_aligned(cryp)) { +- cryp->sgs_copied = 0; +- return 0; +- } +- +- total_in = ALIGN(cryp->total_in, cryp->hw_blocksize); +- pages = total_in ? get_order(total_in) : 1; +- buf_in = (void *)__get_free_pages(GFP_ATOMIC, pages); +- +- total_out = ALIGN(cryp->total_out, cryp->hw_blocksize); +- pages = total_out ? get_order(total_out) : 1; +- buf_out = (void *)__get_free_pages(GFP_ATOMIC, pages); +- +- if (!buf_in || !buf_out) { +- dev_err(cryp->dev, "Can't allocate pages when unaligned\n"); +- cryp->sgs_copied = 0; +- return -EFAULT; +- } +- +- sg_copy_buf(buf_in, cryp->in_sg, 0, cryp->total_in, 0); +- +- sg_init_one(&cryp->in_sgl, buf_in, total_in); +- cryp->in_sg = &cryp->in_sgl; +- cryp->in_sg_len = 1; +- +- sg_init_one(&cryp->out_sgl, buf_out, total_out); +- cryp->out_sg_save = cryp->out_sg; +- cryp->out_sg = &cryp->out_sgl; +- cryp->out_sg_len = 1; +- +- cryp->sgs_copied = 1; +- +- return 0; +-} +- + static void stm32_cryp_hw_write_iv(struct stm32_cryp *cryp, __be32 *iv) + { + if (!iv) +@@ -481,16 +377,100 @@ static int stm32_cryp_gcm_init(struct stm32_cryp *cryp, u32 cfg) + + /* Wait for end of processing */ + ret = stm32_cryp_wait_enable(cryp); +- if (ret) ++ if (ret) { + dev_err(cryp->dev, "Timeout (gcm init)\n"); ++ return ret; ++ } + +- return ret; ++ /* Prepare next phase */ ++ if (cryp->areq->assoclen) { ++ cfg |= CR_PH_HEADER; ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ } else if (stm32_cryp_get_input_text_len(cryp)) { ++ cfg |= CR_PH_PAYLOAD; ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ } ++ ++ return 0; ++} ++ ++static void stm32_crypt_gcmccm_end_header(struct stm32_cryp *cryp) ++{ ++ u32 cfg; ++ int err; ++ ++ /* Check if whole header written */ ++ if (!cryp->header_in) { ++ /* Wait for completion */ ++ err = stm32_cryp_wait_busy(cryp); ++ if (err) { ++ dev_err(cryp->dev, "Timeout (gcm/ccm header)\n"); ++ stm32_cryp_write(cryp, CRYP_IMSCR, 0); ++ stm32_cryp_finish_req(cryp, err); ++ return; ++ } ++ ++ if (stm32_cryp_get_input_text_len(cryp)) { ++ /* Phase 3 : payload */ ++ cfg = stm32_cryp_read(cryp, CRYP_CR); ++ cfg &= ~CR_CRYPEN; ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ ++ cfg &= ~CR_PH_MASK; ++ cfg |= CR_PH_PAYLOAD | CR_CRYPEN; ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ } else { ++ /* ++ * Phase 4 : tag. ++ * Nothing to read, nothing to write, caller have to ++ * end request ++ */ ++ } ++ } + } + ++static void stm32_cryp_write_ccm_first_header(struct stm32_cryp *cryp) ++{ ++ unsigned int i; ++ size_t written; ++ size_t len; ++ u32 alen = cryp->areq->assoclen; ++ u32 block[AES_BLOCK_32] = {0}; ++ u8 *b8 = (u8 *)block; ++ ++ if (alen <= 65280) { ++ /* Write first u32 of B1 */ ++ b8[0] = (alen >> 8) & 0xFF; ++ b8[1] = alen & 0xFF; ++ len = 2; ++ } else { ++ /* Build the two first u32 of B1 */ ++ b8[0] = 0xFF; ++ b8[1] = 0xFE; ++ b8[2] = alen & 0xFF000000; ++ b8[3] = alen & 0x00FF0000; ++ b8[4] = alen & 0x0000FF00; ++ b8[5] = alen & 0x000000FF; ++ len = 6; ++ } ++ ++ written = min_t(size_t, AES_BLOCK_SIZE - len, alen); ++ ++ scatterwalk_copychunks((char *)block + len, &cryp->in_walk, written, 0); ++ for (i = 0; i < AES_BLOCK_32; i++) ++ stm32_cryp_write(cryp, CRYP_DIN, block[i]); ++ ++ cryp->header_in -= written; ++ ++ stm32_crypt_gcmccm_end_header(cryp); ++} ++ ++ + static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg) + { + int ret; +- u8 iv[AES_BLOCK_SIZE], b0[AES_BLOCK_SIZE]; ++ u32 iv_32[AES_BLOCK_32], b0_32[AES_BLOCK_32]; ++ u8 *iv = (u8 *)iv_32, *b0 = (u8 *)b0_32; + __be32 *bd; + u32 *d; + unsigned int i, textlen; +@@ -531,25 +511,35 @@ static int stm32_cryp_ccm_init(struct stm32_cryp *cryp, u32 cfg) + + /* Wait for end of processing */ + ret = stm32_cryp_wait_enable(cryp); +- if (ret) ++ if (ret) { + dev_err(cryp->dev, "Timeout (ccm init)\n"); ++ return ret; ++ } + +- return ret; ++ /* Prepare next phase */ ++ if (cryp->areq->assoclen) { ++ cfg |= CR_PH_HEADER | CR_CRYPEN; ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ ++ /* Write first (special) block (may move to next phase [payload]) */ ++ stm32_cryp_write_ccm_first_header(cryp); ++ } else if (stm32_cryp_get_input_text_len(cryp)) { ++ cfg |= CR_PH_PAYLOAD; ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ } ++ ++ return 0; + } + + static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + { + int ret; + u32 cfg, hw_mode; +- + pm_runtime_resume_and_get(cryp->dev); + + /* Disable interrupt */ + stm32_cryp_write(cryp, CRYP_IMSCR, 0); + +- /* Set key */ +- stm32_cryp_hw_write_key(cryp); +- + /* Set configuration */ + cfg = CR_DATA8 | CR_FFLUSH; + +@@ -575,23 +565,36 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + /* AES ECB/CBC decrypt: run key preparation first */ + if (is_decrypt(cryp) && + ((hw_mode == CR_AES_ECB) || (hw_mode == CR_AES_CBC))) { +- stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP | CR_CRYPEN); ++ /* Configure in key preparation mode */ ++ stm32_cryp_write(cryp, CRYP_CR, cfg | CR_AES_KP); ++ ++ /* Set key only after full configuration done */ ++ stm32_cryp_hw_write_key(cryp); + ++ /* Start prepare key */ ++ stm32_cryp_enable(cryp); + /* Wait for end of processing */ + ret = stm32_cryp_wait_busy(cryp); + if (ret) { + dev_err(cryp->dev, "Timeout (key preparation)\n"); + return ret; + } +- } + +- cfg |= hw_mode; ++ cfg |= hw_mode | CR_DEC_NOT_ENC; ++ ++ /* Apply updated config (Decrypt + algo) and flush */ ++ stm32_cryp_write(cryp, CRYP_CR, cfg); ++ } else { ++ cfg |= hw_mode; ++ if (is_decrypt(cryp)) ++ cfg |= CR_DEC_NOT_ENC; + +- if (is_decrypt(cryp)) +- cfg |= CR_DEC_NOT_ENC; ++ /* Apply config and flush */ ++ stm32_cryp_write(cryp, CRYP_CR, cfg); + +- /* Apply config and flush (valid when CRYPEN = 0) */ +- stm32_cryp_write(cryp, CRYP_CR, cfg); ++ /* Set key only after configuration done */ ++ stm32_cryp_hw_write_key(cryp); ++ } + + switch (hw_mode) { + case CR_AES_GCM: +@@ -605,16 +608,6 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + if (ret) + return ret; + +- /* Phase 2 : header (authenticated data) */ +- if (cryp->areq->assoclen) { +- cfg |= CR_PH_HEADER; +- } else if (stm32_cryp_get_input_text_len(cryp)) { +- cfg |= CR_PH_PAYLOAD; +- stm32_cryp_write(cryp, CRYP_CR, cfg); +- } else { +- cfg |= CR_PH_INIT; +- } +- + break; + + case CR_DES_CBC: +@@ -629,11 +622,7 @@ static int stm32_cryp_hw_init(struct stm32_cryp *cryp) + } + + /* Enable now */ +- cfg |= CR_CRYPEN; +- +- stm32_cryp_write(cryp, CRYP_CR, cfg); +- +- cryp->flags &= ~FLG_CCM_PADDED_WA; ++ stm32_cryp_enable(cryp); + + return 0; + } +@@ -647,24 +636,7 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) + if (!err && (!(is_gcm(cryp) || is_ccm(cryp)))) + stm32_cryp_get_iv(cryp); + +- if (cryp->sgs_copied) { +- void *buf_in, *buf_out; +- int pages, len; +- +- buf_in = sg_virt(&cryp->in_sgl); +- buf_out = sg_virt(&cryp->out_sgl); +- +- sg_copy_buf(buf_out, cryp->out_sg_save, 0, +- cryp->total_out_save, 1); +- +- len = ALIGN(cryp->total_in_save, cryp->hw_blocksize); +- pages = len ? get_order(len) : 1; +- free_pages((unsigned long)buf_in, pages); +- +- len = ALIGN(cryp->total_out_save, cryp->hw_blocksize); +- pages = len ? get_order(len) : 1; +- free_pages((unsigned long)buf_out, pages); +- } ++ memset(cryp->ctx->key, 0, sizeof(cryp->ctx->key)); + + pm_runtime_mark_last_busy(cryp->dev); + pm_runtime_put_autosuspend(cryp->dev); +@@ -674,8 +646,6 @@ static void stm32_cryp_finish_req(struct stm32_cryp *cryp, int err) + else + crypto_finalize_skcipher_request(cryp->engine, cryp->req, + err); +- +- memset(cryp->ctx->key, 0, cryp->ctx->keylen); + } + + static int stm32_cryp_cpu_start(struct stm32_cryp *cryp) +@@ -801,7 +771,20 @@ static int stm32_cryp_aes_aead_setkey(struct crypto_aead *tfm, const u8 *key, + static int stm32_cryp_aes_gcm_setauthsize(struct crypto_aead *tfm, + unsigned int authsize) + { +- return authsize == AES_BLOCK_SIZE ? 0 : -EINVAL; ++ switch (authsize) { ++ case 4: ++ case 8: ++ case 12: ++ case 13: ++ case 14: ++ case 15: ++ case 16: ++ break; ++ default: ++ return -EINVAL; ++ } ++ ++ return 0; + } + + static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, +@@ -825,31 +808,61 @@ static int stm32_cryp_aes_ccm_setauthsize(struct crypto_aead *tfm, + + static int stm32_cryp_aes_ecb_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_ECB | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_ecb_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_ECB); + } + + static int stm32_cryp_aes_cbc_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CBC | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_cbc_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % AES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CBC); + } + + static int stm32_cryp_aes_ctr_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CTR | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_ctr_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_AES | FLG_CTR); + } + +@@ -863,53 +876,122 @@ static int stm32_cryp_aes_gcm_decrypt(struct aead_request *req) + return stm32_cryp_aead_crypt(req, FLG_AES | FLG_GCM); + } + ++static inline int crypto_ccm_check_iv(const u8 *iv) ++{ ++ /* 2 <= L <= 8, so 1 <= L' <= 7. */ ++ if (iv[0] < 1 || iv[0] > 7) ++ return -EINVAL; ++ ++ return 0; ++} ++ + static int stm32_cryp_aes_ccm_encrypt(struct aead_request *req) + { ++ int err; ++ ++ err = crypto_ccm_check_iv(req->iv); ++ if (err) ++ return err; ++ + return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM | FLG_ENCRYPT); + } + + static int stm32_cryp_aes_ccm_decrypt(struct aead_request *req) + { ++ int err; ++ ++ err = crypto_ccm_check_iv(req->iv); ++ if (err) ++ return err; ++ + return stm32_cryp_aead_crypt(req, FLG_AES | FLG_CCM); + } + + static int stm32_cryp_des_ecb_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_ECB | FLG_ENCRYPT); + } + + static int stm32_cryp_des_ecb_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_ECB); + } + + static int stm32_cryp_des_cbc_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_CBC | FLG_ENCRYPT); + } + + static int stm32_cryp_des_cbc_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_DES | FLG_CBC); + } + + static int stm32_cryp_tdes_ecb_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB | FLG_ENCRYPT); + } + + static int stm32_cryp_tdes_ecb_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_ECB); + } + + static int stm32_cryp_tdes_cbc_encrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC | FLG_ENCRYPT); + } + + static int stm32_cryp_tdes_cbc_decrypt(struct skcipher_request *req) + { ++ if (req->cryptlen % DES_BLOCK_SIZE) ++ return -EINVAL; ++ ++ if (req->cryptlen == 0) ++ return 0; ++ + return stm32_cryp_crypt(req, FLG_TDES | FLG_CBC); + } + +@@ -919,6 +1001,7 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req, + struct stm32_cryp_ctx *ctx; + struct stm32_cryp *cryp; + struct stm32_cryp_reqctx *rctx; ++ struct scatterlist *in_sg; + int ret; + + if (!req && !areq) +@@ -944,76 +1027,57 @@ static int stm32_cryp_prepare_req(struct skcipher_request *req, + if (req) { + cryp->req = req; + cryp->areq = NULL; +- cryp->total_in = req->cryptlen; +- cryp->total_out = cryp->total_in; ++ cryp->header_in = 0; ++ cryp->payload_in = req->cryptlen; ++ cryp->payload_out = req->cryptlen; ++ cryp->authsize = 0; + } else { + /* + * Length of input and output data: + * Encryption case: +- * INPUT = AssocData || PlainText ++ * INPUT = AssocData || PlainText + * <- assoclen -> <- cryptlen -> +- * <------- total_in -----------> + * +- * OUTPUT = AssocData || CipherText || AuthTag +- * <- assoclen -> <- cryptlen -> <- authsize -> +- * <---------------- total_out -----------------> ++ * OUTPUT = AssocData || CipherText || AuthTag ++ * <- assoclen -> <-- cryptlen --> <- authsize -> + * + * Decryption case: +- * INPUT = AssocData || CipherText || AuthTag +- * <- assoclen -> <--------- cryptlen ---------> +- * <- authsize -> +- * <---------------- total_in ------------------> ++ * INPUT = AssocData || CipherTex || AuthTag ++ * <- assoclen ---> <---------- cryptlen ----------> + * +- * OUTPUT = AssocData || PlainText +- * <- assoclen -> <- crypten - authsize -> +- * <---------- total_out -----------------> ++ * OUTPUT = AssocData || PlainText ++ * <- assoclen -> <- cryptlen - authsize -> + */ + cryp->areq = areq; + cryp->req = NULL; + cryp->authsize = crypto_aead_authsize(crypto_aead_reqtfm(areq)); +- cryp->total_in = areq->assoclen + areq->cryptlen; +- if (is_encrypt(cryp)) +- /* Append auth tag to output */ +- cryp->total_out = cryp->total_in + cryp->authsize; +- else +- /* No auth tag in output */ +- cryp->total_out = cryp->total_in - cryp->authsize; +- } +- +- cryp->total_in_save = cryp->total_in; +- cryp->total_out_save = cryp->total_out; +- +- cryp->in_sg = req ? req->src : areq->src; +- cryp->out_sg = req ? req->dst : areq->dst; +- cryp->out_sg_save = cryp->out_sg; +- +- cryp->in_sg_len = sg_nents_for_len(cryp->in_sg, cryp->total_in); +- if (cryp->in_sg_len < 0) { +- dev_err(cryp->dev, "Cannot get in_sg_len\n"); +- ret = cryp->in_sg_len; +- return ret; ++ if (is_encrypt(cryp)) { ++ cryp->payload_in = areq->cryptlen; ++ cryp->header_in = areq->assoclen; ++ cryp->payload_out = areq->cryptlen; ++ } else { ++ cryp->payload_in = areq->cryptlen - cryp->authsize; ++ cryp->header_in = areq->assoclen; ++ cryp->payload_out = cryp->payload_in; ++ } + } + +- cryp->out_sg_len = sg_nents_for_len(cryp->out_sg, cryp->total_out); +- if (cryp->out_sg_len < 0) { +- dev_err(cryp->dev, "Cannot get out_sg_len\n"); +- ret = cryp->out_sg_len; +- return ret; +- } + +- ret = stm32_cryp_copy_sgs(cryp); +- if (ret) +- return ret; ++ in_sg = req ? req->src : areq->src; ++ scatterwalk_start(&cryp->in_walk, in_sg); + +- scatterwalk_start(&cryp->in_walk, cryp->in_sg); ++ cryp->out_sg = req ? req->dst : areq->dst; + scatterwalk_start(&cryp->out_walk, cryp->out_sg); + + if (is_gcm(cryp) || is_ccm(cryp)) { + /* In output, jump after assoc data */ +- scatterwalk_advance(&cryp->out_walk, cryp->areq->assoclen); +- cryp->total_out -= cryp->areq->assoclen; ++ scatterwalk_copychunks(NULL, &cryp->out_walk, ++ cryp->areq->assoclen, 2); + } + ++ if (is_ctr(cryp)) ++ memset(cryp->last_ctr, 0, sizeof(cryp->last_ctr)); ++ + ret = stm32_cryp_hw_init(cryp); + return ret; + } +@@ -1061,8 +1125,7 @@ static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq) + if (!cryp) + return -ENODEV; + +- if (unlikely(!cryp->areq->assoclen && +- !stm32_cryp_get_input_text_len(cryp))) { ++ if (unlikely(!cryp->payload_in && !cryp->header_in)) { + /* No input data to process: get tag and finish */ + stm32_cryp_finish_req(cryp, 0); + return 0; +@@ -1071,43 +1134,10 @@ static int stm32_cryp_aead_one_req(struct crypto_engine *engine, void *areq) + return stm32_cryp_cpu_start(cryp); + } + +-static u32 *stm32_cryp_next_out(struct stm32_cryp *cryp, u32 *dst, +- unsigned int n) +-{ +- scatterwalk_advance(&cryp->out_walk, n); +- +- if (unlikely(cryp->out_sg->length == _walked_out)) { +- cryp->out_sg = sg_next(cryp->out_sg); +- if (cryp->out_sg) { +- scatterwalk_start(&cryp->out_walk, cryp->out_sg); +- return (sg_virt(cryp->out_sg) + _walked_out); +- } +- } +- +- return (u32 *)((u8 *)dst + n); +-} +- +-static u32 *stm32_cryp_next_in(struct stm32_cryp *cryp, u32 *src, +- unsigned int n) +-{ +- scatterwalk_advance(&cryp->in_walk, n); +- +- if (unlikely(cryp->in_sg->length == _walked_in)) { +- cryp->in_sg = sg_next(cryp->in_sg); +- if (cryp->in_sg) { +- scatterwalk_start(&cryp->in_walk, cryp->in_sg); +- return (sg_virt(cryp->in_sg) + _walked_in); +- } +- } +- +- return (u32 *)((u8 *)src + n); +-} +- + static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + { +- u32 cfg, size_bit, *dst, d32; +- u8 *d8; +- unsigned int i, j; ++ u32 cfg, size_bit; ++ unsigned int i; + int ret = 0; + + /* Update Config */ +@@ -1130,7 +1160,7 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_DIN, size_bit); + + size_bit = is_encrypt(cryp) ? cryp->areq->cryptlen : +- cryp->areq->cryptlen - AES_BLOCK_SIZE; ++ cryp->areq->cryptlen - cryp->authsize; + size_bit *= 8; + if (cryp->caps->swap_final) + size_bit = (__force u32)cpu_to_be32(size_bit); +@@ -1139,11 +1169,9 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_DIN, size_bit); + } else { + /* CCM: write CTR0 */ +- u8 iv[AES_BLOCK_SIZE]; +- u32 *iv32 = (u32 *)iv; +- __be32 *biv; +- +- biv = (void *)iv; ++ u32 iv32[AES_BLOCK_32]; ++ u8 *iv = (u8 *)iv32; ++ __be32 *biv = (__be32 *)iv32; + + memcpy(iv, cryp->areq->iv, AES_BLOCK_SIZE); + memset(iv + AES_BLOCK_SIZE - 1 - iv[0], 0, iv[0] + 1); +@@ -1165,39 +1193,18 @@ static int stm32_cryp_read_auth_tag(struct stm32_cryp *cryp) + } + + if (is_encrypt(cryp)) { ++ u32 out_tag[AES_BLOCK_32]; ++ + /* Get and write tag */ +- dst = sg_virt(cryp->out_sg) + _walked_out; ++ for (i = 0; i < AES_BLOCK_32; i++) ++ out_tag[i] = stm32_cryp_read(cryp, CRYP_DOUT); + +- for (i = 0; i < AES_BLOCK_32; i++) { +- if (cryp->total_out >= sizeof(u32)) { +- /* Read a full u32 */ +- *dst = stm32_cryp_read(cryp, CRYP_DOUT); +- +- dst = stm32_cryp_next_out(cryp, dst, +- sizeof(u32)); +- cryp->total_out -= sizeof(u32); +- } else if (!cryp->total_out) { +- /* Empty fifo out (data from input padding) */ +- stm32_cryp_read(cryp, CRYP_DOUT); +- } else { +- /* Read less than an u32 */ +- d32 = stm32_cryp_read(cryp, CRYP_DOUT); +- d8 = (u8 *)&d32; +- +- for (j = 0; j < cryp->total_out; j++) { +- *((u8 *)dst) = *(d8++); +- dst = stm32_cryp_next_out(cryp, dst, 1); +- } +- cryp->total_out = 0; +- } +- } ++ scatterwalk_copychunks(out_tag, &cryp->out_walk, cryp->authsize, 1); + } else { + /* Get and check tag */ + u32 in_tag[AES_BLOCK_32], out_tag[AES_BLOCK_32]; + +- scatterwalk_map_and_copy(in_tag, cryp->in_sg, +- cryp->total_in_save - cryp->authsize, +- cryp->authsize, 0); ++ scatterwalk_copychunks(in_tag, &cryp->in_walk, cryp->authsize, 0); + + for (i = 0; i < AES_BLOCK_32; i++) + out_tag[i] = stm32_cryp_read(cryp, CRYP_DOUT); +@@ -1219,113 +1226,63 @@ static void stm32_cryp_check_ctr_counter(struct stm32_cryp *cryp) + + if (unlikely(cryp->last_ctr[3] == 0xFFFFFFFF)) { + cryp->last_ctr[3] = 0; +- cryp->last_ctr[2]++; ++ cryp->last_ctr[2] = cpu_to_be32(be32_to_cpu(cryp->last_ctr[2]) + 1); + if (!cryp->last_ctr[2]) { +- cryp->last_ctr[1]++; ++ cryp->last_ctr[1] = cpu_to_be32(be32_to_cpu(cryp->last_ctr[1]) + 1); + if (!cryp->last_ctr[1]) +- cryp->last_ctr[0]++; ++ cryp->last_ctr[0] = cpu_to_be32(be32_to_cpu(cryp->last_ctr[0]) + 1); + } + + cr = stm32_cryp_read(cryp, CRYP_CR); + stm32_cryp_write(cryp, CRYP_CR, cr & ~CR_CRYPEN); + +- stm32_cryp_hw_write_iv(cryp, (u32 *)cryp->last_ctr); ++ stm32_cryp_hw_write_iv(cryp, cryp->last_ctr); + + stm32_cryp_write(cryp, CRYP_CR, cr); + } + +- cryp->last_ctr[0] = stm32_cryp_read(cryp, CRYP_IV0LR); +- cryp->last_ctr[1] = stm32_cryp_read(cryp, CRYP_IV0RR); +- cryp->last_ctr[2] = stm32_cryp_read(cryp, CRYP_IV1LR); +- cryp->last_ctr[3] = stm32_cryp_read(cryp, CRYP_IV1RR); ++ /* The IV registers are BE */ ++ cryp->last_ctr[0] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV0LR)); ++ cryp->last_ctr[1] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV0RR)); ++ cryp->last_ctr[2] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV1LR)); ++ cryp->last_ctr[3] = cpu_to_be32(stm32_cryp_read(cryp, CRYP_IV1RR)); + } + +-static bool stm32_cryp_irq_read_data(struct stm32_cryp *cryp) ++static void stm32_cryp_irq_read_data(struct stm32_cryp *cryp) + { +- unsigned int i, j; +- u32 d32, *dst; +- u8 *d8; +- size_t tag_size; +- +- /* Do no read tag now (if any) */ +- if (is_encrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp))) +- tag_size = cryp->authsize; +- else +- tag_size = 0; +- +- dst = sg_virt(cryp->out_sg) + _walked_out; +- +- for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { +- if (likely(cryp->total_out - tag_size >= sizeof(u32))) { +- /* Read a full u32 */ +- *dst = stm32_cryp_read(cryp, CRYP_DOUT); ++ unsigned int i; ++ u32 block[AES_BLOCK_32]; + +- dst = stm32_cryp_next_out(cryp, dst, sizeof(u32)); +- cryp->total_out -= sizeof(u32); +- } else if (cryp->total_out == tag_size) { +- /* Empty fifo out (data from input padding) */ +- d32 = stm32_cryp_read(cryp, CRYP_DOUT); +- } else { +- /* Read less than an u32 */ +- d32 = stm32_cryp_read(cryp, CRYP_DOUT); +- d8 = (u8 *)&d32; +- +- for (j = 0; j < cryp->total_out - tag_size; j++) { +- *((u8 *)dst) = *(d8++); +- dst = stm32_cryp_next_out(cryp, dst, 1); +- } +- cryp->total_out = tag_size; +- } +- } ++ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) ++ block[i] = stm32_cryp_read(cryp, CRYP_DOUT); + +- return !(cryp->total_out - tag_size) || !cryp->total_in; ++ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, ++ cryp->hw_blocksize, ++ cryp->payload_out), ++ 1); ++ cryp->payload_out -= min_t(size_t, cryp->hw_blocksize, ++ cryp->payload_out); + } + + static void stm32_cryp_irq_write_block(struct stm32_cryp *cryp) + { +- unsigned int i, j; +- u32 *src; +- u8 d8[4]; +- size_t tag_size; +- +- /* Do no write tag (if any) */ +- if (is_decrypt(cryp) && (is_gcm(cryp) || is_ccm(cryp))) +- tag_size = cryp->authsize; +- else +- tag_size = 0; +- +- src = sg_virt(cryp->in_sg) + _walked_in; ++ unsigned int i; ++ u32 block[AES_BLOCK_32] = {0}; + +- for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) { +- if (likely(cryp->total_in - tag_size >= sizeof(u32))) { +- /* Write a full u32 */ +- stm32_cryp_write(cryp, CRYP_DIN, *src); ++ scatterwalk_copychunks(block, &cryp->in_walk, min_t(size_t, ++ cryp->hw_blocksize, ++ cryp->payload_in), ++ 0); ++ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) ++ stm32_cryp_write(cryp, CRYP_DIN, block[i]); + +- src = stm32_cryp_next_in(cryp, src, sizeof(u32)); +- cryp->total_in -= sizeof(u32); +- } else if (cryp->total_in == tag_size) { +- /* Write padding data */ +- stm32_cryp_write(cryp, CRYP_DIN, 0); +- } else { +- /* Write less than an u32 */ +- memset(d8, 0, sizeof(u32)); +- for (j = 0; j < cryp->total_in - tag_size; j++) { +- d8[j] = *((u8 *)src); +- src = stm32_cryp_next_in(cryp, src, 1); +- } +- +- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); +- cryp->total_in = tag_size; +- } +- } ++ cryp->payload_in -= min_t(size_t, cryp->hw_blocksize, cryp->payload_in); + } + + static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + { + int err; +- u32 cfg, tmp[AES_BLOCK_32]; +- size_t total_in_ori = cryp->total_in; +- struct scatterlist *out_sg_ori = cryp->out_sg; ++ u32 cfg, block[AES_BLOCK_32] = {0}; + unsigned int i; + + /* 'Special workaround' procedure described in the datasheet */ +@@ -1350,18 +1307,27 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + + /* b) pad and write the last block */ + stm32_cryp_irq_write_block(cryp); +- cryp->total_in = total_in_ori; ++ /* wait end of process */ + err = stm32_cryp_wait_output(cryp); + if (err) { +- dev_err(cryp->dev, "Timeout (write gcm header)\n"); ++ dev_err(cryp->dev, "Timeout (write gcm last data)\n"); + return stm32_cryp_finish_req(cryp, err); + } + + /* c) get and store encrypted data */ +- stm32_cryp_irq_read_data(cryp); +- scatterwalk_map_and_copy(tmp, out_sg_ori, +- cryp->total_in_save - total_in_ori, +- total_in_ori, 0); ++ /* ++ * Same code as stm32_cryp_irq_read_data(), but we want to store ++ * block value ++ */ ++ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) ++ block[i] = stm32_cryp_read(cryp, CRYP_DOUT); ++ ++ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, ++ cryp->hw_blocksize, ++ cryp->payload_out), ++ 1); ++ cryp->payload_out -= min_t(size_t, cryp->hw_blocksize, ++ cryp->payload_out); + + /* d) change mode back to AES GCM */ + cfg &= ~CR_ALGO_MASK; +@@ -1374,19 +1340,13 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_CR, cfg); + + /* f) write padded data */ +- for (i = 0; i < AES_BLOCK_32; i++) { +- if (cryp->total_in) +- stm32_cryp_write(cryp, CRYP_DIN, tmp[i]); +- else +- stm32_cryp_write(cryp, CRYP_DIN, 0); +- +- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); +- } ++ for (i = 0; i < AES_BLOCK_32; i++) ++ stm32_cryp_write(cryp, CRYP_DIN, block[i]); + + /* g) Empty fifo out */ + err = stm32_cryp_wait_output(cryp); + if (err) { +- dev_err(cryp->dev, "Timeout (write gcm header)\n"); ++ dev_err(cryp->dev, "Timeout (write gcm padded data)\n"); + return stm32_cryp_finish_req(cryp, err); + } + +@@ -1399,16 +1359,14 @@ static void stm32_cryp_irq_write_gcm_padded_data(struct stm32_cryp *cryp) + + static void stm32_cryp_irq_set_npblb(struct stm32_cryp *cryp) + { +- u32 cfg, payload_bytes; ++ u32 cfg; + + /* disable ip, set NPBLB and reneable ip */ + cfg = stm32_cryp_read(cryp, CRYP_CR); + cfg &= ~CR_CRYPEN; + stm32_cryp_write(cryp, CRYP_CR, cfg); + +- payload_bytes = is_decrypt(cryp) ? cryp->total_in - cryp->authsize : +- cryp->total_in; +- cfg |= (cryp->hw_blocksize - payload_bytes) << CR_NBPBL_SHIFT; ++ cfg |= (cryp->hw_blocksize - cryp->payload_in) << CR_NBPBL_SHIFT; + cfg |= CR_CRYPEN; + stm32_cryp_write(cryp, CRYP_CR, cfg); + } +@@ -1417,13 +1375,11 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + { + int err = 0; + u32 cfg, iv1tmp; +- u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32], tmp[AES_BLOCK_32]; +- size_t last_total_out, total_in_ori = cryp->total_in; +- struct scatterlist *out_sg_ori = cryp->out_sg; ++ u32 cstmp1[AES_BLOCK_32], cstmp2[AES_BLOCK_32]; ++ u32 block[AES_BLOCK_32] = {0}; + unsigned int i; + + /* 'Special workaround' procedure described in the datasheet */ +- cryp->flags |= FLG_CCM_PADDED_WA; + + /* a) disable ip */ + stm32_cryp_write(cryp, CRYP_IMSCR, 0); +@@ -1453,7 +1409,7 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + + /* b) pad and write the last block */ + stm32_cryp_irq_write_block(cryp); +- cryp->total_in = total_in_ori; ++ /* wait end of process */ + err = stm32_cryp_wait_output(cryp); + if (err) { + dev_err(cryp->dev, "Timeout (wite ccm padded data)\n"); +@@ -1461,13 +1417,19 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + } + + /* c) get and store decrypted data */ +- last_total_out = cryp->total_out; +- stm32_cryp_irq_read_data(cryp); +- +- memset(tmp, 0, sizeof(tmp)); +- scatterwalk_map_and_copy(tmp, out_sg_ori, +- cryp->total_out_save - last_total_out, +- last_total_out, 0); ++ /* ++ * Same code as stm32_cryp_irq_read_data(), but we want to store ++ * block value ++ */ ++ for (i = 0; i < cryp->hw_blocksize / sizeof(u32); i++) ++ block[i] = stm32_cryp_read(cryp, CRYP_DOUT); ++ ++ scatterwalk_copychunks(block, &cryp->out_walk, min_t(size_t, ++ cryp->hw_blocksize, ++ cryp->payload_out), ++ 1); ++ cryp->payload_out -= min_t(size_t, cryp->hw_blocksize, ++ cryp->payload_out); + + /* d) Load again CRYP_CSGCMCCMxR */ + for (i = 0; i < ARRAY_SIZE(cstmp2); i++) +@@ -1484,10 +1446,10 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + stm32_cryp_write(cryp, CRYP_CR, cfg); + + /* g) XOR and write padded data */ +- for (i = 0; i < ARRAY_SIZE(tmp); i++) { +- tmp[i] ^= cstmp1[i]; +- tmp[i] ^= cstmp2[i]; +- stm32_cryp_write(cryp, CRYP_DIN, tmp[i]); ++ for (i = 0; i < ARRAY_SIZE(block); i++) { ++ block[i] ^= cstmp1[i]; ++ block[i] ^= cstmp2[i]; ++ stm32_cryp_write(cryp, CRYP_DIN, block[i]); + } + + /* h) wait for completion */ +@@ -1501,30 +1463,34 @@ static void stm32_cryp_irq_write_ccm_padded_data(struct stm32_cryp *cryp) + + static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) + { +- if (unlikely(!cryp->total_in)) { ++ if (unlikely(!cryp->payload_in)) { + dev_warn(cryp->dev, "No more data to process\n"); + return; + } + +- if (unlikely(cryp->total_in < AES_BLOCK_SIZE && ++ if (unlikely(cryp->payload_in < AES_BLOCK_SIZE && + (stm32_cryp_get_hw_mode(cryp) == CR_AES_GCM) && + is_encrypt(cryp))) { + /* Padding for AES GCM encryption */ +- if (cryp->caps->padding_wa) ++ if (cryp->caps->padding_wa) { + /* Special case 1 */ +- return stm32_cryp_irq_write_gcm_padded_data(cryp); ++ stm32_cryp_irq_write_gcm_padded_data(cryp); ++ return; ++ } + + /* Setting padding bytes (NBBLB) */ + stm32_cryp_irq_set_npblb(cryp); + } + +- if (unlikely((cryp->total_in - cryp->authsize < AES_BLOCK_SIZE) && ++ if (unlikely((cryp->payload_in < AES_BLOCK_SIZE) && + (stm32_cryp_get_hw_mode(cryp) == CR_AES_CCM) && + is_decrypt(cryp))) { + /* Padding for AES CCM decryption */ +- if (cryp->caps->padding_wa) ++ if (cryp->caps->padding_wa) { + /* Special case 2 */ +- return stm32_cryp_irq_write_ccm_padded_data(cryp); ++ stm32_cryp_irq_write_ccm_padded_data(cryp); ++ return; ++ } + + /* Setting padding bytes (NBBLB) */ + stm32_cryp_irq_set_npblb(cryp); +@@ -1536,192 +1502,61 @@ static void stm32_cryp_irq_write_data(struct stm32_cryp *cryp) + stm32_cryp_irq_write_block(cryp); + } + +-static void stm32_cryp_irq_write_gcm_header(struct stm32_cryp *cryp) ++static void stm32_cryp_irq_write_gcmccm_header(struct stm32_cryp *cryp) + { +- int err; +- unsigned int i, j; +- u32 cfg, *src; +- +- src = sg_virt(cryp->in_sg) + _walked_in; +- +- for (i = 0; i < AES_BLOCK_32; i++) { +- stm32_cryp_write(cryp, CRYP_DIN, *src); +- +- src = stm32_cryp_next_in(cryp, src, sizeof(u32)); +- cryp->total_in -= min_t(size_t, sizeof(u32), cryp->total_in); +- +- /* Check if whole header written */ +- if ((cryp->total_in_save - cryp->total_in) == +- cryp->areq->assoclen) { +- /* Write padding if needed */ +- for (j = i + 1; j < AES_BLOCK_32; j++) +- stm32_cryp_write(cryp, CRYP_DIN, 0); +- +- /* Wait for completion */ +- err = stm32_cryp_wait_busy(cryp); +- if (err) { +- dev_err(cryp->dev, "Timeout (gcm header)\n"); +- return stm32_cryp_finish_req(cryp, err); +- } +- +- if (stm32_cryp_get_input_text_len(cryp)) { +- /* Phase 3 : payload */ +- cfg = stm32_cryp_read(cryp, CRYP_CR); +- cfg &= ~CR_CRYPEN; +- stm32_cryp_write(cryp, CRYP_CR, cfg); +- +- cfg &= ~CR_PH_MASK; +- cfg |= CR_PH_PAYLOAD; +- cfg |= CR_CRYPEN; +- stm32_cryp_write(cryp, CRYP_CR, cfg); +- } else { +- /* Phase 4 : tag */ +- stm32_cryp_write(cryp, CRYP_IMSCR, 0); +- stm32_cryp_finish_req(cryp, 0); +- } +- +- break; +- } +- +- if (!cryp->total_in) +- break; +- } +-} ++ unsigned int i; ++ u32 block[AES_BLOCK_32] = {0}; ++ size_t written; + +-static void stm32_cryp_irq_write_ccm_header(struct stm32_cryp *cryp) +-{ +- int err; +- unsigned int i = 0, j, k; +- u32 alen, cfg, *src; +- u8 d8[4]; +- +- src = sg_virt(cryp->in_sg) + _walked_in; +- alen = cryp->areq->assoclen; +- +- if (!_walked_in) { +- if (cryp->areq->assoclen <= 65280) { +- /* Write first u32 of B1 */ +- d8[0] = (alen >> 8) & 0xFF; +- d8[1] = alen & 0xFF; +- d8[2] = *((u8 *)src); +- src = stm32_cryp_next_in(cryp, src, 1); +- d8[3] = *((u8 *)src); +- src = stm32_cryp_next_in(cryp, src, 1); +- +- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); +- i++; +- +- cryp->total_in -= min_t(size_t, 2, cryp->total_in); +- } else { +- /* Build the two first u32 of B1 */ +- d8[0] = 0xFF; +- d8[1] = 0xFE; +- d8[2] = alen & 0xFF000000; +- d8[3] = alen & 0x00FF0000; +- +- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); +- i++; +- +- d8[0] = alen & 0x0000FF00; +- d8[1] = alen & 0x000000FF; +- d8[2] = *((u8 *)src); +- src = stm32_cryp_next_in(cryp, src, 1); +- d8[3] = *((u8 *)src); +- src = stm32_cryp_next_in(cryp, src, 1); +- +- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); +- i++; +- +- cryp->total_in -= min_t(size_t, 2, cryp->total_in); +- } +- } ++ written = min_t(size_t, AES_BLOCK_SIZE, cryp->header_in); + +- /* Write next u32 */ +- for (; i < AES_BLOCK_32; i++) { +- /* Build an u32 */ +- memset(d8, 0, sizeof(u32)); +- for (k = 0; k < sizeof(u32); k++) { +- d8[k] = *((u8 *)src); +- src = stm32_cryp_next_in(cryp, src, 1); +- +- cryp->total_in -= min_t(size_t, 1, cryp->total_in); +- if ((cryp->total_in_save - cryp->total_in) == alen) +- break; +- } ++ scatterwalk_copychunks(block, &cryp->in_walk, written, 0); ++ for (i = 0; i < AES_BLOCK_32; i++) ++ stm32_cryp_write(cryp, CRYP_DIN, block[i]); + +- stm32_cryp_write(cryp, CRYP_DIN, *(u32 *)d8); +- +- if ((cryp->total_in_save - cryp->total_in) == alen) { +- /* Write padding if needed */ +- for (j = i + 1; j < AES_BLOCK_32; j++) +- stm32_cryp_write(cryp, CRYP_DIN, 0); +- +- /* Wait for completion */ +- err = stm32_cryp_wait_busy(cryp); +- if (err) { +- dev_err(cryp->dev, "Timeout (ccm header)\n"); +- return stm32_cryp_finish_req(cryp, err); +- } +- +- if (stm32_cryp_get_input_text_len(cryp)) { +- /* Phase 3 : payload */ +- cfg = stm32_cryp_read(cryp, CRYP_CR); +- cfg &= ~CR_CRYPEN; +- stm32_cryp_write(cryp, CRYP_CR, cfg); +- +- cfg &= ~CR_PH_MASK; +- cfg |= CR_PH_PAYLOAD; +- cfg |= CR_CRYPEN; +- stm32_cryp_write(cryp, CRYP_CR, cfg); +- } else { +- /* Phase 4 : tag */ +- stm32_cryp_write(cryp, CRYP_IMSCR, 0); +- stm32_cryp_finish_req(cryp, 0); +- } ++ cryp->header_in -= written; + +- break; +- } +- } ++ stm32_crypt_gcmccm_end_header(cryp); + } + + static irqreturn_t stm32_cryp_irq_thread(int irq, void *arg) + { + struct stm32_cryp *cryp = arg; + u32 ph; ++ u32 it_mask = stm32_cryp_read(cryp, CRYP_IMSCR); ++ + + if (cryp->irq_status & MISR_OUT) + /* Output FIFO IRQ: read data */ +- if (unlikely(stm32_cryp_irq_read_data(cryp))) { +- /* All bytes processed, finish */ +- stm32_cryp_write(cryp, CRYP_IMSCR, 0); +- stm32_cryp_finish_req(cryp, 0); +- return IRQ_HANDLED; +- } ++ stm32_cryp_irq_read_data(cryp); + + if (cryp->irq_status & MISR_IN) { +- if (is_gcm(cryp)) { +- ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK; +- if (unlikely(ph == CR_PH_HEADER)) +- /* Write Header */ +- stm32_cryp_irq_write_gcm_header(cryp); +- else +- /* Input FIFO IRQ: write data */ +- stm32_cryp_irq_write_data(cryp); +- cryp->gcm_ctr++; +- } else if (is_ccm(cryp)) { ++ if (is_gcm(cryp) || is_ccm(cryp)) { + ph = stm32_cryp_read(cryp, CRYP_CR) & CR_PH_MASK; + if (unlikely(ph == CR_PH_HEADER)) + /* Write Header */ +- stm32_cryp_irq_write_ccm_header(cryp); ++ stm32_cryp_irq_write_gcmccm_header(cryp); + else + /* Input FIFO IRQ: write data */ + stm32_cryp_irq_write_data(cryp); ++ if (is_gcm(cryp)) ++ cryp->gcm_ctr++; + } else { + /* Input FIFO IRQ: write data */ + stm32_cryp_irq_write_data(cryp); + } + } + ++ /* Mask useless interrupts */ ++ if (!cryp->payload_in && !cryp->header_in) ++ it_mask &= ~IMSCR_IN; ++ if (!cryp->payload_out) ++ it_mask &= ~IMSCR_OUT; ++ stm32_cryp_write(cryp, CRYP_IMSCR, it_mask); ++ ++ if (!cryp->payload_in && !cryp->header_in && !cryp->payload_out) ++ stm32_cryp_finish_req(cryp, 0); ++ + return IRQ_HANDLED; + } + +@@ -1742,7 +1577,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1759,7 +1594,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = AES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1777,7 +1612,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = 1, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1795,7 +1630,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1812,7 +1647,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1830,7 +1665,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1847,7 +1682,7 @@ static struct skcipher_alg crypto_algs[] = { + .base.cra_flags = CRYPTO_ALG_ASYNC, + .base.cra_blocksize = DES_BLOCK_SIZE, + .base.cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .base.cra_alignmask = 0xf, ++ .base.cra_alignmask = 0, + .base.cra_module = THIS_MODULE, + + .init = stm32_cryp_init_tfm, +@@ -1877,7 +1712,7 @@ static struct aead_alg aead_algs[] = { + .cra_flags = CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .cra_alignmask = 0xf, ++ .cra_alignmask = 0, + .cra_module = THIS_MODULE, + }, + }, +@@ -1897,7 +1732,7 @@ static struct aead_alg aead_algs[] = { + .cra_flags = CRYPTO_ALG_ASYNC, + .cra_blocksize = 1, + .cra_ctxsize = sizeof(struct stm32_cryp_ctx), +- .cra_alignmask = 0xf, ++ .cra_alignmask = 0, + .cra_module = THIS_MODULE, + }, + }, +@@ -1955,7 +1790,9 @@ static int stm32_cryp_probe(struct platform_device *pdev) + + cryp->clk = devm_clk_get(dev, NULL); + if (IS_ERR(cryp->clk)) { +- dev_err(dev, "Could not get clock\n"); ++ if (PTR_ERR(cryp->clk) != -EPROBE_DEFER) ++ dev_err(dev, "Could not get clock\n"); ++ + return PTR_ERR(cryp->clk); + } + +@@ -1973,7 +1810,11 @@ static int stm32_cryp_probe(struct platform_device *pdev) + pm_runtime_enable(dev); + + rst = devm_reset_control_get(dev, NULL); +- if (!IS_ERR(rst)) { ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret == -EPROBE_DEFER) ++ goto err_rst; ++ } else { + reset_control_assert(rst); + udelay(2); + reset_control_deassert(rst); +@@ -2024,9 +1865,7 @@ static int stm32_cryp_probe(struct platform_device *pdev) + spin_lock(&cryp_list.lock); + list_del(&cryp->list); + spin_unlock(&cryp_list.lock); +- +- pm_runtime_disable(dev); +- pm_runtime_put_noidle(dev); ++err_rst: + pm_runtime_disable(dev); + pm_runtime_put_noidle(dev); + +diff --git a/drivers/crypto/stm32/stm32-hash.c b/drivers/crypto/stm32/stm32-hash.c +index ff5362da1..19b3d8518 100644 +--- a/drivers/crypto/stm32/stm32-hash.c ++++ b/drivers/crypto/stm32/stm32-hash.c +@@ -925,15 +925,10 @@ static int stm32_hash_final(struct ahash_request *req) + static int stm32_hash_finup(struct ahash_request *req) + { + struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); +- struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); +- struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); + int err1, err2; + + rctx->flags |= HASH_FLAGS_FINUP; + +- if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) +- rctx->flags &= ~HASH_FLAGS_CPU; +- + err1 = stm32_hash_update(req); + + if (err1 == -EINPROGRESS || err1 == -EBUSY) +@@ -950,7 +945,19 @@ static int stm32_hash_finup(struct ahash_request *req) + + static int stm32_hash_digest(struct ahash_request *req) + { +- return stm32_hash_init(req) ?: stm32_hash_finup(req); ++ int ret; ++ struct stm32_hash_request_ctx *rctx = ahash_request_ctx(req); ++ struct stm32_hash_ctx *ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req)); ++ struct stm32_hash_dev *hdev = stm32_hash_find_dev(ctx); ++ ++ ret = stm32_hash_init(req); ++ if (ret) ++ return ret; ++ ++ if (hdev->dma_lch && stm32_hash_dma_aligned_data(req)) ++ rctx->flags &= ~HASH_FLAGS_CPU; ++ ++ return stm32_hash_finup(req); + } + + static int stm32_hash_export(struct ahash_request *req, void *out) +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0005-ARM-5.10.10-stm32mp1-r1-DMA.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch similarity index 79% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0005-ARM-5.10.10-stm32mp1-r1-DMA.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch index 4aabd5b..df06284 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0005-ARM-5.10.10-stm32mp1-r1-DMA.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch @@ -1,17 +1,17 @@ -From 8419770f37f0543bc5c2390651c46892dc520018 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 08:58:56 +0100 -Subject: [PATCH 05/22] ARM 5.10.10-stm32mp1-r1 DMA +From f7324af2c2808c281ecd773cdc1efd68026aa3fd Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:42 +0200 +Subject: [PATCH 05/23] ARM 5.10.61-stm32mp1-r2 DMA --- drivers/dma/dmaengine.c | 34 ++ - drivers/dma/stm32-dma.c | 1011 ++++++++++++++++++++++++++++++++----- - drivers/dma/stm32-mdma.c | 188 +++++-- + drivers/dma/stm32-dma.c | 1207 +++++++++++++++++++++++++++++++++---- + drivers/dma/stm32-mdma.c | 188 ++++-- include/linux/dmaengine.h | 11 + - 4 files changed, 1070 insertions(+), 174 deletions(-) + 4 files changed, 1272 insertions(+), 168 deletions(-) diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c -index 962cbb5e5f7f..1381f15eb6f2 100644 +index af3ee288b..8a0cf0d8a 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -873,6 +873,33 @@ struct dma_chan *dma_request_chan(struct device *dev, const char *name) @@ -63,7 +63,7 @@ index 962cbb5e5f7f..1381f15eb6f2 100644 * dmaengine_get - register interest in dma_channels */ diff --git a/drivers/dma/stm32-dma.c b/drivers/dma/stm32-dma.c -index d0055d2f0b9a..1d89e0807ef0 100644 +index 1150aa90e..5dd476365 100644 --- a/drivers/dma/stm32-dma.c +++ b/drivers/dma/stm32-dma.c @@ -14,12 +14,14 @@ @@ -147,10 +147,11 @@ index d0055d2f0b9a..1d89e0807ef0 100644 struct stm32_dma_sg_req sg_req[]; }; -@@ -206,6 +236,10 @@ struct stm32_dma_chan { +@@ -206,6 +236,11 @@ struct stm32_dma_chan { u32 threshold; u32 mem_burst; u32 mem_width; ++ enum dma_status status; + struct stm32_dma_mdma mchan; + u32 use_mdma; + u32 sram_size; @@ -158,7 +159,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 }; struct stm32_dma_device { -@@ -214,6 +248,7 @@ struct stm32_dma_device { +@@ -214,6 +249,7 @@ struct stm32_dma_device { struct clk *clk; bool mem2mem; struct stm32_dma_chan chan[STM32_DMA_MAX_CHANNELS]; @@ -166,7 +167,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 }; static struct stm32_dma_device *stm32_dma_get_dev(struct stm32_dma_chan *chan) -@@ -264,6 +299,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, +@@ -264,6 +300,7 @@ static int stm32_dma_get_width(struct stm32_dma_chan *chan, } static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, @@ -174,7 +175,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 u32 threshold) { enum dma_slave_buswidth max_width; -@@ -277,6 +313,9 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, +@@ -277,6 +314,9 @@ static enum dma_slave_buswidth stm32_dma_get_max_width(u32 buf_len, max_width > DMA_SLAVE_BUSWIDTH_1_BYTE) max_width = max_width >> 1; @@ -184,7 +185,30 @@ index d0055d2f0b9a..1d89e0807ef0 100644 return max_width; } -@@ -484,12 +523,20 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) +@@ -374,6 +414,16 @@ static void stm32_dma_set_fifo_config(struct stm32_dma_chan *chan, + } + } + ++static void stm32_dma_slave_caps(struct dma_chan *c, struct dma_slave_caps *caps) ++{ ++ struct stm32_dma_chan *chan = to_stm32_dma_chan(c); ++ ++ if (chan->use_mdma) ++ caps->max_sg_burst = 0; /* unlimited */ ++ else ++ caps->max_sg_burst = STM32_DMA_ALIGNED_MAX_DATA_ITEMS; ++} ++ + static int stm32_dma_slave_config(struct dma_chan *c, + struct dma_slave_config *config) + { +@@ -479,17 +529,26 @@ static void stm32_dma_stop(struct stm32_dma_chan *chan) + } + + chan->busy = false; ++ chan->status = DMA_COMPLETE; + } + static int stm32_dma_terminate_all(struct dma_chan *c) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -206,7 +230,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 vchan_terminate_vdesc(&chan->desc->vdesc); if (chan->busy) stm32_dma_stop(chan); -@@ -503,9 +550,103 @@ static int stm32_dma_terminate_all(struct dma_chan *c) +@@ -503,9 +562,103 @@ static int stm32_dma_terminate_all(struct dma_chan *c) return 0; } @@ -310,7 +334,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 vchan_synchronize(&chan->vchan); } -@@ -528,65 +669,213 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) +@@ -528,7 +681,244 @@ static void stm32_dma_dump_reg(struct stm32_dma_chan *chan) dev_dbg(chan2dev(chan), "SFCR: 0x%08x\n", sfcr); } @@ -343,8 +367,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + dma_unmap_single(ddev->dev, dma_src_buf, len, DMA_TO_DEVICE); + return ret; + } - --static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) ++ + reg.dma_scr = STM32_DMA_SCR_DIR(STM32_DMA_MEM_TO_MEM) | + STM32_DMA_SCR_PBURST(STM32_DMA_BURST_SINGLE) | + STM32_DMA_SCR_MBURST(STM32_DMA_BURST_SINGLE) | @@ -373,6 +396,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + stm32_dma_dump_reg(chan); + + chan->busy = true; ++ chan->status = DMA_IN_PROGRESS; + /* Start DMA */ + reg.dma_scr |= STM32_DMA_SCR_EN; + stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg.dma_scr); @@ -386,6 +410,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + } + + chan->busy = false; ++ chan->status = DMA_COMPLETE; + + ret = stm32_dma_disable_chan(chan); + status = stm32_dma_irq_status(chan); @@ -399,31 +424,21 @@ index d0055d2f0b9a..1d89e0807ef0 100644 +} + +static int stm32_dma_mdma_flush_remaining(struct stm32_dma_chan *chan) - { - struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -- struct virt_dma_desc *vdesc; ++{ ++ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + struct stm32_dma_mdma *mchan = &chan->mchan; - struct stm32_dma_sg_req *sg_req; -- struct stm32_dma_chan_reg *reg; -- u32 status; ++ struct stm32_dma_sg_req *sg_req; + struct dma_device *ddev = mchan->chan->device; + struct dma_async_tx_descriptor *desc = NULL; + enum dma_status status; + dma_addr_t src_buf, dst_buf; + u32 residue, remain, len, dma_scr; - int ret; - -- ret = stm32_dma_disable_chan(chan); -- if (ret < 0) -- return; ++ int ret; ++ + residue = stm32_dma_get_remaining_bytes(chan); + if (!residue) + return 0; - -- if (!chan->desc) { -- vdesc = vchan_next_desc(&chan->vchan); -- if (!vdesc) -- return; ++ + dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); + if (!(dma_scr & STM32_DMA_SCR_EN)) + return -EPERM; @@ -448,15 +463,12 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + residue = stm32_dma_get_remaining_bytes(chan); + } + stm32_dma_disable_chan(chan); - -- list_del(&vdesc->node); ++ + src_buf = mchan->sram_buf + ((len / mchan->sram_period) & 0x1) + * mchan->sram_period; + dst_buf = sg_dma_address(&sg_req->stm32_sgl_req) + len - + (len % mchan->sram_period); - -- chan->desc = to_stm32_dma_desc(vdesc); -- chan->next_sg = 0; ++ + desc = ddev->device_prep_dma_memcpy(mchan->chan, + dst_buf, src_buf, + len % mchan->sram_period, @@ -474,43 +486,28 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + dmaengine_terminate_async(mchan->chan); + return -EBUSY; + } - } - -- if (chan->next_sg == chan->desc->num_sgs) -- chan->next_sg = 0; ++ } ++ + return 0; +} - -- sg_req = &chan->desc->sg_req[chan->next_sg]; -- reg = &sg_req->chan_reg; ++ +static void stm32_dma_start_transfer(struct stm32_dma_chan *chan); - -- reg->dma_scr &= ~STM32_DMA_SCR_EN; -- stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); -- stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); -- stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar); -- stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), reg->dma_sfcr); -- stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar); -- stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr); ++ +static void stm32_mdma_chan_complete(void *param, + const struct dmaengine_result *result) +{ + struct stm32_dma_chan *chan = param; + int ret; - -- chan->next_sg++; ++ + chan->busy = false; ++ chan->status = DMA_COMPLETE; + if (result->result == DMA_TRANS_NOERROR) { + ret = stm32_dma_mdma_flush_remaining(chan); + if (ret) { + dev_err(chan2dev(chan), "Can't flush DMA: %d\n", ret); + return; + } - -- /* Clear interrupt status if it is there */ -- status = stm32_dma_irq_status(chan); -- if (status) -- stm32_dma_irq_clear(chan, status); ++ + if (chan->next_sg == chan->desc->num_sgs) { + vchan_cookie_complete(&chan->desc->vdesc); + chan->desc = NULL; @@ -521,29 +518,22 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + result->result); + } +} - -- if (chan->desc->cyclic) -- stm32_dma_configure_next_sg(chan); ++ +static int stm32_dma_mdma_start(struct stm32_dma_chan *chan, + struct stm32_dma_sg_req *sg_req) +{ + struct stm32_dma_mdma *mchan = &chan->mchan; + struct stm32_dma_mdma_desc *m_desc = &sg_req->m_desc; + int ret; - -- stm32_dma_dump_reg(chan); ++ + ret = dma_submit_error(dmaengine_submit(m_desc->desc)); + if (ret < 0) { + dev_err(chan2dev(chan), "MDMA submit failed\n"); + goto error; + } - -- /* Start DMA */ -- reg->dma_scr |= STM32_DMA_SCR_EN; -- stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); ++ + dma_async_issue_pending(mchan->chan); - -- chan->busy = true; ++ + /* + * In case of M2D transfer, we have to generate dummy DMA transfer to + * copy 1st sg data into SRAM @@ -555,56 +545,54 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + goto error; + } + } - -- dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan); ++ + return 0; +error: + return ret; - } - - static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) -@@ -618,22 +907,134 @@ static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) - } - } - --static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) -+static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) - { -- if (chan->desc) { -- if (chan->desc->cyclic) { -- vchan_cyclic_callback(&chan->desc->vdesc); -- chan->next_sg++; -- stm32_dma_configure_next_sg(chan); ++} ++ ++static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) ++{ + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); -+ struct virt_dma_desc *vdesc; + struct stm32_dma_sg_req *sg_req; -+ struct stm32_dma_chan_reg *reg; -+ u32 status; -+ int ret; ++ u32 dma_scr, dma_sm0ar, dma_sm1ar, id; + -+ ret = stm32_dma_disable_chan(chan); -+ if (ret < 0) -+ return; -+ -+ if (!chan->desc) { -+ vdesc = vchan_next_desc(&chan->vchan); -+ if (!vdesc) -+ return; -+ -+ list_del(&vdesc->node); -+ -+ chan->desc = to_stm32_dma_desc(vdesc); -+ chan->next_sg = 0; -+ } else { -+ vdesc = &chan->desc->vdesc; -+ } ++ id = chan->id; ++ dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); + + if (chan->next_sg == chan->desc->num_sgs) + chan->next_sg = 0; + + sg_req = &chan->desc->sg_req[chan->next_sg]; -+ reg = &sg_req->chan_reg; + ++ if (dma_scr & STM32_DMA_SCR_CT) { ++ dma_sm0ar = sg_req->chan_reg.dma_sm0ar; ++ stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar); ++ dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n", ++ stm32_dma_read(dmadev, STM32_DMA_SM0AR(id))); ++ } else { ++ dma_sm1ar = sg_req->chan_reg.dma_sm1ar; ++ stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar); ++ dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", ++ stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); ++ } ++} + + static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) + { +@@ -552,6 +942,8 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) + + chan->desc = to_stm32_dma_desc(vdesc); + chan->next_sg = 0; ++ } else { ++ vdesc = &chan->desc->vdesc; + } + + if (chan->next_sg == chan->desc->num_sgs) +@@ -560,6 +952,59 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) + sg_req = &chan->desc->sg_req[chan->next_sg]; + reg = &sg_req->chan_reg; + + /* Clear interrupt status if it is there */ + status = stm32_dma_irq_status(chan); + if (status) @@ -638,10 +626,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + chan->desc = NULL; + return; + } - } else { -- chan->busy = false; -- if (chan->next_sg == chan->desc->num_sgs) { -- vchan_cookie_complete(&chan->desc->vdesc); ++ } else { + reg->dma_scr &= ~STM32_DMA_SCR_TCIE; + } + @@ -653,38 +638,145 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + reg->dma_scr |= STM32_DMA_SCR_DBM; + ret = stm32_dma_mdma_start(chan, sg_req); + if (ret < 0) { - chan->desc = NULL; ++ chan->desc = NULL; + return; - } -- stm32_dma_start_transfer(chan); - } - } ++ } ++ } ++ } + + chan->next_sg++; + -+ reg->dma_scr &= ~STM32_DMA_SCR_EN; -+ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); -+ stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); -+ stm32_dma_write(dmadev, STM32_DMA_SM0AR(chan->id), reg->dma_sm0ar); -+ stm32_dma_write(dmadev, STM32_DMA_SFCR(chan->id), reg->dma_sfcr); -+ stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar); -+ stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr); + reg->dma_scr &= ~STM32_DMA_SCR_EN; + stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); + stm32_dma_write(dmadev, STM32_DMA_SPAR(chan->id), reg->dma_spar); +@@ -568,71 +1013,123 @@ static void stm32_dma_start_transfer(struct stm32_dma_chan *chan) + stm32_dma_write(dmadev, STM32_DMA_SM1AR(chan->id), reg->dma_sm1ar); + stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), reg->dma_sndtr); + +- chan->next_sg++; +- +- /* Clear interrupt status if it is there */ +- status = stm32_dma_irq_status(chan); +- if (status) +- stm32_dma_irq_clear(chan, status); +- + if (chan->desc->cyclic) + stm32_dma_configure_next_sg(chan); + + stm32_dma_dump_reg(chan); + + /* Start DMA */ ++ chan->busy = true; ++ chan->status = DMA_IN_PROGRESS; + reg->dma_scr |= STM32_DMA_SCR_EN; + stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); + +- chan->busy = true; +- + dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan); + } + +-static void stm32_dma_configure_next_sg(struct stm32_dma_chan *chan) ++static void stm32_dma_handle_chan_paused(struct stm32_dma_chan *chan) ++{ ++ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + -+ if (chan->desc->cyclic) -+ stm32_dma_configure_next_sg(chan); ++ /* ++ * Read and store current remaining data items and peripheral/memory addresses to be ++ * updated on resume ++ */ ++ chan->chan_reg.dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); ++ /* ++ * Transfer can be paused while between a previous resume and reconfiguration on transfer ++ * complete. If transfer is cyclic and CIRC and DBM have been deactivated for resume, need ++ * to set it here in SCR backup to ensure a good reconfiguration on transfer complete. ++ */ ++ if (chan->desc && chan->desc->cyclic) { ++ if (chan->desc->num_sgs == 1) ++ chan->chan_reg.dma_scr |= STM32_DMA_SCR_CIRC; ++ else ++ chan->chan_reg.dma_scr |= STM32_DMA_SCR_DBM; ++ } ++ chan->chan_reg.dma_sndtr = stm32_dma_read(dmadev, STM32_DMA_SNDTR(chan->id)); ++ ++ dev_dbg(chan2dev(chan), "vchan %pK: paused\n", &chan->vchan); ++} ++ ++static void stm32_dma_post_resume_reconfigure(struct stm32_dma_chan *chan) + { + struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); + struct stm32_dma_sg_req *sg_req; +- u32 dma_scr, dma_sm0ar, dma_sm1ar, id; ++ u32 dma_scr, status, id; + + id = chan->id; + dma_scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); + +- if (dma_scr & STM32_DMA_SCR_DBM) { +- if (chan->next_sg == chan->desc->num_sgs) +- chan->next_sg = 0; ++ /* Clear interrupt status if it is there */ ++ status = stm32_dma_irq_status(chan); ++ if (status) ++ stm32_dma_irq_clear(chan, status); + +- sg_req = &chan->desc->sg_req[chan->next_sg]; ++ if (!chan->next_sg) ++ sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1]; ++ else ++ sg_req = &chan->desc->sg_req[chan->next_sg - 1]; + +- if (dma_scr & STM32_DMA_SCR_CT) { +- dma_sm0ar = sg_req->chan_reg.dma_sm0ar; +- stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), dma_sm0ar); +- dev_dbg(chan2dev(chan), "CT=1 <=> SM0AR: 0x%08x\n", +- stm32_dma_read(dmadev, STM32_DMA_SM0AR(id))); +- } else { +- dma_sm1ar = sg_req->chan_reg.dma_sm1ar; +- stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), dma_sm1ar); +- dev_dbg(chan2dev(chan), "CT=0 <=> SM1AR: 0x%08x\n", +- stm32_dma_read(dmadev, STM32_DMA_SM1AR(id))); +- } ++ /* Reconfigure NDTR with the initial value */ ++ stm32_dma_write(dmadev, STM32_DMA_SNDTR(chan->id), sg_req->chan_reg.dma_sndtr); ++ ++ /* Restore SPAR */ ++ stm32_dma_write(dmadev, STM32_DMA_SPAR(id), sg_req->chan_reg.dma_spar); ++ ++ /* Restore SM0AR/SM1AR whatever DBM/CT as they may have been modified */ ++ stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), sg_req->chan_reg.dma_sm0ar); ++ stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), sg_req->chan_reg.dma_sm1ar); ++ ++ /* Reactivate CIRC/DBM if needed */ ++ if (chan->chan_reg.dma_scr & STM32_DMA_SCR_DBM) { ++ dma_scr |= STM32_DMA_SCR_DBM; ++ /* Restore CT */ ++ if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CT) ++ dma_scr &= ~STM32_DMA_SCR_CT; ++ else ++ dma_scr |= STM32_DMA_SCR_CT; ++ } else if (chan->chan_reg.dma_scr & STM32_DMA_SCR_CIRC) { ++ dma_scr |= STM32_DMA_SCR_CIRC; + } ++ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); ++ ++ stm32_dma_configure_next_sg(chan); + + stm32_dma_dump_reg(chan); + -+ /* Start DMA */ -+ chan->busy = true; -+ reg->dma_scr |= STM32_DMA_SCR_EN; -+ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), reg->dma_scr); ++ dma_scr |= STM32_DMA_SCR_EN; ++ stm32_dma_write(dmadev, STM32_DMA_SCR(chan->id), dma_scr); + -+ dev_dbg(chan2dev(chan), "vchan %pK: started\n", &chan->vchan); -+} -+ -+static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) -+{ ++ dev_dbg(chan2dev(chan), "vchan %pK: reconfigured after pause/resume\n", &chan->vchan); + } + +-static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan) ++static void stm32_dma_handle_chan_done(struct stm32_dma_chan *chan, u32 scr) + { +- if (chan->desc) { +- if (chan->desc->cyclic) { +- vchan_cyclic_callback(&chan->desc->vdesc); +- chan->next_sg++; + if (!chan->desc) + return; + @@ -693,22 +785,33 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + if (chan->use_mdma) + return; + chan->next_sg++; -+ stm32_dma_configure_next_sg(chan); ++ /* cyclic while CIRC/DBM disable => post resume reconfiguration needed */ ++ if (!(scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM))) ++ stm32_dma_post_resume_reconfigure(chan); ++ else if (scr & STM32_DMA_SCR_DBM) + stm32_dma_configure_next_sg(chan); +- } else { +- chan->busy = false; +- if (chan->next_sg == chan->desc->num_sgs) { +- vchan_cookie_complete(&chan->desc->vdesc); +- chan->desc = NULL; +- } +- stm32_dma_start_transfer(chan); + } else { + chan->busy = false; ++ chan->status = DMA_COMPLETE; + if (chan->use_mdma && chan->mchan.dir != DMA_MEM_TO_DEV) + return; + if (chan->next_sg == chan->desc->num_sgs) { + vchan_cookie_complete(&chan->desc->vdesc); + chan->desc = NULL; -+ } + } + + stm32_dma_start_transfer(chan); -+ } + } } - static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) -@@ -648,21 +1049,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) +@@ -648,21 +1145,12 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) scr = stm32_dma_read(dmadev, STM32_DMA_SCR(chan->id)); sfcr = stm32_dma_read(dmadev, STM32_DMA_SFCR(chan->id)); @@ -732,15 +835,19 @@ index d0055d2f0b9a..1d89e0807ef0 100644 dev_err(chan2dev(chan), "FIFO Error\n"); else dev_dbg(chan2dev(chan), "FIFO over/underrun\n"); -@@ -674,6 +1066,19 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) +@@ -674,6 +1162,23 @@ static irqreturn_t stm32_dma_chan_irq(int irq, void *devid) if (sfcr & STM32_DMA_SCR_DMEIE) dev_dbg(chan2dev(chan), "Direct mode overrun\n"); } + + if (status & STM32_DMA_TCI) { + stm32_dma_irq_clear(chan, STM32_DMA_TCI); -+ if (scr & STM32_DMA_SCR_TCIE) -+ stm32_dma_handle_chan_done(chan); ++ if (scr & STM32_DMA_SCR_TCIE) { ++ if (chan->status == DMA_PAUSED) ++ stm32_dma_handle_chan_paused(chan); ++ else ++ stm32_dma_handle_chan_done(chan, scr); ++ } + status &= ~STM32_DMA_TCI; + } + @@ -752,7 +859,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 if (status) { stm32_dma_irq_clear(chan, status); dev_err(chan2dev(chan), "DMA error: status=0x%08x\n", status); -@@ -691,19 +1096,25 @@ static void stm32_dma_issue_pending(struct dma_chan *c) +@@ -691,19 +1196,125 @@ static void stm32_dma_issue_pending(struct dma_chan *c) struct stm32_dma_chan *chan = to_stm32_dma_chan(c); unsigned long flags; @@ -769,7 +876,107 @@ index d0055d2f0b9a..1d89e0807ef0 100644 } + ++ spin_unlock_irqrestore(&chan->vchan.lock, flags); ++} ++ ++static int stm32_dma_pause(struct dma_chan *c) ++{ ++ struct stm32_dma_chan *chan = to_stm32_dma_chan(c); ++ unsigned long flags; ++ int ret; ++ ++ if (chan->status != DMA_IN_PROGRESS || chan->use_mdma) ++ return -EPERM; ++ ++ spin_lock_irqsave(&chan->vchan.lock, flags); ++ ret = stm32_dma_disable_chan(chan); ++ /* ++ * A transfer complete flag is set to indicate the end of transfer due to the stream ++ * interruption, so wait for interrupt ++ */ ++ if (!ret) ++ chan->status = DMA_PAUSED; spin_unlock_irqrestore(&chan->vchan.lock, flags); ++ ++ return ret; ++} ++ ++static int stm32_dma_resume(struct dma_chan *c) ++{ ++ struct stm32_dma_chan *chan = to_stm32_dma_chan(c); ++ struct stm32_dma_device *dmadev = stm32_dma_get_dev(chan); ++ struct stm32_dma_chan_reg chan_reg = chan->chan_reg; ++ u32 id = chan->id, scr, ndtr, offset, spar, sm0ar, sm1ar; ++ struct stm32_dma_sg_req *sg_req; ++ unsigned long flags; ++ ++ if (chan->status != DMA_PAUSED || chan->use_mdma) ++ return -EPERM; ++ ++ scr = stm32_dma_read(dmadev, STM32_DMA_SCR(id)); ++ if (WARN_ON(scr & STM32_DMA_SCR_EN)) ++ return -EPERM; ++ ++ spin_lock_irqsave(&chan->vchan.lock, flags); ++ ++ /* sg_reg[prev_sg] contains original ndtr, sm0ar and sm1ar before pausing the transfer */ ++ if (!chan->next_sg) ++ sg_req = &chan->desc->sg_req[chan->desc->num_sgs - 1]; ++ else ++ sg_req = &chan->desc->sg_req[chan->next_sg - 1]; ++ ++ ndtr = sg_req->chan_reg.dma_sndtr; ++ offset = (ndtr - chan_reg.dma_sndtr) << STM32_DMA_SCR_PSIZE_GET(chan_reg.dma_scr); ++ spar = sg_req->chan_reg.dma_spar; ++ sm0ar = sg_req->chan_reg.dma_sm0ar; ++ sm1ar = sg_req->chan_reg.dma_sm1ar; ++ ++ /* ++ * The peripheral and/or memory addresses have to be updated in order to adjust the ++ * address pointers. Need to check increment. ++ */ ++ if (chan_reg.dma_scr & STM32_DMA_SCR_PINC) ++ stm32_dma_write(dmadev, STM32_DMA_SPAR(id), spar + offset); ++ else ++ stm32_dma_write(dmadev, STM32_DMA_SPAR(id), spar); ++ ++ if (!(chan_reg.dma_scr & STM32_DMA_SCR_MINC)) ++ offset = 0; ++ ++ /* ++ * In case of DBM, the current target could be SM1AR. ++ * Need to temporarily deactivate CIRC/DBM to finish the current transfer, so ++ * SM0AR becomes the current target and must be updated with SM1AR + offset if CT=1. ++ */ ++ if ((chan_reg.dma_scr & STM32_DMA_SCR_DBM) && (chan_reg.dma_scr & STM32_DMA_SCR_CT)) ++ stm32_dma_write(dmadev, STM32_DMA_SM1AR(id), sm1ar + offset); ++ else ++ stm32_dma_write(dmadev, STM32_DMA_SM0AR(id), sm0ar + offset); ++ ++ /* NDTR must be restored otherwise internal HW counter won't be correctly reset */ ++ stm32_dma_write(dmadev, STM32_DMA_SNDTR(id), chan_reg.dma_sndtr); ++ ++ /* ++ * Need to temporarily deactivate CIRC/DBM until next Transfer Complete interrupt, ++ * otherwise NDTR autoreload value will be wrong (lower than the initial period length ++ */ ++ if (chan_reg.dma_scr & (STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM)) { ++ chan_reg.dma_scr &= ~(STM32_DMA_SCR_CIRC | STM32_DMA_SCR_DBM); ++ stm32_dma_write(dmadev, STM32_DMA_SCR(id), chan_reg.dma_scr); ++ } ++ ++ stm32_dma_dump_reg(chan); ++ ++ /* The stream may then be re-enabled to restart transfer from the point it was stopped */ ++ chan->status = DMA_IN_PROGRESS; ++ chan_reg.dma_scr |= STM32_DMA_SCR_EN; ++ stm32_dma_write(dmadev, STM32_DMA_SCR(id), chan_reg.dma_scr); ++ ++ spin_unlock_irqrestore(&chan->vchan.lock, flags); ++ ++ dev_dbg(chan2dev(chan), "vchan %pK: resumed\n", &chan->vchan); ++ ++ return 0; } static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, @@ -780,7 +987,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 { enum dma_slave_buswidth src_addr_width, dst_addr_width; int src_bus_width, dst_bus_width; -@@ -735,14 +1146,21 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -735,14 +1346,21 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, return dst_burst_size; /* Set memory data size */ @@ -805,7 +1012,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 src_best_burst = stm32_dma_get_best_burst(buf_len, src_maxburst, fifoth, -@@ -784,14 +1202,21 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, +@@ -784,14 +1402,21 @@ static int stm32_dma_set_xfer_param(struct stm32_dma_chan *chan, return src_burst_size; /* Set memory data size */ @@ -830,7 +1037,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 dst_best_burst = stm32_dma_get_best_burst(buf_len, dst_maxburst, fifoth, -@@ -838,6 +1263,162 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) +@@ -838,6 +1463,162 @@ static void stm32_dma_clear_reg(struct stm32_dma_chan_reg *regs) memset(regs, 0, sizeof(struct stm32_dma_chan_reg)); } @@ -993,7 +1200,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( struct dma_chan *c, struct scatterlist *sgl, u32 sg_len, enum dma_transfer_direction direction, -@@ -845,9 +1426,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -845,9 +1626,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); struct stm32_dma_desc *desc; @@ -1003,7 +1210,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 int i, ret; if (!chan->config_init) { -@@ -870,48 +1448,140 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( +@@ -870,48 +1648,140 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_slave_sg( else chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -1012,12 +1219,12 @@ index d0055d2f0b9a..1d89e0807ef0 100644 - sg_dma_len(sg)); - if (ret < 0) - goto err; +- +- desc->sg_req[i].len = sg_dma_len(sg); + if (chan->use_mdma) { + struct sg_table new_sgt; + struct scatterlist *s, *_sgl; -- desc->sg_req[i].len = sg_dma_len(sg); -- - nb_data_items = desc->sg_req[i].len / buswidth; - if (nb_data_items > STM32_DMA_ALIGNED_MAX_DATA_ITEMS) { - dev_err(chan2dev(chan), "nb items not supported\n"); @@ -1164,7 +1371,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 int i, ret; if (!buf_len || !period_len) { -@@ -940,7 +1610,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -940,7 +1810,7 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( return NULL; } @@ -1173,7 +1380,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 if (ret < 0) return NULL; -@@ -959,28 +1629,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( +@@ -959,28 +1829,49 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_cyclic( /* Clear periph ctrl if client set it */ chan->chan_reg.dma_scr &= ~STM32_DMA_SCR_PFCTRL; @@ -1191,7 +1398,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 - desc->sg_req[i].len = period_len; + desc->num_sgs = num_periods; + desc->cyclic = true; - ++ + if (chan->use_mdma) { + chan->mchan.dir = direction; + @@ -1203,7 +1410,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + } else { + dma_buf = buf_addr; + } -+ + + for (i = 0; i < num_periods; i++) { + sg_dma_len(&desc->sg_req[i].stm32_sgl_req) = period_len; + sg_dma_address(&desc->sg_req[i].stm32_sgl_req) = dma_buf; @@ -1235,7 +1442,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } -@@ -1021,13 +1712,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1021,13 +1912,13 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( STM32_DMA_SCR_PINC | STM32_DMA_SCR_TCIE | STM32_DMA_SCR_TEIE; @@ -1251,7 +1458,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 } desc->num_sgs = num_sgs; -@@ -1036,18 +1727,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( +@@ -1036,18 +1927,6 @@ static struct dma_async_tx_descriptor *stm32_dma_prep_dma_memcpy( return vchan_tx_prep(&chan->vchan, &desc->vdesc, flags); } @@ -1270,7 +1477,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 /** * stm32_dma_is_current_sg - check that expected sg_req is currently transferred * @chan: dma channel -@@ -1094,6 +1773,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1094,6 +1973,10 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, struct stm32_dma_sg_req *sg_req = &chan->desc->sg_req[chan->next_sg]; int i; @@ -1281,7 +1488,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 /* * Calculate the residue means compute the descriptors * information: -@@ -1125,7 +1808,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1125,7 +2008,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, n_sg++; if (n_sg == chan->desc->num_sgs) n_sg = 0; @@ -1290,7 +1497,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 } /* -@@ -1137,7 +1820,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, +@@ -1137,7 +2020,7 @@ static size_t stm32_dma_desc_residue(struct stm32_dma_chan *chan, */ if (!chan->desc->cyclic || n_sg != 0) for (i = n_sg; i < desc->num_sgs; i++) @@ -1299,7 +1506,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 if (!chan->mem_burst) return residue; -@@ -1155,11 +1838,23 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, +@@ -1155,13 +2038,30 @@ static enum dma_status stm32_dma_tx_status(struct dma_chan *c, struct dma_tx_state *state) { struct stm32_dma_chan *chan = to_stm32_dma_chan(c); @@ -1321,9 +1528,17 @@ index d0055d2f0b9a..1d89e0807ef0 100644 + state); + status = dma_cookie_status(c, cookie, state); - if (status == DMA_COMPLETE || !state) +- if (status == DMA_COMPLETE || !state) ++ if (status == DMA_COMPLETE) ++ return status; ++ ++ status = chan->status; ++ ++ if (!state) return status; -@@ -1216,27 +1911,53 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) + + spin_lock_irqsave(&chan->vchan.lock, flags); +@@ -1216,27 +2116,53 @@ static void stm32_dma_free_chan_resources(struct dma_chan *c) pm_runtime_put(dmadev->ddev.dev); vchan_free_chan_resources(to_virt_chan(c)); @@ -1382,7 +1597,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 } static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, -@@ -1274,6 +1995,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, +@@ -1274,6 +2200,9 @@ static struct dma_chan *stm32_dma_of_xlate(struct of_phandle_args *dma_spec, stm32_dma_set_config(chan, &cfg); @@ -1392,7 +1607,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 return c; } -@@ -1286,11 +2010,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); +@@ -1286,11 +2215,13 @@ MODULE_DEVICE_TABLE(of, stm32_dma_of_match); static int stm32_dma_probe(struct platform_device *pdev) { struct stm32_dma_chan *chan; @@ -1406,7 +1621,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 int i, ret; match = of_match_device(stm32_dma_of_match, &pdev->dev); -@@ -1334,6 +2060,13 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1334,6 +2265,13 @@ static int stm32_dma_probe(struct platform_device *pdev) reset_control_deassert(rst); } @@ -1420,7 +1635,18 @@ index d0055d2f0b9a..1d89e0807ef0 100644 dma_set_max_seg_size(&pdev->dev, STM32_DMA_ALIGNED_MAX_DATA_ITEMS); dma_cap_set(DMA_SLAVE, dd->cap_mask); -@@ -1373,11 +2106,27 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1345,7 +2283,10 @@ static int stm32_dma_probe(struct platform_device *pdev) + dd->device_issue_pending = stm32_dma_issue_pending; + dd->device_prep_slave_sg = stm32_dma_prep_slave_sg; + dd->device_prep_dma_cyclic = stm32_dma_prep_dma_cyclic; ++ dd->device_caps = stm32_dma_slave_caps; + dd->device_config = stm32_dma_slave_config; ++ dd->device_pause = stm32_dma_pause; ++ dd->device_resume = stm32_dma_resume; + dd->device_terminate_all = stm32_dma_terminate_all; + dd->device_synchronize = stm32_dma_synchronize; + dd->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | +@@ -1373,11 +2314,27 @@ static int stm32_dma_probe(struct platform_device *pdev) chan->id = i; chan->vchan.desc_free = stm32_dma_desc_free; vchan_init(&chan->vchan, dd); @@ -1449,7 +1675,7 @@ index d0055d2f0b9a..1d89e0807ef0 100644 for (i = 0; i < STM32_DMA_MAX_CHANNELS; i++) { chan = &dmadev->chan[i]; -@@ -1418,6 +2167,10 @@ static int stm32_dma_probe(struct platform_device *pdev) +@@ -1418,6 +2375,10 @@ static int stm32_dma_probe(struct platform_device *pdev) err_unregister: dma_async_device_unregister(dd); @@ -1460,14 +1686,40 @@ index d0055d2f0b9a..1d89e0807ef0 100644 clk_free: clk_disable_unprepare(dmadev->clk); -@@ -1499,4 +2252,4 @@ static int __init stm32_dma_init(void) +@@ -1450,7 +2411,7 @@ static int stm32_dma_runtime_resume(struct device *dev) + #endif + + #ifdef CONFIG_PM_SLEEP +-static int stm32_dma_suspend(struct device *dev) ++static int stm32_dma_pm_suspend(struct device *dev) + { + struct stm32_dma_device *dmadev = dev_get_drvdata(dev); + int id, ret, scr; +@@ -1474,14 +2435,14 @@ static int stm32_dma_suspend(struct device *dev) + return 0; + } + +-static int stm32_dma_resume(struct device *dev) ++static int stm32_dma_pm_resume(struct device *dev) + { + return pm_runtime_force_resume(dev); + } + #endif + + static const struct dev_pm_ops stm32_dma_pm_ops = { +- SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_suspend, stm32_dma_resume) ++ SET_SYSTEM_SLEEP_PM_OPS(stm32_dma_pm_suspend, stm32_dma_pm_resume) + SET_RUNTIME_PM_OPS(stm32_dma_runtime_suspend, + stm32_dma_runtime_resume, NULL) + }; +@@ -1499,4 +2460,4 @@ static int __init stm32_dma_init(void) { return platform_driver_register(&stm32_dma_driver); } -subsys_initcall(stm32_dma_init); +device_initcall(stm32_dma_init); diff --git a/drivers/dma/stm32-mdma.c b/drivers/dma/stm32-mdma.c -index 08cfbfab837b..a4b25944fba4 100644 +index 9d4739237..88e521bbd 100644 --- a/drivers/dma/stm32-mdma.c +++ b/drivers/dma/stm32-mdma.c @@ -199,7 +199,9 @@ @@ -1863,7 +2115,7 @@ index 08cfbfab837b..a4b25944fba4 100644 if (config.request >= dmadev->nr_requests) { dev_err(mdma2dev(dmadev), "Bad request line\n"); diff --git a/include/linux/dmaengine.h b/include/linux/dmaengine.h -index dd357a747780..42745f58412c 100644 +index dd357a747..42745f584 100644 --- a/include/linux/dmaengine.h +++ b/include/linux/dmaengine.h @@ -1474,9 +1474,11 @@ struct dma_chan *__dma_request_channel(const dma_cap_mask_t *mask, diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0006-ARM-5.10.10-stm32mp1-r1-DRM.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch similarity index 53% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0006-ARM-5.10.10-stm32mp1-r1-DRM.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch index 14038a2..ca683bc 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0006-ARM-5.10.10-stm32mp1-r1-DRM.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch @@ -1,23 +1,31 @@ -From fe6c762c8d16cddae0a0fd5673f7ab8c6b06f4e5 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:01:48 +0100 -Subject: [PATCH 06/22] ARM 5.10.10-stm32mp1-r1 DRM +From 6d9c0eb22dc7c3fbe05bbb000a5d35d0fd1168ab Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:43 +0200 +Subject: [PATCH 06/23] ARM 5.10.61-stm32mp1-r2 DRM --- drivers/gpu/drm/bridge/sii902x.c | 100 +++++++++- drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c | 172 ++++++++++++++---- + drivers/gpu/drm/drm_atomic_state_helper.c | 1 + + drivers/gpu/drm/drm_atomic_uapi.c | 4 + + drivers/gpu/drm/drm_blend.c | 34 +++- + drivers/gpu/drm/drm_mode_config.c | 6 + drivers/gpu/drm/drm_modes.c | 19 +- - .../gpu/drm/panel/panel-orisetech-otm8009a.c | 24 +-- - drivers/gpu/drm/panel/panel-raydium-rm68200.c | 17 +- - drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 3 +- - drivers/gpu/drm/stm/ltdc.c | 72 +++++--- + .../gpu/drm/panel/panel-orisetech-otm8009a.c | 119 +++++++----- + drivers/gpu/drm/panel/panel-raydium-rm68200.c | 21 ++- + drivers/gpu/drm/stm/drv.c | 5 + + drivers/gpu/drm/stm/dw_mipi_dsi-stm.c | 20 +- + drivers/gpu/drm/stm/ltdc.c | 169 +++++++++++------ drivers/input/touchscreen/edt-ft5x06.c | 18 +- drivers/input/touchscreen/goodix.c | 15 ++ - include/uapi/drm/drm_mode.h | 6 + - 10 files changed, 346 insertions(+), 100 deletions(-) + include/drm/drm_blend.h | 1 + + include/drm/drm_crtc.h | 12 ++ + include/drm/drm_mode_config.h | 5 + + include/uapi/drm/drm_mode.h | 34 ++++ + 18 files changed, 591 insertions(+), 164 deletions(-) diff --git a/drivers/gpu/drm/bridge/sii902x.c b/drivers/gpu/drm/bridge/sii902x.c -index 89558e581530..69208ead5384 100644 +index 89558e581..69208ead5 100644 --- a/drivers/gpu/drm/bridge/sii902x.c +++ b/drivers/gpu/drm/bridge/sii902x.c @@ -16,6 +16,7 @@ @@ -203,7 +211,7 @@ index 89558e581530..69208ead5384 100644 .id_table = sii902x_i2c_ids, }; diff --git a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c -index 6b268f9445b3..25b63491135f 100644 +index 6b268f944..25b634911 100644 --- a/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c +++ b/drivers/gpu/drm/bridge/synopsys/dw-mipi-dsi.c @@ -213,6 +213,20 @@ @@ -471,8 +479,115 @@ index 6b268f9445b3..25b63491135f 100644 mipi_dsi_host_unregister(&dsi->dsi_host); pm_runtime_disable(dsi->dev); +diff --git a/drivers/gpu/drm/drm_atomic_state_helper.c b/drivers/gpu/drm/drm_atomic_state_helper.c +index 9ad740451..ae89e8134 100644 +--- a/drivers/gpu/drm/drm_atomic_state_helper.c ++++ b/drivers/gpu/drm/drm_atomic_state_helper.c +@@ -72,6 +72,7 @@ __drm_atomic_helper_crtc_state_reset(struct drm_crtc_state *crtc_state, + struct drm_crtc *crtc) + { + crtc_state->crtc = crtc; ++ crtc_state->bgcolor = drm_argb(16, 0xffff, 0, 0, 0); + } + EXPORT_SYMBOL(__drm_atomic_helper_crtc_state_reset); + +diff --git a/drivers/gpu/drm/drm_atomic_uapi.c b/drivers/gpu/drm/drm_atomic_uapi.c +index 25c269bc4..569f5d364 100644 +--- a/drivers/gpu/drm/drm_atomic_uapi.c ++++ b/drivers/gpu/drm/drm_atomic_uapi.c +@@ -469,6 +469,8 @@ static int drm_atomic_crtc_set_property(struct drm_crtc *crtc, + return -EFAULT; + + set_out_fence_for_crtc(state->state, crtc, fence_ptr); ++ } else if (property == config->bgcolor_property) { ++ state->bgcolor = val; + } else if (crtc->funcs->atomic_set_property) { + return crtc->funcs->atomic_set_property(crtc, state, property, val); + } else { +@@ -503,6 +505,8 @@ drm_atomic_crtc_get_property(struct drm_crtc *crtc, + *val = (state->gamma_lut) ? state->gamma_lut->base.id : 0; + else if (property == config->prop_out_fence_ptr) + *val = 0; ++ else if (property == config->bgcolor_property) ++ *val = state->bgcolor; + else if (crtc->funcs->atomic_get_property) + return crtc->funcs->atomic_get_property(crtc, state, property, val); + else +diff --git a/drivers/gpu/drm/drm_blend.c b/drivers/gpu/drm/drm_blend.c +index f1dcad96f..1e786abc6 100644 +--- a/drivers/gpu/drm/drm_blend.c ++++ b/drivers/gpu/drm/drm_blend.c +@@ -185,6 +185,21 @@ + * plane does not expose the "alpha" property, then this is + * assumed to be 1.0 + * ++ * BACKGROUND_COLOR: ++ * Defines the ARGB color of a full-screen layer that exists below all ++ * planes. This color will be used for pixels not covered by any plane ++ * and may also be blended with plane contents as allowed by a plane's ++ * alpha values. The background color defaults to black, and is assumed ++ * to be black for drivers that do not expose this property. Although ++ * background color isn't a plane, it is assumed that the color provided ++ * here undergoes the same pipe-level degamma/CSC/gamma transformations ++ * that planes undergo. Note that the color value provided here includes ++ * an alpha channel...non-opaque background color values are allowed, ++ * but are generally only honored in special cases (e.g., when a memory ++ * writeback connector is in use). ++ * ++ * This property is setup with drm_crtc_add_bgcolor_property(). ++ * + * IN_FORMATS: + * Blob property which contains the set of buffer format and modifier + * pairs supported by this plane. The blob is a drm_format_modifier_blob +@@ -192,8 +207,7 @@ + * modifiers. Userspace cannot change this property. + * + * Note that all the property extensions described here apply either to the +- * plane or the CRTC (e.g. for the background color, which currently is not +- * exposed and assumed to be black). ++ * plane or the CRTC. + */ + + /** +@@ -609,3 +623,19 @@ int drm_plane_create_blend_mode_property(struct drm_plane *plane, + return 0; + } + EXPORT_SYMBOL(drm_plane_create_blend_mode_property); ++ ++/** ++ * drm_crtc_add_bgcolor_property - add background color property ++ * @crtc: drm crtc ++ * ++ * Adds the background color property to @crtc. The property defaults to ++ * solid black and will accept 64-bit ARGB values in the format generated by ++ * drm_argb(). ++ */ ++void drm_crtc_add_bgcolor_property(struct drm_crtc *crtc) ++{ ++ drm_object_attach_property(&crtc->base, ++ crtc->dev->mode_config.bgcolor_property, ++ drm_argb(16, 0xffff, 0, 0, 0)); ++} ++EXPORT_SYMBOL(drm_crtc_add_bgcolor_property); +diff --git a/drivers/gpu/drm/drm_mode_config.c b/drivers/gpu/drm/drm_mode_config.c +index f1affc1bb..845091106 100644 +--- a/drivers/gpu/drm/drm_mode_config.c ++++ b/drivers/gpu/drm/drm_mode_config.c +@@ -371,6 +371,12 @@ static int drm_mode_create_standard_properties(struct drm_device *dev) + return -ENOMEM; + dev->mode_config.modifiers_property = prop; + ++ prop = drm_property_create_range(dev, 0, "BACKGROUND_COLOR", ++ 0, GENMASK_ULL(63, 0)); ++ if (!prop) ++ return -ENOMEM; ++ dev->mode_config.bgcolor_property = prop; ++ + return 0; + } + diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c -index 501b4fe55a3d..125aab6b12e8 100644 +index 511cde5c7..58ab4a543 100644 --- a/drivers/gpu/drm/drm_modes.c +++ b/drivers/gpu/drm/drm_modes.c @@ -127,7 +127,7 @@ EXPORT_SYMBOL(drm_mode_probed_add); @@ -516,10 +631,69 @@ index 501b4fe55a3d..125aab6b12e8 100644 EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode); diff --git a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -index 6ac1accade80..da0970ca98f8 100644 +index 6ac1accad..70b2bb72d 100644 --- a/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c +++ b/drivers/gpu/drm/panel/panel-orisetech-otm8009a.c -@@ -99,20 +99,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, +@@ -60,6 +60,9 @@ + #define MCS_CMD2_ENA1 0xFF00 /* Enable Access Command2 "CMD2" */ + #define MCS_CMD2_ENA2 0xFF80 /* Enable Access Orise Command2 */ + ++#define OTM8009A_HDISPLAY 480 ++#define OTM8009A_VDISPLAY 800 ++ + struct otm8009a { + struct device *dev; + struct drm_panel panel; +@@ -70,19 +73,35 @@ struct otm8009a { + bool enabled; + }; + +-static const struct drm_display_mode default_mode = { +- .clock = 29700, +- .hdisplay = 480, +- .hsync_start = 480 + 98, +- .hsync_end = 480 + 98 + 32, +- .htotal = 480 + 98 + 32 + 98, +- .vdisplay = 800, +- .vsync_start = 800 + 15, +- .vsync_end = 800 + 15 + 10, +- .vtotal = 800 + 15 + 10 + 14, +- .flags = 0, +- .width_mm = 52, +- .height_mm = 86, ++static const struct drm_display_mode modes[] = { ++ { /* 50 Hz, preferred */ ++ .clock = 29700, ++ .hdisplay = 480, ++ .hsync_start = 480 + 98, ++ .hsync_end = 480 + 98 + 32, ++ .htotal = 480 + 98 + 32 + 98, ++ .vdisplay = 800, ++ .vsync_start = 800 + 15, ++ .vsync_end = 800 + 15 + 10, ++ .vtotal = 800 + 15 + 10 + 14, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, ++ .width_mm = 52, ++ .height_mm = 86, ++ }, ++ { /* 60 Hz */ ++ .clock = 33000, ++ .hdisplay = 480, ++ .hsync_start = 480 + 70, ++ .hsync_end = 480 + 70 + 32, ++ .htotal = 480 + 70 + 32 + 72, ++ .vdisplay = 800, ++ .vsync_start = 800 + 15, ++ .vsync_end = 800 + 15 + 10, ++ .vtotal = 800 + 15 + 10 + 16, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, ++ .width_mm = 52, ++ .height_mm = 86, ++ }, + }; + + static inline struct otm8009a *panel_to_otm8009a(struct drm_panel *panel) +@@ -99,20 +118,6 @@ static void otm8009a_dcs_write_buf(struct otm8009a *ctx, const void *data, dev_warn(ctx->dev, "mipi dsi dcs write buffer failed\n"); } @@ -540,7 +714,71 @@ index 6ac1accade80..da0970ca98f8 100644 #define dcs_write_seq(ctx, seq...) \ ({ \ static const u8 d[] = { seq }; \ -@@ -400,7 +386,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) +@@ -222,12 +227,11 @@ static int otm8009a_init_sequence(struct otm8009a *ctx) + /* Default portrait 480x800 rgb24 */ + dcs_write_seq(ctx, MIPI_DCS_SET_ADDRESS_MODE, 0x00); + +- ret = mipi_dsi_dcs_set_column_address(dsi, 0, +- default_mode.hdisplay - 1); ++ ret = mipi_dsi_dcs_set_column_address(dsi, 0, OTM8009A_HDISPLAY - 1); + if (ret) + return ret; + +- ret = mipi_dsi_dcs_set_page_address(dsi, 0, default_mode.vdisplay - 1); ++ ret = mipi_dsi_dcs_set_page_address(dsi, 0, OTM8009A_VDISPLAY - 1); + if (ret) + return ret; + +@@ -351,24 +355,35 @@ static int otm8009a_get_modes(struct drm_panel *panel, + struct drm_connector *connector) + { + struct drm_display_mode *mode; +- +- mode = drm_mode_duplicate(connector->dev, &default_mode); +- if (!mode) { +- dev_err(panel->dev, "failed to add mode %ux%u@%u\n", +- default_mode.hdisplay, default_mode.vdisplay, +- drm_mode_vrefresh(&default_mode)); +- return -ENOMEM; ++ unsigned int num_modes = ARRAY_SIZE(modes); ++ unsigned int i; ++ ++ for (i = 0; i < num_modes; i++) { ++ mode = drm_mode_duplicate(connector->dev, &modes[i]); ++ if (!mode) { ++ dev_err(panel->dev, "failed to add mode %ux%u@%u\n", ++ modes[i].hdisplay, ++ modes[i].vdisplay, ++ drm_mode_vrefresh(&modes[i])); ++ return -ENOMEM; ++ } ++ ++ mode->type = DRM_MODE_TYPE_DRIVER; ++ ++ /* Setting first mode as preferred */ ++ if (!i) ++ mode->type |= DRM_MODE_TYPE_PREFERRED; ++ ++ drm_mode_set_name(mode); ++ drm_mode_probed_add(connector, mode); + } + +- drm_mode_set_name(mode); +- +- mode->type = DRM_MODE_TYPE_DRIVER | DRM_MODE_TYPE_PREFERRED; +- drm_mode_probed_add(connector, mode); +- + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; ++ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | ++ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; + +- return 1; ++ return num_modes; + } + + static const struct drm_panel_funcs otm8009a_drm_funcs = { +@@ -400,7 +415,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) */ data[0] = MIPI_DCS_SET_DISPLAY_BRIGHTNESS; data[1] = bd->props.brightness; @@ -549,7 +787,7 @@ index 6ac1accade80..da0970ca98f8 100644 /* set Brightness Control & Backlight on */ data[1] = 0x24; -@@ -412,7 +398,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) +@@ -412,7 +427,7 @@ static int otm8009a_backlight_update_status(struct backlight_device *bd) /* Update Brightness Control & Backlight */ data[0] = MIPI_DCS_WRITE_CONTROL_DISPLAY; @@ -558,7 +796,7 @@ index 6ac1accade80..da0970ca98f8 100644 return 0; } -@@ -433,8 +419,10 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) +@@ -433,8 +448,18 @@ static int otm8009a_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { @@ -568,14 +806,22 @@ index 6ac1accade80..da0970ca98f8 100644 + if (ret != -EPROBE_DEFER) + dev_err(dev, "cannot get reset GPIO: %d\n", ret); + return ret; ++ } ++ ++ /* Reset the panel to avoid visual artifacts */ ++ if (ctx->reset_gpio) { ++ gpiod_set_value_cansleep(ctx->reset_gpio, 0); ++ gpiod_set_value_cansleep(ctx->reset_gpio, 1); ++ msleep(20); ++ gpiod_set_value_cansleep(ctx->reset_gpio, 0); } ctx->supply = devm_regulator_get(dev, "power"); diff --git a/drivers/gpu/drm/panel/panel-raydium-rm68200.c b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -index f908eeafb1af..74fa3596618d 100644 +index f908eeafb..d5542266e 100644 --- a/drivers/gpu/drm/panel/panel-raydium-rm68200.c +++ b/drivers/gpu/drm/panel/panel-raydium-rm68200.c -@@ -82,15 +82,15 @@ struct rm68200 { +@@ -82,16 +82,16 @@ struct rm68200 { }; static const struct drm_display_mode default_mode = { @@ -592,12 +838,23 @@ index f908eeafb1af..74fa3596618d 100644 .vsync_start = 1280 + 12, - .vsync_end = 1280 + 12 + 4, - .vtotal = 1280 + 12 + 4 + 12, +- .flags = 0, + .vsync_end = 1280 + 12 + 5, + .vtotal = 1280 + 12 + 5 + 12, - .flags = 0, ++ .flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, .width_mm = 68, .height_mm = 122, -@@ -372,7 +372,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) + }; +@@ -347,6 +347,8 @@ static int rm68200_get_modes(struct drm_panel *panel, + + connector->display_info.width_mm = mode->width_mm; + connector->display_info.height_mm = mode->height_mm; ++ connector->display_info.bus_flags = DRM_BUS_FLAG_DE_HIGH | ++ DRM_BUS_FLAG_PIXDATA_DRIVE_POSEDGE; + + return 1; + } +@@ -372,7 +374,8 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) ctx->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(ctx->reset_gpio)) { ret = PTR_ERR(ctx->reset_gpio); @@ -607,7 +864,7 @@ index f908eeafb1af..74fa3596618d 100644 return ret; } -@@ -391,7 +392,7 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) +@@ -391,7 +394,7 @@ static int rm68200_probe(struct mipi_dsi_device *dsi) dsi->lanes = 2; dsi->format = MIPI_DSI_FMT_RGB888; dsi->mode_flags = MIPI_DSI_MODE_VIDEO | MIPI_DSI_MODE_VIDEO_BURST | @@ -616,11 +873,55 @@ index f908eeafb1af..74fa3596618d 100644 drm_panel_init(&ctx->panel, dev, &rm68200_drm_funcs, DRM_MODE_CONNECTOR_DSI); +diff --git a/drivers/gpu/drm/stm/drv.c b/drivers/gpu/drm/stm/drv.c +index 411103f01..0f2383026 100644 +--- a/drivers/gpu/drm/stm/drv.c ++++ b/drivers/gpu/drm/stm/drv.c +@@ -193,6 +193,11 @@ static int stm_drm_platform_probe(struct platform_device *pdev) + if (ret) + goto err_put; + ++ ret = drm_fb_helper_remove_conflicting_framebuffers(NULL, "stmdrmfb", ++ false); ++ if (ret) ++ goto err_put; ++ + ret = drm_dev_register(ddev, 0); + if (ret) + goto err_put; diff --git a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -index 2e1f2664495d..164f79ef6269 100644 +index 2e1f26644..87f894ea3 100644 --- a/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c +++ b/drivers/gpu/drm/stm/dw_mipi_dsi-stm.c -@@ -419,7 +419,8 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) +@@ -309,14 +309,23 @@ dw_mipi_dsi_get_lane_mbps(void *priv_data, const struct drm_display_mode *mode, + return 0; + } + ++#define DSI_PHY_DELAY(fp, vp, mbps) DIV_ROUND_UP((fp) * (mbps) + 1000 * (vp), 8000) ++ + static int + dw_mipi_dsi_phy_get_timing(void *priv_data, unsigned int lane_mbps, + struct dw_mipi_dsi_dphy_timing *timing) + { +- timing->clk_hs2lp = 0x40; +- timing->clk_lp2hs = 0x40; +- timing->data_hs2lp = 0x40; +- timing->data_lp2hs = 0x40; ++ /* ++ * From STM32MP157 datasheet, valid for STM32F469, STM32F7x9, STM32H747 ++ * phy_clkhs2lp_time = (272+136*UI)/(8*UI) ++ * phy_clklp2hs_time = (512+40*UI)/(8*UI) ++ * phy_hs2lp_time = (192+64*UI)/(8*UI) ++ * phy_lp2hs_time = (256+32*UI)/(8*UI) ++ */ ++ timing->clk_hs2lp = DSI_PHY_DELAY(272, 136, lane_mbps); ++ timing->clk_lp2hs = DSI_PHY_DELAY(512, 40, lane_mbps); ++ timing->data_hs2lp = DSI_PHY_DELAY(192, 64, lane_mbps); ++ timing->data_lp2hs = DSI_PHY_DELAY(256, 32, lane_mbps); + + return 0; + } +@@ -419,7 +428,8 @@ static int dw_mipi_dsi_stm_probe(struct platform_device *pdev) dsi->dsi = dw_mipi_dsi_probe(pdev, &dw_mipi_dsi_stm_plat_data); if (IS_ERR(dsi->dsi)) { ret = PTR_ERR(dsi->dsi); @@ -631,10 +932,139 @@ index 2e1f2664495d..164f79ef6269 100644 } diff --git a/drivers/gpu/drm/stm/ltdc.c b/drivers/gpu/drm/stm/ltdc.c -index 6e28f707092f..308755aa7b95 100644 +index 62488ac14..a7c85a922 100644 --- a/drivers/gpu/drm/stm/ltdc.c +++ b/drivers/gpu/drm/stm/ltdc.c -@@ -724,22 +724,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, +@@ -195,6 +195,11 @@ + + #define NB_PF 8 /* Max nb of HW pixel format */ + ++#define DRM_ARGB_TO_LTDC_RGB24(bgcolor) \ ++ ((u32)(DRM_ARGB_RED(bgcolor, 8) << 16 \ ++ | DRM_ARGB_GREEN(bgcolor, 8) << 8 \ ++ | DRM_ARGB_BLUE(bgcolor, 8))) ++ + enum ltdc_pix_fmt { + PF_NONE, + /* RGB formats */ +@@ -363,6 +368,15 @@ static inline u32 get_pixelformat_without_alpha(u32 drm) + } + } + ++/* ++ * All non-alpha color formats derived from native alpha color formats are ++ * either characterized by a FourCC format code ++ */ ++static inline u32 is_xrgb(u32 drm) ++{ ++ return ((drm & 'X') == 'X' || (drm & ('X' << 8)) == ('X' << 8)); ++} ++ + static irqreturn_t ltdc_irq_thread(int irq, void *arg) + { + struct drm_device *ddev = arg; +@@ -430,7 +444,8 @@ static void ltdc_crtc_atomic_enable(struct drm_crtc *crtc, + pm_runtime_get_sync(ddev->dev); + + /* Sets the background color value */ +- reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); ++ reg_write(ldev->regs, LTDC_BCCR, ++ DRM_ARGB_TO_LTDC_RGB24(crtc->state->bgcolor)); + + /* Enable IRQ */ + reg_set(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); +@@ -451,6 +466,9 @@ static void ltdc_crtc_atomic_disable(struct drm_crtc *crtc, + + drm_crtc_vblank_off(crtc); + ++ /* Reset background color */ ++ reg_write(ldev->regs, LTDC_BCCR, BCCR_BCBLACK); ++ + /* disable IRQ */ + reg_clear(ldev->regs, LTDC_IER, IER_RRIE | IER_FUIE | IER_TERRIE); + +@@ -530,7 +548,6 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) + struct drm_encoder *encoder = NULL; + struct drm_bridge *bridge = NULL; + struct drm_display_mode *mode = &crtc->state->adjusted_mode; +- struct videomode vm; + u32 hsync, vsync, accum_hbp, accum_vbp, accum_act_w, accum_act_h; + u32 total_width, total_height; + u32 bus_flags = 0; +@@ -539,20 +556,17 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) + + /* get encoder from crtc */ + drm_for_each_encoder(encoder, ddev) +- if (encoder->crtc == crtc) +- break; ++ if (encoder->crtc == crtc) break; + + if (encoder) { + /* get bridge from encoder */ + list_for_each_entry(bridge, &encoder->bridge_chain, chain_node) +- if (bridge->encoder == encoder) +- break; ++ if (bridge->encoder == encoder) break; + + /* Get the connector from encoder */ + drm_connector_list_iter_begin(ddev, &iter); + drm_for_each_connector_iter(connector, &iter) +- if (connector->encoder == encoder) +- break; ++ if (connector->encoder == encoder) break; + drm_connector_list_iter_end(&iter); + } + +@@ -569,31 +583,33 @@ static void ltdc_crtc_mode_set_nofb(struct drm_crtc *crtc) + } + } + +- drm_display_mode_to_videomode(mode, &vm); +- + DRM_DEBUG_DRIVER("CRTC:%d mode:%s\n", crtc->base.id, mode->name); +- DRM_DEBUG_DRIVER("Video mode: %dx%d", vm.hactive, vm.vactive); ++ DRM_DEBUG_DRIVER("Video mode: %dx%d", mode->hdisplay, mode->vdisplay); + DRM_DEBUG_DRIVER(" hfp %d hbp %d hsl %d vfp %d vbp %d vsl %d\n", +- vm.hfront_porch, vm.hback_porch, vm.hsync_len, +- vm.vfront_porch, vm.vback_porch, vm.vsync_len); ++ mode->hsync_start - mode->hdisplay, ++ mode->htotal - mode->hsync_end, ++ mode->hsync_end - mode->hsync_start, ++ mode->vsync_start - mode->vdisplay, ++ mode->vtotal - mode->vsync_end, ++ mode->vsync_end - mode->vsync_start); + + /* Convert video timings to ltdc timings */ +- hsync = vm.hsync_len - 1; +- vsync = vm.vsync_len - 1; +- accum_hbp = hsync + vm.hback_porch; +- accum_vbp = vsync + vm.vback_porch; +- accum_act_w = accum_hbp + vm.hactive; +- accum_act_h = accum_vbp + vm.vactive; +- total_width = accum_act_w + vm.hfront_porch; +- total_height = accum_act_h + vm.vfront_porch; ++ hsync = mode->hsync_end - mode->hsync_start - 1; ++ vsync = mode->vsync_end - mode->vsync_start - 1; ++ accum_hbp = mode->htotal - mode->hsync_start - 1; ++ accum_vbp = mode->vtotal - mode->vsync_start - 1; ++ accum_act_w = accum_hbp + mode->hdisplay; ++ accum_act_h = accum_vbp + mode->vdisplay; ++ total_width = mode->htotal - 1; ++ total_height = mode->vtotal - 1; + + /* Configures the HS, VS, DE and PC polarities. Default Active Low */ + val = 0; + +- if (vm.flags & DISPLAY_FLAGS_HSYNC_HIGH) ++ if (mode->flags & DRM_MODE_FLAG_PHSYNC) + val |= GCR_HSPOL; + +- if (vm.flags & DISPLAY_FLAGS_VSYNC_HIGH) ++ if (mode->flags & DRM_MODE_FLAG_PVSYNC) + val |= GCR_VSPOL; + + if (bus_flags & DRM_BUS_FLAG_DE_LOW) +@@ -753,22 +769,44 @@ static int ltdc_plane_atomic_check(struct drm_plane *plane, struct drm_plane_state *state) { struct drm_framebuffer *fb = state->fb; @@ -656,10 +1086,7 @@ index 6e28f707092f..308755aa7b95 100644 + src->y1 = state->src_y >> 16; + src->x2 = (state->src_w >> 16) + src->x1 - 1; + src->y2 = (state->src_h >> 16) + src->y1 - 1; - -- /* Reject scaling */ -- if (src_w != state->crtc_w || src_h != state->crtc_h) { -- DRM_ERROR("Scaling is not supported"); ++ + dst->x1 = state->crtc_x; + dst->y1 = state->crtc_y; + dst->x2 = state->crtc_w + dst->x1 - 1; @@ -678,7 +1105,10 @@ index 6e28f707092f..308755aa7b95 100644 + if (crtc_state && (crtc_state->mode.hdisplay <= dst->x2 || + crtc_state->mode.vdisplay <= dst->y2)) + return -EINVAL; -+ + +- /* Reject scaling */ +- if (src_w != state->crtc_w || src_h != state->crtc_h) { +- DRM_ERROR("Scaling is not supported"); + /* source sizes do not have to exceed destination sizes */ + if (dst->x2 - dst->x1 < src->x2 - src->x1 || + dst->y2 - dst->y1 < src->y2 - src->y1) @@ -687,7 +1117,7 @@ index 6e28f707092f..308755aa7b95 100644 return 0; } -@@ -749,44 +771,36 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -778,44 +816,37 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, { struct ltdc_device *ldev = plane_to_ltdc(plane); struct drm_plane_state *state = plane->state; @@ -701,6 +1131,7 @@ index 6e28f707092f..308755aa7b95 100644 - u32 y1 = state->crtc_y + state->crtc_h - 1; - u32 src_x, src_y, src_w, src_h; u32 val, pitch_in_bytes, line_length, paddr, ahbp, avbp, bpcr; ++ u32 bgcolor = DRM_ARGB_TO_LTDC_RGB24(state->crtc->state->bgcolor); enum ltdc_pix_fmt pf; + struct drm_rect dr; @@ -742,7 +1173,7 @@ index 6e28f707092f..308755aa7b95 100644 reg_update_bits(ldev->regs, LTDC_L1WVPCR + lofs, LXWVPCR_WVSTPOS | LXWVPCR_WVSPPOS, val); -@@ -805,8 +819,8 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, +@@ -834,14 +865,14 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, /* Configures the color frame buffer pitch in bytes & line length */ pitch_in_bytes = fb->pitches[0]; @@ -753,7 +1184,45 @@ index 6e28f707092f..308755aa7b95 100644 val = ((pitch_in_bytes << 16) | line_length); reg_update_bits(ldev->regs, LTDC_L1CFBLR + lofs, LXCFBLR_CFBLL | LXCFBLR_CFBP, val); -@@ -829,7 +843,7 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, + + /* Specifies the constant alpha value */ +- val = CONSTA_MAX; ++ val = state->alpha >> 8; + reg_update_bits(ldev->regs, LTDC_L1CACR + lofs, LXCACR_CONSTA, val); + + /* Specifies the blending factors */ +@@ -849,16 +880,34 @@ static void ltdc_plane_atomic_update(struct drm_plane *plane, + if (!fb->format->has_alpha) + val = BF1_CA | BF2_1CA; + +- /* Manage hw-specific capabilities */ +- if (ldev->caps.non_alpha_only_l1 && +- plane->type != DRM_PLANE_TYPE_PRIMARY) +- val = BF1_PAXCA | BF2_1PAXCA; ++ /* ++ * Manage hw-specific capabilities ++ * ++ * Depending on the hardware version, the background color can not be ++ * properly displayed with non-alpha color formats derived from native ++ * alpha color formats (such as XR24 or XR15) since the use of this ++ * pixel format generates a non transparent layer. As a workaround, ++ * the stage background color of the layer and the general background ++ * color need to be synced. ++ * ++ * This is done by activating for all XRGB color format the default ++ * color as the background color and then setting blending factor ++ * accordingly. ++ */ ++ if (ldev->caps.non_alpha_only_l1) { ++ if (is_xrgb(fb->format->format)) { ++ val = BF1_CA | BF2_1CA; ++ reg_write(ldev->regs, LTDC_L1DCCR + lofs, bgcolor); ++ } else { ++ val = BF1_PAXCA | BF2_1PAXCA; ++ } ++ } + + reg_update_bits(ldev->regs, LTDC_L1BFCR + lofs, LXBFCR_BF2 | LXBFCR_BF1, val); /* Configures the frame buffer line number */ @@ -762,8 +1231,42 @@ index 6e28f707092f..308755aa7b95 100644 reg_update_bits(ldev->regs, LTDC_L1CFBLNR + lofs, LXCFBLNR_CFBLN, val); /* Sets the FB address */ +@@ -992,6 +1041,8 @@ static struct drm_plane *ltdc_plane_create(struct drm_device *ddev, + + drm_plane_helper_add(plane, <dc_plane_helper_funcs); + ++ drm_plane_create_alpha_property(plane); ++ + DRM_DEBUG_DRIVER("plane:%d created\n", plane->base.id); + + return plane; +@@ -1019,6 +1070,8 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) + return -EINVAL; + } + ++ drm_plane_create_zpos_immutable_property(primary, 0); ++ + ret = drm_crtc_init_with_planes(ddev, crtc, primary, NULL, + <dc_crtc_funcs, NULL); + if (ret) { +@@ -1028,6 +1081,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) + + drm_crtc_helper_add(crtc, <dc_crtc_helper_funcs); + ++ drm_crtc_add_bgcolor_property(crtc); + drm_mode_crtc_set_gamma_size(crtc, CLUT_SIZE); + drm_crtc_enable_color_mgmt(crtc, 0, false, CLUT_SIZE); + +@@ -1041,6 +1095,7 @@ static int ltdc_crtc_init(struct drm_device *ddev, struct drm_crtc *crtc) + DRM_ERROR("Can not create overlay plane %d\n", i); + goto cleanup; + } ++ drm_plane_create_zpos_immutable_property(overlay, i); + } + + return 0; diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c -index 6ff81d48da86..1643ddf5f65e 100644 +index 6ff81d48d..1643ddf5f 100644 --- a/drivers/input/touchscreen/edt-ft5x06.c +++ b/drivers/input/touchscreen/edt-ft5x06.c @@ -30,6 +30,8 @@ @@ -813,7 +1316,7 @@ index 6ff81d48da86..1643ddf5f65e 100644 dev_dbg(&client->dev, diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c -index 6612f9e2d7e8..dee33d8dd9f6 100644 +index a06385c55..388544f2d 100644 --- a/drivers/input/touchscreen/goodix.c +++ b/drivers/input/touchscreen/goodix.c @@ -21,6 +21,7 @@ @@ -824,7 +1327,7 @@ index 6612f9e2d7e8..dee33d8dd9f6 100644 #include #include #include -@@ -1204,6 +1205,8 @@ static int goodix_ts_probe(struct i2c_client *client, +@@ -1153,6 +1154,8 @@ static int goodix_ts_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct goodix_ts_data *ts; @@ -833,7 +1336,7 @@ index 6612f9e2d7e8..dee33d8dd9f6 100644 int error; dev_dbg(&client->dev, "I2C Address: 0x%02x\n", client->addr); -@@ -1303,6 +1306,17 @@ static int goodix_ts_probe(struct i2c_client *client, +@@ -1252,6 +1255,17 @@ static int goodix_ts_probe(struct i2c_client *client, return error; } @@ -851,7 +1354,7 @@ index 6612f9e2d7e8..dee33d8dd9f6 100644 return 0; } -@@ -1358,6 +1372,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) +@@ -1307,6 +1321,7 @@ static int __maybe_unused goodix_suspend(struct device *dev) * sooner, delay 58ms here. */ msleep(58); @@ -859,8 +1362,57 @@ index 6612f9e2d7e8..dee33d8dd9f6 100644 return 0; } +diff --git a/include/drm/drm_blend.h b/include/drm/drm_blend.h +index 88bdfec3b..9e2538dd7 100644 +--- a/include/drm/drm_blend.h ++++ b/include/drm/drm_blend.h +@@ -58,4 +58,5 @@ int drm_atomic_normalize_zpos(struct drm_device *dev, + struct drm_atomic_state *state); + int drm_plane_create_blend_mode_property(struct drm_plane *plane, + unsigned int supported_modes); ++void drm_crtc_add_bgcolor_property(struct drm_crtc *crtc); + #endif +diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h +index 59b51a09c..d6808aca9 100644 +--- a/include/drm/drm_crtc.h ++++ b/include/drm/drm_crtc.h +@@ -288,6 +288,18 @@ struct drm_crtc_state { + */ + struct drm_property_blob *gamma_lut; + ++ /** ++ * @bgcolor: ++ * ++ * RGB value representing the pipe's background color. The background ++ * color (aka "canvas color") of a pipe is the color that will be used ++ * for pixels not covered by a plane, or covered by transparent pixels ++ * of a plane. The value here should be built via drm_argb(); ++ * individual color components can be extracted with desired precision ++ * via the DRM_ARGB_*() macros. ++ */ ++ u64 bgcolor; ++ + /** + * @target_vblank: + * +diff --git a/include/drm/drm_mode_config.h b/include/drm/drm_mode_config.h +index a18f73eb3..3e37a3a19 100644 +--- a/include/drm/drm_mode_config.h ++++ b/include/drm/drm_mode_config.h +@@ -861,6 +861,11 @@ struct drm_mode_config { + */ + struct drm_property *hdcp_content_type_property; + ++ /** ++ * @bgcolor_property: RGB background color for CRTC. ++ */ ++ struct drm_property *bgcolor_property; ++ + /* dumb ioctl parameters */ + uint32_t preferred_depth, prefer_shadow; + diff --git a/include/uapi/drm/drm_mode.h b/include/uapi/drm/drm_mode.h -index 863eda048265..7d845d86a474 100644 +index 863eda048..5042afb3d 100644 --- a/include/uapi/drm/drm_mode.h +++ b/include/uapi/drm/drm_mode.h @@ -97,6 +97,12 @@ extern "C" { @@ -876,6 +1428,41 @@ index 863eda048265..7d845d86a474 100644 /* Picture aspect ratio options */ #define DRM_MODE_PICTURE_ASPECT_NONE 0 #define DRM_MODE_PICTURE_ASPECT_4_3 1 +@@ -1030,6 +1036,34 @@ struct drm_mode_rect { + __s32 y2; + }; + ++/* ++ * Put ARGB values into a standard 64-bit representation that can be used ++ * for ioctl parameters, inter-driver commmunication, etc. If the component ++ * values being provided contain less than 16 bits of precision, they'll ++ * be shifted into the most significant bits. ++ */ ++static inline __u64 ++drm_argb(__u8 bpc, __u16 alpha, __u16 red, __u16 green, __u16 blue) ++{ ++ int msb_shift = 16 - bpc; ++ ++ return (__u64)alpha << msb_shift << 48 | ++ (__u64)red << msb_shift << 32 | ++ (__u64)green << msb_shift << 16 | ++ (__u64)blue << msb_shift; ++} ++ ++/* ++ * Extract the specified number of bits of a specific color component from a ++ * standard 64-bit ARGB value. ++ */ ++#define DRM_ARGB_COMP(c, shift, numbits) \ ++ (__u16)(((c) & 0xFFFFull << (shift)) >> ((shift) + 16 - (numbits))) ++#define DRM_ARGB_BLUE(c, numbits) DRM_ARGB_COMP(c, 0, numbits) ++#define DRM_ARGB_GREEN(c, numbits) DRM_ARGB_COMP(c, 16, numbits) ++#define DRM_ARGB_RED(c, numbits) DRM_ARGB_COMP(c, 32, numbits) ++#define DRM_ARGB_ALPHA(c, numbits) DRM_ARGB_COMP(c, 48, numbits) ++ + #if defined(__cplusplus) + } + #endif -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0007-ARM-5.10.10-stm32mp1-r1-HWSPINLOCK.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0007-ARM-5.10.61-stm32mp1-r2-HWSPINLOCK.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0007-ARM-5.10.10-stm32mp1-r1-HWSPINLOCK.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0007-ARM-5.10.61-stm32mp1-r2-HWSPINLOCK.patch index 730272f..54b156d 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0007-ARM-5.10.10-stm32mp1-r1-HWSPINLOCK.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0007-ARM-5.10.61-stm32mp1-r2-HWSPINLOCK.patch @@ -1,9 +1,8 @@ -From 5c27ce1dc05fd740cc8f0f1d8072361ccab51a9f Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:02:36 +0100 -Subject: [PATCH 07/22] ARM 5.10.10-stm32mp1-r1 HWSPINLOCK +From e6689ed5bee01020d4f2411e92c3741a06232c92 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:43 +0200 +Subject: [PATCH 07/23] ARM 5.10.61-stm32mp1-r2 HWSPINLOCK -Signed-off-by: Romuald JEANNE --- Documentation/locking/hwspinlock.rst | 10 ++- drivers/hwspinlock/hwspinlock_core.c | 80 +++++++++++++++++++----- @@ -12,7 +11,7 @@ Signed-off-by: Romuald JEANNE 4 files changed, 110 insertions(+), 42 deletions(-) diff --git a/Documentation/locking/hwspinlock.rst b/Documentation/locking/hwspinlock.rst -index 6f03713b7003..605bd2dc8a03 100644 +index 6f03713b7..605bd2dc8 100644 --- a/Documentation/locking/hwspinlock.rst +++ b/Documentation/locking/hwspinlock.rst @@ -54,9 +54,11 @@ Should be called from a process context (might sleep). @@ -45,7 +44,7 @@ index 6f03713b7003..605bd2dc8a03 100644 }; diff --git a/drivers/hwspinlock/hwspinlock_core.c b/drivers/hwspinlock/hwspinlock_core.c -index fd5f5c5a5244..a2197af8973d 100644 +index fd5f5c5a5..a2197af89 100644 --- a/drivers/hwspinlock/hwspinlock_core.c +++ b/drivers/hwspinlock/hwspinlock_core.c @@ -29,6 +29,8 @@ @@ -230,7 +229,7 @@ index fd5f5c5a5244..a2197af8973d 100644 return ret; } diff --git a/drivers/hwspinlock/hwspinlock_internal.h b/drivers/hwspinlock/hwspinlock_internal.h -index 29892767bb7a..e1f9c9600635 100644 +index 29892767b..e1f9c9600 100644 --- a/drivers/hwspinlock/hwspinlock_internal.h +++ b/drivers/hwspinlock/hwspinlock_internal.h @@ -35,11 +35,13 @@ struct hwspinlock_ops { @@ -248,7 +247,7 @@ index 29892767bb7a..e1f9c9600635 100644 }; diff --git a/drivers/hwspinlock/stm32_hwspinlock.c b/drivers/hwspinlock/stm32_hwspinlock.c -index 3ad0ce0da4d9..6c3be33f3faf 100644 +index 3ad0ce0da..6c3be33f3 100644 --- a/drivers/hwspinlock/stm32_hwspinlock.c +++ b/drivers/hwspinlock/stm32_hwspinlock.c @@ -54,8 +54,23 @@ static const struct hwspinlock_ops stm32_hwspinlock_ops = { diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0008-ARM-5.10.10-stm32mp1-r1-I2C-IIO-IRQCHIP.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch similarity index 55% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0008-ARM-5.10.10-stm32mp1-r1-I2C-IIO-IRQCHIP.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch index 5f65372..0c30d3d 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0008-ARM-5.10.10-stm32mp1-r1-I2C-IIO-IRQCHIP.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch @@ -1,25 +1,25 @@ -From 1d88ececeebbbd2d3aa0ed971961074d1e2b71f4 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:05:39 +0100 -Subject: [PATCH 08/22] ARM 5.10.10-stm32mp1-r1 I2C-IIO-IRQCHIP +From fc843f64f154b843cd7834d6748b409ef1e1487f Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:44 +0200 +Subject: [PATCH 08/23] ARM 5.10.61-stm32mp1-r2 I2C-IIO-IRQCHIP -Signed-off-by: Romuald JEANNE --- - drivers/i2c/busses/i2c-stm32f7.c | 240 ++++++++++++++++++----------- - drivers/iio/adc/sd_adc_modulator.c | 89 +++++++++-- - drivers/iio/adc/stm32-adc-core.c | 21 ++- - drivers/iio/adc/stm32-adc.c | 29 +--- - drivers/iio/adc/stm32-dfsdm-adc.c | 105 ++++++++++++- - drivers/iio/adc/stm32-dfsdm-core.c | 91 +++++++++-- - drivers/iio/adc/stm32-dfsdm.h | 69 ++++++--- - drivers/irqchip/irq-stm32-exti.c | 83 ++++++++-- - 8 files changed, 555 insertions(+), 172 deletions(-) + drivers/i2c/busses/i2c-stm32f7.c | 285 +++++++++++------- + drivers/iio/adc/sd_adc_modulator.c | 89 +++++- + drivers/iio/adc/stm32-adc-core.c | 21 +- + drivers/iio/adc/stm32-adc-core.h | 8 + + drivers/iio/adc/stm32-adc.c | 445 ++++++++++++++++++++++++----- + drivers/iio/adc/stm32-dfsdm-adc.c | 108 ++++++- + drivers/iio/adc/stm32-dfsdm-core.c | 91 ++++-- + drivers/iio/adc/stm32-dfsdm.h | 69 +++-- + drivers/irqchip/irq-stm32-exti.c | 89 +++++- + 9 files changed, 973 insertions(+), 232 deletions(-) diff --git a/drivers/i2c/busses/i2c-stm32f7.c b/drivers/i2c/busses/i2c-stm32f7.c -index f41f51a176a1..b98ac0f4dee3 100644 +index 1e800b65e..0bc9acef2 100644 --- a/drivers/i2c/busses/i2c-stm32f7.c +++ b/drivers/i2c/busses/i2c-stm32f7.c -@@ -51,12 +51,15 @@ +@@ -51,6 +51,7 @@ /* STM32F7 I2C control 1 */ #define STM32F7_I2C_CR1_PECEN BIT(23) @@ -27,15 +27,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 #define STM32F7_I2C_CR1_SMBHEN BIT(20) #define STM32F7_I2C_CR1_WUPEN BIT(18) #define STM32F7_I2C_CR1_SBC BIT(16) - #define STM32F7_I2C_CR1_RXDMAEN BIT(15) - #define STM32F7_I2C_CR1_TXDMAEN BIT(14) - #define STM32F7_I2C_CR1_ANFOFF BIT(12) -+#define STM32F7_I2C_CR1_DNF_MASK GENMASK(11, 8) -+#define STM32F7_I2C_CR1_DNF(n) (((n) & 0xf) << 8) - #define STM32F7_I2C_CR1_ERRIE BIT(7) - #define STM32F7_I2C_CR1_TCIE BIT(6) - #define STM32F7_I2C_CR1_STOPIE BIT(5) -@@ -123,6 +126,7 @@ +@@ -125,6 +126,7 @@ (((n) & STM32F7_I2C_ISR_ADDCODE_MASK) >> 17) #define STM32F7_I2C_ISR_DIR BIT(16) #define STM32F7_I2C_ISR_BUSY BIT(15) @@ -43,7 +35,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 #define STM32F7_I2C_ISR_PECERR BIT(11) #define STM32F7_I2C_ISR_ARLO BIT(9) #define STM32F7_I2C_ISR_BERR BIT(8) -@@ -136,6 +140,7 @@ +@@ -138,6 +140,7 @@ #define STM32F7_I2C_ISR_TXE BIT(0) /* STM32F7 I2C Interrupt Clear */ @@ -51,19 +43,18 @@ index f41f51a176a1..b98ac0f4dee3 100644 #define STM32F7_I2C_ICR_PECCF BIT(11) #define STM32F7_I2C_ICR_ARLOCF BIT(9) #define STM32F7_I2C_ICR_BERRCF BIT(8) -@@ -159,10 +164,8 @@ enum { +@@ -161,10 +164,8 @@ enum { STM32F7_I2C_MAX_SLAVE }; -#define STM32F7_I2C_DNF_DEFAULT 0 --#define STM32F7_I2C_DNF_MAX 16 -+#define STM32F7_I2C_DNF_MAX 15 + #define STM32F7_I2C_DNF_MAX 15 -#define STM32F7_I2C_ANALOG_FILTER_ENABLE 1 #define STM32F7_I2C_ANALOG_FILTER_DELAY_MIN 50 /* ns */ #define STM32F7_I2C_ANALOG_FILTER_DELAY_MAX 260 /* ns */ -@@ -221,8 +224,6 @@ struct stm32f7_i2c_spec { +@@ -223,8 +224,6 @@ struct stm32f7_i2c_spec { * @clock_src: I2C clock source frequency (Hz) * @rise_time: Rise time (ns) * @fall_time: Fall time (ns) @@ -72,7 +63,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 * @fmp_clr_offset: Fast Mode Plus clear register offset from set register */ struct stm32f7_i2c_setup { -@@ -230,8 +231,6 @@ struct stm32f7_i2c_setup { +@@ -232,8 +231,6 @@ struct stm32f7_i2c_setup { u32 clock_src; u32 rise_time; u32 fall_time; @@ -81,7 +72,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 u32 fmp_clr_offset; }; -@@ -281,6 +280,17 @@ struct stm32f7_i2c_msg { +@@ -283,6 +280,17 @@ struct stm32f7_i2c_msg { u8 smbus_buf[I2C_SMBUS_BLOCK_MAX + 3] __aligned(4); }; @@ -99,7 +90,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 /** * struct stm32f7_i2c_dev - private data of the controller * @adap: I2C adapter for this controller -@@ -310,6 +320,10 @@ struct stm32f7_i2c_msg { +@@ -312,6 +320,10 @@ struct stm32f7_i2c_msg { * @wakeup_src: boolean to know if the device is a wakeup source * @smbus_mode: states that the controller is configured in SMBus mode * @host_notify_client: SMBus host-notify client @@ -110,7 +101,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 */ struct stm32f7_i2c_dev { struct i2c_adapter adap; -@@ -338,6 +352,10 @@ struct stm32f7_i2c_dev { +@@ -340,6 +352,10 @@ struct stm32f7_i2c_dev { bool wakeup_src; bool smbus_mode; struct i2c_client *host_notify_client; @@ -121,7 +112,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 }; /* -@@ -383,15 +401,11 @@ static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = { +@@ -385,15 +401,11 @@ static struct stm32f7_i2c_spec stm32f7_i2c_specs[] = { static const struct stm32f7_i2c_setup stm32f7_setup = { .rise_time = STM32F7_I2C_RISE_TIME_DEFAULT, .fall_time = STM32F7_I2C_FALL_TIME_DEFAULT, @@ -137,7 +128,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 .fmp_clr_offset = 0x40, }; -@@ -460,27 +474,28 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, +@@ -462,27 +474,28 @@ static int stm32f7_i2c_compute_timing(struct stm32f7_i2c_dev *i2c_dev, return -EINVAL; } @@ -173,7 +164,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 scldel_min = setup->rise_time + specs->sudat_min; -@@ -646,6 +661,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, +@@ -648,6 +661,7 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, setup->speed_freq = t->bus_freq_hz; i2c_dev->setup.rise_time = t->scl_rise_ns; i2c_dev->setup.fall_time = t->scl_fall_ns; @@ -181,7 +172,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 setup->clock_src = clk_get_rate(i2c_dev->clk); if (!setup->clock_src) { -@@ -653,6 +669,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, +@@ -655,6 +669,9 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, return -EINVAL; } @@ -191,7 +182,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 do { ret = stm32f7_i2c_compute_timing(i2c_dev, setup, &i2c_dev->timing); -@@ -674,12 +693,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, +@@ -676,12 +693,15 @@ static int stm32f7_i2c_setup_timing(struct stm32f7_i2c_dev *i2c_dev, return ret; } @@ -208,7 +199,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 i2c_dev->bus_rate = setup->speed_freq; -@@ -718,13 +740,20 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) +@@ -720,8 +740,8 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) timing |= STM32F7_I2C_TIMINGR_SCLL(t->scll); writel_relaxed(timing, i2c_dev->base + STM32F7_I2C_TIMINGR); @@ -219,19 +210,90 @@ index f41f51a176a1..b98ac0f4dee3 100644 stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_ANFOFF); else - stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, - STM32F7_I2C_CR1_ANFOFF); -+ -+ /* Program the Digital Filter */ -+ stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, -+ STM32F7_I2C_CR1_DNF_MASK); -+ stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, +@@ -732,7 +752,7 @@ static void stm32f7_i2c_hw_config(struct stm32f7_i2c_dev *i2c_dev) + stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, + STM32F7_I2C_CR1_DNF_MASK); + stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, +- STM32F7_I2C_CR1_DNF(i2c_dev->setup.dnf)); + STM32F7_I2C_CR1_DNF(i2c_dev->dnf)); -+ + stm32f7_i2c_set_bits(i2c_dev->base + STM32F7_I2C_CR1, STM32F7_I2C_CR1_PE); - } -@@ -1588,7 +1617,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) +@@ -1403,7 +1423,7 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) + status = readl_relaxed(i2c_dev->base + STM32F7_I2C_ISR); + + /* Slave transmitter mode */ +- if (status & STM32F7_I2C_ISR_TXIS) { ++ if (i2c_dev->slave_running && (status & STM32F7_I2C_ISR_TXIS)) { + i2c_slave_event(i2c_dev->slave_running, + I2C_SLAVE_READ_PROCESSED, + &val); +@@ -1413,7 +1433,8 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) + } + + /* Transfer Complete Reload for Slave receiver mode */ +- if (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE) { ++ if (i2c_dev->slave_running && ++ (status & STM32F7_I2C_ISR_TCR || status & STM32F7_I2C_ISR_RXNE)) { + /* + * Read data byte then set NBYTES to receive next byte or NACK + * the current received byte +@@ -1439,7 +1460,7 @@ static irqreturn_t stm32f7_i2c_slave_isr_event(struct stm32f7_i2c_dev *i2c_dev) + } + + /* STOP received */ +- if (status & STM32F7_I2C_ISR_STOPF) { ++ if (i2c_dev->slave_running && (status & STM32F7_I2C_ISR_STOPF)) { + /* Disable interrupts */ + stm32f7_i2c_disable_irq(i2c_dev, STM32F7_I2C_XFER_IRQ_MASK); + +@@ -1472,6 +1493,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) + { + struct stm32f7_i2c_dev *i2c_dev = data; + struct stm32f7_i2c_msg *f7_msg = &i2c_dev->f7_msg; ++ struct stm32_i2c_dma *dma = i2c_dev->dma; + void __iomem *base = i2c_dev->base; + u32 status, mask; + int ret = IRQ_HANDLED; +@@ -1497,6 +1519,10 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) + dev_dbg(i2c_dev->dev, "<%s>: Receive NACK (addr %x)\n", + __func__, f7_msg->addr); + writel_relaxed(STM32F7_I2C_ICR_NACKCF, base + STM32F7_I2C_ICR); ++ if (i2c_dev->use_dma) { ++ stm32f7_i2c_disable_dma_req(i2c_dev); ++ dmaengine_terminate_async(dma->chan_using); ++ } + f7_msg->result = -ENXIO; + } + +@@ -1512,7 +1538,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) + /* Clear STOP flag */ + writel_relaxed(STM32F7_I2C_ICR_STOPCF, base + STM32F7_I2C_ICR); + +- if (i2c_dev->use_dma) { ++ if (i2c_dev->use_dma && !f7_msg->result) { + ret = IRQ_WAKE_THREAD; + } else { + i2c_dev->master_mode = false; +@@ -1525,7 +1551,7 @@ static irqreturn_t stm32f7_i2c_isr_event(int irq, void *data) + if (f7_msg->stop) { + mask = STM32F7_I2C_CR2_STOP; + stm32f7_i2c_set_bits(base + STM32F7_I2C_CR2, mask); +- } else if (i2c_dev->use_dma) { ++ } else if (i2c_dev->use_dma && !f7_msg->result) { + ret = IRQ_WAKE_THREAD; + } else if (f7_msg->smbus) { + stm32f7_i2c_smbus_rep_start(i2c_dev); +@@ -1562,7 +1588,7 @@ static irqreturn_t stm32f7_i2c_isr_event_thread(int irq, void *data) + if (!ret) { + dev_dbg(i2c_dev->dev, "<%s>: Timed out\n", __func__); + stm32f7_i2c_disable_dma_req(i2c_dev); +- dmaengine_terminate_all(dma->chan_using); ++ dmaengine_terminate_async(dma->chan_using); + f7_msg->result = -ETIMEDOUT; + } + +@@ -1597,7 +1623,8 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) /* Bus error */ if (status & STM32F7_I2C_ISR_BERR) { @@ -241,7 +303,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 writel_relaxed(STM32F7_I2C_ICR_BERRCF, base + STM32F7_I2C_ICR); stm32f7_i2c_release_bus(&i2c_dev->adap); f7_msg->result = -EIO; -@@ -1596,17 +1626,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) +@@ -1605,17 +1632,26 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) /* Arbitration loss */ if (status & STM32F7_I2C_ISR_ARLO) { @@ -270,7 +332,72 @@ index f41f51a176a1..b98ac0f4dee3 100644 if (!i2c_dev->slave_running) { u32 mask; /* Disable interrupts */ -@@ -1973,6 +2012,42 @@ static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) +@@ -1629,7 +1665,7 @@ static irqreturn_t stm32f7_i2c_isr_error(int irq, void *data) + /* Disable dma */ + if (i2c_dev->use_dma) { + stm32f7_i2c_disable_dma_req(i2c_dev); +- dmaengine_terminate_all(dma->chan_using); ++ dmaengine_terminate_async(dma->chan_using); + } + + i2c_dev->master_mode = false; +@@ -1665,12 +1701,26 @@ static int stm32f7_i2c_xfer(struct i2c_adapter *i2c_adap, + time_left = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); + ret = f7_msg->result; ++ if (ret) { ++ if (i2c_dev->use_dma) ++ dmaengine_synchronize(dma->chan_using); ++ ++ /* ++ * It is possible that some unsent data have already been ++ * written into TXDR. To avoid sending old data in a ++ * further transfer, flush TXDR in case of any error ++ */ ++ writel_relaxed(STM32F7_I2C_ISR_TXE, ++ i2c_dev->base + STM32F7_I2C_ISR); ++ goto pm_free; ++ } + + if (!time_left) { + dev_dbg(i2c_dev->dev, "Access to slave 0x%x timed out\n", + i2c_dev->msg->addr); + if (i2c_dev->use_dma) +- dmaengine_terminate_all(dma->chan_using); ++ dmaengine_terminate_sync(dma->chan_using); ++ stm32f7_i2c_wait_free_bus(i2c_dev); + ret = -ETIMEDOUT; + } + +@@ -1713,13 +1763,25 @@ static int stm32f7_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr, + timeout = wait_for_completion_timeout(&i2c_dev->complete, + i2c_dev->adap.timeout); + ret = f7_msg->result; +- if (ret) ++ if (ret) { ++ if (i2c_dev->use_dma) ++ dmaengine_synchronize(dma->chan_using); ++ ++ /* ++ * It is possible that some unsent data have already been ++ * written into TXDR. To avoid sending old data in a ++ * further transfer, flush TXDR in case of any error ++ */ ++ writel_relaxed(STM32F7_I2C_ISR_TXE, ++ i2c_dev->base + STM32F7_I2C_ISR); + goto pm_free; ++ } + + if (!timeout) { + dev_dbg(dev, "Access to slave 0x%x timed out\n", f7_msg->addr); + if (i2c_dev->use_dma) +- dmaengine_terminate_all(dma->chan_using); ++ dmaengine_terminate_sync(dma->chan_using); ++ stm32f7_i2c_wait_free_bus(i2c_dev); + ret = -ETIMEDOUT; + goto pm_free; + } +@@ -1982,6 +2044,42 @@ static void stm32f7_i2c_disable_smbus_host(struct stm32f7_i2c_dev *i2c_dev) } } @@ -313,7 +440,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 static u32 stm32f7_i2c_func(struct i2c_adapter *adap) { struct stm32f7_i2c_dev *i2c_dev = i2c_get_adapdata(adap); -@@ -2164,6 +2239,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -2173,6 +2271,16 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) } } @@ -330,7 +457,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 dev_info(i2c_dev->dev, "STM32F7 I2C-%d bus adapter\n", adap->nr); pm_runtime_mark_last_busy(i2c_dev->dev); -@@ -2171,6 +2256,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) +@@ -2180,6 +2288,9 @@ static int stm32f7_i2c_probe(struct platform_device *pdev) return 0; @@ -340,7 +467,7 @@ index f41f51a176a1..b98ac0f4dee3 100644 i2c_adapter_remove: i2c_del_adapter(adap); -@@ -2205,6 +2293,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) +@@ -2214,6 +2325,7 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) { struct stm32f7_i2c_dev *i2c_dev = platform_get_drvdata(pdev); @@ -348,12 +475,14 @@ index f41f51a176a1..b98ac0f4dee3 100644 stm32f7_i2c_disable_smbus_host(i2c_dev); i2c_del_adapter(&i2c_dev->adap); -@@ -2236,64 +2325,25 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) +@@ -2245,64 +2357,25 @@ static int stm32f7_i2c_remove(struct platform_device *pdev) return 0; } -static int __maybe_unused stm32f7_i2c_runtime_suspend(struct device *dev) --{ ++static void __maybe_unused ++stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) + { - struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); - - if (!stm32f7_i2c_is_slave_registered(i2c_dev)) @@ -380,13 +509,11 @@ index f41f51a176a1..b98ac0f4dee3 100644 - -#ifdef CONFIG_PM_SLEEP -static int stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) -+static void __maybe_unused -+stm32f7_i2c_regs_backup(struct stm32f7_i2c_dev *i2c_dev) - { +-{ - int ret; struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; -- ret = pm_runtime_get_sync(i2c_dev->dev); +- ret = pm_runtime_resume_and_get(i2c_dev->dev); - if (ret < 0) - return ret; - @@ -410,14 +537,14 @@ index f41f51a176a1..b98ac0f4dee3 100644 - int ret; struct stm32f7_i2c_regs *backup_regs = &i2c_dev->backup_regs; -- ret = pm_runtime_get_sync(i2c_dev->dev); +- ret = pm_runtime_resume_and_get(i2c_dev->dev); - if (ret < 0) - return ret; - cr1 = readl_relaxed(i2c_dev->base + STM32F7_I2C_CR1); if (cr1 & STM32F7_I2C_CR1_PE) stm32f7_i2c_clr_bits(i2c_dev->base + STM32F7_I2C_CR1, -@@ -2309,29 +2359,49 @@ static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) +@@ -2318,54 +2391,68 @@ static int stm32f7_i2c_regs_restore(struct stm32f7_i2c_dev *i2c_dev) writel_relaxed(backup_regs->oar1, i2c_dev->base + STM32F7_I2C_OAR1); writel_relaxed(backup_regs->oar2, i2c_dev->base + STM32F7_I2C_OAR2); stm32f7_i2c_write_fm_plus_bits(i2c_dev, true); @@ -456,14 +583,13 @@ index f41f51a176a1..b98ac0f4dee3 100644 return ret; } + } -+ -+ stm32f7_i2c_regs_restore(i2c_dev); ++ stm32f7_i2c_regs_restore(i2c_dev); ++ + return 0; +} + -+#ifdef CONFIG_PM_SLEEP -+static int stm32f7_i2c_suspend(struct device *dev) ++static int __maybe_unused stm32f7_i2c_suspend(struct device *dev) +{ + struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); + @@ -478,7 +604,10 @@ index f41f51a176a1..b98ac0f4dee3 100644 return 0; } -@@ -2341,16 +2411,12 @@ static int stm32f7_i2c_resume(struct device *dev) + +-static int stm32f7_i2c_resume(struct device *dev) ++static int __maybe_unused stm32f7_i2c_resume(struct device *dev) + { struct stm32f7_i2c_dev *i2c_dev = dev_get_drvdata(dev); int ret; @@ -500,8 +629,14 @@ index f41f51a176a1..b98ac0f4dee3 100644 i2c_mark_adapter_resumed(&i2c_dev->adap); + return 0; + } +-#endif + + static const struct dev_pm_ops stm32f7_i2c_pm_ops = { + SET_RUNTIME_PM_OPS(stm32f7_i2c_runtime_suspend, diff --git a/drivers/iio/adc/sd_adc_modulator.c b/drivers/iio/adc/sd_adc_modulator.c -index 327cc2097f6c..ceb15029673c 100644 +index 327cc2097..ceb150296 100644 --- a/drivers/iio/adc/sd_adc_modulator.c +++ b/drivers/iio/adc/sd_adc_modulator.c @@ -9,10 +9,8 @@ @@ -627,7 +762,7 @@ index 327cc2097f6c..ceb15029673c 100644 static struct platform_driver iio_sd_mod_adc = { diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c -index a83199b212a4..9d1ad6e38e85 100644 +index a83199b21..9d1ad6e38 100644 --- a/drivers/iio/adc/stm32-adc-core.c +++ b/drivers/iio/adc/stm32-adc-core.c @@ -200,7 +200,7 @@ static int stm32h7_adc_clk_sel(struct platform_device *pdev, @@ -686,11 +821,331 @@ index a83199b212a4..9d1ad6e38e85 100644 if ((rate / div) <= priv->max_clk_rate) goto out; } +diff --git a/drivers/iio/adc/stm32-adc-core.h b/drivers/iio/adc/stm32-adc-core.h +index 2322809bf..7c924f463 100644 +--- a/drivers/iio/adc/stm32-adc-core.h ++++ b/drivers/iio/adc/stm32-adc-core.h +@@ -102,6 +102,9 @@ + #define STM32H7_ADC_CALFACT 0xC4 + #define STM32H7_ADC_CALFACT2 0xC8 + ++/* STM32MP1 - ADC2 instance option register */ ++#define STM32MP1_ADC2_OR 0xD0 ++ + /* STM32H7 - common registers for all ADC instances */ + #define STM32H7_ADC_CSR (STM32_ADCX_COMN_OFFSET + 0x00) + #define STM32H7_ADC_CCR (STM32_ADCX_COMN_OFFSET + 0x08) +@@ -168,11 +171,16 @@ enum stm32h7_adc_dmngt { + #define STM32H7_EOC_MST BIT(2) + + /* STM32H7_ADC_CCR - bit fields */ ++#define STM32H7_VBATEN BIT(24) ++#define STM32H7_VREFEN BIT(22) + #define STM32H7_PRESC_SHIFT 18 + #define STM32H7_PRESC_MASK GENMASK(21, 18) + #define STM32H7_CKMODE_SHIFT 16 + #define STM32H7_CKMODE_MASK GENMASK(17, 16) + ++/* STM32MP1_ADC2_OR - bit fields */ ++#define STM32MP1_VDDCOREEN BIT(0) ++ + /** + * struct stm32_adc_common - stm32 ADC driver common data (for all instances) + * @base: control registers base cpu addr diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c -index 16c02c30dec7..c067c994dae2 100644 +index 16c02c30d..6e9744944 100644 --- a/drivers/iio/adc/stm32-adc.c +++ b/drivers/iio/adc/stm32-adc.c -@@ -1353,7 +1353,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -35,12 +36,14 @@ + #define STM32H7_BOOST_CLKRATE 20000000UL + + #define STM32_ADC_CH_MAX 20 /* max number of channels */ +-#define STM32_ADC_CH_SZ 10 /* max channel name size */ ++#define STM32_ADC_CH_SZ 16 /* max channel name size */ + #define STM32_ADC_MAX_SQ 16 /* SQ1..SQ16 */ + #define STM32_ADC_MAX_SMP 7 /* SMPx range is [0..7] */ + #define STM32_ADC_TIMEOUT_US 100000 + #define STM32_ADC_TIMEOUT (msecs_to_jiffies(STM32_ADC_TIMEOUT_US / 1000)) + #define STM32_ADC_HW_STOP_DELAY_MS 100 ++#define STM32_ADC_CHAN_NONE -1 ++#define STM32_ADC_VREFINT_VOLTAGE 3300 + + #define STM32_DMA_BUFFER_SIZE PAGE_SIZE + +@@ -77,6 +80,30 @@ enum stm32_adc_extsel { + STM32_EXT20, + }; + ++enum stm32_adc_int_ch { ++ STM32_ADC_INT_CH_NONE = -1, ++ STM32_ADC_INT_CH_VDDCORE, ++ STM32_ADC_INT_CH_VREFINT, ++ STM32_ADC_INT_CH_VBAT, ++ STM32_ADC_INT_CH_NB, ++}; ++ ++/** ++ * struct stm32_adc_ic - ADC internal channels ++ * @name: name of the internal channel ++ * @idx: internal channel enum index ++ */ ++struct stm32_adc_ic { ++ const char *name; ++ u32 idx; ++}; ++ ++static const struct stm32_adc_ic stm32_adc_ic[STM32_ADC_INT_CH_NB] = { ++ { "vddcore", STM32_ADC_INT_CH_VDDCORE }, ++ { "vrefint", STM32_ADC_INT_CH_VREFINT }, ++ { "vbat", STM32_ADC_INT_CH_VBAT }, ++}; ++ + /** + * struct stm32_adc_trig_info - ADC trigger info + * @name: name of the trigger, corresponding to its source +@@ -113,6 +140,16 @@ struct stm32_adc_regs { + int shift; + }; + ++/** ++ * struct stm32_adc_vrefint - stm32 ADC internal reference voltage data ++ * @vrefint_cal: vrefint calibration value from nvmem ++ * @vrefint_data: vrefint actual value ++ */ ++struct stm32_adc_vrefint { ++ u32 vrefint_cal; ++ u32 vrefint_data; ++}; ++ + /** + * struct stm32_adc_regspec - stm32 registers definition + * @dr: data register offset +@@ -126,6 +163,9 @@ struct stm32_adc_regs { + * @res: resolution selection register & bitfield + * @smpr: smpr1 & smpr2 registers offset array + * @smp_bits: smpr1 & smpr2 index and bitfields ++ * @or_vdd: option register & vddcore bitfield ++ * @ccr_vbat: common register & vbat bitfield ++ * @ccr_vref: common register & vrefint bitfield + */ + struct stm32_adc_regspec { + const u32 dr; +@@ -139,6 +179,9 @@ struct stm32_adc_regspec { + const struct stm32_adc_regs res; + const u32 smpr[2]; + const struct stm32_adc_regs *smp_bits; ++ const struct stm32_adc_regs or_vdd; ++ const struct stm32_adc_regs ccr_vbat; ++ const struct stm32_adc_regs ccr_vref; + }; + + struct stm32_adc; +@@ -156,6 +199,7 @@ struct stm32_adc; + * @unprepare: optional unprepare routine (disable, power-down) + * @irq_clear: routine to clear irqs + * @smp_cycles: programmable sampling time (ADC clock cycles) ++ * @ts_vrefint_ns: vrefint minimum sampling time in ns + */ + struct stm32_adc_cfg { + const struct stm32_adc_regspec *regs; +@@ -169,6 +213,7 @@ struct stm32_adc_cfg { + void (*unprepare)(struct iio_dev *); + void (*irq_clear)(struct iio_dev *indio_dev, u32 msk); + const unsigned int *smp_cycles; ++ const unsigned int ts_vrefint_ns; + }; + + /** +@@ -193,7 +238,10 @@ struct stm32_adc_cfg { + * @pcsel: bitmask to preselect channels on some devices + * @smpr_val: sampling time settings (e.g. smpr1 / smpr2) + * @cal: optional calibration data on some devices ++ * @vrefint: internal reference voltage data + * @chan_name: channel name array ++ * @num_diff: number of differential channels ++ * @int_ch: internal channel indexes array + */ + struct stm32_adc { + struct stm32_adc_common *common; +@@ -216,7 +264,10 @@ struct stm32_adc { + u32 pcsel; + u32 smpr_val[2]; + struct stm32_adc_calib cal; ++ struct stm32_adc_vrefint vrefint; + char chan_name[STM32_ADC_CH_MAX][STM32_ADC_CH_SZ]; ++ u32 num_diff; ++ int int_ch[STM32_ADC_INT_CH_NB]; + }; + + struct stm32_adc_diff_channel { +@@ -449,6 +500,24 @@ static const struct stm32_adc_regspec stm32h7_adc_regspec = { + .smp_bits = stm32h7_smp_bits, + }; + ++static const struct stm32_adc_regspec stm32mp1_adc_regspec = { ++ .dr = STM32H7_ADC_DR, ++ .ier_eoc = { STM32H7_ADC_IER, STM32H7_EOCIE }, ++ .ier_ovr = { STM32H7_ADC_IER, STM32H7_OVRIE }, ++ .isr_eoc = { STM32H7_ADC_ISR, STM32H7_EOC }, ++ .isr_ovr = { STM32H7_ADC_ISR, STM32H7_OVR }, ++ .sqr = stm32h7_sq, ++ .exten = { STM32H7_ADC_CFGR, STM32H7_EXTEN_MASK, STM32H7_EXTEN_SHIFT }, ++ .extsel = { STM32H7_ADC_CFGR, STM32H7_EXTSEL_MASK, ++ STM32H7_EXTSEL_SHIFT }, ++ .res = { STM32H7_ADC_CFGR, STM32H7_RES_MASK, STM32H7_RES_SHIFT }, ++ .smpr = { STM32H7_ADC_SMPR1, STM32H7_ADC_SMPR2 }, ++ .smp_bits = stm32h7_smp_bits, ++ .or_vdd = { STM32MP1_ADC2_OR, STM32MP1_VDDCOREEN }, ++ .ccr_vbat = { STM32H7_ADC_CCR, STM32H7_VBATEN }, ++ .ccr_vref = { STM32H7_ADC_CCR, STM32H7_VREFEN }, ++}; ++ + /** + * STM32 ADC registers access routines + * @adc: stm32 adc instance +@@ -581,6 +650,61 @@ static int stm32_adc_hw_start(struct device *dev) + return ret; + } + ++static void stm32_adc_int_ch_enable(struct iio_dev *indio_dev) ++{ ++ struct stm32_adc *adc = iio_priv(indio_dev); ++ u32 i, val, bits = 0, offset = 0; ++ ++ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { ++ if (adc->int_ch[i] == STM32_ADC_CHAN_NONE) ++ continue; ++ ++ switch (i) { ++ case STM32_ADC_INT_CH_VDDCORE: ++ dev_dbg(&indio_dev->dev, "Enable VDDCore\n"); ++ stm32_adc_set_bits(adc, adc->cfg->regs->or_vdd.reg, ++ adc->cfg->regs->or_vdd.mask); ++ break; ++ case STM32_ADC_INT_CH_VREFINT: ++ dev_dbg(&indio_dev->dev, "Enable VREFInt\n"); ++ offset = adc->cfg->regs->ccr_vref.reg; ++ bits |= adc->cfg->regs->ccr_vref.mask; ++ break; ++ case STM32_ADC_INT_CH_VBAT: ++ dev_dbg(&indio_dev->dev, "Enable VBAT\n"); ++ offset = adc->cfg->regs->ccr_vbat.reg; ++ bits |= adc->cfg->regs->ccr_vbat.mask; ++ break; ++ } ++ } ++ ++ if (bits) { ++ val = readl_relaxed(adc->common->base + offset); ++ val |= bits; ++ writel_relaxed(val, adc->common->base + offset); ++ } ++} ++ ++static void stm32_adc_int_ch_disable(struct stm32_adc *adc) ++{ ++ u32 val, bits, offset, i; ++ ++ stm32_adc_clr_bits(adc, adc->cfg->regs->or_vdd.reg, ++ adc->cfg->regs->or_vdd.mask); ++ ++ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { ++ if (adc->int_ch[i] != STM32_ADC_CHAN_NONE) { ++ offset = adc->cfg->regs->ccr_vref.reg; ++ bits = adc->cfg->regs->ccr_vref.mask | ++ adc->cfg->regs->ccr_vbat.mask; ++ val = readl_relaxed(adc->common->base + offset); ++ val &= ~bits; ++ writel_relaxed(bits, adc->common->base + offset); ++ break; ++ } ++ } ++} ++ + /** + * stm32f4_adc_start_conv() - Start conversions for regular channels. + * @indio_dev: IIO device instance +@@ -949,11 +1073,13 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev) + goto pwr_dwn; + calib = ret; + ++ stm32_adc_int_ch_enable(indio_dev); ++ + stm32_adc_writel(adc, STM32H7_ADC_DIFSEL, adc->difsel); + + ret = stm32h7_adc_enable(indio_dev); + if (ret) +- goto pwr_dwn; ++ goto ch_disable; + + /* Either restore or read calibration result for future reference */ + if (calib) +@@ -969,6 +1095,8 @@ static int stm32h7_adc_prepare(struct iio_dev *indio_dev) + + disable: + stm32h7_adc_disable(indio_dev); ++ch_disable: ++ stm32_adc_int_ch_disable(adc); + pwr_dwn: + stm32h7_adc_enter_pwr_down(adc); + +@@ -979,7 +1107,9 @@ static void stm32h7_adc_unprepare(struct iio_dev *indio_dev) + { + struct stm32_adc *adc = iio_priv(indio_dev); + ++ stm32_adc_writel(adc, STM32H7_ADC_PCSEL, 0); + stm32h7_adc_disable(indio_dev); ++ stm32_adc_int_ch_disable(adc); + stm32h7_adc_enter_pwr_down(adc); + } + +@@ -1225,15 +1355,35 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev, + ret = stm32_adc_single_conv(indio_dev, chan, val); + else + ret = -EINVAL; ++ ++ /* If channel mask corresponds to vrefint, store data */ ++ if (adc->int_ch[STM32_ADC_INT_CH_VREFINT] == chan->channel) ++ adc->vrefint.vrefint_data = *val; ++ + iio_device_release_direct_mode(indio_dev); + return ret; + + case IIO_CHAN_INFO_SCALE: + if (chan->differential) { +- *val = adc->common->vref_mv * 2; ++ if (adc->vrefint.vrefint_data && ++ adc->vrefint.vrefint_cal) { ++ *val = STM32_ADC_VREFINT_VOLTAGE * 2 * ++ adc->vrefint.vrefint_cal / ++ adc->vrefint.vrefint_data; ++ } else { ++ *val = adc->common->vref_mv * 2; ++ } + *val2 = chan->scan_type.realbits; + } else { +- *val = adc->common->vref_mv; ++ /* Use vrefint data if available */ ++ if (adc->vrefint.vrefint_data && ++ adc->vrefint.vrefint_cal) { ++ *val = STM32_ADC_VREFINT_VOLTAGE * ++ adc->vrefint.vrefint_cal / ++ adc->vrefint.vrefint_data; ++ } else { ++ *val = adc->common->vref_mv; ++ } + *val2 = chan->scan_type.realbits; + } + return IIO_VAL_FRACTIONAL_LOG2; +@@ -1353,7 +1503,7 @@ static int stm32_adc_set_watermark(struct iio_dev *indio_dev, unsigned int val) * dma cyclic transfers are used, buffer is split into two periods. * There should be : * - always one buffer (period) dma is working on @@ -699,7 +1154,7 @@ index 16c02c30dec7..c067c994dae2 100644 */ watermark = min(watermark, val * (unsigned)(sizeof(u16))); adc->rx_buf_sz = min(rx_buf_sz, watermark * 2 * adc->num_conv); -@@ -1616,31 +1616,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) +@@ -1616,31 +1766,14 @@ static irqreturn_t stm32_adc_trigger_handler(int irq, void *p) dev_dbg(&indio_dev->dev, "%s bufi=%d\n", __func__, adc->bufi); @@ -736,8 +1191,344 @@ index 16c02c30dec7..c067c994dae2 100644 return IRQ_HANDLED; } +@@ -1686,6 +1819,14 @@ static void stm32_adc_smpr_init(struct stm32_adc *adc, int channel, u32 smp_ns) + u32 period_ns, shift = smpr->shift, mask = smpr->mask; + unsigned int smp, r = smpr->reg; + ++ /* ++ * For vrefint channel, ensure that the sampling time cannot ++ * be lower than the one specified in the datasheet ++ */ ++ if (channel == adc->int_ch[STM32_ADC_INT_CH_VREFINT] && ++ smp_ns < adc->cfg->ts_vrefint_ns) ++ smp_ns = adc->cfg->ts_vrefint_ns; ++ + /* Determine sampling time (ADC clock cycles) */ + period_ns = NSEC_PER_SEC / adc->common->rate; + for (smp = 0; smp <= STM32_ADC_MAX_SMP; smp++) +@@ -1735,17 +1876,11 @@ static void stm32_adc_chan_init_one(struct iio_dev *indio_dev, + } + } + +-static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) ++static int stm32_adc_get_legacy_chan_count(struct iio_dev *indio_dev, struct stm32_adc *adc) + { + struct device_node *node = indio_dev->dev.of_node; +- struct stm32_adc *adc = iio_priv(indio_dev); + const struct stm32_adc_info *adc_info = adc->cfg->adc_info; +- struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; +- struct property *prop; +- const __be32 *cur; +- struct iio_chan_spec *channels; +- int scan_index = 0, num_channels = 0, num_diff = 0, ret, i; +- u32 val, smp = 0; ++ int num_channels = 0, ret; + + ret = of_property_count_u32_elems(node, "st,adc-channels"); + if (ret > adc_info->max_channels) { +@@ -1756,23 +1891,17 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) + } + + ret = of_property_count_elems_of_size(node, "st,adc-diff-channels", +- sizeof(*diff)); ++ sizeof(struct stm32_adc_diff_channel)); + if (ret > adc_info->max_channels) { + dev_err(&indio_dev->dev, "Bad st,adc-diff-channels?\n"); + return -EINVAL; + } else if (ret > 0) { +- int size = ret * sizeof(*diff) / sizeof(u32); +- +- num_diff = ret; ++ adc->num_diff = ret; + num_channels += ret; +- ret = of_property_read_u32_array(node, "st,adc-diff-channels", +- (u32 *)diff, size); +- if (ret) +- return ret; + } + + if (!num_channels) { +- dev_err(&indio_dev->dev, "No channels configured\n"); ++ dev_err(indio_dev->dev.parent, "No channel found\n"); + return -ENODATA; + } + +@@ -1783,10 +1912,45 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) + return -EINVAL; + } + +- channels = devm_kcalloc(&indio_dev->dev, num_channels, +- sizeof(struct iio_chan_spec), GFP_KERNEL); +- if (!channels) +- return -ENOMEM; ++ return num_channels; ++} ++ ++static int stm32_adc_legacy_chan_init(struct iio_dev *indio_dev, ++ struct stm32_adc *adc, ++ struct iio_chan_spec *channels) ++{ ++ struct device_node *node = indio_dev->dev.of_node; ++ const struct stm32_adc_info *adc_info = adc->cfg->adc_info; ++ struct stm32_adc_diff_channel diff[STM32_ADC_CH_MAX]; ++ u32 num_diff = adc->num_diff; ++ int size = num_diff * sizeof(*diff) / sizeof(u32); ++ int scan_index = 0, val, ret, i; ++ struct property *prop; ++ const __be32 *cur; ++ u32 smp = 0; ++ ++ if (num_diff) { ++ ret = of_property_read_u32_array(node, "st,adc-diff-channels", ++ (u32 *)diff, size); ++ if (ret) { ++ dev_err(&indio_dev->dev, "Failed to get diff channels %d\n", ret); ++ return ret; ++ } ++ ++ for (i = 0; i < num_diff; i++) { ++ if (diff[i].vinp >= adc_info->max_channels || ++ diff[i].vinn >= adc_info->max_channels) { ++ dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", ++ diff[i].vinp, diff[i].vinn); ++ return -EINVAL; ++ } ++ ++ stm32_adc_chan_init_one(indio_dev, &channels[scan_index], ++ diff[i].vinp, diff[i].vinn, ++ scan_index, true); ++ scan_index++; ++ } ++ } + + of_property_for_each_u32(node, "st,adc-channels", prop, cur, val) { + if (val >= adc_info->max_channels) { +@@ -1797,8 +1961,7 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) + /* Channel can't be configured both as single-ended & diff */ + for (i = 0; i < num_diff; i++) { + if (val == diff[i].vinp) { +- dev_err(&indio_dev->dev, +- "channel %d miss-configured\n", val); ++ dev_err(&indio_dev->dev, "channel %d misconfigured\n", val); + return -EINVAL; + } + } +@@ -1807,19 +1970,6 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) + scan_index++; + } + +- for (i = 0; i < num_diff; i++) { +- if (diff[i].vinp >= adc_info->max_channels || +- diff[i].vinn >= adc_info->max_channels) { +- dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", +- diff[i].vinp, diff[i].vinn); +- return -EINVAL; +- } +- stm32_adc_chan_init_one(indio_dev, &channels[scan_index], +- diff[i].vinp, diff[i].vinn, scan_index, +- true); +- scan_index++; +- } +- + for (i = 0; i < scan_index; i++) { + /* + * Using of_property_read_u32_index(), smp value will only be +@@ -1827,13 +1977,173 @@ static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) + * get either no value, 1 shared value for all indexes, or one + * value per channel. + */ +- of_property_read_u32_index(node, "st,min-sample-time-nsecs", +- i, &smp); ++ of_property_read_u32_index(node, "st,min-sample-time-nsecs", i, &smp); ++ + /* Prepare sampling time settings */ + stm32_adc_smpr_init(adc, channels[i].channel, smp); + } + +- indio_dev->num_channels = scan_index; ++ return scan_index; ++} ++ ++static int stm32_adc_get_int_ch(struct iio_dev *indio_dev, const char *ch_name, ++ int chan) ++{ ++ struct stm32_adc *adc = iio_priv(indio_dev); ++ u16 vrefint; ++ int i, ret; ++ ++ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) { ++ if (!strncmp(stm32_adc_ic[i].name, ch_name, STM32_ADC_CH_SZ)) { ++ adc->int_ch[i] = chan; ++ /* If channel is vrefint get calibration data. */ ++ if (stm32_adc_ic[i].idx == STM32_ADC_INT_CH_VREFINT) { ++ ret = nvmem_cell_read_u16(&indio_dev->dev, "vrefint", &vrefint); ++ if (ret && ret != -ENOENT && ret != -EOPNOTSUPP) { ++ dev_err(&indio_dev->dev, "nvmem access error %d\n", ret); ++ return ret; ++ } ++ if (ret == -ENOENT) ++ dev_dbg(&indio_dev->dev, ++ "vrefint calibration not found\n"); ++ else ++ adc->vrefint.vrefint_cal = vrefint; ++ } ++ } ++ } ++ ++ return 0; ++} ++ ++static int stm32_adc_generic_chan_init(struct iio_dev *indio_dev, ++ struct stm32_adc *adc, ++ struct iio_chan_spec *channels) ++{ ++ struct device_node *node = indio_dev->dev.of_node; ++ const struct stm32_adc_info *adc_info = adc->cfg->adc_info; ++ struct device_node *child; ++ const char *name; ++ int val, scan_index = 0, ret, i; ++ bool differential; ++ u32 vin[2]; ++ ++ for (i = 0; i < STM32_ADC_INT_CH_NB; i++) ++ adc->int_ch[i] = STM32_ADC_CHAN_NONE; ++ ++ for_each_available_child_of_node(node, child) { ++ ret = of_property_read_u32(child, "reg", &val); ++ if (ret) { ++ dev_err(&indio_dev->dev, "Missing channel index %d\n", ret); ++ goto err; ++ } ++ ++ ret = of_property_read_string(child, "label", &name); ++ /* label is optional */ ++ if (!ret) { ++ if (strlen(name) >= STM32_ADC_CH_SZ) { ++ dev_err(&indio_dev->dev, "Label %s exceeds %d characters\n", ++ name, STM32_ADC_CH_SZ); ++ return -EINVAL; ++ } ++ strncpy(adc->chan_name[val], name, STM32_ADC_CH_SZ); ++ ret = stm32_adc_get_int_ch(indio_dev, name, val); ++ if (ret) ++ goto err; ++ } else if (ret != -EINVAL) { ++ dev_err(&indio_dev->dev, "Invalid label %d\n", ret); ++ goto err; ++ } ++ ++ if (val >= adc_info->max_channels) { ++ dev_err(&indio_dev->dev, "Invalid channel %d\n", val); ++ ret = -EINVAL; ++ goto err; ++ } ++ ++ differential = false; ++ ret = of_property_read_u32_array(child, "diff-channels", vin, 2); ++ /* diff-channels is optional */ ++ if (!ret) { ++ differential = true; ++ if (vin[0] != val || vin[1] >= adc_info->max_channels) { ++ dev_err(&indio_dev->dev, "Invalid channel in%d-in%d\n", ++ vin[0], vin[1]); ++ goto err; ++ } ++ } else if (ret != -EINVAL) { ++ dev_err(&indio_dev->dev, "Invalid diff-channels property %d\n", ret); ++ goto err; ++ } ++ ++ stm32_adc_chan_init_one(indio_dev, &channels[scan_index], val, ++ vin[1], scan_index, differential); ++ ++ ret = of_property_read_u32(child, "st,min-sample-time-nsecs", &val); ++ /* st,min-sample-time-nsecs is optional */ ++ if (!ret) { ++ stm32_adc_smpr_init(adc, channels[scan_index].channel, val); ++ if (differential) ++ stm32_adc_smpr_init(adc, vin[1], val); ++ } else if (ret != -EINVAL) { ++ dev_err(&indio_dev->dev, "Invalid st,min-sample-time-nsecs property %d\n", ++ ret); ++ goto err; ++ } ++ ++ scan_index++; ++ } ++ ++ return scan_index; ++ ++err: ++ of_node_put(child); ++ ++ return ret; ++} ++ ++static int stm32_adc_chan_of_init(struct iio_dev *indio_dev) ++{ ++ struct device_node *node = indio_dev->dev.of_node; ++ struct stm32_adc *adc = iio_priv(indio_dev); ++ const struct stm32_adc_info *adc_info = adc->cfg->adc_info; ++ struct iio_chan_spec *channels; ++ int num_channels = 0, ret; ++ bool legacy = false; ++ ++ num_channels = of_get_available_child_count(node); ++ /* ++ * If no channels have been found, fallback to channels legacy properties. ++ * Legacy channel properties will be ignored, if some channels are ++ * already defined using the standard binding. ++ */ ++ if (!num_channels) { ++ ret = stm32_adc_get_legacy_chan_count(indio_dev, adc); ++ if (ret < 0) ++ return ret; ++ ++ legacy = true; ++ num_channels = ret; ++ } ++ ++ if (num_channels > adc_info->max_channels) { ++ dev_err(&indio_dev->dev, "Channel number [%d] exceeds %d\n", ++ num_channels, adc_info->max_channels); ++ return -EINVAL; ++ } ++ ++ channels = devm_kcalloc(&indio_dev->dev, num_channels, ++ sizeof(struct iio_chan_spec), GFP_KERNEL); ++ if (!channels) ++ return -ENOMEM; ++ ++ if (legacy) ++ ret = stm32_adc_legacy_chan_init(indio_dev, adc, channels); ++ else ++ ret = stm32_adc_generic_chan_init(indio_dev, adc, channels); ++ if (ret < 0) ++ return ret; ++ ++ indio_dev->num_channels = ret; + indio_dev->channels = channels; + + return 0; +@@ -2105,7 +2415,7 @@ static const struct stm32_adc_cfg stm32h7_adc_cfg = { + }; + + static const struct stm32_adc_cfg stm32mp1_adc_cfg = { +- .regs = &stm32h7_adc_regspec, ++ .regs = &stm32mp1_adc_regspec, + .adc_info = &stm32h7_adc_info, + .trigs = stm32h7_adc_trigs, + .has_vregready = true, +@@ -2115,6 +2425,7 @@ static const struct stm32_adc_cfg stm32mp1_adc_cfg = { + .unprepare = stm32h7_adc_unprepare, + .smp_cycles = stm32h7_adc_smp_cycles, + .irq_clear = stm32h7_adc_irq_clear, ++ .ts_vrefint_ns = 4300, + }; + + static const struct of_device_id stm32_adc_of_match[] = { diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c -index 9234f14167b7..9d689ed9723a 100644 +index 9234f1416..10e5a48cd 100644 --- a/drivers/iio/adc/stm32-dfsdm-adc.c +++ b/drivers/iio/adc/stm32-dfsdm-adc.c @@ -10,6 +10,7 @@ @@ -770,7 +1561,7 @@ index 9234f14167b7..9d689ed9723a 100644 /* Audio specific */ unsigned int spi_freq; /* SPI bus clock frequency */ -@@ -1224,7 +1233,10 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -1224,7 +1233,13 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, int *val2, long mask) { struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -779,10 +1570,13 @@ index 9234f14167b7..9d689ed9723a 100644 + struct stm32_dfsdm_filter_osr *flo = &fl->flo[fl->fast]; + u32 max = flo->max << (flo->lshift - chan->scan_type.shift); + int ret, idx = chan->scan_index; ++ ++ if (flo->lshift < chan->scan_type.shift) ++ max = flo->max >> (chan->scan_type.shift - flo->lshift); switch (mask) { case IIO_CHAN_INFO_RAW: -@@ -1260,6 +1272,39 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, +@@ -1260,6 +1275,39 @@ static int stm32_dfsdm_read_raw(struct iio_dev *indio_dev, *val = adc->sample_freq; return IIO_VAL_INT; @@ -822,7 +1616,7 @@ index 9234f14167b7..9d689ed9723a 100644 } return -EINVAL; -@@ -1384,7 +1429,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1384,7 +1432,9 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, * IIO_CHAN_INFO_RAW: used to compute regular conversion * IIO_CHAN_INFO_OVERSAMPLING_RATIO: used to set oversampling */ @@ -833,7 +1627,7 @@ index 9234f14167b7..9d689ed9723a 100644 ch->info_mask_shared_by_all = BIT(IIO_CHAN_INFO_OVERSAMPLING_RATIO) | BIT(IIO_CHAN_INFO_SAMP_FREQ); -@@ -1394,7 +1441,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, +@@ -1394,7 +1444,7 @@ static int stm32_dfsdm_adc_chan_init_one(struct iio_dev *indio_dev, ch->scan_type.shift = 8; } ch->scan_type.sign = 's'; @@ -842,7 +1636,7 @@ index 9234f14167b7..9d689ed9723a 100644 ch->scan_type.storagebits = 32; return stm32_dfsdm_chan_configure(adc->dfsdm, -@@ -1435,8 +1482,10 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) +@@ -1435,8 +1485,10 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) { struct iio_chan_spec *ch; struct stm32_dfsdm_adc *adc = iio_priv(indio_dev); @@ -854,7 +1648,7 @@ index 9234f14167b7..9d689ed9723a 100644 adc->oversamp = DFSDM_DEFAULT_OVERSAMPLING; ret = stm32_dfsdm_compute_all_osrs(indio_dev, adc->oversamp); -@@ -1460,6 +1509,21 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) +@@ -1460,6 +1512,21 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) if (!ch) return -ENOMEM; @@ -876,7 +1670,7 @@ index 9234f14167b7..9d689ed9723a 100644 for (chan_idx = 0; chan_idx < num_ch; chan_idx++) { ch[chan_idx].scan_index = chan_idx; ret = stm32_dfsdm_adc_chan_init_one(indio_dev, &ch[chan_idx]); -@@ -1467,6 +1531,38 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) +@@ -1467,6 +1534,38 @@ static int stm32_dfsdm_adc_init(struct device *dev, struct iio_dev *indio_dev) dev_err(&indio_dev->dev, "Channels init failed\n"); return ret; } @@ -915,7 +1709,7 @@ index 9234f14167b7..9d689ed9723a 100644 } indio_dev->num_channels = num_ch; -@@ -1521,6 +1617,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = { +@@ -1521,6 +1620,7 @@ static const struct of_device_id stm32_dfsdm_adc_match[] = { }, {} }; @@ -924,7 +1718,7 @@ index 9234f14167b7..9d689ed9723a 100644 static int stm32_dfsdm_adc_probe(struct platform_device *pdev) { diff --git a/drivers/iio/adc/stm32-dfsdm-core.c b/drivers/iio/adc/stm32-dfsdm-core.c -index 42a7377704a4..627557d8efb0 100644 +index 42a737770..627557d8e 100644 --- a/drivers/iio/adc/stm32-dfsdm-core.c +++ b/drivers/iio/adc/stm32-dfsdm-core.c @@ -6,6 +6,7 @@ @@ -1068,7 +1862,7 @@ index 42a7377704a4..627557d8efb0 100644 ret = stm32_dfsdm_clk_prepare_enable(dfsdm); diff --git a/drivers/iio/adc/stm32-dfsdm.h b/drivers/iio/adc/stm32-dfsdm.h -index 4afc1f528b78..4f230e2a7692 100644 +index 4afc1f528..4f230e2a7 100644 --- a/drivers/iio/adc/stm32-dfsdm.h +++ b/drivers/iio/adc/stm32-dfsdm.h @@ -13,25 +13,28 @@ @@ -1155,10 +1949,34 @@ index 4afc1f528b78..4f230e2a7692 100644 enum stm32_dfsdm_sinc_order { DFSDM_FASTSINC_ORDER, /* FastSinc filter type */ diff --git a/drivers/irqchip/irq-stm32-exti.c b/drivers/irqchip/irq-stm32-exti.c -index 8662d7b7b262..e1c975c27a2e 100644 +index 8662d7b7b..d38896125 100644 --- a/drivers/irqchip/irq-stm32-exti.c +++ b/drivers/irqchip/irq-stm32-exti.c -@@ -193,7 +193,16 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = { +@@ -132,7 +132,6 @@ static const struct stm32_exti_drv_data stm32h7xx_drv_data = { + + static const struct stm32_exti_bank stm32mp1_exti_b1 = { + .imr_ofst = 0x80, +- .emr_ofst = 0x84, + .rtsr_ofst = 0x00, + .ftsr_ofst = 0x04, + .swier_ofst = 0x08, +@@ -142,7 +141,6 @@ static const struct stm32_exti_bank stm32mp1_exti_b1 = { + + static const struct stm32_exti_bank stm32mp1_exti_b2 = { + .imr_ofst = 0x90, +- .emr_ofst = 0x94, + .rtsr_ofst = 0x20, + .ftsr_ofst = 0x24, + .swier_ofst = 0x28, +@@ -152,7 +150,6 @@ static const struct stm32_exti_bank stm32mp1_exti_b2 = { + + static const struct stm32_exti_bank stm32mp1_exti_b3 = { + .imr_ofst = 0xA0, +- .emr_ofst = 0xA4, + .rtsr_ofst = 0x40, + .ftsr_ofst = 0x44, + .swier_ofst = 0x48, +@@ -193,7 +190,16 @@ static const struct stm32_desc_irq stm32mp1_desc_irq[] = { { .exti = 23, .irq_parent = 72, .chip = &stm32_exti_h_chip_direct }, { .exti = 24, .irq_parent = 95, .chip = &stm32_exti_h_chip_direct }, { .exti = 25, .irq_parent = 107, .chip = &stm32_exti_h_chip_direct }, @@ -1170,12 +1988,12 @@ index 8662d7b7b262..e1c975c27a2e 100644 + { .exti = 31, .irq_parent = 53, .chip = &stm32_exti_h_chip_direct }, + { .exti = 32, .irq_parent = 82, .chip = &stm32_exti_h_chip_direct }, + { .exti = 33, .irq_parent = 83, .chip = &stm32_exti_h_chip_direct }, -+ { .exti = 43, .irq_parent = 75, .chip = &stm32_exti_h_chip_direct }, ++ { .exti = 43, .irq_parent = 75, .chip = &stm32_exti_h_chip_direct }, + { .exti = 44, .irq_parent = 98, .chip = &stm32_exti_h_chip_direct }, { .exti = 47, .irq_parent = 93, .chip = &stm32_exti_h_chip_direct }, { .exti = 48, .irq_parent = 138, .chip = &stm32_exti_h_chip_direct }, { .exti = 50, .irq_parent = 139, .chip = &stm32_exti_h_chip_direct }, -@@ -534,6 +543,9 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) +@@ -534,6 +540,9 @@ static int stm32_exti_h_set_type(struct irq_data *d, unsigned int type) unlock: raw_spin_unlock(&chip_data->rlock); @@ -1185,7 +2003,7 @@ index 8662d7b7b262..e1c975c27a2e 100644 return err; } -@@ -551,6 +563,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) +@@ -551,6 +560,9 @@ static int stm32_exti_h_set_wake(struct irq_data *d, unsigned int on) raw_spin_unlock(&chip_data->rlock); @@ -1195,7 +2013,7 @@ index 8662d7b7b262..e1c975c27a2e 100644 return 0; } -@@ -560,7 +575,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, +@@ -560,7 +572,13 @@ static int stm32_exti_h_set_affinity(struct irq_data *d, if (d->parent_data->chip) return irq_chip_set_affinity_parent(d, dest, force); @@ -1210,7 +2028,7 @@ index 8662d7b7b262..e1c975c27a2e 100644 } static int __maybe_unused stm32_exti_h_suspend(void) -@@ -624,6 +645,7 @@ static int stm32_exti_h_retrigger(struct irq_data *d) +@@ -624,6 +642,7 @@ static int stm32_exti_h_retrigger(struct irq_data *d) static struct irq_chip stm32_exti_h_chip = { .name = "stm32-exti-h", .irq_eoi = stm32_exti_h_eoi, @@ -1218,7 +2036,7 @@ index 8662d7b7b262..e1c975c27a2e 100644 .irq_mask = stm32_exti_h_mask, .irq_unmask = stm32_exti_h_unmask, .irq_retrigger = stm32_exti_h_retrigger, -@@ -637,8 +659,8 @@ static struct irq_chip stm32_exti_h_chip_direct = { +@@ -637,8 +656,8 @@ static struct irq_chip stm32_exti_h_chip_direct = { .name = "stm32-exti-h-direct", .irq_eoi = irq_chip_eoi_parent, .irq_ack = irq_chip_ack_parent, @@ -1229,7 +2047,7 @@ index 8662d7b7b262..e1c975c27a2e 100644 .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_set_type = irq_chip_set_type_parent, .irq_set_wake = stm32_exti_h_set_wake, -@@ -669,14 +691,28 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm, +@@ -669,14 +688,28 @@ static int stm32_exti_h_domain_alloc(struct irq_domain *dm, irq_domain_set_hwirq_and_chip(dm, virq, hwirq, desc->chip, chip_data); @@ -1263,7 +2081,17 @@ index 8662d7b7b262..e1c975c27a2e 100644 } return 0; -@@ -841,11 +877,12 @@ static int stm32_exti_probe(struct platform_device *pdev) +@@ -738,7 +771,8 @@ stm32_exti_chip_data *stm32_exti_chip_init(struct stm32_exti_host_data *h_data, + * clear registers to avoid residue + */ + writel_relaxed(0, base + stm32_bank->imr_ofst); +- writel_relaxed(0, base + stm32_bank->emr_ofst); ++ if (stm32_bank->emr_ofst) ++ writel_relaxed(0, base + stm32_bank->emr_ofst); + + pr_info("%pOF: bank%d\n", node, bank_idx); + +@@ -841,11 +875,12 @@ static int stm32_exti_probe(struct platform_device *pdev) { int ret, i; struct device *dev = &pdev->dev; @@ -1277,7 +2105,7 @@ index 8662d7b7b262..e1c975c27a2e 100644 host_data = devm_kzalloc(dev, sizeof(*host_data), GFP_KERNEL); if (!host_data) -@@ -913,6 +950,34 @@ static int stm32_exti_probe(struct platform_device *pdev) +@@ -913,6 +948,34 @@ static int stm32_exti_probe(struct platform_device *pdev) if (ret) return ret; diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0009-ARM-5.10.10-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch similarity index 94% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0009-ARM-5.10.10-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch index ca45962..e352b06 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0009-ARM-5.10.10-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch @@ -1,22 +1,21 @@ -From 4ceafa69af22aeb262fb8d2e0e3cd845773ce0ae Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:07:25 +0100 -Subject: [PATCH 09/22] ARM 5.10.10-stm32mp1-r1 MAILBOX-REMOTEPROC-RPMSG +From 471f33cca896724288eed3ab00e022aab3302b08 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:45 +0200 +Subject: [PATCH 09/23] ARM 5.10.61-stm32mp1-r2 MAILBOX-REMOTEPROC-RPMSG -Signed-off-by: Romuald JEANNE --- Documentation/staging/remoteproc.rst | 22 + drivers/mailbox/Kconfig | 7 + drivers/mailbox/Makefile | 2 + drivers/mailbox/arm-smc-mailbox.c | 166 ++++++ - drivers/remoteproc/Kconfig | 28 + + drivers/remoteproc/Kconfig | 29 + drivers/remoteproc/Makefile | 3 + drivers/remoteproc/remoteproc_core.c | 19 +- drivers/remoteproc/rproc_srm_core.c | 303 ++++++++++ drivers/remoteproc/rproc_srm_core.h | 98 ++++ drivers/remoteproc/rproc_srm_dev.c | 744 +++++++++++++++++++++++++ - drivers/remoteproc/stm32_rproc.c | 364 ++++++++---- - drivers/remoteproc/tee_remoteproc.c | 380 +++++++++++++ + drivers/remoteproc/stm32_rproc.c | 346 ++++++++---- + drivers/remoteproc/tee_remoteproc.c | 378 +++++++++++++ drivers/rpmsg/Kconfig | 9 + drivers/rpmsg/Makefile | 1 + drivers/rpmsg/rpmsg_core.c | 19 + @@ -25,8 +24,8 @@ Signed-off-by: Romuald JEANNE drivers/rpmsg/virtio_rpmsg_bus.c | 11 + include/linux/mailbox/arm-smccc-mbox.h | 20 + include/linux/rpmsg.h | 9 + - include/linux/tee_remoteproc.h | 106 ++++ - 21 files changed, 2540 insertions(+), 115 deletions(-) + include/linux/tee_remoteproc.h | 101 ++++ + 21 files changed, 2516 insertions(+), 115 deletions(-) create mode 100644 drivers/mailbox/arm-smc-mailbox.c create mode 100644 drivers/remoteproc/rproc_srm_core.c create mode 100644 drivers/remoteproc/rproc_srm_core.h @@ -37,7 +36,7 @@ Signed-off-by: Romuald JEANNE create mode 100644 include/linux/tee_remoteproc.h diff --git a/Documentation/staging/remoteproc.rst b/Documentation/staging/remoteproc.rst -index 9cccd3dd6a4b..c2367e3c0b19 100644 +index 9cccd3dd6..c2367e3c0 100644 --- a/Documentation/staging/remoteproc.rst +++ b/Documentation/staging/remoteproc.rst @@ -357,3 +357,25 @@ Of course, RSC_VDEV resource entries are only good enough for static @@ -67,7 +66,7 @@ index 9cccd3dd6a4b..c2367e3c0b19 100644 +The resources handled by the SRM are defined in the DeviceTree: please read +Documentation/devicetree/bindings/remoteproc/rproc-srm.txt for details. diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig -index 05b1009e2820..3d388bf2d6f6 100644 +index 05b1009e2..3d388bf2d 100644 --- a/drivers/mailbox/Kconfig +++ b/drivers/mailbox/Kconfig @@ -16,6 +16,13 @@ config ARM_MHU @@ -85,7 +84,7 @@ index 05b1009e2820..3d388bf2d6f6 100644 tristate "i.MX Mailbox" depends on ARCH_MXC || COMPILE_TEST diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile -index 2e06e02b2e03..24841a298f4a 100644 +index 2e06e02b2..24841a298 100644 --- a/drivers/mailbox/Makefile +++ b/drivers/mailbox/Makefile @@ -7,6 +7,8 @@ obj-$(CONFIG_MAILBOX_TEST) += mailbox-test.o @@ -99,7 +98,7 @@ index 2e06e02b2e03..24841a298f4a 100644 obj-$(CONFIG_ARMADA_37XX_RWTM_MBOX) += armada-37xx-rwtm-mailbox.o diff --git a/drivers/mailbox/arm-smc-mailbox.c b/drivers/mailbox/arm-smc-mailbox.c new file mode 100644 -index 000000000000..a6ec56f41f7f +index 000000000..a6ec56f41 --- /dev/null +++ b/drivers/mailbox/arm-smc-mailbox.c @@ -0,0 +1,166 @@ @@ -270,7 +269,7 @@ index 000000000000..a6ec56f41f7f +MODULE_DESCRIPTION("Generic ARM smc mailbox driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig -index d99548fb5dde..cffac49af045 100644 +index d99548fb5..d3253dc6f 100644 --- a/drivers/remoteproc/Kconfig +++ b/drivers/remoteproc/Kconfig @@ -23,6 +23,25 @@ config REMOTEPROC_CDEV @@ -299,13 +298,21 @@ index d99548fb5dde..cffac49af045 100644 config IMX_REMOTEPROC tristate "IMX6/7 remoteproc support" depends on ARCH_MXC -@@ -288,6 +307,15 @@ config TI_K3_R5_REMOTEPROC +@@ -252,6 +271,7 @@ config STM32_RPROC + depends on ARCH_STM32 + depends on REMOTEPROC + select MAILBOX ++ select TEE_REMOTEPROC + help + Say y here to support STM32 MCU processors via the + remote processor framework. +@@ -288,6 +308,15 @@ config TI_K3_R5_REMOTEPROC It's safe to say N here if you're not interested in utilizing a slave processor. + +config TEE_REMOTEPROC -+ tristate "trusted firmware Support by a Trusted Application" ++ tristate "trusted firmware support by a trusted application" + depends on OPTEE + help + Support for trusted remote processors firmware. The firmware @@ -316,7 +323,7 @@ index d99548fb5dde..cffac49af045 100644 endmenu diff --git a/drivers/remoteproc/Makefile b/drivers/remoteproc/Makefile -index da2ace4ec86c..9f2eb094c509 100644 +index da2ace4ec..9f2eb094c 100644 --- a/drivers/remoteproc/Makefile +++ b/drivers/remoteproc/Makefile @@ -11,6 +11,9 @@ remoteproc-y += remoteproc_sysfs.o @@ -330,7 +337,7 @@ index da2ace4ec86c..9f2eb094c509 100644 obj-$(CONFIG_INGENIC_VPU_RPROC) += ingenic_rproc.o obj-$(CONFIG_MTK_SCP) += mtk_scp.o mtk_scp_ipi.o diff --git a/drivers/remoteproc/remoteproc_core.c b/drivers/remoteproc/remoteproc_core.c -index dab2c0f5caf0..316acd156b0b 100644 +index 47924d5ed..99bdc6eb4 100644 --- a/drivers/remoteproc/remoteproc_core.c +++ b/drivers/remoteproc/remoteproc_core.c @@ -37,6 +37,7 @@ @@ -384,7 +391,7 @@ index dab2c0f5caf0..316acd156b0b 100644 /* * Remind ourselves the remote processor has been attached to rather * than booted by the remoteproc core. This is important because the -@@ -2297,6 +2312,8 @@ int rproc_del(struct rproc *rproc) +@@ -2296,6 +2311,8 @@ int rproc_del(struct rproc *rproc) list_del_rcu(&rproc->node); mutex_unlock(&rproc_list_mutex); @@ -395,7 +402,7 @@ index dab2c0f5caf0..316acd156b0b 100644 diff --git a/drivers/remoteproc/rproc_srm_core.c b/drivers/remoteproc/rproc_srm_core.c new file mode 100644 -index 000000000000..fc61e8b35686 +index 000000000..fc61e8b35 --- /dev/null +++ b/drivers/remoteproc/rproc_srm_core.c @@ -0,0 +1,303 @@ @@ -704,7 +711,7 @@ index 000000000000..fc61e8b35686 +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/rproc_srm_core.h b/drivers/remoteproc/rproc_srm_core.h new file mode 100644 -index 000000000000..7dffdb38f4d4 +index 000000000..7dffdb38f --- /dev/null +++ b/drivers/remoteproc/rproc_srm_core.h @@ -0,0 +1,98 @@ @@ -808,7 +815,7 @@ index 000000000000..7dffdb38f4d4 +#endif diff --git a/drivers/remoteproc/rproc_srm_dev.c b/drivers/remoteproc/rproc_srm_dev.c new file mode 100644 -index 000000000000..9dad0820f263 +index 000000000..9dad0820f --- /dev/null +++ b/drivers/remoteproc/rproc_srm_dev.c @@ -0,0 +1,744 @@ @@ -1557,7 +1564,7 @@ index 000000000000..9dad0820f263 +MODULE_DESCRIPTION("Remoteproc System Resource Manager driver - dev"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/remoteproc/stm32_rproc.c b/drivers/remoteproc/stm32_rproc.c -index d2414cc1d90d..f5a65eea9cdc 100644 +index d2414cc1d..9e9f89895 100644 --- a/drivers/remoteproc/stm32_rproc.c +++ b/drivers/remoteproc/stm32_rproc.c @@ -20,13 +20,11 @@ @@ -1598,26 +1605,17 @@ index d2414cc1d90d..f5a65eea9cdc 100644 struct stm32_syscon pdds; struct stm32_syscon m4_state; struct stm32_syscon rsctbl; -@@ -87,10 +92,17 @@ struct stm32_rproc { +@@ -87,7 +92,8 @@ struct stm32_rproc { struct stm32_rproc_mem *rmems; struct stm32_mbox mb[MBOX_NB_MBX]; struct workqueue_struct *workqueue; - bool secured_soc; -+ bool secured_fw; + bool fw_loaded; + struct tee_rproc *trproc; void __iomem *rsc_va; }; -+struct stm32_rproc_conf { -+ bool secured_fw; -+ struct rproc_ops *ops; -+}; -+ - static int stm32_rproc_pa_to_da(struct rproc *rproc, phys_addr_t pa, u64 *da) - { - unsigned int i; -@@ -207,15 +219,139 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) +@@ -207,15 +213,139 @@ static int stm32_rproc_mbox_idx(struct rproc *rproc, const unsigned char *name) return -EINVAL; } @@ -1727,14 +1725,14 @@ index d2414cc1d90d..f5a65eea9cdc 100644 + + return tee_rproc_get_loaded_rsc_table(ddata->trproc); +} -+ + +static int stm32_rproc_tee_start(struct rproc *rproc) +{ + struct stm32_rproc *ddata = rproc->priv; + + return tee_rproc_start(ddata->trproc); +} - ++ +static int stm32_rproc_tee_attach(struct rproc *rproc) +{ + /* Nothing to do, remote proc already started by the secured context */ @@ -1760,7 +1758,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 static int stm32_rproc_parse_memory_regions(struct rproc *rproc) { struct device *dev = rproc->dev.parent; -@@ -274,12 +410,21 @@ static int stm32_rproc_parse_memory_regions(struct rproc *rproc) +@@ -274,12 +404,21 @@ static int stm32_rproc_parse_memory_regions(struct rproc *rproc) static int stm32_rproc_parse_fw(struct rproc *rproc, const struct firmware *fw) { @@ -1784,7 +1782,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 } static irqreturn_t stm32_rproc_wdg(int irq, void *data) -@@ -370,8 +515,13 @@ static int stm32_rproc_request_mbox(struct rproc *rproc) +@@ -370,8 +509,13 @@ static int stm32_rproc_request_mbox(struct rproc *rproc) ddata->mb[i].chan = mbox_request_channel_byname(cl, name); if (IS_ERR(ddata->mb[i].chan)) { @@ -1799,7 +1797,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 dev_warn(dev, "cannot get %s mbox\n", name); ddata->mb[i].chan = NULL; } -@@ -390,30 +540,6 @@ static int stm32_rproc_request_mbox(struct rproc *rproc) +@@ -390,30 +534,6 @@ static int stm32_rproc_request_mbox(struct rproc *rproc) return -EPROBE_DEFER; } @@ -1830,7 +1828,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 static void stm32_rproc_add_coredump_trace(struct rproc *rproc) { struct rproc_debug_trace *trace; -@@ -453,40 +579,34 @@ static int stm32_rproc_start(struct rproc *rproc) +@@ -453,40 +573,34 @@ static int stm32_rproc_start(struct rproc *rproc) } } @@ -1882,7 +1880,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 err = reset_control_assert(ddata->rst); if (err) { -@@ -494,29 +614,8 @@ static int stm32_rproc_stop(struct rproc *rproc) +@@ -494,29 +608,8 @@ static int stm32_rproc_stop(struct rproc *rproc) return err; } @@ -1913,7 +1911,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 } static void stm32_rproc_kick(struct rproc *rproc, int vqid) -@@ -553,8 +652,36 @@ static struct rproc_ops st_rproc_ops = { +@@ -553,8 +646,19 @@ static struct rproc_ops st_rproc_ops = { .get_boot_addr = rproc_elf_get_boot_addr, }; @@ -1927,31 +1925,14 @@ index d2414cc1d90d..f5a65eea9cdc 100644 + .sanity_check = stm32_rproc_tee_elf_sanity_check, + .load = stm32_rproc_tee_elf_load, +}; -+ -+static const struct stm32_rproc_conf stm32_rproc_default_conf = { -+ .secured_fw = false, -+ .ops = &st_rproc_ops, -+}; -+ -+static const struct stm32_rproc_conf stm32_rproc_tee_conf = { -+ .secured_fw = true, -+ .ops = &st_rproc_tee_ops, -+}; + static const struct of_device_id stm32_rproc_match[] = { - { .compatible = "st,stm32mp1-m4" }, -+ { -+ .compatible = "st,stm32mp1-m4", -+ .data = &stm32_rproc_default_conf, -+ }, -+ { -+ .compatible = "st,stm32mp1-m4_optee", -+ .data = &stm32_rproc_tee_conf, -+ }, ++ {.compatible = "st,stm32mp1-m4",}, {}, }; MODULE_DEVICE_TABLE(of, stm32_rproc_match); -@@ -586,21 +713,18 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, +@@ -586,21 +690,18 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, { struct device *dev = &pdev->dev; struct device_node *np = dev->of_node; @@ -1977,7 +1958,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 ddata->wdg_irq = irq; -@@ -612,36 +736,15 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, +@@ -612,36 +713,15 @@ static int stm32_rproc_parse_dt(struct platform_device *pdev, dev_info(dev, "wdg irq registered\n"); } @@ -1986,7 +1967,11 @@ index d2414cc1d90d..f5a65eea9cdc 100644 - dev_err(dev, "failed to get mcu reset\n"); - return PTR_ERR(ddata->rst); - } -- ++ ddata->rst = devm_reset_control_get(dev, "mcu_rst"); ++ if (IS_ERR(ddata->rst)) ++ return dev_err_probe(dev, PTR_ERR(ddata->rst), ++ "failed to get mcu_reset\n"); + - /* - * if platform is secured the hold boot bit must be written by - * smc call and read normally. @@ -2004,11 +1989,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 - return err; - } - ddata->secured_soc = tzen & tz.mask; -+ ddata->rst = devm_reset_control_get(dev, "mcu_rst"); -+ if (IS_ERR(ddata->rst)) -+ return dev_err_probe(dev, PTR_ERR(ddata->rst), -+ "failed to get mcu_reset\n"); - +- - err = stm32_rproc_get_syscon(np, "st,syscfg-holdboot", - &ddata->hold_boot); - if (err) { @@ -2022,73 +2003,68 @@ index d2414cc1d90d..f5a65eea9cdc 100644 err = stm32_rproc_get_syscon(np, "st,syscfg-pdds", &ddata->pdds); if (err) -@@ -766,6 +869,8 @@ static int stm32_rproc_probe(struct platform_device *pdev) +@@ -766,6 +846,7 @@ static int stm32_rproc_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct stm32_rproc *ddata; struct device_node *np = dev->of_node; -+ const struct of_device_id *of_id; -+ const struct stm32_rproc_conf *conf; ++ struct tee_rproc *trproc; struct rproc *rproc; unsigned int state; int ret; -@@ -774,12 +879,18 @@ static int stm32_rproc_probe(struct platform_device *pdev) +@@ -774,11 +855,32 @@ static int stm32_rproc_probe(struct platform_device *pdev) if (ret) return ret; - rproc = rproc_alloc(dev, np->name, &st_rproc_ops, NULL, sizeof(*ddata)); -+ of_id = of_match_device(stm32_rproc_match, &pdev->dev); -+ if (of_id) -+ conf = (const struct stm32_rproc_conf *)of_id->data; -+ else -+ return -EINVAL; +- if (!rproc) +- return -ENOMEM; ++ trproc = tee_rproc_register(dev, STM32_MP1_FW_ID); ++ if (!IS_ERR_OR_NULL(trproc)) { ++ /* ++ * Delagate the firmware management to the secure context. The ++ * firmware loaded has to be signed. ++ */ ++ dev_info(dev, "Support of signed firmware only\n"); + -+ rproc = rproc_alloc(dev, np->name, conf->ops, NULL, sizeof(*ddata)); - if (!rproc) - return -ENOMEM; - - ddata = rproc->priv; -- -+ ddata->secured_fw = conf->secured_fw; - rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); - - ret = stm32_rproc_parse_dt(pdev, ddata, &rproc->auto_boot); -@@ -820,12 +931,25 @@ static int stm32_rproc_probe(struct platform_device *pdev) - if (ret) - goto free_wkq; - -+ if (ddata->secured_fw) { -+ ddata->trproc = tee_rproc_register(dev, rproc, -+ STM32_MP1_FW_ID); -+ if (IS_ERR(ddata->trproc)) { -+ ret = PTR_ERR(ddata->trproc); -+ dev_err_probe(dev, ret, "TEE rproc device not found\n"); -+ goto free_mb; -+ } ++ } else { ++ if (PTR_ERR(trproc) == -EPROBE_DEFER) ++ return PTR_ERR(trproc); ++ trproc = NULL; + } + - ret = rproc_add(rproc); - if (ret) -- goto free_mb; ++ rproc = rproc_alloc(dev, np->name, ++ trproc ? &st_rproc_tee_ops : &st_rproc_ops, ++ NULL, sizeof(*ddata)); ++ if (!rproc) { ++ ret = -ENOMEM; + goto free_tee; ++ } - return 0; + ddata = rproc->priv; ++ ddata->trproc = trproc; ++ if (trproc) ++ ddata->trproc->rproc = rproc; + rproc_coredump_set_elf_info(rproc, ELFCLASS32, EM_NONE); + +@@ -838,6 +940,10 @@ static int stm32_rproc_probe(struct platform_device *pdev) + device_init_wakeup(dev, false); + } + rproc_free(rproc); +free_tee: ++ if (trproc) ++ tee_rproc_unregister(trproc); ++ + return ret; + } + +@@ -859,10 +965,21 @@ static int stm32_rproc_remove(struct platform_device *pdev) + device_init_wakeup(dev, false); + } + rproc_free(rproc); + if (ddata->trproc) + tee_rproc_unregister(ddata->trproc); - free_mb: - stm32_rproc_free_mbox(rproc); - free_wkq: -@@ -851,6 +975,8 @@ static int stm32_rproc_remove(struct platform_device *pdev) - rproc_shutdown(rproc); - rproc_del(rproc); -+ if (ddata->trproc) -+ tee_rproc_unregister(ddata->trproc); - stm32_rproc_free_mbox(rproc); - destroy_workqueue(ddata->workqueue); - -@@ -863,6 +989,15 @@ static int stm32_rproc_remove(struct platform_device *pdev) return 0; } @@ -2104,7 +2080,7 @@ index d2414cc1d90d..f5a65eea9cdc 100644 static int __maybe_unused stm32_rproc_suspend(struct device *dev) { struct rproc *rproc = dev_get_drvdata(dev); -@@ -891,6 +1026,7 @@ static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, +@@ -891,6 +1008,7 @@ static SIMPLE_DEV_PM_OPS(stm32_rproc_pm_ops, static struct platform_driver stm32_rproc_driver = { .probe = stm32_rproc_probe, .remove = stm32_rproc_remove, @@ -2114,10 +2090,10 @@ index d2414cc1d90d..f5a65eea9cdc 100644 .pm = &stm32_rproc_pm_ops, diff --git a/drivers/remoteproc/tee_remoteproc.c b/drivers/remoteproc/tee_remoteproc.c new file mode 100644 -index 000000000000..67d924c95871 +index 000000000..690cb86f6 --- /dev/null +++ b/drivers/remoteproc/tee_remoteproc.c -@@ -0,0 +1,380 @@ +@@ -0,0 +1,378 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) STMicroelectronics 2020 - All Rights Reserved @@ -2371,8 +2347,7 @@ index 000000000000..67d924c95871 + {} +}; + -+struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, -+ unsigned int fw_id) ++struct tee_rproc *tee_rproc_register(struct device *dev, unsigned int fw_id) +{ + struct tee_client_device *rproc_tee_device; + struct tee_ioctl_open_session_arg sess_arg; @@ -2406,7 +2381,6 @@ index 000000000000..67d924c95871 + return ERR_PTR(ret); + } + -+ trproc->rproc = rproc; + trproc->parent = dev; + trproc->fw_id = fw_id; + trproc->session_id = sess_arg.session; @@ -2448,7 +2422,7 @@ index 000000000000..67d924c95871 + pvt_data.ctx = tee_client_open_context(NULL, tee_ctx_match, NULL, + NULL); + if (IS_ERR(pvt_data.ctx)) -+ return -ENODEV; ++ return PTR_ERR(pvt_data.ctx); + + pvt_data.dev = dev; + INIT_LIST_HEAD(&pvt_data.sessions); @@ -2499,7 +2473,7 @@ index 000000000000..67d924c95871 +MODULE_AUTHOR("Arnaud Pouliquen "); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/Kconfig b/drivers/rpmsg/Kconfig -index f96716893c2a..7c8053aa968e 100644 +index f96716893..7c8053aa9 100644 --- a/drivers/rpmsg/Kconfig +++ b/drivers/rpmsg/Kconfig @@ -64,4 +64,13 @@ config RPMSG_VIRTIO @@ -2517,7 +2491,7 @@ index f96716893c2a..7c8053aa968e 100644 + endmenu diff --git a/drivers/rpmsg/Makefile b/drivers/rpmsg/Makefile -index ffe932ef6050..26a197365679 100644 +index ffe932ef6..26a197365 100644 --- a/drivers/rpmsg/Makefile +++ b/drivers/rpmsg/Makefile @@ -7,4 +7,5 @@ obj-$(CONFIG_RPMSG_QCOM_GLINK) += qcom_glink.o @@ -2527,7 +2501,7 @@ index ffe932ef6050..26a197365679 100644 +obj-$(CONFIG_RPMSG_TTY) += rpmsg_tty.o obj-$(CONFIG_RPMSG_VIRTIO) += virtio_rpmsg_bus.o diff --git a/drivers/rpmsg/rpmsg_core.c b/drivers/rpmsg/rpmsg_core.c -index 91de940896e3..380500872352 100644 +index 91de94089..380500872 100644 --- a/drivers/rpmsg/rpmsg_core.c +++ b/drivers/rpmsg/rpmsg_core.c @@ -283,6 +283,25 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, @@ -2557,7 +2531,7 @@ index 91de940896e3..380500872352 100644 * match a rpmsg channel with a channel info struct. * this is used to make sure we're not creating rpmsg devices for channels diff --git a/drivers/rpmsg/rpmsg_internal.h b/drivers/rpmsg/rpmsg_internal.h -index 3fc83cd50e98..244292540e58 100644 +index 3fc83cd50..244292540 100644 --- a/drivers/rpmsg/rpmsg_internal.h +++ b/drivers/rpmsg/rpmsg_internal.h @@ -47,6 +47,7 @@ struct rpmsg_device_ops { @@ -2578,7 +2552,7 @@ index 3fc83cd50e98..244292540e58 100644 int rpmsg_register_device(struct rpmsg_device *rpdev); diff --git a/drivers/rpmsg/rpmsg_tty.c b/drivers/rpmsg/rpmsg_tty.c new file mode 100644 -index 000000000000..b7bd1196630d +index 000000000..b7bd11966 --- /dev/null +++ b/drivers/rpmsg/rpmsg_tty.c @@ -0,0 +1,342 @@ @@ -2925,7 +2899,7 @@ index 000000000000..b7bd1196630d +MODULE_DESCRIPTION("virtio remote processor messaging tty driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/rpmsg/virtio_rpmsg_bus.c b/drivers/rpmsg/virtio_rpmsg_bus.c -index 7d7ed4e5cce7..b8e60b34c258 100644 +index 7d7ed4e5c..b8e60b34c 100644 --- a/drivers/rpmsg/virtio_rpmsg_bus.c +++ b/drivers/rpmsg/virtio_rpmsg_bus.c @@ -181,6 +181,7 @@ static int virtio_rpmsg_trysendto(struct rpmsg_endpoint *ept, void *data, @@ -2962,7 +2936,7 @@ index 7d7ed4e5cce7..b8e60b34c258 100644 { diff --git a/include/linux/mailbox/arm-smccc-mbox.h b/include/linux/mailbox/arm-smccc-mbox.h new file mode 100644 -index 000000000000..d35fb89a77f5 +index 000000000..d35fb89a7 --- /dev/null +++ b/include/linux/mailbox/arm-smccc-mbox.h @@ -0,0 +1,20 @@ @@ -2987,7 +2961,7 @@ index 000000000000..d35fb89a77f5 + +#endif /* _LINUX_ARM_SMCCC_MBOX_H_ */ diff --git a/include/linux/rpmsg.h b/include/linux/rpmsg.h -index 9fe156d1c018..2af7674035aa 100644 +index 9fe156d1c..2af767403 100644 --- a/include/linux/rpmsg.h +++ b/include/linux/rpmsg.h @@ -135,6 +135,7 @@ int rpmsg_trysend_offchannel(struct rpmsg_endpoint *ept, u32 src, u32 dst, @@ -3015,10 +2989,10 @@ index 9fe156d1c018..2af7674035aa 100644 /* use a macro to avoid include chaining to get THIS_MODULE */ diff --git a/include/linux/tee_remoteproc.h b/include/linux/tee_remoteproc.h new file mode 100644 -index 000000000000..5d2d6ae492d0 +index 000000000..5ba0b6116 --- /dev/null +++ b/include/linux/tee_remoteproc.h -@@ -0,0 +1,106 @@ +@@ -0,0 +1,101 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright(c) 2020 STMicroelectronics 2020 @@ -3051,8 +3025,7 @@ index 000000000000..5d2d6ae492d0 + +#if IS_ENABLED(CONFIG_TEE_REMOTEPROC) + -+struct tee_rproc *tee_rproc_register(struct device *dev, struct rproc *rproc, -+ unsigned int fw_id); ++struct tee_rproc *tee_rproc_register(struct device *dev, unsigned int fw_id); +int tee_rproc_unregister(struct tee_rproc *trproc); + +int tee_rproc_load_fw(struct tee_rproc *trproc, const struct firmware *fw); @@ -3064,13 +3037,9 @@ index 000000000000..5d2d6ae492d0 +#else + +static inline struct tee_rproc *tee_rproc_register(struct device *dev, -+ struct rproc *rproc, + unsigned int fw_id) +{ -+ /* This shouldn't be possible */ -+ WARN_ON(1); -+ -+ return NULL; ++ return ERR_PTR(-ENODEV); +} + +static inline int tee_rproc_unregister(struct tee_rproc *trproc) diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0010-ARM-5.10.10-stm32mp1-r1-MEDIA-SOC-THERMAL.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch similarity index 89% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0010-ARM-5.10.10-stm32mp1-r1-MEDIA-SOC-THERMAL.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch index df1bed5..879c66a 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0010-ARM-5.10.10-stm32mp1-r1-MEDIA-SOC-THERMAL.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch @@ -1,13 +1,11 @@ -From 88453f29216e4dc473683b0fa9fe5e3e7ae0bff2 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:11:20 +0100 -Subject: [PATCH 10/22] ARM 5.10.10-stm32mp1-r1 MEDIA-SOC-THERMAL +From 75eede33771d5a5da7fcccae80f2b2682b4897b3 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:46 +0200 +Subject: [PATCH 10/23] ARM 5.10.61-stm32mp1-r2 MEDIA-SOC-THERMAL -Signed-off-by: Romuald JEANNE --- - drivers/media/cec/platform/Makefile | 1 + drivers/media/i2c/ov5640.c | 111 +++++++--- - drivers/media/platform/stm32/stm32-dcmi.c | 122 +++++++++-- + drivers/media/platform/stm32/stm32-dcmi.c | 173 +++++++++++++--- drivers/media/v4l2-core/v4l2-fwnode.c | 3 + drivers/soc/Kconfig | 1 + drivers/soc/Makefile | 1 + @@ -18,26 +16,15 @@ Signed-off-by: Romuald JEANNE drivers/thermal/st/stm_thermal.c | 30 +-- include/dt-bindings/soc/stm32-hdp.h | 108 ++++++++++ include/media/v4l2-fwnode.h | 2 + - 13 files changed, 784 insertions(+), 68 deletions(-) + 12 files changed, 824 insertions(+), 78 deletions(-) create mode 100644 drivers/soc/st/Kconfig create mode 100644 drivers/soc/st/Makefile create mode 100644 drivers/soc/st/stm32_hdp.c create mode 100644 drivers/soc/st/stm32_pm_domain.c create mode 100644 include/dt-bindings/soc/stm32-hdp.h -diff --git a/drivers/media/cec/platform/Makefile b/drivers/media/cec/platform/Makefile -index 3a947159b25a..ea6f8ee8161c 100644 ---- a/drivers/media/cec/platform/Makefile -+++ b/drivers/media/cec/platform/Makefile -@@ -10,5 +10,6 @@ obj-$(CONFIG_CEC_MESON_AO) += meson/ - obj-$(CONFIG_CEC_SAMSUNG_S5P) += s5p/ - obj-$(CONFIG_CEC_SECO) += seco/ - obj-$(CONFIG_CEC_STI) += sti/ -+obj-$(CONFIG_CEC_STM32) += stm32/ - obj-$(CONFIG_CEC_TEGRA) += tegra/ - diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c -index 8f0812e85901..d7d36ad863ea 100644 +index 8f0812e85..d7d36ad86 100644 --- a/drivers/media/i2c/ov5640.c +++ b/drivers/media/i2c/ov5640.c @@ -65,6 +65,7 @@ @@ -338,7 +325,7 @@ index 8f0812e85901..d7d36ad863ea 100644 ret = hdl->error; goto free_ctrls; diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c -index fd1c41cba52f..60ef8a65f16c 100644 +index fd1c41cba..af7fe3e37 100644 --- a/drivers/media/platform/stm32/stm32-dcmi.c +++ b/drivers/media/platform/stm32/stm32-dcmi.c @@ -95,6 +95,9 @@ enum state { @@ -351,7 +338,16 @@ index fd1c41cba52f..60ef8a65f16c 100644 #define TIMEOUT_MS 1000 #define OVERRUN_ERROR_THRESHOLD 3 -@@ -157,6 +160,7 @@ struct stm32_dcmi { +@@ -120,7 +123,7 @@ struct dcmi_framesize { + struct dcmi_buf { + struct vb2_v4l2_buffer vb; + bool prepared; +- dma_addr_t paddr; ++ struct sg_table sgt; + size_t size; + struct list_head list; + }; +@@ -157,11 +160,13 @@ struct stm32_dcmi { struct vb2_queue queue; struct v4l2_fwnode_bus_parallel bus; @@ -359,7 +355,13 @@ index fd1c41cba52f..60ef8a65f16c 100644 struct completion complete; struct clk *mclk; enum state state; -@@ -324,7 +328,7 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, + struct dma_chan *dma_chan; + dma_cookie_t dma_cookie; ++ u32 dma_max_burst; + u32 misr; + int errors_count; + int overrun_count; +@@ -324,20 +329,19 @@ static int dcmi_start_dma(struct stm32_dcmi *dcmi, } /* @@ -368,6 +370,22 @@ index fd1c41cba52f..60ef8a65f16c 100644 * dmaengine_prep_slave_single() and dmaengine_submit() * by locking the whole DMA submission sequence */ + mutex_lock(&dcmi->dma_lock); + + /* Prepare a DMA transaction */ +- desc = dmaengine_prep_slave_single(dcmi->dma_chan, buf->paddr, +- buf->size, ++ desc = dmaengine_prep_slave_sg(dcmi->dma_chan, buf->sgt.sgl, ++ buf->sgt.nents, + DMA_DEV_TO_MEM, + DMA_PREP_INTERRUPT); + if (!desc) { +- dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_single failed for buffer phy=%pad size=%zu\n", +- __func__, &buf->paddr, buf->size); ++ dev_err(dcmi->dev, "%s: DMA dmaengine_prep_slave_sg failed\n", __func__); + mutex_unlock(&dcmi->dma_lock); + return -EINVAL; + } @@ -438,7 +442,7 @@ static void dcmi_process_jpeg(struct stm32_dcmi *dcmi) } @@ -377,7 +395,59 @@ index fd1c41cba52f..60ef8a65f16c 100644 /* Restart capture */ if (dcmi_restart_capture(dcmi)) -@@ -777,6 +781,23 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) +@@ -529,6 +533,10 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) + struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb); + struct dcmi_buf *buf = container_of(vbuf, struct dcmi_buf, vb); + unsigned long size; ++ unsigned int num_sgs; ++ dma_addr_t dma_buf; ++ struct scatterlist *sg; ++ int i, ret; + + size = dcmi->fmt.fmt.pix.sizeimage; + +@@ -542,15 +550,35 @@ static int dcmi_buf_prepare(struct vb2_buffer *vb) + + if (!buf->prepared) { + /* Get memory addresses */ +- buf->paddr = +- vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + buf->size = vb2_plane_size(&buf->vb.vb2_buf, 0); +- buf->prepared = true; ++ if (buf->size <= dcmi->dma_max_burst) ++ num_sgs = 1; ++ else ++ num_sgs = DIV_ROUND_UP(buf->size, dcmi->dma_max_burst); ++ ++ ret = sg_alloc_table(&buf->sgt, num_sgs, GFP_ATOMIC); ++ if (ret) { ++ dev_err(dcmi->dev, "sg table alloc failed\n"); ++ return ret; ++ } + +- vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); ++ dma_buf = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0); + + dev_dbg(dcmi->dev, "buffer[%d] phy=%pad size=%zu\n", +- vb->index, &buf->paddr, buf->size); ++ vb->index, &dma_buf, buf->size); ++ ++ for_each_sg(buf->sgt.sgl, sg, num_sgs, i) { ++ size_t bytes = min_t(size_t, size, dcmi->dma_max_burst); ++ ++ sg_dma_address(sg) = dma_buf; ++ sg_dma_len(sg) = bytes; ++ dma_buf += bytes; ++ size -= bytes; ++ } ++ ++ buf->prepared = true; ++ ++ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, buf->size); + } + + return 0; +@@ -777,6 +805,23 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) if (dcmi->bus.flags & V4L2_MBUS_PCLK_SAMPLE_RISING) val |= CR_PCKPOL; @@ -401,7 +471,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 reg_write(dcmi->regs, DCMI_CR, val); /* Set crop */ -@@ -784,8 +805,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) +@@ -784,8 +829,31 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count) dcmi_set_crop(dcmi); /* Enable jpeg capture */ @@ -435,7 +505,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 /* Enable dcmi */ reg_set(dcmi->regs, DCMI_CR, CR_ENABLE); -@@ -882,7 +926,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) +@@ -882,7 +950,7 @@ static void dcmi_stop_streaming(struct vb2_queue *vq) /* Stop all pending DMA operations */ mutex_lock(&dcmi->dma_lock); @@ -444,7 +514,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 mutex_unlock(&dcmi->dma_lock); pm_runtime_put(dcmi->dev); -@@ -1067,8 +1111,9 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) +@@ -1067,8 +1135,9 @@ static int dcmi_set_fmt(struct stm32_dcmi *dcmi, struct v4l2_format *f) if (ret) return ret; @@ -456,7 +526,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 dcmi->do_crop = false; /* pix to mbus format */ -@@ -1574,6 +1619,22 @@ static const struct dcmi_format dcmi_formats[] = { +@@ -1574,6 +1643,22 @@ static const struct dcmi_format dcmi_formats[] = { .fourcc = V4L2_PIX_FMT_JPEG, .mbus_code = MEDIA_BUS_FMT_JPEG_1X8, .bpp = 1, @@ -479,7 +549,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 }, }; -@@ -1592,6 +1653,11 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) +@@ -1592,6 +1677,11 @@ static int dcmi_formats_init(struct stm32_dcmi *dcmi) if (dcmi_formats[i].mbus_code != mbus_code.code) continue; @@ -491,7 +561,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 /* Code supported, have we got this fourcc yet? */ for (j = 0; j < num_fmts; j++) if (sd_fmts[j]->fourcc == -@@ -1745,6 +1811,15 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, +@@ -1745,6 +1835,15 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, dev_dbg(dcmi->dev, "Subdev \"%s\" bound\n", subdev->name); @@ -507,7 +577,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 /* * Link this sub-device to DCMI, it could be * a parallel camera sensor or a bridge -@@ -1757,10 +1832,11 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, +@@ -1757,10 +1856,11 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier, &dcmi->vdev->entity, 0, MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED); @@ -521,7 +591,15 @@ index fd1c41cba52f..60ef8a65f16c 100644 dev_dbg(dcmi->dev, "DCMI is now linked to \"%s\"\n", subdev->name); -@@ -1851,7 +1927,9 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -1835,6 +1935,7 @@ static int dcmi_probe(struct platform_device *pdev) + struct stm32_dcmi *dcmi; + struct vb2_queue *q; + struct dma_chan *chan; ++ struct dma_slave_caps caps; + struct clk *mclk; + int irq; + int ret = 0; +@@ -1851,7 +1952,9 @@ static int dcmi_probe(struct platform_device *pdev) dcmi->rstc = devm_reset_control_get_exclusive(&pdev->dev, NULL); if (IS_ERR(dcmi->rstc)) { @@ -532,7 +610,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 return PTR_ERR(dcmi->rstc); } -@@ -1873,9 +1951,18 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -1873,9 +1976,18 @@ static int dcmi_probe(struct platform_device *pdev) dev_err(&pdev->dev, "CSI bus not supported\n"); return -ENODEV; } @@ -551,7 +629,20 @@ index fd1c41cba52f..60ef8a65f16c 100644 irq = platform_get_irq(pdev, 0); if (irq <= 0) -@@ -1972,15 +2059,6 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -1917,6 +2029,12 @@ static int dcmi_probe(struct platform_device *pdev) + return ret; + } + ++ dcmi->dma_max_burst = UINT_MAX; ++ ret = dma_get_slave_caps(chan, &caps); ++ if (!ret && caps.max_sg_burst) ++ dcmi->dma_max_burst = caps.max_sg_burst * ++ DMA_SLAVE_BUSWIDTH_4_BYTES; ++ + spin_lock_init(&dcmi->irqlock); + mutex_init(&dcmi->lock); + mutex_init(&dcmi->dma_lock); +@@ -1972,15 +2090,6 @@ static int dcmi_probe(struct platform_device *pdev) } dcmi->vdev->entity.flags |= MEDIA_ENT_FL_DEFAULT; @@ -567,7 +658,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 /* Buffer queue */ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; q->io_modes = VB2_MMAP | VB2_READ | VB2_DMABUF; -@@ -2001,7 +2079,7 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -2001,7 +2110,7 @@ static int dcmi_probe(struct platform_device *pdev) ret = dcmi_graph_init(dcmi); if (ret < 0) @@ -576,7 +667,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 /* Reset device */ ret = reset_control_assert(dcmi->rstc); -@@ -2027,7 +2105,10 @@ static int dcmi_probe(struct platform_device *pdev) +@@ -2027,7 +2136,10 @@ static int dcmi_probe(struct platform_device *pdev) return 0; err_cleanup: @@ -587,7 +678,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 err_media_entity_cleanup: media_entity_cleanup(&dcmi->vdev->entity); err_device_release: -@@ -2049,6 +2130,7 @@ static int dcmi_remove(struct platform_device *pdev) +@@ -2049,6 +2161,7 @@ static int dcmi_remove(struct platform_device *pdev) v4l2_async_notifier_unregister(&dcmi->notifier); v4l2_async_notifier_cleanup(&dcmi->notifier); @@ -596,7 +687,7 @@ index fd1c41cba52f..60ef8a65f16c 100644 v4l2_device_unregister(&dcmi->v4l2_dev); media_device_cleanup(&dcmi->mdev); diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c -index dfc53d11053f..7d0e2f5d1700 100644 +index dfc53d110..7d0e2f5d1 100644 --- a/drivers/media/v4l2-core/v4l2-fwnode.c +++ b/drivers/media/v4l2-core/v4l2-fwnode.c @@ -356,6 +356,9 @@ v4l2_fwnode_endpoint_parse_parallel_bus(struct fwnode_handle *fwnode, @@ -610,7 +701,7 @@ index dfc53d11053f..7d0e2f5d1700 100644 default: bus->flags = flags; diff --git a/drivers/soc/Kconfig b/drivers/soc/Kconfig -index 425ab6f7e375..30afdfbfd9cc 100644 +index 425ab6f7e..30afdfbfd 100644 --- a/drivers/soc/Kconfig +++ b/drivers/soc/Kconfig @@ -15,6 +15,7 @@ source "drivers/soc/renesas/Kconfig" @@ -622,7 +713,7 @@ index 425ab6f7e375..30afdfbfd9cc 100644 source "drivers/soc/tegra/Kconfig" source "drivers/soc/ti/Kconfig" diff --git a/drivers/soc/Makefile b/drivers/soc/Makefile -index 36452bed86ef..6b957db9a9bb 100644 +index 36452bed8..6b957db9a 100644 --- a/drivers/soc/Makefile +++ b/drivers/soc/Makefile @@ -21,6 +21,7 @@ obj-y += renesas/ @@ -635,7 +726,7 @@ index 36452bed86ef..6b957db9a9bb 100644 obj-y += ti/ diff --git a/drivers/soc/st/Kconfig b/drivers/soc/st/Kconfig new file mode 100644 -index 000000000000..8ab604999db4 +index 000000000..8ab604999 --- /dev/null +++ b/drivers/soc/st/Kconfig @@ -0,0 +1,17 @@ @@ -658,7 +749,7 @@ index 000000000000..8ab604999db4 +endif # ARCH_STM32 diff --git a/drivers/soc/st/Makefile b/drivers/soc/st/Makefile new file mode 100644 -index 000000000000..85905b7688ed +index 000000000..85905b768 --- /dev/null +++ b/drivers/soc/st/Makefile @@ -0,0 +1,2 @@ @@ -666,7 +757,7 @@ index 000000000000..85905b7688ed +obj-$(CONFIG_STM32_HDP) += stm32_hdp.o diff --git a/drivers/soc/st/stm32_hdp.c b/drivers/soc/st/stm32_hdp.c new file mode 100644 -index 000000000000..47687ebd1ffd +index 000000000..47687ebd1 --- /dev/null +++ b/drivers/soc/st/stm32_hdp.c @@ -0,0 +1,242 @@ @@ -914,7 +1005,7 @@ index 000000000000..47687ebd1ffd +module_platform_driver(hdp_driver); diff --git a/drivers/soc/st/stm32_pm_domain.c b/drivers/soc/st/stm32_pm_domain.c new file mode 100644 -index 000000000000..0386624c20f2 +index 000000000..0386624c2 --- /dev/null +++ b/drivers/soc/st/stm32_pm_domain.c @@ -0,0 +1,212 @@ @@ -1131,7 +1222,7 @@ index 000000000000..0386624c20f2 +} +core_initcall(stm32_pm_domains_init); diff --git a/drivers/thermal/st/stm_thermal.c b/drivers/thermal/st/stm_thermal.c -index 5fd3fb8912a6..1e065a3323f9 100644 +index 5fd3fb891..1e065a332 100644 --- a/drivers/thermal/st/stm_thermal.c +++ b/drivers/thermal/st/stm_thermal.c @@ -82,8 +82,7 @@ @@ -1215,7 +1306,7 @@ index 5fd3fb8912a6..1e065a3323f9 100644 diff --git a/include/dt-bindings/soc/stm32-hdp.h b/include/dt-bindings/soc/stm32-hdp.h new file mode 100644 -index 000000000000..d98665327281 +index 000000000..d98665327 --- /dev/null +++ b/include/dt-bindings/soc/stm32-hdp.h @@ -0,0 +1,108 @@ @@ -1328,7 +1419,7 @@ index 000000000000..d98665327281 + +#endif /* _DT_BINDINGS_STM32_HDP_H */ diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h -index ed0840f3d5df..598822e23e9e 100644 +index ed0840f3d..598822e23 100644 --- a/include/media/v4l2-fwnode.h +++ b/include/media/v4l2-fwnode.h @@ -49,11 +49,13 @@ struct v4l2_fwnode_bus_mipi_csi2 { diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0011-ARM-5.10.10-stm32mp1-r1-MFD.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0011-ARM-5.10.61-stm32mp1-r2-MFD.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0011-ARM-5.10.10-stm32mp1-r1-MFD.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0011-ARM-5.10.61-stm32mp1-r2-MFD.patch index 9005095..5c75c54 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0011-ARM-5.10.10-stm32mp1-r1-MFD.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0011-ARM-5.10.61-stm32mp1-r2-MFD.patch @@ -1,9 +1,8 @@ -From 55dcc42c73d9d2c733972cd89bbbbb6d75b7d942 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:12:12 +0100 -Subject: [PATCH 11/22] ARM 5.10.10-stm32mp1-r1 MFD +From a8b88220ea06e256ca6268be9856a8bbe522b0b5 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:47 +0200 +Subject: [PATCH 11/23] ARM 5.10.61-stm32mp1-r2 MFD -Signed-off-by: Romuald JEANNE --- drivers/mfd/Kconfig | 10 + drivers/mfd/Makefile | 1 + @@ -16,10 +15,10 @@ Signed-off-by: Romuald JEANNE create mode 100644 drivers/mfd/stm32-pwr.c diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig -index 4789507f325b..2917b4466f74 100644 +index b8847ae04..16449cfc8 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig -@@ -2052,6 +2052,16 @@ config MFD_STPMIC1 +@@ -2053,6 +2053,16 @@ config MFD_STPMIC1 To compile this driver as a module, choose M here: the module will be called stpmic1. @@ -37,7 +36,7 @@ index 4789507f325b..2917b4466f74 100644 tristate "Support for STMicroelectronics Multi-Function eXpander (STMFX)" depends on I2C diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile -index 1780019d2474..90ffa501ae2d 100644 +index 1780019d2..90ffa501a 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -255,6 +255,7 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o @@ -50,7 +49,7 @@ index 1780019d2474..90ffa501ae2d 100644 obj-$(CONFIG_RAVE_SP_CORE) += rave-sp.o diff --git a/drivers/mfd/stm32-pwr.c b/drivers/mfd/stm32-pwr.c new file mode 100644 -index 000000000000..5c130603d554 +index 000000000..5c130603d --- /dev/null +++ b/drivers/mfd/stm32-pwr.c @@ -0,0 +1,402 @@ @@ -457,7 +456,7 @@ index 000000000000..5c130603d554 +arch_initcall(stm32_pwr_init); +module_exit(stm32_pwr_exit); diff --git a/drivers/mfd/stmfx.c b/drivers/mfd/stmfx.c -index 988e2ba6dd0f..39b2fc952b7d 100644 +index 988e2ba6d..39b2fc952 100644 --- a/drivers/mfd/stmfx.c +++ b/drivers/mfd/stmfx.c @@ -81,13 +81,11 @@ static struct mfd_cell stmfx_cells[] = { @@ -475,7 +474,7 @@ index 988e2ba6dd0f..39b2fc952b7d 100644 .resources = stmfx_ts_resources, .num_resources = ARRAY_SIZE(stmfx_ts_resources), diff --git a/drivers/mfd/stpmic1.c b/drivers/mfd/stpmic1.c -index eb3da558c3fb..40eef5d18b90 100644 +index eb3da558c..40eef5d18 100644 --- a/drivers/mfd/stpmic1.c +++ b/drivers/mfd/stpmic1.c @@ -170,6 +170,9 @@ static int stpmic1_suspend(struct device *dev) @@ -499,7 +498,7 @@ index eb3da558c3fb..40eef5d18b90 100644 return 0; diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c -index 3b2b93c5bbcb..507572b091ab 100644 +index 3b2b93c5b..507572b09 100644 --- a/drivers/mfd/wm8994-core.c +++ b/drivers/mfd/wm8994-core.c @@ -185,6 +185,12 @@ static int wm8994_resume(struct device *dev) @@ -516,7 +515,7 @@ index 3b2b93c5bbcb..507572b091ab 100644 wm8994->supplies); if (ret != 0) { diff --git a/include/linux/mfd/stm32-timers.h b/include/linux/mfd/stm32-timers.h -index f8db83aedb2b..f48f04dc4187 100644 +index f8db83aed..f48f04dc4 100644 --- a/include/linux/mfd/stm32-timers.h +++ b/include/linux/mfd/stm32-timers.h @@ -31,6 +31,7 @@ diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch new file mode 100644 index 0000000..acd1f3e --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch @@ -0,0 +1,40 @@ +From b1ce5fb5a80db8945c9496f8ad9a74280d31ecf8 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:47 +0200 +Subject: [PATCH 12/23] ARM 5.10.61-stm32mp1-r2 MMC + +--- + drivers/mmc/core/mmc_test.c | 2 +- + drivers/mmc/host/mmci.c | 3 --- + 2 files changed, 1 insertion(+), 4 deletions(-) + +diff --git a/drivers/mmc/core/mmc_test.c b/drivers/mmc/core/mmc_test.c +index 152e7525e..b1f0d04f9 100644 +--- a/drivers/mmc/core/mmc_test.c ++++ b/drivers/mmc/core/mmc_test.c +@@ -2124,7 +2124,7 @@ static int mmc_test_rw_multiple(struct mmc_test_card *test, + if (mmc_can_erase(test->card) && + tdata->prepare & MMC_TEST_PREP_ERASE) { + ret = mmc_erase(test->card, dev_addr, +- size / 512, MMC_SECURE_ERASE_ARG); ++ size / 512, test->card->erase_arg); + if (ret) + ret = mmc_erase(test->card, dev_addr, + size / 512, MMC_ERASE_ARG); +diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c +index 9bde0def1..fa6d85190 100644 +--- a/drivers/mmc/host/mmci.c ++++ b/drivers/mmc/host/mmci.c +@@ -2104,9 +2104,6 @@ static int mmci_probe(struct amba_device *dev, + host->stop_abort.arg = 0; + host->stop_abort.flags = MMC_RSP_R1B | MMC_CMD_AC; + +- /* We support these PM capabilities. */ +- mmc->pm_caps |= MMC_PM_KEEP_POWER; +- + /* + * We can do SGIO + */ +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0013-ARM-5.10.10-stm32mp1-r1-NET-TTY.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0013-ARM-5.10.61-stm32mp1-r2-NET-TTY.patch similarity index 54% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0013-ARM-5.10.10-stm32mp1-r1-NET-TTY.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0013-ARM-5.10.61-stm32mp1-r2-NET-TTY.patch index 5bdb79e..6c77653 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0013-ARM-5.10.10-stm32mp1-r1-NET-TTY.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0013-ARM-5.10.61-stm32mp1-r2-NET-TTY.patch @@ -1,9 +1,8 @@ -From 480758c596f5d02d795cb5896c5280a6787b72d2 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:13:39 +0100 -Subject: [PATCH 13/22] ARM 5.10.10-stm32mp1-r1 NET-TTY +From 286a0f7ad98148a83597347e2e33eb1141973c06 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:48 +0200 +Subject: [PATCH 13/23] ARM 5.10.61-stm32mp1-r2 NET-TTY -Signed-off-by: Romuald JEANNE --- .../net/ethernet/stmicro/stmmac/dwmac-stm32.c | 58 +- .../net/ethernet/stmicro/stmmac/stmmac_main.c | 42 +- @@ -11,13 +10,13 @@ Signed-off-by: Romuald JEANNE drivers/tty/serial/serial_core.c | 10 + drivers/tty/serial/serial_mctrl_gpio.c | 38 + drivers/tty/serial/serial_mctrl_gpio.h | 18 + - drivers/tty/serial/stm32-usart.c | 1250 +++++++++++------ - drivers/tty/serial/stm32-usart.h | 28 +- + drivers/tty/serial/stm32-usart.c | 1095 ++++++++++++----- + drivers/tty/serial/stm32-usart.h | 30 +- include/uapi/linux/serial.h | 2 + - 9 files changed, 973 insertions(+), 486 deletions(-) + 9 files changed, 949 insertions(+), 357 deletions(-) diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c -index 5d4df4c5254e..ffaa434e075b 100644 +index 5d4df4c52..ffaa434e0 100644 --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-stm32.c @@ -89,7 +89,6 @@ struct stm32_dwmac { @@ -119,10 +118,10 @@ index 5d4df4c5254e..ffaa434e075b 100644 return ret; } diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -index b3d6d8e3f4de..9c69edc20751 100644 +index 3134f7e66..9ac005db1 100644 --- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c +++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c -@@ -1533,18 +1533,18 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) +@@ -1548,18 +1548,18 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv, u32 queue) stmmac_free_tx_buffer(priv, queue, i); } @@ -148,7 +147,7 @@ index b3d6d8e3f4de..9c69edc20751 100644 /** * free_dma_rx_desc_resources - free RX dma desc resources -@@ -5289,8 +5289,25 @@ int stmmac_resume(struct device *dev) +@@ -5316,8 +5316,25 @@ int stmmac_resume(struct device *dev) stmmac_reset_queues_param(priv); @@ -176,7 +175,7 @@ index b3d6d8e3f4de..9c69edc20751 100644 stmmac_hw_setup(ndev, false); stmmac_init_coalesce(priv); -@@ -5308,6 +5325,13 @@ int stmmac_resume(struct device *dev) +@@ -5335,6 +5352,13 @@ int stmmac_resume(struct device *dev) netif_device_attach(ndev); return 0; @@ -191,7 +190,7 @@ index b3d6d8e3f4de..9c69edc20751 100644 EXPORT_SYMBOL_GPL(stmmac_resume); diff --git a/drivers/net/phy/realtek.c b/drivers/net/phy/realtek.c -index 575580d3ffe0..a200019180de 100644 +index b4879306b..aa3295e9c 100644 --- a/drivers/net/phy/realtek.c +++ b/drivers/net/phy/realtek.c @@ -26,16 +26,11 @@ @@ -227,7 +226,7 @@ index 575580d3ffe0..a200019180de 100644 switch (phydev->interface) { case PHY_INTERFACE_MODE_RGMII: -@@ -621,6 +617,7 @@ static struct phy_driver realtek_drvs[] = { +@@ -634,6 +630,7 @@ static struct phy_driver realtek_drvs[] = { PHY_ID_MATCH_EXACT(0x001cc916), .name = "RTL8211F Gigabit Ethernet", .config_init = &rtl8211f_config_init, @@ -236,10 +235,10 @@ index 575580d3ffe0..a200019180de 100644 .config_intr = &rtl8211f_config_intr, .suspend = genphy_suspend, diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c -index 828f9ad1be49..c8ed6756c255 100644 +index 68a0ff605..1afbeaea6 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c -@@ -3224,6 +3224,16 @@ int uart_get_rs485_mode(struct uart_port *port) +@@ -3226,6 +3226,16 @@ int uart_get_rs485_mode(struct uart_port *port) u32 rs485_delay[2]; int ret; @@ -257,7 +256,7 @@ index 828f9ad1be49..c8ed6756c255 100644 rs485_delay, 2); if (!ret) { diff --git a/drivers/tty/serial/serial_mctrl_gpio.c b/drivers/tty/serial/serial_mctrl_gpio.c -index fb4781292d40..1fc2f704769e 100644 +index fb4781292..1fc2f7047 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.c +++ b/drivers/tty/serial/serial_mctrl_gpio.c @@ -299,4 +299,42 @@ void mctrl_gpio_disable_ms(struct mctrl_gpios *gpios) @@ -304,7 +303,7 @@ index fb4781292d40..1fc2f704769e 100644 + MODULE_LICENSE("GPL"); diff --git a/drivers/tty/serial/serial_mctrl_gpio.h b/drivers/tty/serial/serial_mctrl_gpio.h -index b134a0ffc894..fc76910fb105 100644 +index b134a0ffc..fc76910fb 100644 --- a/drivers/tty/serial/serial_mctrl_gpio.h +++ b/drivers/tty/serial/serial_mctrl_gpio.h @@ -91,6 +91,16 @@ void mctrl_gpio_enable_ms(struct mctrl_gpios *gpios); @@ -340,7 +339,7 @@ index b134a0ffc894..fc76910fb105 100644 #endif diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c -index ee6c7762d355..5694e78646eb 100644 +index 844059861..3475ff831 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -4,6 +4,7 @@ @@ -351,40 +350,12 @@ index ee6c7762d355..5694e78646eb 100644 * * Inspired by st-asc.c from STMicroelectronics (c) */ -@@ -34,15 +35,15 @@ - #include "serial_mctrl_gpio.h" - #include "stm32-usart.h" - --static void stm32_stop_tx(struct uart_port *port); --static void stm32_transmit_chars(struct uart_port *port); -+static void stm32_usart_stop_tx(struct uart_port *port); -+static void stm32_usart_transmit_chars(struct uart_port *port); - - static inline struct stm32_port *to_stm32_port(struct uart_port *port) - { - return container_of(port, struct stm32_port, port); - } - --static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) -+static void stm32_usart_set_bits(struct uart_port *port, u32 reg, u32 bits) - { - u32 val; - -@@ -51,7 +52,7 @@ static void stm32_set_bits(struct uart_port *port, u32 reg, u32 bits) +@@ -60,38 +61,65 @@ static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits) writel_relaxed(val, port->membase + reg); } --static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) -+static void stm32_usart_clr_bits(struct uart_port *port, u32 reg, u32 bits) - { - u32 val; - -@@ -60,43 +61,70 @@ static void stm32_clr_bits(struct uart_port *port, u32 reg, u32 bits) - writel_relaxed(val, port->membase + reg); - } - --static void stm32_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, -- u32 delay_DDE, u32 baud) +-static void stm32_usart_config_reg_rs485(u32 *cr1, u32 *cr3, u32 delay_ADE, +- u32 delay_DDE, u32 baud) +static u32 stm32_usart_config_delay_rs485(u32 *cr1, u32 delay, u32 baud, + bool over8, u32 rs485_deat_dedt_max, + struct serial_rs485 *rs485conf) @@ -468,74 +439,86 @@ index ee6c7762d355..5694e78646eb 100644 *cr1 |= rs485_deat_dedt; } --static int stm32_config_rs485(struct uart_port *port, -- struct serial_rs485 *rs485conf) -+static int stm32_usart_config_rs485(struct uart_port *port, -+ struct serial_rs485 *rs485conf) +@@ -99,8 +127,8 @@ static int stm32_usart_config_rs485(struct uart_port *port, + struct serial_rs485 *rs485conf) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -104,7 +132,7 @@ static int stm32_config_rs485(struct uart_port *port, +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_config *cfg = &stm32_port->info->cfg; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_config *cfg = &stm32_port->info->cfg; u32 usartdiv, baud, cr1, cr3; bool over8; -- stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -+ stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - - port->rs485 = *rs485conf; - -@@ -122,9 +150,7 @@ static int stm32_config_rs485(struct uart_port *port, +@@ -122,10 +150,7 @@ static int stm32_usart_config_rs485(struct uart_port *port, << USART_BRR_04_R_SHIFT; baud = DIV_ROUND_CLOSEST(port->uartclk, usartdiv); -- stm32_config_reg_rs485(&cr1, &cr3, -- rs485conf->delay_rts_before_send, -- rs485conf->delay_rts_after_send, baud); +- stm32_usart_config_reg_rs485(&cr1, &cr3, +- rs485conf->delay_rts_before_send, +- rs485conf->delay_rts_after_send, +- baud); + stm32_usart_config_reg_rs485(&cr1, &cr3, baud, rs485conf); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; -@@ -137,18 +163,19 @@ static int stm32_config_rs485(struct uart_port *port, - writel_relaxed(cr3, port->membase + ofs->cr3); - writel_relaxed(cr1, port->membase + ofs->cr1); - } else { -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DEM | USART_CR3_DEP); -- stm32_clr_bits(port, ofs->cr1, -- USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); -+ stm32_usart_clr_bits(port, ofs->cr3, -+ USART_CR3_DEM | USART_CR3_DEP); -+ stm32_usart_clr_bits(port, ofs->cr1, -+ USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); - } - -- stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -+ stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - - return 0; - } - --static int stm32_init_rs485(struct uart_port *port, -- struct platform_device *pdev) -+static int stm32_usart_init_rs485(struct uart_port *port, -+ struct platform_device *pdev) - { - struct serial_rs485 *rs485conf = &port->rs485; - -@@ -162,64 +189,67 @@ static int stm32_init_rs485(struct uart_port *port, +@@ -164,63 +189,109 @@ static int stm32_usart_init_rs485(struct uart_port *port, return uart_get_rs485_mode(port); } --static int stm32_pending_rx(struct uart_port *port, u32 *sr, int *last_res, -- bool threaded) -+static bool stm32_usart_rx_dma_enabled(struct uart_port *port) +-static int stm32_usart_pending_rx(struct uart_port *port, u32 *sr, +- int *last_res, bool threaded) ++static bool stm32_usart_rx_dma_started(struct stm32_port *stm32_port) +{ -+ struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ return stm32_port->rx_ch ? stm32_port->rx_dma_busy : false; ++} + -+ if (!stm32_port->rx_ch) -+ return false; ++static void stm32_usart_rx_dma_terminate(struct stm32_port *stm32_port) ++{ ++ dmaengine_terminate_async(stm32_port->rx_ch); ++ stm32_port->rx_dma_busy = false; ++} + -+ return !!(readl_relaxed(port->membase + ofs->cr3) & USART_CR3_DMAR); ++static int stm32_usart_dma_pause_resume(struct stm32_port *stm32_port, ++ struct dma_chan *chan, ++ enum dma_status expected_status, ++ int (*dma_action)(struct dma_chan *chan), ++ bool (*dma_started)(struct stm32_port *stm32_port), ++ void (*dma_terminate)(struct stm32_port *stm32_port)) ++{ ++ struct uart_port *port = &stm32_port->port; ++ enum dma_status dma_status; ++ int ret; ++ ++ if (!(*dma_started)(stm32_port)) ++ return -EPERM; ++ ++ dma_status = dmaengine_tx_status(chan, chan->cookie, NULL); ++ if (dma_status != expected_status) ++ return -EAGAIN; ++ ++ ret = (*dma_action)(chan); ++ if (ret) { ++ dev_err(port->dev, "DMA failed with error code: %d\n", ret); ++ (*dma_terminate)(stm32_port); ++ } ++ return ret; ++} ++ ++static int stm32_usart_rx_dma_pause(struct stm32_port *stm32_port) ++{ ++ return stm32_usart_dma_pause_resume(stm32_port, stm32_port->rx_ch, ++ DMA_IN_PROGRESS, dmaengine_pause, ++ stm32_usart_rx_dma_started, ++ stm32_usart_rx_dma_terminate); ++} ++ ++static int stm32_usart_rx_dma_resume(struct stm32_port *stm32_port) ++{ ++ return stm32_usart_dma_pause_resume(stm32_port, stm32_port->rx_ch, ++ DMA_PAUSED, dmaengine_resume, ++ stm32_usart_rx_dma_started, ++ stm32_usart_rx_dma_terminate); +} + +/* @@ -545,9 +528,10 @@ index ee6c7762d355..5694e78646eb 100644 +static bool stm32_usart_pending_rx_pio(struct uart_port *port, u32 *sr) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - enum dma_status status; - struct dma_tx_state state; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; *sr = readl_relaxed(port->membase + ofs->isr); + /* Get pending characters in RDR or FIFO */ @@ -556,15 +540,14 @@ index ee6c7762d355..5694e78646eb 100644 + * Get all pending characters from the RDR or the FIFO when + * using interrupts + */ -+ if (!stm32_usart_rx_dma_enabled(port)) ++ if (!stm32_usart_rx_dma_started(stm32_port)) + return true; - if (threaded && stm32_port->rx_ch) { - status = dmaengine_tx_status(stm32_port->rx_ch, - stm32_port->rx_ch->cookie, - &state); -- if ((status == DMA_IN_PROGRESS) && -- (*last_res != state.residue)) +- if (status == DMA_IN_PROGRESS && (*last_res != state.residue)) - return 1; - else - return 0; @@ -579,12 +562,13 @@ index ee6c7762d355..5694e78646eb 100644 + return false; } --static unsigned long stm32_get_char(struct uart_port *port, u32 *sr, -- int *last_res) +-static unsigned long stm32_usart_get_char(struct uart_port *port, u32 *sr, +- int *last_res) +static unsigned long stm32_usart_get_char_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; - if (stm32_port->rx_ch) { @@ -603,43 +587,42 @@ index ee6c7762d355..5694e78646eb 100644 return c; } --static void stm32_receive_chars(struct uart_port *port, bool threaded) +-static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) +static unsigned int stm32_usart_receive_chars_pio(struct uart_port *port) { - struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long c; + unsigned int size = 0; u32 sr; char flag; -- if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) -- pm_wakeup_event(tport->tty->dev, 0); +- spin_lock(&port->lock); - -- while (stm32_pending_rx(port, &sr, &stm32_port->last_res, threaded)) { +- while (stm32_usart_pending_rx(port, &sr, &stm32_port->last_res, +- threaded)) { + while (stm32_usart_pending_rx_pio(port, &sr)) { sr |= USART_SR_DUMMY_RX; flag = TTY_NORMAL; -@@ -238,8 +268,9 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) +@@ -239,8 +310,9 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) writel_relaxed(sr & USART_SR_ERR_MASK, port->membase + ofs->icr); -- c = stm32_get_char(port, &sr, &stm32_port->last_res); +- c = stm32_usart_get_char(port, &sr, &stm32_port->last_res); + c = stm32_usart_get_char_pio(port); port->icount.rx++; + size++; if (sr & USART_SR_ERR_MASK) { if (sr & USART_SR_ORE) { port->icount.overrun++; -@@ -273,25 +304,140 @@ static void stm32_receive_chars(struct uart_port *port, bool threaded) +@@ -274,21 +346,216 @@ static void stm32_usart_receive_chars(struct uart_port *port, bool threaded) uart_insert_char(port, sr, USART_SR_ORE, c, flag); } - spin_unlock(&port->lock); -- tty_flip_buffer_push(tport); -- spin_lock(&port->lock); + return size; +} + @@ -649,9 +632,19 @@ index ee6c7762d355..5694e78646eb 100644 + struct stm32_port *stm32_port = to_stm32_port(port); + struct tty_port *ttyport = &stm32_port->port.state->port; + unsigned char *dma_start; -+ int dma_count; ++ int dma_count, i; + + dma_start = stm32_port->rx_buf + (RX_BUF_L - stm32_port->last_res); ++ ++ /* ++ * Apply rdr_mask on buffer in order to mask parity bit. ++ * This loop is useless in cs8 mode because DMA copies only ++ * 8 bits and already ignores parity bit. ++ */ ++ if (!(stm32_port->rdr_mask == (BIT(8) - 1))) ++ for (i = 0; i < dma_size; i++) ++ *(dma_start + i) &= stm32_port->rdr_mask; ++ + dma_count = tty_insert_flip_string(ttyport, dma_start, dma_size); + port->icount.rx += dma_count; + if (dma_count != dma_size) @@ -680,7 +673,8 @@ index ee6c7762d355..5694e78646eb 100644 + dma_size = stm32_port->last_res - stm32_port->rx_dma_state.residue; + stm32_usart_push_buffer_dma(port, dma_size); + size += dma_size; -+ + +- tty_flip_buffer_push(tport); + return size; +} + @@ -694,11 +688,12 @@ index ee6c7762d355..5694e78646eb 100644 + u32 sr; + unsigned int size; + -+ if (stm32_usart_rx_dma_enabled(port) || force_dma_flush) { ++ if (stm32_usart_rx_dma_started(stm32_port) || force_dma_flush) { + rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, + stm32_port->rx_ch->cookie, + &stm32_port->rx_dma_state); -+ if (rx_dma_status == DMA_IN_PROGRESS) { ++ if (rx_dma_status == DMA_IN_PROGRESS || ++ rx_dma_status == DMA_PAUSED) { + /* Empty DMA buffer */ + size = stm32_usart_receive_chars_dma(port); + sr = readl_relaxed(port->membase + ofs->isr); @@ -716,8 +711,7 @@ index ee6c7762d355..5694e78646eb 100644 + } + } else { + /* Disable RX DMA */ -+ dmaengine_terminate_async(stm32_port->rx_ch); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ stm32_usart_rx_dma_terminate(stm32_port); + /* Fall back to interrupt mode */ + dev_dbg(port->dev, + "DMA error, fallback to irq mode\n"); @@ -731,6 +725,72 @@ index ee6c7762d355..5694e78646eb 100644 + tty_flip_buffer_push(tport); +} + ++static void stm32_usart_rx_dma_complete(void *arg) ++{ ++ struct uart_port *port = arg; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&port->lock, flags); ++ stm32_usart_receive_chars(port, false); ++ spin_unlock_irqrestore(&port->lock, flags); ++} ++ ++static int stm32_usart_rx_dma_start_or_resume(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct dma_async_tx_descriptor *desc; ++ enum dma_status rx_dma_status; ++ int ret; ++ ++ if (stm32_port->throttled) ++ return 0; ++ ++ if (stm32_port->rx_dma_busy) { ++ rx_dma_status = dmaengine_tx_status(stm32_port->rx_ch, ++ stm32_port->rx_ch->cookie, ++ NULL); ++ if (rx_dma_status == DMA_IN_PROGRESS) ++ return 0; ++ ++ if (rx_dma_status == DMA_PAUSED && !stm32_usart_rx_dma_resume(stm32_port)) ++ return 0; ++ ++ dev_err(port->dev, "DMA failed : status error.\n"); ++ stm32_usart_rx_dma_terminate(stm32_port); ++ } ++ ++ stm32_port->rx_dma_busy = true; ++ ++ stm32_port->last_res = RX_BUF_L; ++ /* Prepare a DMA cyclic transaction */ ++ desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, ++ stm32_port->rx_dma_buf, ++ RX_BUF_L, RX_BUF_P, ++ DMA_DEV_TO_MEM, ++ DMA_PREP_INTERRUPT); ++ if (!desc) { ++ dev_err(port->dev, "rx dma prep cyclic failed\n"); ++ stm32_port->rx_dma_busy = false; ++ return -ENODEV; ++ } ++ ++ desc->callback = stm32_usart_rx_dma_complete; ++ desc->callback_param = port; ++ ++ /* Push current DMA transaction in the pending queue */ ++ ret = dma_submit_error(dmaengine_submit(desc)); ++ if (ret) { ++ dmaengine_terminate_sync(stm32_port->rx_ch); ++ stm32_port->rx_dma_busy = false; ++ return ret; ++ } ++ ++ /* Issue pending DMA requests */ ++ dma_async_issue_pending(stm32_port->rx_ch); ++ ++ return 0; ++} ++ +static void stm32_usart_tx_dma_terminate(struct stm32_port *stm32_port) +{ + dmaengine_terminate_async(stm32_port->tx_ch); @@ -749,119 +809,99 @@ index ee6c7762d355..5694e78646eb 100644 + return stm32_port->tx_dma_busy; +} + -+static bool stm32_usart_tx_dma_enabled(struct stm32_port *stm32_port) ++static int stm32_usart_tx_dma_pause(struct stm32_port *stm32_port) +{ -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ return stm32_usart_dma_pause_resume(stm32_port, stm32_port->tx_ch, ++ DMA_IN_PROGRESS, dmaengine_pause, ++ stm32_usart_tx_dma_started, ++ stm32_usart_tx_dma_terminate); ++} + -+ return !!(readl_relaxed(stm32_port->port.membase + ofs->cr3) -+ & USART_CR3_DMAT); ++static int stm32_usart_tx_dma_resume(struct stm32_port *stm32_port) ++{ ++ return stm32_usart_dma_pause_resume(stm32_port, stm32_port->tx_ch, ++ DMA_PAUSED, dmaengine_resume, ++ stm32_usart_tx_dma_started, ++ stm32_usart_tx_dma_terminate); } --static void stm32_tx_dma_complete(void *arg) -+static void stm32_usart_tx_dma_complete(void *arg) + static void stm32_usart_tx_dma_complete(void *arg) { struct uart_port *port = arg; struct stm32_port *stm32port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; -+ unsigned long flags; +- const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32port->info->ofs; + unsigned long flags; -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); +- dmaengine_terminate_async(stm32port->tx_ch); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32port->tx_dma_busy = false; -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_usart_tx_dma_terminate(stm32port); /* Let's see if we have pending data to send */ -- stm32_transmit_chars(port); -+ spin_lock_irqsave(&port->lock, flags); -+ stm32_usart_transmit_chars(port); -+ spin_unlock_irqrestore(&port->lock, flags); - } - --static void stm32_tx_interrupt_enable(struct uart_port *port) -+static void stm32_usart_tx_interrupt_enable(struct uart_port *port) + spin_lock_irqsave(&port->lock, flags); +@@ -299,13 +566,13 @@ static void stm32_usart_tx_dma_complete(void *arg) + static void stm32_usart_tx_interrupt_enable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -300,33 +446,41 @@ static void stm32_tx_interrupt_enable(struct uart_port *port) +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + /* * Enables TX FIFO threashold irq when FIFO is enabled, * or TX empty irq when FIFO is disabled */ - if (stm32_port->fifoen) -- stm32_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); + if (stm32_port->fifoen && stm32_port->txftcfg >= 0) -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_TXFTIE); else -- stm32_set_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); - } - --static void stm32_tx_interrupt_disable(struct uart_port *port) -+static void stm32_usart_rx_dma_complete(void *arg) -+{ -+ struct uart_port *port = arg; -+ unsigned long flags; -+ -+ spin_lock_irqsave(&port->lock, flags); -+ stm32_usart_receive_chars(port, false); -+ spin_unlock_irqrestore(&port->lock, flags); -+} -+ -+static void stm32_usart_tx_interrupt_disable(struct uart_port *port) + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_TXEIE); +@@ -314,9 +581,9 @@ static void stm32_usart_tx_interrupt_enable(struct uart_port *port) + static void stm32_usart_tx_interrupt_disable(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - if (stm32_port->fifoen) -- stm32_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + if (stm32_port->fifoen && stm32_port->txftcfg >= 0) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_TXFTIE); else -- stm32_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); -+ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); - } - --static void stm32_transmit_chars_pio(struct uart_port *port) -+static void stm32_usart_transmit_chars_pio(struct uart_port *port) + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_TXEIE); +@@ -325,14 +592,9 @@ static void stm32_usart_tx_interrupt_disable(struct uart_port *port) + static void stm32_usart_transmit_chars_pio(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; - if (stm32_port->tx_dma_busy) { -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); +- stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - stm32_port->tx_dma_busy = false; - } -+ if (stm32_usart_tx_dma_enabled(stm32_port)) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - +- while (!uart_circ_empty(xmit)) { /* Check that TDR is empty before filling FIFO */ -@@ -339,24 +493,25 @@ static void stm32_transmit_chars_pio(struct uart_port *port) - - /* rely on TXE irq (mask or unmask) for sending remaining data */ - if (uart_circ_empty(xmit)) -- stm32_tx_interrupt_disable(port); -+ stm32_usart_tx_interrupt_disable(port); - else -- stm32_tx_interrupt_enable(port); -+ stm32_usart_tx_interrupt_enable(port); - } - --static void stm32_transmit_chars_dma(struct uart_port *port) -+static void stm32_usart_transmit_chars_dma(struct uart_port *port) + if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) +@@ -352,15 +614,19 @@ static void stm32_usart_transmit_chars_pio(struct uart_port *port) + static void stm32_usart_transmit_chars_dma(struct uart_port *port) { struct stm32_port *stm32port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct circ_buf *xmit = &port->state->xmit; struct dma_async_tx_descriptor *desc = NULL; - dma_cookie_t cookie; - unsigned int count, i; -+ unsigned int count, i, ret; ++ dma_cookie_t cookie; ++ unsigned int count; ++ int ret; - if (stm32port->tx_dma_busy) + if (stm32_usart_tx_dma_started(stm32port)) { -+ if (!stm32_usart_tx_dma_enabled(stm32port)) -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); ++ ret = stm32_usart_tx_dma_resume(stm32port); ++ if (ret < 0 && ret != -EAGAIN) ++ goto fallback_err; return; - - stm32port->tx_dma_busy = true; @@ -869,18 +909,10 @@ index ee6c7762d355..5694e78646eb 100644 count = uart_circ_chars_pending(xmit); -@@ -384,136 +539,181 @@ static void stm32_transmit_chars_dma(struct uart_port *port) - DMA_MEM_TO_DEV, - DMA_PREP_INTERRUPT); +@@ -391,13 +657,24 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) + if (!desc) + goto fallback_err; -- if (!desc) { -- for (i = count; i > 0; i--) -- stm32_transmit_chars_pio(port); -- return; -- } -+ if (!desc) -+ goto fallback_err; -+ + /* + * Take "tx_dma_busy" flag. This flag will be release when + * dmaengine_terminate_async will be called. This flag helps @@ -888,50 +920,46 @@ index ee6c7762d355..5694e78646eb 100644 + * if the callback of the previous is not called. + */ + stm32port->tx_dma_busy = true; - -- desc->callback = stm32_tx_dma_complete; -+ desc->callback = stm32_usart_tx_dma_complete; ++ + desc->callback = stm32_usart_tx_dma_complete; desc->callback_param = port; /* Push current DMA TX transaction in the pending queue */ - cookie = dmaengine_submit(desc); +- if (dma_submit_error(dmaengine_submit(desc))) { +- /* dma no yet started, safe to free resources */ +- dmaengine_terminate_async(stm32port->tx_ch); ++ cookie = dmaengine_submit(desc); + ret = dma_submit_error(cookie); ++ /* dma no yet started, safe to free resources */ + if (ret) { -+ /* dma no yet started, safe to free resources */ ++ dev_err(port->dev, "DMA failed with error code: %d\n", ret); + stm32_usart_tx_dma_terminate(stm32port); -+ goto fallback_err; -+ } + goto fallback_err; + } - /* Issue pending DMA TX requests */ - dma_async_issue_pending(stm32port->tx_ch); +@@ -411,24 +688,36 @@ static void stm32_usart_transmit_chars_dma(struct uart_port *port) + return; -- stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); - - xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1); - port->icount.tx += count; -+ return; -+ -+fallback_err: -+ for (i = count; i > 0; i--) -+ stm32_usart_transmit_chars_pio(port); + fallback_err: +- for (i = count; i > 0; i--) +- stm32_usart_transmit_chars_pio(port); ++ stm32_usart_transmit_chars_pio(port); } --static void stm32_transmit_chars(struct uart_port *port) -+static void stm32_usart_transmit_chars(struct uart_port *port) + static void stm32_usart_transmit_chars(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; + u32 isr; + int ret; if (port->x_char) { - if (stm32_port->tx_dma_busy) -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); -+ if (stm32_usart_tx_dma_started(stm32_port) && -+ stm32_usart_tx_dma_enabled(stm32_port)) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); +- stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ /* dma terminate may have been called in case of dma pause failure */ ++ stm32_usart_tx_dma_pause(stm32_port); + + /* Check that TDR is empty before filling FIFO */ + ret = @@ -946,193 +974,96 @@ index ee6c7762d355..5694e78646eb 100644 port->x_char = 0; port->icount.tx++; - if (stm32_port->tx_dma_busy) -- stm32_set_bits(port, ofs->cr3, USART_CR3_DMAT); -+ if (stm32_usart_tx_dma_started(stm32_port)) -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); +- stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAT); ++ ++ /* dma terminate may have been called in case of dma resume failure */ ++ stm32_usart_tx_dma_resume(stm32_port); return; } - if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { -- stm32_tx_interrupt_disable(port); -+ stm32_usart_tx_interrupt_disable(port); - return; - } - - if (ofs->icr == UNDEF_REG) -- stm32_clr_bits(port, ofs->isr, USART_SR_TC); -+ stm32_usart_clr_bits(port, ofs->isr, USART_SR_TC); - else - writel_relaxed(USART_ICR_TCCF, port->membase + ofs->icr); - - if (stm32_port->tx_ch) -- stm32_transmit_chars_dma(port); -+ stm32_usart_transmit_chars_dma(port); - else -- stm32_transmit_chars_pio(port); -+ stm32_usart_transmit_chars_pio(port); - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); - - if (uart_circ_empty(xmit)) -- stm32_tx_interrupt_disable(port); -+ stm32_usart_tx_interrupt_disable(port); - } - --static irqreturn_t stm32_interrupt(int irq, void *ptr) -+static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) - { +@@ -459,7 +748,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) struct uart_port *port = ptr; -+ struct tty_port *tport = &port->state->port; + struct tty_port *tport = &port->state->port; struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; u32 sr; -- spin_lock(&port->lock); -- sr = readl_relaxed(port->membase + ofs->isr); - - if ((sr & USART_SR_RTOF) && ofs->icr != UNDEF_REG) - writel_relaxed(USART_ICR_RTOCF, - port->membase + ofs->icr); - -- if ((sr & USART_SR_WUF) && (ofs->icr != UNDEF_REG)) -+ if ((sr & USART_SR_WUF) && ofs->icr != UNDEF_REG) { -+ /* Clear wake up flag and disable wake up interrupt */ - writel_relaxed(USART_ICR_WUCF, - port->membase + ofs->icr); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); -+ if (irqd_is_wakeup_set(irq_get_irq_data(port->irq))) -+ pm_wakeup_event(tport->tty->dev, 0); -+ } +@@ -477,8 +766,18 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) + pm_wakeup_event(tport->tty->dev, 0); + } - if ((sr & USART_SR_RXNE) && !(stm32_port->rx_ch)) -- stm32_receive_chars(port, false); -- -- if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) -- stm32_transmit_chars(port); + /* + * rx errors in dma mode has to be handled ASAP to avoid overrun as the + * DMA request line has been masked by HW and rx data are stacking in + * FIFO. + */ + if (!stm32_port->throttled && -+ (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_enabled(port)) || -+ ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_enabled(port)))) { ++ (((sr & USART_SR_RXNE) && !stm32_usart_rx_dma_started(stm32_port)) || ++ ((sr & USART_SR_ERR_MASK) && stm32_usart_rx_dma_started(stm32_port)))) { + spin_lock(&port->lock); -+ stm32_usart_receive_chars(port, false); + stm32_usart_receive_chars(port, false); + spin_unlock(&port->lock); + } -- spin_unlock(&port->lock); -+ if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { -+ spin_lock(&port->lock); -+ stm32_usart_transmit_chars(port); -+ spin_unlock(&port->lock); -+ } + if ((sr & USART_SR_TXE) && !(stm32_port->tx_ch)) { + spin_lock(&port->lock); +@@ -486,7 +785,7 @@ static irqreturn_t stm32_usart_interrupt(int irq, void *ptr) + spin_unlock(&port->lock); + } - if (stm32_port->rx_ch) -+ if (stm32_usart_rx_dma_enabled(port)) ++ if (stm32_usart_rx_dma_started(stm32_port)) return IRQ_WAKE_THREAD; else return IRQ_HANDLED; - } - --static irqreturn_t stm32_threaded_interrupt(int irq, void *ptr) -+static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) +@@ -496,9 +795,13 @@ static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) { struct uart_port *port = ptr; -- struct stm32_port *stm32_port = to_stm32_port(port); -- -- spin_lock(&port->lock); -- -- if (stm32_port->rx_ch) -- stm32_receive_chars(port, true); + struct stm32_port *stm32_port = to_stm32_port(port); + unsigned long flags; -- spin_unlock(&port->lock); +- if (stm32_port->rx_ch) +- stm32_usart_receive_chars(port, true); + spin_lock_irqsave(&port->lock, flags); + /* Receiver timeout irq for DMA RX */ -+ stm32_usart_receive_chars(port, false); ++ if (!stm32_port->throttled) ++ stm32_usart_receive_chars(port, false); + spin_unlock_irqrestore(&port->lock, flags); return IRQ_HANDLED; } - --static unsigned int stm32_tx_empty(struct uart_port *port) -+static unsigned int stm32_usart_tx_empty(struct uart_port *port) +@@ -506,7 +809,7 @@ static irqreturn_t stm32_usart_threaded_interrupt(int irq, void *ptr) + static unsigned int stm32_usart_tx_empty(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - -- return readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE; -+ if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) -+ return TIOCSER_TEMT; -+ -+ return 0; - } - --static void stm32_set_mctrl(struct uart_port *port, unsigned int mctrl) -+static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl) - { - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - - if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) -- stm32_set_bits(port, ofs->cr3, USART_CR3_RTSE); -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_RTSE); - else -- stm32_clr_bits(port, ofs->cr3, USART_CR3_RTSE); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_RTSE); - - mctrl_gpio_set(stm32_port->gpios, mctrl); - } - --static unsigned int stm32_get_mctrl(struct uart_port *port) -+static unsigned int stm32_usart_get_mctrl(struct uart_port *port) - { - struct stm32_port *stm32_port = to_stm32_port(port); - unsigned int ret; -@@ -524,23 +724,27 @@ static unsigned int stm32_get_mctrl(struct uart_port *port) - return mctrl_gpio_get(stm32_port->gpios, &ret); - } - --static void stm32_enable_ms(struct uart_port *port) -+static void stm32_usart_enable_ms(struct uart_port *port) - { - mctrl_gpio_enable_ms(to_stm32_port(port)->gpios); - } - --static void stm32_disable_ms(struct uart_port *port) -+static void stm32_usart_disable_ms(struct uart_port *port) - { - mctrl_gpio_disable_ms(to_stm32_port(port)->gpios); - } - - /* Transmit stop */ --static void stm32_stop_tx(struct uart_port *port) -+static void stm32_usart_stop_tx(struct uart_port *port) - { - struct stm32_port *stm32_port = to_stm32_port(port); - struct serial_rs485 *rs485conf = &port->rs485; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -- stm32_tx_interrupt_disable(port); -+ stm32_usart_tx_interrupt_disable(port); -+ if (stm32_usart_tx_dma_started(stm32_port) && -+ stm32_usart_tx_dma_enabled(stm32_port)) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); - - if (rs485conf->flags & SER_RS485_ENABLED) { - if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { -@@ -554,13 +758,13 @@ static void stm32_stop_tx(struct uart_port *port) - } - - /* There are probably characters waiting to be transmitted. */ --static void stm32_start_tx(struct uart_port *port) -+static void stm32_usart_start_tx(struct uart_port *port) + if (readl_relaxed(port->membase + ofs->isr) & USART_SR_TC) + return TIOCSER_TEMT; +@@ -517,7 +820,7 @@ static unsigned int stm32_usart_tx_empty(struct uart_port *port) + static void stm32_usart_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct stm32_port *stm32_port = to_stm32_port(port); +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + + if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS)) + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_RTSE); +@@ -556,6 +859,9 @@ static void stm32_usart_stop_tx(struct uart_port *port) + + stm32_usart_tx_interrupt_disable(port); + ++ /* dma terminate may have been called in case of dma pause failure */ ++ stm32_usart_tx_dma_pause(stm32_port); ++ + if (rs485conf->flags & SER_RS485_ENABLED) { + if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { + mctrl_gpio_set(stm32_port->gpios, +@@ -574,7 +880,7 @@ static void stm32_usart_start_tx(struct uart_port *port) struct serial_rs485 *rs485conf = &port->rs485; struct circ_buf *xmit = &port->state->xmit; @@ -1141,219 +1072,127 @@ index ee6c7762d355..5694e78646eb 100644 return; if (rs485conf->flags & SER_RS485_ENABLED) { -@@ -573,93 +777,166 @@ static void stm32_start_tx(struct uart_port *port) - } - } +@@ -590,18 +896,35 @@ static void stm32_usart_start_tx(struct uart_port *port) + stm32_usart_transmit_chars(port); + } -- stm32_transmit_chars(port); -+ stm32_usart_transmit_chars(port); -+} -+ +/* Flush the transmit buffer. */ +static void stm32_usart_flush_buffer(struct uart_port *port) +{ + struct stm32_port *stm32_port = to_stm32_port(port); -+ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + -+ if (stm32_port->tx_ch) { ++ if (stm32_port->tx_ch) + stm32_usart_tx_dma_terminate(stm32_port); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); -+ } - } - ++} ++ /* Throttle the remote when input buffer is about to overflow. */ --static void stm32_throttle(struct uart_port *port) -+static void stm32_usart_throttle(struct uart_port *port) + static void stm32_usart_throttle(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long flags; spin_lock_irqsave(&port->lock, flags); -- stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + + /* -+ * Disable DMA request line if enabled, so the RX data gets queued -+ * into the FIFO. ++ * Pause DMA transfer, so the RX data gets queued into the FIFO. + * Hardware flow control is triggered when RX FIFO is full. + */ -+ if (stm32_usart_rx_dma_enabled(port)) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); ++ stm32_usart_rx_dma_pause(stm32_port); + -+ stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); if (stm32_port->cr3_irq) -- stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); -+ stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_port->throttled = true; spin_unlock_irqrestore(&port->lock, flags); } - /* Unthrottle the remote, the input buffer can now accept data. */ --static void stm32_unthrottle(struct uart_port *port) -+static void stm32_usart_unthrottle(struct uart_port *port) +@@ -609,7 +932,7 @@ static void stm32_usart_throttle(struct uart_port *port) + static void stm32_usart_unthrottle(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; unsigned long flags; spin_lock_irqsave(&port->lock, flags); -- stm32_set_bits(port, ofs->cr1, stm32_port->cr1_irq); -+ stm32_usart_set_bits(port, ofs->cr1, stm32_port->cr1_irq); +@@ -617,6 +940,15 @@ static void stm32_usart_unthrottle(struct uart_port *port) if (stm32_port->cr3_irq) -- stm32_set_bits(port, ofs->cr3, stm32_port->cr3_irq); -+ stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + stm32_usart_set_bits(port, ofs->cr3, stm32_port->cr3_irq); + ++ stm32_port->throttled = false; + + /* -+ * Switch back to DMA mode (re-enable DMA request line). ++ * Switch back to DMA mode (resume DMA). + * Hardware flow control is stopped when FIFO is not full any more. + */ + if (stm32_port->rx_ch) -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); - -+ stm32_port->throttled = false; ++ stm32_usart_rx_dma_start_or_resume(port); ++ spin_unlock_irqrestore(&port->lock, flags); } - /* Receive stop */ --static void stm32_stop_rx(struct uart_port *port) -+static void stm32_usart_stop_rx(struct uart_port *port) +@@ -624,7 +956,10 @@ static void stm32_usart_unthrottle(struct uart_port *port) + static void stm32_usart_stop_rx(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; - -- stm32_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); -- if (stm32_port->cr3_irq) -- stm32_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); -+ /* Disable DMA request line. */ -+ if (stm32_port->rx_ch) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - -+ stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); -+ if (stm32_port->cr3_irq) -+ stm32_usart_clr_bits(port, ofs->cr3, stm32_port->cr3_irq); - } - - /* Handle breaks - ignored by us */ --static void stm32_break_ctl(struct uart_port *port, int break_state) -+static void stm32_usart_break_ctl(struct uart_port *port, int break_state) -+{ -+} -+ -+static int stm32_usart_start_rx_dma_cyclic(struct uart_port *port) - { -+ struct stm32_port *stm32_port = to_stm32_port(port); +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -+ struct dma_async_tx_descriptor *desc; -+ int ret; + -+ stm32_port->last_res = RX_BUF_L; -+ /* Prepare a DMA cyclic transaction */ -+ desc = dmaengine_prep_dma_cyclic(stm32_port->rx_ch, -+ stm32_port->rx_dma_buf, -+ RX_BUF_L, RX_BUF_P, -+ DMA_DEV_TO_MEM, -+ DMA_PREP_INTERRUPT); -+ if (!desc) { -+ dev_err(port->dev, "rx dma prep cyclic failed\n"); -+ return -ENODEV; -+ } -+ -+ desc->callback = stm32_usart_rx_dma_complete; -+ desc->callback_param = port; -+ -+ /* Push current DMA transaction in the pending queue */ -+ ret = dma_submit_error(dmaengine_submit(desc)); -+ if (ret) { -+ dmaengine_terminate_sync(stm32_port->rx_ch); -+ return ret; -+ } -+ -+ /* Issue pending DMA requests */ -+ dma_async_issue_pending(stm32_port->rx_ch); -+ -+ /* -+ * DMA request line not re-enabled at resume when port is throttled. -+ * It will be re-enabled by unthrottle ops. -+ */ -+ if (!stm32_port->throttled) -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_DMAR); -+ -+ return 0; - } ++ /* Disable DMA request line. */ ++ stm32_usart_rx_dma_pause(stm32_port); --static int stm32_startup(struct uart_port *port) -+static int stm32_usart_startup(struct uart_port *port) + stm32_usart_clr_bits(port, ofs->cr1, stm32_port->cr1_irq); + if (stm32_port->cr3_irq) +@@ -639,8 +974,8 @@ static void stm32_usart_break_ctl(struct uart_port *port, int break_state) + static int stm32_usart_startup(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_config *cfg = &stm32_port->info->cfg; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct stm32_usart_config *cfg = &stm32_port->info->cfg; const char *name = to_platform_device(port->dev)->name; u32 val; int ret; - -- ret = request_threaded_irq(port->irq, stm32_interrupt, -- stm32_threaded_interrupt, -+ ret = request_threaded_irq(port->irq, stm32_usart_interrupt, -+ stm32_usart_threaded_interrupt, - IRQF_NO_SUSPEND, name, port); - if (ret) - return ret; - - /* RX FIFO Flush */ +@@ -656,6 +991,14 @@ static int stm32_usart_startup(struct uart_port *port) if (ofs->rqr != UNDEF_REG) -- stm32_set_bits(port, ofs->rqr, USART_RQR_RXFRQ); -+ writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); + writel_relaxed(USART_RQR_RXFRQ, port->membase + ofs->rqr); -- /* Tx and RX FIFO configuration */ -- if (stm32_port->fifoen) { -- val = readl_relaxed(port->membase + ofs->cr3); -- val &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK); -- val |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; -- val |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; -- writel_relaxed(val, port->membase + ofs->cr3); + if (stm32_port->rx_ch) { -+ ret = stm32_usart_start_rx_dma_cyclic(port); ++ ret = stm32_usart_rx_dma_start_or_resume(port); + if (ret) { + free_irq(port->irq, port); + return ret; + } - } - -- /* RX FIFO enabling */ -- val = stm32_port->cr1_irq | USART_CR1_RE; -- if (stm32_port->fifoen) -- val |= USART_CR1_FIFOEN; -- stm32_set_bits(port, ofs->cr1, val); -+ /* RX enabling */ -+ val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); -+ stm32_usart_set_bits(port, ofs->cr1, val); - - return 0; - } - --static void stm32_shutdown(struct uart_port *port) -+static void stm32_usart_shutdown(struct uart_port *port) ++ } ++ + /* RX enabling */ + val = stm32_port->cr1_irq | USART_CR1_RE | BIT(cfg->uart_enable_bit); + stm32_usart_set_bits(port, ofs->cr1, val); +@@ -666,11 +1009,17 @@ static int stm32_usart_startup(struct uart_port *port) + static void stm32_usart_shutdown(struct uart_port *port) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -667,8 +944,14 @@ static void stm32_shutdown(struct uart_port *port) +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_config *cfg = &stm32_port->info->cfg; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_config *cfg = &stm32_port->info->cfg; u32 val, isr; int ret; -+ if (stm32_usart_tx_dma_enabled(stm32_port)) -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); -+ + if (stm32_usart_tx_dma_started(stm32_port)) + stm32_usart_tx_dma_terminate(stm32_port); ++ ++ if (stm32_port->tx_ch) ++ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + /* Disable modem control interrupts */ -- stm32_disable_ms(port); -+ stm32_usart_disable_ms(port); + stm32_usart_disable_ms(port); - val = USART_CR1_TXEIE | USART_CR1_TE; - val |= stm32_port->cr1_irq | USART_CR1_RE; -@@ -680,15 +963,25 @@ static void stm32_shutdown(struct uart_port *port) +@@ -684,8 +1033,13 @@ static void stm32_usart_shutdown(struct uart_port *port) isr, (isr & USART_SR_TC), 10, 100000); @@ -1364,96 +1203,36 @@ index ee6c7762d355..5694e78646eb 100644 + + /* Disable RX DMA. */ + if (stm32_port->rx_ch) -+ dmaengine_terminate_async(stm32_port->rx_ch); -+ -+ /* flush RX & TX FIFO */ -+ if (ofs->rqr != UNDEF_REG) -+ writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, -+ port->membase + ofs->rqr); - -- stm32_clr_bits(port, ofs->cr1, val); -+ stm32_usart_clr_bits(port, ofs->cr1, val); - - free_irq(port->irq, port); - } - --static unsigned int stm32_get_databits(struct ktermios *termios) -+static unsigned int stm32_usart_get_databits(struct ktermios *termios) - { - unsigned int bits; - -@@ -718,8 +1011,9 @@ static unsigned int stm32_get_databits(struct ktermios *termios) - return bits; - } - --static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, -- struct ktermios *old) -+static void stm32_usart_set_termios(struct uart_port *port, -+ struct ktermios *termios, -+ struct ktermios *old) - { - struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -728,8 +1022,9 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - unsigned int baud, bits; - u32 usartdiv, mantissa, fraction, oversampling; - tcflag_t cflag = termios->c_cflag; -- u32 cr1, cr2, cr3; -+ u32 cr1, cr2, cr3, isr; - unsigned long flags; -+ int ret; - - if (!stm32_port->hw_flow_control) - cflag &= ~CRTSCTS; -@@ -738,26 +1033,42 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - - spin_lock_irqsave(&port->lock, flags); - -+ ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, -+ isr, -+ (isr & USART_SR_TC), -+ 10, 100000); -+ -+ /* Send the TC error message only when ISR_TC is not set. */ -+ if (ret) -+ dev_err(port->dev, "Transmission is not complete\n"); -+ - /* Stop serial port and reset value */ - writel_relaxed(0, port->membase + ofs->cr1); ++ stm32_usart_rx_dma_terminate(stm32_port); /* flush RX & TX FIFO */ if (ofs->rqr != UNDEF_REG) -- stm32_set_bits(port, ofs->rqr, -- USART_RQR_TXFRQ | USART_RQR_RXFRQ); -+ writel_relaxed(USART_RQR_TXFRQ | USART_RQR_RXFRQ, -+ port->membase + ofs->rqr); - - cr1 = USART_CR1_TE | USART_CR1_RE; - if (stm32_port->fifoen) - cr1 |= USART_CR1_FIFOEN; - cr2 = 0; -+ -+ /* Tx and RX FIFO configuration */ +@@ -732,8 +1086,8 @@ static void stm32_usart_set_termios(struct uart_port *port, + struct ktermios *old) + { + struct stm32_port *stm32_port = to_stm32_port(port); +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_config *cfg = &stm32_port->info->cfg; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_config *cfg = &stm32_port->info->cfg; + struct serial_rs485 *rs485conf = &port->rs485; + unsigned int baud, bits; + u32 usartdiv, mantissa, fraction, oversampling; +@@ -775,9 +1129,10 @@ static void stm32_usart_set_termios(struct uart_port *port, cr3 = readl_relaxed(port->membase + ofs->cr3); -- cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTCFG_MASK | USART_CR3_RXFTIE -- | USART_CR3_TXFTCFG_MASK; -+ cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; -+ if (stm32_port->fifoen) { + cr3 &= USART_CR3_TXFTIE | USART_CR3_RXFTIE; + if (stm32_port->fifoen) { +- cr3 &= ~(USART_CR3_TXFTCFG_MASK | USART_CR3_RXFTCFG_MASK); +- cr3 |= USART_CR3_TXFTCFG_HALF << USART_CR3_TXFTCFG_SHIFT; +- cr3 |= USART_CR3_RXFTCFG_HALF << USART_CR3_RXFTCFG_SHIFT; + if (stm32_port->txftcfg >= 0) + cr3 |= stm32_port->txftcfg << USART_CR3_TXFTCFG_SHIFT; + if (stm32_port->rxftcfg >= 0) + cr3 |= stm32_port->rxftcfg << USART_CR3_RXFTCFG_SHIFT; -+ } + } if (cflag & CSTOPB) - cr2 |= USART_CR2_STOP_2B; - -- bits = stm32_get_databits(termios); -+ bits = stm32_usart_get_databits(termios); - stm32_port->rdr_mask = (BIT(bits) - 1); - - if (cflag & PARENB) { -@@ -781,7 +1092,8 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -807,7 +1162,8 @@ static void stm32_usart_set_termios(struct uart_port *port, , bits); if (ofs->rtor != UNDEF_REG && (stm32_port->rx_ch || @@ -1463,7 +1242,7 @@ index ee6c7762d355..5694e78646eb 100644 if (cflag & CSTOPB) bits = bits + 3; /* 1 start bit + 2 stop bits */ else -@@ -791,9 +1103,12 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -817,9 +1173,12 @@ static void stm32_usart_set_termios(struct uart_port *port, stm32_port->cr1_irq = USART_CR1_RTOIE; writel_relaxed(bits, port->membase + ofs->rtor); cr2 |= USART_CR2_RTOEN; @@ -1479,34 +1258,7 @@ index ee6c7762d355..5694e78646eb 100644 } cr1 |= stm32_port->cr1_irq; -@@ -808,12 +1123,6 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; - } - -- /* Handle modem control interrupts */ -- if (UART_ENABLE_MS(port, termios->c_cflag)) -- stm32_enable_ms(port); -- else -- stm32_disable_ms(port); -- - usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); - - /* -@@ -825,11 +1134,11 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, - if (usartdiv < 16) { - oversampling = 8; - cr1 |= USART_CR1_OVER8; -- stm32_set_bits(port, ofs->cr1, USART_CR1_OVER8); -+ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_OVER8); - } else { - oversampling = 16; - cr1 &= ~USART_CR1_OVER8; -- stm32_clr_bits(port, ofs->cr1, USART_CR1_OVER8); -+ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_OVER8); - } - - mantissa = (usartdiv / oversampling) << USART_BRR_DIV_M_SHIFT; -@@ -862,13 +1171,19 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -882,14 +1241,19 @@ static void stm32_usart_set_termios(struct uart_port *port, if ((termios->c_cflag & CREAD) == 0) port->ignore_status_mask |= USART_SR_DUMMY_RX; @@ -1523,133 +1275,97 @@ index ee6c7762d355..5694e78646eb 100644 + } if (rs485conf->flags & SER_RS485_ENABLED) { -- stm32_config_reg_rs485(&cr1, &cr3, -- rs485conf->delay_rts_before_send, -- rs485conf->delay_rts_after_send, baud); +- stm32_usart_config_reg_rs485(&cr1, &cr3, +- rs485conf->delay_rts_before_send, +- rs485conf->delay_rts_after_send, +- baud); + stm32_usart_config_reg_rs485(&cr1, &cr3, baud, rs485conf); if (rs485conf->flags & SER_RS485_RTS_ON_SEND) { cr3 &= ~USART_CR3_DEP; rs485conf->flags &= ~SER_RS485_RTS_AFTER_SEND; -@@ -882,43 +1197,55 @@ static void stm32_set_termios(struct uart_port *port, struct ktermios *termios, +@@ -903,8 +1267,8 @@ static void stm32_usart_set_termios(struct uart_port *port, cr1 &= ~(USART_CR1_DEDT_MASK | USART_CR1_DEAT_MASK); } +- /* Configure wake up from low power on start bit detection */ +- if (stm32_port->wakeirq > 0) { + /* Enable wake up from low power on start bit detection */ + if (stm32_port->wakeup_src) { -+ cr3 &= ~USART_CR3_WUS_MASK; -+ cr3 |= USART_CR3_WUS_START_BIT; -+ } -+ - writel_relaxed(cr3, port->membase + ofs->cr3); - writel_relaxed(cr2, port->membase + ofs->cr2); - writel_relaxed(cr1, port->membase + ofs->cr1); - -- stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -+ stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - spin_unlock_irqrestore(&port->lock, flags); -+ -+ /* Handle modem control interrupts */ -+ if (UART_ENABLE_MS(port, termios->c_cflag)) -+ stm32_usart_enable_ms(port); -+ else -+ stm32_usart_disable_ms(port); - } - --static const char *stm32_type(struct uart_port *port) -+static const char *stm32_usart_type(struct uart_port *port) - { - return (port->type == PORT_STM32) ? DRIVER_NAME : NULL; - } - --static void stm32_release_port(struct uart_port *port) -+static void stm32_usart_release_port(struct uart_port *port) - { - } - --static int stm32_request_port(struct uart_port *port) -+static int stm32_usart_request_port(struct uart_port *port) - { - return 0; - } - --static void stm32_config_port(struct uart_port *port, int flags) -+static void stm32_usart_config_port(struct uart_port *port, int flags) - { - if (flags & UART_CONFIG_TYPE) - port->type = PORT_STM32; - } - - static int --stm32_verify_port(struct uart_port *port, struct serial_struct *ser) -+stm32_usart_verify_port(struct uart_port *port, struct serial_struct *ser) - { - /* No user changeable parameters */ - return -EINVAL; - } - --static void stm32_pm(struct uart_port *port, unsigned int state, -- unsigned int oldstate) -+static void stm32_usart_pm(struct uart_port *port, unsigned int state, -+ unsigned int oldstate) + cr3 &= ~USART_CR3_WUS_MASK; + cr3 |= USART_CR3_WUS_START_BIT; + } +@@ -955,8 +1319,8 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state, { struct stm32_port *stm32port = container_of(port, struct stm32_port, port); -@@ -932,7 +1259,7 @@ static void stm32_pm(struct uart_port *port, unsigned int state, - break; - case UART_PM_STATE_OFF: - spin_lock_irqsave(&port->lock, flags); -- stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -+ stm32_usart_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); - spin_unlock_irqrestore(&port->lock, flags); - pm_runtime_put_sync(port->dev); - break; -@@ -940,59 +1267,101 @@ static void stm32_pm(struct uart_port *port, unsigned int state, +- const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; +- const struct stm32_usart_config *cfg = &stm32port->info->cfg; ++ struct stm32_usart_offsets *ofs = &stm32port->info->ofs; ++ struct stm32_usart_config *cfg = &stm32port->info->cfg; + unsigned long flags = 0; + + switch (state) { +@@ -972,6 +1336,40 @@ static void stm32_usart_pm(struct uart_port *port, unsigned int state, + } } ++#if defined(CONFIG_CONSOLE_POLL) ++ ++ /* Callbacks for characters polling in debug context (i.e. KGDB). */ ++static int stm32_usart_poll_init(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ ++ return clk_prepare_enable(stm32_port->clk); ++} ++ ++static int stm32_usart_poll_get_char(struct uart_port *port) ++{ ++ struct stm32_port *stm32_port = to_stm32_port(port); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ unsigned int ret; ++ ++ if (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_RXNE)) ++ return NO_POLL_CHAR; ++ ++ ret = readl_relaxed(port->membase + ofs->rdr); ++ /* Apply RDR data mask */ ++ ret &= stm32_port->rdr_mask; ++ ++ return ret; ++} ++ ++static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, int ch); ++ ++static void stm32_usart_poll_put_char(struct uart_port *port, unsigned char ch) ++{ ++ stm32_usart_console_putchar(port, (int)ch); ++} ++#endif ++ static const struct uart_ops stm32_uart_ops = { -- .tx_empty = stm32_tx_empty, -- .set_mctrl = stm32_set_mctrl, -- .get_mctrl = stm32_get_mctrl, -- .stop_tx = stm32_stop_tx, -- .start_tx = stm32_start_tx, -- .throttle = stm32_throttle, -- .unthrottle = stm32_unthrottle, -- .stop_rx = stm32_stop_rx, -- .enable_ms = stm32_enable_ms, -- .break_ctl = stm32_break_ctl, -- .startup = stm32_startup, -- .shutdown = stm32_shutdown, -- .set_termios = stm32_set_termios, -- .pm = stm32_pm, -- .type = stm32_type, -- .release_port = stm32_release_port, -- .request_port = stm32_request_port, -- .config_port = stm32_config_port, -- .verify_port = stm32_verify_port, -+ .tx_empty = stm32_usart_tx_empty, -+ .set_mctrl = stm32_usart_set_mctrl, -+ .get_mctrl = stm32_usart_get_mctrl, -+ .stop_tx = stm32_usart_stop_tx, -+ .start_tx = stm32_usart_start_tx, -+ .throttle = stm32_usart_throttle, -+ .unthrottle = stm32_usart_unthrottle, -+ .stop_rx = stm32_usart_stop_rx, -+ .enable_ms = stm32_usart_enable_ms, -+ .break_ctl = stm32_usart_break_ctl, -+ .startup = stm32_usart_startup, -+ .shutdown = stm32_usart_shutdown, + .tx_empty = stm32_usart_tx_empty, + .set_mctrl = stm32_usart_set_mctrl, +@@ -985,6 +1383,7 @@ static const struct uart_ops stm32_uart_ops = { + .break_ctl = stm32_usart_break_ctl, + .startup = stm32_usart_startup, + .shutdown = stm32_usart_shutdown, + .flush_buffer = stm32_usart_flush_buffer, -+ .set_termios = stm32_usart_set_termios, -+ .pm = stm32_usart_pm, -+ .type = stm32_usart_type, -+ .release_port = stm32_usart_release_port, -+ .request_port = stm32_usart_request_port, -+ .config_port = stm32_usart_config_port, -+ .verify_port = stm32_usart_verify_port, + .set_termios = stm32_usart_set_termios, + .pm = stm32_usart_pm, + .type = stm32_usart_type, +@@ -992,8 +1391,52 @@ static const struct uart_ops stm32_uart_ops = { + .request_port = stm32_usart_request_port, + .config_port = stm32_usart_config_port, + .verify_port = stm32_usart_verify_port, ++#if defined(CONFIG_CONSOLE_POLL) ++ .poll_init = stm32_usart_poll_init, ++ .poll_get_char = stm32_usart_poll_get_char, ++ .poll_put_char = stm32_usart_poll_put_char, ++#endif /* CONFIG_CONSOLE_POLL */ ++ }; --static int stm32_init_port(struct stm32_port *stm32port, -- struct platform_device *pdev) +/* + * STM32H7 RX & TX FIFO threshold configuration (CR3 RXFTCFG / TXFTCFG) + * Note: 1 isn't a valid value in RXFTCFG / TXFTCFG. In this case, @@ -1688,34 +1404,10 @@ index ee6c7762d355..5694e78646eb 100644 + clk_disable_unprepare(stm32port->clk); +} + -+static int stm32_usart_init_port(struct stm32_port *stm32port, -+ struct platform_device *pdev) + static int stm32_usart_init_port(struct stm32_port *stm32port, + struct platform_device *pdev) { - struct uart_port *port = &stm32port->port; - struct resource *res; - int ret; - -+ ret = platform_get_irq(pdev, 0); -+ if (ret <= 0) -+ return ret ? : -ENODEV; -+ - port->iotype = UPIO_MEM; - port->flags = UPF_BOOT_AUTOCONF; - port->ops = &stm32_uart_ops; - port->dev = &pdev->dev; - port->fifosize = stm32port->info->cfg.fifosize; - port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_STM32_CONSOLE); -- -- ret = platform_get_irq(pdev, 0); -- if (ret <= 0) -- return ret ? : -ENODEV; - port->irq = ret; -+ port->rs485_config = stm32_usart_config_rs485; - -- port->rs485_config = stm32_config_rs485; -- -- ret = stm32_init_rs485(port, pdev); -+ ret = stm32_usart_init_rs485(port, pdev); +@@ -1018,13 +1461,17 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, if (ret) return ret; @@ -1738,7 +1430,7 @@ index ee6c7762d355..5694e78646eb 100644 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); port->membase = devm_ioremap_resource(&pdev->dev, res); -@@ -1023,7 +1392,10 @@ static int stm32_init_port(struct stm32_port *stm32port, +@@ -1055,7 +1502,10 @@ static int stm32_usart_init_port(struct stm32_port *stm32port, goto err_clk; } @@ -1750,16 +1442,7 @@ index ee6c7762d355..5694e78646eb 100644 if (stm32port->hw_flow_control) { if (mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_CTS) || mctrl_gpio_to_gpiod(stm32port->gpios, UART_GPIO_RTS)) { -@@ -1041,7 +1413,7 @@ static int stm32_init_port(struct stm32_port *stm32port, - return ret; - } - --static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) -+static struct stm32_port *stm32_usart_of_get_port(struct platform_device *pdev) - { - struct device_node *np = pdev->dev.of_node; - int id; -@@ -1065,6 +1437,8 @@ static struct stm32_port *stm32_of_get_stm32_port(struct platform_device *pdev) +@@ -1097,6 +1547,8 @@ static struct stm32_port *stm32_usart_of_get_port(struct platform_device *pdev) stm32_ports[id].cr1_irq = USART_CR1_RXNEIE; stm32_ports[id].cr3_irq = 0; stm32_ports[id].last_res = RX_BUF_L; @@ -1768,12 +1451,10 @@ index ee6c7762d355..5694e78646eb 100644 return &stm32_ports[id]; } -@@ -1079,30 +1453,28 @@ static const struct of_device_id stm32_match[] = { +@@ -1111,36 +1563,28 @@ static const struct of_device_id stm32_match[] = { MODULE_DEVICE_TABLE(of, stm32_match); #endif --static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, -- struct platform_device *pdev) +static void stm32_usart_of_dma_rx_remove(struct stm32_port *stm32port, + struct platform_device *pdev) +{ @@ -1782,17 +1463,24 @@ index ee6c7762d355..5694e78646eb 100644 + stm32port->rx_dma_buf); +} + -+static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, -+ struct platform_device *pdev) + static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, + struct platform_device *pdev) { - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct uart_port *port = &stm32port->port; struct device *dev = &pdev->dev; struct dma_slave_config config; - struct dma_async_tx_descriptor *desc = NULL; -- dma_cookie_t cookie; int ret; +- /* +- * Using DMA and threaded handler for the console could lead to +- * deadlocks. +- */ +- if (uart_console(port)) +- return -ENODEV; +- - /* Request DMA RX channel */ - stm32port->rx_ch = dma_request_slave_channel(dev, "rx"); - if (!stm32port->rx_ch) { @@ -1800,20 +1488,18 @@ index ee6c7762d355..5694e78646eb 100644 - return -ENODEV; - } stm32port->rx_buf = dma_alloc_coherent(&pdev->dev, RX_BUF_L, -- &stm32port->rx_dma_buf, -- GFP_KERNEL); + &stm32port->rx_dma_buf, + GFP_KERNEL); - if (!stm32port->rx_buf) { - ret = -ENOMEM; - goto alloc_err; - } -+ &stm32port->rx_dma_buf, -+ GFP_KERNEL); + if (!stm32port->rx_buf) + return -ENOMEM; /* Configure DMA channel */ memset(&config, 0, sizeof(config)); -@@ -1112,47 +1484,23 @@ static int stm32_of_dma_rx_probe(struct stm32_port *stm32port, +@@ -1150,73 +1594,35 @@ static int stm32_usart_of_dma_rx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->rx_ch, &config); if (ret < 0) { dev_err(dev, "rx dma channel config failed\n"); @@ -1830,17 +1516,21 @@ index ee6c7762d355..5694e78646eb 100644 - dev_err(dev, "rx dma prep cyclic failed\n"); - ret = -ENODEV; - goto config_err; -+ stm32_usart_of_dma_rx_remove(stm32port, pdev); -+ return ret; - } - +- } +- - /* No callback as dma buffer is drained on usart interrupt */ - desc->callback = NULL; - desc->callback_param = NULL; - - /* Push current DMA transaction in the pending queue */ -- cookie = dmaengine_submit(desc); -- +- ret = dma_submit_error(dmaengine_submit(desc)); +- if (ret) { +- dmaengine_terminate_sync(stm32port->rx_ch); +- goto config_err; ++ stm32_usart_of_dma_rx_remove(stm32port, pdev); ++ return ret; + } + - /* Issue pending DMA requests */ - dma_async_issue_pending(stm32port->rx_ch); - @@ -1865,14 +1555,13 @@ index ee6c7762d355..5694e78646eb 100644 + stm32port->tx_dma_buf); } --static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, -- struct platform_device *pdev) -+static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, -+ struct platform_device *pdev) + static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, + struct platform_device *pdev) { - struct stm32_usart_offsets *ofs = &stm32port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32port->info->ofs; struct uart_port *port = &stm32port->port; -@@ -1160,21 +1508,11 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, + struct device *dev = &pdev->dev; struct dma_slave_config config; int ret; @@ -1885,20 +1574,18 @@ index ee6c7762d355..5694e78646eb 100644 - return -ENODEV; - } stm32port->tx_buf = dma_alloc_coherent(&pdev->dev, TX_BUF_L, -- &stm32port->tx_dma_buf, -- GFP_KERNEL); + &stm32port->tx_dma_buf, + GFP_KERNEL); - if (!stm32port->tx_buf) { - ret = -ENOMEM; - goto alloc_err; - } -+ &stm32port->tx_dma_buf, -+ GFP_KERNEL); + if (!stm32port->tx_buf) + return -ENOMEM; /* Configure DMA channel */ memset(&config, 0, sizeof(config)); -@@ -1184,31 +1522,20 @@ static int stm32_of_dma_tx_probe(struct stm32_port *stm32port, +@@ -1226,26 +1632,16 @@ static int stm32_usart_of_dma_tx_probe(struct stm32_port *stm32port, ret = dmaengine_slave_config(stm32port->tx_ch, &config); if (ret < 0) { dev_err(dev, "tx dma channel config failed\n"); @@ -1922,47 +1609,44 @@ index ee6c7762d355..5694e78646eb 100644 - return ret; } --static int stm32_serial_probe(struct platform_device *pdev) -+static int stm32_usart_serial_probe(struct platform_device *pdev) + static int stm32_usart_serial_probe(struct platform_device *pdev) { - const struct of_device_id *match; ++ const struct of_device_id *match; struct stm32_port *stm32port; int ret; -- stm32port = stm32_of_get_stm32_port(pdev); -+ stm32port = stm32_usart_of_get_port(pdev); +@@ -1253,34 +1649,57 @@ static int stm32_usart_serial_probe(struct platform_device *pdev) if (!stm32port) return -ENODEV; -@@ -1218,105 +1545,145 @@ static int stm32_serial_probe(struct platform_device *pdev) - else +- stm32port->info = of_device_get_match_data(&pdev->dev); +- if (!stm32port->info) ++ match = of_match_device(stm32_match, &pdev->dev); ++ if (match && match->data) ++ stm32port->info = (struct stm32_usart_info *)match->data; ++ else return -EINVAL; -- ret = stm32_init_port(stm32port, pdev); -+ ret = stm32_usart_init_port(stm32port, pdev); + ret = stm32_usart_init_port(stm32port, pdev); if (ret) return ret; - if (stm32port->wakeirq > 0) { - ret = device_init_wakeup(&pdev->dev, true); -- if (ret) -- goto err_uninit; -- -- ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, -- stm32port->wakeirq); + if (stm32port->wakeup_src) { + device_set_wakeup_capable(&pdev->dev, true); + ret = dev_pm_set_wake_irq(&pdev->dev, stm32port->port.irq); if (ret) -- goto err_nowup; +- goto err_uninit; - -- device_set_wakeup_enable(&pdev->dev, false); +- ret = dev_pm_set_dedicated_wake_irq(&pdev->dev, +- stm32port->wakeirq); +- if (ret) +- goto err_nowup; + goto err_deinit_port; - } ++ } -- ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); -- if (ret) -- goto err_wirq; +- device_set_wakeup_enable(&pdev->dev, false); + stm32port->rx_ch = dma_request_chan_linked(&pdev->dev, "rx"); + if (PTR_ERR(stm32port->rx_ch) == -EPROBE_DEFER) { + ret = -EPROBE_DEFER; @@ -1985,9 +1669,9 @@ index ee6c7762d355..5694e78646eb 100644 + /* Fall back in interrupt mode */ + dma_release_chan_linked(&pdev->dev, stm32port->rx_ch); + stm32port->rx_ch = NULL; -+ } + } -- ret = stm32_of_dma_rx_probe(stm32port, pdev); +- ret = stm32_usart_of_dma_rx_probe(stm32port, pdev); - if (ret) - dev_info(&pdev->dev, "interrupt mode used for rx (no dma)\n"); + if (stm32port->tx_ch && stm32_usart_of_dma_tx_probe(stm32port, pdev)) { @@ -1996,7 +1680,7 @@ index ee6c7762d355..5694e78646eb 100644 + stm32port->tx_ch = NULL; + } -- ret = stm32_of_dma_tx_probe(stm32port, pdev); +- ret = stm32_usart_of_dma_tx_probe(stm32port, pdev); - if (ret) - dev_info(&pdev->dev, "interrupt mode used for tx (no dma)\n"); + if (!stm32port->rx_ch) @@ -2006,33 +1690,34 @@ index ee6c7762d355..5694e78646eb 100644 platform_set_drvdata(pdev, &stm32port->port); - pm_runtime_get_noresume(&pdev->dev); - pm_runtime_set_active(&pdev->dev); - pm_runtime_enable(&pdev->dev); -+ -+ ret = uart_add_one_port(&stm32_usart_driver, &stm32port->port); -+ if (ret) -+ goto err_port; -+ - pm_runtime_put_sync(&pdev->dev); +@@ -1301,35 +1720,27 @@ static int stm32_usart_serial_probe(struct platform_device *pdev) + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); - return 0; - --err_wirq: -- if (stm32port->wakeirq > 0) -+err_port: -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); -+ -+ if (stm32port->tx_ch) { +- if (stm32port->rx_ch) { +- dmaengine_terminate_async(stm32port->rx_ch); +- dma_release_channel(stm32port->rx_ch); +- } +- +- if (stm32port->rx_dma_buf) +- dma_free_coherent(&pdev->dev, +- RX_BUF_L, stm32port->rx_buf, +- stm32port->rx_dma_buf); +- + if (stm32port->tx_ch) { +- dmaengine_terminate_async(stm32port->tx_ch); + stm32_usart_of_dma_tx_remove(stm32port, pdev); -+ dma_release_channel(stm32port->tx_ch); -+ } -+ + dma_release_channel(stm32port->tx_ch); + } + +- if (stm32port->tx_dma_buf) +- dma_free_coherent(&pdev->dev, +- TX_BUF_L, stm32port->tx_buf, +- stm32port->tx_dma_buf); + if (stm32port->rx_ch) + stm32_usart_of_dma_rx_remove(stm32port, pdev); -+ + +- if (stm32port->wakeirq > 0) +err_dma_rx: + if (stm32port->rx_ch) + dma_release_chan_linked(&pdev->dev, stm32port->rx_ch); @@ -2054,61 +1739,60 @@ index ee6c7762d355..5694e78646eb 100644 return ret; } - --static int stm32_serial_remove(struct platform_device *pdev) -+static int stm32_usart_serial_remove(struct platform_device *pdev) +@@ -1338,8 +1749,9 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) { struct uart_port *port = platform_get_drvdata(pdev); struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; int err; + u32 cr3; pm_runtime_get_sync(&pdev->dev); -+ err = uart_remove_one_port(&stm32_usart_driver, port); -+ if (err) -+ return(err); + err = uart_remove_one_port(&stm32_usart_driver, port); +@@ -1350,59 +1762,61 @@ static int stm32_usart_serial_remove(struct platform_device *pdev) + pm_runtime_set_suspended(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAR); +- stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); - -- if (stm32_port->rx_ch) +- if (stm32_port->rx_ch) { +- dmaengine_terminate_async(stm32_port->rx_ch); - dma_release_channel(stm32_port->rx_ch); +- } - - if (stm32_port->rx_dma_buf) - dma_free_coherent(&pdev->dev, - RX_BUF_L, stm32_port->rx_buf, - stm32_port->rx_dma_buf); -+ pm_runtime_disable(&pdev->dev); -+ pm_runtime_set_suspended(&pdev->dev); -+ pm_runtime_put_noidle(&pdev->dev); - -- stm32_clr_bits(port, ofs->cr3, USART_CR3_DMAT); +- +- stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_PEIE); -+ cr3 = readl_relaxed(port->membase + ofs->cr3); -+ cr3 &= ~USART_CR3_EIE; -+ cr3 &= ~USART_CR3_DMAR; -+ cr3 &= ~USART_CR3_DDRE; -+ writel_relaxed(cr3, port->membase + ofs->cr3); -- if (stm32_port->tx_ch) -+ if (stm32_port->tx_ch) { + if (stm32_port->tx_ch) { +- dmaengine_terminate_async(stm32_port->tx_ch); + stm32_usart_tx_dma_terminate(stm32_port); + stm32_usart_of_dma_tx_remove(stm32_port, pdev); dma_release_channel(stm32_port->tx_ch); -+ } -+ -+ if (stm32_port->rx_ch) { -+ stm32_usart_of_dma_rx_remove(stm32_port, pdev); -+ dma_release_chan_linked(&pdev->dev, stm32_port->rx_ch); -+ } + } - if (stm32_port->tx_dma_buf) - dma_free_coherent(&pdev->dev, - TX_BUF_L, stm32_port->tx_buf, - stm32_port->tx_dma_buf); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); ++ if (stm32_port->rx_ch) { ++ stm32_usart_of_dma_rx_remove(stm32_port, pdev); ++ dma_release_chan_linked(&pdev->dev, stm32_port->rx_ch); ++ } - if (stm32_port->wakeirq > 0) { ++ cr3 = readl_relaxed(port->membase + ofs->cr3); ++ cr3 &= ~USART_CR3_EIE; ++ cr3 &= ~USART_CR3_DMAR; ++ cr3 &= ~USART_CR3_DMAT; ++ cr3 &= ~USART_CR3_DDRE; ++ writel_relaxed(cr3, port->membase + ofs->cr3); ++ + if (stm32_port->wakeup_src) { dev_pm_clear_wake_irq(&pdev->dev); device_init_wakeup(&pdev->dev, false); @@ -2117,83 +1801,115 @@ index ee6c7762d355..5694e78646eb 100644 - clk_disable_unprepare(stm32_port->clk); + stm32_usart_deinit_port(stm32_port); -- err = uart_remove_one_port(&stm32_usart_driver, port); -- -- pm_runtime_disable(&pdev->dev); -- pm_runtime_put_noidle(&pdev->dev); -- -- return err; -+ return 0; + return 0; } -- - #ifdef CONFIG_SERIAL_STM32_CONSOLE --static void stm32_console_putchar(struct uart_port *port, int ch) -+static void stm32_usart_console_putchar(struct uart_port *port, int ch) +-#ifdef CONFIG_SERIAL_STM32_CONSOLE +-static void stm32_usart_console_putchar(struct uart_port *port, int ch) ++static void __maybe_unused stm32_usart_console_putchar(struct uart_port *port, int ch) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -@@ -1327,7 +1694,8 @@ static void stm32_console_putchar(struct uart_port *port, int ch) +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- +- while (!(readl_relaxed(port->membase + ofs->isr) & USART_SR_TXE)) +- cpu_relax(); ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ u32 isr; ++ int ret; + ++ ret = readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, isr, ++ (isr & USART_SR_TXE), 100, ++ STM32_USART_TIMEOUT_USEC); ++ if (ret != 0) { ++ dev_err(port->dev, "Error while sending data in UART TX : %d\n", ret); ++ return; ++ } writel_relaxed(ch, port->membase + ofs->tdr); } --static void stm32_console_write(struct console *co, const char *s, unsigned cnt) -+static void stm32_usart_console_write(struct console *co, const char *s, -+ unsigned int cnt) ++#ifdef CONFIG_SERIAL_STM32_CONSOLE + static void stm32_usart_console_write(struct console *co, const char *s, + unsigned int cnt) { struct uart_port *port = &stm32_ports[co->index].port; struct stm32_port *stm32_port = to_stm32_port(port); -@@ -1351,7 +1719,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) - new_cr1 |= USART_CR1_TE | BIT(cfg->uart_enable_bit); - writel_relaxed(new_cr1, port->membase + ofs->cr1); +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; +- const struct stm32_usart_config *cfg = &stm32_port->info->cfg; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_config *cfg = &stm32_port->info->cfg; + unsigned long flags; + u32 old_cr1, new_cr1; + int locked = 1; +@@ -1475,6 +1889,57 @@ static struct console stm32_console = { + #define STM32_SERIAL_CONSOLE NULL + #endif /* CONFIG_SERIAL_STM32_CONSOLE */ -- uart_console_write(port, s, cnt, stm32_console_putchar); -+ uart_console_write(port, s, cnt, stm32_usart_console_putchar); - - /* Restore interrupt state */ - writel_relaxed(old_cr1, port->membase + ofs->cr1); -@@ -1361,7 +1729,7 @@ static void stm32_console_write(struct console *co, const char *s, unsigned cnt) - local_irq_restore(flags); - } - --static int stm32_console_setup(struct console *co, char *options) -+static int stm32_usart_console_setup(struct console *co, char *options) - { - struct stm32_port *stm32port; - int baud = 9600; -@@ -1380,7 +1748,7 @@ static int stm32_console_setup(struct console *co, char *options) - * this to be called during the uart port registration when the - * driver gets probed and the port should be mapped at that point. - */ -- if (stm32port->port.mapbase == 0 || stm32port->port.membase == NULL) -+ if (stm32port->port.mapbase == 0 || !stm32port->port.membase) - return -ENXIO; - - if (options) -@@ -1392,8 +1760,8 @@ static int stm32_console_setup(struct console *co, char *options) - static struct console stm32_console = { - .name = STM32_SERIAL_NAME, - .device = uart_console_device, -- .write = stm32_console_write, -- .setup = stm32_console_setup, -+ .write = stm32_usart_console_write, -+ .setup = stm32_usart_console_setup, - .flags = CON_PRINTBUFFER, - .index = -1, - .data = &stm32_usart_driver, -@@ -1414,41 +1782,72 @@ static struct uart_driver stm32_usart_driver = { ++#ifdef CONFIG_SERIAL_EARLYCON ++static void early_stm32_usart_console_putchar(struct uart_port *port, int ch) ++{ ++ struct stm32_usart_info *info = port->private_data; ++ ++ while (!(readl_relaxed(port->membase + info->ofs.isr) & USART_SR_TXE)) ++ cpu_relax(); ++ ++ writel_relaxed(ch, port->membase + info->ofs.tdr); ++} ++ ++static void early_stm32_serial_write(struct console *console, const char *s, unsigned int count) ++{ ++ struct earlycon_device *device = console->data; ++ struct uart_port *port = &device->port; ++ ++ uart_console_write(port, s, count, early_stm32_usart_console_putchar); ++} ++ ++static int __init early_stm32_h7_serial_setup(struct earlycon_device *device, const char *options) ++{ ++ if (!(device->port.membase || device->port.iobase)) ++ return -ENODEV; ++ device->port.private_data = &stm32h7_info; ++ device->con->write = early_stm32_serial_write; ++ return 0; ++} ++ ++static int __init early_stm32_f7_serial_setup(struct earlycon_device *device, const char *options) ++{ ++ if (!(device->port.membase || device->port.iobase)) ++ return -ENODEV; ++ device->port.private_data = &stm32f7_info; ++ device->con->write = early_stm32_serial_write; ++ return 0; ++} ++ ++static int __init early_stm32_f4_serial_setup(struct earlycon_device *device, const char *options) ++{ ++ if (!(device->port.membase || device->port.iobase)) ++ return -ENODEV; ++ device->port.private_data = &stm32f4_info; ++ device->con->write = early_stm32_serial_write; ++ return 0; ++} ++ ++OF_EARLYCON_DECLARE(stm32h7serial, "st,stm32h7-uart", early_stm32_h7_serial_setup); ++OF_EARLYCON_DECLARE(stm32f7serial, "st,stm32f7-uart", early_stm32_f7_serial_setup); ++OF_EARLYCON_DECLARE(stm32f4serial, "st,stm32-uart", early_stm32_f4_serial_setup); ++#endif /* CONFIG_SERIAL_EARLYCON */ ++ + static struct uart_driver stm32_usart_driver = { + .driver_name = DRIVER_NAME, + .dev_name = STM32_SERIAL_NAME, +@@ -1484,14 +1949,17 @@ static struct uart_driver stm32_usart_driver = { .cons = STM32_SERIAL_CONSOLE, }; --static void __maybe_unused stm32_serial_enable_wakeup(struct uart_port *port, -- bool enable) +-static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, +- bool enable) +static int __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, + bool enable) { struct stm32_port *stm32_port = to_stm32_port(port); - struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; -- struct stm32_usart_config *cfg = &stm32_port->info->cfg; -- u32 val; +- const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; ++ struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; + struct tty_port *tport = &port->state->port; + unsigned long flags; + int ret; @@ -2203,21 +1919,12 @@ index ee6c7762d355..5694e78646eb 100644 + if (!stm32_port->wakeup_src || !tty_port_initialized(tport)) + return 0; -+ /* -+ * Enable low-power wake-up and wake-up irq if argument is set to -+ * "enable", disable low-power wake-up and wake-up irq otherwise -+ */ + /* + * Enable low-power wake-up and wake-up irq if argument is set to +@@ -1500,22 +1968,53 @@ static void __maybe_unused stm32_usart_serial_en_wakeup(struct uart_port *port, if (enable) { -- stm32_clr_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -- stm32_set_bits(port, ofs->cr1, USART_CR1_UESM); -- val = readl_relaxed(port->membase + ofs->cr3); -- val &= ~USART_CR3_WUS_MASK; -- /* Enable Wake up interrupt from low power on start bit */ -- val |= USART_CR3_WUS_START_BIT | USART_CR3_WUFIE; -- writel_relaxed(val, port->membase + ofs->cr3); -- stm32_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); -+ stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); -+ stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + stm32_usart_set_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_set_bits(port, ofs->cr3, USART_CR3_WUFIE); + mctrl_gpio_enable_irq_wake(stm32_port->gpios); + + /* @@ -2228,10 +1935,10 @@ index ee6c7762d355..5694e78646eb 100644 + if (stm32_port->rx_ch) { + /* Avoid race with RX IRQ when DMAR is cleared */ + spin_lock_irqsave(&port->lock, flags); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAR); + /* Poll data from DMA RX buffer if any */ -+ stm32_usart_receive_chars(port, true); -+ dmaengine_terminate_async(stm32_port->rx_ch); ++ if (!stm32_usart_rx_dma_pause(stm32_port)) ++ stm32_usart_receive_chars(port, true); ++ stm32_usart_rx_dma_terminate(stm32_port); + spin_unlock_irqrestore(&port->lock, flags); + } + @@ -2240,22 +1947,20 @@ index ee6c7762d355..5694e78646eb 100644 + stm32_usart_receive_chars(port, false); + spin_unlock_irqrestore(&port->lock, flags); } else { -- stm32_clr_bits(port, ofs->cr1, USART_CR1_UESM); + if (stm32_port->rx_ch) { -+ ret = stm32_usart_start_rx_dma_cyclic(port); ++ ret = stm32_usart_rx_dma_start_or_resume(port); + if (ret) + return ret; + } + mctrl_gpio_disable_irq_wake(stm32_port->gpios); -+ stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); -+ stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); + stm32_usart_clr_bits(port, ofs->cr1, USART_CR1_UESM); + stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_WUFIE); } + + return 0; } --static int __maybe_unused stm32_serial_suspend(struct device *dev) -+static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) + static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; @@ -2263,9 +1968,9 @@ index ee6c7762d355..5694e78646eb 100644 uart_suspend_port(&stm32_usart_driver, port); - if (device_may_wakeup(dev)) -- stm32_serial_enable_wakeup(port, true); +- stm32_usart_serial_en_wakeup(port, true); - else -- stm32_serial_enable_wakeup(port, false); +- stm32_usart_serial_en_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, true); + if (ret) @@ -2274,7 +1979,7 @@ index ee6c7762d355..5694e78646eb 100644 /* * When "no_console_suspend" is enabled, keep the pinctrl default state -@@ -1457,7 +1856,7 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev) +@@ -1524,7 +2023,7 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) * capabilities. */ if (console_suspend_enabled || !uart_console(port)) { @@ -2283,12 +1988,8 @@ index ee6c7762d355..5694e78646eb 100644 pinctrl_pm_select_idle_state(dev); else pinctrl_pm_select_sleep_state(dev); -@@ -1466,19 +1865,23 @@ static int __maybe_unused stm32_serial_suspend(struct device *dev) - return 0; - } - --static int __maybe_unused stm32_serial_resume(struct device *dev) -+static int __maybe_unused stm32_usart_serial_resume(struct device *dev) +@@ -1536,11 +2035,15 @@ static int __maybe_unused stm32_usart_serial_suspend(struct device *dev) + static int __maybe_unused stm32_usart_serial_resume(struct device *dev) { struct uart_port *port = dev_get_drvdata(dev); + int ret; @@ -2296,7 +1997,7 @@ index ee6c7762d355..5694e78646eb 100644 pinctrl_pm_select_default_state(dev); - if (device_may_wakeup(dev)) -- stm32_serial_enable_wakeup(port, false); +- stm32_usart_serial_en_wakeup(port, false); + if (device_may_wakeup(dev) || device_wakeup_path(dev)) { + ret = stm32_usart_serial_en_wakeup(port, false); + if (ret) @@ -2305,71 +2006,8 @@ index ee6c7762d355..5694e78646eb 100644 return uart_resume_port(&stm32_usart_driver, port); } - --static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) -+static int __maybe_unused stm32_usart_runtime_suspend(struct device *dev) - { - struct uart_port *port = dev_get_drvdata(dev); - struct stm32_port *stm32port = container_of(port, -@@ -1489,7 +1892,7 @@ static int __maybe_unused stm32_serial_runtime_suspend(struct device *dev) - return 0; - } - --static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) -+static int __maybe_unused stm32_usart_runtime_resume(struct device *dev) - { - struct uart_port *port = dev_get_drvdata(dev); - struct stm32_port *stm32port = container_of(port, -@@ -1499,14 +1902,15 @@ static int __maybe_unused stm32_serial_runtime_resume(struct device *dev) - } - - static const struct dev_pm_ops stm32_serial_pm_ops = { -- SET_RUNTIME_PM_OPS(stm32_serial_runtime_suspend, -- stm32_serial_runtime_resume, NULL) -- SET_SYSTEM_SLEEP_PM_OPS(stm32_serial_suspend, stm32_serial_resume) -+ SET_RUNTIME_PM_OPS(stm32_usart_runtime_suspend, -+ stm32_usart_runtime_resume, NULL) -+ SET_SYSTEM_SLEEP_PM_OPS(stm32_usart_serial_suspend, -+ stm32_usart_serial_resume) - }; - - static struct platform_driver stm32_serial_driver = { -- .probe = stm32_serial_probe, -- .remove = stm32_serial_remove, -+ .probe = stm32_usart_serial_probe, -+ .remove = stm32_usart_serial_remove, - .driver = { - .name = DRIVER_NAME, - .pm = &stm32_serial_pm_ops, -@@ -1514,7 +1918,7 @@ static struct platform_driver stm32_serial_driver = { - }, - }; - --static int __init usart_init(void) -+static int __init stm32_usart_init(void) - { - static char banner[] __initdata = "STM32 USART driver initialized"; - int ret; -@@ -1532,14 +1936,14 @@ static int __init usart_init(void) - return ret; - } - --static void __exit usart_exit(void) -+static void __exit stm32_usart_exit(void) - { - platform_driver_unregister(&stm32_serial_driver); - uart_unregister_driver(&stm32_usart_driver); - } - --module_init(usart_init); --module_exit(usart_exit); -+module_init(stm32_usart_init); -+module_exit(stm32_usart_exit); - - MODULE_ALIAS("platform:" DRIVER_NAME); - MODULE_DESCRIPTION("STMicroelectronics STM32 serial port driver"); diff --git a/drivers/tty/serial/stm32-usart.h b/drivers/tty/serial/stm32-usart.h -index d4c916e78d40..f4708007ec0e 100644 +index 94b568aa4..c634b78de 100644 --- a/drivers/tty/serial/stm32-usart.h +++ b/drivers/tty/serial/stm32-usart.h @@ -106,7 +106,7 @@ struct stm32_usart_info stm32h7_info = { @@ -2381,7 +2019,7 @@ index d4c916e78d40..f4708007ec0e 100644 #define USART_SR_ORE BIT(3) #define USART_SR_IDLE BIT(4) #define USART_SR_RXNE BIT(5) -@@ -123,13 +123,11 @@ struct stm32_usart_info stm32h7_info = { +@@ -123,7 +123,8 @@ struct stm32_usart_info stm32h7_info = { #define USART_SR_SBKF BIT(18) /* F7 */ #define USART_SR_WUF BIT(20) /* H7 */ #define USART_SR_TEACK BIT(21) /* F7 */ @@ -2391,13 +2029,7 @@ index d4c916e78d40..f4708007ec0e 100644 /* Dummy bits */ #define USART_SR_DUMMY_RX BIT(16) --/* USART_ICR (F7) */ --#define USART_CR_TC BIT(6) -- - /* USART_DR */ - #define USART_DR_MASK GENMASK(8, 0) - -@@ -216,12 +214,6 @@ struct stm32_usart_info stm32h7_info = { +@@ -213,12 +214,6 @@ struct stm32_usart_info stm32h7_info = { #define USART_CR3_TXFTCFG_MASK GENMASK(31, 29) /* H7 */ #define USART_CR3_TXFTCFG_SHIFT 29 /* H7 */ @@ -2410,7 +2042,7 @@ index d4c916e78d40..f4708007ec0e 100644 /* USART_GTPR */ #define USART_GTPR_PSC_MASK GENMASK(7, 0) #define USART_GTPR_GT_MASK GENMASK(15, 8) -@@ -252,9 +244,9 @@ struct stm32_usart_info stm32h7_info = { +@@ -249,14 +244,16 @@ struct stm32_usart_info stm32h7_info = { #define STM32_SERIAL_NAME "ttySTM" #define STM32_MAX_PORTS 8 @@ -2420,10 +2052,18 @@ index d4c916e78d40..f4708007ec0e 100644 +#define RX_BUF_L 4096 /* dma rx buffer length */ +#define RX_BUF_P (RX_BUF_L / 2) /* dma rx buffer period */ +#define TX_BUF_L RX_BUF_L /* dma tx buffer length */ ++ ++#define STM32_USART_TIMEOUT_USEC USEC_PER_SEC /* 1s timeout in µs */ struct stm32_port { struct uart_port port; -@@ -269,12 +261,16 @@ struct stm32_port { + struct clk *clk; +- const struct stm32_usart_info *info; ++ struct stm32_usart_info *info; + struct dma_chan *rx_ch; /* dma rx channel */ + dma_addr_t rx_dma_buf; /* dma rx buffer bus address */ + unsigned char *rx_buf; /* dma rx buffer cpu address */ +@@ -266,12 +263,17 @@ struct stm32_port { u32 cr1_irq; /* USART_CR1_RXNEIE or RTOIE */ u32 cr3_irq; /* USART_CR3_RXFTIE */ int last_res; @@ -2439,11 +2079,12 @@ index d4c916e78d40..f4708007ec0e 100644 struct mctrl_gpios *gpios; /* modem control gpios */ + struct dma_tx_state rx_dma_state; + bool tx_dma_busy; /* dma tx transaction in progress */ ++ bool rx_dma_busy; /* dma rx transaction in progress */ }; static struct stm32_port stm32_ports[STM32_MAX_PORTS]; diff --git a/include/uapi/linux/serial.h b/include/uapi/linux/serial.h -index 93eb3c496ff1..2d98e65d2a78 100644 +index 93eb3c496..2d98e65d2 100644 --- a/include/uapi/linux/serial.h +++ b/include/uapi/linux/serial.h @@ -128,6 +128,8 @@ struct serial_rs485 { diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0014-ARM-5.10.10-stm32mp1-r1-PERF.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0014-ARM-5.10.61-stm32mp1-r2-PERF.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0014-ARM-5.10.10-stm32mp1-r1-PERF.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0014-ARM-5.10.61-stm32mp1-r2-PERF.patch index dd8284c..e32f452 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0014-ARM-5.10.10-stm32mp1-r1-PERF.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0014-ARM-5.10.61-stm32mp1-r2-PERF.patch @@ -1,20 +1,20 @@ -From f9e34d8836c280d291e1779bf50f895f55a1e8fc Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:16:53 +0100 -Subject: [PATCH 14/22] ARM 5.10.10-stm32mp1-r1 PERF +From 000853359feed98e3d2f08d2fc1cc94e8e51fa2d Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:48 +0200 +Subject: [PATCH 14/23] ARM 5.10.61-stm32mp1-r2 PERF --- Documentation/admin-guide/perf/index.rst | 1 + .../admin-guide/perf/stm32-ddr-pmu.rst | 44 ++ drivers/perf/Kconfig | 7 + drivers/perf/Makefile | 1 + - drivers/perf/stm32_ddr_pmu.c | 428 ++++++++++++++++++ - 5 files changed, 481 insertions(+) + drivers/perf/stm32_ddr_pmu.c | 429 ++++++++++++++++++ + 5 files changed, 482 insertions(+) create mode 100644 Documentation/admin-guide/perf/stm32-ddr-pmu.rst create mode 100644 drivers/perf/stm32_ddr_pmu.c diff --git a/Documentation/admin-guide/perf/index.rst b/Documentation/admin-guide/perf/index.rst -index 5a8f2529a033..9f68f68be161 100644 +index 5a8f2529a..9f68f68be 100644 --- a/Documentation/admin-guide/perf/index.rst +++ b/Documentation/admin-guide/perf/index.rst @@ -11,6 +11,7 @@ Performance monitor support @@ -27,7 +27,7 @@ index 5a8f2529a033..9f68f68be161 100644 xgene-pmu diff --git a/Documentation/admin-guide/perf/stm32-ddr-pmu.rst b/Documentation/admin-guide/perf/stm32-ddr-pmu.rst new file mode 100644 -index 000000000000..db647fc1acad +index 000000000..db647fc1a --- /dev/null +++ b/Documentation/admin-guide/perf/stm32-ddr-pmu.rst @@ -0,0 +1,44 @@ @@ -76,7 +76,7 @@ index 000000000000..db647fc1acad + 20.021068551 seconds time elapsed + diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig -index 130327ff0b0e..a62a26fc516a 100644 +index 130327ff0..a62a26fc5 100644 --- a/drivers/perf/Kconfig +++ b/drivers/perf/Kconfig @@ -106,6 +106,13 @@ config QCOM_L3_PMU @@ -94,7 +94,7 @@ index 130327ff0b0e..a62a26fc516a 100644 tristate "Cavium ThunderX2 SoC PMU UNCORE" depends on ARCH_THUNDER2 && ARM64 && ACPI && NUMA diff --git a/drivers/perf/Makefile b/drivers/perf/Makefile -index 5365fd56f88f..7f2b7c5f9216 100644 +index 5365fd56f..7f2b7c5f9 100644 --- a/drivers/perf/Makefile +++ b/drivers/perf/Makefile @@ -10,6 +10,7 @@ obj-$(CONFIG_FSL_IMX8_DDR_PMU) += fsl_imx8_ddr_perf.o @@ -107,10 +107,10 @@ index 5365fd56f88f..7f2b7c5f9216 100644 obj-$(CONFIG_ARM_SPE_PMU) += arm_spe_pmu.o diff --git a/drivers/perf/stm32_ddr_pmu.c b/drivers/perf/stm32_ddr_pmu.c new file mode 100644 -index 000000000000..ee7a33083e02 +index 000000000..a6a2c5479 --- /dev/null +++ b/drivers/perf/stm32_ddr_pmu.c -@@ -0,0 +1,428 @@ +@@ -0,0 +1,429 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file is the STM32 DDR performance monitor (DDRPERFM) driver @@ -524,6 +524,7 @@ index 000000000000..ee7a33083e02 + { .compatible = "st,stm32-ddr-pmu" }, + { }, +}; ++MODULE_DEVICE_TABLE(of, stm32_ddr_pmu_of_match); + +static struct platform_driver stm32_ddr_pmu_driver = { + .driver = { diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0015-ARM-5.10.10-stm32mp1-r1-PHY-USB.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch similarity index 76% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0015-ARM-5.10.10-stm32mp1-r1-PHY-USB.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch index 4311e17..b34153e 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0015-ARM-5.10.10-stm32mp1-r1-PHY-USB.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch @@ -1,27 +1,25 @@ -From 731c37c7d36e13cac98e1c872657c03613fc5259 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:14:10 +0100 -Subject: [PATCH 15/22] ARM 5.10.10-stm32mp1-r1 PHY-USB +From a936dc53617e4f56a85fc96fb7dd4567261a160d Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:49 +0200 +Subject: [PATCH 15/23] ARM 5.10.61-stm32mp1-r2 PHY-USB -Signed-off-by: Romuald JEANNE --- - drivers/phy/st/phy-stm32-usbphyc.c | 499 +++++++++++++++++++++++++---- + drivers/phy/st/phy-stm32-usbphyc.c | 509 +++++++++++++++++++++++++---- drivers/usb/core/hcd.c | 9 +- drivers/usb/core/phy.c | 22 +- drivers/usb/core/phy.h | 6 +- drivers/usb/dwc2/core.c | 123 ++++--- - drivers/usb/dwc2/core.h | 4 + - drivers/usb/dwc2/drd.c | 21 +- - drivers/usb/dwc2/gadget.c | 5 +- - drivers/usb/dwc2/hcd.c | 6 +- - drivers/usb/dwc2/params.c | 8 + + drivers/usb/dwc2/core.h | 14 + + drivers/usb/dwc2/drd.c | 37 ++- + drivers/usb/dwc2/gadget.c | 6 +- + drivers/usb/dwc2/hcd.c | 7 +- + drivers/usb/dwc2/params.c | 24 ++ drivers/usb/dwc2/platform.c | 47 ++- drivers/usb/host/ehci-platform.c | 16 +- - drivers/usb/typec/stusb160x.c | 11 +- - 13 files changed, 615 insertions(+), 162 deletions(-) + 12 files changed, 662 insertions(+), 158 deletions(-) diff --git a/drivers/phy/st/phy-stm32-usbphyc.c b/drivers/phy/st/phy-stm32-usbphyc.c -index 2b3639cba51a..5f169d5c669e 100644 +index 2b3639cba..f21160659 100644 --- a/drivers/phy/st/phy-stm32-usbphyc.c +++ b/drivers/phy/st/phy-stm32-usbphyc.c @@ -7,8 +7,9 @@ @@ -147,7 +145,7 @@ index 2b3639cba51a..5f169d5c669e 100644 #define PLL_FVCO_MHZ 2880 #define PLL_INFF_MIN_RATE_HZ 19200000 #define PLL_INFF_MAX_RATE_HZ 38400000 -@@ -58,7 +135,7 @@ struct pll_params { +@@ -58,9 +135,10 @@ struct pll_params { struct stm32_usbphyc_phy { struct phy *phy; struct stm32_usbphyc *usbphyc; @@ -155,8 +153,11 @@ index 2b3639cba51a..5f169d5c669e 100644 + struct regulator *vbus; u32 index; bool active; ++ u32 tune; }; -@@ -70,6 +147,10 @@ struct stm32_usbphyc { + + struct stm32_usbphyc { +@@ -70,6 +148,10 @@ struct stm32_usbphyc { struct reset_control *rst; struct stm32_usbphyc_phy **phys; int nphys; @@ -167,7 +168,7 @@ index 2b3639cba51a..5f169d5c669e 100644 int switch_setup; }; -@@ -83,6 +164,41 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) +@@ -83,6 +165,41 @@ static inline void stm32_usbphyc_clr_bits(void __iomem *reg, u32 bits) writel_relaxed(readl_relaxed(reg) & ~bits, reg); } @@ -209,7 +210,7 @@ index 2b3639cba51a..5f169d5c669e 100644 static void stm32_usbphyc_get_pll_params(u32 clk_rate, struct pll_params *pll_params) { -@@ -142,83 +258,106 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) +@@ -142,83 +259,106 @@ static int stm32_usbphyc_pll_init(struct stm32_usbphyc *usbphyc) return 0; } @@ -294,28 +295,28 @@ index 2b3639cba51a..5f169d5c669e 100644 - return 0; -} - +- -static int stm32_usbphyc_pll_disable(struct stm32_usbphyc *usbphyc) -{ - void __iomem *pll_reg = usbphyc->base + STM32_USBPHYC_PLL; -+reg_disable: -+ stm32_usbphyc_regulators_disable(usbphyc); - +- - /* Check if other phy port active */ - if (stm32_usbphyc_has_one_phy_active(usbphyc)) - return 0; -+dec_n_pll_cons: -+ atomic_dec(&usbphyc->n_pll_cons); - stm32_usbphyc_clr_bits(pll_reg, PLLEN); - /* Wait for minimum width of powerdown pulse (ENABLE = Low) */ - udelay(PLL_PWR_DOWN_TIME_US); -- ++reg_disable: ++ stm32_usbphyc_regulators_disable(usbphyc); + - if (readl_relaxed(pll_reg) & PLLEN) { - dev_err(usbphyc->dev, "PLL not reset\n"); - return -EIO; - } -- ++dec_n_pll_cons: ++ atomic_dec(&usbphyc->n_pll_cons); + - return 0; + return ret; } @@ -354,7 +355,7 @@ index 2b3639cba51a..5f169d5c669e 100644 } static int stm32_usbphyc_phy_exit(struct phy *phy) -@@ -235,14 +374,20 @@ static int stm32_usbphyc_phy_power_on(struct phy *phy) +@@ -235,14 +375,20 @@ static int stm32_usbphyc_phy_power_on(struct phy *phy) { struct stm32_usbphyc_phy *usbphyc_phy = phy_get_drvdata(phy); @@ -377,7 +378,7 @@ index 2b3639cba51a..5f169d5c669e 100644 } static const struct phy_ops stm32_usbphyc_phy_ops = { -@@ -253,6 +398,162 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { +@@ -253,6 +399,163 @@ static const struct phy_ops stm32_usbphyc_phy_ops = { .owner = THIS_MODULE, }; @@ -443,9 +444,10 @@ index 2b3639cba51a..5f169d5c669e 100644 +static void stm32_usbphyc_phy_tuning(struct stm32_usbphyc *usbphyc, + struct device_node *np, u32 index) +{ ++ struct stm32_usbphyc_phy *usbphyc_phy = usbphyc->phys[index]; + struct device_node *tune_np; + u32 reg = STM32_USBPHYC_TUNE(index); -+ u32 otpcomp, val, tune = 0; ++ u32 otpcomp, val; + int ret; + + tune_np = of_parse_phandle(np, "st,phy-tuning", 0); @@ -458,25 +460,25 @@ index 2b3639cba51a..5f169d5c669e 100644 + ret = of_property_read_u32(tune_np, "st,current-boost", &val); + if (!ret && val < BOOST_MAX) { + val = (val == BOOST_2_MA) ? 1 : 0; -+ tune |= INCURREN | FIELD_PREP(INCURRINT, val); ++ usbphyc_phy->tune |= INCURREN | FIELD_PREP(INCURRINT, val); + } else if (ret != -EINVAL) { + dev_warn(usbphyc->dev, + "phy%d: invalid st,current-boost value\n", index); + } + + if (!of_property_read_bool(tune_np, "st,no-lsfs-fb-cap")) -+ tune |= LFSCAPEN; ++ usbphyc_phy->tune |= LFSCAPEN; + + if (of_property_read_bool(tune_np, "st,hs-slew-ctrl")) -+ tune |= HSDRVSLEW; ++ usbphyc_phy->tune |= HSDRVSLEW; + + ret = of_property_read_u32(tune_np, "st,hs-dc-level", &val); + if (!ret && val < DC_MAX) { + if (val == DC_MINUS_5_TO_7_MV) { -+ tune |= HSDRVDCCUR; ++ usbphyc_phy->tune |= HSDRVDCCUR; + } else { + val = (val == DC_PLUS_10_TO_14_MV) ? 1 : 0; -+ tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); ++ usbphyc_phy->tune |= HSDRVCURINCR | FIELD_PREP(HSDRVDCLEV, val); + } + } else if (ret != -EINVAL) { + dev_warn(usbphyc->dev, @@ -484,63 +486,63 @@ index 2b3639cba51a..5f169d5c669e 100644 + } + + if (of_property_read_bool(tune_np, "st,fs-rftime-tuning")) -+ tune |= FSDRVRFADJ; ++ usbphyc_phy->tune |= FSDRVRFADJ; + + if (of_property_read_bool(tune_np, "st,hs-rftime-reduction")) -+ tune |= HSDRVRFRED; ++ usbphyc_phy->tune |= HSDRVRFRED; + + ret = of_property_read_u32(tune_np, "st,hs-current-trim", &val); + if (!ret && val < CUR_MAX) -+ tune |= FIELD_PREP(HSDRVCHKITRM, val); ++ usbphyc_phy->tune |= FIELD_PREP(HSDRVCHKITRM, val); + else if (ret != -EINVAL) + dev_warn(usbphyc->dev, + "phy%d: invalid st,hs-current-trim value\n", index); + + ret = of_property_read_u32(tune_np, "st,hs-impedance-trim", &val); + if (!ret && val < IMP_MAX) -+ tune |= FIELD_PREP(HSDRVCHKZTRM, val); ++ usbphyc_phy->tune |= FIELD_PREP(HSDRVCHKZTRM, val); + else if (ret != -EINVAL) + dev_warn(usbphyc->dev, + "phy%d: invalid hs-impedance-trim value\n", index); + + ret = of_property_read_u32(tune_np, "st,squelch-level", &val); + if (!ret && val < SQLCH_MAX) -+ tune |= FIELD_PREP(SQLCHCTL, val); ++ usbphyc_phy->tune |= FIELD_PREP(SQLCHCTL, val); + else if (ret != -EINVAL) + dev_warn(usbphyc->dev, + "phy%d: invalid st,squelch-level value\n", index); + + if (of_property_read_bool(tune_np, "st,hs-rx-gain-eq")) -+ tune |= HDRXGNEQEN; ++ usbphyc_phy->tune |= HDRXGNEQEN; + + ret = of_property_read_u32(tune_np, "st,hs-rx-offset", &val); + if (!ret && val < RX_OFFSET_MAX) -+ tune |= FIELD_PREP(HSRXOFF, val); ++ usbphyc_phy->tune |= FIELD_PREP(HSRXOFF, val); + else if (ret != -EINVAL) + dev_warn(usbphyc->dev, + "phy%d: invalid st,hs-rx-offset value\n", index); + + if (of_property_read_bool(tune_np, "st,no-hs-ftime-ctrl")) -+ tune |= HSFALLPREEM; ++ usbphyc_phy->tune |= HSFALLPREEM; + + if (!of_property_read_bool(tune_np, "st,no-lsfs-sc")) -+ tune |= SHTCCTCTLPROT; ++ usbphyc_phy->tune |= SHTCCTCTLPROT; + + if (of_property_read_bool(tune_np, "st,hs-tx-staggering")) -+ tune |= STAGSEL; ++ usbphyc_phy->tune |= STAGSEL; + + of_node_put(tune_np); + + /* Restore OTP compensation code */ -+ tune |= FIELD_PREP(OTPCOMP, otpcomp); ++ usbphyc_phy->tune |= FIELD_PREP(OTPCOMP, otpcomp); + -+ writel_relaxed(tune, usbphyc->base + reg); ++ writel_relaxed(usbphyc_phy->tune, usbphyc->base + reg); +} + static void stm32_usbphyc_switch_setup(struct stm32_usbphyc *usbphyc, u32 utmi_switch) { -@@ -313,7 +614,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -313,7 +616,7 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) struct device_node *child, *np = dev->of_node; struct resource *res; struct phy_provider *phy_provider; @@ -549,7 +551,7 @@ index 2b3639cba51a..5f169d5c669e 100644 int ret, port = 0; usbphyc = devm_kzalloc(dev, sizeof(*usbphyc), GFP_KERNEL); -@@ -328,11 +629,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -328,11 +631,8 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) return PTR_ERR(usbphyc->base); usbphyc->clk = devm_clk_get(dev, NULL); @@ -563,7 +565,7 @@ index 2b3639cba51a..5f169d5c669e 100644 ret = clk_prepare_enable(usbphyc->clk); if (ret) { -@@ -345,6 +643,23 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -345,6 +645,23 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) reset_control_assert(usbphyc->rst); udelay(2); reset_control_deassert(usbphyc->rst); @@ -587,7 +589,7 @@ index 2b3639cba51a..5f169d5c669e 100644 } usbphyc->switch_setup = -EINVAL; -@@ -356,11 +671,26 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -356,11 +673,26 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto clk_disable; } @@ -615,7 +617,7 @@ index 2b3639cba51a..5f169d5c669e 100644 phy = devm_phy_create(dev, child, &stm32_usbphyc_phy_ops); if (IS_ERR(phy)) { -@@ -378,24 +708,15 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -378,18 +710,6 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto put_child; } @@ -634,16 +636,7 @@ index 2b3639cba51a..5f169d5c669e 100644 ret = of_property_read_u32(child, "reg", &index); if (ret || index > usbphyc->nphys) { dev_err(&phy->dev, "invalid reg property: %d\n", ret); - goto put_child; - } - -+ /* Configure phy tuning */ -+ stm32_usbphyc_phy_tuning(usbphyc, child, index); -+ - usbphyc->phys[port] = usbphyc_phy; - phy_set_bus_width(phy, 8); - phy_set_drvdata(phy, usbphyc_phy); -@@ -405,6 +726,14 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -405,6 +725,17 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) usbphyc->phys[port]->index = index; usbphyc->phys[port]->active = false; @@ -654,11 +647,14 @@ index 2b3639cba51a..5f169d5c669e 100644 + goto put_child; + usbphyc->phys[port]->vbus = NULL; + } ++ ++ /* Configure phy tuning */ ++ stm32_usbphyc_phy_tuning(usbphyc, child, index); + port++; } -@@ -416,6 +745,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -416,6 +747,13 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) goto clk_disable; } @@ -672,7 +668,7 @@ index 2b3639cba51a..5f169d5c669e 100644 version = readl_relaxed(usbphyc->base + STM32_USBPHYC_VERSION); dev_info(dev, "registered rev:%lu.%lu\n", FIELD_GET(MAJREV, version), FIELD_GET(MINREV, version)); -@@ -433,12 +769,34 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) +@@ -433,12 +771,42 @@ static int stm32_usbphyc_probe(struct platform_device *pdev) static int stm32_usbphyc_remove(struct platform_device *pdev) { struct stm32_usbphyc *usbphyc = dev_get_drvdata(&pdev->dev); @@ -694,10 +690,18 @@ index 2b3639cba51a..5f169d5c669e 100644 +static int stm32_usbphyc_resume(struct device *dev) +{ + struct stm32_usbphyc *usbphyc = dev_get_drvdata(dev); ++ struct stm32_usbphyc_phy *usbphyc_phy; ++ int port; + + if (usbphyc->switch_setup >= 0) + stm32_usbphyc_switch_setup(usbphyc, usbphyc->switch_setup); + ++ for (port = 0; port < usbphyc->nphys; port++) { ++ usbphyc_phy = usbphyc->phys[port]; ++ if (usbphyc_phy->tune) ++ writel_relaxed(usbphyc_phy->tune, usbphyc->base + STM32_USBPHYC_TUNE(port)); ++ } ++ + return 0; +} +#endif @@ -707,7 +711,7 @@ index 2b3639cba51a..5f169d5c669e 100644 static const struct of_device_id stm32_usbphyc_of_match[] = { { .compatible = "st,stm32mp1-usbphyc", }, { }, -@@ -451,6 +809,7 @@ static struct platform_driver stm32_usbphyc_driver = { +@@ -451,6 +819,7 @@ static struct platform_driver stm32_usbphyc_driver = { .driver = { .of_match_table = stm32_usbphyc_of_match, .name = "stm32-usbphyc", @@ -716,10 +720,10 @@ index 2b3639cba51a..5f169d5c669e 100644 }; module_platform_driver(stm32_usbphyc_driver); diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c -index 2c6b9578a7d3..7765fb216128 100644 +index 99908d8d2..5290a47b4 100644 --- a/drivers/usb/core/hcd.c +++ b/drivers/usb/core/hcd.c -@@ -2131,7 +2131,8 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) +@@ -2138,7 +2138,8 @@ int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg) if (!PMSG_IS_AUTO(msg)) usb_phy_roothub_suspend(hcd->self.sysdev, @@ -729,7 +733,7 @@ index 2c6b9578a7d3..7765fb216128 100644 /* Did we race with a root-hub wakeup event? */ if (rhdev->do_remote_wakeup) { -@@ -2172,7 +2173,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) +@@ -2179,7 +2180,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) if (!PMSG_IS_AUTO(msg)) { status = usb_phy_roothub_resume(hcd->self.sysdev, @@ -739,7 +743,7 @@ index 2c6b9578a7d3..7765fb216128 100644 if (status) return status; } -@@ -2217,7 +2219,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) +@@ -2224,7 +2226,8 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg) } } else { hcd->state = old_state; @@ -750,7 +754,7 @@ index 2c6b9578a7d3..7765fb216128 100644 "resume", status); if (status != -ESHUTDOWN) diff --git a/drivers/usb/core/phy.c b/drivers/usb/core/phy.c -index fb1588e7c282..746615aa1b2d 100644 +index fb1588e7c..746615aa1 100644 --- a/drivers/usb/core/phy.c +++ b/drivers/usb/core/phy.c @@ -212,34 +212,36 @@ void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub) @@ -801,7 +805,7 @@ index fb1588e7c282..746615aa1b2d 100644 return err; diff --git a/drivers/usb/core/phy.h b/drivers/usb/core/phy.h -index 20a267cd986b..3df4ddbb6046 100644 +index 20a267cd9..3df4ddbb6 100644 --- a/drivers/usb/core/phy.h +++ b/drivers/usb/core/phy.h @@ -23,8 +23,10 @@ int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub); @@ -818,7 +822,7 @@ index 20a267cd986b..3df4ddbb6046 100644 #endif /* __USB_CORE_PHY_H_ */ diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c -index fec17a2d2447..6f9236d4dd38 100644 +index 15911ac75..997b14c05 100644 --- a/drivers/usb/dwc2/core.c +++ b/drivers/usb/dwc2/core.c @@ -83,6 +83,7 @@ int dwc2_backup_global_registers(struct dwc2_hsotg *hsotg) @@ -1006,10 +1010,28 @@ index fec17a2d2447..6f9236d4dd38 100644 /** diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h -index 7161344c6522..80bd2900e20a 100644 +index 641e4251c..21d1fc490 100644 --- a/drivers/usb/dwc2/core.h +++ b/drivers/usb/dwc2/core.h -@@ -685,6 +685,7 @@ struct dwc2_hw_params { +@@ -240,6 +240,9 @@ enum dwc2_ep0_state { + * 1 - SRP Only capable + * 2 - No HNP/SRP capable (always available) + * Defaults to best available option (0, 1, then 2) ++ * @otg_rev: The OTG revision number the device is compliant with, ++ * in binary-coded decimal (i.e. 2.0 is 0200H). ++ * (see struct usb_otg_caps) + * @host_dma: Specifies whether to use slave or DMA mode for accessing + * the data FIFOs. The driver will automatically detect the + * value for this parameter if none is specified. +@@ -452,6 +455,7 @@ struct dwc2_core_params { + #define DWC2_CAP_PARAM_SRP_ONLY_CAPABLE 1 + #define DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE 2 + ++ u16 otg_rev; + u8 phy_type; + #define DWC2_PHY_TYPE_PARAM_FS 0 + #define DWC2_PHY_TYPE_PARAM_UTMI 1 +@@ -687,6 +691,7 @@ struct dwc2_hw_params { * @grxfsiz: Backup of GRXFSIZ register * @gnptxfsiz: Backup of GNPTXFSIZ register * @gi2cctl: Backup of GI2CCTL register @@ -1017,7 +1039,7 @@ index 7161344c6522..80bd2900e20a 100644 * @glpmcfg: Backup of GLPMCFG register * @gdfifocfg: Backup of GDFIFOCFG register * @pcgcctl: Backup of PCGCCTL register -@@ -701,6 +702,7 @@ struct dwc2_gregs_backup { +@@ -703,6 +708,7 @@ struct dwc2_gregs_backup { u32 grxfsiz; u32 gnptxfsiz; u32 gi2cctl; @@ -1025,7 +1047,41 @@ index 7161344c6522..80bd2900e20a 100644 u32 glpmcfg; u32 pcgcctl; u32 pcgcctl1; -@@ -1329,6 +1331,8 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); +@@ -863,6 +869,8 @@ struct dwc2_hregs_backup { + * - USB_DR_MODE_HOST + * - USB_DR_MODE_OTG + * @role_sw: usb_role_switch handle ++ * @role_sw_default_mode: default operation mode of controller while usb role ++ * is USB_ROLE_NONE + * @hcd_enabled: Host mode sub-driver initialization indicator. + * @gadget_enabled: Peripheral mode sub-driver initialization indicator. + * @ll_hw_enabled: Status of low-level hardware resources. +@@ -1046,6 +1054,8 @@ struct dwc2_hregs_backup { + * @new_connection: Used in host mode. True if there are new connected + * device + * @enabled: Indicates the enabling state of controller ++ * @dw_otg_caps: OTG caps from the platform parameters, used to setup the ++ * gadget structure. + * + */ + struct dwc2_hsotg { +@@ -1058,6 +1068,7 @@ struct dwc2_hsotg { + enum usb_otg_state op_state; + enum usb_dr_mode dr_mode; + struct usb_role_switch *role_sw; ++ enum usb_dr_mode role_sw_default_mode; + unsigned int hcd_enabled:1; + unsigned int gadget_enabled:1; + unsigned int ll_hw_enabled:1; +@@ -1211,6 +1222,7 @@ struct dwc2_hsotg { + unsigned int remote_wakeup_allowed:1; + struct dwc2_hsotg_ep *eps_in[MAX_EPS_CHANNELS]; + struct dwc2_hsotg_ep *eps_out[MAX_EPS_CHANNELS]; ++ struct usb_otg_caps dw_otg_caps; + #endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */ + }; + +@@ -1331,6 +1343,8 @@ void dwc2_disable_global_interrupts(struct dwc2_hsotg *hcd); void dwc2_hib_restore_common(struct dwc2_hsotg *hsotg, int rem_wakeup, int is_host); @@ -1035,7 +1091,7 @@ index 7161344c6522..80bd2900e20a 100644 int dwc2_restore_global_registers(struct dwc2_hsotg *hsotg); diff --git a/drivers/usb/dwc2/drd.c b/drivers/usb/dwc2/drd.c -index 2d4176f5788e..27202eb05bde 100644 +index 2d4176f57..9e78d98da 100644 --- a/drivers/usb/dwc2/drd.c +++ b/drivers/usb/dwc2/drd.c @@ -7,6 +7,7 @@ @@ -1046,8 +1102,14 @@ index 2d4176f5788e..27202eb05bde 100644 #include #include #include -@@ -25,9 +26,9 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) +@@ -23,11 +24,15 @@ static void dwc2_ovr_init(struct dwc2_hsotg *hsotg) + gotgctl |= GOTGCTL_BVALOEN | GOTGCTL_AVALOEN | GOTGCTL_VBVALOEN; + gotgctl |= GOTGCTL_DBNCE_FLTR_BYPASS; gotgctl &= ~(GOTGCTL_BVALOVAL | GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL); ++ if (hsotg->role_sw_default_mode == USB_DR_MODE_HOST) ++ gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; ++ else if (hsotg->role_sw_default_mode == USB_DR_MODE_PERIPHERAL) ++ gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; dwc2_writel(hsotg, gotgctl, GOTGCTL); - dwc2_force_mode(hsotg, false); @@ -1058,7 +1120,23 @@ index 2d4176f5788e..27202eb05bde 100644 } static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) -@@ -86,6 +87,19 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) +@@ -39,6 +44,7 @@ static int dwc2_ovr_avalid(struct dwc2_hsotg *hsotg, bool valid) + (!valid && !(gotgctl & GOTGCTL_ASESVLD))) + return -EALREADY; + ++ gotgctl &= ~GOTGCTL_BVALOVAL; + if (valid) + gotgctl |= GOTGCTL_AVALOVAL | GOTGCTL_VBVALOVAL; + else +@@ -57,6 +63,7 @@ static int dwc2_ovr_bvalid(struct dwc2_hsotg *hsotg, bool valid) + (!valid && !(gotgctl & GOTGCTL_BSESVLD))) + return -EALREADY; + ++ gotgctl &= ~GOTGCTL_AVALOVAL; + if (valid) + gotgctl |= GOTGCTL_BVALOVAL | GOTGCTL_VBVALOVAL; + else +@@ -86,6 +93,19 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) } #endif @@ -1078,7 +1156,7 @@ index 2d4176f5788e..27202eb05bde 100644 spin_lock_irqsave(&hsotg->lock, flags); if (role == USB_ROLE_HOST) { -@@ -110,6 +124,9 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) +@@ -110,6 +130,9 @@ static int dwc2_drd_role_sw_set(struct usb_role_switch *sw, enum usb_role role) /* This will raise a Connector ID Status Change Interrupt */ dwc2_force_mode(hsotg, role == USB_ROLE_HOST); @@ -1088,11 +1166,33 @@ index 2d4176f5788e..27202eb05bde 100644 dev_dbg(hsotg->dev, "%s-session valid\n", role == USB_ROLE_NONE ? "No" : role == USB_ROLE_HOST ? "A" : "B"); +@@ -121,11 +144,21 @@ int dwc2_drd_init(struct dwc2_hsotg *hsotg) + { + struct usb_role_switch_desc role_sw_desc = {0}; + struct usb_role_switch *role_sw; ++ const char *str; + int ret; + + if (!device_property_read_bool(hsotg->dev, "usb-role-switch")) + return 0; + ++ hsotg->role_sw_default_mode = USB_DR_MODE_UNKNOWN; ++ ret = device_property_read_string(hsotg->dev, "role-switch-default-mode", &str); ++ if (!ret) { ++ if (!strncmp(str, "host", strlen("host"))) ++ hsotg->role_sw_default_mode = USB_DR_MODE_HOST; ++ else if (!strncmp(str, "peripheral", strlen("peripheral"))) ++ hsotg->role_sw_default_mode = USB_DR_MODE_PERIPHERAL; ++ } ++ + role_sw_desc.driver_data = hsotg; + role_sw_desc.fwnode = dev_fwnode(hsotg->dev); + role_sw_desc.set = dwc2_drd_role_sw_set; diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c -index 0a0d11151cfb..780187454251 100644 +index b06286f13..9f6baef56 100644 --- a/drivers/usb/dwc2/gadget.c +++ b/drivers/usb/dwc2/gadget.c -@@ -3565,7 +3565,8 @@ void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) +@@ -3562,7 +3562,8 @@ void dwc2_hsotg_core_disconnect(struct dwc2_hsotg *hsotg) void dwc2_hsotg_core_connect(struct dwc2_hsotg *hsotg) { /* remove the soft-disconnect and let's go */ @@ -1102,7 +1202,15 @@ index 0a0d11151cfb..780187454251 100644 } /** -@@ -4982,7 +4983,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) +@@ -4892,6 +4893,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg) + hsotg->gadget.max_speed = USB_SPEED_HIGH; + hsotg->gadget.ops = &dwc2_hsotg_gadget_ops; + hsotg->gadget.name = dev_name(dev); ++ hsotg->gadget.otg_caps = &hsotg->dw_otg_caps; + hsotg->remote_wakeup_allowed = 0; + + if (hsotg->params.lpm) +@@ -5000,7 +5002,7 @@ int dwc2_hsotg_suspend(struct dwc2_hsotg *hsotg) hsotg->gadget.speed = USB_SPEED_UNKNOWN; spin_unlock_irqrestore(&hsotg->lock, flags); @@ -1112,10 +1220,10 @@ index 0a0d11151cfb..780187454251 100644 dwc2_hsotg_ep_disable_lock(&hsotg->eps_in[ep]->ep); if (hsotg->eps_out[ep]) diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c -index e9ac215b9663..a953f7b2e3a3 100644 +index 6af1dcbc3..71d5ca1a7 100644 --- a/drivers/usb/dwc2/hcd.c +++ b/drivers/usb/dwc2/hcd.c -@@ -1735,7 +1735,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) +@@ -1736,7 +1736,8 @@ static void dwc2_hcd_cleanup_channels(struct dwc2_hsotg *hsotg) * release_channel_ddma(), which is called from ep_disable when * device disconnects */ @@ -1125,7 +1233,7 @@ index e9ac215b9663..a953f7b2e3a3 100644 } /* All channels have been freed, mark them available */ if (hsotg->params.uframe_sched) { -@@ -3611,7 +3612,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, +@@ -3612,7 +3613,8 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, if (wvalue != USB_PORT_FEAT_TEST && (!windex || windex > 1)) goto error; @@ -1135,11 +1243,35 @@ index e9ac215b9663..a953f7b2e3a3 100644 /* * The port is disconnected, which means the core is * either in device mode or it soon will be. Just +@@ -3698,6 +3700,7 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq, + hprt0 &= ~HPRT0_TSTCTL_MASK; + hprt0 |= (windex >> 8) << HPRT0_TSTCTL_SHIFT; + dwc2_writel(hsotg, hprt0, HPRT0); ++ hsotg->test_mode = windex >> 8; + break; + + default: diff --git a/drivers/usb/dwc2/params.c b/drivers/usb/dwc2/params.c -index 267543c3dc38..92df3d620f7d 100644 +index 267543c3d..49a677ba6 100644 --- a/drivers/usb/dwc2/params.c +++ b/drivers/usb/dwc2/params.c -@@ -177,7 +177,10 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) +@@ -36,6 +36,7 @@ + #include + #include + #include ++#include + + #include "core.h" + +@@ -168,6 +169,7 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) + struct dwc2_core_params *p = &hsotg->params; + + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++ p->otg_rev = 0x200; + p->speed = DWC2_SPEED_PARAM_FULL; + p->host_rx_fifo_size = 128; + p->host_nperio_tx_fifo_size = 96; +@@ -177,7 +179,10 @@ static void dwc2_set_stm32mp15_fsotg_params(struct dwc2_hsotg *hsotg) p->i2c_enable = false; p->activate_stm_fs_transceiver = true; p->activate_stm_id_vb_detection = true; @@ -1150,7 +1282,12 @@ index 267543c3dc38..92df3d620f7d 100644 } static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) -@@ -189,7 +192,12 @@ static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) +@@ -185,11 +190,17 @@ static void dwc2_set_stm32mp15_hsotg_params(struct dwc2_hsotg *hsotg) + struct dwc2_core_params *p = &hsotg->params; + + p->otg_cap = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++ p->otg_rev = 0x200; + p->activate_stm_id_vb_detection = !device_property_read_bool(hsotg->dev, "usb-role-switch"); p->host_rx_fifo_size = 440; p->host_nperio_tx_fifo_size = 256; p->host_perio_tx_fifo_size = 256; @@ -1163,8 +1300,61 @@ index 267543c3dc38..92df3d620f7d 100644 } const struct of_device_id dwc2_of_match_table[] = { +@@ -231,18 +242,25 @@ static void dwc2_set_param_otg_cap(struct dwc2_hsotg *hsotg) + switch (hsotg->hw_params.op_mode) { + case GHWCFG2_OP_MODE_HNP_SRP_CAPABLE: + val = DWC2_CAP_PARAM_HNP_SRP_CAPABLE; ++ hsotg->dw_otg_caps.hnp_support = true; ++ hsotg->dw_otg_caps.srp_support = true; + break; + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: + val = DWC2_CAP_PARAM_SRP_ONLY_CAPABLE; ++ hsotg->dw_otg_caps.hnp_support = false; ++ hsotg->dw_otg_caps.srp_support = true; + break; + default: + val = DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE; ++ hsotg->dw_otg_caps.hnp_support = false; ++ hsotg->dw_otg_caps.srp_support = false; + break; + } + + hsotg->params.otg_cap = val; ++ hsotg->dw_otg_caps.otg_rev = hsotg->params.otg_rev; + } + + static void dwc2_set_param_phy_type(struct dwc2_hsotg *hsotg) +@@ -450,6 +468,9 @@ static void dwc2_get_device_properties(struct dwc2_hsotg *hsotg) + } + } + ++ if (hsotg->dr_mode == USB_DR_MODE_OTG) ++ of_usb_update_otg_caps(hsotg->dev->of_node, &hsotg->dw_otg_caps); ++ + if (of_find_property(hsotg->dev->of_node, "disable-over-current", NULL)) + p->oc_disable = true; + } +@@ -469,6 +490,7 @@ static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) + case GHWCFG2_OP_MODE_SRP_ONLY_CAPABLE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_DEVICE: + case GHWCFG2_OP_MODE_SRP_CAPABLE_HOST: ++ hsotg->dw_otg_caps.hnp_support = false; + break; + default: + valid = 0; +@@ -477,6 +499,8 @@ static void dwc2_check_param_otg_cap(struct dwc2_hsotg *hsotg) + break; + case DWC2_CAP_PARAM_NO_HNP_SRP_CAPABLE: + /* always valid */ ++ hsotg->dw_otg_caps.hnp_support = false; ++ hsotg->dw_otg_caps.srp_support = false; + break; + default: + valid = 0; diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c -index 5f18acac7406..f0964babf260 100644 +index 5f18acac7..f0964babf 100644 --- a/drivers/usb/dwc2/platform.c +++ b/drivers/usb/dwc2/platform.c @@ -224,8 +224,7 @@ static int dwc2_lowlevel_hw_init(struct dwc2_hsotg *hsotg) @@ -1271,7 +1461,7 @@ index 5f18acac7406..f0964babf260 100644 dwc2_drd_resume(dwc2); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c -index a48dd3fac153..5017913ce6cb 100644 +index a48dd3fac..5017913ce 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -35,6 +35,7 @@ @@ -1332,42 +1522,6 @@ index a48dd3fac153..5017913ce6cb 100644 if (pdata->power_on) { int err = pdata->power_on(pdev); if (err < 0) -diff --git a/drivers/usb/typec/stusb160x.c b/drivers/usb/typec/stusb160x.c -index d21750bbbb44..a7b51bf4af18 100644 ---- a/drivers/usb/typec/stusb160x.c -+++ b/drivers/usb/typec/stusb160x.c -@@ -739,10 +739,6 @@ static int stusb160x_probe(struct i2c_client *client) - typec_set_pwr_opmode(chip->port, chip->pwr_opmode); - - if (client->irq) { -- ret = stusb160x_irq_init(chip, client->irq); -- if (ret) -- goto port_unregister; -- - chip->role_sw = fwnode_usb_role_switch_get(fwnode); - if (IS_ERR(chip->role_sw)) { - ret = PTR_ERR(chip->role_sw); -@@ -752,6 +748,10 @@ static int stusb160x_probe(struct i2c_client *client) - ret); - goto port_unregister; - } -+ -+ ret = stusb160x_irq_init(chip, client->irq); -+ if (ret) -+ goto role_sw_put; - } else { - /* - * If Source or Dual power role, need to enable VDD supply -@@ -775,6 +775,9 @@ static int stusb160x_probe(struct i2c_client *client) - - return 0; - -+role_sw_put: -+ if (chip->role_sw) -+ usb_role_switch_put(chip->role_sw); - port_unregister: - typec_unregister_port(chip->port); - all_reg_disable: -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch new file mode 100644 index 0000000..834ca94 --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch @@ -0,0 +1,2218 @@ +From b38c029ee9690c49ab2b225e9f83221f4c17254f Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:50 +0200 +Subject: [PATCH 16/23] ARM 5.10.61-stm32mp1-r2 PINCTRL-REGULATOR-SPI + +--- + drivers/mtd/nand/spi/core.c | 157 ++++++++---- + drivers/pinctrl/stm32/pinctrl-stm32.c | 121 +++++---- + drivers/pinctrl/stm32/pinctrl-stm32.h | 17 +- + drivers/pinctrl/stm32/pinctrl-stm32mp157.c | 1 + + drivers/pwm/pwm-stm32-lp.c | 4 +- + drivers/pwm/pwm-stm32.c | 4 + + drivers/regulator/stm32-pwr.c | 85 ++++++- + drivers/regulator/stpmic1_regulator.c | 182 ++++++++++++- + drivers/spi/Kconfig | 1 + + drivers/spi/spi-mem.c | 86 +++++++ + drivers/spi/spi-stm32-qspi.c | 176 +++++++++++-- + drivers/spi/spi-stm32.c | 267 +++++++++----------- + include/dt-bindings/pinctrl/stm32-pinfunc.h | 1 + + include/linux/mtd/spinand.h | 22 ++ + include/linux/spi/spi-mem.h | 16 ++ + 15 files changed, 840 insertions(+), 300 deletions(-) + +diff --git a/drivers/mtd/nand/spi/core.c b/drivers/mtd/nand/spi/core.c +index 558d8a148..89ebb42a2 100644 +--- a/drivers/mtd/nand/spi/core.c ++++ b/drivers/mtd/nand/spi/core.c +@@ -138,20 +138,12 @@ int spinand_select_target(struct spinand_device *spinand, unsigned int target) + return 0; + } + +-static int spinand_init_cfg_cache(struct spinand_device *spinand) ++static int spinand_read_cfg(struct spinand_device *spinand) + { + struct nand_device *nand = spinand_to_nand(spinand); +- struct device *dev = &spinand->spimem->spi->dev; + unsigned int target; + int ret; + +- spinand->cfg_cache = devm_kcalloc(dev, +- nand->memorg.ntargets, +- sizeof(*spinand->cfg_cache), +- GFP_KERNEL); +- if (!spinand->cfg_cache) +- return -ENOMEM; +- + for (target = 0; target < nand->memorg.ntargets; target++) { + ret = spinand_select_target(spinand, target); + if (ret) +@@ -170,6 +162,21 @@ static int spinand_init_cfg_cache(struct spinand_device *spinand) + return 0; + } + ++static int spinand_init_cfg_cache(struct spinand_device *spinand) ++{ ++ struct nand_device *nand = spinand_to_nand(spinand); ++ struct device *dev = &spinand->spimem->spi->dev; ++ ++ spinand->cfg_cache = devm_kcalloc(dev, ++ nand->memorg.ntargets, ++ sizeof(*spinand->cfg_cache), ++ GFP_KERNEL); ++ if (!spinand->cfg_cache) ++ return -ENOMEM; ++ ++ return 0; ++} ++ + static int spinand_init_quad_enable(struct spinand_device *spinand) + { + bool enable = false; +@@ -341,20 +348,26 @@ static int spinand_erase_op(struct spinand_device *spinand, + return spi_mem_exec_op(spinand->spimem, &op); + } + +-static int spinand_wait(struct spinand_device *spinand, u8 *s) ++static int spinand_wait(struct spinand_device *spinand, ++ unsigned long initial_delay_us, ++ unsigned long poll_delay_us, ++ u8 *s) + { +- unsigned long timeo = jiffies + msecs_to_jiffies(400); ++ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(REG_STATUS, ++ spinand->scratchbuf); + u8 status; + int ret; + +- do { +- ret = spinand_read_status(spinand, &status); +- if (ret) +- return ret; ++ ret = spi_mem_poll_status(spinand->spimem, &op, STATUS_BUSY, 0, ++ initial_delay_us, ++ poll_delay_us, ++ SPINAND_WAITRDY_TIMEOUT_MS); ++ if (ret) ++ return ret; + +- if (!(status & STATUS_BUSY)) +- goto out; +- } while (time_before(jiffies, timeo)); ++ status = *spinand->scratchbuf; ++ if (!(status & STATUS_BUSY)) ++ goto out; + + /* + * Extra read, just in case the STATUS_READY bit has changed +@@ -394,7 +407,10 @@ static int spinand_reset_op(struct spinand_device *spinand) + if (ret) + return ret; + +- return spinand_wait(spinand, NULL); ++ return spinand_wait(spinand, ++ SPINAND_RESET_INITIAL_DELAY_US, ++ SPINAND_RESET_POLL_DELAY_US, ++ NULL); + } + + static int spinand_lock_block(struct spinand_device *spinand, u8 lock) +@@ -442,7 +458,10 @@ static int spinand_read_page(struct spinand_device *spinand, + if (ret) + return ret; + +- ret = spinand_wait(spinand, &status); ++ ret = spinand_wait(spinand, ++ SPINAND_READ_INITIAL_DELAY_US, ++ SPINAND_READ_POLL_DELAY_US, ++ &status); + if (ret < 0) + return ret; + +@@ -474,7 +493,10 @@ static int spinand_write_page(struct spinand_device *spinand, + if (ret) + return ret; + +- ret = spinand_wait(spinand, &status); ++ ret = spinand_wait(spinand, ++ SPINAND_WRITE_INITIAL_DELAY_US, ++ SPINAND_WRITE_POLL_DELAY_US, ++ &status); + if (!ret && (status & STATUS_PROG_FAILED)) + ret = -EIO; + +@@ -659,7 +681,11 @@ static int spinand_erase(struct nand_device *nand, const struct nand_pos *pos) + if (ret) + return ret; + +- ret = spinand_wait(spinand, &status); ++ ret = spinand_wait(spinand, ++ SPINAND_ERASE_INITIAL_DELAY_US, ++ SPINAND_ERASE_POLL_DELAY_US, ++ &status); ++ + if (!ret && (status & STATUS_ERASE_FAILED)) + ret = -EIO; + +@@ -989,12 +1015,71 @@ static const struct mtd_ooblayout_ops spinand_noecc_ooblayout = { + .free = spinand_noecc_ooblayout_free, + }; + ++static int spinand_init_flash(struct spinand_device *spinand) ++{ ++ struct device *dev = &spinand->spimem->spi->dev; ++ struct nand_device *nand = spinand_to_nand(spinand); ++ int ret, i; ++ ++ ret = spinand_read_cfg(spinand); ++ if (ret) ++ return ret; ++ ++ ret = spinand_init_quad_enable(spinand); ++ if (ret) ++ return ret; ++ ++ ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); ++ if (ret) ++ return ret; ++ ++ ret = spinand_manufacturer_init(spinand); ++ if (ret) { ++ dev_err(dev, ++ "Failed to initialize the SPI NAND chip (err = %d)\n", ++ ret); ++ return ret; ++ } ++ ++ /* After power up, all blocks are locked, so unlock them here. */ ++ for (i = 0; i < nand->memorg.ntargets; i++) { ++ ret = spinand_select_target(spinand, i); ++ if (ret) ++ break; ++ ++ ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); ++ if (ret) ++ break; ++ } ++ ++ if (ret) ++ spinand_manufacturer_cleanup(spinand); ++ ++ return ret; ++} ++ ++static void spinand_mtd_resume(struct mtd_info *mtd) ++{ ++ struct spinand_device *spinand = mtd_to_spinand(mtd); ++ int ret; ++ ++ ret = spinand_reset_op(spinand); ++ if (ret) ++ return; ++ ++ ret = spinand_init_flash(spinand); ++ if (ret) ++ return; ++ ++ spinand_ecc_enable(spinand, false); ++} ++ + static int spinand_init(struct spinand_device *spinand) + { + struct device *dev = &spinand->spimem->spi->dev; + struct mtd_info *mtd = spinand_to_mtd(spinand); + struct nand_device *nand = mtd_to_nanddev(mtd); +- int ret, i; ++ int ret; + + /* + * We need a scratch buffer because the spi_mem interface requires that +@@ -1027,22 +1112,10 @@ static int spinand_init(struct spinand_device *spinand) + if (ret) + goto err_free_bufs; + +- ret = spinand_init_quad_enable(spinand); ++ ret = spinand_init_flash(spinand); + if (ret) + goto err_free_bufs; + +- ret = spinand_upd_cfg(spinand, CFG_OTP_ENABLE, 0); +- if (ret) +- goto err_free_bufs; +- +- ret = spinand_manufacturer_init(spinand); +- if (ret) { +- dev_err(dev, +- "Failed to initialize the SPI NAND chip (err = %d)\n", +- ret); +- goto err_free_bufs; +- } +- + ret = spinand_create_dirmaps(spinand); + if (ret) { + dev_err(dev, +@@ -1051,17 +1124,6 @@ static int spinand_init(struct spinand_device *spinand) + goto err_manuf_cleanup; + } + +- /* After power up, all blocks are locked, so unlock them here. */ +- for (i = 0; i < nand->memorg.ntargets; i++) { +- ret = spinand_select_target(spinand, i); +- if (ret) +- goto err_manuf_cleanup; +- +- ret = spinand_lock_block(spinand, BL_ALL_UNLOCKED); +- if (ret) +- goto err_manuf_cleanup; +- } +- + ret = nanddev_init(nand, &spinand_ops, THIS_MODULE); + if (ret) + goto err_manuf_cleanup; +@@ -1077,6 +1139,7 @@ static int spinand_init(struct spinand_device *spinand) + mtd->_block_isreserved = spinand_mtd_block_isreserved; + mtd->_erase = spinand_mtd_erase; + mtd->_max_bad_blocks = nanddev_mtd_max_bad_blocks; ++ mtd->_resume = spinand_mtd_resume; + + if (spinand->eccinfo.ooblayout) + mtd_set_ooblayout(mtd, spinand->eccinfo.ooblayout); +diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.c b/drivers/pinctrl/stm32/pinctrl-stm32.c +index 3af443054..474b9debc 100644 +--- a/drivers/pinctrl/stm32/pinctrl-stm32.c ++++ b/drivers/pinctrl/stm32/pinctrl-stm32.c +@@ -73,6 +73,7 @@ static const char * const stm32_gpio_functions[] = { + "af8", "af9", "af10", + "af11", "af12", "af13", + "af14", "af15", "analog", ++ "reserved", + }; + + struct stm32_pinctrl_group { +@@ -115,6 +116,7 @@ struct stm32_pinctrl { + u32 pkg; + u16 irqmux_map; + spinlock_t irqmux_lock; ++ u32 pin_base_shift; + }; + + static inline int stm32_gpio_pin(int gpio) +@@ -414,57 +416,25 @@ static int stm32_gpio_domain_activate(struct irq_domain *d, + { + struct stm32_gpio_bank *bank = d->host_data; + struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); +- unsigned long flags; + int ret = 0; + +- /* +- * gpio irq mux is shared between several banks, a lock has to be done +- * to avoid overriding. +- */ +- spin_lock_irqsave(&pctl->irqmux_lock, flags); +- + if (pctl->hwlock) { + ret = hwspin_lock_timeout_in_atomic(pctl->hwlock, + HWSPNLCK_TIMEOUT); + if (ret) { + dev_err(pctl->dev, "Can't get hwspinlock\n"); +- goto unlock; ++ return ret; + } + } + +- if (pctl->irqmux_map & BIT(irq_data->hwirq)) { +- dev_err(pctl->dev, "irq line %ld already requested.\n", +- irq_data->hwirq); +- ret = -EBUSY; +- if (pctl->hwlock) +- hwspin_unlock_in_atomic(pctl->hwlock); +- goto unlock; +- } else { +- pctl->irqmux_map |= BIT(irq_data->hwirq); +- } +- + regmap_field_write(pctl->irqmux[irq_data->hwirq], bank->bank_ioport_nr); + + if (pctl->hwlock) + hwspin_unlock_in_atomic(pctl->hwlock); + +-unlock: +- spin_unlock_irqrestore(&pctl->irqmux_lock, flags); + return ret; + } + +-static void stm32_gpio_domain_deactivate(struct irq_domain *d, +- struct irq_data *irq_data) +-{ +- struct stm32_gpio_bank *bank = d->host_data; +- struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); +- unsigned long flags; +- +- spin_lock_irqsave(&pctl->irqmux_lock, flags); +- pctl->irqmux_map &= ~BIT(irq_data->hwirq); +- spin_unlock_irqrestore(&pctl->irqmux_lock, flags); +-} +- + static int stm32_gpio_domain_alloc(struct irq_domain *d, + unsigned int virq, + unsigned int nr_irqs, void *data) +@@ -472,9 +442,28 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d, + struct stm32_gpio_bank *bank = d->host_data; + struct irq_fwspec *fwspec = data; + struct irq_fwspec parent_fwspec; +- irq_hw_number_t hwirq; ++ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); ++ irq_hw_number_t hwirq = fwspec->param[0]; ++ unsigned long flags; ++ int ret = 0; ++ ++ /* ++ * Check first that the IRQ MUX of that line is free. ++ * gpio irq mux is shared between several banks, protect with a lock ++ */ ++ spin_lock_irqsave(&pctl->irqmux_lock, flags); ++ ++ if (pctl->irqmux_map & BIT(hwirq)) { ++ dev_err(pctl->dev, "irq line %ld already requested.\n", hwirq); ++ ret = -EBUSY; ++ } else { ++ pctl->irqmux_map |= BIT(hwirq); ++ } ++ ++ spin_unlock_irqrestore(&pctl->irqmux_lock, flags); ++ if (ret) ++ return ret; + +- hwirq = fwspec->param[0]; + parent_fwspec.fwnode = d->parent->fwnode; + parent_fwspec.param_count = 2; + parent_fwspec.param[0] = fwspec->param[0]; +@@ -486,12 +475,26 @@ static int stm32_gpio_domain_alloc(struct irq_domain *d, + return irq_domain_alloc_irqs_parent(d, virq, nr_irqs, &parent_fwspec); + } + ++static void stm32_gpio_domain_free(struct irq_domain *d, unsigned int virq, ++ unsigned int nr_irqs) ++{ ++ struct stm32_gpio_bank *bank = d->host_data; ++ struct stm32_pinctrl *pctl = dev_get_drvdata(bank->gpio_chip.parent); ++ struct irq_data *irq_data = irq_domain_get_irq_data(d, virq); ++ unsigned long flags, hwirq = irq_data->hwirq; ++ ++ irq_domain_free_irqs_common(d, virq, nr_irqs); ++ ++ spin_lock_irqsave(&pctl->irqmux_lock, flags); ++ pctl->irqmux_map &= ~BIT(hwirq); ++ spin_unlock_irqrestore(&pctl->irqmux_lock, flags); ++} ++ + static const struct irq_domain_ops stm32_gpio_domain_ops = { +- .translate = stm32_gpio_domain_translate, +- .alloc = stm32_gpio_domain_alloc, +- .free = irq_domain_free_irqs_common, ++ .translate = stm32_gpio_domain_translate, ++ .alloc = stm32_gpio_domain_alloc, ++ .free = stm32_gpio_domain_free, + .activate = stm32_gpio_domain_activate, +- .deactivate = stm32_gpio_domain_deactivate, + }; + + /* Pinctrl functions */ +@@ -513,7 +516,7 @@ stm32_pctrl_find_group_by_pin(struct stm32_pinctrl *pctl, u32 pin) + static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, + u32 pin_num, u32 fnum) + { +- int i; ++ int i, k; + + for (i = 0; i < pctl->npins; i++) { + const struct stm32_desc_pin *pin = pctl->pins + i; +@@ -522,7 +525,10 @@ static bool stm32_pctrl_is_function_valid(struct stm32_pinctrl *pctl, + if (pin->pin.number != pin_num) + continue; + +- while (func && func->name) { ++ if (fnum == STM32_PIN_RSVD) ++ return true; ++ ++ for (k = 0; k < STM32_CONFIG_NUM; k++) { + if (func->num == fnum) + return true; + func++; +@@ -833,6 +839,11 @@ static int stm32_pmx_set_mux(struct pinctrl_dev *pctldev, + return -EINVAL; + } + ++ if (function == STM32_PIN_RSVD) { ++ dev_dbg(pctl->dev, "Reserved pins, skipping HW update.\n"); ++ return 0; ++ } ++ + bank = gpiochip_get_data(range->gc); + pin = stm32_gpio_pin(g->pin); + +@@ -1147,10 +1158,27 @@ static int stm32_pconf_set(struct pinctrl_dev *pctldev, unsigned int pin, + return 0; + } + ++static struct stm32_desc_pin * ++stm32_pconf_get_pin_desc_by_pin_number(struct stm32_pinctrl *pctl, ++ unsigned int pin_number) ++{ ++ struct stm32_desc_pin *pins = pctl->pins; ++ int i; ++ ++ for (i = 0; i < pctl->npins; i++) { ++ if (pins->pin.number == pin_number) ++ return pins; ++ pins++; ++ } ++ return NULL; ++} ++ + static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, + struct seq_file *s, + unsigned int pin) + { ++ struct stm32_pinctrl *pctl = pinctrl_dev_get_drvdata(pctldev); ++ const struct stm32_desc_pin *pin_desc; + struct pinctrl_gpio_range *range; + struct stm32_gpio_bank *bank; + int offset; +@@ -1200,7 +1228,12 @@ static void stm32_pconf_dbg_show(struct pinctrl_dev *pctldev, + case 2: + drive = stm32_pconf_get_driving(bank, offset); + speed = stm32_pconf_get_speed(bank, offset); +- seq_printf(s, "%d - %s - %s - %s %s", alt, ++ pin_desc = stm32_pconf_get_pin_desc_by_pin_number(pctl, pin); ++ if (!pin_desc) ++ return; ++ ++ seq_printf(s, "%d (%s) - %s - %s - %s %s", alt, ++ pin_desc->functions[alt + 1].name, + drive ? "open drain" : "push pull", + biasing[bias], + speeds[speed], "speed"); +@@ -1409,7 +1442,8 @@ static int stm32_pctrl_create_pins_tab(struct stm32_pinctrl *pctl, + if (pctl->pkg && !(pctl->pkg & p->pkg)) + continue; + pins->pin = p->pin; +- pins->functions = p->functions; ++ memcpy((struct stm32_desc_pin *)pins->functions, p->functions, ++ STM32_CONFIG_NUM * sizeof(struct stm32_desc_function)); + pins++; + nb_pins_available++; + } +@@ -1518,6 +1552,7 @@ int stm32_pctl_probe(struct platform_device *pdev) + pctl->pctl_desc.pctlops = &stm32_pctrl_ops; + pctl->pctl_desc.pmxops = &stm32_pmx_ops; + pctl->dev = &pdev->dev; ++ pctl->pin_base_shift = pctl->match_data->pin_base_shift; + + pctl->pctl_dev = devm_pinctrl_register(&pdev->dev, &pctl->pctl_desc, + pctl); +diff --git a/drivers/pinctrl/stm32/pinctrl-stm32.h b/drivers/pinctrl/stm32/pinctrl-stm32.h +index b0882d120..a7137fbff 100644 +--- a/drivers/pinctrl/stm32/pinctrl-stm32.h ++++ b/drivers/pinctrl/stm32/pinctrl-stm32.h +@@ -17,6 +17,8 @@ + #define STM32_PIN_GPIO 0 + #define STM32_PIN_AF(x) ((x) + 1) + #define STM32_PIN_ANALOG (STM32_PIN_AF(15) + 1) ++#define STM32_PIN_RSVD (STM32_PIN_ANALOG + 1) ++#define STM32_CONFIG_NUM (STM32_PIN_RSVD + 1) + + /* package information */ + #define STM32MP_PKG_AA BIT(0) +@@ -24,6 +26,8 @@ + #define STM32MP_PKG_AC BIT(2) + #define STM32MP_PKG_AD BIT(3) + ++#define STM32MP157_Z_BASE_SHIFT 400 ++ + struct stm32_desc_function { + const char *name; + const unsigned char num; +@@ -31,26 +35,26 @@ struct stm32_desc_function { + + struct stm32_desc_pin { + struct pinctrl_pin_desc pin; +- const struct stm32_desc_function *functions; ++ const struct stm32_desc_function functions[STM32_CONFIG_NUM]; + const unsigned int pkg; + }; + + #define STM32_PIN(_pin, ...) \ + { \ + .pin = _pin, \ +- .functions = (struct stm32_desc_function[]){ \ +- __VA_ARGS__, { } }, \ ++ .functions = { \ ++ __VA_ARGS__}, \ + } + + #define STM32_PIN_PKG(_pin, _pkg, ...) \ + { \ + .pin = _pin, \ + .pkg = _pkg, \ +- .functions = (struct stm32_desc_function[]){ \ +- __VA_ARGS__, { } }, \ ++ .functions = { \ ++ __VA_ARGS__}, \ + } + #define STM32_FUNCTION(_num, _name) \ +- { \ ++ [_num] = { \ + .num = _num, \ + .name = _name, \ + } +@@ -58,6 +62,7 @@ struct stm32_desc_pin { + struct stm32_pinctrl_match_data { + const struct stm32_desc_pin *pins; + const unsigned int npins; ++ const unsigned int pin_base_shift; + }; + + struct stm32_gpio_bank; +diff --git a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +index 2ccb99d64..86fe6d5ac 100644 +--- a/drivers/pinctrl/stm32/pinctrl-stm32mp157.c ++++ b/drivers/pinctrl/stm32/pinctrl-stm32mp157.c +@@ -2328,6 +2328,7 @@ static struct stm32_pinctrl_match_data stm32mp157_match_data = { + static struct stm32_pinctrl_match_data stm32mp157_z_match_data = { + .pins = stm32mp157_z_pins, + .npins = ARRAY_SIZE(stm32mp157_z_pins), ++ .pin_base_shift = STM32MP157_Z_BASE_SHIFT, + }; + + static const struct of_device_id stm32mp157_pctrl_match[] = { +diff --git a/drivers/pwm/pwm-stm32-lp.c b/drivers/pwm/pwm-stm32-lp.c +index 134c14621..5967025e9 100644 +--- a/drivers/pwm/pwm-stm32-lp.c ++++ b/drivers/pwm/pwm-stm32-lp.c +@@ -58,7 +58,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, + + /* Calculate the period and prescaler value */ + div = (unsigned long long)clk_get_rate(priv->clk) * state->period; +- do_div(div, NSEC_PER_SEC); ++ div = DIV_ROUND_CLOSEST_ULL(div, NSEC_PER_SEC); + if (!div) { + /* Clock is too slow to achieve requested period. */ + dev_dbg(priv->chip.dev, "Can't reach %llu ns\n", state->period); +@@ -78,7 +78,7 @@ static int stm32_pwm_lp_apply(struct pwm_chip *chip, struct pwm_device *pwm, + + /* Calculate the duty cycle */ + dty = prd * state->duty_cycle; +- do_div(dty, state->period); ++ dty = DIV_ROUND_CLOSEST_ULL(dty, state->period); + + if (!cstate.enabled) { + /* enable clock to drive PWM counter */ +diff --git a/drivers/pwm/pwm-stm32.c b/drivers/pwm/pwm-stm32.c +index d3be944f2..13f47e255 100644 +--- a/drivers/pwm/pwm-stm32.c ++++ b/drivers/pwm/pwm-stm32.c +@@ -207,6 +207,10 @@ static int stm32_pwm_capture(struct pwm_chip *chip, struct pwm_device *pwm, + regmap_write(priv->regmap, TIM_ARR, priv->max_arr); + regmap_write(priv->regmap, TIM_PSC, psc); + ++ /* Reset input selector to its default input and disable slave mode */ ++ regmap_write(priv->regmap, TIM_TISEL, 0x0); ++ regmap_write(priv->regmap, TIM_SMCR, 0x0); ++ + /* Map TI1 or TI2 PWM input to IC1 & IC2 (or TI3/4 to IC3 & IC4) */ + regmap_update_bits(priv->regmap, + pwm->hwpwm < 2 ? TIM_CCMR1 : TIM_CCMR2, +diff --git a/drivers/regulator/stm32-pwr.c b/drivers/regulator/stm32-pwr.c +index 2a42acb7c..2b328b970 100644 +--- a/drivers/regulator/stm32-pwr.c ++++ b/drivers/regulator/stm32-pwr.c +@@ -3,12 +3,15 @@ + // Authors: Gabriel Fernandez + // Pascal Paillet . + ++#include + #include + #include ++#include + #include + #include + #include + #include ++#include + #include + #include + +@@ -24,6 +27,11 @@ + #define REG_1_1_EN BIT(30) + #define REG_1_1_RDY BIT(31) + ++#define STM32_SMC_PWR 0x82001001 ++#define STM32_WRITE 0x1 ++#define STM32_SMC_REG_SET 0x2 ++#define STM32_SMC_REG_CLEAR 0x3 ++ + /* list of supported regulators */ + enum { + PWR_REG11, +@@ -39,10 +47,18 @@ static u32 ready_mask_table[STM32PWR_REG_NUM_REGS] = { + }; + + struct stm32_pwr_reg { ++ int tzen; + void __iomem *base; + u32 ready_mask; + }; + ++#define SMC(class, op, address, val)\ ++ ({\ ++ struct arm_smccc_res res;\ ++ arm_smccc_smc(class, op, address, val,\ ++ 0, 0, 0, 0, &res);\ ++ }) ++ + static int stm32_pwr_reg_is_ready(struct regulator_dev *rdev) + { + struct stm32_pwr_reg *priv = rdev_get_drvdata(rdev); +@@ -69,9 +85,15 @@ static int stm32_pwr_reg_enable(struct regulator_dev *rdev) + int ret; + u32 val; + +- val = readl_relaxed(priv->base + REG_PWR_CR3); +- val |= rdev->desc->enable_mask; +- writel_relaxed(val, priv->base + REG_PWR_CR3); ++ if (priv->tzen) { ++ SMC(STM32_SMC_PWR, STM32_SMC_REG_SET, REG_PWR_CR3, ++ rdev->desc->enable_mask); ++ } else { ++ val = readl_relaxed(priv->base + REG_PWR_CR3); ++ val |= rdev->desc->enable_mask; ++ writel_relaxed(val, priv->base + REG_PWR_CR3); ++ } ++ + + /* use an arbitrary timeout of 20ms */ + ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, val, +@@ -88,9 +110,14 @@ static int stm32_pwr_reg_disable(struct regulator_dev *rdev) + int ret; + u32 val; + +- val = readl_relaxed(priv->base + REG_PWR_CR3); +- val &= ~rdev->desc->enable_mask; +- writel_relaxed(val, priv->base + REG_PWR_CR3); ++ if (priv->tzen) { ++ SMC(STM32_SMC_PWR, STM32_SMC_REG_CLEAR, REG_PWR_CR3, ++ rdev->desc->enable_mask); ++ } else { ++ val = readl_relaxed(priv->base + REG_PWR_CR3); ++ val &= ~rdev->desc->enable_mask; ++ writel_relaxed(val, priv->base + REG_PWR_CR3); ++ } + + /* use an arbitrary timeout of 20ms */ + ret = readx_poll_timeout(stm32_pwr_reg_is_ready, rdev, val, !val, +@@ -121,12 +148,50 @@ static const struct regulator_ops stm32_pwr_reg_ops = { + .supply_name = _supply, \ + } \ + +-static const struct regulator_desc stm32_pwr_desc[] = { ++static struct regulator_desc stm32_pwr_desc[] = { + PWR_REG(PWR_REG11, "reg11", 1100000, REG_1_1_EN, "vdd"), + PWR_REG(PWR_REG18, "reg18", 1800000, REG_1_8_EN, "vdd"), + PWR_REG(PWR_USB33, "usb33", 3300000, USB_3_3_EN, "vdd_3v3_usbfs"), + }; + ++static int is_stm32_soc_secured(struct platform_device *pdev, int *val) ++{ ++ struct device_node *np = pdev->dev.of_node; ++ struct regmap *syscon; ++ u32 reg, mask; ++ int tzc_val = 0; ++ int err; ++ ++ syscon = syscon_regmap_lookup_by_phandle(np, "st,tzcr"); ++ if (IS_ERR(syscon)) { ++ if (PTR_ERR(syscon) != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "tzcr syscon required\n"); ++ return PTR_ERR(syscon); ++ } ++ ++ err = of_property_read_u32_index(np, "st,tzcr", 1, ®); ++ if (err) { ++ dev_err(&pdev->dev, "tzcr offset required !\n"); ++ return err; ++ } ++ ++ err = of_property_read_u32_index(np, "st,tzcr", 2, &mask); ++ if (err) { ++ dev_err(&pdev->dev, "tzcr mask required !\n"); ++ return err; ++ } ++ ++ err = regmap_read(syscon, reg, &tzc_val); ++ if (err) { ++ dev_err(&pdev->dev, "failed to read tzcr status !\n"); ++ return err; ++ } ++ ++ *val = tzc_val & mask; ++ ++ return 0; ++} ++ + static int stm32_pwr_regulator_probe(struct platform_device *pdev) + { + struct device_node *np = pdev->dev.of_node; +@@ -135,6 +200,11 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) + struct regulator_dev *rdev; + struct regulator_config config = { }; + int i, ret = 0; ++ int tzen = 0; ++ ++ ret = is_stm32_soc_secured(pdev, &tzen); ++ if (ret) ++ return ret; + + base = of_iomap(np, 0); + if (!base) { +@@ -149,6 +219,7 @@ static int stm32_pwr_regulator_probe(struct platform_device *pdev) + GFP_KERNEL); + if (!priv) + return -ENOMEM; ++ priv->tzen = tzen; + priv->base = base; + priv->ready_mask = ready_mask_table[i]; + config.driver_data = priv; +diff --git a/drivers/regulator/stpmic1_regulator.c b/drivers/regulator/stpmic1_regulator.c +index cf10fdb72..c5337a12a 100644 +--- a/drivers/regulator/stpmic1_regulator.c ++++ b/drivers/regulator/stpmic1_regulator.c +@@ -2,7 +2,9 @@ + // Copyright (C) STMicroelectronics 2018 + // Author: Pascal Paillet for STMicroelectronics. + ++#include + #include ++#include + #include + #include + #include +@@ -30,10 +32,26 @@ struct stpmic1_regulator_cfg { + u8 icc_mask; + }; + ++/** ++ * struct boost_data - this structure is used as driver data for the usb boost ++ * @boost_rdev: device for boost regulator ++ * @vbus_otg_rdev: device for vbus_otg regulator ++ * @sw_out_rdev: device for sw_out regulator ++ * @occ_timeout: overcurrent detection timeout ++ */ ++struct boost_data { ++ struct regulator_dev *boost_rdev; ++ struct regulator_dev *vbus_otg_rdev; ++ struct regulator_dev *sw_out_rdev; ++ ktime_t occ_timeout; ++}; ++ + static int stpmic1_set_mode(struct regulator_dev *rdev, unsigned int mode); + static unsigned int stpmic1_get_mode(struct regulator_dev *rdev); + static int stpmic1_set_icc(struct regulator_dev *rdev); + static unsigned int stpmic1_map_mode(unsigned int mode); ++static int regulator_enable_boost(struct regulator_dev *rdev); ++static int regulator_disable_boost(struct regulator_dev *rdev); + + enum { + STPMIC1_BUCK1 = 0, +@@ -181,8 +199,8 @@ static const struct regulator_ops stpmic1_vref_ddr_ops = { + + static const struct regulator_ops stpmic1_boost_regul_ops = { + .is_enabled = regulator_is_enabled_regmap, +- .enable = regulator_enable_regmap, +- .disable = regulator_disable_regmap, ++ .enable = regulator_enable_boost, ++ .disable = regulator_disable_boost, + .set_over_current_protection = stpmic1_set_icc, + }; + +@@ -513,6 +531,79 @@ static irqreturn_t stpmic1_curlim_irq_handler(int irq, void *data) + return IRQ_HANDLED; + } + ++static int regulator_enable_boost(struct regulator_dev *rdev) ++{ ++ struct boost_data *usb_data = rdev_get_drvdata(rdev); ++ ++ usb_data->occ_timeout = ktime_add_us(ktime_get(), 100000); ++ ++ return regulator_enable_regmap(rdev); ++} ++ ++static int regulator_disable_boost(struct regulator_dev *rdev) ++{ ++ struct boost_data *usb_data = rdev_get_drvdata(rdev); ++ ++ usb_data->occ_timeout = 0; ++ ++ return regulator_disable_regmap(rdev); ++} ++ ++static void stpmic1_reset_boost(struct boost_data *usb_data) ++{ ++ int otg_on = 0; ++ int sw_out_on = 0; ++ ++ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "reset usb boost\n"); ++ ++ /* the boost was actually disabled by the over-current protection */ ++ regulator_disable_regmap(usb_data->boost_rdev); ++ ++ if (usb_data->vbus_otg_rdev) ++ otg_on = regulator_is_enabled_regmap(usb_data->vbus_otg_rdev); ++ if (otg_on) ++ regulator_disable_regmap(usb_data->vbus_otg_rdev); ++ ++ if (usb_data->sw_out_rdev) ++ sw_out_on = regulator_is_enabled_regmap(usb_data->sw_out_rdev); ++ if (sw_out_on) ++ regulator_disable_regmap(usb_data->sw_out_rdev); ++ ++ regulator_enable_regmap(usb_data->boost_rdev); ++ ++ /* sleep at least 5ms */ ++ usleep_range(5000, 10000); ++ ++ if (otg_on) ++ regulator_enable_regmap(usb_data->vbus_otg_rdev); ++ ++ if (sw_out_on) ++ regulator_enable_regmap(usb_data->sw_out_rdev); ++ ++} ++ ++static irqreturn_t stpmic1_boost_irq_handler(int irq, void *data) ++{ ++ struct boost_data *usb_data = (struct boost_data *)data; ++ ++ dev_dbg(rdev_get_dev(usb_data->boost_rdev), "usb boost irq handler\n"); ++ ++ /* overcurrent detected on boost after timeout */ ++ if (usb_data->occ_timeout != 0 && ++ ktime_compare(ktime_get(), usb_data->occ_timeout) > 0) { ++ /* reset usb boost and usb power switches */ ++ stpmic1_reset_boost(usb_data); ++ return IRQ_HANDLED; ++ } ++ ++ /* Send an overcurrent notification */ ++ regulator_notifier_call_chain(usb_data->boost_rdev, ++ REGULATOR_EVENT_OVER_CURRENT, ++ NULL); ++ ++ return IRQ_HANDLED; ++} ++ + #define MATCH(_name, _id) \ + [STPMIC1_##_id] = { \ + .name = #_name, \ +@@ -536,9 +627,10 @@ static struct of_regulator_match stpmic1_matches[] = { + MATCH(pwr_sw2, SW_OUT), + }; + +-static int stpmic1_regulator_register(struct platform_device *pdev, int id, +- struct of_regulator_match *match, +- const struct stpmic1_regulator_cfg *cfg) ++static struct regulator_dev * ++stpmic1_regulator_register(struct platform_device *pdev, int id, ++ struct of_regulator_match *match, ++ const struct stpmic1_regulator_cfg *cfg) + { + struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); + struct regulator_dev *rdev; +@@ -556,7 +648,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, + if (IS_ERR(rdev)) { + dev_err(&pdev->dev, "failed to register %s regulator\n", + cfg->desc.name); +- return PTR_ERR(rdev); ++ return rdev; + } + + /* set mask reset */ +@@ -568,7 +660,7 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, + cfg->mask_reset_mask); + if (ret) { + dev_err(&pdev->dev, "set mask reset failed\n"); +- return ret; ++ return ERR_PTR(ret); + } + } + +@@ -582,15 +674,60 @@ static int stpmic1_regulator_register(struct platform_device *pdev, int id, + pdev->name, rdev); + if (ret) { + dev_err(&pdev->dev, "Request IRQ failed\n"); +- return ret; ++ return ERR_PTR(ret); + } + } +- return 0; ++ ++ return rdev; ++} ++ ++static struct regulator_dev * ++stpmic1_boost_register(struct platform_device *pdev, int id, ++ struct of_regulator_match *match, ++ const struct stpmic1_regulator_cfg *cfg, ++ struct boost_data *usb_data) ++{ ++ struct stpmic1 *pmic_dev = dev_get_drvdata(pdev->dev.parent); ++ struct regulator_dev *rdev; ++ struct regulator_config config = {}; ++ int ret = 0; ++ int irq; ++ ++ config.dev = &pdev->dev; ++ config.init_data = match->init_data; ++ config.of_node = match->of_node; ++ config.regmap = pmic_dev->regmap; ++ config.driver_data = (void *)usb_data; ++ ++ rdev = devm_regulator_register(&pdev->dev, &cfg->desc, &config); ++ if (IS_ERR(rdev)) { ++ dev_err(&pdev->dev, "failed to register %s regulator\n", ++ cfg->desc.name); ++ return rdev; ++ } ++ ++ /* setup an irq handler for over-current detection */ ++ irq = of_irq_get(config.of_node, 0); ++ if (irq > 0) { ++ ret = devm_request_threaded_irq(&pdev->dev, ++ irq, NULL, ++ stpmic1_boost_irq_handler, ++ IRQF_ONESHOT, pdev->name, ++ usb_data); ++ if (ret) { ++ dev_err(&pdev->dev, "Request IRQ failed\n"); ++ return ERR_PTR(ret); ++ } ++ } ++ ++ return rdev; + } + + static int stpmic1_regulator_probe(struct platform_device *pdev) + { + int i, ret; ++ struct boost_data *usb_data; ++ struct regulator_dev *rdev; + + ret = of_regulator_match(&pdev->dev, pdev->dev.of_node, stpmic1_matches, + ARRAY_SIZE(stpmic1_matches)); +@@ -600,11 +737,30 @@ static int stpmic1_regulator_probe(struct platform_device *pdev) + return ret; + } + ++ usb_data = devm_kzalloc(&pdev->dev, sizeof(*usb_data), GFP_KERNEL); ++ if (!usb_data) ++ return -ENOMEM; ++ + for (i = 0; i < ARRAY_SIZE(stpmic1_regulator_cfgs); i++) { +- ret = stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], +- &stpmic1_regulator_cfgs[i]); +- if (ret < 0) +- return ret; ++ if (i == STPMIC1_BOOST) { ++ rdev = ++ stpmic1_boost_register(pdev, i, &stpmic1_matches[i], ++ &stpmic1_regulator_cfgs[i], ++ usb_data); ++ ++ usb_data->boost_rdev = rdev; ++ } else { ++ rdev = ++ stpmic1_regulator_register(pdev, i, &stpmic1_matches[i], ++ &stpmic1_regulator_cfgs[i]); ++ ++ if (i == STPMIC1_VBUS_OTG) ++ usb_data->vbus_otg_rdev = rdev; ++ else if (i == STPMIC1_SW_OUT) ++ usb_data->sw_out_rdev = rdev; ++ } ++ if (IS_ERR(rdev)) ++ return PTR_ERR(rdev); + } + + dev_dbg(&pdev->dev, "stpmic1_regulator driver probed\n"); +diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig +index aadaea052..6bdeeea0d 100644 +--- a/drivers/spi/Kconfig ++++ b/drivers/spi/Kconfig +@@ -795,6 +795,7 @@ config SPI_STM32_QSPI + tristate "STMicroelectronics STM32 QUAD SPI controller" + depends on ARCH_STM32 || COMPILE_TEST + depends on OF ++ depends on SPI_MEM + help + This enables support for the Quad SPI controller in master mode. + This driver does not support generic SPI. The implementation only +diff --git a/drivers/spi/spi-mem.c b/drivers/spi/spi-mem.c +index 4682f49dc..1325db7f5 100644 +--- a/drivers/spi/spi-mem.c ++++ b/drivers/spi/spi-mem.c +@@ -6,6 +6,7 @@ + * Author: Boris Brezillon + */ + #include ++#include + #include + #include + #include +@@ -726,6 +727,91 @@ static inline struct spi_mem_driver *to_spi_mem_drv(struct device_driver *drv) + return container_of(drv, struct spi_mem_driver, spidrv.driver); + } + ++static int spi_mem_read_status(struct spi_mem *mem, ++ const struct spi_mem_op *op, ++ u16 *status) ++{ ++ const u8 *bytes = (u8 *)op->data.buf.in; ++ int ret; ++ ++ ret = spi_mem_exec_op(mem, op); ++ if (ret) ++ return ret; ++ ++ if (op->data.nbytes > 1) ++ *status = ((u16)bytes[0] << 8) | bytes[1]; ++ else ++ *status = bytes[0]; ++ ++ return 0; ++} ++ ++/** ++ * spi_mem_poll_status() - Poll memory device status ++ * @mem: SPI memory device ++ * @op: the memory operation to execute ++ * @mask: status bitmask to ckeck ++ * @match: (status & mask) expected value ++ * @initial_delay_us: delay in us before starting to poll ++ * @polling_delay_us: time to sleep between reads in us ++ * @timeout_ms: timeout in milliseconds ++ * ++ * This function polls a status register and returns when ++ * (status & mask) == match or when the timeout has expired. ++ * ++ * Return: 0 in case of success, -ETIMEDOUT in case of error, ++ * -EOPNOTSUPP if not supported. ++ */ ++int spi_mem_poll_status(struct spi_mem *mem, ++ const struct spi_mem_op *op, ++ u16 mask, u16 match, ++ unsigned long initial_delay_us, ++ unsigned long polling_delay_us, ++ u16 timeout_ms) ++{ ++ struct spi_controller *ctlr = mem->spi->controller; ++ int ret = -EOPNOTSUPP; ++ int read_status_ret; ++ u16 status; ++ ++ if (op->data.nbytes < 1 || op->data.nbytes > 2 || ++ op->data.dir != SPI_MEM_DATA_IN) ++ return -EINVAL; ++ ++ if (ctlr->mem_ops && ctlr->mem_ops->poll_status) { ++ ret = spi_mem_access_start(mem); ++ if (ret) ++ return ret; ++ ++ ret = ctlr->mem_ops->poll_status(mem, op, mask, match, ++ initial_delay_us, polling_delay_us, ++ timeout_ms); ++ ++ spi_mem_access_end(mem); ++ } ++ ++ if (ret == -EOPNOTSUPP) { ++ if (!spi_mem_supports_op(mem, op)) ++ return ret; ++ ++ if (initial_delay_us < 10) ++ udelay(initial_delay_us); ++ else ++ usleep_range((initial_delay_us >> 2) + 1, ++ initial_delay_us); ++ ++ ret = read_poll_timeout(spi_mem_read_status, read_status_ret, ++ (read_status_ret || ((status) & mask) == match), ++ polling_delay_us, timeout_ms * 1000, false, mem, ++ op, &status); ++ if (read_status_ret) ++ return read_status_ret; ++ } ++ ++ return ret; ++} ++EXPORT_SYMBOL_GPL(spi_mem_poll_status); ++ + static int spi_mem_probe(struct spi_device *spi) + { + struct spi_mem_driver *memdrv = to_spi_mem_drv(spi->dev.driver); +diff --git a/drivers/spi/spi-stm32-qspi.c b/drivers/spi/spi-stm32-qspi.c +index 4f24f6392..39003e1f6 100644 +--- a/drivers/spi/spi-stm32-qspi.c ++++ b/drivers/spi/spi-stm32-qspi.c +@@ -36,6 +36,7 @@ + #define CR_FTIE BIT(18) + #define CR_SMIE BIT(19) + #define CR_TOIE BIT(20) ++#define CR_APMS BIT(22) + #define CR_PRESC_MASK GENMASK(31, 24) + + #define QSPI_DCR 0x04 +@@ -53,6 +54,7 @@ + #define QSPI_FCR 0x0c + #define FCR_CTEF BIT(0) + #define FCR_CTCF BIT(1) ++#define FCR_CSMF BIT(3) + + #define QSPI_DLR 0x10 + +@@ -91,7 +93,6 @@ + #define STM32_AUTOSUSPEND_DELAY -1 + + struct stm32_qspi_flash { +- struct stm32_qspi *qspi; + u32 cs; + u32 presc; + }; +@@ -107,6 +108,7 @@ struct stm32_qspi { + u32 clk_rate; + struct stm32_qspi_flash flash[STM32_QSPI_MAX_NORCHIP]; + struct completion data_completion; ++ struct completion match_completion; + u32 fmode; + + struct dma_chan *dma_chtx; +@@ -115,6 +117,7 @@ struct stm32_qspi { + + u32 cr_reg; + u32 dcr_reg; ++ unsigned long status_timeout; + + /* + * to protect device configuration, could be different between +@@ -128,11 +131,20 @@ static irqreturn_t stm32_qspi_irq(int irq, void *dev_id) + struct stm32_qspi *qspi = (struct stm32_qspi *)dev_id; + u32 cr, sr; + ++ cr = readl_relaxed(qspi->io_base + QSPI_CR); + sr = readl_relaxed(qspi->io_base + QSPI_SR); + ++ if (cr & CR_SMIE && sr & SR_SMF) { ++ /* disable irq */ ++ cr &= ~CR_SMIE; ++ writel_relaxed(cr, qspi->io_base + QSPI_CR); ++ complete(&qspi->match_completion); ++ ++ return IRQ_HANDLED; ++ } ++ + if (sr & (SR_TEF | SR_TCF)) { + /* disable irq */ +- cr = readl_relaxed(qspi->io_base + QSPI_CR); + cr &= ~CR_TCIE & ~CR_TEIE; + writel_relaxed(cr, qspi->io_base + QSPI_CR); + complete(&qspi->data_completion); +@@ -269,8 +281,9 @@ static int stm32_qspi_tx(struct stm32_qspi *qspi, const struct spi_mem_op *op) + + if (qspi->fmode == CCR_FMODE_MM) + return stm32_qspi_tx_mm(qspi, op); +- else if ((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || +- (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) ++ else if (((op->data.dir == SPI_MEM_DATA_IN && qspi->dma_chrx) || ++ (op->data.dir == SPI_MEM_DATA_OUT && qspi->dma_chtx)) && ++ op->data.nbytes > 4) + if (!stm32_qspi_tx_dma(qspi, op)) + return 0; + +@@ -321,6 +334,24 @@ static int stm32_qspi_wait_cmd(struct stm32_qspi *qspi, + return err; + } + ++static int stm32_qspi_wait_poll_status(struct stm32_qspi *qspi, ++ const struct spi_mem_op *op) ++{ ++ u32 cr; ++ ++ reinit_completion(&qspi->match_completion); ++ cr = readl_relaxed(qspi->io_base + QSPI_CR); ++ writel_relaxed(cr | CR_SMIE, qspi->io_base + QSPI_CR); ++ ++ if (!wait_for_completion_timeout(&qspi->match_completion, ++ msecs_to_jiffies(qspi->status_timeout))) ++ return -ETIMEDOUT; ++ ++ writel_relaxed(FCR_CSMF, qspi->io_base + QSPI_FCR); ++ ++ return 0; ++} ++ + static int stm32_qspi_get_mode(struct stm32_qspi *qspi, u8 buswidth) + { + if (buswidth == 4) +@@ -333,8 +364,8 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) + { + struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); + struct stm32_qspi_flash *flash = &qspi->flash[mem->spi->chip_select]; +- u32 ccr, cr, addr_max; +- int timeout, err = 0; ++ u32 ccr, cr; ++ int timeout, err = 0, err_poll_status = 0; + + dev_dbg(qspi->dev, "cmd:%#x mode:%d.%d.%d.%d addr:%#llx len:%#x\n", + op->cmd.opcode, op->cmd.buswidth, op->addr.buswidth, +@@ -345,18 +376,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) + if (err) + goto abort; + +- addr_max = op->addr.val + op->data.nbytes + 1; +- +- if (op->data.dir == SPI_MEM_DATA_IN) { +- if (addr_max < qspi->mm_size && +- op->addr.buswidth) +- qspi->fmode = CCR_FMODE_MM; +- else +- qspi->fmode = CCR_FMODE_INDR; +- } else { +- qspi->fmode = CCR_FMODE_INDW; +- } +- + cr = readl_relaxed(qspi->io_base + QSPI_CR); + cr &= ~CR_PRESC_MASK & ~CR_FSEL; + cr |= FIELD_PREP(CR_PRESC_MASK, flash->presc); +@@ -366,8 +385,6 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) + if (op->data.nbytes) + writel_relaxed(op->data.nbytes - 1, + qspi->io_base + QSPI_DLR); +- else +- qspi->fmode = CCR_FMODE_INDW; + + ccr = qspi->fmode; + ccr |= FIELD_PREP(CCR_INST_MASK, op->cmd.opcode); +@@ -394,6 +411,9 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) + if (op->addr.nbytes && qspi->fmode != CCR_FMODE_MM) + writel_relaxed(op->addr.val, qspi->io_base + QSPI_AR); + ++ if (qspi->fmode == CCR_FMODE_APM) ++ err_poll_status = stm32_qspi_wait_poll_status(qspi, op); ++ + err = stm32_qspi_tx(qspi, op); + + /* +@@ -403,7 +423,7 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) + * byte of device (device size - fifo size). like device size is not + * knows, the prefetching is always stop. + */ +- if (err || qspi->fmode == CCR_FMODE_MM) ++ if (err || err_poll_status || qspi->fmode == CCR_FMODE_MM) + goto abort; + + /* wait end of tx in indirect mode */ +@@ -422,15 +442,49 @@ static int stm32_qspi_send(struct spi_mem *mem, const struct spi_mem_op *op) + cr, !(cr & CR_ABORT), 1, + STM32_ABT_TIMEOUT_US); + +- writel_relaxed(FCR_CTCF, qspi->io_base + QSPI_FCR); ++ writel_relaxed(FCR_CTCF | FCR_CSMF, qspi->io_base + QSPI_FCR); + +- if (err || timeout) +- dev_err(qspi->dev, "%s err:%d abort timeout:%d\n", +- __func__, err, timeout); ++ if (err || err_poll_status || timeout) ++ dev_err(qspi->dev, "%s err:%d err_poll_status:%d abort timeout:%d\n", ++ __func__, err, err_poll_status, timeout); + + return err; + } + ++static int stm32_qspi_poll_status(struct spi_mem *mem, const struct spi_mem_op *op, ++ u16 mask, u16 match, ++ unsigned long initial_delay_us, ++ unsigned long polling_rate_us, ++ unsigned long timeout_ms) ++{ ++ struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); ++ int ret; ++ ++ if (!spi_mem_supports_op(mem, op)) ++ return -EOPNOTSUPP; ++ ++ ret = pm_runtime_get_sync(qspi->dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(qspi->dev); ++ return ret; ++ } ++ ++ mutex_lock(&qspi->lock); ++ ++ writel_relaxed(mask, qspi->io_base + QSPI_PSMKR); ++ writel_relaxed(match, qspi->io_base + QSPI_PSMAR); ++ qspi->fmode = CCR_FMODE_APM; ++ qspi->status_timeout = timeout_ms; ++ ++ ret = stm32_qspi_send(mem, op); ++ mutex_unlock(&qspi->lock); ++ ++ pm_runtime_mark_last_busy(qspi->dev); ++ pm_runtime_put_autosuspend(qspi->dev); ++ ++ return ret; ++} ++ + static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + { + struct stm32_qspi *qspi = spi_controller_get_devdata(mem->spi->master); +@@ -443,6 +497,11 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + } + + mutex_lock(&qspi->lock); ++ if (op->data.dir == SPI_MEM_DATA_IN && op->data.nbytes) ++ qspi->fmode = CCR_FMODE_INDR; ++ else ++ qspi->fmode = CCR_FMODE_INDW; ++ + ret = stm32_qspi_send(mem, op); + mutex_unlock(&qspi->lock); + +@@ -452,6 +511,64 @@ static int stm32_qspi_exec_op(struct spi_mem *mem, const struct spi_mem_op *op) + return ret; + } + ++static int stm32_qspi_dirmap_create(struct spi_mem_dirmap_desc *desc) ++{ ++ struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); ++ ++ if (desc->info.op_tmpl.data.dir == SPI_MEM_DATA_OUT) ++ return -EOPNOTSUPP; ++ ++ /* should never happen, as mm_base == null is an error probe exit condition */ ++ if (!qspi->mm_base && desc->info.op_tmpl.data.dir == SPI_MEM_DATA_IN) ++ return -EOPNOTSUPP; ++ ++ if (!qspi->mm_size) ++ return -EOPNOTSUPP; ++ ++ return 0; ++} ++ ++static ssize_t stm32_qspi_dirmap_read(struct spi_mem_dirmap_desc *desc, ++ u64 offs, size_t len, void *buf) ++{ ++ struct stm32_qspi *qspi = spi_controller_get_devdata(desc->mem->spi->master); ++ struct spi_mem_op op; ++ u32 addr_max; ++ int ret; ++ ++ ret = pm_runtime_get_sync(qspi->dev); ++ if (ret < 0) { ++ pm_runtime_put_noidle(qspi->dev); ++ return ret; ++ } ++ ++ mutex_lock(&qspi->lock); ++ /* make a local copy of desc op_tmpl and complete dirmap rdesc ++ * spi_mem_op template with offs, len and *buf in order to get ++ * all needed transfer information into struct spi_mem_op ++ */ ++ memcpy(&op, &desc->info.op_tmpl, sizeof(struct spi_mem_op)); ++ dev_dbg(qspi->dev, "%s len = 0x%x offs = 0x%llx buf = 0x%p\n", __func__, len, offs, buf); ++ ++ op.data.nbytes = len; ++ op.addr.val = desc->info.offset + offs; ++ op.data.buf.in = buf; ++ ++ addr_max = op.addr.val + op.data.nbytes + 1; ++ if (addr_max < qspi->mm_size && op.addr.buswidth) ++ qspi->fmode = CCR_FMODE_MM; ++ else ++ qspi->fmode = CCR_FMODE_INDR; ++ ++ ret = stm32_qspi_send(desc->mem, &op); ++ mutex_unlock(&qspi->lock); ++ ++ pm_runtime_mark_last_busy(qspi->dev); ++ pm_runtime_put_autosuspend(qspi->dev); ++ ++ return ret ?: len; ++} ++ + static int stm32_qspi_setup(struct spi_device *spi) + { + struct spi_controller *ctrl = spi->master; +@@ -475,12 +592,11 @@ static int stm32_qspi_setup(struct spi_device *spi) + presc = DIV_ROUND_UP(qspi->clk_rate, spi->max_speed_hz) - 1; + + flash = &qspi->flash[spi->chip_select]; +- flash->qspi = qspi; + flash->cs = spi->chip_select; + flash->presc = presc; + + mutex_lock(&qspi->lock); +- qspi->cr_reg = 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; ++ qspi->cr_reg = CR_APMS | 3 << CR_FTHRES_SHIFT | CR_SSHIFT | CR_EN; + writel_relaxed(qspi->cr_reg, qspi->io_base + QSPI_CR); + + /* set dcr fsize to max address */ +@@ -557,7 +673,10 @@ static void stm32_qspi_dma_free(struct stm32_qspi *qspi) + * to check supported mode. + */ + static const struct spi_controller_mem_ops stm32_qspi_mem_ops = { +- .exec_op = stm32_qspi_exec_op, ++ .exec_op = stm32_qspi_exec_op, ++ .dirmap_create = stm32_qspi_dirmap_create, ++ .dirmap_read = stm32_qspi_dirmap_read, ++ .poll_status = stm32_qspi_poll_status, + }; + + static int stm32_qspi_probe(struct platform_device *pdev) +@@ -612,6 +731,7 @@ static int stm32_qspi_probe(struct platform_device *pdev) + } + + init_completion(&qspi->data_completion); ++ init_completion(&qspi->match_completion); + + qspi->clk = devm_clk_get(dev, NULL); + if (IS_ERR(qspi->clk)) { +diff --git a/drivers/spi/spi-stm32.c b/drivers/spi/spi-stm32.c +index a6dfc8fef..c42c0ae92 100644 +--- a/drivers/spi/spi-stm32.c ++++ b/drivers/spi/spi-stm32.c +@@ -5,6 +5,7 @@ + // Copyright (C) 2017, STMicroelectronics - All Rights Reserved + // Author(s): Amelie Delaunay for STMicroelectronics. + ++#include + #include + #include + #include +@@ -31,8 +32,8 @@ + #define STM32F4_SPI_CR1_CPHA BIT(0) + #define STM32F4_SPI_CR1_CPOL BIT(1) + #define STM32F4_SPI_CR1_MSTR BIT(2) +-#define STM32F4_SPI_CR1_BR_SHIFT 3 + #define STM32F4_SPI_CR1_BR GENMASK(5, 3) ++#define STM32F4_SPI_CR1_BR_SHIFT 3 + #define STM32F4_SPI_CR1_SPE BIT(6) + #define STM32F4_SPI_CR1_LSBFRST BIT(7) + #define STM32F4_SPI_CR1_SSI BIT(8) +@@ -94,27 +95,22 @@ + #define STM32H7_SPI_CR1_SSI BIT(12) + + /* STM32H7_SPI_CR2 bit fields */ +-#define STM32H7_SPI_CR2_TSIZE_SHIFT 0 + #define STM32H7_SPI_CR2_TSIZE GENMASK(15, 0) ++#define STM32H7_SPI_TSIZE_MAX GENMASK(15, 0) + + /* STM32H7_SPI_CFG1 bit fields */ +-#define STM32H7_SPI_CFG1_DSIZE_SHIFT 0 + #define STM32H7_SPI_CFG1_DSIZE GENMASK(4, 0) +-#define STM32H7_SPI_CFG1_FTHLV_SHIFT 5 + #define STM32H7_SPI_CFG1_FTHLV GENMASK(8, 5) + #define STM32H7_SPI_CFG1_RXDMAEN BIT(14) + #define STM32H7_SPI_CFG1_TXDMAEN BIT(15) +-#define STM32H7_SPI_CFG1_MBR_SHIFT 28 + #define STM32H7_SPI_CFG1_MBR GENMASK(30, 28) ++#define STM32H7_SPI_CFG1_MBR_SHIFT 28 + #define STM32H7_SPI_CFG1_MBR_MIN 0 + #define STM32H7_SPI_CFG1_MBR_MAX (GENMASK(30, 28) >> 28) + + /* STM32H7_SPI_CFG2 bit fields */ +-#define STM32H7_SPI_CFG2_MIDI_SHIFT 4 + #define STM32H7_SPI_CFG2_MIDI GENMASK(7, 4) +-#define STM32H7_SPI_CFG2_COMM_SHIFT 17 + #define STM32H7_SPI_CFG2_COMM GENMASK(18, 17) +-#define STM32H7_SPI_CFG2_SP_SHIFT 19 + #define STM32H7_SPI_CFG2_SP GENMASK(21, 19) + #define STM32H7_SPI_CFG2_MASTER BIT(22) + #define STM32H7_SPI_CFG2_LSBFRST BIT(23) +@@ -130,17 +126,15 @@ + #define STM32H7_SPI_IER_EOTIE BIT(3) + #define STM32H7_SPI_IER_TXTFIE BIT(4) + #define STM32H7_SPI_IER_OVRIE BIT(6) +-#define STM32H7_SPI_IER_MODFIE BIT(9) + #define STM32H7_SPI_IER_ALL GENMASK(10, 0) + + /* STM32H7_SPI_SR bit fields */ + #define STM32H7_SPI_SR_RXP BIT(0) + #define STM32H7_SPI_SR_TXP BIT(1) + #define STM32H7_SPI_SR_EOT BIT(3) ++#define STM32H7_SPI_SR_TXTF BIT(4) + #define STM32H7_SPI_SR_OVR BIT(6) +-#define STM32H7_SPI_SR_MODF BIT(9) + #define STM32H7_SPI_SR_SUSP BIT(11) +-#define STM32H7_SPI_SR_RXPLVL_SHIFT 13 + #define STM32H7_SPI_SR_RXPLVL GENMASK(14, 13) + #define STM32H7_SPI_SR_RXWNE BIT(15) + +@@ -167,7 +161,7 @@ + #define SPI_3WIRE_TX 3 + #define SPI_3WIRE_RX 4 + +-#define SPI_1HZ_NS 1000000000 ++#define STM32_SPI_AUTOSUSPEND_DELAY 1 /* 1 ms */ + + /* + * use PIO for small transfers, avoiding DMA setup/teardown overhead for drivers +@@ -268,7 +262,6 @@ struct stm32_spi_cfg { + * @base: virtual memory area + * @clk: hw kernel clock feeding the SPI clock generator + * @clk_rate: rate of the hw kernel clock feeding the SPI clock generator +- * @rst: SPI controller reset line + * @lock: prevent I/O concurrent access + * @irq: SPI controller interrupt line + * @fifo_size: size of the embedded fifo in bytes +@@ -294,7 +287,6 @@ struct stm32_spi { + void __iomem *base; + struct clk *clk; + u32 clk_rate; +- struct reset_control *rst; + spinlock_t lock; /* prevent I/O concurrent access */ + int irq; + unsigned int fifo_size; +@@ -417,9 +409,7 @@ static int stm32h7_spi_get_bpw_mask(struct stm32_spi *spi) + stm32_spi_set_bits(spi, STM32H7_SPI_CFG1, STM32H7_SPI_CFG1_DSIZE); + + cfg1 = readl_relaxed(spi->base + STM32H7_SPI_CFG1); +- max_bpw = (cfg1 & STM32H7_SPI_CFG1_DSIZE) >> +- STM32H7_SPI_CFG1_DSIZE_SHIFT; +- max_bpw += 1; ++ max_bpw = FIELD_GET(STM32H7_SPI_CFG1_DSIZE, cfg1) + 1; + + spin_unlock_irqrestore(&spi->lock, flags); + +@@ -599,30 +589,30 @@ static void stm32f4_spi_read_rx(struct stm32_spi *spi) + /** + * stm32h7_spi_read_rxfifo - Read bytes in Receive Data Register + * @spi: pointer to the spi controller data structure +- * @flush: boolean indicating that FIFO should be flushed + * + * Write in rx_buf depends on remaining bytes to avoid to write beyond + * rx_buf end. + */ +-static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) ++static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi) + { + u32 sr = readl_relaxed(spi->base + STM32H7_SPI_SR); +- u32 rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> +- STM32H7_SPI_SR_RXPLVL_SHIFT; ++ u32 rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); + + while ((spi->rx_len > 0) && + ((sr & STM32H7_SPI_SR_RXP) || +- (flush && ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { ++ ((sr & STM32H7_SPI_SR_EOT) && ++ ((sr & STM32H7_SPI_SR_RXWNE) || (rxplvl > 0))))) { + u32 offs = spi->cur_xferlen - spi->rx_len; + + if ((spi->rx_len >= sizeof(u32)) || +- (flush && (sr & STM32H7_SPI_SR_RXWNE))) { ++ (sr & STM32H7_SPI_SR_RXWNE)) { + u32 *rx_buf32 = (u32 *)(spi->rx_buf + offs); + + *rx_buf32 = readl_relaxed(spi->base + STM32H7_SPI_RXDR); + spi->rx_len -= sizeof(u32); + } else if ((spi->rx_len >= sizeof(u16)) || +- (flush && (rxplvl >= 2 || spi->cur_bpw > 8))) { ++ (!(sr & STM32H7_SPI_SR_RXWNE) && ++ (rxplvl >= 2 || spi->cur_bpw > 8))) { + u16 *rx_buf16 = (u16 *)(spi->rx_buf + offs); + + *rx_buf16 = readw_relaxed(spi->base + STM32H7_SPI_RXDR); +@@ -635,12 +625,11 @@ static void stm32h7_spi_read_rxfifo(struct stm32_spi *spi, bool flush) + } + + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); +- rxplvl = (sr & STM32H7_SPI_SR_RXPLVL) >> +- STM32H7_SPI_SR_RXPLVL_SHIFT; ++ rxplvl = FIELD_GET(STM32H7_SPI_SR_RXPLVL, sr); + } + +- dev_dbg(spi->dev, "%s%s: %d bytes left\n", __func__, +- flush ? "(flush)" : "", spi->rx_len); ++ dev_dbg(spi->dev, "%s: %d bytes left (sr=%08x)\n", ++ __func__, spi->rx_len, sr); + } + + /** +@@ -707,18 +696,12 @@ static void stm32f4_spi_disable(struct stm32_spi *spi) + * stm32h7_spi_disable - Disable SPI controller + * @spi: pointer to the spi controller data structure + * +- * RX-Fifo is flushed when SPI controller is disabled. To prevent any data +- * loss, use stm32h7_spi_read_rxfifo(flush) to read the remaining bytes in +- * RX-Fifo. +- * Normally, if TSIZE has been configured, we should relax the hardware at the +- * reception of the EOT interrupt. But in case of error, EOT will not be +- * raised. So the subsystem unprepare_message call allows us to properly +- * complete the transfer from an hardware point of view. ++ * RX-Fifo is flushed when SPI controller is disabled. + */ + static void stm32h7_spi_disable(struct stm32_spi *spi) + { + unsigned long flags; +- u32 cr1, sr; ++ u32 cr1; + + dev_dbg(spi->dev, "disable controller\n"); + +@@ -731,25 +714,6 @@ static void stm32h7_spi_disable(struct stm32_spi *spi) + return; + } + +- /* Wait on EOT or suspend the flow */ +- if (readl_relaxed_poll_timeout_atomic(spi->base + STM32H7_SPI_SR, +- sr, !(sr & STM32H7_SPI_SR_EOT), +- 10, 100000) < 0) { +- if (cr1 & STM32H7_SPI_CR1_CSTART) { +- writel_relaxed(cr1 | STM32H7_SPI_CR1_CSUSP, +- spi->base + STM32H7_SPI_CR1); +- if (readl_relaxed_poll_timeout_atomic( +- spi->base + STM32H7_SPI_SR, +- sr, !(sr & STM32H7_SPI_SR_SUSP), +- 10, 100000) < 0) +- dev_warn(spi->dev, +- "Suspend request timeout\n"); +- } +- } +- +- if (!spi->cur_usedma && spi->rx_buf && (spi->rx_len > 0)) +- stm32h7_spi_read_rxfifo(spi, true); +- + if (spi->cur_usedma && spi->dma_tx) + dmaengine_terminate_all(spi->dma_tx); + if (spi->cur_usedma && spi->dma_rx) +@@ -907,7 +871,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) + { + struct spi_master *master = dev_id; + struct stm32_spi *spi = spi_master_get_devdata(master); +- u32 sr, ier, mask; ++ u32 sr, ier, mask, ifcr; + unsigned long flags; + bool end = false; + +@@ -915,6 +879,7 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) + + sr = readl_relaxed(spi->base + STM32H7_SPI_SR); + ier = readl_relaxed(spi->base + STM32H7_SPI_IER); ++ ifcr = 0; + + mask = ier; + /* +@@ -927,57 +892,63 @@ static irqreturn_t stm32h7_spi_irq_thread(int irq, void *dev_id) + * DXPIE is set in Full-Duplex, one IT will be raised if TXP and RXP + * are set. So in case of Full-Duplex, need to poll TXP and RXP event. + */ +- if ((spi->cur_comm == SPI_FULL_DUPLEX) && !spi->cur_usedma) ++ if ((spi->cur_comm == SPI_FULL_DUPLEX) && (!spi->cur_usedma)) + mask |= STM32H7_SPI_SR_TXP | STM32H7_SPI_SR_RXP; + +- if (!(sr & mask)) { ++ mask &= sr; ++ ++ if (!mask) { + dev_warn(spi->dev, "spurious IT (sr=0x%08x, ier=0x%08x)\n", + sr, ier); + spin_unlock_irqrestore(&spi->lock, flags); + return IRQ_NONE; + } + +- if (sr & STM32H7_SPI_SR_SUSP) { ++ if (mask & STM32H7_SPI_SR_SUSP) { + static DEFINE_RATELIMIT_STATE(rs, + DEFAULT_RATELIMIT_INTERVAL * 10, + 1); + if (__ratelimit(&rs)) + dev_dbg_ratelimited(spi->dev, "Communication suspended\n"); + if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, false); ++ stm32h7_spi_read_rxfifo(spi); + /* + * If communication is suspended while using DMA, it means + * that something went wrong, so stop the current transfer + */ + if (spi->cur_usedma) + end = true; ++ ifcr |= STM32H7_SPI_SR_SUSP; + } + +- if (sr & STM32H7_SPI_SR_MODF) { +- dev_warn(spi->dev, "Mode fault: transfer aborted\n"); +- end = true; +- } +- +- if (sr & STM32H7_SPI_SR_OVR) { ++ if (mask & STM32H7_SPI_SR_OVR) { + dev_err(spi->dev, "Overrun: RX data lost\n"); + end = true; ++ ifcr |= STM32H7_SPI_SR_OVR; + } + +- if (sr & STM32H7_SPI_SR_EOT) { ++ if (mask & STM32H7_SPI_SR_TXTF) ++ ifcr |= STM32H7_SPI_SR_TXTF; ++ ++ if (mask & STM32H7_SPI_SR_EOT) { + if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, true); +- end = true; ++ stm32h7_spi_read_rxfifo(spi); ++ ifcr |= STM32H7_SPI_SR_EOT; ++ if (!spi->cur_usedma || ++ (spi->cur_usedma && (spi->cur_comm == SPI_SIMPLEX_TX || ++ spi->cur_comm == SPI_3WIRE_TX))) ++ end = true; + } + +- if (sr & STM32H7_SPI_SR_TXP) ++ if (mask & STM32H7_SPI_SR_TXP) + if (!spi->cur_usedma && (spi->tx_buf && (spi->tx_len > 0))) + stm32h7_spi_write_txfifo(spi); + +- if (sr & STM32H7_SPI_SR_RXP) ++ if (mask & STM32H7_SPI_SR_RXP) + if (!spi->cur_usedma && (spi->rx_buf && (spi->rx_len > 0))) +- stm32h7_spi_read_rxfifo(spi, false); ++ stm32h7_spi_read_rxfifo(spi); + +- writel_relaxed(sr & mask, spi->base + STM32H7_SPI_IFCR); ++ writel_relaxed(ifcr, spi->base + STM32H7_SPI_IFCR); + + spin_unlock_irqrestore(&spi->lock, flags); + +@@ -1029,6 +1000,20 @@ static int stm32_spi_prepare_msg(struct spi_master *master, + spi_dev->mode & SPI_LSB_FIRST, + spi_dev->mode & SPI_CS_HIGH); + ++ /* On STM32H7, messages should not exceed a maximum size setted ++ * afterward via the set_number_of_data function. In order to ++ * ensure that, split large messages into several messages ++ */ ++ if (spi->cfg->set_number_of_data) { ++ int ret; ++ ++ ret = spi_split_transfers_maxsize(master, msg, ++ STM32H7_SPI_TSIZE_MAX, ++ GFP_KERNEL | GFP_DMA); ++ if (ret) ++ return ret; ++ } ++ + spin_lock_irqsave(&spi->lock, flags); + + /* CPOL, CPHA and LSB FIRST bits have common register */ +@@ -1060,42 +1045,17 @@ static void stm32f4_spi_dma_tx_cb(void *data) + } + + /** +- * stm32f4_spi_dma_rx_cb - dma callback ++ * stm32_spi_dma_rx_cb - dma callback + * @data: pointer to the spi controller data structure + * + * DMA callback is called when the transfer is complete for DMA RX channel. + */ +-static void stm32f4_spi_dma_rx_cb(void *data) ++static void stm32_spi_dma_rx_cb(void *data) + { + struct stm32_spi *spi = data; + + spi_finalize_current_transfer(spi->master); +- stm32f4_spi_disable(spi); +-} +- +-/** +- * stm32h7_spi_dma_cb - dma callback +- * @data: pointer to the spi controller data structure +- * +- * DMA callback is called when the transfer is complete or when an error +- * occurs. If the transfer is complete, EOT flag is raised. +- */ +-static void stm32h7_spi_dma_cb(void *data) +-{ +- struct stm32_spi *spi = data; +- unsigned long flags; +- u32 sr; +- +- spin_lock_irqsave(&spi->lock, flags); +- +- sr = readl_relaxed(spi->base + STM32H7_SPI_SR); +- +- spin_unlock_irqrestore(&spi->lock, flags); +- +- if (!(sr & STM32H7_SPI_SR_EOT)) +- dev_warn(spi->dev, "DMA error (sr=0x%08x)\n", sr); +- +- /* Now wait for EOT, or SUSP or OVR in case of error */ ++ spi->cfg->disable(spi); + } + + /** +@@ -1214,7 +1174,7 @@ static int stm32h7_spi_transfer_one_irq(struct stm32_spi *spi) + + /* Enable the interrupts relative to the end of transfer */ + ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE | +- STM32H7_SPI_IER_OVRIE | STM32H7_SPI_IER_MODFIE; ++ STM32H7_SPI_IER_OVRIE; + + spin_lock_irqsave(&spi->lock, flags); + +@@ -1261,11 +1221,13 @@ static void stm32f4_spi_transfer_one_dma_start(struct stm32_spi *spi) + */ + static void stm32h7_spi_transfer_one_dma_start(struct stm32_spi *spi) + { +- /* Enable the interrupts relative to the end of transfer */ +- stm32_spi_set_bits(spi, STM32H7_SPI_IER, STM32H7_SPI_IER_EOTIE | +- STM32H7_SPI_IER_TXTFIE | +- STM32H7_SPI_IER_OVRIE | +- STM32H7_SPI_IER_MODFIE); ++ uint32_t ier = STM32H7_SPI_IER_OVRIE; ++ ++ /* Enable the interrupts */ ++ if (spi->cur_comm == SPI_SIMPLEX_TX || spi->cur_comm == SPI_3WIRE_TX) ++ ier |= STM32H7_SPI_IER_EOTIE | STM32H7_SPI_IER_TXTFIE; ++ ++ stm32_spi_set_bits(spi, STM32H7_SPI_IER, ier); + + stm32_spi_enable(spi); + +@@ -1401,15 +1363,13 @@ static void stm32h7_spi_set_bpw(struct stm32_spi *spi) + bpw = spi->cur_bpw - 1; + + cfg1_clrb |= STM32H7_SPI_CFG1_DSIZE; +- cfg1_setb |= (bpw << STM32H7_SPI_CFG1_DSIZE_SHIFT) & +- STM32H7_SPI_CFG1_DSIZE; ++ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_DSIZE, bpw); + + spi->cur_fthlv = stm32h7_spi_prepare_fthlv(spi, spi->cur_xferlen); + fthlv = spi->cur_fthlv - 1; + + cfg1_clrb |= STM32H7_SPI_CFG1_FTHLV; +- cfg1_setb |= (fthlv << STM32H7_SPI_CFG1_FTHLV_SHIFT) & +- STM32H7_SPI_CFG1_FTHLV; ++ cfg1_setb |= FIELD_PREP(STM32H7_SPI_CFG1_FTHLV, fthlv); + + writel_relaxed( + (readl_relaxed(spi->base + STM32H7_SPI_CFG1) & +@@ -1427,8 +1387,7 @@ static void stm32_spi_set_mbr(struct stm32_spi *spi, u32 mbrdiv) + u32 clrb = 0, setb = 0; + + clrb |= spi->cfg->regs->br.mask; +- setb |= ((u32)mbrdiv << spi->cfg->regs->br.shift) & +- spi->cfg->regs->br.mask; ++ setb |= (mbrdiv << spi->cfg->regs->br.shift) & spi->cfg->regs->br.mask; + + writel_relaxed((readl_relaxed(spi->base + spi->cfg->regs->br.reg) & + ~clrb) | setb, +@@ -1519,8 +1478,7 @@ static int stm32h7_spi_set_mode(struct stm32_spi *spi, unsigned int comm_type) + } + + cfg2_clrb |= STM32H7_SPI_CFG2_COMM; +- cfg2_setb |= (mode << STM32H7_SPI_CFG2_COMM_SHIFT) & +- STM32H7_SPI_CFG2_COMM; ++ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_COMM, mode); + + writel_relaxed( + (readl_relaxed(spi->base + STM32H7_SPI_CFG2) & +@@ -1542,15 +1500,16 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) + + cfg2_clrb |= STM32H7_SPI_CFG2_MIDI; + if ((len > 1) && (spi->cur_midi > 0)) { +- u32 sck_period_ns = DIV_ROUND_UP(SPI_1HZ_NS, spi->cur_speed); +- u32 midi = min((u32)DIV_ROUND_UP(spi->cur_midi, sck_period_ns), +- (u32)STM32H7_SPI_CFG2_MIDI >> +- STM32H7_SPI_CFG2_MIDI_SHIFT); ++ u32 sck_period_ns = DIV_ROUND_UP(NSEC_PER_SEC, spi->cur_speed); ++ u32 midi = min_t(u32, ++ DIV_ROUND_UP(spi->cur_midi, sck_period_ns), ++ FIELD_GET(STM32H7_SPI_CFG2_MIDI, ++ STM32H7_SPI_CFG2_MIDI)); ++ + + dev_dbg(spi->dev, "period=%dns, midi=%d(=%dns)\n", + sck_period_ns, midi, midi * sck_period_ns); +- cfg2_setb |= (midi << STM32H7_SPI_CFG2_MIDI_SHIFT) & +- STM32H7_SPI_CFG2_MIDI; ++ cfg2_setb |= FIELD_PREP(STM32H7_SPI_CFG2_MIDI, midi); + } + + writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CFG2) & +@@ -1565,14 +1524,8 @@ static void stm32h7_spi_data_idleness(struct stm32_spi *spi, u32 len) + */ + static int stm32h7_spi_number_of_data(struct stm32_spi *spi, u32 nb_words) + { +- u32 cr2_clrb = 0, cr2_setb = 0; +- +- if (nb_words <= (STM32H7_SPI_CR2_TSIZE >> +- STM32H7_SPI_CR2_TSIZE_SHIFT)) { +- cr2_clrb |= STM32H7_SPI_CR2_TSIZE; +- cr2_setb = nb_words << STM32H7_SPI_CR2_TSIZE_SHIFT; +- writel_relaxed((readl_relaxed(spi->base + STM32H7_SPI_CR2) & +- ~cr2_clrb) | cr2_setb, ++ if (nb_words <= STM32H7_SPI_TSIZE_MAX) { ++ writel_relaxed(FIELD_PREP(STM32H7_SPI_CR2_TSIZE, nb_words), + spi->base + STM32H7_SPI_CR2); + } else { + return -EMSGSIZE; +@@ -1673,10 +1626,6 @@ static int stm32_spi_transfer_one(struct spi_master *master, + struct stm32_spi *spi = spi_master_get_devdata(master); + int ret; + +- /* Don't do anything on 0 bytes transfers */ +- if (transfer->len == 0) +- return 0; +- + spi->tx_buf = transfer->tx_buf; + spi->rx_buf = transfer->rx_buf; + spi->tx_len = spi->tx_buf ? transfer->len : 0; +@@ -1790,7 +1739,7 @@ static const struct stm32_spi_cfg stm32f4_spi_cfg = { + .set_mode = stm32f4_spi_set_mode, + .transfer_one_dma_start = stm32f4_spi_transfer_one_dma_start, + .dma_tx_cb = stm32f4_spi_dma_tx_cb, +- .dma_rx_cb = stm32f4_spi_dma_rx_cb, ++ .dma_rx_cb = stm32_spi_dma_rx_cb, + .transfer_one_irq = stm32f4_spi_transfer_one_irq, + .irq_handler_event = stm32f4_spi_irq_event, + .irq_handler_thread = stm32f4_spi_irq_thread, +@@ -1810,8 +1759,11 @@ static const struct stm32_spi_cfg stm32h7_spi_cfg = { + .set_data_idleness = stm32h7_spi_data_idleness, + .set_number_of_data = stm32h7_spi_number_of_data, + .transfer_one_dma_start = stm32h7_spi_transfer_one_dma_start, +- .dma_rx_cb = stm32h7_spi_dma_cb, +- .dma_tx_cb = stm32h7_spi_dma_cb, ++ .dma_rx_cb = stm32_spi_dma_rx_cb, ++ /* ++ * dma_tx_cb is not necessary since in case of TX, dma is followed by ++ * SPI access hence handling is performed within the SPI interrupt ++ */ + .transfer_one_irq = stm32h7_spi_transfer_one_irq, + .irq_handler_thread = stm32h7_spi_irq_thread, + .baud_rate_div_min = STM32H7_SPI_MBR_DIV_MIN, +@@ -1831,6 +1783,7 @@ static int stm32_spi_probe(struct platform_device *pdev) + struct spi_master *master; + struct stm32_spi *spi; + struct resource *res; ++ struct reset_control *rst; + int ret; + + master = devm_spi_alloc_master(&pdev->dev, sizeof(struct stm32_spi)); +@@ -1890,11 +1843,19 @@ static int stm32_spi_probe(struct platform_device *pdev) + goto err_clk_disable; + } + +- spi->rst = devm_reset_control_get_exclusive(&pdev->dev, NULL); +- if (!IS_ERR(spi->rst)) { +- reset_control_assert(spi->rst); ++ rst = devm_reset_control_get_optional_exclusive(&pdev->dev, NULL); ++ if (rst) { ++ if (IS_ERR(rst)) { ++ ret = PTR_ERR(rst); ++ if (ret != -EPROBE_DEFER) ++ dev_err(&pdev->dev, "reset get failed: %d\n", ++ ret); ++ goto err_clk_disable; ++ } ++ ++ reset_control_assert(rst); + udelay(2); +- reset_control_deassert(spi->rst); ++ reset_control_deassert(rst); + } + + if (spi->cfg->has_fifo) +@@ -1948,6 +1909,9 @@ static int stm32_spi_probe(struct platform_device *pdev) + if (spi->dma_tx || spi->dma_rx) + master->can_dma = stm32_spi_can_dma; + ++ pm_runtime_set_autosuspend_delay(&pdev->dev, ++ STM32_SPI_AUTOSUSPEND_DELAY); ++ pm_runtime_use_autosuspend(&pdev->dev); + pm_runtime_set_active(&pdev->dev); + pm_runtime_get_noresume(&pdev->dev); + pm_runtime_enable(&pdev->dev); +@@ -1959,11 +1923,8 @@ static int stm32_spi_probe(struct platform_device *pdev) + goto err_pm_disable; + } + +- if (!master->cs_gpiods) { +- dev_err(&pdev->dev, "no CS gpios available\n"); +- ret = -EINVAL; +- goto err_pm_disable; +- } ++ pm_runtime_mark_last_busy(&pdev->dev); ++ pm_runtime_put_autosuspend(&pdev->dev); + + dev_info(&pdev->dev, "driver initialized\n"); + +@@ -1973,6 +1934,7 @@ static int stm32_spi_probe(struct platform_device *pdev) + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(&pdev->dev); + err_dma_release: + if (spi->dma_tx) + dma_release_channel(spi->dma_tx); +@@ -1997,6 +1959,8 @@ static int stm32_spi_remove(struct platform_device *pdev) + pm_runtime_disable(&pdev->dev); + pm_runtime_put_noidle(&pdev->dev); + pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_dont_use_autosuspend(&pdev->dev); ++ + if (master->dma_tx) + dma_release_channel(master->dma_tx); + if (master->dma_rx) +@@ -2004,14 +1968,12 @@ static int stm32_spi_remove(struct platform_device *pdev) + + clk_disable_unprepare(spi->clk); + +- + pinctrl_pm_select_sleep_state(&pdev->dev); + + return 0; + } + +-#ifdef CONFIG_PM +-static int stm32_spi_runtime_suspend(struct device *dev) ++static int __maybe_unused stm32_spi_runtime_suspend(struct device *dev) + { + struct spi_master *master = dev_get_drvdata(dev); + struct stm32_spi *spi = spi_master_get_devdata(master); +@@ -2021,7 +1983,7 @@ static int stm32_spi_runtime_suspend(struct device *dev) + return pinctrl_pm_select_sleep_state(dev); + } + +-static int stm32_spi_runtime_resume(struct device *dev) ++static int __maybe_unused stm32_spi_runtime_resume(struct device *dev) + { + struct spi_master *master = dev_get_drvdata(dev); + struct stm32_spi *spi = spi_master_get_devdata(master); +@@ -2033,10 +1995,8 @@ static int stm32_spi_runtime_resume(struct device *dev) + + return clk_prepare_enable(spi->clk); + } +-#endif + +-#ifdef CONFIG_PM_SLEEP +-static int stm32_spi_suspend(struct device *dev) ++static int __maybe_unused stm32_spi_suspend(struct device *dev) + { + struct spi_master *master = dev_get_drvdata(dev); + int ret; +@@ -2048,7 +2008,7 @@ static int stm32_spi_suspend(struct device *dev) + return pm_runtime_force_suspend(dev); + } + +-static int stm32_spi_resume(struct device *dev) ++static int __maybe_unused stm32_spi_resume(struct device *dev) + { + struct spi_master *master = dev_get_drvdata(dev); + struct stm32_spi *spi = spi_master_get_devdata(master); +@@ -2078,7 +2038,6 @@ static int stm32_spi_resume(struct device *dev) + + return 0; + } +-#endif + + static const struct dev_pm_ops stm32_spi_pm_ops = { + SET_SYSTEM_SLEEP_PM_OPS(stm32_spi_suspend, stm32_spi_resume) +diff --git a/include/dt-bindings/pinctrl/stm32-pinfunc.h b/include/dt-bindings/pinctrl/stm32-pinfunc.h +index e6fb8ada3..370a25a93 100644 +--- a/include/dt-bindings/pinctrl/stm32-pinfunc.h ++++ b/include/dt-bindings/pinctrl/stm32-pinfunc.h +@@ -26,6 +26,7 @@ + #define AF14 0xf + #define AF15 0x10 + #define ANALOG 0x11 ++#define RSVD 0x12 + + /* define Pins number*/ + #define PIN_NO(port, line) (((port) - 'A') * 0x10 + (line)) +diff --git a/include/linux/mtd/spinand.h b/include/linux/mtd/spinand.h +index 7b78c4ba9..74b5db35c 100644 +--- a/include/linux/mtd/spinand.h ++++ b/include/linux/mtd/spinand.h +@@ -170,6 +170,28 @@ struct spinand_op; + struct spinand_device; + + #define SPINAND_MAX_ID_LEN 4 ++/* ++ * For erase, write and read operation, we got the following timings : ++ * tBERS (erase) 1ms to 4ms ++ * tPROG 300us to 400us ++ * tREAD 25us to 100us ++ * In order to minimize latency, the min value is divided by 4 for the ++ * initial delay, and dividing by 20 for the poll delay. ++ * For reset, 5us/10us/500us if the device is respectively ++ * reading/programming/erasing when the RESET occurs. Since we always ++ * issue a RESET when the device is IDLE, 5us is selected for both initial ++ * and poll delay. ++ */ ++#define SPINAND_READ_INITIAL_DELAY_US 6 ++#define SPINAND_READ_POLL_DELAY_US 5 ++#define SPINAND_RESET_INITIAL_DELAY_US 5 ++#define SPINAND_RESET_POLL_DELAY_US 5 ++#define SPINAND_WRITE_INITIAL_DELAY_US 75 ++#define SPINAND_WRITE_POLL_DELAY_US 15 ++#define SPINAND_ERASE_INITIAL_DELAY_US 250 ++#define SPINAND_ERASE_POLL_DELAY_US 50 ++ ++#define SPINAND_WAITRDY_TIMEOUT_MS 400 + + /** + * struct spinand_id - SPI NAND id structure +diff --git a/include/linux/spi/spi-mem.h b/include/linux/spi/spi-mem.h +index 159463cc6..c24fa5c11 100644 +--- a/include/linux/spi/spi-mem.h ++++ b/include/linux/spi/spi-mem.h +@@ -250,6 +250,9 @@ static inline void *spi_mem_get_drvdata(struct spi_mem *mem) + * the currently mapped area), and the caller of + * spi_mem_dirmap_write() is responsible for calling it again in + * this case. ++ * @poll_status: poll memory device status until (status & mask) == match or ++ * when the timeout has expired. It fills the data buffer with ++ * the last status value. + * + * This interface should be implemented by SPI controllers providing an + * high-level interface to execute SPI memory operation, which is usually the +@@ -274,6 +277,12 @@ struct spi_controller_mem_ops { + u64 offs, size_t len, void *buf); + ssize_t (*dirmap_write)(struct spi_mem_dirmap_desc *desc, + u64 offs, size_t len, const void *buf); ++ int (*poll_status)(struct spi_mem *mem, ++ const struct spi_mem_op *op, ++ u16 mask, u16 match, ++ unsigned long initial_delay_us, ++ unsigned long polling_rate_us, ++ unsigned long timeout_ms); + }; + + /** +@@ -360,6 +369,13 @@ devm_spi_mem_dirmap_create(struct device *dev, struct spi_mem *mem, + void devm_spi_mem_dirmap_destroy(struct device *dev, + struct spi_mem_dirmap_desc *desc); + ++int spi_mem_poll_status(struct spi_mem *mem, ++ const struct spi_mem_op *op, ++ u16 mask, u16 match, ++ unsigned long initial_delay_us, ++ unsigned long polling_delay_us, ++ u16 timeout_ms); ++ + int spi_mem_driver_register_with_owner(struct spi_mem_driver *drv, + struct module *owner); + +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0017-ARM-5.10.10-stm32mp1-r1-RESET-RTC-WATCHDOG.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch similarity index 81% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0017-ARM-5.10.10-stm32mp1-r1-RESET-RTC-WATCHDOG.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch index acb6dea..5ed70b8 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0017-ARM-5.10.10-stm32mp1-r1-RESET-RTC-WATCHDOG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch @@ -1,27 +1,26 @@ -From c40d4d83b3de542be7d64b88f0c842ebecc9a6b2 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:09:52 +0100 -Subject: [PATCH 17/22] ARM 5.10.10-stm32mp1-r1 RESET-RTC-WATCHDOG +From 32651dddd362b90d443aa3e6f15b699d0e1ad26c Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:50 +0200 +Subject: [PATCH 17/23] ARM 5.10.61-stm32mp1-r2 RESET-RTC-WATCHDOG -Signed-off-by: Romuald JEANNE --- drivers/reset/Kconfig | 6 - drivers/reset/Makefile | 1 - - drivers/reset/reset-stm32mp1.c | 115 ------------- + drivers/reset/reset-stm32mp1.c | 115 ----------- drivers/rtc/Kconfig | 1 + - drivers/rtc/rtc-stm32.c | 180 ++++++++++++++++---- + drivers/rtc/rtc-stm32.c | 214 +++++++++++++++----- drivers/watchdog/stm32_iwdg.c | 13 +- include/dt-bindings/reset/stm32mp1-resets.h | 15 ++ include/dt-bindings/rtc/rtc-stm32.h | 13 ++ - 8 files changed, 183 insertions(+), 161 deletions(-) + 8 files changed, 202 insertions(+), 176 deletions(-) delete mode 100644 drivers/reset/reset-stm32mp1.c create mode 100644 include/dt-bindings/rtc/rtc-stm32.h diff --git a/drivers/reset/Kconfig b/drivers/reset/Kconfig -index 07d162b179fc..c3186d80c33e 100644 +index 147543ad3..6c1409b38 100644 --- a/drivers/reset/Kconfig +++ b/drivers/reset/Kconfig -@@ -180,12 +180,6 @@ config RESET_SIMPLE +@@ -182,12 +182,6 @@ config RESET_SIMPLE - Allwinner SoCs - ZTE's zx2967 family @@ -35,7 +34,7 @@ index 07d162b179fc..c3186d80c33e 100644 bool "SoCFPGA Reset Driver" if COMPILE_TEST && !ARCH_SOCFPGA default ARCH_SOCFPGA diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile -index 16947610cc3b..b2c9eff41d3b 100644 +index 16947610c..b2c9eff41 100644 --- a/drivers/reset/Makefile +++ b/drivers/reset/Makefile @@ -24,7 +24,6 @@ obj-$(CONFIG_RESET_QCOM_PDC) += reset-qcom-pdc.o @@ -48,7 +47,7 @@ index 16947610cc3b..b2c9eff41d3b 100644 obj-$(CONFIG_RESET_TI_SCI) += reset-ti-sci.o diff --git a/drivers/reset/reset-stm32mp1.c b/drivers/reset/reset-stm32mp1.c deleted file mode 100644 -index b221a28041fa..000000000000 +index b221a2804..000000000 --- a/drivers/reset/reset-stm32mp1.c +++ /dev/null @@ -1,115 +0,0 @@ @@ -168,10 +167,10 @@ index b221a28041fa..000000000000 - -builtin_platform_driver(stm32_reset_driver); diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig -index 65ad9d0b47ab..f2a4d7c633c8 100644 +index 33e4ecd6c..65619e077 100644 --- a/drivers/rtc/Kconfig +++ b/drivers/rtc/Kconfig -@@ -1884,6 +1884,7 @@ config RTC_DRV_R7301 +@@ -1885,6 +1885,7 @@ config RTC_DRV_R7301 config RTC_DRV_STM32 tristate "STM32 RTC" select REGMAP_MMIO @@ -180,7 +179,7 @@ index 65ad9d0b47ab..f2a4d7c633c8 100644 help If you say yes here you get support for the STM32 On-Chip diff --git a/drivers/rtc/rtc-stm32.c b/drivers/rtc/rtc-stm32.c -index d774aa18f57a..7fd6347691bb 100644 +index d096b58cd..ffab177ed 100644 --- a/drivers/rtc/rtc-stm32.c +++ b/drivers/rtc/rtc-stm32.c @@ -6,6 +6,8 @@ @@ -333,7 +332,48 @@ index d774aa18f57a..7fd6347691bb 100644 static void stm32_rtc_wpr_unlock(struct stm32_rtc *rtc) { const struct stm32_rtc_registers *regs = &rtc->data->regs; -@@ -547,7 +642,8 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, +@@ -160,10 +255,9 @@ static int stm32_rtc_enter_init_mode(struct stm32_rtc *rtc) + * slowest rtc_ck frequency may be 32kHz and highest should be + * 1MHz, we poll every 10 us with a timeout of 100ms. + */ +- return readl_relaxed_poll_timeout_atomic( +- rtc->base + regs->isr, +- isr, (isr & STM32_RTC_ISR_INITF), +- 10, 100000); ++ return readl_relaxed_poll_timeout_atomic(rtc->base + regs->isr, isr, ++ (isr & STM32_RTC_ISR_INITF), ++ 10, 100000); + } + + return 0; +@@ -448,16 +542,16 @@ static int stm32_rtc_valid_alrm(struct stm32_rtc *rtc, struct rtc_time *tm) + * M-D-Y H:M:S < alarm <= (M+1)-D-Y H:M:S + * with a specific case for December... + */ +- if ((((tm->tm_year > cur_year) && +- (tm->tm_mon == 0x1) && (cur_mon == 0x12)) || +- ((tm->tm_year == cur_year) && +- (tm->tm_mon <= cur_mon + 1))) && +- ((tm->tm_mday > cur_day) || +- ((tm->tm_mday == cur_day) && +- ((tm->tm_hour > cur_hour) || +- ((tm->tm_hour == cur_hour) && (tm->tm_min > cur_min)) || +- ((tm->tm_hour == cur_hour) && (tm->tm_min == cur_min) && +- (tm->tm_sec >= cur_sec)))))) ++ if (((tm->tm_year > cur_year && ++ tm->tm_mon == 0x1 && cur_mon == 0x12) || ++ (tm->tm_year == cur_year && ++ tm->tm_mon <= cur_mon + 1)) && ++ (tm->tm_mday > cur_day || ++ (tm->tm_mday == cur_day && ++ (tm->tm_hour > cur_hour || ++ (tm->tm_hour == cur_hour && tm->tm_min > cur_min) || ++ (tm->tm_hour == cur_hour && tm->tm_min == cur_min && ++ tm->tm_sec >= cur_sec))))) + return 0; + + return -EINVAL; +@@ -547,7 +641,8 @@ static void stm32_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32_rtc_data = { .has_pclk = false, .need_dbp = true, @@ -343,7 +383,7 @@ index d774aa18f57a..7fd6347691bb 100644 .regs = { .tr = 0x00, .dr = 0x04, -@@ -558,6 +654,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { +@@ -558,6 +653,7 @@ static const struct stm32_rtc_data stm32_rtc_data = { .wpr = 0x24, .sr = 0x0C, /* set to ISR offset to ease alarm management */ .scr = UNDEF_REG, @@ -351,7 +391,7 @@ index d774aa18f57a..7fd6347691bb 100644 .verr = UNDEF_REG, }, .events = { -@@ -569,7 +666,8 @@ static const struct stm32_rtc_data stm32_rtc_data = { +@@ -569,7 +665,8 @@ static const struct stm32_rtc_data stm32_rtc_data = { static const struct stm32_rtc_data stm32h7_rtc_data = { .has_pclk = true, .need_dbp = true, @@ -361,7 +401,7 @@ index d774aa18f57a..7fd6347691bb 100644 .regs = { .tr = 0x00, .dr = 0x04, -@@ -580,6 +678,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { +@@ -580,6 +677,7 @@ static const struct stm32_rtc_data stm32h7_rtc_data = { .wpr = 0x24, .sr = 0x0C, /* set to ISR offset to ease alarm management */ .scr = UNDEF_REG, @@ -369,7 +409,7 @@ index d774aa18f57a..7fd6347691bb 100644 .verr = UNDEF_REG, }, .events = { -@@ -600,7 +699,8 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, +@@ -600,7 +698,8 @@ static void stm32mp1_rtc_clear_events(struct stm32_rtc *rtc, static const struct stm32_rtc_data stm32mp1_data = { .has_pclk = true, .need_dbp = false, @@ -379,7 +419,7 @@ index d774aa18f57a..7fd6347691bb 100644 .regs = { .tr = 0x00, .dr = 0x04, -@@ -611,6 +711,7 @@ static const struct stm32_rtc_data stm32mp1_data = { +@@ -611,6 +710,7 @@ static const struct stm32_rtc_data stm32mp1_data = { .wpr = 0x24, .sr = 0x50, .scr = 0x5C, @@ -387,32 +427,45 @@ index d774aa18f57a..7fd6347691bb 100644 .verr = 0x3F4, }, .events = { -@@ -641,11 +742,20 @@ static int stm32_rtc_init(struct platform_device *pdev, +@@ -641,18 +741,32 @@ static int stm32_rtc_init(struct platform_device *pdev, pred_a_max = STM32_RTC_PRER_PRED_A >> STM32_RTC_PRER_PRED_A_SHIFT; pred_s_max = STM32_RTC_PRER_PRED_S >> STM32_RTC_PRER_PRED_S_SHIFT; - for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { - pred_s = (rate / (pred_a + 1)) - 1; ++ if (rate > (pred_a_max + 1) * (pred_s_max + 1)) { ++ dev_err(&pdev->dev, "rtc_ck rate is too high: %dHz\n", rate); ++ return -EINVAL; ++ } ++ + if (rtc->data->need_accuracy) { + for (pred_a = 0; pred_a <= pred_a_max; pred_a++) { + pred_s = (rate / (pred_a + 1)) - 1; -+ -+ if (((pred_s + 1) * (pred_a + 1)) == rate) + +- if (((pred_s + 1) * (pred_a + 1)) == rate) +- break; ++ if (pred_s <= pred_s_max && ((pred_s + 1) * (pred_a + 1)) == rate) + break; + } + } else { + for (pred_a = pred_a_max; pred_a + 1 > 0; pred_a--) { + pred_s = (rate / (pred_a + 1)) - 1; - -- if (((pred_s + 1) * (pred_a + 1)) == rate) -- break; ++ + if (((pred_s + 1) * (pred_a + 1)) == rate) + break; + } } /* -@@ -736,13 +846,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) + * Can't find a 1Hz, so give priority to RTC power consumption + * by choosing the higher possible value for prediv_a + */ +- if ((pred_s > pred_s_max) || (pred_a > pred_a_max)) { ++ if (pred_s > pred_s_max || pred_a > pred_a_max) { + pred_a = pred_a_max; + pred_s = (rate / (pred_a + 1)) - 1; + +@@ -736,13 +850,15 @@ static int stm32_rtc_probe(struct platform_device *pdev) } else { rtc->pclk = devm_clk_get(&pdev->dev, "pclk"); if (IS_ERR(rtc->pclk)) { @@ -425,12 +478,12 @@ index d774aa18f57a..7fd6347691bb 100644 } if (IS_ERR(rtc->rtc_ck)) { - dev_err(&pdev->dev, "no rtc_ck clock"); -+ if (PTR_ERR(rtc->pclk) != -EPROBE_DEFER) ++ if (PTR_ERR(rtc->rtc_ck) != -EPROBE_DEFER) + dev_err(&pdev->dev, "no rtc_ck clock"); return PTR_ERR(rtc->rtc_ck); } -@@ -779,19 +891,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) +@@ -779,19 +895,12 @@ static int stm32_rtc_probe(struct platform_device *pdev) } ret = device_init_wakeup(&pdev->dev, true); @@ -455,7 +508,7 @@ index d774aa18f57a..7fd6347691bb 100644 platform_set_drvdata(pdev, rtc); -@@ -814,6 +919,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) +@@ -814,6 +923,21 @@ static int stm32_rtc_probe(struct platform_device *pdev) goto err; } @@ -477,7 +530,7 @@ index d774aa18f57a..7fd6347691bb 100644 /* * If INITS flag is reset (calendar year field set to 0x00), calendar * must be initialized -@@ -850,6 +970,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) +@@ -852,6 +976,9 @@ static int stm32_rtc_remove(struct platform_device *pdev) const struct stm32_rtc_registers *regs = &rtc->data->regs; unsigned int cr; @@ -487,7 +540,7 @@ index d774aa18f57a..7fd6347691bb 100644 /* Disable interrupts */ stm32_rtc_wpr_unlock(rtc); cr = readl_relaxed(rtc->base + regs->cr); -@@ -879,9 +1002,6 @@ static int stm32_rtc_suspend(struct device *dev) +@@ -881,9 +1008,6 @@ static int stm32_rtc_suspend(struct device *dev) if (rtc->data->has_pclk) clk_disable_unprepare(rtc->pclk); @@ -497,7 +550,7 @@ index d774aa18f57a..7fd6347691bb 100644 return 0; } -@@ -903,15 +1023,13 @@ static int stm32_rtc_resume(struct device *dev) +@@ -905,15 +1029,13 @@ static int stm32_rtc_resume(struct device *dev) return ret; } @@ -517,7 +570,7 @@ index d774aa18f57a..7fd6347691bb 100644 static struct platform_driver stm32_rtc_driver = { .probe = stm32_rtc_probe, diff --git a/drivers/watchdog/stm32_iwdg.c b/drivers/watchdog/stm32_iwdg.c -index 25188d6bbe15..a3436c296c97 100644 +index 25188d6bb..a3436c296 100644 --- a/drivers/watchdog/stm32_iwdg.c +++ b/drivers/watchdog/stm32_iwdg.c @@ -162,18 +162,15 @@ static int stm32_iwdg_clk_init(struct platform_device *pdev, @@ -545,7 +598,7 @@ index 25188d6bbe15..a3436c296c97 100644 ret = clk_prepare_enable(wdt->clk_pclk); if (ret) { diff --git a/include/dt-bindings/reset/stm32mp1-resets.h b/include/dt-bindings/reset/stm32mp1-resets.h -index f0c3aaef67a0..f3a0ed317835 100644 +index f0c3aaef6..f3a0ed317 100644 --- a/include/dt-bindings/reset/stm32mp1-resets.h +++ b/include/dt-bindings/reset/stm32mp1-resets.h @@ -7,6 +7,7 @@ @@ -577,7 +630,7 @@ index f0c3aaef67a0..f3a0ed317835 100644 #endif /* _DT_BINDINGS_STM32MP1_RESET_H_ */ diff --git a/include/dt-bindings/rtc/rtc-stm32.h b/include/dt-bindings/rtc/rtc-stm32.h new file mode 100644 -index 000000000000..4373c4dea587 +index 000000000..4373c4dea --- /dev/null +++ b/include/dt-bindings/rtc/rtc-stm32.h @@ -0,0 +1,13 @@ diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0018-ARM-5.10.10-stm32mp1-r1-SCMI.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch similarity index 88% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0018-ARM-5.10.10-stm32mp1-r1-SCMI.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch index b763a28..2b2aab3 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0018-ARM-5.10.10-stm32mp1-r1-SCMI.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch @@ -1,7 +1,7 @@ -From 51f0826032cee1b8cb0a1597c0a8d60b0042109d Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:17:18 +0100 -Subject: [PATCH 18/22] ARM 5.10.10-stm32mp1-r1 SCMI +From 03fe6061e18768eee7b247999cecaad2280098cf Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:51 +0200 +Subject: [PATCH 18/23] ARM 5.10.61-stm32mp1-r2 SCMI --- drivers/firmware/arm_scmi/base.c | 2 +- @@ -14,7 +14,7 @@ Subject: [PATCH 18/22] ARM 5.10.10-stm32mp1-r1 SCMI 7 files changed, 16 insertions(+), 13 deletions(-) diff --git a/drivers/firmware/arm_scmi/base.c b/drivers/firmware/arm_scmi/base.c -index 017e5d8bd869..a70b10ebaf45 100644 +index 017e5d8bd..a70b10eba 100644 --- a/drivers/firmware/arm_scmi/base.c +++ b/drivers/firmware/arm_scmi/base.c @@ -183,7 +183,7 @@ static int scmi_base_implementation_list_get(const struct scmi_handle *handle, @@ -27,7 +27,7 @@ index 017e5d8bd869..a70b10ebaf45 100644 break; diff --git a/drivers/firmware/arm_scmi/bus.c b/drivers/firmware/arm_scmi/bus.c -index 1377ec76a45d..8ea04b069129 100644 +index def8a84d1..33d1a6c79 100644 --- a/drivers/firmware/arm_scmi/bus.c +++ b/drivers/firmware/arm_scmi/bus.c @@ -60,11 +60,6 @@ static int scmi_protocol_init(int protocol_id, struct scmi_handle *handle) @@ -54,7 +54,7 @@ index 1377ec76a45d..8ea04b069129 100644 } diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c -index 4645677d86f1..c348a6f2eb29 100644 +index 4645677d8..c348a6f2e 100644 --- a/drivers/firmware/arm_scmi/clock.c +++ b/drivers/firmware/arm_scmi/clock.c @@ -161,7 +161,7 @@ scmi_clock_describe_rates_get(const struct scmi_handle *handle, u32 clk_id, @@ -67,7 +67,7 @@ index 4645677d86f1..c348a6f2eb29 100644 goto err; diff --git a/drivers/firmware/arm_scmi/common.h b/drivers/firmware/arm_scmi/common.h -index 65063fa948d4..98e642b591c5 100644 +index 34b7ae798..9fa5c0022 100644 --- a/drivers/firmware/arm_scmi/common.h +++ b/drivers/firmware/arm_scmi/common.h @@ -143,6 +143,8 @@ struct scmi_xfer { @@ -80,10 +80,10 @@ index 65063fa948d4..98e642b591c5 100644 struct scmi_xfer *xfer); int scmi_xfer_get_init(const struct scmi_handle *h, u8 msg_id, u8 prot_id, diff --git a/drivers/firmware/arm_scmi/driver.c b/drivers/firmware/arm_scmi/driver.c -index 3dfd8b6a0ebf..479f67d2377b 100644 +index 763223248..2b3ce604f 100644 --- a/drivers/firmware/arm_scmi/driver.c +++ b/drivers/firmware/arm_scmi/driver.c -@@ -410,6 +410,16 @@ void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle, +@@ -415,6 +415,16 @@ void scmi_reset_rx_to_maxsz(const struct scmi_handle *handle, xfer->rx.len = info->desc->max_msg_size; } @@ -101,7 +101,7 @@ index 3dfd8b6a0ebf..479f67d2377b 100644 /** diff --git a/drivers/firmware/arm_scmi/perf.c b/drivers/firmware/arm_scmi/perf.c -index 82fb3babff72..7bea0f6464ff 100644 +index 82fb3babf..7bea0f646 100644 --- a/drivers/firmware/arm_scmi/perf.c +++ b/drivers/firmware/arm_scmi/perf.c @@ -281,7 +281,7 @@ scmi_perf_describe_levels_get(const struct scmi_handle *handle, u32 domain, @@ -114,7 +114,7 @@ index 82fb3babff72..7bea0f6464ff 100644 break; diff --git a/drivers/firmware/arm_scmi/sensors.c b/drivers/firmware/arm_scmi/sensors.c -index b4232d611033..6dae881be774 100644 +index b4232d611..6dae881be 100644 --- a/drivers/firmware/arm_scmi/sensors.c +++ b/drivers/firmware/arm_scmi/sensors.c @@ -134,7 +134,7 @@ static int scmi_sensor_description_get(const struct scmi_handle *handle, diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0019-ARM-5.10.10-stm32mp1-r1-SOUND.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch similarity index 83% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0019-ARM-5.10.10-stm32mp1-r1-SOUND.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch index febbf99..a5b6517 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0019-ARM-5.10.10-stm32mp1-r1-SOUND.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch @@ -1,17 +1,19 @@ -From f934df539b8cdfa58cb512b439749dba32a42932 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:16:24 +0100 -Subject: [PATCH 19/22] ARM 5.10.10-stm32mp1-r1 SOUND +From e8a701ceba6fdf12989b38212c510bfdfea5c830 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:51 +0200 +Subject: [PATCH 19/23] ARM 5.10.61-stm32mp1-r2 SOUND --- sound/soc/codecs/Kconfig | 2 +- sound/soc/codecs/wm8994.c | 81 ++++++++- - sound/soc/stm/stm32_i2s.c | 310 +++++++++++++++++++++++++++++----- + sound/soc/stm/stm32_adfsdm.c | 11 +- + sound/soc/stm/stm32_i2s.c | 316 +++++++++++++++++++++++++++++----- sound/soc/stm/stm32_sai_sub.c | 4 +- - 4 files changed, 344 insertions(+), 53 deletions(-) + sound/soc/stm/stm32_spdifrx.c | 4 + + 6 files changed, 361 insertions(+), 57 deletions(-) diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 34c6dd04b85a..3afc5d1f074d 100644 +index 34c6dd04b..3afc5d1f0 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -1642,7 +1642,7 @@ config SND_SOC_WM8993 @@ -24,7 +26,7 @@ index 34c6dd04b85a..3afc5d1f074d 100644 config SND_SOC_WM8995 tristate diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c -index f57884113406..6d30b438ba0f 100644 +index f57884113..6d30b438b 100644 --- a/sound/soc/codecs/wm8994.c +++ b/sound/soc/codecs/wm8994.c @@ -7,6 +7,7 @@ @@ -175,11 +177,47 @@ index f57884113406..6d30b438ba0f 100644 if (control->revision < 4) { snd_soc_dapm_new_controls(dapm, wm8994_lateclk_revd_widgets, ARRAY_SIZE(wm8994_lateclk_revd_widgets)); +diff --git a/sound/soc/stm/stm32_adfsdm.c b/sound/soc/stm/stm32_adfsdm.c +index c4031988f..a67cadc03 100644 +--- a/sound/soc/stm/stm32_adfsdm.c ++++ b/sound/soc/stm/stm32_adfsdm.c +@@ -12,7 +12,7 @@ + #include + #include + #include +- ++#include + #include + #include + #include +@@ -353,15 +353,20 @@ static int stm32_adfsdm_probe(struct platform_device *pdev) + #endif + + ret = snd_soc_add_component(component, NULL, 0); +- if (ret < 0) ++ if (ret < 0) { + dev_err(&pdev->dev, "%s: Failed to register PCM platform\n", + __func__); ++ return ret; ++ } + +- return ret; ++ pm_runtime_enable(&pdev->dev); ++ ++ return 0; + } + + static int stm32_adfsdm_remove(struct platform_device *pdev) + { ++ pm_runtime_disable(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); + + return 0; diff --git a/sound/soc/stm/stm32_i2s.c b/sound/soc/stm/stm32_i2s.c -index 7c4d63c33f15..7d1672cf78cc 100644 +index 7c4d63c33..f324ce974 100644 --- a/sound/soc/stm/stm32_i2s.c +++ b/sound/soc/stm/stm32_i2s.c -@@ -8,6 +8,7 @@ +@@ -8,10 +8,12 @@ #include #include @@ -187,7 +225,12 @@ index 7c4d63c33f15..7d1672cf78cc 100644 #include #include #include -@@ -196,6 +197,9 @@ enum i2s_datlen { + #include ++#include + #include + #include + #include +@@ -196,6 +198,9 @@ enum i2s_datlen { #define STM32_I2S_IS_MASTER(x) ((x)->ms_flg == I2S_MS_MASTER) #define STM32_I2S_IS_SLAVE(x) ((x)->ms_flg == I2S_MS_SLAVE) @@ -197,7 +240,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 /** * struct stm32_i2s_data - private data of I2S * @regmap_conf: I2S register map configuration pointer -@@ -206,6 +210,7 @@ enum i2s_datlen { +@@ -206,6 +211,7 @@ enum i2s_datlen { * @dma_data_rx: dma configuration data for tx channel * @substream: PCM substream data pointer * @i2sclk: kernel clock feeding the I2S clock generator @@ -205,7 +248,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 * @pclk: peripheral clock driving bus interface * @x8kclk: I2S parent clock for sampling frequencies multiple of 8kHz * @x11kclk: I2S parent clock for sampling frequencies multiple of 11kHz -@@ -215,6 +220,9 @@ enum i2s_datlen { +@@ -215,6 +221,9 @@ enum i2s_datlen { * @irq_lock: prevent race condition with IRQ * @mclk_rate: master clock frequency (Hz) * @fmt: DAI protocol @@ -215,7 +258,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 * @refcount: keep count of opened streams on I2S * @ms_flg: master mode flag. */ -@@ -227,6 +235,7 @@ struct stm32_i2s_data { +@@ -227,6 +236,7 @@ struct stm32_i2s_data { struct snd_dmaengine_dai_dma_data dma_data_rx; struct snd_pcm_substream *substream; struct clk *i2sclk; @@ -223,7 +266,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 struct clk *pclk; struct clk *x8kclk; struct clk *x11kclk; -@@ -236,10 +245,210 @@ struct stm32_i2s_data { +@@ -236,10 +246,210 @@ struct stm32_i2s_data { spinlock_t irq_lock; /* used to prevent race condition with IRQ */ unsigned int mclk_rate; unsigned int fmt; @@ -434,7 +477,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 static irqreturn_t stm32_i2s_isr(int irq, void *devid) { struct stm32_i2s_data *i2s = (struct stm32_i2s_data *)devid; -@@ -405,18 +614,46 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, +@@ -405,18 +615,46 @@ static int stm32_i2s_set_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); @@ -488,7 +531,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 } static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, -@@ -424,11 +661,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -424,11 +662,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, { struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); unsigned long i2s_clock_rate; @@ -502,7 +545,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 if (!(rate % 11025)) clk_set_parent(i2s->i2sclk, i2s->x11kclk); -@@ -449,7 +685,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -449,7 +686,10 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, * dsp mode : div = i2s_clk / (nb_bits x ws) */ if (i2s->mclk_rate) { @@ -514,10 +557,11 @@ index 7c4d63c33f15..7d1672cf78cc 100644 } else { frame_len = 32; if ((i2s->fmt & SND_SOC_DAIFMT_FORMAT_MASK) == -@@ -462,34 +701,13 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, +@@ -461,35 +701,14 @@ static int stm32_i2s_configure_clock(struct snd_soc_dai *cpu_dai, + if (ret < 0) return ret; - nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1); +- nb_bits = frame_len * ((cgfr & I2S_CGFR_CHLEN) + 1); - tmp = DIV_ROUND_CLOSEST(i2s_clock_rate, (nb_bits * rate)); - } - @@ -539,6 +583,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 - if (((div == 1) && odd) || (div > I2S_CGFR_I2SDIV_MAX)) { - dev_err(cpu_dai->dev, "Wrong divider setting\n"); - return -EINVAL; ++ nb_bits = frame_len * (FIELD_GET(I2S_CGFR_CHLEN, cgfr) + 1); + ret = stm32_i2s_calc_clk_div(i2s, i2s_clock_rate, + (nb_bits * rate)); + if (ret) @@ -554,7 +599,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 if (ret < 0) return ret; -@@ -694,9 +912,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, +@@ -694,9 +913,6 @@ static void stm32_i2s_shutdown(struct snd_pcm_substream *substream, struct stm32_i2s_data *i2s = snd_soc_dai_get_drvdata(cpu_dai); unsigned long flags; @@ -564,7 +609,7 @@ index 7c4d63c33f15..7d1672cf78cc 100644 clk_disable_unprepare(i2s->i2sclk); spin_lock_irqsave(&i2s->irq_lock, flags); -@@ -861,6 +1076,13 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, +@@ -861,6 +1077,13 @@ static int stm32_i2s_parse_dt(struct platform_device *pdev, return PTR_ERR(i2s->x11kclk); } @@ -578,7 +623,15 @@ index 7c4d63c33f15..7d1672cf78cc 100644 /* Get irqs */ irq = platform_get_irq(pdev, 0); if (irq < 0) -@@ -906,16 +1128,16 @@ static int stm32_i2s_probe(struct platform_device *pdev) +@@ -892,6 +1115,7 @@ static int stm32_i2s_remove(struct platform_device *pdev) + { + snd_dmaengine_pcm_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); + + return 0; + } +@@ -906,16 +1130,16 @@ static int stm32_i2s_probe(struct platform_device *pdev) if (!i2s) return -ENOMEM; @@ -599,8 +652,17 @@ index 7c4d63c33f15..7d1672cf78cc 100644 ret = stm32_i2s_dais_init(pdev, i2s); if (ret) return ret; +@@ -974,6 +1198,8 @@ static int stm32_i2s_probe(struct platform_device *pdev) + FIELD_GET(I2S_VERR_MIN_MASK, val)); + } + ++ pm_runtime_enable(&pdev->dev); ++ + return ret; + + error: diff --git a/sound/soc/stm/stm32_sai_sub.c b/sound/soc/stm/stm32_sai_sub.c -index 3aa1cf262402..780f48138985 100644 +index 3aa1cf262..780f48138 100644 --- a/sound/soc/stm/stm32_sai_sub.c +++ b/sound/soc/stm/stm32_sai_sub.c @@ -1294,7 +1294,7 @@ static struct snd_soc_dai_driver stm32_sai_playback_dai = { @@ -621,6 +683,35 @@ index 3aa1cf262402..780f48138985 100644 .rate_min = 8000, .rate_max = 192000, .rates = SNDRV_PCM_RATE_CONTINUOUS, +diff --git a/sound/soc/stm/stm32_spdifrx.c b/sound/soc/stm/stm32_spdifrx.c +index 1bfa3b2ba..aa38f9df9 100644 +--- a/sound/soc/stm/stm32_spdifrx.c ++++ b/sound/soc/stm/stm32_spdifrx.c +@@ -12,6 +12,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -956,6 +957,7 @@ static int stm32_spdifrx_remove(struct platform_device *pdev) + + snd_dmaengine_pcm_unregister(&pdev->dev); + snd_soc_unregister_component(&pdev->dev); ++ pm_runtime_disable(&pdev->dev); + + return 0; + } +@@ -1046,6 +1048,8 @@ static int stm32_spdifrx_probe(struct platform_device *pdev) + FIELD_GET(SPDIFRX_VERR_MIN_MASK, ver)); + } + ++ pm_runtime_enable(&pdev->dev); ++ + return ret; + + error: -- 2.17.1 diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch new file mode 100644 index 0000000..41b91ce --- /dev/null +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch @@ -0,0 +1,31 @@ +From 49a7d9003e2c89aa252d3ccccb16d4ab22a90ef6 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:52 +0200 +Subject: [PATCH 20/23] ARM 5.10.61-stm32mp1-r2 MISC + +--- + drivers/opp/core.c | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/drivers/opp/core.c b/drivers/opp/core.c +index 903b465c8..dbcce5de9 100644 +--- a/drivers/opp/core.c ++++ b/drivers/opp/core.c +@@ -1608,9 +1608,13 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, + struct opp_table *opp_table; + + opp_table = dev_pm_opp_get_opp_table(dev); +- if (IS_ERR(opp_table)) ++ ++ if (PTR_ERR(opp_table) == -EPROBE_DEFER) + return opp_table; + ++ if (!opp_table) ++ return ERR_PTR(-ENOMEM); ++ + /* Make sure there are no concurrent readers while updating opp_table */ + WARN_ON(!list_empty(&opp_table->opp_list)); + +-- +2.17.1 + diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0020-ARM-5.10.10-stm32mp1-r1-MISC-CPUIDLE-POWER.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch similarity index 58% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0020-ARM-5.10.10-stm32mp1-r1-MISC-CPUIDLE-POWER.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch index 7ab331e..a4fd750 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0020-ARM-5.10.10-stm32mp1-r1-MISC-CPUIDLE-POWER.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch @@ -1,23 +1,22 @@ -From 996898e1ae8bd13f5bb6986c52bd9777b68e80fa Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:18:38 +0100 -Subject: [PATCH 20/22] ARM 5.10.10-stm32mp1-r1 MISC-CPUIDLE-POWER +From 5707d44444b4bd31e2690d5d7e72f83c6e28b48b Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Fri, 15 Oct 2021 08:44:32 +0200 +Subject: [PATCH 21/23] ARM 5.10.61-stm32mp1-r2 CPUIDLE-POWER -Signed-off-by: Romuald JEANNE --- drivers/base/power/domain.c | 4 +- drivers/base/power/main.c | 4 +- drivers/cpuidle/Kconfig.arm | 8 + drivers/cpuidle/Makefile | 1 + drivers/cpuidle/cpuidle-stm32.c | 276 ++++++++++++++++++++++++++++++++ - drivers/opp/core.c | 6 +- + drivers/nvmem/stm32-romem.c | 165 +++++++++++++++++-- include/linux/pm_wakeup.h | 10 ++ kernel/power/suspend.c | 1 - - 8 files changed, 304 insertions(+), 6 deletions(-) + 8 files changed, 453 insertions(+), 16 deletions(-) create mode 100644 drivers/cpuidle/cpuidle-stm32.c diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c -index 743268996336..e0894ef8457c 100644 +index 743268996..e0894ef84 100644 --- a/drivers/base/power/domain.c +++ b/drivers/base/power/domain.c @@ -1142,7 +1142,7 @@ static int genpd_finish_suspend(struct device *dev, bool poweroff) @@ -39,7 +38,7 @@ index 743268996336..e0894ef8457c 100644 genpd_lock(genpd); diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c -index c7ac49042cee..921c5b2ec30a 100644 +index c7ac49042..921c5b2ec 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -1359,7 +1359,7 @@ static void dpm_propagate_wakeup_to_parent(struct device *dev) @@ -61,7 +60,7 @@ index c7ac49042cee..921c5b2ec30a 100644 if (dev->power.direct_complete) { diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm -index 0844fadc4be8..2b8a0756e4ff 100644 +index 334f83e56..4de5db493 100644 --- a/drivers/cpuidle/Kconfig.arm +++ b/drivers/cpuidle/Kconfig.arm @@ -91,6 +91,14 @@ config ARM_EXYNOS_CPUIDLE @@ -80,7 +79,7 @@ index 0844fadc4be8..2b8a0756e4ff 100644 bool "CPU Idle Driver for mvebu v7 family processors" depends on (ARCH_MVEBU || COMPILE_TEST) && !ARM64 diff --git a/drivers/cpuidle/Makefile b/drivers/cpuidle/Makefile -index 26bbc5e74123..cc1eccc73d65 100644 +index 26bbc5e74..cc1eccc73 100644 --- a/drivers/cpuidle/Makefile +++ b/drivers/cpuidle/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_ARM_PSCI_CPUIDLE) += cpuidle-psci.o @@ -93,7 +92,7 @@ index 26bbc5e74123..cc1eccc73d65 100644 # MIPS drivers diff --git a/drivers/cpuidle/cpuidle-stm32.c b/drivers/cpuidle/cpuidle-stm32.c new file mode 100644 -index 000000000000..d3413386cc7f +index 000000000..d3413386c --- /dev/null +++ b/drivers/cpuidle/cpuidle-stm32.c @@ -0,0 +1,276 @@ @@ -373,27 +372,292 @@ index 000000000000..d3413386cc7f +MODULE_AUTHOR("<>"); +MODULE_DESCRIPTION("STM32 cpu idle driver"); +MODULE_LICENSE("GPL v2"); -diff --git a/drivers/opp/core.c b/drivers/opp/core.c -index 903b465c8568..dbcce5de9346 100644 ---- a/drivers/opp/core.c -+++ b/drivers/opp/core.c -@@ -1608,9 +1608,13 @@ struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, - struct opp_table *opp_table; +diff --git a/drivers/nvmem/stm32-romem.c b/drivers/nvmem/stm32-romem.c +index 354be5268..14013fa66 100644 +--- a/drivers/nvmem/stm32-romem.c ++++ b/drivers/nvmem/stm32-romem.c +@@ -2,15 +2,17 @@ + /* + * STM32 Factory-programmed memory read access driver + * +- * Copyright (C) 2017, STMicroelectronics - All Rights Reserved ++ * Copyright (C) 2017-2021, STMicroelectronics - All Rights Reserved + * Author: Fabrice Gasnier for STMicroelectronics. + */ - opp_table = dev_pm_opp_get_opp_table(dev); -- if (IS_ERR(opp_table)) + #include ++#include + #include + #include + #include + #include ++#include + + /* BSEC secure service access from non-secure */ + #define STM32_SMC_BSEC 0x82001003 +@@ -25,6 +27,8 @@ + /* 32 (x 32-bits) lower shadow registers */ + #define STM32MP15_BSEC_NUM_LOWER 32 + ++#define STM32_ROMEM_AUTOSUSPEND_DELAY_MS 50 + -+ if (PTR_ERR(opp_table) == -EPROBE_DEFER) - return opp_table; + struct stm32_romem_cfg { + int size; + }; +@@ -32,6 +36,7 @@ struct stm32_romem_cfg { + struct stm32_romem_priv { + void __iomem *base; + struct nvmem_config cfg; ++ struct clk *clk; + }; -+ if (!opp_table) -+ return ERR_PTR(-ENOMEM); + static int stm32_romem_read(void *context, unsigned int offset, void *buf, +@@ -39,11 +44,18 @@ static int stm32_romem_read(void *context, unsigned int offset, void *buf, + { + struct stm32_romem_priv *priv = context; + u8 *buf8 = buf; +- int i; ++ int i, ret; + - /* Make sure there are no concurrent readers while updating opp_table */ - WARN_ON(!list_empty(&opp_table->opp_list)); ++ ret = pm_runtime_resume_and_get(priv->cfg.dev); ++ if (ret < 0) ++ return ret; + for (i = offset; i < offset + bytes; i++) + *buf8++ = readb_relaxed(priv->base + i); + ++ pm_runtime_mark_last_busy(priv->cfg.dev); ++ pm_runtime_put_autosuspend(priv->cfg.dev); ++ + return 0; + } + +@@ -74,13 +86,19 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, + u8 *buf8 = buf, *val8 = (u8 *)&val; + int i, j = 0, ret, skip_bytes, size; + ++ ret = pm_runtime_resume_and_get(priv->cfg.dev); ++ if (ret < 0) ++ return ret; ++ + /* Round unaligned access to 32-bits */ + roffset = rounddown(offset, 4); + skip_bytes = offset & 0x3; + rbytes = roundup(bytes + skip_bytes, 4); + +- if (roffset + rbytes > priv->cfg.size) +- return -EINVAL; ++ if (roffset + rbytes > priv->cfg.size) { ++ ret = -EINVAL; ++ goto end_read; ++ } + + for (i = roffset; (i < roffset + rbytes); i += 4) { + u32 otp = i >> 2; +@@ -95,7 +113,7 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, + if (ret) { + dev_err(dev, "Can't read data%d (%d)\n", otp, + ret); +- return ret; ++ goto end_read; + } + } + /* skip first bytes in case of unaligned read */ +@@ -109,7 +127,11 @@ static int stm32_bsec_read(void *context, unsigned int offset, void *buf, + skip_bytes = 0; + } + +- return 0; ++end_read: ++ pm_runtime_mark_last_busy(priv->cfg.dev); ++ pm_runtime_put_autosuspend(priv->cfg.dev); ++ ++ return ret; + } + + static int stm32_bsec_write(void *context, unsigned int offset, void *buf, +@@ -120,20 +142,30 @@ static int stm32_bsec_write(void *context, unsigned int offset, void *buf, + u32 *buf32 = buf; + int ret, i; + ++ ret = pm_runtime_resume_and_get(priv->cfg.dev); ++ if (ret < 0) ++ return ret; ++ + /* Allow only writing complete 32-bits aligned words */ +- if ((bytes % 4) || (offset % 4)) +- return -EINVAL; ++ if ((bytes % 4) || (offset % 4)) { ++ ret = -EINVAL; ++ goto end_write; ++ } + + for (i = offset; i < offset + bytes; i += 4) { + ret = stm32_bsec_smc(STM32_SMC_PROG_OTP, i >> 2, *buf32++, + NULL); + if (ret) { + dev_err(dev, "Can't write data%d (%d)\n", i >> 2, ret); +- return ret; ++ goto end_write; + } + } + +- return 0; ++end_write: ++ pm_runtime_mark_last_busy(priv->cfg.dev); ++ pm_runtime_put_autosuspend(priv->cfg.dev); ++ ++ return ret; + } + + static int stm32_romem_probe(struct platform_device *pdev) +@@ -142,6 +174,8 @@ static int stm32_romem_probe(struct platform_device *pdev) + struct device *dev = &pdev->dev; + struct stm32_romem_priv *priv; + struct resource *res; ++ struct nvmem_device *nvmem; ++ int ret; + + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); + if (!priv) +@@ -159,6 +193,27 @@ static int stm32_romem_probe(struct platform_device *pdev) + priv->cfg.priv = priv; + priv->cfg.owner = THIS_MODULE; + ++ priv->clk = devm_clk_get_optional(&pdev->dev, NULL); ++ if (IS_ERR(priv->clk)) ++ return dev_err_probe(dev, PTR_ERR(priv->clk), ++ "failed to get clock\n"); ++ ++ if (priv->clk) { ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(dev, "failed to enable clock (%d)\n", ret); ++ return ret; ++ } ++ } ++ ++ pm_runtime_set_autosuspend_delay(dev, ++ STM32_ROMEM_AUTOSUSPEND_DELAY_MS); ++ pm_runtime_use_autosuspend(dev); ++ ++ pm_runtime_get_noresume(dev); ++ pm_runtime_set_active(dev); ++ pm_runtime_enable(dev); ++ + cfg = (const struct stm32_romem_cfg *) + of_match_device(dev->driver->of_match_table, dev)->data; + if (!cfg) { +@@ -171,9 +226,95 @@ static int stm32_romem_probe(struct platform_device *pdev) + priv->cfg.reg_write = stm32_bsec_write; + } + +- return PTR_ERR_OR_ZERO(devm_nvmem_register(dev, &priv->cfg)); ++ platform_set_drvdata(pdev, priv); ++ ++ nvmem = nvmem_register(&priv->cfg); ++ if (IS_ERR(nvmem)) ++ goto err_pm_stop; ++ ++ pm_runtime_mark_last_busy(dev); ++ pm_runtime_put_autosuspend(dev); ++ ++ return 0; ++ ++err_pm_stop: ++ pm_runtime_disable(dev); ++ pm_runtime_set_suspended(dev); ++ pm_runtime_put_noidle(dev); ++ ++ if (priv->clk) ++ clk_disable_unprepare(priv->clk); ++ ++ return PTR_ERR(nvmem); + } + ++static int stm32_romem_remove(struct platform_device *pdev) ++{ ++ struct stm32_romem_priv *priv; ++ int ret; ++ ++ priv = dev_get_drvdata(&pdev->dev); ++ if (!priv) ++ return -ENODEV; ++ ++ ret = pm_runtime_get_sync(&pdev->dev); ++ if (ret < 0) ++ return ret; ++ ++ nvmem_unregister((struct nvmem_device *)&priv->cfg); ++ ++ pm_runtime_disable(&pdev->dev); ++ pm_runtime_set_suspended(&pdev->dev); ++ pm_runtime_put_noidle(&pdev->dev); ++ ++ if (priv->clk) ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_romem_runtime_suspend(struct device *dev) ++{ ++ struct stm32_romem_priv *priv; ++ ++ priv = dev_get_drvdata(dev); ++ if (!priv) ++ return -ENODEV; ++ ++ if (priv->clk) ++ clk_disable_unprepare(priv->clk); ++ ++ return 0; ++} ++ ++static int __maybe_unused stm32_romem_runtime_resume(struct device *dev) ++{ ++ struct stm32_romem_priv *priv; ++ int ret; ++ ++ priv = dev_get_drvdata(dev); ++ if (!priv) ++ return -ENODEV; ++ ++ if (priv->clk) { ++ ret = clk_prepare_enable(priv->clk); ++ if (ret) { ++ dev_err(priv->cfg.dev, ++ "Failed to prepare_enable clock (%d)\n", ret); ++ return ret; ++ } ++ } ++ ++ return 0; ++} ++ ++static const struct dev_pm_ops stm32_romem_pm_ops = { ++ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend, ++ pm_runtime_force_resume) ++ SET_RUNTIME_PM_OPS(stm32_romem_runtime_suspend, ++ stm32_romem_runtime_resume, NULL) ++}; ++ + static const struct stm32_romem_cfg stm32mp15_bsec_cfg = { + .size = 384, /* 96 x 32-bits data words */ + }; +@@ -189,8 +330,10 @@ MODULE_DEVICE_TABLE(of, stm32_romem_of_match); + + static struct platform_driver stm32_romem_driver = { + .probe = stm32_romem_probe, ++ .remove = stm32_romem_remove, + .driver = { + .name = "stm32-romem", ++ .pm = &stm32_romem_pm_ops, + .of_match_table = of_match_ptr(stm32_romem_of_match), + }, + }; diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h -index aa3da6611533..196a157456aa 100644 +index aa3da6611..196a15745 100644 --- a/include/linux/pm_wakeup.h +++ b/include/linux/pm_wakeup.h @@ -84,6 +84,11 @@ static inline bool device_may_wakeup(struct device *dev) @@ -421,7 +685,7 @@ index aa3da6611533..196a157456aa 100644 static inline void __pm_stay_awake(struct wakeup_source *ws) {} diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c -index 32391acc806b..dc800d4f5b9f 100644 +index 32391acc8..dc800d4f5 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -34,7 +34,6 @@ diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0021-ARM-5.10.10-stm32mp1-r1-DEVICETREE.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0022-ARM-5.10.61-stm32mp1-r2-DEVICETREE.patch similarity index 91% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0021-ARM-5.10.10-stm32mp1-r1-DEVICETREE.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0022-ARM-5.10.61-stm32mp1-r2-DEVICETREE.patch index 81d157e..a27b97a 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0021-ARM-5.10.10-stm32mp1-r1-DEVICETREE.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0022-ARM-5.10.61-stm32mp1-r2-DEVICETREE.patch @@ -1,7 +1,7 @@ -From f539f59331650f195c24a84b2a99f5f8109c0e38 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:03:16 +0100 -Subject: [PATCH 21/22] ARM 5.10.10-stm32mp1-r1 DEVICETREE +From ea7834b1e021f316e86fbc96575fac5c49a6b784 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:57 +0200 +Subject: [PATCH 22/23] ARM 5.10.61-stm32mp1-r2 DEVICETREE --- .../bindings/connector/usb-connector.yaml | 24 + @@ -11,27 +11,33 @@ Subject: [PATCH 21/22] ARM 5.10.10-stm32mp1-r1 DEVICETREE .../devicetree/bindings/hwlock/hwlock.txt | 27 +- .../bindings/hwlock/st,stm32-hwspinlock.yaml | 4 +- .../devicetree/bindings/i2c/st,stm32-i2c.yaml | 12 + + .../devicetree/bindings/iio/adc/adc.txt | 23 - + .../devicetree/bindings/iio/adc/adc.yaml | 42 ++ .../iio/adc/sigma-delta-modulator.yaml | 3 + + .../bindings/iio/adc/st,stm32-adc.yaml | 102 ++- .../bindings/iio/adc/st,stm32-dfsdm-adc.yaml | 7 +- .../interrupt-controller/st,stm32-exti.yaml | 19 + + .../bindings/media/st,stm32-cec.yaml | 2 +- .../bindings/media/st,stm32-dcmi.yaml | 38 + .../bindings/media/video-interfaces.txt | 2 + .../bindings/mfd/st,stm32-timers.yaml | 6 +- .../bindings/mfd/st,stm32mp1-pwr.txt | 57 ++ + .../bindings/nvmem/st,stm32-romem.yaml | 6 + .../bindings/perf/stm32-ddr-pmu.yaml | 44 ++ .../bindings/phy/phy-stm32-usbphyc.txt | 73 -- - .../bindings/phy/phy-stm32-usbphyc.yaml | 179 +++++ + .../bindings/phy/phy-stm32-usbphyc.yaml | 194 +++++ .../bindings/pinctrl/st,stm32-pinctrl.yaml | 8 + .../bindings/remoteproc/rproc-srm.txt | 58 ++ .../bindings/remoteproc/st,stm32-rproc.yaml | 51 +- + .../devicetree/bindings/rtc/st,stm32-rtc.yaml | 20 + .../devicetree/bindings/serial/rs485.yaml | 16 + - .../bindings/serial/st,stm32-uart.yaml | 75 +- + .../bindings/serial/st,stm32-uart.yaml | 79 +- .../bindings/soc/stm32/stm32_hdp.txt | 39 + .../bindings/sound/st,stm32-adfsdm.txt | 63 -- .../bindings/sound/st,stm32-i2s.yaml | 4 + .../bindings/sound/st,stm32-sai.txt | 107 --- .../bindings/sound/st,stm32-sai.yaml | 200 +++++ - .../devicetree/bindings/usb/dwc2.yaml | 4 + + .../devicetree/bindings/usb/dwc2.yaml | 38 + .../devicetree/bindings/usb/generic-ehci.yaml | 5 + .../devicetree/bindings/usb/st,stusb160x.yaml | 87 +++ arch/arm/boot/dts/Makefile | 48 ++ @@ -39,41 +45,43 @@ Subject: [PATCH 21/22] ARM 5.10.10-stm32mp1-r1 DEVICETREE arch/arm/boot/dts/stm32f746.dtsi | 4 + arch/arm/boot/dts/stm32h743.dtsi | 4 + .../boot/dts/stm32mp15-m4-srm-pinctrl.dtsi | 524 +++++++++++++ - arch/arm/boot/dts/stm32mp15-m4-srm.dtsi | 442 +++++++++++ - arch/arm/boot/dts/stm32mp15-no-scmi.dtsi | 157 ++++ - arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 228 +++++- - arch/arm/boot/dts/stm32mp151.dtsi | 627 +++++++++++----- + arch/arm/boot/dts/stm32mp15-m4-srm.dtsi | 448 +++++++++++ + arch/arm/boot/dts/stm32mp15-no-scmi.dtsi | 153 ++++ + arch/arm/boot/dts/stm32mp15-pinctrl.dtsi | 211 +++++- + arch/arm/boot/dts/stm32mp151.dtsi | 644 +++++++++++----- arch/arm/boot/dts/stm32mp153.dtsi | 8 +- arch/arm/boot/dts/stm32mp157.dtsi | 3 +- - arch/arm/boot/dts/stm32mp157a-dk1.dts | 2 +- + arch/arm/boot/dts/stm32mp157a-dk1.dts | 8 +- arch/arm/boot/dts/stm32mp157a-ed1.dts | 32 + - arch/arm/boot/dts/stm32mp157a-ev1.dts | 88 +++ + arch/arm/boot/dts/stm32mp157a-ev1.dts | 83 +++ .../boot/dts/stm32mp157c-dk2-a7-examples.dts | 60 ++ .../boot/dts/stm32mp157c-dk2-m4-examples.dts | 129 ++++ - arch/arm/boot/dts/stm32mp157c-dk2.dts | 68 +- - arch/arm/boot/dts/stm32mp157c-ed1.dts | 368 +--------- + arch/arm/boot/dts/stm32mp157c-dk2.dts | 71 +- + arch/arm/boot/dts/stm32mp157c-ed1.dts | 368 +-------- .../boot/dts/stm32mp157c-ev1-a7-examples.dts | 57 ++ .../boot/dts/stm32mp157c-ev1-m4-examples.dts | 146 ++++ - arch/arm/boot/dts/stm32mp157c-ev1.dts | 330 +-------- - arch/arm/boot/dts/stm32mp157d-dk1.dts | 28 + + arch/arm/boot/dts/stm32mp157c-ev1.dts | 335 +-------- + arch/arm/boot/dts/stm32mp157d-dk1.dts | 22 + arch/arm/boot/dts/stm32mp157d-ed1.dts | 33 + - arch/arm/boot/dts/stm32mp157d-ev1.dts | 88 +++ + arch/arm/boot/dts/stm32mp157d-ev1.dts | 83 +++ .../boot/dts/stm32mp157f-dk2-a7-examples.dts | 60 ++ .../boot/dts/stm32mp157f-dk2-m4-examples.dts | 129 ++++ - arch/arm/boot/dts/stm32mp157f-dk2.dts | 157 ++++ + arch/arm/boot/dts/stm32mp157f-dk2.dts | 154 ++++ arch/arm/boot/dts/stm32mp157f-ed1.dts | 37 + .../boot/dts/stm32mp157f-ev1-a7-examples.dts | 57 ++ .../boot/dts/stm32mp157f-ev1-m4-examples.dts | 146 ++++ - arch/arm/boot/dts/stm32mp157f-ev1.dts | 89 +++ + arch/arm/boot/dts/stm32mp157f-ev1.dts | 84 +++ arch/arm/boot/dts/stm32mp15xa.dtsi | 13 + arch/arm/boot/dts/stm32mp15xc.dtsi | 6 +- arch/arm/boot/dts/stm32mp15xd.dtsi | 42 ++ arch/arm/boot/dts/stm32mp15xf.dtsi | 20 + - arch/arm/boot/dts/stm32mp15xx-dkx.dtsi | 122 +++- - arch/arm/boot/dts/stm32mp15xx-edx.dtsi | 413 +++++++++++ - arch/arm/boot/dts/stm32mp15xx-evx.dtsi | 686 ++++++++++++++++++ - 68 files changed, 5596 insertions(+), 1195 deletions(-) + arch/arm/boot/dts/stm32mp15xx-dkx.dtsi | 143 +++- + arch/arm/boot/dts/stm32mp15xx-edx.dtsi | 419 +++++++++++ + arch/arm/boot/dts/stm32mp15xx-evx.dtsi | 696 ++++++++++++++++++ + 74 files changed, 5831 insertions(+), 1237 deletions(-) create mode 100644 Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt + delete mode 100644 Documentation/devicetree/bindings/iio/adc/adc.txt + create mode 100644 Documentation/devicetree/bindings/iio/adc/adc.yaml create mode 100644 Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt create mode 100644 Documentation/devicetree/bindings/perf/stm32-ddr-pmu.yaml delete mode 100644 Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt @@ -110,7 +118,7 @@ Subject: [PATCH 21/22] ARM 5.10.10-stm32mp1-r1 DEVICETREE create mode 100644 arch/arm/boot/dts/stm32mp15xx-evx.dtsi diff --git a/Documentation/devicetree/bindings/connector/usb-connector.yaml b/Documentation/devicetree/bindings/connector/usb-connector.yaml -index 728f82db073d..ccf6eb22ba05 100644 +index 728f82db0..ccf6eb22b 100644 --- a/Documentation/devicetree/bindings/connector/usb-connector.yaml +++ b/Documentation/devicetree/bindings/connector/usb-connector.yaml @@ -93,6 +93,24 @@ properties: @@ -153,7 +161,7 @@ index 728f82db073d..ccf6eb22ba05 100644 examples: diff --git a/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt new file mode 100644 -index 000000000000..1292eb2612a0 +index 000000000..1292eb261 --- /dev/null +++ b/Documentation/devicetree/bindings/cpufreq/stm32-cpufreq.txt @@ -0,0 +1,61 @@ @@ -219,7 +227,7 @@ index 000000000000..1292eb2612a0 + }; + }; diff --git a/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml b/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml -index 2a5325f480f6..99351fe0fa17 100644 +index 2a5325f48..99351fe0f 100644 --- a/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml +++ b/Documentation/devicetree/bindings/dma/st,stm32-dma.yaml @@ -40,6 +40,21 @@ description: | @@ -298,7 +306,7 @@ index 2a5325f480f6..99351fe0fa17 100644 ... diff --git a/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml b/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml -index c30be840be1c..c4bb58014374 100644 +index c30be840b..c4bb58014 100644 --- a/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml +++ b/Documentation/devicetree/bindings/dma/st,stm32-mdma.yaml @@ -10,8 +10,8 @@ description: | @@ -342,7 +350,7 @@ index c30be840be1c..c4bb58014374 100644 dma-requests = <32>; st,ahb-addr-masks = <0x20000000>, <0x00000000>; diff --git a/Documentation/devicetree/bindings/hwlock/hwlock.txt b/Documentation/devicetree/bindings/hwlock/hwlock.txt -index 085d1f5c916a..e98088a409ba 100644 +index 085d1f5c9..e98088a40 100644 --- a/Documentation/devicetree/bindings/hwlock/hwlock.txt +++ b/Documentation/devicetree/bindings/hwlock/hwlock.txt @@ -13,7 +13,7 @@ hwlock providers: @@ -397,7 +405,7 @@ index 085d1f5c916a..e98088a409ba 100644 + }; \ No newline at end of file diff --git a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml -index 47cf9c8d97e9..539a1dc052b7 100644 +index 47cf9c8d9..539a1dc05 100644 --- a/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml +++ b/Documentation/devicetree/bindings/hwlock/st,stm32-hwspinlock.yaml @@ -12,7 +12,7 @@ maintainers: @@ -419,7 +427,7 @@ index 47cf9c8d97e9..539a1dc052b7 100644 clocks = <&rcc HSEM>; clock-names = "hsem"; diff --git a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml -index d747f4990ad8..9f0b098e899a 100644 +index d747f4990..9f0b098e8 100644 --- a/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml +++ b/Documentation/devicetree/bindings/i2c/st,stm32-i2c.yaml @@ -20,6 +20,13 @@ allOf: @@ -448,8 +456,85 @@ index d747f4990ad8..9f0b098e899a 100644 - if: properties: compatible: +diff --git a/Documentation/devicetree/bindings/iio/adc/adc.txt b/Documentation/devicetree/bindings/iio/adc/adc.txt +deleted file mode 100644 +index 5bbaa330a..000000000 +--- a/Documentation/devicetree/bindings/iio/adc/adc.txt ++++ /dev/null +@@ -1,23 +0,0 @@ +-Common ADCs properties +- +-Optional properties for child nodes: +-- bipolar : Boolean, if set the channel is used in bipolar mode. +-- diff-channels : Differential channels muxed for this ADC. The first value +- specifies the positive input pin, the second value the negative +- input pin. +- +-Example: +- adc@0 { +- compatible = "some,adc"; +- ... +- channel@0 { +- bipolar; +- diff-channels = <0 1>; +- ... +- }; +- +- channel@1 { +- diff-channels = <2 3>; +- ... +- }; +- }; +diff --git a/Documentation/devicetree/bindings/iio/adc/adc.yaml b/Documentation/devicetree/bindings/iio/adc/adc.yaml +new file mode 100644 +index 000000000..912a7635e +--- /dev/null ++++ b/Documentation/devicetree/bindings/iio/adc/adc.yaml +@@ -0,0 +1,42 @@ ++# SPDX-License-Identifier: GPL-2.0 ++%YAML 1.2 ++--- ++$id: http://devicetree.org/schemas/iio/adc/adc.yaml# ++$schema: http://devicetree.org/meta-schemas/core.yaml# ++ ++title: Generic IIO bindings for ADC channels ++ ++maintainers: ++ - Jonathan Cameron ++ ++description: ++ A few properties are defined in a common way ADC channels. ++ ++properties: ++ $nodename: ++ pattern: "^channel(@[0-9a-f]+)?$" ++ description: ++ A channel index should match reg. ++ ++ reg: ++ maxItems: 1 ++ ++ label: ++ $ref: /schemas/types.yaml#/definitions/string ++ description: Unique name to identify which channel this is. ++ ++ bipolar: ++ $ref: /schemas/types.yaml#/definitions/flag ++ description: If provided, the channel is to be used in bipolar mode. ++ ++ diff-channels: ++ $ref: /schemas/types.yaml#/definitions/uint32-array ++ maxItems: 2 ++ minItems: 2 ++ description: ++ Many ADCs have dual Muxes to allow different input pins to be routed ++ to both the positive and negative inputs of a differential ADC. ++ The first value specifies the positive input pin, the second ++ specifies the negative input pin. ++ ++additionalProperties: true diff --git a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.yaml b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.yaml -index a390343d0c2a..bf5d71fb60da 100644 +index a390343d0..bf5d71fb6 100644 --- a/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.yaml +++ b/Documentation/devicetree/bindings/iio/adc/sigma-delta-modulator.yaml @@ -21,6 +21,9 @@ properties: @@ -462,8 +547,140 @@ index a390343d0c2a..bf5d71fb60da 100644 required: - compatible - '#io-channel-cells' +diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml +index 28417b31b..8649dfba9 100644 +--- a/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml ++++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml +@@ -264,7 +264,9 @@ patternProperties: + , ,... vinp and vinn are numbered from 0 to 19. + + Note: At least one of "st,adc-channels" or "st,adc-diff-channels" is +- required. Both properties can be used together. Some channels can be ++ required if no adc generic channel is defined. These legacy channel ++ properties are exclusive with adc generic channel bindings. ++ Both properties can be used together. Some channels can be + used as single-ended and some other ones as differential (mixed). But + channels can't be configured both as single-ended and differential. + $ref: /schemas/types.yaml#/definitions/uint32-matrix +@@ -289,6 +291,49 @@ patternProperties: + each channel. + $ref: /schemas/types.yaml#/definitions/uint32-array + ++ nvmem-cells: ++ items: ++ - description: Phandle to the calibration vrefint data provided by otp ++ ++ nvmem-cell-names: ++ items: ++ - const: vrefint ++ ++ patternProperties: ++ "^channel@([0-9]|1[0-9])$": ++ type: object ++ $ref: "adc.yaml" ++ description: | ++ Represents the external channels which are connected to the ADC. ++ ++ properties: ++ reg: ++ items: ++ minimum: 0 ++ maximum: 19 ++ ++ label: ++ description: | ++ Unique name to identify which channel this is. ++ Reserved label names "vddcore", "vrefint" and "vbat" ++ are used to identify internal channels with matching names. ++ ++ diff-channels: ++ $ref: /schemas/types.yaml#/definitions/uint32-array ++ items: ++ minimum: 0 ++ maximum: 19 ++ ++ st,min-sample-time-nsecs: ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ description: | ++ Minimum sampling time in nanoseconds. Depending on hardware (board) ++ e.g. high/low analog input source impedance, fine tune of ADC ++ sampling time may be recommended. ++ ++ required: ++ - reg ++ + allOf: + - if: + properties: +@@ -366,6 +411,15 @@ patternProperties: + items: + minimum: 40 + ++ - if: ++ patternProperties: ++ contains: ++ "^channel@([0-9]|1[0-9])$" ++ then: ++ properties: ++ st,adc-channels: false ++ st,adc-diff-channels: false ++ + additionalProperties: false + + anyOf: +@@ -450,4 +504,50 @@ examples: + // other adc child node follow... + }; + ++ - | ++ // Example 3: with stm32mp157c to setup ADC2 with: ++ // - internal channels 13, 14, 15. ++ #include ++ #include ++ adc122: adc@48003000 { ++ compatible = "st,stm32mp1-adc-core"; ++ reg = <0x48003000 0x400>; ++ interrupts = , ++ ; ++ clocks = <&rcc ADC12>, <&rcc ADC12_K>; ++ clock-names = "bus", "adc"; ++ booster-supply = <&booster>; ++ vdd-supply = <&vdd>; ++ vdda-supply = <&vdda>; ++ vref-supply = <&vref>; ++ st,syscfg = <&syscfg>; ++ interrupt-controller; ++ #interrupt-cells = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ adc@100 { ++ compatible = "st,stm32mp1-adc"; ++ #io-channel-cells = <1>; ++ reg = <0x100>; ++ interrupts = <1>; ++ #address-cells = <1>; ++ #size-cells = <0>; ++ channel@13 { ++ reg = <13>; ++ label = "vrefint"; ++ st,min-sample-time-nsecs = <9000>; ++ }; ++ channel@14 { ++ reg = <14>; ++ label = "vddcore"; ++ st,min-sample-time-nsecs = <9000>; ++ }; ++ channel@15 { ++ reg = <15>; ++ label = "vbat"; ++ st,min-sample-time-nsecs = <9000>; ++ }; ++ }; ++ }; ++ + ... diff --git a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml -index d61bc011e820..6f2398cdc82d 100644 +index d61bc011e..6f2398cdc 100644 --- a/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml +++ b/Documentation/devicetree/bindings/iio/adc/st,stm32-dfsdm-adc.yaml @@ -199,8 +199,6 @@ patternProperties: @@ -495,7 +712,7 @@ index d61bc011e820..6f2398cdc82d 100644 - io-channels diff --git a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml -index 2a5b29567926..8e4093cbc9b5 100644 +index 2a5b29567..8e4093cbc 100644 --- a/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml +++ b/Documentation/devicetree/bindings/interrupt-controller/st,stm32-exti.yaml @@ -39,6 +39,25 @@ properties: @@ -524,8 +741,21 @@ index 2a5b29567926..8e4093cbc9b5 100644 required: - "#interrupt-cells" - compatible +diff --git a/Documentation/devicetree/bindings/media/st,stm32-cec.yaml b/Documentation/devicetree/bindings/media/st,stm32-cec.yaml +index d75019c09..8a460b105 100644 +--- a/Documentation/devicetree/bindings/media/st,stm32-cec.yaml ++++ b/Documentation/devicetree/bindings/media/st,stm32-cec.yaml +@@ -47,7 +47,7 @@ examples: + compatible = "st,stm32-cec"; + reg = <0x40006c00 0x400>; + interrupts = ; +- clocks = <&rcc CEC_K>, <&clk_lse>; ++ clocks = <&rcc CEC_K>, <&rcc CEC>; + clock-names = "cec", "hdmi-cec"; + }; + diff --git a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml -index 3fe778cb5cc3..c18574bb3e81 100644 +index 3fe778cb5..c18574bb3 100644 --- a/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml +++ b/Documentation/devicetree/bindings/media/st,stm32-dcmi.yaml @@ -44,6 +44,43 @@ properties: @@ -581,7 +811,7 @@ index 3fe778cb5cc3..c18574bb3e81 100644 hsync-active = <0>; vsync-active = <0>; diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt -index 3920f25a9123..5d63c4de8783 100644 +index 3920f25a9..5d63c4de8 100644 --- a/Documentation/devicetree/bindings/media/video-interfaces.txt +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt @@ -513,6 +513,8 @@ Optional endpoint properties @@ -594,7 +824,7 @@ index 3920f25a9123..5d63c4de8783 100644 Example ------- diff --git a/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml b/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml -index f212fc6e1661..0f16c8864a87 100644 +index f212fc6e1..0f16c8864 100644 --- a/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml +++ b/Documentation/devicetree/bindings/mfd/st,stm32-timers.yaml @@ -131,7 +131,7 @@ additionalProperties: false @@ -620,7 +850,7 @@ index f212fc6e1661..0f16c8864a87 100644 compatible = "st,stm32-timer-counter"; diff --git a/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt new file mode 100644 -index 000000000000..eb622387bb65 +index 000000000..eb622387b --- /dev/null +++ b/Documentation/devicetree/bindings/mfd/st,stm32mp1-pwr.txt @@ -0,0 +1,57 @@ @@ -681,9 +911,26 @@ index 000000000000..eb622387bb65 + }; +}; + +diff --git a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml +index 0b80ce22a..2ed707cff 100644 +--- a/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml ++++ b/Documentation/devicetree/bindings/nvmem/st,stm32-romem.yaml +@@ -24,6 +24,12 @@ properties: + - st,stm32f4-otp + - st,stm32mp15-bsec + ++ clocks: ++ maxItems: 1 ++ description: | ++ - It's not present on stm32f4. ++ - It's optional on stm32mp15. ++ + patternProperties: + "^.*@[0-9a-f]+$": + type: object diff --git a/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.yaml b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.yaml new file mode 100644 -index 000000000000..085f2886e580 +index 000000000..085f2886e --- /dev/null +++ b/Documentation/devicetree/bindings/perf/stm32-ddr-pmu.yaml @@ -0,0 +1,44 @@ @@ -733,7 +980,7 @@ index 000000000000..085f2886e580 +... diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt deleted file mode 100644 -index 725ae71ae653..000000000000 +index 725ae71ae..000000000 --- a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.txt +++ /dev/null @@ -1,73 +0,0 @@ @@ -812,10 +1059,10 @@ index 725ae71ae653..000000000000 - }; diff --git a/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml new file mode 100644 -index 000000000000..35460bb9f513 +index 000000000..ab186edb2 --- /dev/null +++ b/Documentation/devicetree/bindings/phy/phy-stm32-usbphyc.yaml -@@ -0,0 +1,179 @@ +@@ -0,0 +1,194 @@ +# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause +%YAML 1.2 +--- @@ -855,6 +1102,9 @@ index 000000000000..35460bb9f513 + clocks: + maxItems: 1 + ++ resets: ++ maxItems: 1 ++ + '#address-cells': + const: 1 + @@ -887,9 +1137,6 @@ index 000000000000..35460bb9f513 + phy-supply: + description: regulator providing 3V3 power supply to the PHY. + -+ vbus-supply: -+ description: regulator providing 5V Vbus to the USB connector. -+ + st,phy-tuning: + $ref: /schemas/types.yaml#definitions/phandle + description: @@ -919,6 +1166,13 @@ index 000000000000..35460bb9f513 + '#phy-cells': + enum: [ 0x0, 0x1 ] + ++ connector: ++ type: object ++ allOf: ++ - $ref: ../connector/usb-connector.yaml ++ properties: ++ vbus-supply: true ++ + allOf: + - if: + properties: @@ -941,6 +1195,8 @@ index 000000000000..35460bb9f513 + - phy-supply + - '#phy-cells' + ++ additionalProperties: false ++ +required: + - compatible + - reg @@ -953,6 +1209,8 @@ index 000000000000..35460bb9f513 + - usb-phy@0 + - usb-phy@1 + ++additionalProperties: false ++ +examples: + - | + #include @@ -985,6 +1243,10 @@ index 000000000000..35460bb9f513 + phy-supply = <&vdd_usb>; + #phy-cells = <0>; + st,phy-tuning = <&usb_phy_tuning>; ++ connector { ++ compatible = "usb-a-connector"; ++ vbus-supply = <&vbus_sw>; ++ }; + }; + + usbphyc_port1: usb-phy@1 { @@ -996,7 +1258,7 @@ index 000000000000..35460bb9f513 + }; +... diff --git a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml -index 72877544ca78..f67e2e7079f5 100644 +index 72877544c..f67e2e707 100644 --- a/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml +++ b/Documentation/devicetree/bindings/pinctrl/st,stm32-pinctrl.yaml @@ -139,9 +139,13 @@ patternProperties: @@ -1026,7 +1288,7 @@ index 72877544ca78..f67e2e7079f5 100644 type: boolean diff --git a/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt new file mode 100644 -index 000000000000..baa6e8e135e1 +index 000000000..baa6e8e13 --- /dev/null +++ b/Documentation/devicetree/bindings/remoteproc/rproc-srm.txt @@ -0,0 +1,58 @@ @@ -1089,7 +1351,7 @@ index 000000000000..baa6e8e135e1 + }; + }; diff --git a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml -index 4ffa25268fcc..7180d545ab80 100644 +index 4ffa25268..7180d545a 100644 --- a/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml +++ b/Documentation/devicetree/bindings/remoteproc/st,stm32-rproc.yaml @@ -16,7 +16,9 @@ maintainers: @@ -1179,9 +1441,74 @@ index 4ffa25268fcc..7180d545ab80 100644 + st,syscfg-m4-state = <&tamp 0x148 0xFFFFFFFF>; }; + ... +diff --git a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml +index 5456604b1..fc6cb003d 100644 +--- a/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml ++++ b/Documentation/devicetree/bindings/rtc/st,stm32-rtc.yaml +@@ -52,6 +52,13 @@ properties: + override default rtc_ck parent clock phandle of the new parent clock of rtc_ck + maxItems: 1 + ++ st,lsco: ++ $ref: "/schemas/types.yaml#/definitions/uint32" ++ description: | ++ To select and enable RTC Low Speed Clock Output on stm32mp1. ++ Refer to for the supported values. ++ Pinctrl state named "default" may be defined to reserve pin for RTC output. ++ + allOf: + - if: + properties: +@@ -67,6 +74,9 @@ allOf: + + clock-names: false + ++ st,lsco: ++ maxItems: 0 ++ + required: + - st,syscfg + +@@ -82,6 +92,9 @@ allOf: + minItems: 2 + maxItems: 2 + ++ st,lsco: ++ maxItems: 0 ++ + required: + - clock-names + - st,syscfg +@@ -101,6 +114,9 @@ allOf: + assigned-clocks: false + assigned-clock-parents: false + ++ st,lsco: ++ maxItems: 1 ++ + required: + - clock-names + +@@ -129,12 +145,16 @@ examples: + + #include + #include ++ #include + rtc@5c004000 { + compatible = "st,stm32mp1-rtc"; + reg = <0x5c004000 0x400>; + clocks = <&rcc RTCAPB>, <&rcc RTC>; + clock-names = "pclk", "rtc_ck"; + interrupts = ; ++ st,lsco = ; ++ pinctrl-0 = <&rtc_out2_rmp_pins_a>; ++ pinctrl-names = "default"; + }; + ... diff --git a/Documentation/devicetree/bindings/serial/rs485.yaml b/Documentation/devicetree/bindings/serial/rs485.yaml -index 0c9fa694f85c..a2ac9de2d85e 100644 +index 0c9fa694f..a2ac9de2d 100644 --- a/Documentation/devicetree/bindings/serial/rs485.yaml +++ b/Documentation/devicetree/bindings/serial/rs485.yaml @@ -29,6 +29,22 @@ properties: @@ -1208,7 +1535,7 @@ index 0c9fa694f85c..a2ac9de2d85e 100644 description: drive RTS low when sending (default is high). $ref: /schemas/types.yaml#/definitions/flag diff --git a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml -index 06d5f251ec88..d2df06f4d8f9 100644 +index 51f390e5c..ea7d6be6b 100644 --- a/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml +++ b/Documentation/devicetree/bindings/serial/st,stm32-uart.yaml @@ -9,9 +9,6 @@ maintainers: @@ -1221,7 +1548,7 @@ index 06d5f251ec88..d2df06f4d8f9 100644 properties: compatible: enum: -@@ -50,26 +47,54 @@ properties: +@@ -50,26 +47,58 @@ properties: minItems: 1 maxItems: 2 @@ -1267,6 +1594,10 @@ index 06d5f251ec88..d2df06f4d8f9 100644 + enum: [1, 2, 4, 8, 12, 14, 16] + default: 8 + ++ power-domains: ++ $ref: ../power/power-domain.yaml ++ maxItems: 1 ++ +allOf: + - $ref: rs485.yaml + @@ -1288,7 +1619,7 @@ index 06d5f251ec88..d2df06f4d8f9 100644 required: - compatible -@@ -82,6 +107,26 @@ additionalProperties: false +@@ -83,6 +112,26 @@ additionalProperties: examples: - | #include @@ -1317,7 +1648,7 @@ index 06d5f251ec88..d2df06f4d8f9 100644 reg = <0x40011000 0x400>; diff --git a/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt new file mode 100644 -index 000000000000..e2bd82f4980e +index 000000000..e2bd82f49 --- /dev/null +++ b/Documentation/devicetree/bindings/soc/stm32/stm32_hdp.txt @@ -0,0 +1,39 @@ @@ -1362,7 +1693,7 @@ index 000000000000..e2bd82f4980e +}; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt b/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt deleted file mode 100644 -index 864f5b00b031..000000000000 +index 864f5b00b..000000000 --- a/Documentation/devicetree/bindings/sound/st,stm32-adfsdm.txt +++ /dev/null @@ -1,63 +0,0 @@ @@ -1430,7 +1761,7 @@ index 864f5b00b031..000000000000 - }; - }; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml -index f32410890589..6feb5a09c184 100644 +index f32410890..6feb5a09c 100644 --- a/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml +++ b/Documentation/devicetree/bindings/sound/st,stm32-i2s.yaml @@ -54,6 +54,10 @@ properties: @@ -1446,7 +1777,7 @@ index f32410890589..6feb5a09c184 100644 - "#sound-dai-cells" diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt b/Documentation/devicetree/bindings/sound/st,stm32-sai.txt deleted file mode 100644 -index c42b91e525fa..000000000000 +index c42b91e52..000000000 --- a/Documentation/devicetree/bindings/sound/st,stm32-sai.txt +++ /dev/null @@ -1,107 +0,0 @@ @@ -1559,7 +1890,7 @@ index c42b91e525fa..000000000000 -}; diff --git a/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml new file mode 100644 -index 000000000000..6ad48c7681c1 +index 000000000..6ad48c768 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/st,stm32-sai.yaml @@ -0,0 +1,200 @@ @@ -1764,10 +2095,55 @@ index 000000000000..6ad48c7681c1 + +... diff --git a/Documentation/devicetree/bindings/usb/dwc2.yaml b/Documentation/devicetree/bindings/usb/dwc2.yaml -index e5ee51b7b470..5dbe0b723667 100644 +index e5ee51b7b..98e12c5b2 100644 --- a/Documentation/devicetree/bindings/usb/dwc2.yaml +++ b/Documentation/devicetree/bindings/usb/dwc2.yaml -@@ -129,6 +129,10 @@ properties: +@@ -103,10 +103,44 @@ properties: + dr_mode: + enum: [host, peripheral, otg] + ++ otg-rev: ++ description: ++ Tells usb driver the release number of the OTG and EH supplement with ++ which the device and its descriptors are compliant, in binary-coded ++ decimal (i.e. 2.0 is 0200H). This property is used if any real OTG ++ features (HNP/SRP/ADP) is enabled. If ADP is required, otg-rev should be ++ 0x0200 or above. ++ $ref: /schemas/types.yaml#/definitions/uint32 ++ enum: [0x0100, 0x0120, 0x0130, 0x0200] ++ ++ hnp-disable: ++ description: ++ Tells OTG controllers we want to disable OTG HNP. Normally HNP is the ++ basic function of real OTG except you want it to be a srp-capable only B ++ device. ++ type: boolean ++ ++ srp-disable: ++ description: ++ Tells OTG controllers we want to disable OTG SRP. SRP is optional for OTG ++ device. ++ type: boolean ++ ++ adp-disable: ++ description: ++ Tells OTG controllers we want to disable OTG ADP. ADP is optional for OTG ++ device. ++ type: boolean ++ + usb-role-switch: + $ref: /schemas/types.yaml#/definitions/flag + description: Support role switch. + ++ role-switch-default-mode: ++ enum: [host, peripheral] ++ description: indicating if usb-role-switch is enabled, the default operation ++ mode of controller at init. ++ + g-rx-fifo-size: + $ref: /schemas/types.yaml#/definitions/uint32 + description: size of rx fifo size in gadget mode. +@@ -129,6 +163,10 @@ properties: description: If present indicates that we need to reset the PHY when we detect a wakeup. This is due to a hardware errata. @@ -1779,7 +2155,7 @@ index e5ee51b7b470..5dbe0b723667 100644 - compatible - reg diff --git a/Documentation/devicetree/bindings/usb/generic-ehci.yaml b/Documentation/devicetree/bindings/usb/generic-ehci.yaml -index 247ef00381ea..e7647bd1195c 100644 +index 247ef0038..e7647bd11 100644 --- a/Documentation/devicetree/bindings/usb/generic-ehci.yaml +++ b/Documentation/devicetree/bindings/usb/generic-ehci.yaml @@ -91,6 +91,11 @@ properties: @@ -1796,7 +2172,7 @@ index 247ef00381ea..e7647bd1195c 100644 - reg diff --git a/Documentation/devicetree/bindings/usb/st,stusb160x.yaml b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml new file mode 100644 -index 000000000000..9a51efa9d101 +index 000000000..9a51efa9d --- /dev/null +++ b/Documentation/devicetree/bindings/usb/st,stusb160x.yaml @@ -0,0 +1,87 @@ @@ -1888,7 +2264,7 @@ index 000000000000..9a51efa9d101 + }; +... diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile -index ce66ffd5a1bb..4c3ba0468276 100644 +index ce66ffd5a..4c3ba0468 100644 --- a/arch/arm/boot/dts/Makefile +++ b/arch/arm/boot/dts/Makefile @@ -1,4 +1,36 @@ @@ -1958,10 +2334,10 @@ index ce66ffd5a1bb..4c3ba0468276 100644 stm32mp157c-odyssey.dtb dtb-$(CONFIG_MACH_SUN4I) += \ diff --git a/arch/arm/boot/dts/stm32429i-eval.dts b/arch/arm/boot/dts/stm32429i-eval.dts -index 67e7648de41e..7e10ae744c9d 100644 +index 8b0ead46e..9ac1ffe53 100644 --- a/arch/arm/boot/dts/stm32429i-eval.dts +++ b/arch/arm/boot/dts/stm32429i-eval.dts -@@ -188,6 +188,7 @@ +@@ -186,6 +186,7 @@ port { dcmi_0: endpoint { remote-endpoint = <&ov2640_0>; @@ -1970,10 +2346,10 @@ index 67e7648de41e..7e10ae744c9d 100644 hsync-active = <0>; vsync-active = <0>; diff --git a/arch/arm/boot/dts/stm32f746.dtsi b/arch/arm/boot/dts/stm32f746.dtsi -index 640ff54ed00c..2e69f1bb84ef 100644 +index d49e481b3..cebee29c5 100644 --- a/arch/arm/boot/dts/stm32f746.dtsi +++ b/arch/arm/boot/dts/stm32f746.dtsi -@@ -349,6 +349,7 @@ +@@ -345,6 +345,7 @@ clocks = <&rcc 1 CLK_I2C1>; #address-cells = <1>; #size-cells = <0>; @@ -1981,7 +2357,7 @@ index 640ff54ed00c..2e69f1bb84ef 100644 status = "disabled"; }; -@@ -361,6 +362,7 @@ +@@ -357,6 +358,7 @@ clocks = <&rcc 1 CLK_I2C2>; #address-cells = <1>; #size-cells = <0>; @@ -1989,7 +2365,7 @@ index 640ff54ed00c..2e69f1bb84ef 100644 status = "disabled"; }; -@@ -373,6 +375,7 @@ +@@ -369,6 +371,7 @@ clocks = <&rcc 1 CLK_I2C3>; #address-cells = <1>; #size-cells = <0>; @@ -1997,7 +2373,7 @@ index 640ff54ed00c..2e69f1bb84ef 100644 status = "disabled"; }; -@@ -385,6 +388,7 @@ +@@ -381,6 +384,7 @@ clocks = <&rcc 1 CLK_I2C4>; #address-cells = <1>; #size-cells = <0>; @@ -2006,7 +2382,7 @@ index 640ff54ed00c..2e69f1bb84ef 100644 }; diff --git a/arch/arm/boot/dts/stm32h743.dtsi b/arch/arm/boot/dts/stm32h743.dtsi -index 7febe19e780d..078b078297ae 100644 +index 1579707ea..7e74250f4 100644 --- a/arch/arm/boot/dts/stm32h743.dtsi +++ b/arch/arm/boot/dts/stm32h743.dtsi @@ -144,6 +144,7 @@ @@ -2043,7 +2419,7 @@ index 7febe19e780d..078b078297ae 100644 diff --git a/arch/arm/boot/dts/stm32mp15-m4-srm-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-m4-srm-pinctrl.dtsi new file mode 100644 -index 000000000000..b4030e5c9422 +index 000000000..b4030e5c9 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15-m4-srm-pinctrl.dtsi @@ -0,0 +1,524 @@ @@ -2573,10 +2949,10 @@ index 000000000000..b4030e5c9422 +}; diff --git a/arch/arm/boot/dts/stm32mp15-m4-srm.dtsi b/arch/arm/boot/dts/stm32mp15-m4-srm.dtsi new file mode 100644 -index 000000000000..60454aee4123 +index 000000000..3162c3595 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15-m4-srm.dtsi -@@ -0,0 +1,442 @@ +@@ -0,0 +1,448 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -2756,7 +3132,7 @@ index 000000000000..60454aee4123 + reg = <0x40016000 0x400>; + interrupt-parent = <&exti>; + interrupts = <69 1>; -+ clocks = <&rcc CEC_K>, <&scmi0_clk CK_SCMI0_LSE>; ++ clocks = <&rcc CEC_K>, <&rcc CEC>; + clock-names = "cec", "hdmi-cec"; + status = "disabled"; + }; @@ -2994,6 +3370,12 @@ index 000000000000..60454aee4123 + clocks = <&rcc SAI4_K>; + clock-names = "sai_ck"; + status = "disabled"; ++ }; ++ m4_fmc: memory-controller@58002000 { ++ compatible = "rproc-srm-dev"; ++ reg = <0x5800200 0x1000>; ++ clocks = <&rcc FMC_K>; ++ status = "disabled"; + }; + m4_qspi: qspi@58003000 { + compatible = "rproc-srm-dev"; @@ -3021,10 +3403,10 @@ index 000000000000..60454aee4123 + diff --git a/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi b/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi new file mode 100644 -index 000000000000..94a10b86a179 +index 000000000..c7d2d7c8f --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15-no-scmi.dtsi -@@ -0,0 +1,157 @@ +@@ -0,0 +1,153 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2020 - All Rights Reserved @@ -3106,10 +3488,6 @@ index 000000000000..94a10b86a179 + resets = <&rcc MCU_R>, <&rcc MCU_HOLD_BOOT_R>; + + m4_system_resources { -+ m4_cec: cec@40016000 { -+ clocks = <&rcc CEC_K>, <&rcc CK_LSE>; -+ }; -+ + m4_m_can1: can@4400e000 { + clocks = <&rcc CK_HSE>, <&rcc FDCAN_K>; + }; @@ -3128,8 +3506,8 @@ index 000000000000..94a10b86a179 + /delete-node/ sram@2ffff000; +}; + -+&cec { -+ clocks = <&rcc CEC_K>, <&clk_lse>; ++&bsec { ++ clocks = <&rcc BSEC>; +}; + +&gpioz { @@ -3183,7 +3561,7 @@ index 000000000000..94a10b86a179 + clocks = <&rcc USART1_K>; +}; diff --git a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi -index d84686e00370..a0b76e238c18 100644 +index dee4d32ab..236d77e09 100644 --- a/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi +++ b/arch/arm/boot/dts/stm32mp15-pinctrl.dtsi @@ -118,6 +118,45 @@ @@ -3449,41 +3827,25 @@ index d84686e00370..a0b76e238c18 100644 usart2_pins_a: usart2-0 { pins1 { pinmux = , /* USART2_TX */ -@@ -1806,10 +1949,15 @@ - usart2_idle_pins_c: usart2-idle-2 { - pins1 { - pinmux = , /* USART2_TX */ -- , /* USART2_RTS */ - ; /* USART2_CTS_NSS */ - }; - pins2 { -+ pinmux = ; /* USART2_RTS */ -+ bias-disable; -+ drive-push-pull; -+ slew-rate = <3>; -+ }; -+ pins3 { - pinmux = ; /* USART2_RX */ +@@ -1794,7 +1937,7 @@ + ; /* USART2_RTS */ bias-disable; - }; -@@ -1855,10 +2003,15 @@ - usart3_idle_pins_b: usart3-idle-1 { - pins1 { - pinmux = , /* USART3_TX */ -- , /* USART3_RTS */ - ; /* USART3_CTS_NSS */ - }; - pins2 { -+ pinmux = ; /* USART3_RTS */ -+ bias-disable; -+ drive-push-pull; + drive-push-pull; +- slew-rate = <3>; + slew-rate = <0>; -+ }; -+ pins3 { - pinmux = ; /* USART3_RX */ - bias-disable; }; -@@ -1884,19 +2037,24 @@ + pins2 { + pinmux = , /* USART2_RX */ +@@ -1812,7 +1955,7 @@ + pinmux = ; /* USART2_RTS */ + bias-disable; + drive-push-pull; +- slew-rate = <3>; ++ slew-rate = <0>; + }; + pins3 { + pinmux = ; /* USART2_RX */ +@@ -1894,7 +2037,7 @@ pins2 { pinmux = , /* USART3_RX */ ; /* USART3_CTS_NSS */ @@ -3492,26 +3854,16 @@ index d84686e00370..a0b76e238c18 100644 }; }; - usart3_idle_pins_c: usart3-idle-2 { - pins1 { - pinmux = , /* USART3_TX */ -- , /* USART3_RTS */ - ; /* USART3_CTS_NSS */ +@@ -1911,7 +2054,7 @@ }; - pins2 { -- pinmux = ; /* USART3_RX */ -+ pinmux = ; /* USART3_RTS */ - bias-disable; -+ drive-push-pull; -+ slew-rate = <0>; -+ }; -+ pins3 { -+ pinmux = ; /* USART3_RX */ + pins3 { + pinmux = ; /* USART3_RX */ +- bias-disable; + bias-pull-up; }; }; -@@ -1970,4 +2128,12 @@ +@@ -1985,4 +2128,12 @@ bias-disable; }; }; @@ -3525,7 +3877,7 @@ index d84686e00370..a0b76e238c18 100644 + }; }; diff --git a/arch/arm/boot/dts/stm32mp151.dtsi b/arch/arm/boot/dts/stm32mp151.dtsi -index 84757901cd8d..ca71139f3ad4 100644 +index b479016fe..ab5723c47 100644 --- a/arch/arm/boot/dts/stm32mp151.dtsi +++ b/arch/arm/boot/dts/stm32mp151.dtsi @@ -5,7 +5,10 @@ @@ -4000,7 +4352,7 @@ index 84757901cd8d..ca71139f3ad4 100644 reg = <0x40016000 0x400>; interrupts = ; - clocks = <&rcc CEC_K>, <&clk_lse>; -+ clocks = <&rcc CEC_K>, <&scmi0_clk CK_SCMI0_LSE>; ++ clocks = <&rcc CEC_K>, <&rcc CEC>; clock-names = "cec", "hdmi-cec"; status = "disabled"; }; @@ -4267,16 +4619,18 @@ index 84757901cd8d..ca71139f3ad4 100644 dma-names = "rx"; status = "disabled"; }; -@@ -1039,7 +1179,7 @@ +@@ -1039,15 +1179,17 @@ reg = <0x100>; interrupt-parent = <&adc>; interrupts = <1>; - dmas = <&dmamux1 10 0x400 0x01>; + dmas = <&dmamux1 10 0x400 0x80000001>; dma-names = "rx"; ++ nvmem-cells = <&vrefint>; ++ nvmem-cell-names = "vrefint"; status = "disabled"; }; -@@ -1047,7 +1187,7 @@ + }; sdmmc3: sdmmc@48004000 { compatible = "arm,pl18x", "arm,primecell"; @@ -4285,7 +4639,7 @@ index 84757901cd8d..ca71139f3ad4 100644 reg = <0x48004000 0x400>; interrupts = ; interrupt-names = "cmd_irq"; -@@ -1067,27 +1207,37 @@ +@@ -1067,27 +1209,38 @@ clock-names = "otg"; resets = <&rcc USBO_R>; reset-names = "dwc2"; @@ -4297,6 +4651,7 @@ index 84757901cd8d..ca71139f3ad4 100644 - g-tx-fifo-size = <128 128 64 64 64 64 32 32>; + g-tx-fifo-size = <256 16 16 16 16 16 16 16>; dr_mode = "otg"; ++ otg-rev = <0x200>; usb33d-supply = <&usb33>; + power-domains = <&pd_core>; + wakeup-source; @@ -4330,7 +4685,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1098,21 +1248,30 @@ +@@ -1098,21 +1251,31 @@ resets = <&rcc CAMITF_R>; clocks = <&rcc DCMI>; clock-names = "mclk"; @@ -4354,6 +4709,7 @@ index 84757901cd8d..ca71139f3ad4 100644 + <&scmi0_clk CK_SCMI0_CSI>, + <&scmi0_clk CK_SCMI0_LSE>, + <&scmi0_clk CK_SCMI0_LSI>; ++ clocks-boot-on = ; }; pwr_regulators: pwr@50001000 { @@ -4363,7 +4719,7 @@ index 84757901cd8d..ca71139f3ad4 100644 reg11: reg11 { regulator-name = "reg11"; -@@ -1138,11 +1297,38 @@ +@@ -1138,11 +1301,38 @@ reg = <0x50001014 0x4>; }; @@ -4402,7 +4758,7 @@ index 84757901cd8d..ca71139f3ad4 100644 }; syscfg: syscon@50020000 { -@@ -1156,8 +1342,11 @@ +@@ -1156,8 +1346,11 @@ #size-cells = <0>; compatible = "st,stm32-lptimer"; reg = <0x50021000 0x400>; @@ -4414,7 +4770,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; pwm { -@@ -1176,6 +1365,11 @@ +@@ -1176,6 +1369,11 @@ compatible = "st,stm32-lptimer-counter"; status = "disabled"; }; @@ -4426,7 +4782,7 @@ index 84757901cd8d..ca71139f3ad4 100644 }; lptimer3: timer@50022000 { -@@ -1183,8 +1377,11 @@ +@@ -1183,8 +1381,11 @@ #size-cells = <0>; compatible = "st,stm32-lptimer"; reg = <0x50022000 0x400>; @@ -4438,7 +4794,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; pwm { -@@ -1198,13 +1395,21 @@ +@@ -1198,13 +1399,21 @@ reg = <2>; status = "disabled"; }; @@ -4460,7 +4816,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; pwm { -@@ -1212,13 +1417,21 @@ +@@ -1212,13 +1421,21 @@ #pwm-cells = <3>; status = "disabled"; }; @@ -4482,7 +4838,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; pwm { -@@ -1226,6 +1439,11 @@ +@@ -1226,6 +1443,11 @@ #pwm-cells = <3>; status = "disabled"; }; @@ -4494,7 +4850,7 @@ index 84757901cd8d..ca71139f3ad4 100644 }; vrefbuf: vrefbuf@50025000 { -@@ -1250,7 +1468,7 @@ +@@ -1250,7 +1472,7 @@ sai4a: audio-controller@50027004 { #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-a"; @@ -4503,7 +4859,7 @@ index 84757901cd8d..ca71139f3ad4 100644 clocks = <&rcc SAI4_K>; clock-names = "sai_ck"; dmas = <&dmamux1 99 0x400 0x01>; -@@ -1260,7 +1478,7 @@ +@@ -1260,7 +1482,7 @@ sai4b: audio-controller@50027024 { #sound-dai-cells = <0>; compatible = "st,stm32-sai-sub-b"; @@ -4512,7 +4868,7 @@ index 84757901cd8d..ca71139f3ad4 100644 clocks = <&rcc SAI4_K>; clock-names = "sai_ck"; dmas = <&dmamux1 100 0x400 0x01>; -@@ -1278,13 +1496,21 @@ +@@ -1278,13 +1500,21 @@ status = "disabled"; }; @@ -4537,7 +4893,7 @@ index 84757901cd8d..ca71139f3ad4 100644 dma-names = "in"; dma-maxburst = <2>; status = "disabled"; -@@ -1293,8 +1519,8 @@ +@@ -1293,8 +1523,8 @@ rng1: rng@54003000 { compatible = "st,stm32-rng"; reg = <0x54003000 0x400>; @@ -4548,7 +4904,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1303,8 +1529,8 @@ +@@ -1303,8 +1533,8 @@ reg = <0x58000000 0x1000>; interrupts = ; clocks = <&rcc MDMA>; @@ -4559,7 +4915,7 @@ index 84757901cd8d..ca71139f3ad4 100644 dma-channels = <32>; dma-requests = <48>; }; -@@ -1335,9 +1561,9 @@ +@@ -1335,9 +1565,9 @@ <4 0x09010000 0x1000>, <4 0x09020000 0x1000>; interrupts = ; @@ -4572,18 +4928,18 @@ index 84757901cd8d..ca71139f3ad4 100644 dma-names = "tx", "rx", "ecc"; status = "disabled"; }; -@@ -1348,8 +1574,8 @@ +@@ -1348,8 +1578,8 @@ reg = <0x58003000 0x1000>, <0x70000000 0x10000000>; reg-names = "qspi", "qspi_mm"; interrupts = ; - dmas = <&mdma1 22 0x10 0x100002 0x0 0x0>, - <&mdma1 22 0x10 0x100008 0x0 0x0>; -+ dmas = <&mdma1 22 0x2 0x100002 0x0 0x0 0x0>, -+ <&mdma1 22 0x2 0x100008 0x0 0x0 0x0>; ++ dmas = <&mdma1 22 0x2 0x10100002 0x0 0x0 0x0>, ++ <&mdma1 22 0x2 0x10100008 0x0 0x0 0x0>; dma-names = "tx", "rx"; clocks = <&rcc QSPI_K>; resets = <&rcc QSPI_R>; -@@ -1360,7 +1586,7 @@ +@@ -1360,7 +1590,7 @@ sdmmc1: sdmmc@58005000 { compatible = "arm,pl18x", "arm,primecell"; @@ -4592,7 +4948,7 @@ index 84757901cd8d..ca71139f3ad4 100644 reg = <0x58005000 0x1000>; interrupts = ; interrupt-names = "cmd_irq"; -@@ -1375,7 +1601,7 @@ +@@ -1375,7 +1605,7 @@ sdmmc2: sdmmc@58007000 { compatible = "arm,pl18x", "arm,primecell"; @@ -4601,7 +4957,7 @@ index 84757901cd8d..ca71139f3ad4 100644 reg = <0x58007000 0x1000>; interrupts = ; interrupt-names = "cmd_irq"; -@@ -1405,8 +1631,10 @@ +@@ -1399,24 +1629,29 @@ compatible = "st,stm32mp1-dwmac", "snps,dwmac-4.20a"; reg = <0x5800a000 0x2000>; reg-names = "stmmaceth"; @@ -4614,15 +4970,37 @@ index 84757901cd8d..ca71139f3ad4 100644 clock-names = "stmmaceth", "mac-clk-tx", "mac-clk-rx", -@@ -1423,6 +1651,7 @@ + "eth-ck", +- "ethstp"; ++ "ethstp", ++ "ptp_ref"; + clocks = <&rcc ETHMAC>, + <&rcc ETHTX>, + <&rcc ETHRX>, + <&rcc ETHCK_K>, +- <&rcc ETHSTP>; ++ <&rcc ETHSTP>, ++ <&rcc ETHPTP_K>; + st,syscon = <&syscfg 0x4>; + snps,mixed-burst; + snps,pbl = <2>; snps,en-tx-lpi-clockgating; snps,axi-config = <&stmmac_axi_config_0>; snps,tso; + power-domains = <&pd_core>; status = "disabled"; - }; -@@ -1440,8 +1669,10 @@ + stmmac_axi_config_0: stmmac-axi-config { +@@ -1429,7 +1664,7 @@ + usbh_ohci: usbh-ohci@5800c000 { + compatible = "generic-ohci"; + reg = <0x5800c000 0x1000>; +- clocks = <&rcc USBH>; ++ clocks = <&rcc USBH>, <&usbphyc>; + resets = <&rcc USBH_R>; + interrupts = ; + status = "disabled"; +@@ -1440,8 +1675,10 @@ reg = <0x5800d000 0x1000>; clocks = <&rcc USBH>; resets = <&rcc USBH_R>; @@ -4634,7 +5012,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1464,7 +1695,7 @@ +@@ -1464,7 +1701,7 @@ iwdg2: watchdog@5a002000 { compatible = "st,stm32mp1-iwdg"; reg = <0x5a002000 0x400>; @@ -4643,7 +5021,7 @@ index 84757901cd8d..ca71139f3ad4 100644 clock-names = "pclk", "lsi"; status = "disabled"; }; -@@ -1472,10 +1703,13 @@ +@@ -1472,10 +1709,13 @@ usbphyc: usbphyc@5a006000 { #address-cells = <1>; #size-cells = <0>; @@ -4657,7 +5035,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; usbphyc_port0: usb-phy@0 { -@@ -1489,11 +1723,21 @@ +@@ -1489,11 +1729,22 @@ }; }; @@ -4666,6 +5044,7 @@ index 84757901cd8d..ca71139f3ad4 100644 + reg = <0x5a007000 0x400>; + clocks = <&rcc DDRPERFM>; + resets = <&rcc DDRPERFM_R>; ++ status = "disabled"; + }; + usart1: serial@5c000000 { @@ -4681,7 +5060,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1503,11 +1747,12 @@ +@@ -1503,11 +1754,12 @@ compatible = "st,stm32h7-spi"; reg = <0x5c001000 0x400>; interrupts = ; @@ -4698,7 +5077,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1515,23 +1760,29 @@ +@@ -1515,51 +1767,72 @@ compatible = "st,stm32mp15-i2c"; reg = <0x5c002000 0x400>; interrupt-names = "event", "error"; @@ -4734,12 +5113,17 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1540,26 +1791,37 @@ + bsec: efuse@5c005000 { + compatible = "st,stm32mp15-bsec"; reg = <0x5c005000 0x400>; ++ clocks = <&scmi0_clk CK_SCMI0_BSEC>; #address-cells = <1>; #size-cells = <1>; + part_number_otp: part_number_otp@4 { + reg = <0x4 0x1>; ++ }; ++ vrefint: calib@52 { ++ reg = <0x52 0x2>; + }; ts_cal1: calib@5c { reg = <0x5c 0x2>; @@ -4776,7 +5160,7 @@ index 84757901cd8d..ca71139f3ad4 100644 status = "disabled"; }; -@@ -1574,6 +1836,7 @@ +@@ -1574,6 +1847,7 @@ ranges = <0 0x50002000 0xa400>; interrupt-parent = <&exti>; st,syscfg = <&exti 0x60 0xff>; @@ -4784,7 +5168,7 @@ index 84757901cd8d..ca71139f3ad4 100644 pins-are-numbered; gpioa: gpio@50002000 { -@@ -1706,6 +1969,7 @@ +@@ -1706,6 +1980,7 @@ pins-are-numbered; interrupt-parent = <&exti>; st,syscfg = <&exti 0x60 0xff>; @@ -4792,7 +5176,7 @@ index 84757901cd8d..ca71139f3ad4 100644 gpioz: gpio@54004000 { gpio-controller; -@@ -1713,12 +1977,30 @@ +@@ -1713,12 +1988,30 @@ interrupt-controller; #interrupt-cells = <2>; reg = <0 0x400>; @@ -4824,7 +5208,7 @@ index 84757901cd8d..ca71139f3ad4 100644 }; mlahb: ahb { -@@ -1735,11 +2017,18 @@ +@@ -1735,11 +2028,18 @@ reg = <0x10000000 0x40000>, <0x30000000 0x40000>, <0x38000000 0x10000>; @@ -4847,7 +5231,7 @@ index 84757901cd8d..ca71139f3ad4 100644 }; }; diff --git a/arch/arm/boot/dts/stm32mp153.dtsi b/arch/arm/boot/dts/stm32mp153.dtsi -index 1c1889b194cf..cf16b843c6b5 100644 +index 1c1889b19..cf16b843c 100644 --- a/arch/arm/boot/dts/stm32mp153.dtsi +++ b/arch/arm/boot/dts/stm32mp153.dtsi @@ -10,9 +10,11 @@ @@ -4882,7 +5266,7 @@ index 1c1889b194cf..cf16b843c6b5 100644 bosch,mram-cfg = <0x1400 0 0 32 0 0 2 2>; status = "disabled"; diff --git a/arch/arm/boot/dts/stm32mp157.dtsi b/arch/arm/boot/dts/stm32mp157.dtsi -index 54e73ccea446..8a34964b9d79 100644 +index 54e73ccea..8a34964b9 100644 --- a/arch/arm/boot/dts/stm32mp157.dtsi +++ b/arch/arm/boot/dts/stm32mp157.dtsi @@ -20,7 +20,8 @@ @@ -4896,7 +5280,7 @@ index 54e73ccea446..8a34964b9d79 100644 resets = <&rcc DSI_R>; reset-names = "apb"; diff --git a/arch/arm/boot/dts/stm32mp157a-dk1.dts b/arch/arm/boot/dts/stm32mp157a-dk1.dts -index 4c8be9c8eb20..f415e581a63c 100644 +index 4c8be9c8e..f48207dad 100644 --- a/arch/arm/boot/dts/stm32mp157a-dk1.dts +++ b/arch/arm/boot/dts/stm32mp157a-dk1.dts @@ -7,6 +7,7 @@ @@ -4907,17 +5291,23 @@ index 4c8be9c8eb20..f415e581a63c 100644 #include "stm32mp15-pinctrl.dtsi" #include "stm32mp15xxac-pinctrl.dtsi" #include "stm32mp15xx-dkx.dtsi" -@@ -16,7 +17,6 @@ +@@ -15,13 +16,6 @@ + model = "STMicroelectronics STM32MP157A-DK1 Discovery Board"; compatible = "st,stm32mp157a-dk1", "st,stm32mp157"; - aliases { +- aliases { - ethernet0 = ðernet0; - serial0 = &uart4; - serial1 = &usart3; - serial2 = &uart7; +- serial0 = &uart4; +- serial1 = &usart3; +- serial2 = &uart7; +- }; +- + chosen { + stdout-path = "serial0:115200n8"; + }; diff --git a/arch/arm/boot/dts/stm32mp157a-ed1.dts b/arch/arm/boot/dts/stm32mp157a-ed1.dts new file mode 100644 -index 000000000000..0213ca5c17fa +index 000000000..0213ca5c1 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-ed1.dts @@ -0,0 +1,32 @@ @@ -4955,10 +5345,10 @@ index 000000000000..0213ca5c17fa +}; diff --git a/arch/arm/boot/dts/stm32mp157a-ev1.dts b/arch/arm/boot/dts/stm32mp157a-ev1.dts new file mode 100644 -index 000000000000..11bd88a82f05 +index 000000000..85c73a916 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157a-ev1.dts -@@ -0,0 +1,88 @@ +@@ -0,0 +1,83 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -4976,11 +5366,6 @@ index 000000000000..11bd88a82f05 + chosen { + stdout-path = "serial0:115200n8"; + }; -+ -+ aliases { -+ serial0 = &uart4; -+ serial1 = &usart3; -+ }; +}; + +<dc { @@ -5049,7 +5434,7 @@ index 000000000000..11bd88a82f05 +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts new file mode 100644 -index 000000000000..372ceb2c7128 +index 000000000..372ceb2c7 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2-a7-examples.dts @@ -0,0 +1,60 @@ @@ -5115,7 +5500,7 @@ index 000000000000..372ceb2c7128 +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts new file mode 100644 -index 000000000000..14eac740d4e3 +index 000000000..14eac740d --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-dk2-m4-examples.dts @@ -0,0 +1,129 @@ @@ -5249,10 +5634,10 @@ index 000000000000..14eac740d4e3 + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-dk2.dts b/arch/arm/boot/dts/stm32mp157c-dk2.dts -index 045636555ddd..1c894f288c66 100644 +index 045636555..53d75e1c2 100644 --- a/arch/arm/boot/dts/stm32mp157c-dk2.dts +++ b/arch/arm/boot/dts/stm32mp157c-dk2.dts -@@ -11,13 +11,13 @@ +@@ -11,27 +11,32 @@ #include "stm32mp15-pinctrl.dtsi" #include "stm32mp15xxac-pinctrl.dtsi" #include "stm32mp15xx-dkx.dtsi" @@ -5264,10 +5649,12 @@ index 045636555ddd..1c894f288c66 100644 aliases { - ethernet0 = ðernet0; - serial0 = &uart4; - serial1 = &usart3; - serial2 = &uart7; -@@ -27,11 +27,19 @@ +- serial0 = &uart4; +- serial1 = &usart3; +- serial2 = &uart7; + serial3 = &usart2; + }; + chosen { stdout-path = "serial0:115200n8"; }; @@ -5288,7 +5675,7 @@ index 045636555ddd..1c894f288c66 100644 ports { port@0 { -@@ -49,7 +57,7 @@ +@@ -49,7 +54,7 @@ }; }; @@ -5297,7 +5684,7 @@ index 045636555ddd..1c894f288c66 100644 compatible = "orisetech,otm8009a"; reg = <0>; reset-gpios = <&gpioe 4 GPIO_ACTIVE_LOW>; -@@ -65,6 +73,18 @@ +@@ -65,6 +70,18 @@ }; &i2c1 { @@ -5316,7 +5703,7 @@ index 045636555ddd..1c894f288c66 100644 touchscreen@38 { compatible = "focaltech,ft6236"; reg = <0x38>; -@@ -73,6 +93,8 @@ +@@ -73,6 +90,8 @@ interrupt-controller; touchscreen-size-x = <480>; touchscreen-size-y = <800>; @@ -5325,7 +5712,7 @@ index 045636555ddd..1c894f288c66 100644 status = "okay"; }; }; -@@ -88,10 +110,48 @@ +@@ -88,10 +107,48 @@ }; }; @@ -5376,7 +5763,7 @@ index 045636555ddd..1c894f288c66 100644 + }; }; diff --git a/arch/arm/boot/dts/stm32mp157c-ed1.dts b/arch/arm/boot/dts/stm32mp157c-ed1.dts -index 2e77ccec3fc1..d2c24803b99e 100644 +index 2e77ccec3..d2c24803b 100644 --- a/arch/arm/boot/dts/stm32mp157c-ed1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ed1.dts @@ -1,7 +1,7 @@ @@ -5778,7 +6165,7 @@ index 2e77ccec3fc1..d2c24803b99e 100644 -}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts new file mode 100644 -index 000000000000..8a4eda70d452 +index 000000000..b729b334f --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1-a7-examples.dts @@ -0,0 +1,57 @@ @@ -5809,7 +6196,7 @@ index 000000000000..8a4eda70d452 + button@1 { + label = "PA13"; + linux,code = ; -+ interrupts-extended = <&gpioa 13 IRQ_TYPE_EDGE_FALLING>; ++ gpios = <&gpioa 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + wakeup-source; + }; @@ -5841,7 +6228,7 @@ index 000000000000..8a4eda70d452 +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts new file mode 100644 -index 000000000000..b1bb38efbfa8 +index 000000000..b1bb38efb --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157c-ev1-m4-examples.dts @@ -0,0 +1,146 @@ @@ -5992,7 +6379,7 @@ index 000000000000..b1bb38efbfa8 + status = "disabled"; +}; diff --git a/arch/arm/boot/dts/stm32mp157c-ev1.dts b/arch/arm/boot/dts/stm32mp157c-ev1.dts -index a55e80ce2602..e84897ef4443 100644 +index a55e80ce2..3dd124412 100644 --- a/arch/arm/boot/dts/stm32mp157c-ev1.dts +++ b/arch/arm/boot/dts/stm32mp157c-ev1.dts @@ -1,13 +1,12 @@ @@ -6012,13 +6399,17 @@ index a55e80ce2602..e84897ef4443 100644 / { model = "STMicroelectronics STM32MP157C eval daughter on eval mother"; -@@ -20,89 +19,29 @@ - aliases { - serial0 = &uart4; - serial1 = &usart3; -- ethernet0 = ðernet0; +@@ -16,93 +15,28 @@ + chosen { + stdout-path = "serial0:115200n8"; }; - +- aliases { +- serial0 = &uart4; +- serial1 = &usart3; +- ethernet0 = ðernet0; +- }; +- - clocks { - clk_ext_camera: clk-ext-camera { - #clock-cells = <0>; @@ -6111,7 +6502,7 @@ index a55e80ce2602..e84897ef4443 100644 port@0 { reg = <0>; dsi_in: endpoint { -@@ -118,7 +57,7 @@ +@@ -118,7 +52,7 @@ }; }; @@ -6120,7 +6511,7 @@ index a55e80ce2602..e84897ef4443 100644 compatible = "raydium,rm68200"; reg = <0>; reset-gpios = <&gpiof 15 GPIO_ACTIVE_LOW>; -@@ -134,243 +73,16 @@ +@@ -134,243 +68,16 @@ }; }; @@ -6300,16 +6691,10 @@ index a55e80ce2602..e84897ef4443 100644 - status = "okay"; - }; - timer@1 { -+ gt9147: goodix_ts@5d { -+ compatible = "goodix,gt9147"; -+ reg = <0x5d>; -+ panel = <&panel_dsi>; -+ pinctrl-0 = <&goodix_pins>; -+ pinctrl-names = "default"; - status = "okay"; +- status = "okay"; - }; -}; - +- -&timers8 { - /delete-property/dmas; - /delete-property/dma-names; @@ -6321,12 +6706,16 @@ index a55e80ce2602..e84897ef4443 100644 - status = "okay"; - }; - timer@7 { -- status = "okay"; -+ interrupts = <14 IRQ_TYPE_EDGE_RISING>; -+ interrupt-parent = <&stmfx_pinctrl>; - }; - }; -- ++ gt9147: goodix_ts@5d { ++ compatible = "goodix,gt9147"; ++ reg = <0x5d>; ++ panel = <&panel_dsi>; ++ pinctrl-0 = <&goodix_pins>; ++ pinctrl-names = "default"; + status = "okay"; +- }; +-}; + -&timers12 { - /delete-property/dmas; - /delete-property/dma-names; @@ -6339,8 +6728,10 @@ index a55e80ce2602..e84897ef4443 100644 - }; - timer@11 { - status = "okay"; -- }; --}; ++ interrupts = <14 IRQ_TYPE_EDGE_RISING>; ++ interrupt-parent = <&stmfx_pinctrl>; + }; + }; - -&usart3 { - pinctrl-names = "default", "sleep", "idle"; @@ -6374,10 +6765,10 @@ index a55e80ce2602..e84897ef4443 100644 -}; diff --git a/arch/arm/boot/dts/stm32mp157d-dk1.dts b/arch/arm/boot/dts/stm32mp157d-dk1.dts new file mode 100644 -index 000000000000..bcc012cfff7c +index 000000000..d54dcf16a --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157d-dk1.dts -@@ -0,0 +1,28 @@ +@@ -0,0 +1,22 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -6396,19 +6787,13 @@ index 000000000000..bcc012cfff7c + model = "STMicroelectronics STM32MP157D-DK1 Discovery Board"; + compatible = "st,stm32mp157d-dk1", "st,stm32mp157"; + -+ aliases { -+ serial0 = &uart4; -+ serial1 = &usart3; -+ serial2 = &uart7; -+ }; -+ + chosen { + stdout-path = "serial0:115200n8"; + }; +}; diff --git a/arch/arm/boot/dts/stm32mp157d-ed1.dts b/arch/arm/boot/dts/stm32mp157d-ed1.dts new file mode 100644 -index 000000000000..5aa383d3b585 +index 000000000..5aa383d3b --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157d-ed1.dts @@ -0,0 +1,33 @@ @@ -6447,10 +6832,10 @@ index 000000000000..5aa383d3b585 +}; diff --git a/arch/arm/boot/dts/stm32mp157d-ev1.dts b/arch/arm/boot/dts/stm32mp157d-ev1.dts new file mode 100644 -index 000000000000..5cb08c707990 +index 000000000..dbb2b3e05 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157d-ev1.dts -@@ -0,0 +1,88 @@ +@@ -0,0 +1,83 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -6468,11 +6853,6 @@ index 000000000000..5cb08c707990 + chosen { + stdout-path = "serial0:115200n8"; + }; -+ -+ aliases { -+ serial0 = &uart4; -+ serial1 = &usart3; -+ }; +}; + +<dc { @@ -6541,7 +6921,7 @@ index 000000000000..5cb08c707990 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts b/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts new file mode 100644 -index 000000000000..8dcb52fedb22 +index 000000000..8dcb52fed --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-dk2-a7-examples.dts @@ -0,0 +1,60 @@ @@ -6607,7 +6987,7 @@ index 000000000000..8dcb52fedb22 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts b/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts new file mode 100644 -index 000000000000..72652299743b +index 000000000..726522997 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-dk2-m4-examples.dts @@ -0,0 +1,129 @@ @@ -6742,10 +7122,10 @@ index 000000000000..72652299743b +}; diff --git a/arch/arm/boot/dts/stm32mp157f-dk2.dts b/arch/arm/boot/dts/stm32mp157f-dk2.dts new file mode 100644 -index 000000000000..15a397c4cf5d +index 000000000..1244ae184 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-dk2.dts -@@ -0,0 +1,157 @@ +@@ -0,0 +1,154 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -6766,9 +7146,6 @@ index 000000000000..15a397c4cf5d + compatible = "st,stm32mp157f-dk2", "st,stm32mp157"; + + aliases { -+ serial0 = &uart4; -+ serial1 = &usart3; -+ serial2 = &uart7; + serial3 = &usart2; + }; + @@ -6905,7 +7282,7 @@ index 000000000000..15a397c4cf5d +}; diff --git a/arch/arm/boot/dts/stm32mp157f-ed1.dts b/arch/arm/boot/dts/stm32mp157f-ed1.dts new file mode 100644 -index 000000000000..29c6833e2896 +index 000000000..29c6833e2 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ed1.dts @@ -0,0 +1,37 @@ @@ -6948,7 +7325,7 @@ index 000000000000..29c6833e2896 +}; diff --git a/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts b/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts new file mode 100644 -index 000000000000..3d51e48d14fe +index 000000000..cc78697e7 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ev1-a7-examples.dts @@ -0,0 +1,57 @@ @@ -6979,7 +7356,7 @@ index 000000000000..3d51e48d14fe + button@1 { + label = "PA13"; + linux,code = ; -+ interrupts-extended = <&gpioa 13 IRQ_TYPE_EDGE_FALLING>; ++ gpios = <&gpioa 13 (GPIO_ACTIVE_LOW | GPIO_PULL_UP)>; + status = "okay"; + wakeup-source; + }; @@ -7011,7 +7388,7 @@ index 000000000000..3d51e48d14fe +}; diff --git a/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts b/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts new file mode 100644 -index 000000000000..d508be27666a +index 000000000..d508be276 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ev1-m4-examples.dts @@ -0,0 +1,146 @@ @@ -7163,10 +7540,10 @@ index 000000000000..d508be27666a +}; diff --git a/arch/arm/boot/dts/stm32mp157f-ev1.dts b/arch/arm/boot/dts/stm32mp157f-ev1.dts new file mode 100644 -index 000000000000..6fe600f81388 +index 000000000..0ef17cdc6 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp157f-ev1.dts -@@ -0,0 +1,89 @@ +@@ -0,0 +1,84 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2019 - All Rights Reserved @@ -7185,11 +7562,6 @@ index 000000000000..6fe600f81388 + chosen { + stdout-path = "serial0:115200n8"; + }; -+ -+ aliases { -+ serial0 = &uart4; -+ serial1 = &usart3; -+ }; +}; + +<dc { @@ -7258,7 +7630,7 @@ index 000000000000..6fe600f81388 +}; diff --git a/arch/arm/boot/dts/stm32mp15xa.dtsi b/arch/arm/boot/dts/stm32mp15xa.dtsi new file mode 100644 -index 000000000000..5ed7e594f4cd +index 000000000..5ed7e594f --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xa.dtsi @@ -0,0 +1,13 @@ @@ -7276,7 +7648,7 @@ index 000000000000..5ed7e594f4cd + }; +}; diff --git a/arch/arm/boot/dts/stm32mp15xc.dtsi b/arch/arm/boot/dts/stm32mp15xc.dtsi -index b06a55a2fa18..adc1568a7285 100644 +index b06a55a2f..adc1568a7 100644 --- a/arch/arm/boot/dts/stm32mp15xc.dtsi +++ b/arch/arm/boot/dts/stm32mp15xc.dtsi @@ -4,14 +4,16 @@ @@ -7300,7 +7672,7 @@ index b06a55a2fa18..adc1568a7285 100644 }; diff --git a/arch/arm/boot/dts/stm32mp15xd.dtsi b/arch/arm/boot/dts/stm32mp15xd.dtsi new file mode 100644 -index 000000000000..e2f8b1297c33 +index 000000000..e2f8b1297 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xd.dtsi @@ -0,0 +1,42 @@ @@ -7348,7 +7720,7 @@ index 000000000000..e2f8b1297c33 +}; diff --git a/arch/arm/boot/dts/stm32mp15xf.dtsi b/arch/arm/boot/dts/stm32mp15xf.dtsi new file mode 100644 -index 000000000000..77f50b9bda64 +index 000000000..77f50b9bd --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xf.dtsi @@ -0,0 +1,20 @@ @@ -7373,10 +7745,10 @@ index 000000000000..77f50b9bda64 + }; +}; diff --git a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi -index 93398cfae97e..acff8755d308 100644 +index 93398cfae..884c538fc 100644 --- a/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi +++ b/arch/arm/boot/dts/stm32mp15xx-dkx.dtsi -@@ -4,10 +4,16 @@ +@@ -4,10 +4,19 @@ * Author: Alexandre Torgue for STMicroelectronics. */ @@ -7388,12 +7760,28 @@ index 93398cfae97e..acff8755d308 100644 / { + aliases { + ethernet0 = ðernet0; ++ serial0 = &uart4; ++ serial1 = &usart3; ++ serial2 = &uart7; + }; + memory@c0000000 { device_type = "memory"; reg = <0xc0000000 0x20000000>; -@@ -72,7 +78,7 @@ +@@ -42,6 +51,12 @@ + no-map; + }; + ++ mcu_rsc_table: mcu_rsc_table@10048000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10048000 0x8000>; ++ no-map; ++ }; ++ + mcuram: mcuram@30000000 { + compatible = "shared-dma-pool"; + reg = <0x30000000 0x40000>; +@@ -72,7 +87,7 @@ sound { compatible = "audio-graph-card"; @@ -7402,7 +7790,7 @@ index 93398cfae97e..acff8755d308 100644 routing = "Playback" , "MCLK", "Capture" , "MCLK", -@@ -81,6 +87,17 @@ +@@ -81,6 +96,17 @@ status = "okay"; }; @@ -7420,7 +7808,7 @@ index 93398cfae97e..acff8755d308 100644 vin: vin { compatible = "regulator-fixed"; regulator-name = "vin"; -@@ -124,6 +141,26 @@ +@@ -124,6 +150,26 @@ status = "okay"; }; @@ -7447,7 +7835,7 @@ index 93398cfae97e..acff8755d308 100644 &dts { status = "okay"; }; -@@ -136,6 +173,8 @@ +@@ -136,6 +182,8 @@ phy-mode = "rgmii-id"; max-speed = <1000>; phy-handle = <&phy0>; @@ -7456,7 +7844,7 @@ index 93398cfae97e..acff8755d308 100644 mdio0 { #address-cells = <1>; -@@ -151,6 +190,10 @@ +@@ -151,6 +199,10 @@ contiguous-area = <&gpu_reserved>; }; @@ -7467,14 +7855,14 @@ index 93398cfae97e..acff8755d308 100644 &i2c1 { pinctrl-names = "default", "sleep"; pinctrl-0 = <&i2c1_pins_a>; -@@ -238,10 +281,34 @@ +@@ -238,10 +290,34 @@ /delete-property/dmas; /delete-property/dma-names; + stusb1600@28 { + compatible = "st,stusb1600"; + reg = <0x28>; -+ interrupts = <11 IRQ_TYPE_EDGE_FALLING>; ++ interrupts = <11 IRQ_TYPE_LEVEL_LOW>; + interrupt-parent = <&gpioi>; + pinctrl-names = "default"; + pinctrl-0 = <&stusb1600_pins_a>; @@ -7503,7 +7891,7 @@ index 93398cfae97e..acff8755d308 100644 interrupt-controller; #interrupt-cells = <2>; status = "okay"; -@@ -348,23 +415,24 @@ +@@ -348,23 +424,24 @@ vref_ddr: vref_ddr { regulator-name = "vref_ddr"; regulator-always-on; @@ -7533,7 +7921,13 @@ index 93398cfae97e..acff8755d308 100644 }; onkey { -@@ -442,6 +510,7 @@ +@@ -437,11 +514,12 @@ + + &m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, +- <&vdev0vring1>, <&vdev0buffer>; ++ <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; mbox-names = "vq0", "vq1", "shutdown"; interrupt-parent = <&exti>; interrupts = <68 1>; @@ -7541,7 +7935,7 @@ index 93398cfae97e..acff8755d308 100644 status = "okay"; }; -@@ -469,8 +538,6 @@ +@@ -469,8 +547,6 @@ sai2a: audio-controller@4400b004 { #clock-cells = <0>; dma-names = "tx"; @@ -7550,7 +7944,7 @@ index 93398cfae97e..acff8755d308 100644 status = "okay"; sai2a_port: port { -@@ -528,6 +595,27 @@ +@@ -528,6 +604,27 @@ status = "disabled"; }; @@ -7578,7 +7972,7 @@ index 93398cfae97e..acff8755d308 100644 &timers1 { /* spare dmas for other usage */ /delete-property/dmas; -@@ -618,6 +706,8 @@ +@@ -618,6 +715,8 @@ pinctrl-0 = <&uart4_pins_a>; pinctrl-1 = <&uart4_sleep_pins_a>; pinctrl-2 = <&uart4_idle_pins_a>; @@ -7587,7 +7981,7 @@ index 93398cfae97e..acff8755d308 100644 status = "okay"; }; -@@ -626,6 +716,8 @@ +@@ -626,6 +725,8 @@ pinctrl-0 = <&uart7_pins_c>; pinctrl-1 = <&uart7_sleep_pins_c>; pinctrl-2 = <&uart7_idle_pins_c>; @@ -7596,7 +7990,7 @@ index 93398cfae97e..acff8755d308 100644 status = "disabled"; }; -@@ -648,6 +740,12 @@ +@@ -648,6 +749,12 @@ phy-names = "usb2-phy"; usb-role-switch; status = "okay"; @@ -7609,13 +8003,23 @@ index 93398cfae97e..acff8755d308 100644 }; &usbphyc { -@@ -656,14 +754,12 @@ +@@ -656,14 +763,22 @@ &usbphyc_port0 { phy-supply = <&vdd_usb>; - vdda1v1-supply = <®11>; - vdda1v8-supply = <®18>; + st,phy-tuning = <&usb_phy_tuning>; ++ ++ /* ++ * Hack to keep hub active until all connected devices are suspended ++ * otherwise the hub will be powered off as soon as the v3v3 is disabled ++ * and it can disturb connected devices. ++ */ ++ connector { ++ compatible = "usb-a-connector"; ++ vbus-supply = <&v3v3>; ++ }; }; &usbphyc_port1 { @@ -7628,10 +8032,10 @@ index 93398cfae97e..acff8755d308 100644 &vrefbuf { diff --git a/arch/arm/boot/dts/stm32mp15xx-edx.dtsi b/arch/arm/boot/dts/stm32mp15xx-edx.dtsi new file mode 100644 -index 000000000000..3662f449de23 +index 000000000..817982009 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xx-edx.dtsi -@@ -0,0 +1,413 @@ +@@ -0,0 +1,419 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -7678,6 +8082,12 @@ index 000000000000..3662f449de23 + no-map; + }; + ++ mcu_rsc_table: mcu_rsc_table@10048000 { ++ compatible = "shared-dma-pool"; ++ reg = <0x10048000 0x8000>; ++ no-map; ++ }; ++ + mcuram: mcuram@30000000 { + compatible = "shared-dma-pool"; + reg = <0x30000000 0x40000>; @@ -7949,7 +8359,7 @@ index 000000000000..3662f449de23 + +&m4_rproc { + memory-region = <&retram>, <&mcuram>, <&mcuram2>, <&vdev0vring0>, -+ <&vdev0vring1>, <&vdev0buffer>; ++ <&vdev0vring1>, <&vdev0buffer>, <&mcu_rsc_table>; + mboxes = <&ipcc 0>, <&ipcc 1>, <&ipcc 2>; + mbox-names = "vq0", "vq1", "shutdown"; + interrupt-parent = <&exti>; @@ -8047,10 +8457,10 @@ index 000000000000..3662f449de23 +}; diff --git a/arch/arm/boot/dts/stm32mp15xx-evx.dtsi b/arch/arm/boot/dts/stm32mp15xx-evx.dtsi new file mode 100644 -index 000000000000..47a2c8e5ead7 +index 000000000..a7589d9d7 --- /dev/null +++ b/arch/arm/boot/dts/stm32mp15xx-evx.dtsi -@@ -0,0 +1,686 @@ +@@ -0,0 +1,696 @@ +// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) +/* + * Copyright (C) STMicroelectronics 2017 - All Rights Reserved @@ -8063,6 +8473,7 @@ index 000000000000..47a2c8e5ead7 +/ { + aliases { + ethernet0 = ðernet0; ++ serial1 = &usart3; + }; + + clocks { @@ -8731,7 +9142,16 @@ index 000000000000..47a2c8e5ead7 + +&usbphyc_port0 { + st,phy-tuning = <&usb_phy_tuning>; -+ vbus-supply = <&vbus_sw>; ++ ++ /* ++ * Hack to keep hub active until all connected devices are suspended ++ * otherwise the hub will be powered off as soon as the v3v3 is disabled ++ * and it can disturb connected devices. ++ */ ++ connector { ++ compatible = "usb-a-connector"; ++ vbus-supply = <&v3v3>; ++ }; +}; + +&usbphyc_port1 { diff --git a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0022-ARM-5.10.10-stm32mp1-r1-CONFIG.patch b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0023-ARM-5.10.61-stm32mp1-r2-CONFIG.patch similarity index 96% rename from recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0022-ARM-5.10.10-stm32mp1-r1-CONFIG.patch rename to recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0023-ARM-5.10.61-stm32mp1-r2-CONFIG.patch index 12cf834..de57575 100644 --- a/recipes-kernel/linux/linux-stm32mp/5.10/5.10.10/0022-ARM-5.10.10-stm32mp1-r1-CONFIG.patch +++ b/recipes-kernel/linux/linux-stm32mp/5.10/5.10.61/0023-ARM-5.10.61-stm32mp1-r2-CONFIG.patch @@ -1,23 +1,22 @@ -From 106f488712b412ed24f600c82febf95901c45054 Mon Sep 17 00:00:00 2001 -From: Romuald JEANNE -Date: Tue, 16 Mar 2021 09:03:42 +0100 -Subject: [PATCH 22/22] ARM 5.10.10-stm32mp1-r1 CONFIG +From 3bf729d5673783f6e5d2414bb526be34c0a6dbd7 Mon Sep 17 00:00:00 2001 +From: Lionel Vitte +Date: Thu, 14 Oct 2021 16:51:57 +0200 +Subject: [PATCH 23/23] ARM 5.10.61-stm32mp1-r2 CONFIG -Signed-off-by: Romuald JEANNE --- - .../fragment-01-multiv7_cleanup.config | 374 ++++++++++++++++ + .../fragment-01-multiv7_cleanup.config | 382 +++++++++++++++++ .../configs/fragment-02-multiv7_addons.config | 398 ++++++++++++++++++ arch/arm/configs/multi_v7_defconfig | 5 + - 3 files changed, 777 insertions(+) + 3 files changed, 785 insertions(+) create mode 100644 arch/arm/configs/fragment-01-multiv7_cleanup.config create mode 100644 arch/arm/configs/fragment-02-multiv7_addons.config diff --git a/arch/arm/configs/fragment-01-multiv7_cleanup.config b/arch/arm/configs/fragment-01-multiv7_cleanup.config new file mode 100644 -index 000000000000..0c5667237e27 +index 000000000..4ea7ae3bc --- /dev/null +++ b/arch/arm/configs/fragment-01-multiv7_cleanup.config -@@ -0,0 +1,374 @@ +@@ -0,0 +1,382 @@ +# +# CPU Core family selection +# @@ -392,9 +391,17 @@ index 000000000000..0c5667237e27 +# CONFIG_DVB_CXD2099 is not set +# CONFIG_DVB_SP2 is not set +# end of Customise DVB Frontends ++ ++# Remove Console display driver support ++# CONFIG_FRAMEBUFFER_CONSOLE is not set ++ ++# Remove GCC plugins as not supported by GCC9.x ++# To enable on GCC10 ++# ++# CONFIG_GCC_PLUGINS is not set diff --git a/arch/arm/configs/fragment-02-multiv7_addons.config b/arch/arm/configs/fragment-02-multiv7_addons.config new file mode 100644 -index 000000000000..d6c1a48d5702 +index 000000000..d6c1a48d5 --- /dev/null +++ b/arch/arm/configs/fragment-02-multiv7_addons.config @@ -0,0 +1,398 @@ @@ -797,7 +804,7 @@ index 000000000000..d6c1a48d5702 +CONFIG_TEE=y +CONFIG_OPTEE=y diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig -index a611b0c1e540..abf1b17cb03a 100644 +index a611b0c1e..abf1b17cb 100644 --- a/arch/arm/configs/multi_v7_defconfig +++ b/arch/arm/configs/multi_v7_defconfig @@ -829,6 +829,8 @@ CONFIG_USB_CONFIGFS_F_HID=y diff --git a/recipes-kernel/linux/linux-stm32mp_5.10.bb b/recipes-kernel/linux/linux-stm32mp_5.10.bb index 7dcc130..d0f3fa9 100644 --- a/recipes-kernel/linux/linux-stm32mp_5.10.bb +++ b/recipes-kernel/linux/linux-stm32mp_5.10.bb @@ -7,40 +7,41 @@ LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" include linux-stm32mp.inc LINUX_VERSION = "5.10" -LINUX_SUBVERSION = "10" +LINUX_SUBVERSION = "61" LINUX_TARNAME = "linux-${LINUX_VERSION}.${LINUX_SUBVERSION}" SRC_URI = "https://cdn.kernel.org/pub/linux/kernel/v5.x/${LINUX_TARNAME}.tar.xz;name=kernel" #SRC_URI = "https://git.kernel.org/torvalds/t/linux-${LINUX_VERSION}-${LINUX_SUBVERSION}.tar.gz;name=kernel" -SRC_URI[kernel.sha256sum] = "60ed866fa951522a5255ea37ec3ac2006d3f3427d4783a13ef478464f37cdb19" +SRC_URI[kernel.sha256sum] = "82eae38cc5cd11dd6aaac91c02ff0d006c7bafd6d4cf5c6a791930820a3a91d1" SRC_URI += " \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0001-ARM-5.10.10-stm32mp1-r1-MACHINE.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0002-ARM-5.10.10-stm32mp1-r1-CLOCK.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0003-ARM-5.10.10-stm32mp1-r1-CPUFREQ.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0004-ARM-5.10.10-stm32mp1-r1-CRYPTO.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0005-ARM-5.10.10-stm32mp1-r1-DMA.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0006-ARM-5.10.10-stm32mp1-r1-DRM.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0007-ARM-5.10.10-stm32mp1-r1-HWSPINLOCK.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0008-ARM-5.10.10-stm32mp1-r1-I2C-IIO-IRQCHIP.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0009-ARM-5.10.10-stm32mp1-r1-MAILBOX-REMOTEPROC-RPMSG.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0010-ARM-5.10.10-stm32mp1-r1-MEDIA-SOC-THERMAL.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0011-ARM-5.10.10-stm32mp1-r1-MFD.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0012-ARM-5.10.10-stm32mp1-r1-MMC.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0013-ARM-5.10.10-stm32mp1-r1-NET-TTY.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0014-ARM-5.10.10-stm32mp1-r1-PERF.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0015-ARM-5.10.10-stm32mp1-r1-PHY-USB.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0016-ARM-5.10.10-stm32mp1-r1-PINCTRL-REGULATOR-SPI.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0017-ARM-5.10.10-stm32mp1-r1-RESET-RTC-WATCHDOG.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0018-ARM-5.10.10-stm32mp1-r1-SCMI.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0019-ARM-5.10.10-stm32mp1-r1-SOUND.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0020-ARM-5.10.10-stm32mp1-r1-MISC-CPUIDLE-POWER.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0021-ARM-5.10.10-stm32mp1-r1-DEVICETREE.patch \ - file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0022-ARM-5.10.10-stm32mp1-r1-CONFIG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0001-ARM-5.10.61-stm32mp1-r2-MACHINE.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0002-ARM-5.10.61-stm32mp1-r2-CLOCK.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0003-ARM-5.10.61-stm32mp1-r2-CPUFREQ.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0004-ARM-5.10.61-stm32mp1-r2-CRYPTO.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0005-ARM-5.10.61-stm32mp1-r2-DMA.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0006-ARM-5.10.61-stm32mp1-r2-DRM.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0007-ARM-5.10.61-stm32mp1-r2-HWSPINLOCK.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0008-ARM-5.10.61-stm32mp1-r2-I2C-IIO-IRQCHIP.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0009-ARM-5.10.61-stm32mp1-r2-MAILBOX-REMOTEPROC-RPMSG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0010-ARM-5.10.61-stm32mp1-r2-MEDIA-SOC-THERMAL.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0011-ARM-5.10.61-stm32mp1-r2-MFD.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0012-ARM-5.10.61-stm32mp1-r2-MMC.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0013-ARM-5.10.61-stm32mp1-r2-NET-TTY.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0014-ARM-5.10.61-stm32mp1-r2-PERF.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0015-ARM-5.10.61-stm32mp1-r2-PHY-USB.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0016-ARM-5.10.61-stm32mp1-r2-PINCTRL-REGULATOR-SPI.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0017-ARM-5.10.61-stm32mp1-r2-RESET-RTC-WATCHDOG.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0018-ARM-5.10.61-stm32mp1-r2-SCMI.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0019-ARM-5.10.61-stm32mp1-r2-SOUND.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0020-ARM-5.10.61-stm32mp1-r2-MISC.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0021-ARM-5.10.61-stm32mp1-r2-CPUIDLE-POWER.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0022-ARM-5.10.61-stm32mp1-r2-DEVICETREE.patch \ + file://${LINUX_VERSION}/${LINUX_VERSION}.${LINUX_SUBVERSION}/0023-ARM-5.10.61-stm32mp1-r2-CONFIG.patch \ " LINUX_TARGET = "stm32mp" -LINUX_RELEASE = "r1" +LINUX_RELEASE = "r2" PV = "${LINUX_VERSION}.${LINUX_SUBVERSION}-${LINUX_TARGET}-${LINUX_RELEASE}" @@ -57,7 +58,7 @@ S = "${WORKDIR}/linux-${LINUX_VERSION}.${LINUX_SUBVERSION}" BBCLASSEXTEND = "devupstream:target" SRC_URI_class-devupstream = "git://github.com/STMicroelectronics/linux.git;protocol=https;branch=${ARCHIVER_ST_BRANCH}" -SRCREV_class-devupstream = "ce6891abb1c895d4849e6f784615687341b3dbde" +SRCREV_class-devupstream = "64e6a220537c5cd7e8cc5b723ef09c6341388c98" # --------------------------------- # Configure default preference to manage dynamic selection between tarball and github