Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 15b4511a authored by Hans Verkuil's avatar Hans Verkuil Committed by Eric Anholt
Browse files

drm/vc4: add HDMI CEC support



This patch adds support to VC4 for CEC.  It is under a separate
Kconfig option to keep everyone using VC4 from needing to pull in the
CEC core.

Thanks to Eric Anholt for providing me with the CEC register information.

Signed-off-by: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarEric Anholt <eric@anholt.net>
Reviewed-by: default avatarEric Anholt <eric@anholt.net>
Link: https://patchwork.freedesktop.org/patch/msgid/20170716104804.48308-4-hverkuil@xs4all.nl
parent 10ee275c
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -19,3 +19,11 @@ config DRM_VC4
	  This driver requires that "avoid_warnings=2" be present in
	  the config.txt for the firmware, to keep it from smashing
	  our display setup.

config DRM_VC4_HDMI_CEC
       bool "Broadcom VC4 HDMI CEC Support"
       depends on DRM_VC4
       select CEC_CORE
       help
	  Choose this option if you have a Broadcom VC4 GPU
	  and want to use CEC.
+224 −6
Original line number Diff line number Diff line
@@ -57,9 +57,14 @@
#include <sound/pcm_drm_eld.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include "media/cec.h"
#include "vc4_drv.h"
#include "vc4_regs.h"

#define HSM_CLOCK_FREQ 163682864
#define CEC_CLOCK_FREQ 40000
#define CEC_CLOCK_DIV  (HSM_CLOCK_FREQ / CEC_CLOCK_FREQ)

/* HDMI audio information */
struct vc4_hdmi_audio {
	struct snd_soc_card card;
@@ -85,6 +90,11 @@ struct vc4_hdmi {
	int hpd_gpio;
	bool hpd_active_low;

	struct cec_adapter *cec_adap;
	struct cec_msg cec_rx_msg;
	bool cec_tx_ok;
	bool cec_irq_was_rx;

	struct clk *pixel_clock;
	struct clk *hsm_clock;
};
@@ -149,6 +159,23 @@ static const struct {
	HDMI_REG(VC4_HDMI_VERTB1),
	HDMI_REG(VC4_HDMI_TX_PHY_RESET_CTL),
	HDMI_REG(VC4_HDMI_TX_PHY_CTL0),

	HDMI_REG(VC4_HDMI_CEC_CNTRL_1),
	HDMI_REG(VC4_HDMI_CEC_CNTRL_2),
	HDMI_REG(VC4_HDMI_CEC_CNTRL_3),
	HDMI_REG(VC4_HDMI_CEC_CNTRL_4),
	HDMI_REG(VC4_HDMI_CEC_CNTRL_5),
	HDMI_REG(VC4_HDMI_CPU_STATUS),
	HDMI_REG(VC4_HDMI_CPU_MASK_STATUS),

	HDMI_REG(VC4_HDMI_CEC_RX_DATA_1),
	HDMI_REG(VC4_HDMI_CEC_RX_DATA_2),
	HDMI_REG(VC4_HDMI_CEC_RX_DATA_3),
	HDMI_REG(VC4_HDMI_CEC_RX_DATA_4),
	HDMI_REG(VC4_HDMI_CEC_TX_DATA_1),
	HDMI_REG(VC4_HDMI_CEC_TX_DATA_2),
	HDMI_REG(VC4_HDMI_CEC_TX_DATA_3),
	HDMI_REG(VC4_HDMI_CEC_TX_DATA_4),
};

static const struct {
@@ -216,7 +243,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)
		if (gpio_get_value_cansleep(vc4->hdmi->hpd_gpio) ^
		    vc4->hdmi->hpd_active_low)
			return connector_status_connected;
		else
		cec_phys_addr_invalidate(vc4->hdmi->cec_adap);
		return connector_status_disconnected;
	}

@@ -225,7 +252,7 @@ vc4_hdmi_connector_detect(struct drm_connector *connector, bool force)

	if (HDMI_READ(VC4_HDMI_HOTPLUG) & VC4_HDMI_HOTPLUG_CONNECTED)
		return connector_status_connected;
	else
	cec_phys_addr_invalidate(vc4->hdmi->cec_adap);
	return connector_status_disconnected;
}

@@ -247,6 +274,7 @@ static int vc4_hdmi_connector_get_modes(struct drm_connector *connector)
	struct edid *edid;

	edid = drm_get_edid(connector, vc4->hdmi->ddc);
	cec_s_phys_addr_from_edid(vc4->hdmi->cec_adap, edid);
	if (!edid)
		return -ENODEV;

@@ -1121,6 +1149,159 @@ static void vc4_hdmi_audio_cleanup(struct vc4_hdmi *hdmi)
		snd_soc_unregister_codec(dev);
}

#ifdef CONFIG_DRM_VC4_HDMI_CEC
static irqreturn_t vc4_cec_irq_handler_thread(int irq, void *priv)
{
	struct vc4_dev *vc4 = priv;
	struct vc4_hdmi *hdmi = vc4->hdmi;

	if (hdmi->cec_irq_was_rx) {
		if (hdmi->cec_rx_msg.len)
			cec_received_msg(hdmi->cec_adap, &hdmi->cec_rx_msg);
	} else if (hdmi->cec_tx_ok) {
		cec_transmit_done(hdmi->cec_adap, CEC_TX_STATUS_OK,
				  0, 0, 0, 0);
	} else {
		/*
		 * This CEC implementation makes 1 retry, so if we
		 * get a NACK, then that means it made 2 attempts.
		 */
		cec_transmit_done(hdmi->cec_adap, CEC_TX_STATUS_NACK,
				  0, 2, 0, 0);
	}
	return IRQ_HANDLED;
}

static void vc4_cec_read_msg(struct vc4_dev *vc4, u32 cntrl1)
{
	struct cec_msg *msg = &vc4->hdmi->cec_rx_msg;
	unsigned int i;

	msg->len = 1 + ((cntrl1 & VC4_HDMI_CEC_REC_WRD_CNT_MASK) >>
					VC4_HDMI_CEC_REC_WRD_CNT_SHIFT);
	for (i = 0; i < msg->len; i += 4) {
		u32 val = HDMI_READ(VC4_HDMI_CEC_RX_DATA_1 + i);

		msg->msg[i] = val & 0xff;
		msg->msg[i + 1] = (val >> 8) & 0xff;
		msg->msg[i + 2] = (val >> 16) & 0xff;
		msg->msg[i + 3] = (val >> 24) & 0xff;
	}
}

static irqreturn_t vc4_cec_irq_handler(int irq, void *priv)
{
	struct vc4_dev *vc4 = priv;
	struct vc4_hdmi *hdmi = vc4->hdmi;
	u32 stat = HDMI_READ(VC4_HDMI_CPU_STATUS);
	u32 cntrl1, cntrl5;

	if (!(stat & VC4_HDMI_CPU_CEC))
		return IRQ_NONE;
	hdmi->cec_rx_msg.len = 0;
	cntrl1 = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
	cntrl5 = HDMI_READ(VC4_HDMI_CEC_CNTRL_5);
	hdmi->cec_irq_was_rx = cntrl5 & VC4_HDMI_CEC_RX_CEC_INT;
	if (hdmi->cec_irq_was_rx) {
		vc4_cec_read_msg(vc4, cntrl1);
		cntrl1 |= VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1);
		cntrl1 &= ~VC4_HDMI_CEC_CLEAR_RECEIVE_OFF;
	} else {
		hdmi->cec_tx_ok = cntrl1 & VC4_HDMI_CEC_TX_STATUS_GOOD;
		cntrl1 &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
	}
	HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, cntrl1);
	HDMI_WRITE(VC4_HDMI_CPU_CLEAR, VC4_HDMI_CPU_CEC);

	return IRQ_WAKE_THREAD;
}

static int vc4_hdmi_cec_adap_enable(struct cec_adapter *adap, bool enable)
{
	struct vc4_dev *vc4 = cec_get_drvdata(adap);
	/* clock period in microseconds */
	const u32 usecs = 1000000 / CEC_CLOCK_FREQ;
	u32 val = HDMI_READ(VC4_HDMI_CEC_CNTRL_5);

	val &= ~(VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET |
		 VC4_HDMI_CEC_CNT_TO_4700_US_MASK |
		 VC4_HDMI_CEC_CNT_TO_4500_US_MASK);
	val |= ((4700 / usecs) << VC4_HDMI_CEC_CNT_TO_4700_US_SHIFT) |
	       ((4500 / usecs) << VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT);

	if (enable) {
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val |
			   VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val);
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_2,
			 ((1500 / usecs) << VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT) |
			 ((1300 / usecs) << VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT) |
			 ((800 / usecs) << VC4_HDMI_CEC_CNT_TO_800_US_SHIFT) |
			 ((600 / usecs) << VC4_HDMI_CEC_CNT_TO_600_US_SHIFT) |
			 ((400 / usecs) << VC4_HDMI_CEC_CNT_TO_400_US_SHIFT));
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_3,
			 ((2750 / usecs) << VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT) |
			 ((2400 / usecs) << VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT) |
			 ((2050 / usecs) << VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT) |
			 ((1700 / usecs) << VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT));
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_4,
			 ((4300 / usecs) << VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT) |
			 ((3900 / usecs) << VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT) |
			 ((3600 / usecs) << VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT) |
			 ((3500 / usecs) << VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT));

		HDMI_WRITE(VC4_HDMI_CPU_MASK_CLEAR, VC4_HDMI_CPU_CEC);
	} else {
		HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, VC4_HDMI_CPU_CEC);
		HDMI_WRITE(VC4_HDMI_CEC_CNTRL_5, val |
			   VC4_HDMI_CEC_TX_SW_RESET | VC4_HDMI_CEC_RX_SW_RESET);
	}
	return 0;
}

static int vc4_hdmi_cec_adap_log_addr(struct cec_adapter *adap, u8 log_addr)
{
	struct vc4_dev *vc4 = cec_get_drvdata(adap);

	HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1,
		   (HDMI_READ(VC4_HDMI_CEC_CNTRL_1) & ~VC4_HDMI_CEC_ADDR_MASK) |
		   (log_addr & 0xf) << VC4_HDMI_CEC_ADDR_SHIFT);
	return 0;
}

static int vc4_hdmi_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
				      u32 signal_free_time, struct cec_msg *msg)
{
	struct vc4_dev *vc4 = cec_get_drvdata(adap);
	u32 val;
	unsigned int i;

	for (i = 0; i < msg->len; i += 4)
		HDMI_WRITE(VC4_HDMI_CEC_TX_DATA_1 + i,
			   (msg->msg[i]) |
			   (msg->msg[i + 1] << 8) |
			   (msg->msg[i + 2] << 16) |
			   (msg->msg[i + 3] << 24));

	val = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
	val &= ~VC4_HDMI_CEC_START_XMIT_BEGIN;
	HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val);
	val &= ~VC4_HDMI_CEC_MESSAGE_LENGTH_MASK;
	val |= (msg->len - 1) << VC4_HDMI_CEC_MESSAGE_LENGTH_SHIFT;
	val |= VC4_HDMI_CEC_START_XMIT_BEGIN;

	HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, val);
	return 0;
}

static const struct cec_adap_ops vc4_hdmi_cec_adap_ops = {
	.adap_enable = vc4_hdmi_cec_adap_enable,
	.adap_log_addr = vc4_hdmi_cec_adap_log_addr,
	.adap_transmit = vc4_hdmi_cec_adap_transmit,
};
#endif

static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
{
	struct platform_device *pdev = to_platform_device(dev);
@@ -1180,7 +1361,7 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
	 * needs to be a bit higher than the pixel clock rate
	 * (generally 148.5Mhz).
	 */
	ret = clk_set_rate(hdmi->hsm_clock, 163682864);
	ret = clk_set_rate(hdmi->hsm_clock, HSM_CLOCK_FREQ);
	if (ret) {
		DRM_ERROR("Failed to set HSM clock rate: %d\n", ret);
		goto err_put_i2c;
@@ -1231,6 +1412,37 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)
		ret = PTR_ERR(hdmi->connector);
		goto err_destroy_encoder;
	}
#ifdef CONFIG_DRM_VC4_HDMI_CEC
	hdmi->cec_adap = cec_allocate_adapter(&vc4_hdmi_cec_adap_ops,
					      vc4, "vc4",
					      CEC_CAP_TRANSMIT |
					      CEC_CAP_LOG_ADDRS |
					      CEC_CAP_PASSTHROUGH |
					      CEC_CAP_RC, 1);
	ret = PTR_ERR_OR_ZERO(hdmi->cec_adap);
	if (ret < 0)
		goto err_destroy_conn;
	HDMI_WRITE(VC4_HDMI_CPU_MASK_SET, 0xffffffff);
	value = HDMI_READ(VC4_HDMI_CEC_CNTRL_1);
	value &= ~VC4_HDMI_CEC_DIV_CLK_CNT_MASK;
	/*
	 * Set the logical address to Unregistered and set the clock
	 * divider: the hsm_clock rate and this divider setting will
	 * give a 40 kHz CEC clock.
	 */
	value |= VC4_HDMI_CEC_ADDR_MASK |
		 (4091 << VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT);
	HDMI_WRITE(VC4_HDMI_CEC_CNTRL_1, value);
	ret = devm_request_threaded_irq(dev, platform_get_irq(pdev, 0),
					vc4_cec_irq_handler,
					vc4_cec_irq_handler_thread, 0,
					"vc4 hdmi cec", vc4);
	if (ret)
		goto err_delete_cec_adap;
	ret = cec_register_adapter(hdmi->cec_adap, dev);
	if (ret < 0)
		goto err_delete_cec_adap;
#endif

	ret = vc4_hdmi_audio_init(hdmi);
	if (ret)
@@ -1238,6 +1450,12 @@ static int vc4_hdmi_bind(struct device *dev, struct device *master, void *data)

	return 0;

#ifdef CONFIG_DRM_VC4_HDMI_CEC
err_delete_cec_adap:
	cec_delete_adapter(hdmi->cec_adap);
err_destroy_conn:
	vc4_hdmi_connector_destroy(hdmi->connector);
#endif
err_destroy_encoder:
	vc4_hdmi_encoder_destroy(hdmi->encoder);
err_unprepare_hsm:
@@ -1257,7 +1475,7 @@ static void vc4_hdmi_unbind(struct device *dev, struct device *master,
	struct vc4_hdmi *hdmi = vc4->hdmi;

	vc4_hdmi_audio_cleanup(hdmi);

	cec_unregister_adapter(hdmi->cec_adap);
	vc4_hdmi_connector_destroy(hdmi->connector);
	vc4_hdmi_encoder_destroy(hdmi->encoder);

+113 −0
Original line number Diff line number Diff line
@@ -561,16 +561,129 @@
# define VC4_HDMI_VERTB_VBP_MASK		VC4_MASK(8, 0)
# define VC4_HDMI_VERTB_VBP_SHIFT		0

#define VC4_HDMI_CEC_CNTRL_1			0x0e8
/* Set when the transmission has ended. */
# define VC4_HDMI_CEC_TX_EOM			BIT(31)
/* If set, transmission was acked on the 1st or 2nd attempt (only one
 * retry is attempted).  If in continuous mode, this means TX needs to
 * be filled if !TX_EOM.
 */
# define VC4_HDMI_CEC_TX_STATUS_GOOD		BIT(30)
# define VC4_HDMI_CEC_RX_EOM			BIT(29)
# define VC4_HDMI_CEC_RX_STATUS_GOOD		BIT(28)
/* Number of bytes received for the message. */
# define VC4_HDMI_CEC_REC_WRD_CNT_MASK		VC4_MASK(27, 24)
# define VC4_HDMI_CEC_REC_WRD_CNT_SHIFT		24
/* Sets continuous receive mode.  Generates interrupt after each 8
 * bytes to signal that RX_DATA should be consumed, and at RX_EOM.
 *
 * If disabled, maximum 16 bytes will be received (including header),
 * and interrupt at RX_EOM.  Later bytes will be acked but not put
 * into the RX_DATA.
 */
# define VC4_HDMI_CEC_RX_CONTINUE		BIT(23)
# define VC4_HDMI_CEC_TX_CONTINUE		BIT(22)
/* Set this after a CEC interrupt. */
# define VC4_HDMI_CEC_CLEAR_RECEIVE_OFF		BIT(21)
/* Starts a TX.  Will wait for appropriate idel time before CEC
 * activity. Must be cleared in between transmits.
 */
# define VC4_HDMI_CEC_START_XMIT_BEGIN		BIT(20)
# define VC4_HDMI_CEC_MESSAGE_LENGTH_MASK	VC4_MASK(19, 16)
# define VC4_HDMI_CEC_MESSAGE_LENGTH_SHIFT	16
/* Device's CEC address */
# define VC4_HDMI_CEC_ADDR_MASK			VC4_MASK(15, 12)
# define VC4_HDMI_CEC_ADDR_SHIFT		12
/* Divides off of HSM clock to generate CEC bit clock. */
/* With the current defaults the CEC bit clock is 40 kHz = 25 usec */
# define VC4_HDMI_CEC_DIV_CLK_CNT_MASK		VC4_MASK(11, 0)
# define VC4_HDMI_CEC_DIV_CLK_CNT_SHIFT		0

/* Set these fields to how many bit clock cycles get to that many
 * microseconds.
 */
#define VC4_HDMI_CEC_CNTRL_2			0x0ec
# define VC4_HDMI_CEC_CNT_TO_1500_US_MASK	VC4_MASK(30, 24)
# define VC4_HDMI_CEC_CNT_TO_1500_US_SHIFT	24
# define VC4_HDMI_CEC_CNT_TO_1300_US_MASK	VC4_MASK(23, 17)
# define VC4_HDMI_CEC_CNT_TO_1300_US_SHIFT	17
# define VC4_HDMI_CEC_CNT_TO_800_US_MASK	VC4_MASK(16, 11)
# define VC4_HDMI_CEC_CNT_TO_800_US_SHIFT	11
# define VC4_HDMI_CEC_CNT_TO_600_US_MASK	VC4_MASK(10, 5)
# define VC4_HDMI_CEC_CNT_TO_600_US_SHIFT	5
# define VC4_HDMI_CEC_CNT_TO_400_US_MASK	VC4_MASK(4, 0)
# define VC4_HDMI_CEC_CNT_TO_400_US_SHIFT	0

#define VC4_HDMI_CEC_CNTRL_3			0x0f0
# define VC4_HDMI_CEC_CNT_TO_2750_US_MASK	VC4_MASK(31, 24)
# define VC4_HDMI_CEC_CNT_TO_2750_US_SHIFT	24
# define VC4_HDMI_CEC_CNT_TO_2400_US_MASK	VC4_MASK(23, 16)
# define VC4_HDMI_CEC_CNT_TO_2400_US_SHIFT	16
# define VC4_HDMI_CEC_CNT_TO_2050_US_MASK	VC4_MASK(15, 8)
# define VC4_HDMI_CEC_CNT_TO_2050_US_SHIFT	8
# define VC4_HDMI_CEC_CNT_TO_1700_US_MASK	VC4_MASK(7, 0)
# define VC4_HDMI_CEC_CNT_TO_1700_US_SHIFT	0

#define VC4_HDMI_CEC_CNTRL_4			0x0f4
# define VC4_HDMI_CEC_CNT_TO_4300_US_MASK	VC4_MASK(31, 24)
# define VC4_HDMI_CEC_CNT_TO_4300_US_SHIFT	24
# define VC4_HDMI_CEC_CNT_TO_3900_US_MASK	VC4_MASK(23, 16)
# define VC4_HDMI_CEC_CNT_TO_3900_US_SHIFT	16
# define VC4_HDMI_CEC_CNT_TO_3600_US_MASK	VC4_MASK(15, 8)
# define VC4_HDMI_CEC_CNT_TO_3600_US_SHIFT	8
# define VC4_HDMI_CEC_CNT_TO_3500_US_MASK	VC4_MASK(7, 0)
# define VC4_HDMI_CEC_CNT_TO_3500_US_SHIFT	0

#define VC4_HDMI_CEC_CNTRL_5			0x0f8
# define VC4_HDMI_CEC_TX_SW_RESET		BIT(27)
# define VC4_HDMI_CEC_RX_SW_RESET		BIT(26)
# define VC4_HDMI_CEC_PAD_SW_RESET		BIT(25)
# define VC4_HDMI_CEC_MUX_TP_OUT_CEC		BIT(24)
# define VC4_HDMI_CEC_RX_CEC_INT		BIT(23)
# define VC4_HDMI_CEC_CLK_PRELOAD_MASK		VC4_MASK(22, 16)
# define VC4_HDMI_CEC_CLK_PRELOAD_SHIFT		16
# define VC4_HDMI_CEC_CNT_TO_4700_US_MASK	VC4_MASK(15, 8)
# define VC4_HDMI_CEC_CNT_TO_4700_US_SHIFT	8
# define VC4_HDMI_CEC_CNT_TO_4500_US_MASK	VC4_MASK(7, 0)
# define VC4_HDMI_CEC_CNT_TO_4500_US_SHIFT	0

/* Transmit data, first byte is low byte of the 32-bit reg.  MSB of
 * each byte transmitted first.
 */
#define VC4_HDMI_CEC_TX_DATA_1			0x0fc
#define VC4_HDMI_CEC_TX_DATA_2			0x100
#define VC4_HDMI_CEC_TX_DATA_3			0x104
#define VC4_HDMI_CEC_TX_DATA_4			0x108
#define VC4_HDMI_CEC_RX_DATA_1			0x10c
#define VC4_HDMI_CEC_RX_DATA_2			0x110
#define VC4_HDMI_CEC_RX_DATA_3			0x114
#define VC4_HDMI_CEC_RX_DATA_4			0x118

#define VC4_HDMI_TX_PHY_RESET_CTL		0x2c0

#define VC4_HDMI_TX_PHY_CTL0			0x2c4
# define VC4_HDMI_TX_PHY_RNG_PWRDN		BIT(25)

/* Interrupt status bits */
#define VC4_HDMI_CPU_STATUS			0x340
#define VC4_HDMI_CPU_SET			0x344
#define VC4_HDMI_CPU_CLEAR			0x348
# define VC4_HDMI_CPU_CEC			BIT(6)
# define VC4_HDMI_CPU_HOTPLUG			BIT(0)

#define VC4_HDMI_CPU_MASK_STATUS		0x34c
#define VC4_HDMI_CPU_MASK_SET			0x350
#define VC4_HDMI_CPU_MASK_CLEAR			0x354

#define VC4_HDMI_GCP(x)				(0x400 + ((x) * 0x4))
#define VC4_HDMI_RAM_PACKET(x)			(0x400 + ((x) * 0x24))
#define VC4_HDMI_PACKET_STRIDE			0x24

#define VC4_HD_M_CTL				0x00c
/* Debug: Current receive value on the CEC pad. */
# define VC4_HD_CECRXD				BIT(9)
/* Debug: Override CEC output to 0. */
# define VC4_HD_CECOVR				BIT(8)
# define VC4_HD_M_REGISTER_FILE_STANDBY		(3 << 6)
# define VC4_HD_M_RAM_STANDBY			(3 << 4)
# define VC4_HD_M_SW_RST			BIT(2)