drivers/gpu/drm/bridge/microchip-lvds.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/bridge/microchip-lvds.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/bridge/microchip-lvds.c
Extension
.c
Size
6317 bytes
Lines
241
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 mchp_lvds {
	struct device *dev;
	void __iomem *regs;
	struct clk *pclk;
	struct drm_bridge bridge;
	struct drm_bridge *panel_bridge;
};

static inline struct mchp_lvds *bridge_to_lvds(struct drm_bridge *bridge)
{
	return container_of(bridge, struct mchp_lvds, bridge);
}

static inline u32 lvds_readl(struct mchp_lvds *lvds, u32 offset)
{
	return readl_relaxed(lvds->regs + offset);
}

static inline void lvds_writel(struct mchp_lvds *lvds, u32 offset, u32 val)
{
	writel_relaxed(val, lvds->regs + offset);
}

static void lvds_serialiser_on(struct mchp_lvds *lvds, u32 bus_format)
{
	unsigned long timeout = jiffies + msecs_to_jiffies(LVDS_POLL_TIMEOUT_MS);
	u8 map, pix_size;

	/* The LVDSC registers can only be written if WPEN is cleared */
	lvds_writel(lvds, LVDSC_WPMR, (LVDSC_WPMR_WPKEY_PSSWD &
				LVDSC_WPMR_WPKEY_MASK));

	/* Wait for the status of configuration registers to be changed */
	while (lvds_readl(lvds, LVDSC_SR) & LVDSC_SR_CS) {
		if (time_after(jiffies, timeout)) {
			dev_err(lvds->dev, "%s: timeout error\n", __func__);
			return;
		}
		usleep_range(1000, 2000);
	}

	switch (bus_format) {
	case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG:
		map = LVDSC_CFGR_MAPPING_JEIDA;
		pix_size = LVDSC_CFGR_PIXSIZE_18BITS;
		break;
	case MEDIA_BUS_FMT_RGB888_1X7X4_SPWG:
		map = LVDSC_CFGR_MAPPING_VESA;
		pix_size = LVDSC_CFGR_PIXSIZE_24BITS;
		break;
	default:
		map = LVDSC_CFGR_MAPPING_JEIDA;
		pix_size = LVDSC_CFGR_PIXSIZE_24BITS;
		break;
	}

	/* Configure the LVDSC */
	lvds_writel(lvds, LVDSC_CFGR, map | LVDSC_CFGR_DC_UNBALANCED |
		    LVDSC_CFGR_DEN_POL_HIGH | pix_size);

	/* Enable the LVDS serializer */
	lvds_writel(lvds, LVDSC_CR, LVDSC_CR_SER_EN);
}

static int mchp_lvds_attach(struct drm_bridge *bridge,
			    struct drm_encoder *encoder,
			    enum drm_bridge_attach_flags flags)
{
	struct mchp_lvds *lvds = bridge_to_lvds(bridge);

	return drm_bridge_attach(encoder, lvds->panel_bridge,
				 bridge, flags);
}

static void mchp_lvds_atomic_enable(struct drm_bridge *bridge,
				    struct drm_atomic_commit *state)
{
	struct mchp_lvds *lvds = bridge_to_lvds(bridge);
	struct drm_connector *connector;
	int ret;

	ret = clk_prepare_enable(lvds->pclk);
	if (ret < 0) {
		dev_err(lvds->dev, "failed to enable lvds pclk %d\n", ret);
		return;
	}

	ret = pm_runtime_get_sync(lvds->dev);
	if (ret < 0) {
		dev_err(lvds->dev, "failed to get pm runtime: %d\n", ret);

Annotation

Implementation Notes