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

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

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/bridge/imx/imx8qxp-ldb.c
Extension
.c
Size
20490 bytes
Lines
733
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 imx8qxp_ldb_channel {
	struct ldb_channel base;
	struct phy *phy;
	unsigned int di_id;
};

struct imx8qxp_ldb {
	struct ldb base;
	struct device *dev;
	struct imx8qxp_ldb_channel *channel[MAX_LDB_CHAN_NUM];
	struct clk *clk_pixel;
	struct clk *clk_bypass;
	struct drm_bridge *companion;
	int active_chno;
};

static inline struct imx8qxp_ldb_channel *
base_to_imx8qxp_ldb_channel(struct ldb_channel *base)
{
	return container_of(base, struct imx8qxp_ldb_channel, base);
}

static inline struct imx8qxp_ldb *base_to_imx8qxp_ldb(struct ldb *base)
{
	return container_of(base, struct imx8qxp_ldb, base);
}

static void imx8qxp_ldb_bridge_destroy(struct drm_bridge *bridge)
{
	struct ldb_channel *ldb_ch = bridge->driver_private;
	struct imx8qxp_ldb *imx8qxp_ldb;

	if (!ldb_ch)
		return;

	imx8qxp_ldb = base_to_imx8qxp_ldb(ldb_ch->ldb);
	drm_bridge_put(imx8qxp_ldb->companion);
}

static void imx8qxp_ldb_set_phy_cfg(struct imx8qxp_ldb *imx8qxp_ldb,
				    unsigned long di_clk, bool is_split,
				    struct phy_configure_opts_lvds *phy_cfg)
{
	phy_cfg->bits_per_lane_and_dclk_cycle = 7;
	phy_cfg->lanes = 4;

	if (is_split) {
		phy_cfg->differential_clk_rate = di_clk / 2;
		phy_cfg->is_slave = !imx8qxp_ldb->companion;
	} else {
		phy_cfg->differential_clk_rate = di_clk;
		phy_cfg->is_slave = false;
	}
}

static int
imx8qxp_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 imx8qxp_ldb_channel *imx8qxp_ldb_ch =
					base_to_imx8qxp_ldb_channel(ldb_ch);
	struct imx8qxp_ldb *imx8qxp_ldb = base_to_imx8qxp_ldb(ldb);
	struct drm_bridge *companion = imx8qxp_ldb->companion;
	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;

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

	if (is_split && companion) {
		ret = companion->funcs->atomic_check(companion,
					bridge_state, crtc_state, conn_state);

Annotation

Implementation Notes