drivers/gpu/drm/meson/meson_dw_hdmi.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/meson/meson_dw_hdmi.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/meson/meson_dw_hdmi.c
Extension
.c
Size
25059 bytes
Lines
875
Domain
Driver Families
Bucket
drivers/gpu
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct meson_dw_hdmi_data {
	unsigned int	(*top_read)(struct meson_dw_hdmi *dw_hdmi,
				    unsigned int addr);
	void		(*top_write)(struct meson_dw_hdmi *dw_hdmi,
				     unsigned int addr, unsigned int data);
	unsigned int	(*dwc_read)(struct meson_dw_hdmi *dw_hdmi,
				    unsigned int addr);
	void		(*dwc_write)(struct meson_dw_hdmi *dw_hdmi,
				     unsigned int addr, unsigned int data);
	u32 cntl0_init;
	u32 cntl1_init;
};

struct meson_dw_hdmi {
	struct dw_hdmi_plat_data dw_plat_data;
	struct meson_drm *priv;
	struct device *dev;
	void __iomem *hdmitx;
	const struct meson_dw_hdmi_data *data;
	struct reset_control *hdmitx_apb;
	struct reset_control *hdmitx_ctrl;
	struct reset_control *hdmitx_phy;
	u32 irq_stat;
	struct dw_hdmi *hdmi;
	struct drm_bridge *bridge;
};

static inline int dw_hdmi_is_compatible(struct meson_dw_hdmi *dw_hdmi,
					const char *compat)
{
	return of_device_is_compatible(dw_hdmi->dev->of_node, compat);
}

/* PHY (via TOP bridge) and Controller dedicated register interface */

static unsigned int dw_hdmi_top_read(struct meson_dw_hdmi *dw_hdmi,
				     unsigned int addr)
{
	unsigned long flags;
	unsigned int data;

	spin_lock_irqsave(&reg_lock, flags);

	/* ADDR must be written twice */
	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);

	/* Read needs a second DATA read */
	data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);
	data = readl(dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);

	spin_unlock_irqrestore(&reg_lock, flags);

	return data;
}

static unsigned int dw_hdmi_g12a_top_read(struct meson_dw_hdmi *dw_hdmi,
					  unsigned int addr)
{
	return readl(dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
}

static inline void dw_hdmi_top_write(struct meson_dw_hdmi *dw_hdmi,
				     unsigned int addr, unsigned int data)
{
	unsigned long flags;

	spin_lock_irqsave(&reg_lock, flags);

	/* ADDR must be written twice */
	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);
	writel(addr & 0xffff, dw_hdmi->hdmitx + HDMITX_TOP_ADDR_REG);

	/* Write needs single DATA write */
	writel(data, dw_hdmi->hdmitx + HDMITX_TOP_DATA_REG);

	spin_unlock_irqrestore(&reg_lock, flags);
}

static inline void dw_hdmi_g12a_top_write(struct meson_dw_hdmi *dw_hdmi,
					  unsigned int addr, unsigned int data)
{
	writel(data, dw_hdmi->hdmitx + HDMITX_TOP_G12A_OFFSET + (addr << 2));
}

/* Helper to change specific bits in PHY registers */
static inline void dw_hdmi_top_write_bits(struct meson_dw_hdmi *dw_hdmi,
					  unsigned int addr,
					  unsigned int mask,
					  unsigned int val)

Annotation

Implementation Notes