drm/rockchip: dsi: Clearly distinguish between SNPS PHY and Non-SNPS PHY

Change-Id: Ia947050f444eac75e951ddc8cd7e0b4453673094
Signed-off-by: WeiYong Bi <bivvy.bi@rock-chips.com>
This commit is contained in:
WeiYong Bi 2017-07-13 15:15:13 +08:00 committed by Huang, Tao
commit 9d268a4e2b
2 changed files with 114 additions and 84 deletions

View file

@ -18,9 +18,11 @@ Required properties:
For vopb,set the reg = <0> and set the reg = <1> for vopl.
Optional properties
- clocks, clock-names: phandle to the mipi dsi phy config clock, name should be
"phy_cfg".phandle to the mipi dsi phy reference clock, name should be 'ref'.
- phys: phandle to third party MIPI PHY node
- clocks, clock-names:
phandle to the SNPS-PHY config clock, name should be "phy_cfg".
phandle to the SNPS-PHY PLL reference clock, name should be "ref".
phandle to the Non-SNPS PHY high speed clock, name should be "hs_clk".
- phys: phandle to Non-SNPS PHY node
- phy-names: the string "mipi_dphy" when is found in a node, along with "phys"
attribute, provides phandle to MIPI PHY node
- resets : phandle to the reset of MIPI DSI APB Clock.
@ -79,34 +81,21 @@ For Rockchip RK3288:
For Rockchip RK3368:
mipi_dsi_host: mipi-dsi-host@ff960000 {
compatible = "rockchip,rk3368-mipi-dsi";
phys = <&mipi_dphy>;
phy-names = "mipi_dphy";
resets = <&cru SRST_MIPIDSI0>;
reset-names = "apb";
...
dsi: dsi@ff960000 {
compatible = "rockchip,rk3368-mipi-dsi";
clocks = <&cru PCLK_MIPI_DSI0>, <&mipi_dphy>;
clock-names = "pclk", "hs_clk";
phys = <&mipi_dphy>;
phy-names = "mipi_dphy";
resets = <&cru SRST_MIPIDSI0>;
reset-names = "apb";
...
ports@1 {
#address-cells = <1>;
#size-cells = <0>;
reg = <1>;
mipi_in: port {
#address-cells = <1>;
#size-cells = <0>;
mipi_in_vop: endpoint@0 {
reg = <0>;
remote-endpoint = <&vop_out_mipi>;
ports {
port {
dsi_in_vop: endpoint {
remote-endpoint = <&vop_out_dsi>;
};
};
};
};
dsi_panel: panel@0 {
compatible = "simple-panel-dsi";
reg = <0>;
dsi,lanes = <4>;
...
};
};

View file

@ -295,28 +295,35 @@ struct dw_mipi_dsi_plat_data {
struct drm_display_mode *mode);
};
struct mipi_dphy {
/* SNPS PHY */
struct clk *cfg_clk;
struct clk *ref_clk;
u16 input_div;
u16 feedback_div;
/* Non-SNPS PHY */
struct phy *phy;
struct clk *hs_clk;
};
struct dw_mipi_dsi {
struct drm_encoder encoder;
struct drm_connector connector;
struct mipi_dsi_host dsi_host;
struct phy *phy;
struct mipi_dphy dphy;
struct drm_panel *panel;
struct device *dev;
struct regmap *grf_regmap;
struct reset_control *rst;
void __iomem *base;
struct clk *pllref_clk;
struct clk *pclk;
struct clk *phy_cfg_clk;
unsigned long mode_flags;
unsigned int lane_mbps; /* per lane */
u32 channel;
u32 lanes;
u32 format;
u16 input_div;
u16 feedback_div;
struct drm_display_mode mode;
const struct dw_mipi_dsi_plat_data *pdata;
@ -468,8 +475,8 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
dsi_write(dsi, DSI_PWR_UP, POWERUP);
if (!IS_ERR(dsi->phy_cfg_clk)) {
ret = clk_prepare_enable(dsi->phy_cfg_clk);
if (!IS_ERR(dsi->dphy.cfg_clk)) {
ret = clk_prepare_enable(dsi->dphy.cfg_clk);
if (ret) {
dev_err(dsi->dev, "Failed to enable phy_cfg_clk\n");
return ret;
@ -487,11 +494,11 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
dw_mipi_dsi_phy_write(dsi, 0x44, HSFREQRANGE_SEL(testdin));
dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->input_div));
dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_LOW_SEL(dsi->feedback_div) |
LOW_PROGRAM_EN);
dw_mipi_dsi_phy_write(dsi, 0x18, LOOP_DIV_HIGH_SEL(dsi->feedback_div) |
HIGH_PROGRAM_EN);
dw_mipi_dsi_phy_write(dsi, 0x17, INPUT_DIVIDER(dsi->dphy.input_div));
val = LOOP_DIV_LOW_SEL(dsi->dphy.feedback_div) | LOW_PROGRAM_EN;
dw_mipi_dsi_phy_write(dsi, 0x18, val);
val = LOOP_DIV_HIGH_SEL(dsi->dphy.feedback_div) | HIGH_PROGRAM_EN;
dw_mipi_dsi_phy_write(dsi, 0x18, val);
dw_mipi_dsi_phy_write(dsi, 0x19, PLL_LOOP_DIV_EN | PLL_INPUT_DIV_EN);
dw_mipi_dsi_phy_write(dsi, 0x20, POWER_CONTROL | INTERNAL_REG_CURRENT |
@ -530,26 +537,28 @@ static int dw_mipi_dsi_phy_init(struct dw_mipi_dsi *dsi)
"failed to wait for phy clk lane stop state\n");
phy_init_end:
if (!IS_ERR(dsi->phy_cfg_clk))
clk_disable_unprepare(dsi->phy_cfg_clk);
if (!IS_ERR(dsi->dphy.cfg_clk))
clk_disable_unprepare(dsi->dphy.cfg_clk);
return ret;
}
static int rockchip_dsi_calc_bandwidth(struct dw_mipi_dsi *dsi)
static unsigned long rockchip_dsi_calc_bandwidth(struct dw_mipi_dsi *dsi)
{
int bpp;
unsigned long mpclk, tmp;
unsigned int target_mbps = 1000;
unsigned int value;
struct device_node *np = dsi->dev->of_node;
unsigned int max_mbps = dptdin_map[ARRAY_SIZE(dptdin_map) - 1].max_mbps;
unsigned int max_mbps;
int lanes;
/* optional override of the desired bandwidth */
if (!of_property_read_u32(np, "rockchip,lane-rate", &value))
return value;
max_mbps = dsi->pdata->max_bit_rate_per_lane / USEC_PER_SEC;
bpp = mipi_dsi_pixel_format_to_bpp(dsi->format);
if (bpp < 0) {
dev_err(dsi->dev, "failed to get bpp for pixel format %d\n",
@ -569,18 +578,18 @@ static int rockchip_dsi_calc_bandwidth(struct dw_mipi_dsi *dsi)
dev_err(dsi->dev, "DPHY clock frequency is out of range\n");
}
return target_mbps;
return target_mbps * USEC_PER_SEC;
}
static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi)
static unsigned long dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi,
unsigned long rate)
{
unsigned int i, pre;
unsigned long pllref, tmp;
unsigned int m = 1, n = 1, target_mbps;
unsigned int m = 1, n = 1;
unsigned long target_mbps = rate / USEC_PER_SEC;
target_mbps = rockchip_dsi_calc_bandwidth(dsi);
pllref = DIV_ROUND_UP(clk_get_rate(dsi->pllref_clk), USEC_PER_SEC);
pllref = DIV_ROUND_UP(clk_get_rate(dsi->dphy.ref_clk), USEC_PER_SEC);
tmp = pllref;
for (i = 1; i < 6; i++) {
@ -594,11 +603,10 @@ static int dw_mipi_dsi_get_lane_bps(struct dw_mipi_dsi *dsi)
break;
}
dsi->lane_mbps = pllref / n * m;
dsi->input_div = n;
dsi->feedback_div = m;
dsi->dphy.input_div = n;
dsi->dphy.feedback_div = m;
return 0;
return (pllref * m / n) * USEC_PER_SEC;
}
static int dw_mipi_dsi_host_attach(struct mipi_dsi_host *host,
@ -911,8 +919,10 @@ static void rockchip_dsi_disable(struct dw_mipi_dsi *dsi)
/* phy */
dsi_write(dsi, DSI_PHY_RSTZ, PHY_RSTZ);
if (dsi->phy)
phy_power_off(dsi->phy);
if (dsi->dphy.phy) {
clk_disable_unprepare(dsi->dphy.hs_clk);
phy_power_off(dsi->dphy.phy);
}
pm_runtime_put(dsi->dev);
clk_disable_unprepare(dsi->pclk);
@ -961,12 +971,15 @@ static void rockchip_dsi_grf_config(struct dw_mipi_dsi *dsi, int vop_id)
static void rockchip_dsi_pre_init(struct dw_mipi_dsi *dsi)
{
unsigned long bw, rate;
int ret;
if (clk_prepare_enable(dsi->pclk)) {
dev_err(dsi->dev, "%s: Failed to enable pclk\n", __func__);
return;
}
if (clk_prepare_enable(dsi->pllref_clk)) {
if (clk_prepare_enable(dsi->dphy.ref_clk)) {
dev_err(dsi->dev, "Failed to enable pllref_clk\n");
return;
}
@ -981,17 +994,27 @@ static void rockchip_dsi_pre_init(struct dw_mipi_dsi *dsi)
udelay(10);
}
if (dsi->phy) {
phy_power_on(dsi->phy);
bw = rockchip_dsi_calc_bandwidth(dsi);
/*
* If using the third party PHY, we get the lane
* rate information from PHY.
*/
dsi->lane_mbps = phy_get_bus_width(dsi->phy);
if (dsi->dphy.phy) {
rate = clk_round_rate(dsi->dphy.hs_clk, bw);
ret = clk_set_rate(dsi->dphy.hs_clk, rate);
if (ret) {
dev_err(dsi->dev, "failed to set hs clock rate: %lu\n",
rate);
return;
}
clk_prepare_enable(dsi->dphy.hs_clk);
phy_power_on(dsi->dphy.phy);
} else {
dw_mipi_dsi_get_lane_bps(dsi);
rate = dw_mipi_dsi_get_lane_bps(dsi, bw);
}
dsi->lane_mbps = rate / USEC_PER_SEC;
dev_info(dsi->dev, "final DSI-Link bandwidth: %u x %d Mbps\n",
dsi->lane_mbps, dsi->lanes);
}
static void rockchip_dsi_host_init(struct dw_mipi_dsi *dsi)
@ -1021,7 +1044,7 @@ static void rockchip_dsi_enable(struct dw_mipi_dsi *dsi)
{
dsi_write(dsi, DSI_LPCLK_CTRL, PHY_TXREQUESTCLKHS);
dw_mipi_dsi_set_mode(dsi, DSI_VIDEO_MODE);
clk_disable_unprepare(dsi->pllref_clk);
clk_disable_unprepare(dsi->dphy.ref_clk);
clk_disable_unprepare(dsi->pclk);
}
@ -1328,18 +1351,6 @@ static int rockchip_dsi_clk_get(struct dw_mipi_dsi *dsi)
return ret;
}
dsi->pllref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(dsi->pllref_clk)) {
dev_info(dev, "No PHY reference clock specified\n");
dsi->pllref_clk = NULL;
}
dsi->phy_cfg_clk = devm_clk_get(dev, "phy_cfg");
if (IS_ERR(dsi->phy_cfg_clk)) {
dev_info(dev, "No PHY APB clock specified\n");
dsi->phy_cfg_clk = NULL;
}
return 0;
}
@ -1348,13 +1359,43 @@ static int rockchip_dsi_dphy_parse(struct dw_mipi_dsi *dsi)
struct device *dev = dsi->dev;
int ret;
dsi->phy = devm_phy_optional_get(dev, "mipi_dphy");
if (IS_ERR(dsi->phy)) {
ret = PTR_ERR(dsi->phy);
dsi->dphy.phy = devm_phy_optional_get(dev, "mipi_dphy");
if (IS_ERR(dsi->dphy.phy)) {
ret = PTR_ERR(dsi->dphy.phy);
dev_err(dev, "failed to get mipi dphy: %d\n", ret);
return ret;
}
if (dsi->dphy.phy) {
dev_dbg(dev, "Use Non-SNPS PHY\n");
dsi->dphy.hs_clk = devm_clk_get(dev, "hs_clk");
if (IS_ERR(dsi->dphy.hs_clk)) {
dev_err(dev, "failed to get PHY high-speed clock\n");
return PTR_ERR(dsi->dphy.hs_clk);
}
} else {
dev_dbg(dev, "Use SNPS PHY\n");
dsi->dphy.ref_clk = devm_clk_get(dev, "ref");
if (IS_ERR(dsi->dphy.ref_clk)) {
dev_err(dev, "failed to get PHY reference clock\n");
return PTR_ERR(dsi->dphy.ref_clk);
}
/* Check if cfg_clk provided */
dsi->dphy.cfg_clk = devm_clk_get(dev, "phy_cfg");
if (IS_ERR(dsi->dphy.cfg_clk)) {
if (PTR_ERR(dsi->dphy.cfg_clk) != -ENOENT) {
dev_err(dev, "failed to get PHY config clk\n");
return PTR_ERR(dsi->dphy.cfg_clk);
}
/* Otherwise mark the cfg_clk pointer to NULL */
dsi->dphy.cfg_clk = NULL;
}
}
return 0;
}