drivers/gpu/drm/bridge/imx/imx8qm-ldb.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/bridge/imx/imx8qm-ldb.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/bridge/imx/imx8qm-ldb.c
Extension
.c
Size
16330 bytes
Lines
590
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 imx8qm_ldb_channel {
	struct ldb_channel base;
	struct phy *phy;
};

struct imx8qm_ldb {
	struct ldb base;
	struct device *dev;
	struct imx8qm_ldb_channel *channel[MAX_LDB_CHAN_NUM];
	struct clk *clk_pixel;
	struct clk *clk_bypass;
	int active_chno;
};

static inline struct imx8qm_ldb_channel *
base_to_imx8qm_ldb_channel(struct ldb_channel *base)
{
	return container_of(base, struct imx8qm_ldb_channel, base);
}

static inline struct imx8qm_ldb *base_to_imx8qm_ldb(struct ldb *base)
{
	return container_of(base, struct imx8qm_ldb, base);
}

static void imx8qm_ldb_set_phy_cfg(struct imx8qm_ldb *imx8qm_ldb,
				   unsigned long di_clk,
				   bool is_split, bool is_slave,
				   struct phy_configure_opts_lvds *phy_cfg)
{
	phy_cfg->bits_per_lane_and_dclk_cycle = 7;
	phy_cfg->lanes = 4;
	phy_cfg->differential_clk_rate = is_split ? di_clk / 2 : di_clk;
	phy_cfg->is_slave = is_slave;
}

static int imx8qm_ldb_bridge_atomic_check(struct drm_bridge *bridge,
					  struct drm_bridge_state *bridge_state,
					  struct drm_crtc_state *crtc_state,
					  struct drm_connector_state *conn_state)
{
	struct ldb_channel *ldb_ch = bridge->driver_private;
	struct ldb *ldb = ldb_ch->ldb;
	struct imx8qm_ldb_channel *imx8qm_ldb_ch =
					base_to_imx8qm_ldb_channel(ldb_ch);
	struct imx8qm_ldb *imx8qm_ldb = base_to_imx8qm_ldb(ldb);
	struct drm_display_mode *adj = &crtc_state->adjusted_mode;
	unsigned long di_clk = adj->clock * 1000;
	bool is_split = ldb_channel_is_split_link(ldb_ch);
	union phy_configure_opts opts = { };
	struct phy_configure_opts_lvds *phy_cfg = &opts.lvds;
	int ret;

	ret = ldb_bridge_atomic_check_helper(bridge, bridge_state,
					     crtc_state, conn_state);
	if (ret)
		return ret;

	imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, false, phy_cfg);
	ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts);
	if (ret < 0) {
		DRM_DEV_DEBUG_DRIVER(imx8qm_ldb->dev,
				     "failed to validate PHY: %d\n", ret);
		return ret;
	}

	if (is_split) {
		imx8qm_ldb_ch =
			imx8qm_ldb->channel[imx8qm_ldb->active_chno ^ 1];
		imx8qm_ldb_set_phy_cfg(imx8qm_ldb, di_clk, is_split, true,
				       phy_cfg);
		ret = phy_validate(imx8qm_ldb_ch->phy, PHY_MODE_LVDS, 0, &opts);
		if (ret < 0) {
			DRM_DEV_DEBUG_DRIVER(imx8qm_ldb->dev,
					     "failed to validate slave PHY: %d\n",
					     ret);
			return ret;
		}
	}

	return ret;
}

static void
imx8qm_ldb_bridge_mode_set(struct drm_bridge *bridge,
			   const struct drm_display_mode *mode,
			   const struct drm_display_mode *adjusted_mode)
{
	struct ldb_channel *ldb_ch = bridge->driver_private;
	struct ldb *ldb = ldb_ch->ldb;

Annotation

Implementation Notes