From 84cbf1d198d035471965232e89b4650c54edcfb1 Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjoerd@collabora.com>
Date: Sat, 15 Jun 2024 16:38:07 +0200
Subject: [PATCH 1/2] [UCPD] Don't disable ucpd rx after each reception

When disabling the UCPD RX after every reception it's relatively easy to
drop packets. This seems to happen in particular with GoodCRC packets
which can be sent very quickly by a receiver. To avoid this enable
reception as soon as the pd phy get split out (preparing for packet
processing) and only disable again when the pd phy gets dropped.
---
 embassy-stm32/src/ucpd.rs | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index 89e2f5d49..cbec85ff3 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -169,6 +169,9 @@ impl<'d, T: Instance> Ucpd<'d, T> {
         // Enable hard reset receive interrupt.
         r.imr().modify(|w| w.set_rxhrstdetie(true));
 
+        // Enable PD packet reception
+        r.cr().modify(|w| w.set_phyrxen(true));
+
         // Both parts must be dropped before the peripheral can be disabled.
         T::state().drop_not_ready.store(true, Ordering::Relaxed);
 
@@ -319,6 +322,7 @@ pub struct PdPhy<'d, T: Instance> {
 
 impl<'d, T: Instance> Drop for PdPhy<'d, T> {
     fn drop(&mut self) {
+        T::REGS.cr().modify(|w| w.set_phyrxen(false));
         // Check if the Type-C part was dropped already.
         let drop_not_ready = &T::state().drop_not_ready;
         if drop_not_ready.load(Ordering::Relaxed) {
@@ -350,9 +354,7 @@ impl<'d, T: Instance> PdPhy<'d, T> {
             w.set_rxmsgendcf(true);
         });
 
-        r.cr().modify(|w| w.set_phyrxen(true));
         let _on_drop = OnDrop::new(|| {
-            r.cr().modify(|w| w.set_phyrxen(false));
             Self::enable_rx_interrupt(false);
         });
 

From 9e8035cfb922d1b85f020e31bee2d3f815ba6f28 Mon Sep 17 00:00:00 2001
From: Sjoerd Simons <sjoerd@collabora.com>
Date: Sun, 16 Jun 2024 11:00:56 +0200
Subject: [PATCH 2/2] [USPD] clear interrupt flags right after reception

Clearing the interrupt flags at beginning of reception will masks
overruns and cause corrupted packets to be received. Instead clear the
flags right after disabling the interrupt/after reception, so overruns
on the next receive can be caught.

Tested by forcing overruns due to explicit sleeps

Signed-off-by: Sjoerd Simons <sjoerd@collabora.com>
---
 embassy-stm32/src/ucpd.rs | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/embassy-stm32/src/ucpd.rs b/embassy-stm32/src/ucpd.rs
index cbec85ff3..40aea75cb 100644
--- a/embassy-stm32/src/ucpd.rs
+++ b/embassy-stm32/src/ucpd.rs
@@ -347,15 +347,14 @@ impl<'d, T: Instance> PdPhy<'d, T> {
                 .read(r.rxdr().as_ptr() as *mut u8, buf, TransferOptions::default())
         };
 
-        // Clear interrupt flags (possibly set from last receive).
-        r.icr().write(|w| {
-            w.set_rxorddetcf(true);
-            w.set_rxovrcf(true);
-            w.set_rxmsgendcf(true);
-        });
-
         let _on_drop = OnDrop::new(|| {
             Self::enable_rx_interrupt(false);
+            // Clear interrupt flags
+            r.icr().write(|w| {
+                w.set_rxorddetcf(true);
+                w.set_rxovrcf(true);
+                w.set_rxmsgendcf(true);
+            });
         });
 
         poll_fn(|cx| {