Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5c829028 authored by Hai Li's avatar Hai Li Committed by Rob Clark
Browse files

drm/msm/dsi: Split PHY drivers to separate files



This change moves each PHY type specific code into
separate files.

Signed-off-by: default avatarHai Li <hali@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent 29e61690
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm
ccflags-$(CONFIG_DRM_MSM_DSI_PLL) += -Idrivers/gpu/drm/msm/dsi
ccflags-$(CONFIG_DRM_MSM_DSI) += -Idrivers/gpu/drm/msm/dsi

msm-y := \
	adreno/adreno_device.o \
@@ -56,7 +56,9 @@ msm-$(CONFIG_COMMON_CLK) += mdp/mdp4/mdp4_lvds_pll.o
msm-$(CONFIG_DRM_MSM_DSI) += dsi/dsi.o \
			dsi/dsi_host.o \
			dsi/dsi_manager.o \
			dsi/dsi_phy.o \
			dsi/phy/dsi_phy.o \
			dsi/phy/dsi_phy_20nm.o \
			dsi/phy/dsi_phy_28nm.o \
			mdp/mdp5/mdp5_cmd_encoder.o

msm-$(CONFIG_DRM_MSM_DSI_PLL) += dsi/pll/dsi_pll.o \
+448 −0
Original line number Diff line number Diff line
@@ -12,167 +12,8 @@
 */

#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>

#include "dsi.h"
#include "dsi.xml.h"

#define dsi_phy_read(offset) msm_readl((offset))
#define dsi_phy_write(offset, data) msm_writel((data), (offset))

struct dsi_phy_ops {
	int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
		const unsigned long bit_rate, const unsigned long esc_rate);
	void (*disable)(struct msm_dsi_phy *phy);
};

struct dsi_phy_cfg {
	enum msm_dsi_phy_type type;
	struct dsi_reg_config reg_cfg;
	struct dsi_phy_ops ops;

	/* Each cell {phy_id, pll_id} of the truth table indicates
	 * if the source PLL is on the right side of the PHY.
	 * Fill default H/W values in illegal cells, eg. cell {0, 1}.
	 */
	bool src_pll_truthtable[DSI_MAX][DSI_MAX];
};

struct dsi_dphy_timing {
	u32 clk_pre;
	u32 clk_post;
	u32 clk_zero;
	u32 clk_trail;
	u32 clk_prepare;
	u32 hs_exit;
	u32 hs_zero;
	u32 hs_prepare;
	u32 hs_trail;
	u32 hs_rqst;
	u32 ta_go;
	u32 ta_sure;
	u32 ta_get;
};

struct msm_dsi_phy {
	struct platform_device *pdev;
	void __iomem *base;
	void __iomem *reg_base;
	int id;

	struct clk *ahb_clk;
	struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];

	struct dsi_dphy_timing timing;
	const struct dsi_phy_cfg *cfg;

	bool regulator_ldo_mode;

	struct msm_dsi_pll *pll;
};

static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
{
	struct regulator_bulk_data *s = phy->supplies;
	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
	struct device *dev = &phy->pdev->dev;
	int num = phy->cfg->reg_cfg.num;
	int i, ret;

	for (i = 0; i < num; i++)
		s[i].supply = regs[i].name;

	ret = devm_regulator_bulk_get(&phy->pdev->dev, num, s);
	if (ret < 0) {
		dev_err(dev, "%s: failed to init regulator, ret=%d\n",
						__func__, ret);
		return ret;
	}

	for (i = 0; i < num; i++) {
		if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
			ret = regulator_set_voltage(s[i].consumer,
				regs[i].min_voltage, regs[i].max_voltage);
			if (ret < 0) {
				dev_err(dev,
					"regulator %d set voltage failed, %d\n",
					i, ret);
				return ret;
			}
		}
	}

	return 0;
}

static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
{
	struct regulator_bulk_data *s = phy->supplies;
	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
	int num = phy->cfg->reg_cfg.num;
	int i;

	DBG("");
	for (i = num - 1; i >= 0; i--)
		if (regs[i].disable_load >= 0)
			regulator_set_load(s[i].consumer,
						regs[i].disable_load);

	regulator_bulk_disable(num, s);
}

static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
{
	struct regulator_bulk_data *s = phy->supplies;
	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
	struct device *dev = &phy->pdev->dev;
	int num = phy->cfg->reg_cfg.num;
	int ret, i;

	DBG("");
	for (i = 0; i < num; i++) {
		if (regs[i].enable_load >= 0) {
			ret = regulator_set_load(s[i].consumer,
							regs[i].enable_load);
			if (ret < 0) {
				dev_err(dev,
					"regulator %d set op mode failed, %d\n",
					i, ret);
				goto fail;
			}
		}
	}

	ret = regulator_bulk_enable(num, s);
	if (ret < 0) {
		dev_err(dev, "regulator enable failed, %d\n", ret);
		goto fail;
	}

	return 0;

fail:
	for (i--; i >= 0; i--)
		regulator_set_load(s[i].consumer, regs[i].disable_load);
	return ret;
}

static void dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
				u32 bit_mask)
{
	int phy_id = phy->id;
	u32 val;

	if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
		return;

	val = dsi_phy_read(phy->base + reg);

	if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
		dsi_phy_write(phy->base + reg, val | bit_mask);
	else
		dsi_phy_write(phy->base + reg, val & (~bit_mask));
}
#include "dsi_phy.h"

#define S_DIV_ROUND_UP(n, d)	\
	(((n) >= 0) ? (((n) + (d) - 1) / (d)) : (((n) - (d) + 1) / (d)))
@@ -181,6 +22,7 @@ static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
				s32 min_result, bool even)
{
	s32 v;

	v = (tmax - tmin) * percent;
	v = S_DIV_ROUND_UP(v, 100) + tmin;
	if (even && (v & 0x1))
@@ -189,7 +31,7 @@ static inline s32 linear_inter(s32 tmax, s32 tmin, s32 percent,
		return max_t(s32, min_result, v);
}

static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
static void dsi_dphy_timing_calc_clk_zero(struct msm_dsi_dphy_timing *timing,
					s32 ui, s32 coeff, s32 pcnt)
{
	s32 tmax, tmin, clk_z;
@@ -211,7 +53,7 @@ static void dsi_dphy_timing_calc_clk_zero(struct dsi_dphy_timing *timing,
	timing->clk_zero = clk_z + 8 - temp;
}

static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
	const unsigned long bit_rate, const unsigned long esc_rate)
{
	s32 ui, lpx;
@@ -281,9 +123,8 @@ static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
	temp += 8 * ui + lpx;
	tmin = S_DIV_ROUND_UP(temp, 8 * ui) - 1;
	if (tmin > tmax) {
		temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false) >> 1;
		temp = linear_inter(2 * tmax, tmin, pcnt2, 0, false);
		timing->clk_pre = temp >> 1;
		temp = (2 * tmax - tmin) * pcnt2;
	} else {
		timing->clk_pre = linear_inter(tmax, tmin, pcnt2, 0, false);
	}
@@ -301,234 +142,119 @@ static int dsi_dphy_timing_calc(struct dsi_dphy_timing *timing,
	return 0;
}

static void dsi_28nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
				u32 bit_mask)
{
	void __iomem *base = phy->reg_base;
	int phy_id = phy->id;
	u32 val;

	if (!enable) {
		dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
	if ((phy_id >= DSI_MAX) || (pll_id >= DSI_MAX))
		return;
	}

	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x0);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CAL_PWR_CFG, 1);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_5, 0);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_3, 0);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_2, 0x3);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_1, 0x9);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_0, 0x7);
	dsi_phy_write(base + REG_DSI_28nm_PHY_REGULATOR_CTRL_4, 0x20);
	val = dsi_phy_read(phy->base + reg);

	if (phy->cfg->src_pll_truthtable[phy_id][pll_id])
		dsi_phy_write(phy->base + reg, val | bit_mask);
	else
		dsi_phy_write(phy->base + reg, val & (~bit_mask));
}

static int dsi_28nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
		const unsigned long bit_rate, const unsigned long esc_rate)
static int dsi_phy_regulator_init(struct msm_dsi_phy *phy)
{
	struct dsi_dphy_timing *timing = &phy->timing;
	int i;
	void __iomem *base = phy->base;
	struct regulator_bulk_data *s = phy->supplies;
	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
	struct device *dev = &phy->pdev->dev;
	int num = phy->cfg->reg_cfg.num;
	int i, ret;

	DBG("");
	for (i = 0; i < num; i++)
		s[i].supply = regs[i].name;

	if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
		pr_err("%s: D-PHY timing calculation failed\n", __func__);
		return -EINVAL;
	ret = devm_regulator_bulk_get(dev, num, s);
	if (ret < 0) {
		dev_err(dev, "%s: failed to init regulator, ret=%d\n",
						__func__, ret);
		return ret;
	}

	dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_0, 0xff);

	dsi_28nm_phy_regulator_ctrl(phy, true);

	dsi_phy_write(base + REG_DSI_28nm_PHY_LDO_CNTRL, 0x00);

	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_0,
		DSI_28nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_1,
		DSI_28nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_2,
		DSI_28nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
	if (timing->clk_zero & BIT(8))
		dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_3,
			DSI_28nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_4,
		DSI_28nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_5,
		DSI_28nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_6,
		DSI_28nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_7,
		DSI_28nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_8,
		DSI_28nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_9,
		DSI_28nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
		DSI_28nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_10,
		DSI_28nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
	dsi_phy_write(base + REG_DSI_28nm_PHY_TIMING_CTRL_11,
		DSI_28nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));

	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_1, 0x00);
	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);

	dsi_phy_write(base + REG_DSI_28nm_PHY_STRENGTH_1, 0x6);

	for (i = 0; i < 4; i++) {
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_0(i), 0);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_1(i), 0);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_2(i), 0);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_3(i), 0);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_DATAPATH(i), 0);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_DEBUG_SEL(i), 0);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_0(i), 0x1);
		dsi_phy_write(base + REG_DSI_28nm_PHY_LN_TEST_STR_1(i), 0x97);
	}
	dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(0), 0);
	dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(1), 0x5);
	dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(2), 0xa);
	dsi_phy_write(base + REG_DSI_28nm_PHY_LN_CFG_4(3), 0xf);

	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_CFG_1, 0xc0);
	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR0, 0x1);
	dsi_phy_write(base + REG_DSI_28nm_PHY_LNCK_TEST_STR1, 0xbb);

	dsi_phy_write(base + REG_DSI_28nm_PHY_CTRL_0, 0x5f);

	dsi_phy_set_src_pll(phy, src_pll_id, REG_DSI_28nm_PHY_GLBL_TEST_CTRL,
			DSI_28nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);
	for (i = 0; i < num; i++) {
		if ((regs[i].min_voltage >= 0) && (regs[i].max_voltage >= 0)) {
			ret = regulator_set_voltage(s[i].consumer,
				regs[i].min_voltage, regs[i].max_voltage);
			if (ret < 0) {
				dev_err(dev,
					"regulator %d set voltage failed, %d\n",
					i, ret);
				return ret;
			}
		}
	}

	return 0;
}

static void dsi_28nm_phy_disable(struct msm_dsi_phy *phy)
static void dsi_phy_regulator_disable(struct msm_dsi_phy *phy)
{
	dsi_phy_write(phy->base + REG_DSI_28nm_PHY_CTRL_0, 0);
	dsi_28nm_phy_regulator_ctrl(phy, false);
	struct regulator_bulk_data *s = phy->supplies;
	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
	int num = phy->cfg->reg_cfg.num;
	int i;

	/*
	 * Wait for the registers writes to complete in order to
	 * ensure that the phy is completely disabled
	 */
	wmb();
	DBG("");
	for (i = num - 1; i >= 0; i--)
		if (regs[i].disable_load >= 0)
			regulator_set_load(s[i].consumer, regs[i].disable_load);

	regulator_bulk_disable(num, s);
}

static void dsi_20nm_phy_regulator_ctrl(struct msm_dsi_phy *phy, bool enable)
static int dsi_phy_regulator_enable(struct msm_dsi_phy *phy)
{
	void __iomem *base = phy->reg_base;
	struct regulator_bulk_data *s = phy->supplies;
	const struct dsi_reg_entry *regs = phy->cfg->reg_cfg.regs;
	struct device *dev = &phy->pdev->dev;
	int num = phy->cfg->reg_cfg.num;
	int ret, i;

	if (!enable) {
		dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0);
		return;
	DBG("");
	for (i = 0; i < num; i++) {
		if (regs[i].enable_load >= 0) {
			ret = regulator_set_load(s[i].consumer,
							regs[i].enable_load);
			if (ret < 0) {
				dev_err(dev,
					"regulator %d set op mode failed, %d\n",
					i, ret);
				goto fail;
			}

	if (phy->regulator_ldo_mode) {
		dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x1d);
		return;
		}

	/* non LDO mode */
	dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_1, 0x03);
	dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_2, 0x03);
	dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_3, 0x00);
	dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_4, 0x20);
	dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CAL_PWR_CFG, 0x01);
	dsi_phy_write(phy->base + REG_DSI_20nm_PHY_LDO_CNTRL, 0x00);
	dsi_phy_write(base + REG_DSI_20nm_PHY_REGULATOR_CTRL_0, 0x03);
	}

static int dsi_20nm_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
		const unsigned long bit_rate, const unsigned long esc_rate)
{
	struct dsi_dphy_timing *timing = &phy->timing;
	int i;
	void __iomem *base = phy->base;
	u32 cfg_4[4] = {0x20, 0x40, 0x20, 0x00};

	DBG("");

	if (dsi_dphy_timing_calc(timing, bit_rate, esc_rate)) {
		pr_err("%s: D-PHY timing calculation failed\n", __func__);
		return -EINVAL;
	ret = regulator_bulk_enable(num, s);
	if (ret < 0) {
		dev_err(dev, "regulator enable failed, %d\n", ret);
		goto fail;
	}

	dsi_20nm_phy_regulator_ctrl(phy, true);

	dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_0, 0xff);

	dsi_phy_set_src_pll(phy, src_pll_id, REG_DSI_20nm_PHY_GLBL_TEST_CTRL,
			DSI_20nm_PHY_GLBL_TEST_CTRL_BITCLK_HS_SEL);

	for (i = 0; i < 4; i++) {
		dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_3(i),
							(i >> 1) * 0x40);
		dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_0(i), 0x01);
		dsi_phy_write(base + REG_DSI_20nm_PHY_LN_TEST_STR_1(i), 0x46);
		dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_0(i), 0x02);
		dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_1(i), 0xa0);
		dsi_phy_write(base + REG_DSI_20nm_PHY_LN_CFG_4(i), cfg_4[i]);
	}

	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_3, 0x80);
	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR0, 0x01);
	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_TEST_STR1, 0x46);
	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_0, 0x00);
	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_1, 0xa0);
	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_2, 0x00);
	dsi_phy_write(base + REG_DSI_20nm_PHY_LNCK_CFG_4, 0x00);

	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_0,
		DSI_20nm_PHY_TIMING_CTRL_0_CLK_ZERO(timing->clk_zero));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_1,
		DSI_20nm_PHY_TIMING_CTRL_1_CLK_TRAIL(timing->clk_trail));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_2,
		DSI_20nm_PHY_TIMING_CTRL_2_CLK_PREPARE(timing->clk_prepare));
	if (timing->clk_zero & BIT(8))
		dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_3,
			DSI_20nm_PHY_TIMING_CTRL_3_CLK_ZERO_8);
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_4,
		DSI_20nm_PHY_TIMING_CTRL_4_HS_EXIT(timing->hs_exit));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_5,
		DSI_20nm_PHY_TIMING_CTRL_5_HS_ZERO(timing->hs_zero));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_6,
		DSI_20nm_PHY_TIMING_CTRL_6_HS_PREPARE(timing->hs_prepare));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_7,
		DSI_20nm_PHY_TIMING_CTRL_7_HS_TRAIL(timing->hs_trail));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_8,
		DSI_20nm_PHY_TIMING_CTRL_8_HS_RQST(timing->hs_rqst));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_9,
		DSI_20nm_PHY_TIMING_CTRL_9_TA_GO(timing->ta_go) |
		DSI_20nm_PHY_TIMING_CTRL_9_TA_SURE(timing->ta_sure));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_10,
		DSI_20nm_PHY_TIMING_CTRL_10_TA_GET(timing->ta_get));
	dsi_phy_write(base + REG_DSI_20nm_PHY_TIMING_CTRL_11,
		DSI_20nm_PHY_TIMING_CTRL_11_TRIG3_CMD(0));

	dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_1, 0x00);

	dsi_phy_write(base + REG_DSI_20nm_PHY_STRENGTH_1, 0x06);

	/* make sure everything is written before enable */
	wmb();
	dsi_phy_write(base + REG_DSI_20nm_PHY_CTRL_0, 0x7f);

	return 0;
}

static void dsi_20nm_phy_disable(struct msm_dsi_phy *phy)
{
	dsi_phy_write(phy->base + REG_DSI_20nm_PHY_CTRL_0, 0);
	dsi_20nm_phy_regulator_ctrl(phy, false);
fail:
	for (i--; i >= 0; i--)
		regulator_set_load(s[i].consumer, regs[i].disable_load);
	return ret;
}

static int dsi_phy_enable_resource(struct msm_dsi_phy *phy)
{
	struct device *dev = &phy->pdev->dev;
	int ret;

	pm_runtime_get_sync(&phy->pdev->dev);
	pm_runtime_get_sync(dev);

	ret = clk_prepare_enable(phy->ahb_clk);
	if (ret) {
		pr_err("%s: can't enable ahb clk, %d\n", __func__, ret);
		pm_runtime_put_sync(&phy->pdev->dev);
		dev_err(dev, "%s: can't enable ahb clk, %d\n", __func__, ret);
		pm_runtime_put_sync(dev);
	}

	return ret;
@@ -540,114 +266,70 @@ static void dsi_phy_disable_resource(struct msm_dsi_phy *phy)
	pm_runtime_put_sync(&phy->pdev->dev);
}

static const struct dsi_phy_cfg dsi_phy_cfgs[MSM_DSI_PHY_MAX] = {
	[MSM_DSI_PHY_28NM_HPM] = {
		.type = MSM_DSI_PHY_28NM_HPM,
		.src_pll_truthtable = { {true, true}, {false, true} },
		.reg_cfg = {
			.num = 1,
			.regs = {
				{"vddio", 1800000, 1800000, 100000, 100},
			},
		},
		.ops = {
			.enable = dsi_28nm_phy_enable,
			.disable = dsi_28nm_phy_disable,
		}
	},
	[MSM_DSI_PHY_28NM_LP] = {
		.type = MSM_DSI_PHY_28NM_LP,
		.src_pll_truthtable = { {true, true}, {true, true} },
		.reg_cfg = {
			.num = 1,
			.regs = {
				{"vddio", 1800000, 1800000, 100000, 100},
			},
		},
		.ops = {
			.enable = dsi_28nm_phy_enable,
			.disable = dsi_28nm_phy_disable,
		}
	},
	[MSM_DSI_PHY_20NM] = {
		.type = MSM_DSI_PHY_20NM,
		.src_pll_truthtable = { {false, true}, {false, true} },
		.reg_cfg = {
			.num = 2,
			.regs = {
				{"vddio", 1800000, 1800000, 100000, 100},
				{"vcca", 1000000, 1000000, 10000, 100},
			},
		},
		.ops = {
			.enable = dsi_20nm_phy_enable,
			.disable = dsi_20nm_phy_disable,
		}
	},
};

static const struct of_device_id dsi_phy_dt_match[] = {
	{ .compatible = "qcom,dsi-phy-28nm-hpm",
	  .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_HPM],},
	  .data = &dsi_phy_28nm_hpm_cfgs },
	{ .compatible = "qcom,dsi-phy-28nm-lp",
	  .data = &dsi_phy_cfgs[MSM_DSI_PHY_28NM_LP],},
	  .data = &dsi_phy_28nm_lp_cfgs },
	{ .compatible = "qcom,dsi-phy-20nm",
	  .data = &dsi_phy_cfgs[MSM_DSI_PHY_20NM],},
	  .data = &dsi_phy_20nm_cfgs },
	{}
};

static int dsi_phy_driver_probe(struct platform_device *pdev)
{
	struct msm_dsi_phy *phy;
	struct device *dev = &pdev->dev;
	const struct of_device_id *match;
	int ret;

	phy = devm_kzalloc(&pdev->dev, sizeof(*phy), GFP_KERNEL);
	phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
	if (!phy)
		return -ENOMEM;

	match = of_match_node(dsi_phy_dt_match, pdev->dev.of_node);
	match = of_match_node(dsi_phy_dt_match, dev->of_node);
	if (!match)
		return -ENODEV;

	phy->cfg = match->data;
	phy->pdev = pdev;

	ret = of_property_read_u32(pdev->dev.of_node,
	ret = of_property_read_u32(dev->of_node,
				"qcom,dsi-phy-index", &phy->id);
	if (ret) {
		dev_err(&pdev->dev,
			"%s: PHY index not specified, ret=%d\n",
		dev_err(dev, "%s: PHY index not specified, %d\n",
			__func__, ret);
		goto fail;
	}

	phy->regulator_ldo_mode = of_property_read_bool(pdev->dev.of_node,
	phy->regulator_ldo_mode = of_property_read_bool(dev->of_node,
				"qcom,dsi-phy-regulator-ldo-mode");

	phy->base = msm_ioremap(pdev, "dsi_phy", "DSI_PHY");
	if (IS_ERR(phy->base)) {
		dev_err(&pdev->dev, "%s: failed to map phy base\n", __func__);
		dev_err(dev, "%s: failed to map phy base\n", __func__);
		ret = -ENOMEM;
		goto fail;
	}
	phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator", "DSI_PHY_REG");

	phy->reg_base = msm_ioremap(pdev, "dsi_phy_regulator",
				"DSI_PHY_REG");
	if (IS_ERR(phy->reg_base)) {
		dev_err(&pdev->dev,
			"%s: failed to map phy regulator base\n", __func__);
		dev_err(dev, "%s: failed to map phy regulator base\n",
			__func__);
		ret = -ENOMEM;
		goto fail;
	}

	ret = dsi_phy_regulator_init(phy);
	if (ret) {
		dev_err(&pdev->dev, "%s: failed to init regulator\n", __func__);
		dev_err(dev, "%s: failed to init regulator\n", __func__);
		goto fail;
	}

	phy->ahb_clk = devm_clk_get(&pdev->dev, "iface_clk");
	phy->ahb_clk = devm_clk_get(dev, "iface_clk");
	if (IS_ERR(phy->ahb_clk)) {
		pr_err("%s: Unable to get ahb clk\n", __func__);
		dev_err(dev, "%s: Unable to get ahb clk\n", __func__);
		ret = PTR_ERR(phy->ahb_clk);
		goto fail;
	}
@@ -661,7 +343,7 @@ static int dsi_phy_driver_probe(struct platform_device *pdev)

	phy->pll = msm_dsi_pll_init(pdev, phy->cfg->type, phy->id);
	if (!phy->pll)
		dev_info(&pdev->dev,
		dev_info(dev,
			"%s: pll init failed, need separate pll clk driver\n",
			__func__);

@@ -711,6 +393,7 @@ void __exit msm_dsi_phy_driver_unregister(void)
int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,
	const unsigned long bit_rate, const unsigned long esc_rate)
{
	struct device *dev = &phy->pdev->dev;
	int ret;

	if (!phy || !phy->cfg->ops.enable)
@@ -718,12 +401,19 @@ int msm_dsi_phy_enable(struct msm_dsi_phy *phy, int src_pll_id,

	ret = dsi_phy_regulator_enable(phy);
	if (ret) {
		dev_err(&phy->pdev->dev, "%s: regulator enable failed, %d\n",
		dev_err(dev, "%s: regulator enable failed, %d\n",
			__func__, ret);
		return ret;
	}

	return phy->cfg->ops.enable(phy, src_pll_id, bit_rate, esc_rate);
	ret = phy->cfg->ops.enable(phy, src_pll_id, bit_rate, esc_rate);
	if (ret) {
		dev_err(dev, "%s: phy enable failed, %d\n", __func__, ret);
		dsi_phy_regulator_disable(phy);
		return ret;
	}

	return 0;
}

void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
@@ -732,6 +422,7 @@ void msm_dsi_phy_disable(struct msm_dsi_phy *phy)
		return;

	phy->cfg->ops.disable(phy);

	dsi_phy_regulator_disable(phy);
}

@@ -740,6 +431,7 @@ void msm_dsi_phy_get_clk_pre_post(struct msm_dsi_phy *phy,
{
	if (!phy)
		return;

	if (clk_pre)
		*clk_pre = phy->timing.clk_pre;
	if (clk_post)
+89 −0
Original line number Diff line number Diff line
/*
 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __DSI_PHY_H__
#define __DSI_PHY_H__

#include <linux/regulator/consumer.h>

#include "dsi.h"

#define dsi_phy_read(offset) msm_readl((offset))
#define dsi_phy_write(offset, data) msm_writel((data), (offset))

struct msm_dsi_phy_ops {
	int (*enable)(struct msm_dsi_phy *phy, int src_pll_id,
		const unsigned long bit_rate, const unsigned long esc_rate);
	void (*disable)(struct msm_dsi_phy *phy);
};

struct msm_dsi_phy_cfg {
	enum msm_dsi_phy_type type;
	struct dsi_reg_config reg_cfg;
	struct msm_dsi_phy_ops ops;

	/*
	 * Each cell {phy_id, pll_id} of the truth table indicates
	 * if the source PLL selection bit should be set for each PHY.
	 * Fill default H/W values in illegal cells, eg. cell {0, 1}.
	 */
	bool src_pll_truthtable[DSI_MAX][DSI_MAX];
};

extern const struct msm_dsi_phy_cfg dsi_phy_28nm_hpm_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_28nm_lp_cfgs;
extern const struct msm_dsi_phy_cfg dsi_phy_20nm_cfgs;

struct msm_dsi_dphy_timing {
	u32 clk_pre;
	u32 clk_post;
	u32 clk_zero;
	u32 clk_trail;
	u32 clk_prepare;
	u32 hs_exit;
	u32 hs_zero;
	u32 hs_prepare;
	u32 hs_trail;
	u32 hs_rqst;
	u32 ta_go;
	u32 ta_sure;
	u32 ta_get;
};

struct msm_dsi_phy {
	struct platform_device *pdev;
	void __iomem *base;
	void __iomem *reg_base;
	int id;

	struct clk *ahb_clk;
	struct regulator_bulk_data supplies[DSI_DEV_REGULATOR_MAX];

	struct msm_dsi_dphy_timing timing;
	const struct msm_dsi_phy_cfg *cfg;

	bool regulator_ldo_mode;

	struct msm_dsi_pll *pll;
};

/*
 * PHY internal functions
 */
int msm_dsi_dphy_timing_calc(struct msm_dsi_dphy_timing *timing,
	const unsigned long bit_rate, const unsigned long esc_rate);
void msm_dsi_phy_set_src_pll(struct msm_dsi_phy *phy, int pll_id, u32 reg,
				u32 bit_mask);

#endif /* __DSI_PHY_H__ */
Loading