drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c

Source file repositories/reference/linux-study-clean/drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c

File Facts

System
Linux kernel
Corpus path
drivers/gpu/drm/msm/disp/mdp4/mdp4_lvds_pll.c
Extension
.c
Size
4446 bytes
Lines
184
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 mdp4_lvds_pll {
	struct clk_hw pll_hw;
	struct drm_device *dev;
	unsigned long pixclk;
};
#define to_mdp4_lvds_pll(x) container_of(x, struct mdp4_lvds_pll, pll_hw)

static struct mdp4_kms *get_kms(struct mdp4_lvds_pll *lvds_pll)
{
	struct msm_drm_private *priv = lvds_pll->dev->dev_private;
	return to_mdp4_kms(to_mdp_kms(priv->kms));
}

struct pll_rate {
	unsigned long rate;
	struct {
		uint32_t val;
		uint32_t reg;
	} conf[32];
};

/* NOTE: keep sorted highest freq to lowest: */
static const struct pll_rate freqtbl[] = {
	{ 72000000, {
		{ 0x8f, REG_MDP4_LVDS_PHY_PLL_CTRL_1 },
		{ 0x30, REG_MDP4_LVDS_PHY_PLL_CTRL_2 },
		{ 0xc6, REG_MDP4_LVDS_PHY_PLL_CTRL_3 },
		{ 0x10, REG_MDP4_LVDS_PHY_PLL_CTRL_5 },
		{ 0x07, REG_MDP4_LVDS_PHY_PLL_CTRL_6 },
		{ 0x62, REG_MDP4_LVDS_PHY_PLL_CTRL_7 },
		{ 0x41, REG_MDP4_LVDS_PHY_PLL_CTRL_8 },
		{ 0x0d, REG_MDP4_LVDS_PHY_PLL_CTRL_9 },
		{ 0, 0 } }
	},
};

static const struct pll_rate *find_rate(unsigned long rate)
{
	int i;
	for (i = 1; i < ARRAY_SIZE(freqtbl); i++)
		if (rate > freqtbl[i].rate)
			return &freqtbl[i-1];
	return &freqtbl[i-1];
}

static int mdp4_lvds_pll_enable(struct clk_hw *hw)
{
	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);
	const struct pll_rate *pll_rate = find_rate(lvds_pll->pixclk);
	int i;

	DBG("pixclk=%lu (%lu)", lvds_pll->pixclk, pll_rate->rate);

	if (WARN_ON(!pll_rate))
		return -EINVAL;

	mdp4_write(mdp4_kms, REG_MDP4_LCDC_LVDS_PHY_RESET, 0x33);

	for (i = 0; pll_rate->conf[i].reg; i++)
		mdp4_write(mdp4_kms, pll_rate->conf[i].reg, pll_rate->conf[i].val);

	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x01);

	/* Wait until LVDS PLL is locked and ready */
	while (!mdp4_read(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_LOCKED))
		cpu_relax();

	return 0;
}

static void mdp4_lvds_pll_disable(struct clk_hw *hw)
{
	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
	struct mdp4_kms *mdp4_kms = get_kms(lvds_pll);

	DBG("");

	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, 0x0);
	mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_PLL_CTRL_0, 0x0);
}

static unsigned long mdp4_lvds_pll_recalc_rate(struct clk_hw *hw,
				unsigned long parent_rate)
{
	struct mdp4_lvds_pll *lvds_pll = to_mdp4_lvds_pll(hw);
	return lvds_pll->pixclk;
}

static int mdp4_lvds_pll_determine_rate(struct clk_hw *hw,

Annotation

Implementation Notes