On Mon Jun 30 13:08:46 2025 +0200, Hans Verkuil wrote:
> This adds support for inserting 'glitches' after a falling and/or
> rising edge. This tests what happens when there are little voltage
> spikes after falling or rising edges, which can be caused due to
> noise or reflections on the CEC line.
> 
> A proper CEC implementation will deglitch this, but a poor implementation
> can create a Low Drive pulse in response, effectively making CEC unusable.
> 
> Signed-off-by: Hans Verkuil <hverk...@xs4all.nl>
> Signed-off-by: Mauro Carvalho Chehab <mchehab+hua...@kernel.org>

Patch committed.

Thanks,
Mauro Carvalho Chehab

 drivers/media/cec/core/cec-pin-error-inj.c | 48 +++++++++++++++++++++++++++++-
 drivers/media/cec/core/cec-pin-priv.h      |  7 +++++
 drivers/media/cec/core/cec-pin.c           | 29 ++++++++++++++++++
 3 files changed, 83 insertions(+), 1 deletion(-)

---

diff --git a/drivers/media/cec/core/cec-pin-error-inj.c 
b/drivers/media/cec/core/cec-pin-error-inj.c
index 6e61a04b8168..68cbd83dfd6e 100644
--- a/drivers/media/cec/core/cec-pin-error-inj.c
+++ b/drivers/media/cec/core/cec-pin-error-inj.c
@@ -95,6 +95,10 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter *adap, 
char *line)
                pin->tx_custom_pulse = false;
                pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
                pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
+               pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT;
+               pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT;
+               pin->tx_glitch_falling_edge = false;
+               pin->tx_glitch_rising_edge = false;
                return true;
        }
        if (!strcmp(token, "rx-clear")) {
@@ -111,6 +115,10 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter 
*adap, char *line)
                pin->tx_custom_pulse = false;
                pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
                pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
+               pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT;
+               pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT;
+               pin->tx_glitch_falling_edge = false;
+               pin->tx_glitch_rising_edge = false;
                return true;
        }
        if (!strcmp(token, "tx-ignore-nack-until-eom")) {
@@ -122,6 +130,14 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter 
*adap, char *line)
                cec_pin_start_timer(pin);
                return true;
        }
+       if (!strcmp(token, "tx-glitch-falling-edge")) {
+               pin->tx_glitch_falling_edge = true;
+               return true;
+       }
+       if (!strcmp(token, "tx-glitch-rising-edge")) {
+               pin->tx_glitch_rising_edge = true;
+               return true;
+       }
        if (!p)
                return false;
 
@@ -139,7 +155,23 @@ bool cec_pin_error_inj_parse_line(struct cec_adapter 
*adap, char *line)
 
                if (kstrtou32(p, 0, &usecs) || usecs > 10000000)
                        return false;
-               pin->tx_custom_high_usecs = usecs;
+               pin->tx_glitch_high_usecs = usecs;
+               return true;
+       }
+       if (!strcmp(token, "tx-glitch-low-usecs")) {
+               u32 usecs;
+
+               if (kstrtou32(p, 0, &usecs) || usecs > 100)
+                       return false;
+               pin->tx_glitch_low_usecs = usecs;
+               return true;
+       }
+       if (!strcmp(token, "tx-glitch-high-usecs")) {
+               u32 usecs;
+
+               if (kstrtou32(p, 0, &usecs) || usecs > 100)
+                       return false;
+               pin->tx_glitch_high_usecs = usecs;
                return true;
        }
 
@@ -285,6 +317,10 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, 
struct seq_file *sf)
        seq_puts(sf, "#   tx-custom-low-usecs <usecs>        define the 'low' 
time for the custom pulse\n");
        seq_puts(sf, "#   tx-custom-high-usecs <usecs>       define the 'high' 
time for the custom pulse\n");
        seq_puts(sf, "#   tx-custom-pulse                    transmit the 
custom pulse once the bus is idle\n");
+       seq_puts(sf, "#   tx-glitch-low-usecs <usecs>        define the 'low' 
time for the glitch pulse\n");
+       seq_puts(sf, "#   tx-glitch-high-usecs <usecs>       define the 'high' 
time for the glitch pulse\n");
+       seq_puts(sf, "#   tx-glitch-falling-edge             send the glitch 
pulse after every falling edge\n");
+       seq_puts(sf, "#   tx-glitch-rising-edge              send the glitch 
pulse after every rising edge\n");
        seq_puts(sf, "#\n");
        seq_puts(sf, "# TX error injection:\n");
        seq_puts(sf, "#   <op>[,<mode>] tx-no-eom            don't set the EOM 
bit\n");
@@ -334,6 +370,10 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, 
struct seq_file *sf)
 
        if (pin->tx_ignore_nack_until_eom)
                seq_puts(sf, "tx-ignore-nack-until-eom\n");
+       if (pin->tx_glitch_falling_edge)
+               seq_puts(sf, "tx-glitch-falling-edge\n");
+       if (pin->tx_glitch_rising_edge)
+               seq_puts(sf, "tx-glitch-rising-edge\n");
        if (pin->tx_custom_pulse)
                seq_puts(sf, "tx-custom-pulse\n");
        if (pin->tx_custom_low_usecs != CEC_TIM_CUSTOM_DEFAULT)
@@ -342,5 +382,11 @@ int cec_pin_error_inj_show(struct cec_adapter *adap, 
struct seq_file *sf)
        if (pin->tx_custom_high_usecs != CEC_TIM_CUSTOM_DEFAULT)
                seq_printf(sf, "tx-custom-high-usecs %u\n",
                           pin->tx_custom_high_usecs);
+       if (pin->tx_glitch_low_usecs != CEC_TIM_GLITCH_DEFAULT)
+               seq_printf(sf, "tx-glitch-low-usecs %u\n",
+                          pin->tx_glitch_low_usecs);
+       if (pin->tx_glitch_high_usecs != CEC_TIM_GLITCH_DEFAULT)
+               seq_printf(sf, "tx-glitch-high-usecs %u\n",
+                          pin->tx_glitch_high_usecs);
        return 0;
 }
diff --git a/drivers/media/cec/core/cec-pin-priv.h 
b/drivers/media/cec/core/cec-pin-priv.h
index 156a9f81be94..88eefcb60ab8 100644
--- a/drivers/media/cec/core/cec-pin-priv.h
+++ b/drivers/media/cec/core/cec-pin-priv.h
@@ -164,6 +164,9 @@ enum cec_pin_state {
 /* The default for the low/high time of the custom pulse */
 #define CEC_TIM_CUSTOM_DEFAULT                         1000
 
+/* The default for the low/high time of the glitch pulse */
+#define CEC_TIM_GLITCH_DEFAULT                         1
+
 #define CEC_NUM_PIN_EVENTS                             128
 #define CEC_PIN_EVENT_FL_IS_HIGH                       (1 << 0)
 #define CEC_PIN_EVENT_FL_DROPPED                       (1 << 1)
@@ -227,10 +230,14 @@ struct cec_pin {
 
        u32                             tx_custom_low_usecs;
        u32                             tx_custom_high_usecs;
+       u32                             tx_glitch_low_usecs;
+       u32                             tx_glitch_high_usecs;
        bool                            tx_ignore_nack_until_eom;
        bool                            tx_custom_pulse;
        bool                            tx_generated_poll;
        bool                            tx_post_eom;
+       bool                            tx_glitch_falling_edge;
+       bool                            tx_glitch_rising_edge;
        u8                              tx_extra_bytes;
        u32                             tx_low_drive_cnt;
 #ifdef CONFIG_CEC_PIN_ERROR_INJ
diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c
index 59ac12113f3a..f3b0febf0f1c 100644
--- a/drivers/media/cec/core/cec-pin.c
+++ b/drivers/media/cec/core/cec-pin.c
@@ -142,15 +142,42 @@ static bool cec_pin_read(struct cec_pin *pin)
        return v;
 }
 
+static void cec_pin_insert_glitch(struct cec_pin *pin, bool rising_edge)
+{
+       /*
+        * Insert a short glitch after the falling or rising edge to
+        * simulate reflections on the CEC line. This can be used to
+        * test deglitch filters, which should be present in CEC devices
+        * to deal with noise on the line.
+        */
+       if (!pin->tx_glitch_high_usecs || !pin->tx_glitch_low_usecs)
+               return;
+       if (rising_edge) {
+               udelay(pin->tx_glitch_high_usecs);
+               call_void_pin_op(pin, low);
+               udelay(pin->tx_glitch_low_usecs);
+               call_void_pin_op(pin, high);
+       } else {
+               udelay(pin->tx_glitch_low_usecs);
+               call_void_pin_op(pin, high);
+               udelay(pin->tx_glitch_high_usecs);
+               call_void_pin_op(pin, low);
+       }
+}
+
 static void cec_pin_low(struct cec_pin *pin)
 {
        call_void_pin_op(pin, low);
+       if (pin->tx_glitch_falling_edge && pin->adap->cec_pin_is_high)
+               cec_pin_insert_glitch(pin, false);
        cec_pin_update(pin, false, false);
 }
 
 static bool cec_pin_high(struct cec_pin *pin)
 {
        call_void_pin_op(pin, high);
+       if (pin->tx_glitch_rising_edge && !pin->adap->cec_pin_is_high)
+               cec_pin_insert_glitch(pin, true);
        return cec_pin_read(pin);
 }
 
@@ -1350,6 +1377,8 @@ struct cec_adapter *cec_pin_allocate_adapter(const struct 
cec_pin_ops *pin_ops,
        init_waitqueue_head(&pin->kthread_waitq);
        pin->tx_custom_low_usecs = CEC_TIM_CUSTOM_DEFAULT;
        pin->tx_custom_high_usecs = CEC_TIM_CUSTOM_DEFAULT;
+       pin->tx_glitch_low_usecs = CEC_TIM_GLITCH_DEFAULT;
+       pin->tx_glitch_high_usecs = CEC_TIM_GLITCH_DEFAULT;
 
        adap = cec_allocate_adapter(&cec_pin_adap_ops, priv, name,
                            caps | CEC_CAP_MONITOR_ALL | CEC_CAP_MONITOR_PIN,

Reply via email to