media: tegra_cec: a fix and an enhancement
Subsystems (4)
cover media: tegra_cec: a fix and an enhancement
Two tegra_cec patches: the first works around a HW bug where, if a transmit was NACKed, the retransmit would contain corrupt data.
The second logs when a Low Drive is received (i.e. generated by another CEC device). This helps debug issues with (typically) bad cables or CEC voltages.
Regards,
Hans
Hans Verkuil (2):
media: cec: tegra_cec: don't break off msg on NACK
media: cec: tegra_cec: keep track of number of Rx Low Drives
drivers/media/cec/platform/tegra/tegra_cec.c | 32 +++++++++++++++++++- 1 file changed, 31 insertions(+), 1 deletion(-)
Signature · 1 line
2.53.0
PATCH 1/2 media: cec: tegra_cec: don't break off msg on NACK
The Tegra CEC hardware has a bug where, if the first attempt to transmit a message is NACKed so the transmit is aborted, then the second attempt can contain corrupt data.
Ensure that the full message is always transmitted to avoid hitting this bug.
I suspect some internal state is not reset in the case of aborting a message due to a NACK.
--- drivers/media/cec/platform/tegra/tegra_cec.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
drivers/media/cec/platform/tegra/tegra_cec.c +12 -1
@@ -243,7 +243,18 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); -cec_write (cec,TEGRA_CEC_HW_CONTROL ,TEGRA_CEC_HWCTRL_TX_RX_MODE ); +/* +* TX_NAK_MODE ensures that the whole message is transmitted even +* if each byte is NACKed. Without this flag the retransmit of the +* messages after a NACK can be corrupt. This is a bug in the hardware. +* +* While less efficient, in practice you rarely transmit messages +* that can be NACKed, with the exception of POLL messages which +* are just one byte anyway. +*/ +cec_write (cec,TEGRA_CEC_HW_CONTROL , +TEGRA_CEC_HWCTRL_TX_RX_MODE | +TEGRA_CEC_HWCTRL_TX_NAK_MODE );return 0 ; }
Signature · 1 line
2.53.0
Re: [PATCH 1/2] media: cec: tegra_cec: don't break off msg on NACK
Quoted 43 lines · Hans Verkuil
The Tegra CEC hardware has a bug where, if the first attempt to transmit a message is NACKed so the transmit is aborted, then the second attempt can contain corrupt data.
Ensure that the full message is always transmitted to avoid hitting this bug.
I suspect some internal state is not reset in the case of aborting a message due to a NACK.
Signed-off-by Hans Verkuil <[email protected]>--- drivers/media/cec/platform/tegra/tegra_cec.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)drivers/media/cec/platform/tegra/tegra_cec.c +12
-1@@ -243,7 +243,18 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED); -cec_write (cec,TEGRA_CEC_HW_CONTROL ,TEGRA_CEC_HWCTRL_TX_RX_MODE ); +/* +* TX_NAK_MODE ensures that the whole message is transmitted even +* if each byte is NACKed. Without this flag the retransmit of the +* messages after a NACK can be corrupt. This is a bug in the hardware. +* +* While less efficient, in practice you rarely transmit messages +* that can be NACKed, with the exception of POLL messages which +* are just one byte anyway. +*/ +cec_write (cec,TEGRA_CEC_HW_CONTROL , +TEGRA_CEC_HWCTRL_TX_RX_MODE | +TEGRA_CEC_HWCTRL_TX_NAK_MODE );return 0 ; }Signature · 1 line
2.53.0
PATCH 2/2 media: cec: tegra_cec: keep track of number of Rx Low Drives
In reply to Hans VerkuilKeep track of Rx Low Drive conditions. Useful for detecting potential hardware/cable problems as it suggests unstable or incorrect voltage levels.
Note that the Tx Low Drive conditions are already logged in the CEC core.
--- drivers/media/cec/platform/tegra/tegra_cec.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
drivers/media/cec/platform/tegra/tegra_cec.c +19 -0
@@ -24,6 +24,7 @@#include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/clk/tegra.h> #include <media/cec-notifier.h>
@@ -47,6 +48,7 @@ struct tegra_cec {u32 tx_buf[CEC_MAX_MSG_SIZE ];u8 tx_buf_cur;u8 tx_buf_cnt; +u32 rx_total_low_drives; };static inline u32 cec_read (struct tegra_cec *cec,u32 reg)
@@ -116,6 +118,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data)return IRQ_WAKE_THREAD ; } +if (status &TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED ) { +dev_warn_ratelimited (dev,"RX bus error detected, generated low drive\n" ); + cec->rx_total_low_drives++; +cec_write (cec,TEGRA_CEC_INT_STAT , +TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED ); + } +if ((status &TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED ) || (status &TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED )) {tegra_cec_error_recovery (cec);
@@ -241,6 +250,7 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED |TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | +TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED | TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED);/*
@@ -318,11 +328,20 @@ static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,return 0 ; } +static void tegra_cec_adap_status (struct cec_adapter *adap,struct seq_file *file) +{ +struct tegra_cec *cec = adap->priv; + +seq_printf (file,"receive low drive count: %u\n" , + cec->rx_total_low_drives); +} +static const struct cec_adap_ops tegra_cec_ops = { .adap_enable = tegra_cec_adap_enable, .adap_log_addr = tegra_cec_adap_log_addr, .adap_transmit = tegra_cec_adap_transmit, .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, + .adap_status = tegra_cec_adap_status, };static int tegra_cec_probe (struct platform_device *pdev)
Signature · 1 line
2.53.0
Re: [PATCH 2/2] media: cec: tegra_cec: keep track of number of Rx Low Drives
Quoted 79 lines · Hans Verkuil
Keep track of Rx Low Drive conditions. Useful for detecting potential hardware/cable problems as it suggests unstable or incorrect voltage levels.
Note that the Tx Low Drive conditions are already logged in the CEC core.
Signed-off-by Hans Verkuil <[email protected]>--- drivers/media/cec/platform/tegra/tegra_cec.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)drivers/media/cec/platform/tegra/tegra_cec.c +19
-0@@ -24,6 +24,7 @@#include <linux/of.h> #include <linux/of_platform.h> #include <linux/platform_device.h> +#include <linux/seq_file.h> #include <linux/clk/tegra.h> #include <media/cec-notifier.h> @@ -47,6 +48,7 @@ struct tegra_cec {u32 tx_buf[CEC_MAX_MSG_SIZE ];u8 tx_buf_cur;u8 tx_buf_cnt; +u32 rx_total_low_drives; };static inline u32 cec_read (struct tegra_cec *cec,u32 reg)@@ -116,6 +118,13 @@ static irqreturn_t tegra_cec_irq_handler(int irq, void *data)return IRQ_WAKE_THREAD ; } +if (status &TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED ) { +dev_warn_ratelimited (dev,"RX bus error detected, generated low drive\n" ); + cec->rx_total_low_drives++; +cec_write (cec,TEGRA_CEC_INT_STAT , +TEGRA_CEC_INT_STAT_RX_BUS_ERROR_DETECTED ); + } +if ((status &TEGRA_CEC_INT_STAT_TX_ARBITRATION_FAILED ) || (status &TEGRA_CEC_INT_STAT_TX_BUS_ANOMALY_DETECTED )) {tegra_cec_error_recovery (cec);@@ -241,6 +250,7 @@ static int tegra_cec_adap_enable(struct cec_adapter *adap, bool enable)TEGRA_CEC_INT_MASK_TX_BUS_ANOMALY_DETECTED |TEGRA_CEC_INT_MASK_TX_FRAME_TRANSMITTED |TEGRA_CEC_INT_MASK_RX_REGISTER_FULL | +TEGRA_CEC_INT_MASK_RX_BUS_ERROR_DETECTED | TEGRA_CEC_INT_MASK_RX_START_BIT_DETECTED);/* @@ -318,11 +328,20 @@ static int tegra_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,return 0 ; } +static void tegra_cec_adap_status (struct cec_adapter *adap,struct seq_file *file) +{ +struct tegra_cec *cec = adap->priv; + +seq_printf (file,"receive low drive count: %u\n" , + cec->rx_total_low_drives); +} +static const struct cec_adap_ops tegra_cec_ops = { .adap_enable = tegra_cec_adap_enable, .adap_log_addr = tegra_cec_adap_log_addr, .adap_transmit = tegra_cec_adap_transmit, .adap_monitor_all_enable = tegra_cec_adap_monitor_all_enable, + .adap_status = tegra_cec_adap_status, };static int tegra_cec_probe (struct platform_device *pdev)Signature · 1 line
2.53.0