diff --git a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay index 7c864a4ab138..ec2778275501 100644 --- a/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay +++ b/applications/sdp/mspi/boards/nrf54l15dk_nrf54l15_cpuflpr.overlay @@ -10,16 +10,16 @@ #address-cells = <1>; #size-cells = <1>; - sram_tx: memory@2003c000 { - reg = <0x2003c000 0x07f0>; + sram_tx: memory@2003b400 { + reg = <0x2003b400 0x07f0>; }; - sram_rx: memory@2003c7f0 { - reg = <0x2003c7f0 0x07f0>; + sram_rx: memory@2003bbf0 { + reg = <0x2003bbf0 0x07f0>; }; - cpuflpr_error_code: memory@2003cfe0 { - reg = <0x2003cfe0 0x0020>; /* 32bytes */ + cpuflpr_error_code: memory@2003c3e0 { + reg = <0x2003c3e0 0x0020>; /* 32bytes */ }; }; }; @@ -37,16 +37,16 @@ }; &cpuflpr_rram { - reg = <0x17a000 DT_SIZE_K(12)>; + reg = <0x179400 DT_SIZE_K(15)>; }; &cpuflpr_code_partition { - reg = <0x0 DT_SIZE_K(12)>; + reg = <0x0 DT_SIZE_K(15)>; }; &cpuflpr_sram { - reg = <0x2003d000 DT_SIZE_K(12)>; - ranges = <0x0 0x2003d000 0x3000>; + reg = <0x2003c400 DT_SIZE_K(15)>; + ranges = <0x0 0x2003c400 0x3c00>; }; &cpuflpr_vevif_rx { diff --git a/applications/sdp/mspi/src/hrt/hrt-nrf54l15.s b/applications/sdp/mspi/src/hrt/hrt-nrf54l15.s index 61f02fedbf56..12ea1137f4fc 100644 --- a/applications/sdp/mspi/src/hrt/hrt-nrf54l15.s +++ b/applications/sdp/mspi/src/hrt/hrt-nrf54l15.s @@ -167,70 +167,6 @@ hrt_tx: #NO_APP j .L11 .size hrt_tx, .-hrt_tx - .section .text.hrt_tx_rx.constprop.0,"ax",@progbits - .align 1 - .type hrt_tx_rx.constprop.0, @function -hrt_tx_rx.constprop.0: - lw a4,0(a0) - mv a5,a1 - lw a1,4(a0) - beq a1,zero,.L19 - li a1,8 - div a1,a1,a5 - li t1,126976 - slli a5,a5,12 - and a5,a5,t1 - lw a4,0(a4) - addi a1,a1,-1 - andi a1,a1,63 - or a1,a1,a5 - li a5,2097152 - addi a5,a5,1024 - or a1,a1,a5 - #APP - csrw 3019, a1 - #NO_APP - li t1,65536 - li a5,0 - li a1,-16777216 - li t0,1 - add a3,a3,t1 -.L21: - lw t1,4(a0) - bltu a5,t1,.L26 -.L19: - ret -.L26: - lbu t1,16(a0) - andi t2,t1,0xff - beq t1,zero,.L22 - bne t2,t0,.L23 - and t1,a4,a1 - #APP - csrw 3017, t1 - #NO_APP -.L23: - slli a4,a4,8 - bne a5,zero,.L24 - beq a2,zero,.L24 - #APP - csrw 2002, a3 - #NO_APP -.L25: - addi a5,a5,1 - j .L21 -.L22: - and t1,a4,a1 - #APP - csrw 3016, t1 - #NO_APP - j .L23 -.L24: - #APP - csrr t1, 3018 - #NO_APP - j .L25 - .size hrt_tx_rx.constprop.0, .-hrt_tx_rx.constprop.0 .section .text.hrt_write,"ax",@progbits .align 1 .globl hrt_write @@ -242,160 +178,172 @@ hrt_write: sw s1,4(sp) mv s0,a0 sb zero,3(sp) - #APP - csrr s1, 3008 - #NO_APP lhu a5,90(a0) #APP csrw 3009, a5 #NO_APP li a5,0 - addi a4,a0,4 + li a2,20 li a3,4 -.L33: - lw a2,0(a4) - bne a2,zero,.L32 +.L21: + mul a4,a5,a2 + add a4,s0,a4 + lw a4,4(a4) + bne a4,zero,.L20 addi a5,a5,1 - andi a5,a5,0xff - addi a4,a4,20 - bne a5,a3,.L33 + bne a5,a3,.L21 li a5,3 -.L32: +.L22: li a4,1 - beq a5,a4,.L34 + beq a5,a4,.L23 li a4,3 - beq a5,a4,.L35 - li a4,0 - bne a5,zero,.L36 - lbu a4,80(s0) -.L36: - lui a3,%hi(xfer_shift_ctrl+2) - sb a4,%lo(xfer_shift_ctrl+2)(a3) + beq a5,a4,.L24 + li a3,0 + bne a5,zero,.L25 + lbu a3,80(s0) +.L43: + andi a3,a3,0xff +.L25: + lui a4,%hi(xfer_shift_ctrl+2) + sb a3,%lo(xfer_shift_ctrl+2)(a4) #APP csrw 2000, 2 #NO_APP - lhu a3,84(s0) + lhu a4,84(s0) + slli a4,a4,16 + srli a4,a4,16 #APP csrr a2, 2003 #NO_APP li a1,-65536 and a2,a2,a1 - or a3,a3,a2 + or a4,a4,a2 #APP - csrw 2003, a3 + csrw 2003, a4 csrw 3011, 0 #NO_APP li a2,2031616 - slli a3,a4,16 - and a3,a3,a2 - ori a3,a3,4 + slli a4,a3,16 + and a4,a4,a2 + ori a4,a4,4 #APP - csrw 3043, a3 + csrw 3043, a4 #NO_APP - li a3,20 - mul a5,a5,a3 + li a4,20 + mul a5,a5,a4 li a2,1 add a5,s0,a5 - lw a3,4(a5) - beq a3,a2,.L37 + lw a4,4(a5) + beq a4,a2,.L26 li a2,2 - beq a3,a2,.L38 + beq a4,a2,.L27 li a5,32 - div a5,a5,a4 - j .L54 -.L34: - lbu a4,81(s0) - j .L36 -.L35: - lbu a4,83(s0) - j .L36 -.L37: + div a5,a5,a3 + j .L44 +.L20: + andi a5,a5,0xff + j .L22 +.L23: + lbu a3,81(s0) + j .L43 +.L24: + lbu a3,83(s0) + j .L43 +.L26: lbu a5,8(a5) -.L54: +.L44: #APP csrw 3022, a5 #NO_APP + lbu a5,89(s0) lbu a4,87(s0) + bne a5,zero,.L30 li a5,1 sll a5,a5,a4 - lbu a4,89(s0) slli a5,a5,16 srli a5,a5,16 - bne a4,zero,.L41 #APP csrc 3008, a5 #NO_APP -.L42: - lhu a3,84(s0) +.L31: + #APP + csrr s1, 3008 + #NO_APP lbu a1,80(s0) + lhu a3,84(s0) addi a2,sp,3 mv a0,s0 call hrt_tx - lhu a3,84(s0) lbu a1,81(s0) + lhu a3,84(s0) addi a2,sp,3 addi a0,s0,20 call hrt_tx - lhu a3,84(s0) lbu a1,82(s0) + lhu a3,84(s0) addi a2,sp,3 addi a0,s0,40 call hrt_tx - lhu a3,84(s0) lbu a1,83(s0) + lhu a3,84(s0) addi a2,sp,3 addi a0,s0,60 call hrt_tx lbu a5,94(s0) - bne a5,zero,.L43 + bne a5,zero,.L32 li a5,4096 addi a5,a5,1 #APP csrw 3019, a5 #NO_APP - slli s1,s1,1 - slli s1,s1,16 - srli s1,s1,16 + li a4,131072 + slli a5,s1,1 + addi a4,a4,-2 + and a5,a5,a4 #APP - csrw 3012, s1 + csrw 3012, a5 csrw 2000, 0 #NO_APP -.L44: +.L33: #APP csrw 2005, 0 #NO_APP lbu a5,88(s0) - bne a5,zero,.L31 + bne a5,zero,.L19 + lbu a5,89(s0) lbu a4,87(s0) + bne a5,zero,.L36 li a5,1 sll a5,a5,a4 - lbu a4,89(s0) slli a5,a5,16 srli a5,a5,16 - bne a4,zero,.L47 #APP csrs 3008, a5 #NO_APP -.L31: +.L19: lw ra,12(sp) lw s0,8(sp) lw s1,4(sp) addi sp,sp,16 jr ra -.L38: +.L27: lbu a5,9(a5) - j .L54 -.L41: + j .L44 +.L30: + li a5,1 + sll a5,a5,a4 + slli a5,a5,16 + srli a5,a5,16 #APP csrs 3008, a5 #NO_APP - j .L42 -.L43: + j .L31 +.L32: #APP csrr a5, 3022 #NO_APP andi a5,a5,0xff - bne a5,zero,.L43 + bne a5,zero,.L32 #APP csrw 2000, 0 #NO_APP @@ -404,190 +352,293 @@ hrt_write: #APP csrw 3019, a5 #NO_APP - lbu a5,94(s0) - li a4,1 - bne a5,a4,.L45 - lbu a4,86(s0) - sll a5,a5,a4 + lbu a3,94(s0) + li a5,1 + andi a4,a3,0xff + bne a3,a5,.L34 + lbu a5,86(s0) + sll a5,a4,a5 slli a5,a5,16 srli a5,a5,16 #APP csrc 3008, a5 #NO_APP - j .L44 -.L45: - li a3,3 - bne a5,a3,.L44 - lbu a5,86(s0) - sll a4,a4,a5 - slli a4,a4,16 - srli a4,a4,16 + j .L33 +.L34: + lbu a3,94(s0) + li a4,3 + bne a3,a4,.L33 + lbu a4,86(s0) + sll a5,a5,a4 + slli a5,a5,16 + srli a5,a5,16 #APP - csrs 3008, a4 + csrs 3008, a5 #NO_APP - j .L44 -.L47: + j .L33 +.L36: + li a5,1 + sll a5,a5,a4 + slli a5,a5,16 + srli a5,a5,16 #APP csrc 3008, a5 #NO_APP - j .L31 + j .L19 .size hrt_write, .-hrt_write .section .text.hrt_read,"ax",@progbits .align 1 .globl hrt_read .type hrt_read, @function hrt_read: - addi sp,sp,-12 - sw s0,4(sp) - sw ra,8(sp) - sw s1,0(sp) - lbu s1,83(a0) - lbu a5,89(a0) - lbu a4,87(a0) + addi sp,sp,-36 + sw s0,28(sp) + sw s1,24(sp) + sw ra,32(sp) + lbu a5,83(a0) + li s1,32 mv s0,a0 + div s1,s1,a5 + lbu a5,83(a0) + lbu a4,83(a0) + lw t0,64(a0) + lbu t1,88(a0) + lw a1,60(a0) + lbu a3,89(a0) + lbu a2,87(a0) + andi a5,a5,0xff + andi a4,a4,0xff + andi t1,t1,0xff + addi s1,s1,-1 andi s1,s1,0xff - bne a5,zero,.L56 - li a5,1 - sll a5,a5,a4 - slli a5,a5,16 - srli a5,a5,16 + bne a3,zero,.L46 + li a3,1 + sll a3,a3,a2 + slli a3,a3,16 + srli a3,a3,16 #APP - csrc 3008, a5 + csrc 3008, a3 #NO_APP -.L57: - lbu a4,83(s0) - li a5,1 - bne a4,a5,.L58 - lhu a5,90(s0) - slli a5,a5,16 - srli a5,a5,16 - andi a5,a5,-5 - slli a5,a5,16 - srli a5,a5,16 - sh a5,90(s0) - lhu a5,90(s0) +.L47: + sw a1,20(sp) + sw t1,16(sp) + sw t0,12(sp) + sw a4,8(sp) + sw a5,4(sp) #APP - csrw 3009, a5 + csrr a5, 3008 #NO_APP -.L58: + li a3,1 + sw zero,64(s0) + sb a3,88(s0) + mv a0,s0 + sw a5,0(sp) + call hrt_write + lw t0,12(sp) + lw t1,16(sp) + li a3,1 + sw t0,64(s0) + sb t1,88(s0) + lbu a0,83(s0) + lw a5,4(sp) + lw a4,8(sp) + lw a1,20(sp) + bne a0,a3,.L48 + lhu a3,90(s0) + slli a3,a3,16 + srli a3,a3,16 + andi a3,a3,-5 + slli a3,a3,16 + srli a3,a3,16 + sh a3,90(s0) + lhu a3,90(s0) +.L76: #APP + csrw 3009, a3 csrw 3011, 2 #NO_APP - li a5,65536 - addi a5,a5,4 + li a3,2031616 + slli a4,a4,16 + and a4,a4,a3 + ori a3,a4,4 #APP - csrw 3043, a5 - csrw 3022, 8 + csrw 3043, a3 + csrw 3022, 1 csrw 2000, 2 csrw 2001, 2 #NO_APP - lhu a5,84(s0) - slli a5,a5,16 - srli a5,a5,16 + lhu a3,84(s0) + slli a3,a3,16 + srli a3,a3,16 #APP - csrr a4, 2003 + csrr a0, 2003 #NO_APP - li a3,-65536 - and a4,a4,a3 - or a5,a5,a4 + li t1,-65536 + and a0,a0,t1 + or a3,a3,a0 #APP - csrw 2003, a5 + csrw 2003, a3 #NO_APP - lhu a5,84(s0) - slli a5,a5,16 - srli a5,a5,16 + lhu a3,84(s0) + slli a3,a3,16 + srli a3,a3,16 #APP - csrr a4, 2003 + csrr a0, 2003 #NO_APP - slli a5,a5,1 - slli a4,a4,16 - addi a5,a5,1 - srli a4,a4,16 - slli a5,a5,16 - or a5,a5,a4 + slli a3,a3,1 + slli a0,a0,16 + addi a3,a3,1 + srli a0,a0,16 + slli a3,a3,16 + or a3,a3,a0 #APP - csrw 2003, a5 + csrw 2003, a3 #NO_APP - lbu a1,80(s0) - lhu a3,84(s0) + li a3,126976 + slli a5,a5,12 + and a5,a5,a3 + li a0,2097152 + andi a3,s1,63 + or a3,a3,a5 + addi a0,a0,1024 + or a3,a3,a0 + #APP + csrw 3019, a3 + csrw 3017, 0 + #NO_APP + lw a0,64(s0) + li a3,1 + beq a0,a3,.L50 +.L52: + li t1,2097152 + addi a0,a1,-4 li a2,1 - mv a0,s0 - call hrt_tx_rx.constprop.0 - lbu a1,81(s0) + li a1,0 + li t0,32 + addi t1,t1,1024 + li t2,65536 +.L51: + lw a3,64(s0) + bgtu a3,a1,.L64 +.L65: + #APP + csrr a3, 3021 + #NO_APP + andi a3,a3,0xff + bne a3,zero,.L65 + #APP + csrr a3, 2005 + #NO_APP + slli a3,a3,16 + srli a3,a3,16 +.L66: + #APP + csrr a0, 2005 + #NO_APP + mv a1,a3 + slli a3,a0,16 + srli a3,a3,16 + bne a3,a1,.L66 + lw a3,0(sp) + slli a2,a3,24 + #APP + csrw 3017, a2 + csrw 3043, a4 + csrr a4, 3018 + #NO_APP + lbu a2,68(s0) + lbu a3,83(s0) + mul a2,a2,a3 + li a3,32 + sub a3,a3,a2 + srl a4,a4,a3 + sw a4,72(s0) + j .L56 +.L46: + li a3,1 + sll a3,a3,a2 + slli a3,a3,16 + srli a3,a3,16 + #APP + csrs 3008, a3 + #NO_APP + j .L47 +.L48: + lhu a3,92(s0) + j .L76 +.L50: + lbu a0,68(s0) + li a3,2 + bne a0,a3,.L52 lhu a3,84(s0) - li a2,0 - addi a0,s0,20 - call hrt_tx_rx.constprop.0 - lbu a4,83(s0) - li a5,1 - beq a4,a5,.L59 - lhu a5,92(s0) + li a1,65536 + add a3,a3,a1 #APP - csrw 3009, a5 + csrw 2002, a3 #NO_APP -.L59: - lbu a4,81(s0) - lbu a5,83(s0) - beq a4,a5,.L67 - li a5,2031616 - slli s1,s1,16 - and s1,s1,a5 - ori s1,s1,4 +.L53: #APP - csrw 3043, s1 + csrr a3, 3021 #NO_APP - lbu a4,83(s0) - li a5,8 - div a5,a5,a4 - addi a5,a5,-1 - andi a5,a5,0xff + andi a3,a3,0xff + bne a3,zero,.L53 #APP - csrw 3023, a5 - csrr a5, 3018 + csrr a3, 2005 #NO_APP - li a4,4 -.L61: - lw a3,64(s0) - bgtu a3,a4,.L62 + slli a3,a3,16 + srli a3,a3,16 +.L54: #APP - csrw 2000, 0 - csrw 2001, 0 - csrw 3019, 0 + csrr a0, 2005 #NO_APP - lbu a4,88(s0) - bne a4,zero,.L63 - lbu a4,89(s0) - lbu a3,87(s0) - bne a4,zero,.L64 - li a4,1 - sll a4,a4,a3 - slli a4,a4,16 - srli a4,a4,16 + mv a1,a3 + slli a3,a0,16 + srli a3,a3,16 + bne a3,a1,.L54 + lw a3,0(sp) + slli a2,a3,24 #APP - csrs 3008, a4 + csrw 3017, a2 + csrw 3043, a4 + #NO_APP + lbu a3,83(s0) + li a4,8 + bne a3,a4,.L55 + #APP + csrr a4, 3018 #NO_APP -.L63: - lbu a3,81(s0) - lbu a4,83(s0) - beq a3,a4,.L65 - lw a4,60(s0) - andi a3,a5,0xff - sb a3,0(a4) lw a3,60(s0) - srli a4,a5,8 + srli a4,a4,16 andi a4,a4,0xff - sb a4,1(a3) + sb a4,0(a3) lw a3,60(s0) - srli a4,a5,16 - andi a4,a4,0xff - sb a4,2(a3) - lw a4,60(s0) - srli a5,a5,24 - sb a5,3(a4) -.L65: + sb a4,1(a3) +.L56: + #APP + csrw 2000, 0 + csrw 2001, 0 + #NO_APP + andi s1,s1,63 + or s1,s1,a5 + #APP + csrw 3019, s1 + #NO_APP + lbu a5,88(s0) + bne a5,zero,.L67 + lbu a5,89(s0) + lbu a4,87(s0) + bne a5,zero,.L68 + li a5,1 + sll a5,a5,a4 + slli a5,a5,16 + srli a5,a5,16 + #APP + csrs 3008, a5 + #NO_APP +.L67: lbu a4,83(s0) li a5,1 - bne a4,a5,.L55 + bne a4,a5,.L45 lhu a5,90(s0) ori a5,a5,4 sh a5,90(s0) @@ -595,44 +646,75 @@ hrt_read: #APP csrw 3009, a5 #NO_APP -.L55: - lw ra,8(sp) - lw s0,4(sp) - lw s1,0(sp) - addi sp,sp,12 +.L45: + lw ra,32(sp) + lw s0,28(sp) + lw s1,24(sp) + addi sp,sp,36 jr ra -.L56: - li a5,1 - sll a5,a5,a4 - slli a5,a5,16 - srli a5,a5,16 - #APP - csrs 3008, a5 - #NO_APP - j .L57 -.L62: +.L55: #APP - csrr a2, 3018 + csrr a4, 3018 #NO_APP lw a3,60(s0) - srli a2,a2,24 - add a3,a3,a4 - sb a2,0(a3) - addi a4,a4,1 - j .L61 -.L67: - li a4,0 - li a5,0 - j .L61 + srli a4,a4,24 + sb a4,0(a3) + j .L56 .L64: - li a4,1 - sll a4,a4,a3 - slli a4,a4,16 - srli a4,a4,16 + lw a3,64(s0) + sub a3,a3,a1 + beq a3,a2,.L58 + li s1,2 + beq a3,s1,.L59 + lbu s1,83(s0) + div s1,t0,s1 + j .L77 +.L58: + lbu s1,68(s0) +.L77: + addi s1,s1,-1 + andi s1,s1,0xff + bne a1,zero,.L62 + addi a3,s1,-2 + andi s1,a3,0xff + andi a3,a3,63 + or a3,a3,a5 + or a3,a3,t1 + #APP + csrw 3019, a3 + #NO_APP + lhu a3,84(s0) + add a3,a3,t2 + #APP + csrw 2002, a3 + csrr a3, 3018 + #NO_APP +.L63: + addi a1,a1,1 + addi a0,a0,4 + j .L51 +.L59: + lbu s1,69(s0) + j .L77 +.L62: + andi a3,s1,63 + or a3,a3,a5 + or a3,a3,t1 #APP - csrc 3008, a4 + csrw 3019, a3 + csrr a3, 3018 #NO_APP + sw a3,0(a0) j .L63 +.L68: + li a5,1 + sll a5,a5,a4 + slli a5,a5,16 + srli a5,a5,16 + #APP + csrc 3008, a5 + #NO_APP + j .L67 .size hrt_read, .-hrt_read .section .sdata.xfer_shift_ctrl,"aw" .align 2 diff --git a/applications/sdp/mspi/src/hrt/hrt.c b/applications/sdp/mspi/src/hrt/hrt.c index 47604facf9f4..2b91858722d5 100644 --- a/applications/sdp/mspi/src/hrt/hrt.c +++ b/applications/sdp/mspi/src/hrt/hrt.c @@ -14,9 +14,8 @@ #define CNT1_INIT_VALUE 1 #define MSB_MASK (0xff000000) -#define FOURTH_BYTE_SHIFT_CNT 24 -#define THIRD_BYTE_SHIFT_CNT 16 -#define SECOND_BYTE_SHIFT_CNT 8 +#define BYTE_3_SHIFT 24 +#define BYTE_2_SHIFT 16 /* * Macro for calculating TOP value of CNT1. It should be twice as TOP value of CNT0 @@ -118,18 +117,12 @@ static void hrt_tx(volatile hrt_xfer_data_t *xfer_data, uint8_t frame_width, boo } } -void hrt_write(hrt_xfer_t *hrt_xfer_params) +void hrt_write(volatile hrt_xfer_t *hrt_xfer_params) { hrt_frame_element_t first_element = HRT_FE_DATA; bool counter_running = false; - nrf_vpr_csr_vio_mode_out_t out_mode = {.mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE}; - - /* - * Least significant bit is ignored when the whole OUTB is shifted to OUT at once after - * switching to no shifting mode, so the read value need to be shifted left by 1. - */ - uint16_t prev_out = nrf_vpr_csr_vio_out_get() << 1; + uint16_t prev_out = 0; /* Configure clock and pins */ nrf_vpr_csr_vio_dir_set(hrt_xfer_params->tx_direction_mask); @@ -183,6 +176,8 @@ void hrt_write(hrt_xfer_t *hrt_xfer_params) nrf_vpr_csr_vio_out_or_set(BIT(hrt_xfer_params->ce_vio)); } + prev_out = nrf_vpr_csr_vio_out_get(); + /* Transfer command */ hrt_tx(&hrt_xfer_params->xfer_data[HRT_FE_COMMAND], hrt_xfer_params->bus_widths.command, &counter_running, hrt_xfer_params->counter_value); @@ -205,7 +200,12 @@ void hrt_write(hrt_xfer_t *hrt_xfer_params) */ if (hrt_xfer_params->cpp_mode == MSPI_CPP_MODE_0) { nrf_vpr_csr_vio_shift_ctrl_buffered_set(&write_final_shift_ctrl_cfg); - nrf_vpr_csr_vio_out_buffered_set(prev_out); + /* + * Least significant bit is ignored when the whole OUTB is shifted to OUT at once + * after switching to no shifting mode, so the read value need to be shifted left + * by 1. + */ + nrf_vpr_csr_vio_out_buffered_set(prev_out << 1); nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_STOP); } else { while (nrf_vpr_csr_vio_shift_cnt_out_get() != 0) { @@ -235,140 +235,208 @@ void hrt_write(hrt_xfer_t *hrt_xfer_params) } } -static void hrt_tx_rx(volatile hrt_xfer_data_t *xfer_data, uint8_t frame_width, bool start_counter, - uint16_t cnt0_val, uint16_t cnt1_val) +void hrt_read(volatile hrt_xfer_t *hrt_xfer_params) { - nrf_vpr_csr_vio_shift_ctrl_t shift_ctrl = { - .shift_count = SHIFTCNTB_VALUE(BITS_IN_BYTE / frame_width), + nrf_vpr_csr_vio_shift_ctrl_t rx_shift_ctrl = { + .shift_count = SHIFTCNTB_VALUE(BITS_IN_WORD / hrt_xfer_params->bus_widths.data), .out_mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE, - .frame_width = frame_width, + .frame_width = hrt_xfer_params->bus_widths.data, .in_mode = NRF_VPR_CSR_VIO_MODE_IN_SHIFT, }; - - uint32_t to_send = *((uint32_t *)xfer_data->data); - - if (xfer_data->word_count == 0) { - return; - } - - nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl); - - for (uint32_t i = 0; i < xfer_data->word_count; i++) { - switch (xfer_data->fun_out) { - case HRT_FUN_OUT_WORD: - nrf_vpr_csr_vio_out_buffered_reversed_word_set(to_send & MSB_MASK); - break; - case HRT_FUN_OUT_BYTE: - nrf_vpr_csr_vio_out_buffered_reversed_byte_set(to_send & MSB_MASK); - break; - default: - break; - } - - to_send = to_send << BITS_IN_BYTE; - - if ((i == 0) && start_counter) { - /* Start both counters */ - nrf_vpr_csr_vtim_combined_counter_set( - (cnt0_val << VPRCSR_NORDIC_CNT_CNT0_Pos) + - (cnt1_val << VPRCSR_NORDIC_CNT_CNT1_Pos)); - } else { - /* - * Since we start reading right after the transmission is started, - * we need to read from INB register in the meantime, even if stop_cnt - * from nrf_vpr_csr_vio_config_t is set to false. Otherwise clock is - * not generated when the actual data is sent by a peripheral device. - */ - nrf_vpr_csr_vio_in_buffered_reversed_byte_get(); - } - } -} - -void hrt_read(volatile hrt_xfer_t *hrt_xfer_params) -{ - static const nrf_vpr_csr_vio_shift_ctrl_t shift_ctrl = { - .out_mode = NRF_VPR_CSR_VIO_SHIFT_NONE, - .in_mode = NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS, - }; - static const nrf_vpr_csr_vio_mode_out_t out_mode = { - .mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE, - .frame_width = 1, - }; - nrf_vpr_csr_vio_mode_out_t out_mode_in = { + nrf_vpr_csr_vio_mode_out_t rx_out_mode = { .mode = NRF_VPR_CSR_VIO_SHIFT_OUTB_TOGGLE, .frame_width = hrt_xfer_params->bus_widths.data, }; + uint32_t data_length = hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count; + bool hold = hrt_xfer_params->ce_hold; + uint32_t *data = (uint32_t *)hrt_xfer_params->xfer_data[HRT_FE_DATA].data; + uint32_t last_word; + uint16_t prev_out; + uint16_t cnt0; + uint16_t cnt0_prev; - uint32_t rec_data = 0; - uint32_t iter = 0; - - /* Enable CS */ + /* Enable CE */ if (hrt_xfer_params->ce_polarity == MSPI_CE_ACTIVE_LOW) { nrf_vpr_csr_vio_out_clear_set(BIT(hrt_xfer_params->ce_vio)); } else { nrf_vpr_csr_vio_out_or_set(BIT(hrt_xfer_params->ce_vio)); } + /* Get state of all VIO to reset it correctly after transfer. */ + prev_out = nrf_vpr_csr_vio_out_get(); + + /* Write only command address and dummy cycles and keep CS active. */ + hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count = 0; + hrt_xfer_params->ce_hold = true; + hrt_write(hrt_xfer_params); + + /* Restore variables values for read phase. */ + hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count = data_length; + hrt_xfer_params->ce_hold = hold; + /* Configure clock and pins */ - /* Set DQ1 as input in SPI case. */ if (hrt_xfer_params->bus_widths.data == 1) { + /* Set DQ1 as input */ WRITE_BIT(hrt_xfer_params->tx_direction_mask, SPI_INPUT_PIN_NUM, VPRCSR_NORDIC_DIR_INPUT); nrf_vpr_csr_vio_dir_set(hrt_xfer_params->tx_direction_mask); + } else { + nrf_vpr_csr_vio_dir_set(hrt_xfer_params->rx_direction_mask); } /* Initial configuration */ nrf_vpr_csr_vio_mode_in_set(NRF_VPR_CSR_VIO_MODE_IN_SHIFT); - nrf_vpr_csr_vio_mode_out_set(&out_mode); - nrf_vpr_csr_vio_shift_cnt_out_set(BITS_IN_BYTE); + nrf_vpr_csr_vio_mode_out_set(&rx_out_mode); + + /* Value of 1 is set to SHIFTCNTOUT register to start MSPI clock running, 0 is not possible. + * This causes 1 to be written to SHIFTCNTOUT and SHIFTCNTIN. + * When starting timers with nrf_vpr_csr_vtim_combined_counter_set both should start + * simoultaneously but it does not happen. + * 1. First TIMER 0 starts. + * 2. When SHIFTCNTOUT reaches 0, TIMER 1 starts. + * 3. When SHIFTCNTIN reaches 0 SHIFTCTRLB register is loaded and both timers and + * shift counters continue to run together. + * So writing n to SHIFTCNTOUT and starting timers causes 2*n clock pulses to be generated. + */ + nrf_vpr_csr_vio_shift_cnt_out_set(1); /* Counter settings */ nrf_vpr_csr_vtim_count_mode_set(0, NRF_VPR_CSR_VTIM_COUNT_RELOAD); nrf_vpr_csr_vtim_count_mode_set(1, NRF_VPR_CSR_VTIM_COUNT_RELOAD); - /* Set top counters value. Trigger data capture every two clock cycles */ + /* Set top counters value. CNT1 - trigger data capture every two clock cycles */ nrf_vpr_csr_vtim_simple_counter_top_set(0, hrt_xfer_params->counter_value); nrf_vpr_csr_vtim_simple_counter_top_set(1, CNT1_TOP_CALCULATE(hrt_xfer_params->counter_value)); - /* Transfer command */ - hrt_tx_rx(&hrt_xfer_params->xfer_data[HRT_FE_COMMAND], hrt_xfer_params->bus_widths.command, - true, hrt_xfer_params->counter_value, CNT1_INIT_VALUE); + nrf_vpr_csr_vio_shift_ctrl_buffered_set(&rx_shift_ctrl); - /* Transfer address */ - hrt_tx_rx(&hrt_xfer_params->xfer_data[HRT_FE_ADDRESS], hrt_xfer_params->bus_widths.address, - false, hrt_xfer_params->counter_value, CNT1_INIT_VALUE); + /* Make sure that there is no data leftover in output register. */ + nrf_vpr_csr_vio_out_buffered_reversed_word_set(0x00); - /* Set pins as input for cases other than SINGLE mode. */ - if (hrt_xfer_params->bus_widths.data != 1) { - nrf_vpr_csr_vio_dir_set(hrt_xfer_params->rx_direction_mask); - } + /* Special case when only 2 clocks are required. */ + if ((hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count == 1) && + (hrt_xfer_params->xfer_data[HRT_FE_DATA].last_word_clocks == 2)) { - if (hrt_xfer_params->bus_widths.address != hrt_xfer_params->bus_widths.data) { - /* - * When writing to SHIFTCTRLB, reception of data starts 6 clock cycles (3 bytes) too - * late. When writing to OUTMODEB and SHIFTCNTB separately, the problem disappears. + /* Start reception. */ + nrf_vpr_csr_vtim_combined_counter_set( + (hrt_xfer_params->counter_value << VPRCSR_NORDIC_CNT_CNT0_Pos) + + (CNT1_INIT_VALUE << VPRCSR_NORDIC_CNT_CNT1_Pos)); + + /* Wait for reception to end, transfer has to be stopped "manualy". + * Setting SHIFTCTRLB cannot be used because with RTPERIPHCTRL:STOPCOUNTERS == 1, + * counter stops 1 clock too early. */ - nrf_vpr_csr_vio_mode_out_buffered_set(&out_mode_in); - nrf_vpr_csr_vio_shift_cnt_out_buffered_set( - SHIFTCNTB_VALUE(BITS_IN_BYTE / hrt_xfer_params->bus_widths.data)); + while (nrf_vpr_csr_vio_shift_cnt_in_get() > 0) { + } + /* Wait until timer 0 stops. + * WAIT0 cannot be used for this because in higher frequencies function + * nrf_vpr_csr_vtim_simple_wait_set is called when CNT0 has already stopped, + * making code wait indefinitely. + */ + cnt0 = nrf_vpr_csr_vtim_simple_counter_get(0); + cnt0_prev = cnt0 + 1; - /* - * When calling `vpr_csr_vio_in_buffered_reversed_byte_get` for the first time in - * 1_1_4 mode, CPU stalls for 8 clock cycles instead of 2 (so there are 4 bytes in - * the register, not 1). It is probably due to HW issue causing SHIFT_CNT_IN to be - * updated one word too late. For this reason, read all four bytes at once, save - * them in a temporary variable, and put them in buffer later to not perform not - * needed operations during receive. + while (cnt0 != cnt0_prev) { + cnt0_prev = cnt0; + cnt0 = nrf_vpr_csr_vtim_simple_counter_get(0); + } + + /* Reset VIO outputs. */ + nrf_vpr_csr_vio_out_buffered_reversed_word_set(prev_out << BYTE_3_SHIFT); + + /* Set out mode to none so that reading INB/INBRB register doesn't cause + * clock to continue running. */ - rec_data = nrf_vpr_csr_vio_in_buffered_reversed_byte_get(); - iter = 4; - } + rx_out_mode.mode = NRF_VPR_CSR_VIO_SHIFT_NONE; + nrf_vpr_csr_vio_mode_out_set(&rx_out_mode); + + if (hrt_xfer_params->bus_widths.data == 8) { + last_word = nrf_vpr_csr_vio_in_buffered_reversed_byte_get(); + hrt_xfer_params->xfer_data[HRT_FE_DATA].data[0] = + (uint8_t)(last_word >> BYTE_2_SHIFT); + hrt_xfer_params->xfer_data[HRT_FE_DATA].data[1] = + (uint8_t)(last_word >> BYTE_2_SHIFT); + } else { + hrt_xfer_params->xfer_data[HRT_FE_DATA].data[0] = + (uint8_t)(nrf_vpr_csr_vio_in_buffered_reversed_byte_get() >> + BYTE_3_SHIFT); + } + } else { + uint32_t i = 0; + + for (; i < hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count; i++) { + + switch (hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count - i) { + case 1: /* Last transfer */ + rx_shift_ctrl.shift_count = SHIFTCNTB_VALUE( + hrt_xfer_params->xfer_data[HRT_FE_DATA].last_word_clocks); + break; + case 2: /* Last but one transfer */ + rx_shift_ctrl.shift_count = + SHIFTCNTB_VALUE(hrt_xfer_params->xfer_data[HRT_FE_DATA] + .penultimate_word_clocks); + break; + default: + rx_shift_ctrl.shift_count = SHIFTCNTB_VALUE( + BITS_IN_WORD / hrt_xfer_params->bus_widths.data); + } + + if (i == 0) { + /* Value of 1 is set to SHIFTCNTOUT register to start MSPI clock + * running, 0 is not possible. Due to hardware error it causes 2*1 + * clock pulses to be generated. After that n-2 pulses have to be + * generated to receive total of n bits + */ + rx_shift_ctrl.shift_count -= 2; + nrf_vpr_csr_vio_shift_ctrl_buffered_set(&rx_shift_ctrl); + + nrf_vpr_csr_vtim_combined_counter_set( + (hrt_xfer_params->counter_value + << VPRCSR_NORDIC_CNT_CNT0_Pos) + + (CNT1_INIT_VALUE << VPRCSR_NORDIC_CNT_CNT1_Pos)); + /* Read INBRB to continue clock beyond first 2 pulses. */ + nrf_vpr_csr_vio_in_buffered_reversed_byte_get(); + + } else { + nrf_vpr_csr_vio_shift_ctrl_buffered_set(&rx_shift_ctrl); + + data[i - 1] = nrf_vpr_csr_vio_in_buffered_reversed_byte_get(); + } + } + + /* Wait for reception to end, transfer has to be stopped "manualy". + * Setting SHIFTCTRLB cannot be used because with RTPERIPHCTRL:STOPCOUNTERS == 1, + * counter stops 1 clock too early. + */ + while (nrf_vpr_csr_vio_shift_cnt_in_get() > 0) { + } + /* Wait until timer 0 stops. + * WAIT0 cannot be used for this because in higher frequencies function + * nrf_vpr_csr_vtim_simple_wait_set is called when CNT0 has already stopped, + * making code wait indefinitely. + */ + cnt0 = nrf_vpr_csr_vtim_simple_counter_get(0); + cnt0_prev = cnt0 + 1; + + while (cnt0 != cnt0_prev) { + cnt0_prev = cnt0; + cnt0 = nrf_vpr_csr_vtim_simple_counter_get(0); + } - /* Receive data. For QUAD_1_1_4 mode this starts later due to HW issue described above. */ - for (; iter < hrt_xfer_params->xfer_data[HRT_FE_DATA].word_count; iter++) { - hrt_xfer_params->xfer_data[HRT_FE_DATA].data[iter] = - nrf_vpr_csr_vio_in_buffered_reversed_byte_get() >> FOURTH_BYTE_SHIFT_CNT; + /* Reset VIO outputs. */ + nrf_vpr_csr_vio_out_buffered_reversed_word_set(prev_out << BYTE_3_SHIFT); + + /* Set out mode to none so that reading INB/INBRB register doesn't cause + * clock to continue running. + */ + rx_out_mode.mode = NRF_VPR_CSR_VIO_SHIFT_NONE; + nrf_vpr_csr_vio_mode_out_set(&rx_out_mode); + + hrt_xfer_params->xfer_data[HRT_FE_DATA].last_word = + nrf_vpr_csr_vio_in_buffered_reversed_byte_get() >> + (BITS_IN_WORD - hrt_xfer_params->xfer_data[HRT_FE_DATA].last_word_clocks * + hrt_xfer_params->bus_widths.data); } /* Stop counters */ @@ -376,7 +444,9 @@ void hrt_read(volatile hrt_xfer_t *hrt_xfer_params) nrf_vpr_csr_vtim_count_mode_set(1, NRF_VPR_CSR_VTIM_COUNT_STOP); /* Final configuration */ - nrf_vpr_csr_vio_shift_ctrl_buffered_set(&shift_ctrl); + rx_shift_ctrl.out_mode = NRF_VPR_CSR_VIO_SHIFT_NONE; + rx_shift_ctrl.in_mode = NRF_VPR_CSR_VIO_MODE_IN_CONTINUOUS; + nrf_vpr_csr_vio_shift_ctrl_buffered_set(&rx_shift_ctrl); /* Disable CS */ if (!hrt_xfer_params->ce_hold) { @@ -388,15 +458,7 @@ void hrt_read(volatile hrt_xfer_t *hrt_xfer_params) } } - /* Copy the first 4 bytes of data to buffer. */ - if (hrt_xfer_params->bus_widths.address != hrt_xfer_params->bus_widths.data) { - hrt_xfer_params->xfer_data[HRT_FE_DATA].data[0] = rec_data; - hrt_xfer_params->xfer_data[HRT_FE_DATA].data[1] = rec_data >> SECOND_BYTE_SHIFT_CNT; - hrt_xfer_params->xfer_data[HRT_FE_DATA].data[2] = rec_data >> THIRD_BYTE_SHIFT_CNT; - hrt_xfer_params->xfer_data[HRT_FE_DATA].data[3] = rec_data >> FOURTH_BYTE_SHIFT_CNT; - } - - /* Set DQ1 back as output in SINGLE mode. */ + /* Set DQ1 back as output. */ if (hrt_xfer_params->bus_widths.data == 1) { WRITE_BIT(hrt_xfer_params->tx_direction_mask, SPI_INPUT_PIN_NUM, VPRCSR_NORDIC_DIR_OUTPUT); diff --git a/applications/sdp/mspi/src/hrt/hrt.h b/applications/sdp/mspi/src/hrt/hrt.h index 63606ce2b52b..014e9a639b03 100644 --- a/applications/sdp/mspi/src/hrt/hrt.h +++ b/applications/sdp/mspi/src/hrt/hrt.h @@ -123,7 +123,7 @@ typedef struct { * * @param[in] hrt_xfer_params Hrt transfer parameters and data. */ -void hrt_write(hrt_xfer_t *hrt_xfer_params); +void hrt_write(volatile hrt_xfer_t *hrt_xfer_params); /** @brief Read. * diff --git a/applications/sdp/mspi/src/main.c b/applications/sdp/mspi/src/main.c index 1df6f2e91078..2d26c02c2197 100644 --- a/applications/sdp/mspi/src/main.c +++ b/applications/sdp/mspi/src/main.c @@ -24,8 +24,14 @@ #define DATA_PINS_MAX 8 #define VIO_COUNT 11 +/* Bellow this CNT0 period pin steering force has to be increased to produce correct waveform. + * CNT0 value 1 generates 32MHz clock. + */ #define STD_PAD_BIAS_CNT0_THRESHOLD 1 +/* Max RX frequency is 21.333333MHz which corresponds to counter period value of 2. */ +#define RX_CNT0_MIN_VALUE 2 + #define PAD_BIAS_VALUE 1 #define MAX_SHIFT_COUNT 63 @@ -91,6 +97,35 @@ static NRF_TIMER_Type *fault_timer; static volatile uint32_t *cpuflpr_error_ctx_ptr = (uint32_t *)DT_REG_ADDR(DT_NODELABEL(cpuflpr_error_code)); +static void distribute_last_word_bits(void) +{ + uint32_t *rx_data = (uint32_t *)xfer_params.xfer_data[HRT_FE_DATA].data; + uint32_t last_word = xfer_params.xfer_data[HRT_FE_DATA].last_word; + uint32_t word_count = xfer_params.xfer_data[HRT_FE_DATA].word_count; + uint32_t penultimate_word_bits = + xfer_params.xfer_data[HRT_FE_DATA].penultimate_word_clocks * + xfer_params.bus_widths.data; + uint32_t last_word_bits = + xfer_params.xfer_data[HRT_FE_DATA].last_word_clocks * xfer_params.bus_widths.data; + uint32_t penultimate_word_shift = BITS_IN_WORD - penultimate_word_bits; + /* In case when last word is too short, penultimate word has to give it 1 byte. + * this is here to pass this byte back to penultimate word to avoid holes. + */ + if ((penultimate_word_shift != 0) && (word_count > 1)) { + rx_data[word_count - 2] = (rx_data[word_count - 2] >> penultimate_word_shift) | + (last_word << penultimate_word_bits); + last_word = last_word >> penultimate_word_shift; + } + + /* This is to avoid writing outside of data buffer in case when buffer_length%4 != + * 0. + */ + for (uint8_t byte = 0; + byte < NRFX_CEIL_DIV(last_word_bits - penultimate_word_shift, BITS_IN_BYTE); byte++) { + ((uint8_t *)&(rx_data[word_count - 1]))[byte] = ((uint8_t *)&last_word)[byte]; + } +} + static void adjust_tail(volatile hrt_xfer_data_t *xfer_data, uint16_t frame_width, uint32_t data_length) { @@ -180,10 +215,24 @@ static void configure_clock(enum mspi_cpp_mode cpp_mode) nrf_vpr_csr_vio_config_set(&vio_config); } -static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet) +static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet, volatile uint8_t *rx_buffer) { + nrf_vpr_csr_vio_config_t config; volatile nrfe_mspi_dev_config_t *device = &nrfe_mspi_devices[nrfe_mspi_xfer_config_ptr->device_index]; + uint16_t dummy_cycles = 0; + + if (xfer_packet->opcode == NRFE_MSPI_TXRX) { + NRFX_ASSERT(device->cnt0_value >= RX_CNT0_MIN_VALUE); + + nrf_vpr_csr_vio_config_get(&config); + config.input_sel = true; + nrf_vpr_csr_vio_config_set(&config); + + dummy_cycles = nrfe_mspi_xfer_config_ptr->rx_dummy; + } else { + dummy_cycles = nrfe_mspi_xfer_config_ptr->tx_dummy; + } xfer_params.counter_value = device->cnt0_value; xfer_params.ce_vio = ce_vios[device->ce_index]; @@ -203,6 +252,7 @@ static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet) xfer_packet->address << (BITS_IN_WORD - nrfe_mspi_xfer_config_ptr->address_length * BITS_IN_BYTE); + /* Configure command phase. */ xfer_params.xfer_data[HRT_FE_COMMAND].fun_out = HRT_FUN_OUT_WORD; xfer_params.xfer_data[HRT_FE_COMMAND].data = (uint8_t *)&xfer_packet->command; xfer_params.xfer_data[HRT_FE_COMMAND].word_count = 0; @@ -210,6 +260,7 @@ static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet) adjust_tail(&xfer_params.xfer_data[HRT_FE_COMMAND], xfer_params.bus_widths.command, nrfe_mspi_xfer_config_ptr->command_length * BITS_IN_BYTE); + /* Configure address phase. */ xfer_params.xfer_data[HRT_FE_ADDRESS].fun_out = HRT_FUN_OUT_WORD; xfer_params.xfer_data[HRT_FE_ADDRESS].data = (uint8_t *)&xfer_packet->address; xfer_params.xfer_data[HRT_FE_ADDRESS].word_count = 0; @@ -217,6 +268,7 @@ static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet) adjust_tail(&xfer_params.xfer_data[HRT_FE_ADDRESS], xfer_params.bus_widths.address, nrfe_mspi_xfer_config_ptr->address_length * BITS_IN_BYTE); + /* Configure dummy_cycles phase. */ xfer_params.xfer_data[HRT_FE_DUMMY_CYCLES].fun_out = HRT_FUN_OUT_WORD; xfer_params.xfer_data[HRT_FE_DUMMY_CYCLES].data = NULL; xfer_params.xfer_data[HRT_FE_DUMMY_CYCLES].word_count = 0; @@ -228,22 +280,29 @@ static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet) * increasing shift count of last word in the previous part. * Beyond that, dummy cycles have to be treated af different transfer part. */ - if (xfer_params.xfer_data[elem].last_word_clocks + nrfe_mspi_xfer_config_ptr->tx_dummy <= - MAX_SHIFT_COUNT) { - xfer_params.xfer_data[elem].last_word_clocks += nrfe_mspi_xfer_config_ptr->tx_dummy; + if (xfer_params.xfer_data[elem].last_word_clocks + dummy_cycles <= MAX_SHIFT_COUNT) { + xfer_params.xfer_data[elem].last_word_clocks += dummy_cycles; } else { adjust_tail(&xfer_params.xfer_data[HRT_FE_DUMMY_CYCLES], xfer_params.bus_widths.dummy_cycles, - nrfe_mspi_xfer_config_ptr->tx_dummy * - xfer_params.bus_widths.dummy_cycles); + dummy_cycles * xfer_params.bus_widths.dummy_cycles); } + /* Configure data phase. */ xfer_params.xfer_data[HRT_FE_DATA].fun_out = HRT_FUN_OUT_BYTE; - xfer_params.xfer_data[HRT_FE_DATA].data = xfer_packet->data; xfer_params.xfer_data[HRT_FE_DATA].word_count = 0; + if (xfer_packet->opcode == NRFE_MSPI_TXRX) { + xfer_params.xfer_data[HRT_FE_DATA].data = NULL; + + adjust_tail(&xfer_params.xfer_data[HRT_FE_DATA], xfer_params.bus_widths.data, + xfer_packet->num_bytes * BITS_IN_BYTE); - adjust_tail(&xfer_params.xfer_data[HRT_FE_DATA], xfer_params.bus_widths.data, - xfer_packet->num_bytes * BITS_IN_BYTE); + xfer_params.xfer_data[HRT_FE_DATA].data = rx_buffer; + } else { + xfer_params.xfer_data[HRT_FE_DATA].data = xfer_packet->data; + adjust_tail(&xfer_params.xfer_data[HRT_FE_DATA], xfer_params.bus_widths.data, + xfer_packet->num_bytes * BITS_IN_BYTE); + } /* Hardware issue: Additional clock edge when transmitting in modes other * than MSPI_CPP_MODE_0. @@ -252,65 +311,27 @@ static void xfer_execute(nrfe_mspi_xfer_packet_msg_t *xfer_packet) * and disable clock before the last pulse. */ if (device->cpp == MSPI_CPP_MODE_2) { - for (uint8_t i = 0; i < HRT_FE_MAX; i++) { - if (xfer_params.xfer_data[HRT_FE_MAX - 1 - i].word_count != 0) { - xfer_params.xfer_data[HRT_FE_MAX - 1 - i].last_word_clocks++; + /* Ommit data phase in rx mode */ + for (uint8_t phase = xfer_packet->opcode == NRFE_MSPI_TXRX ? 1 : 0; + phase < HRT_FE_MAX; phase++) { + if (xfer_params.xfer_data[HRT_FE_MAX - 1 - phase].word_count != 0) { + xfer_params.xfer_data[HRT_FE_MAX - 1 - phase].last_word_clocks++; break; } } } - nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE)); -} - -void prepare_and_read_data(nrfe_mspi_xfer_packet_msg_t *xfer_packet, volatile uint8_t *buffer) -{ - volatile nrfe_mspi_dev_config_t *device = - &nrfe_mspi_devices[nrfe_mspi_xfer_config_ptr->device_index]; - nrf_vpr_csr_vio_config_t config; - - xfer_params.counter_value = device->cnt0_value; - xfer_params.ce_vio = ce_vios[device->ce_index]; - xfer_params.ce_hold = nrfe_mspi_xfer_config_ptr->hold_ce; - xfer_params.ce_polarity = device->ce_polarity; - xfer_params.bus_widths = io_modes[device->io_mode]; - xfer_params.xfer_data[HRT_FE_DATA].data = buffer; - - nrf_vpr_csr_vio_config_get(&config); - config.input_sel = true; - nrf_vpr_csr_vio_config_set(&config); - - /* - * Fix position of command and address if command/address length is < BITS_IN_WORD, - * so that leading zeros would not be printed instead of data bits. - */ - xfer_packet->command = - xfer_packet->command - << (BITS_IN_WORD - nrfe_mspi_xfer_config_ptr->command_length * BITS_IN_BYTE); - xfer_packet->address = - xfer_packet->address - << (BITS_IN_WORD - nrfe_mspi_xfer_config_ptr->address_length * BITS_IN_BYTE); - - /* Configure command phase. */ - xfer_params.xfer_data[HRT_FE_COMMAND].fun_out = HRT_FUN_OUT_WORD; - xfer_params.xfer_data[HRT_FE_COMMAND].data = (uint8_t *)&xfer_packet->command; - xfer_params.xfer_data[HRT_FE_COMMAND].word_count = - nrfe_mspi_xfer_config_ptr->command_length; - - /* Configure address phase. */ - xfer_params.xfer_data[HRT_FE_ADDRESS].fun_out = HRT_FUN_OUT_WORD; - xfer_params.xfer_data[HRT_FE_ADDRESS].data = (uint8_t *)&xfer_packet->address; - xfer_params.xfer_data[HRT_FE_ADDRESS].word_count = - nrfe_mspi_xfer_config_ptr->address_length; - - /* Configure data phase. */ - xfer_params.xfer_data[HRT_FE_DATA].word_count = xfer_packet->num_bytes; - /* Read/write barrier to make sure that all configuration is done before jumping to HRT. */ nrf_barrier_rw(); - /* Read data */ - nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_READ)); + if (xfer_packet->opcode == NRFE_MSPI_TXRX) { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_READ)); + + distribute_last_word_bits(); + + } else { + nrf_vpr_clic_int_pending_set(NRF_VPRCLIC, VEVIF_IRQN(HRT_VEVIF_IDX_WRITE)); + } } static void config_pins(nrfe_mspi_pinctrl_soc_pin_msg_t *pins_cfg) @@ -465,14 +486,19 @@ static void ep_recv(const void *data, size_t len, void *priv) case NRFE_MSPI_TX: nrfe_mspi_xfer_packet_msg_t *packet = (nrfe_mspi_xfer_packet_msg_t *)data; - xfer_execute(packet); + xfer_execute(packet, NULL); break; case NRFE_MSPI_TXRX: { nrfe_mspi_xfer_packet_msg_t *packet = (nrfe_mspi_xfer_packet_msg_t *)data; - num_bytes = packet->num_bytes; - - if (num_bytes > 0) { - prepare_and_read_data(packet, response_buffer + 1); + if (packet->num_bytes > 0) { +#ifdef CONFIG_SDP_MSPI_IPC_NO_COPY + xfer_execute(packet, packet->data); +#else + NRFX_ASSERT(packet->num_bytes <= + CONFIG_SDP_MSPI_MAX_RESPONSE_SIZE - sizeof(nrfe_mspi_opcode_t)); + num_bytes = packet->num_bytes; + xfer_execute(packet, response_buffer + sizeof(nrfe_mspi_opcode_t)); +#endif } break; } @@ -482,7 +508,9 @@ static void ep_recv(const void *data, size_t len, void *priv) } response_buffer[0] = opcode; - ipc_service_send(&ep, (const void *)response_buffer, sizeof(opcode) + num_bytes); + ipc_service_send(&ep, (const void *)response_buffer, + sizeof(nrfe_mspi_opcode_t) + num_bytes); + #if defined(CONFIG_SDP_MSPI_FAULT_TIMER) if (fault_timer != NULL) { nrf_timer_task_trigger(fault_timer, NRF_TIMER_TASK_CLEAR); @@ -534,7 +562,7 @@ __attribute__((interrupt)) void hrt_handler_read(void) __attribute__((interrupt)) void hrt_handler_write(void) { - hrt_write((hrt_xfer_t *)&xfer_params); + hrt_write(&xfer_params); } /** diff --git a/drivers/mspi/mspi_nrfe.c b/drivers/mspi/mspi_nrfe.c index 862b042712c7..be2f39dba623 100644 --- a/drivers/mspi/mspi_nrfe.c +++ b/drivers/mspi/mspi_nrfe.c @@ -526,7 +526,7 @@ static int xfer_packet(struct mspi_xfer_packet *packet, uint32_t timeout) nrfe_mspi_opcode_t opcode = (packet->dir == MSPI_RX) ? NRFE_MSPI_TXRX : NRFE_MSPI_TX; #ifdef CONFIG_MSPI_NRFE_IPC_NO_COPY - /* Check for alignment problems. */ + /* In case of buffer alignment problems: create correctly aligned temporary buffer. */ uint32_t len = ((uint32_t)packet->data_buf) % sizeof(uint32_t) != 0 ? sizeof(nrfe_mspi_xfer_packet_msg_t) + packet->num_bytes : sizeof(nrfe_mspi_xfer_packet_msg_t); @@ -542,10 +542,14 @@ static int xfer_packet(struct mspi_xfer_packet *packet, uint32_t timeout) xfer_packet->num_bytes = packet->num_bytes; #ifdef CONFIG_MSPI_NRFE_IPC_NO_COPY - /* Check for alignlemt problems. */ + /* In case of buffer alignment problems: fill temporary buffer with TX data and + * set it as packet data. + */ if (((uint32_t)packet->data_buf) % sizeof(uint32_t) != 0) { - memcpy((void *)(buffer + sizeof(nrfe_mspi_xfer_packet_msg_t)), - (void *)packet->data_buf, packet->num_bytes); + if (packet->dir == MSPI_TX) { + memcpy((void *)(buffer + sizeof(nrfe_mspi_xfer_packet_msg_t)), + (void *)packet->data_buf, packet->num_bytes); + } xfer_packet->data = buffer + sizeof(nrfe_mspi_xfer_packet_msg_t); } else { xfer_packet->data = packet->data_buf; @@ -557,20 +561,39 @@ static int xfer_packet(struct mspi_xfer_packet *packet, uint32_t timeout) rc = send_data(xfer_packet->opcode, xfer_packet, len); /* Wait for the transfer to complete and receive data. */ - if ((packet->dir == MSPI_RX) && (ipc_receive_buffer != NULL) && (ipc_received > 0)) { - /* - * It is not possible to check whether received data is valid, so packet->num_bytes - * should always be equal to ipc_received. If it is not, then something went wrong. + if (packet->dir == MSPI_RX) { + + /* In case of CONFIG_MSPI_NRFE_IPC_NO_COPY ipc_received if equal to 0 because + * packet buffer address was passed to vpr and data was written directly there. + * So there is no way of checking how much data was written. + */ +#ifdef CONFIG_MSPI_NRFE_IPC_NO_COPY + /* In case of buffer alignment problems: copy received data from temporary buffer + * back to users buffer. */ - if (packet->num_bytes != ipc_received) { - rc = -EIO; - } else { - memcpy((void *)packet->data_buf, (void *)ipc_receive_buffer, ipc_received); + if (((uint32_t)packet->data_buf) % sizeof(uint32_t) != 0) { + memcpy((void *)packet->data_buf, (void *)xfer_packet->data, + packet->num_bytes); } +#else + if ((ipc_receive_buffer != NULL) && (ipc_received > 0)) { + /* + * It is not possible to check whether received data is valid, so + * packet->num_bytes should always be equal to ipc_received. If it is not, + * then something went wrong. + */ + if (packet->num_bytes != ipc_received) { + rc = -EIO; + } else { + memcpy((void *)packet->data_buf, (void *)ipc_receive_buffer, + ipc_received); + } - /* Clear the receive buffer pointer and size */ - ipc_receive_buffer = NULL; - ipc_received = 0; + /* Clear the receive buffer pointer and size */ + ipc_receive_buffer = NULL; + ipc_received = 0; + } +#endif } return rc; diff --git a/include/drivers/mspi/nrfe_mspi.h b/include/drivers/mspi/nrfe_mspi.h index 3d8d55f6fa45..31cb73ab4731 100644 --- a/include/drivers/mspi/nrfe_mspi.h +++ b/include/drivers/mspi/nrfe_mspi.h @@ -41,7 +41,9 @@ typedef enum { NRFE_MSPI_TXRX, NRFE_MSPI_SDP_APP_HARD_FAULT, NRFE_MSPI_WRONG_OPCODE, - NRFE_MSPI_ALL_OPCODES = NRFE_MSPI_WRONG_OPCODE, + NRFE_MSPI_OPCODES_COUNT = NRFE_MSPI_WRONG_OPCODE, + /* This is to make sizeof(nrfe_mspi_opcode_t)==32bit, for alignment purpouse. */ + NREE_MSPI_OPCODES_MAX = 0xFFFFFFFFU, } nrfe_mspi_opcode_t; typedef struct { @@ -95,7 +97,7 @@ typedef struct { } nrfe_mspi_xfer_packet_msg_t; typedef struct { - nrfe_mspi_opcode_t opcode; /* Same as application's request. */ + nrfe_mspi_opcode_t opcode; uint8_t data; } nrfe_mspi_flpr_response_msg_t; diff --git a/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay b/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay index 98eb8b27c236..bc4fc1a6370a 100644 --- a/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay +++ b/snippets/sdp/mspi/soc/nrf54l15_cpuapp.overlay @@ -10,29 +10,29 @@ #address-cells = <1>; #size-cells = <1>; - cpuflpr_code_partition: image@17a000 { - reg = <0x17a000 DT_SIZE_K(12)>; + cpuflpr_code_partition: image@179400 { + reg = <0x179400 DT_SIZE_K(15)>; }; - sram_rx: memory@2003c000 { - reg = <0x2003c000 0x07f0>; + sram_rx: memory@2003b400 { + reg = <0x2003b400 0x07f0>; }; - sram_tx: memory@2003c7f0 { - reg = <0x2003c7f0 0x07f0>; + sram_tx: memory@2003bbf0 { + reg = <0x2003bbf0 0x07f0>; }; - cpuflpr_error_code: memory@2003cfe0 { - reg = <0x2003cfe0 0x0020>; /* 32bytes */ + cpuflpr_error_code: memory@2003c3e0 { + reg = <0x2003c3e0 0x0020>; /* 32bytes */ }; }; - cpuflpr_sram_code_data: memory@2003d000 { + cpuflpr_sram_code_data: memory@2003c400 { compatible = "mmio-sram"; - reg = <0x2003d000 DT_SIZE_K(12)>; + reg = <0x2003c400 DT_SIZE_K(15)>; #address-cells = <1>; #size-cells = <1>; - ranges = <0x0 0x2003d000 0x3000>; + ranges = <0x0 0x2003c400 0x3c00>; }; }; @@ -49,12 +49,12 @@ }; &cpuapp_rram { - reg = <0x0 DT_SIZE_K(1512)>; + reg = <0x0 DT_SIZE_K(1509)>; }; &cpuapp_sram { - reg = <0x20000000 DT_SIZE_K(240)>; - ranges = <0x0 0x20000000 0x3c000>; + reg = <0x20000000 DT_SIZE_K(237)>; + ranges = <0x0 0x20000000 0x3b400>; }; &cpuflpr_vpr {