1 From 423173ed6e873ec9a6ae0e62d55bd4c746f0f982 Mon Sep 17 00:00:00 2001
2 From: Maxime Ripard <maxime@cerno.tech>
3 Date: Mon, 11 Jan 2021 15:23:03 +0100
4 Subject: [PATCH] drm/vc4: hdmi: Split the interrupt handlers
6 The BCM2711 has two different interrupt sources to transmit and receive
7 CEC messages, provided through an external interrupt chip shared between
8 the two HDMI interrupt controllers.
10 The rest of the CEC controller is identical though so we need to change
11 a bit the code organisation to share the code as much as possible, yet
12 still allowing to register independant handlers.
14 Signed-off-by: Maxime Ripard <maxime@cerno.tech>
15 Reviewed-by: Dave Stevenson <dave.stevenson@raspberrypi.com>
17 drivers/gpu/drm/vc4/vc4_hdmi.c | 86 +++++++++++++++++++++++++---------
18 1 file changed, 65 insertions(+), 21 deletions(-)
20 --- a/drivers/gpu/drm/vc4/vc4_hdmi.c
21 +++ b/drivers/gpu/drm/vc4/vc4_hdmi.c
22 @@ -1574,15 +1574,22 @@ static int vc4_hdmi_audio_init(struct vc
25 #ifdef CONFIG_DRM_VC4_HDMI_CEC
26 -static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
27 +static irqreturn_t vc4_cec_irq_handler_rx_thread(int irq, void *priv)
29 + struct vc4_hdmi *vc4_hdmi = priv;
31 + if (vc4_hdmi->cec_rx_msg.len)
32 + cec_received_msg(vc4_hdmi->cec_adap,
33 + &vc4_hdmi->cec_rx_msg);
38 +static irqreturn_t vc4_cec_irq_handler_tx_thread(int irq, void *priv)
40 struct vc4_hdmi *vc4_hdmi = priv;
42 - if (vc4_hdmi->cec_irq_was_rx) {
43 - if (vc4_hdmi->cec_rx_msg.len)
44 - cec_received_msg(vc4_hdmi->cec_adap,
45 - &vc4_hdmi->cec_rx_msg);
46 - } else if (vc4_hdmi->cec_tx_ok) {
47 + if (vc4_hdmi->cec_tx_ok) {
48 cec_transmit_done(vc4_hdmi->cec_adap, CEC_TX_STATUS_OK,
51 @@ -1596,6 +1603,19 @@ static irqreturn_t vc4_cec_irq_handler_t
55 +static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
57 + struct vc4_hdmi *vc4_hdmi = priv;
60 + if (vc4_hdmi->cec_irq_was_rx)
61 + ret = vc4_cec_irq_handler_rx_thread(irq, priv);
63 + ret = vc4_cec_irq_handler_tx_thread(irq, priv);
68 static void vc4_cec_read_msg(struct vc4_hdmi *vc4_hdmi, u32 cntrl1)
70 struct drm_device *dev = vc4_hdmi->connector.dev;
71 @@ -1620,31 +1640,55 @@ static void vc4_cec_read_msg(struct vc4_
75 +static irqreturn_t vc4_cec_irq_handler_tx_bare(int irq, void *priv)
77 + struct vc4_hdmi *vc4_hdmi = priv;
80 + cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
81 + vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
82 + cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
83 + HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
85 + return IRQ_WAKE_THREAD;
88 +static irqreturn_t vc4_cec_irq_handler_rx_bare(int irq, void *priv)
90 + struct vc4_hdmi *vc4_hdmi = priv;
93 + vc4_hdmi->cec_rx_msg.len = 0;
94 + cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
95 + vc4_cec_read_msg(vc4_hdmi, cntrl1);
96 + cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
97 + HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
98 + cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
100 + HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
102 + return IRQ_WAKE_THREAD;
105 static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
107 struct vc4_hdmi *vc4_hdmi = priv;
108 u32 stat = HDMI_READ(HDMI_CEC_CPU_STATUS);
109 - u32 cntrl1, cntrl5;
113 if (!(stat & VC4_HDMI_CPU_CEC))
115 - vc4_hdmi->cec_rx_msg.len = 0;
116 - cntrl1 = HDMI_READ(HDMI_CEC_CNTRL_1);
118 cntrl5 = HDMI_READ(HDMI_CEC_CNTRL_5);
119 vc4_hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
120 - if (vc4_hdmi->cec_irq_was_rx) {
121 - vc4_cec_read_msg(vc4_hdmi, cntrl1);
122 - cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
123 - HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
124 - cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
126 - vc4_hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
127 - cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
129 - HDMI_WRITE(HDMI_CEC_CNTRL_1, cntrl1);
130 - HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
131 + if (vc4_hdmi->cec_irq_was_rx)
132 + ret = vc4_cec_irq_handler_rx_bare(irq, priv);
134 + ret = vc4_cec_irq_handler_tx_bare(irq, priv);
136 - return IRQ_WAKE_THREAD;
137 + HDMI_WRITE(HDMI_CEC_CPU_CLEAR, VC4_HDMI_CPU_CEC);
141 static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)