Skip to content

Commit

Permalink
drm/msm/dsi: Move PHY operations out of host
Browse files Browse the repository at this point in the history
Since DSI PHY has been a separate platform device, it should not
depend on the resources in host to be functional. This change is
to trigger PHY operations in manager, instead of host, so that
host and PHY can be completely separated.

Signed-off-by: Hai Li <hali@codeaurora.org>
Signed-off-by: Archit Taneja <architt@codeaurora.org>
Signed-off-by: Rob Clark <robdclark@gmail.com>
  • Loading branch information
Hai Li authored and Rob Clark committed Feb 6, 2017
1 parent 34d9545 commit b62aa70
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 125 deletions.
18 changes: 12 additions & 6 deletions drivers/gpu/drm/msm/dsi/dsi.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define DSI_MAX 2

struct msm_dsi_phy_shared_timings;
struct msm_dsi_phy_clk_request;

enum msm_dsi_phy_type {
MSM_DSI_PHY_28NM_HPM,
Expand Down Expand Up @@ -92,10 +93,6 @@ struct drm_bridge *msm_dsi_manager_bridge_init(u8 id);
void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge);
struct drm_connector *msm_dsi_manager_connector_init(u8 id);
struct drm_connector *msm_dsi_manager_ext_bridge_init(u8 id);
int msm_dsi_manager_phy_enable(int id,
const unsigned long bit_rate, const unsigned long esc_rate,
struct msm_dsi_phy_shared_timings *shared_timing);
void msm_dsi_manager_phy_disable(int id);
int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg);
bool msm_dsi_manager_cmd_xfer_trigger(int id, u32 dma_base, u32 len);
void msm_dsi_manager_attach_dsi_device(int id, u32 device_flags);
Expand Down Expand Up @@ -155,7 +152,8 @@ void msm_dsi_host_cmd_xfer_commit(struct mipi_dsi_host *host,
u32 dma_base, u32 len);
int msm_dsi_host_enable(struct mipi_dsi_host *host);
int msm_dsi_host_disable(struct mipi_dsi_host *host);
int msm_dsi_host_power_on(struct mipi_dsi_host *host);
int msm_dsi_host_power_on(struct mipi_dsi_host *host,
struct msm_dsi_phy_shared_timings *phy_shared_timings);
int msm_dsi_host_power_off(struct mipi_dsi_host *host);
int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
struct drm_display_mode *mode);
Expand All @@ -167,6 +165,8 @@ void msm_dsi_host_unregister(struct mipi_dsi_host *host);
int msm_dsi_host_set_src_pll(struct mipi_dsi_host *host,
struct msm_dsi_pll *src_pll);
void msm_dsi_host_reset_phy(struct mipi_dsi_host *host);
void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host,
struct msm_dsi_phy_clk_request *clk_req);
void msm_dsi_host_destroy(struct mipi_dsi_host *host);
int msm_dsi_host_modeset_init(struct mipi_dsi_host *host,
struct drm_device *dev);
Expand All @@ -179,10 +179,16 @@ struct msm_dsi_phy_shared_timings {
u32 clk_pre;
bool clk_pre_inc_by_2;
};

struct msm_dsi_phy_clk_request {
unsigned long bitclk_rate;
unsigned long escclk_rate;
};

void msm_dsi_phy_driver_register(void);
void 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 msm_dsi_phy_clk_request *clk_req);
void msm_dsi_phy_disable(struct msm_dsi_phy *phy);
void msm_dsi_phy_get_shared_timings(struct msm_dsi_phy *phy,
struct msm_dsi_phy_shared_timings *shared_timing);
Expand Down
46 changes: 19 additions & 27 deletions drivers/gpu/drm/msm/dsi/dsi_host.c
Original file line number Diff line number Diff line change
Expand Up @@ -2128,6 +2128,15 @@ void msm_dsi_host_reset_phy(struct mipi_dsi_host *host)
udelay(100);
}

void msm_dsi_host_get_phy_clk_req(struct mipi_dsi_host *host,
struct msm_dsi_phy_clk_request *clk_req)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);

clk_req->bitclk_rate = msm_host->byte_clk_rate * 8;
clk_req->escclk_rate = msm_host->esc_clk_rate;
}

int msm_dsi_host_enable(struct mipi_dsi_host *host)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
Expand Down Expand Up @@ -2175,10 +2184,10 @@ static void msm_dsi_sfpb_config(struct msm_dsi_host *msm_host, bool enable)
SFPB_GPREG_MASTER_PORT_EN(en));
}

int msm_dsi_host_power_on(struct mipi_dsi_host *host)
int msm_dsi_host_power_on(struct mipi_dsi_host *host,
struct msm_dsi_phy_shared_timings *phy_shared_timings)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
struct msm_dsi_phy_shared_timings phy_shared_timings;
int ret = 0;

mutex_lock(&msm_host->dev_mutex);
Expand All @@ -2189,35 +2198,13 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)

msm_dsi_sfpb_config(msm_host, true);

ret = dsi_calc_clk_rate(msm_host);
if (ret) {
pr_err("%s: unable to calc clk rate, %d\n", __func__, ret);
goto unlock_ret;
}

ret = dsi_host_regulator_enable(msm_host);
if (ret) {
pr_err("%s:Failed to enable vregs.ret=%d\n",
__func__, ret);
goto unlock_ret;
}

ret = dsi_bus_clk_enable(msm_host);
if (ret) {
pr_err("%s: failed to enable bus clocks, %d\n", __func__, ret);
goto fail_disable_reg;
}

ret = msm_dsi_manager_phy_enable(msm_host->id,
msm_host->byte_clk_rate * 8,
msm_host->esc_clk_rate,
&phy_shared_timings);
dsi_bus_clk_disable(msm_host);
if (ret) {
pr_err("%s: failed to enable phy, %d\n", __func__, ret);
goto fail_disable_reg;
}

ret = dsi_clk_ctrl(msm_host, 1);
if (ret) {
pr_err("%s: failed to enable clocks. ret=%d\n", __func__, ret);
Expand All @@ -2233,7 +2220,7 @@ int msm_dsi_host_power_on(struct mipi_dsi_host *host)

dsi_timing_setup(msm_host);
dsi_sw_reset(msm_host);
dsi_ctrl_config(msm_host, true, &phy_shared_timings);
dsi_ctrl_config(msm_host, true, phy_shared_timings);

if (msm_host->disp_en_gpio)
gpiod_set_value(msm_host->disp_en_gpio, 1);
Expand Down Expand Up @@ -2269,8 +2256,6 @@ int msm_dsi_host_power_off(struct mipi_dsi_host *host)

pinctrl_pm_select_sleep_state(&msm_host->pdev->dev);

msm_dsi_manager_phy_disable(msm_host->id);

dsi_clk_ctrl(msm_host, 0);

dsi_host_regulator_disable(msm_host);
Expand All @@ -2290,6 +2275,7 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
struct drm_display_mode *mode)
{
struct msm_dsi_host *msm_host = to_msm_dsi_host(host);
int ret;

if (msm_host->mode) {
drm_mode_destroy(msm_host->dev, msm_host->mode);
Expand All @@ -2302,6 +2288,12 @@ int msm_dsi_host_set_display_mode(struct mipi_dsi_host *host,
return -ENOMEM;
}

ret = dsi_calc_clk_rate(msm_host);
if (ret) {
pr_err("%s: unable to calc clk rate, %d\n", __func__, ret);
return ret;
}

return 0;
}

Expand Down
178 changes: 105 additions & 73 deletions drivers/gpu/drm/msm/dsi/dsi_manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,84 @@ static int dsi_mgr_setup_components(int id)
return ret;
}

static int enable_phy(struct msm_dsi *msm_dsi, int src_pll_id,
struct msm_dsi_phy_shared_timings *shared_timings)
{
struct msm_dsi_phy_clk_request clk_req;
int ret;

msm_dsi_host_get_phy_clk_req(msm_dsi->host, &clk_req);

ret = msm_dsi_phy_enable(msm_dsi->phy, src_pll_id, &clk_req);
msm_dsi_phy_get_shared_timings(msm_dsi->phy, shared_timings);

return ret;
}

static int
dsi_mgr_phy_enable(int id,
struct msm_dsi_phy_shared_timings shared_timings[DSI_MAX])
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
int ret;

/* In case of dual DSI, some registers in PHY1 have been programmed
* during PLL0 clock's set_rate. The PHY1 reset called by host1 here
* will silently reset those PHY1 registers. Therefore we need to reset
* and enable both PHYs before any PLL clock operation.
*/
if (IS_DUAL_DSI() && mdsi && sdsi) {
if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
msm_dsi_host_reset_phy(mdsi->host);
msm_dsi_host_reset_phy(sdsi->host);

ret = enable_phy(mdsi, src_pll_id,
&shared_timings[DSI_CLOCK_MASTER]);
if (ret)
return ret;
ret = enable_phy(sdsi, src_pll_id,
&shared_timings[DSI_CLOCK_SLAVE]);
if (ret) {
msm_dsi_phy_disable(mdsi->phy);
return ret;
}
}
} else {
msm_dsi_host_reset_phy(mdsi->host);
ret = enable_phy(msm_dsi, src_pll_id, &shared_timings[id]);
if (ret)
return ret;
}

msm_dsi->phy_enabled = true;

return 0;
}

static void dsi_mgr_phy_disable(int id)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);

/* disable DSI phy
* In dual-dsi configuration, the phy should be disabled for the
* first controller only when the second controller is disabled.
*/
msm_dsi->phy_enabled = false;
if (IS_DUAL_DSI() && mdsi && sdsi) {
if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
msm_dsi_phy_disable(sdsi->phy);
msm_dsi_phy_disable(mdsi->phy);
}
} else {
msm_dsi_phy_disable(msm_dsi->phy);
}
}

struct dsi_connector {
struct drm_connector base;
int id;
Expand Down Expand Up @@ -360,22 +438,31 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
struct msm_dsi *msm_dsi1 = dsi_mgr_get_dsi(DSI_1);
struct mipi_dsi_host *host = msm_dsi->host;
struct drm_panel *panel = msm_dsi->panel;
struct msm_dsi_phy_shared_timings phy_shared_timings[DSI_MAX];
bool is_dual_dsi = IS_DUAL_DSI();
int ret;

DBG("id=%d", id);
if (!msm_dsi_device_connected(msm_dsi) ||
(is_dual_dsi && (DSI_1 == id)))
if (!msm_dsi_device_connected(msm_dsi))
return;

ret = msm_dsi_host_power_on(host);
ret = dsi_mgr_phy_enable(id, phy_shared_timings);
if (ret)
goto phy_en_fail;

/* Do nothing with the host if it is DSI 1 in case of dual DSI */
if (is_dual_dsi && (DSI_1 == id))
return;

ret = msm_dsi_host_power_on(host, &phy_shared_timings[id]);
if (ret) {
pr_err("%s: power on host %d failed, %d\n", __func__, id, ret);
goto host_on_fail;
}

if (is_dual_dsi && msm_dsi1) {
ret = msm_dsi_host_power_on(msm_dsi1->host);
ret = msm_dsi_host_power_on(msm_dsi1->host,
&phy_shared_timings[DSI_1]);
if (ret) {
pr_err("%s: power on host1 failed, %d\n",
__func__, ret);
Expand Down Expand Up @@ -434,6 +521,8 @@ static void dsi_mgr_bridge_pre_enable(struct drm_bridge *bridge)
host1_on_fail:
msm_dsi_host_power_off(host);
host_on_fail:
dsi_mgr_phy_disable(id);
phy_en_fail:
return;
}

Expand All @@ -459,10 +548,17 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)

DBG("id=%d", id);

if (!msm_dsi_device_connected(msm_dsi) ||
(is_dual_dsi && (DSI_1 == id)))
if (!msm_dsi_device_connected(msm_dsi))
return;

/*
* Do nothing with the host if it is DSI 1 in case of dual DSI.
* It is safe to call dsi_mgr_phy_disable() here because a single PHY
* won't be diabled until both PHYs request disable.
*/
if (is_dual_dsi && (DSI_1 == id))
goto disable_phy;

if (panel) {
ret = drm_panel_disable(panel);
if (ret)
Expand Down Expand Up @@ -497,6 +593,9 @@ static void dsi_mgr_bridge_post_disable(struct drm_bridge *bridge)
pr_err("%s: host1 power off failed, %d\n",
__func__, ret);
}

disable_phy:
dsi_mgr_phy_disable(id);
}

static void dsi_mgr_bridge_mode_set(struct drm_bridge *bridge,
Expand Down Expand Up @@ -664,73 +763,6 @@ void msm_dsi_manager_bridge_destroy(struct drm_bridge *bridge)
{
}

int msm_dsi_manager_phy_enable(int id,
const unsigned long bit_rate, const unsigned long esc_rate,
struct msm_dsi_phy_shared_timings *shared_timings)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
struct msm_dsi_phy *phy = msm_dsi->phy;
int src_pll_id = IS_DUAL_DSI() ? DSI_CLOCK_MASTER : id;
int ret;

/* In case of dual DSI, some registers in PHY1 have been programmed
* during PLL0 clock's set_rate. The PHY1 reset called by host1 here
* will silently reset those PHY1 registers. Therefore we need to reset
* and enable both PHYs before any PLL clock operation.
*/
if (IS_DUAL_DSI() && mdsi && sdsi) {
if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
msm_dsi_host_reset_phy(mdsi->host);
msm_dsi_host_reset_phy(sdsi->host);
ret = msm_dsi_phy_enable(mdsi->phy, src_pll_id,
bit_rate, esc_rate);
if (ret)
return ret;
ret = msm_dsi_phy_enable(sdsi->phy, src_pll_id,
bit_rate, esc_rate);
if (ret) {
msm_dsi_phy_disable(mdsi->phy);
return ret;
}
}
} else {
msm_dsi_host_reset_phy(msm_dsi->host);
ret = msm_dsi_phy_enable(msm_dsi->phy, src_pll_id, bit_rate,
esc_rate);
if (ret)
return ret;
}

msm_dsi->phy_enabled = true;
msm_dsi_phy_get_shared_timings(phy, shared_timings);

return 0;
}

void msm_dsi_manager_phy_disable(int id)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
struct msm_dsi *mdsi = dsi_mgr_get_dsi(DSI_CLOCK_MASTER);
struct msm_dsi *sdsi = dsi_mgr_get_dsi(DSI_CLOCK_SLAVE);
struct msm_dsi_phy *phy = msm_dsi->phy;

/* disable DSI phy
* In dual-dsi configuration, the phy should be disabled for the
* first controller only when the second controller is disabled.
*/
msm_dsi->phy_enabled = false;
if (IS_DUAL_DSI() && mdsi && sdsi) {
if (!mdsi->phy_enabled && !sdsi->phy_enabled) {
msm_dsi_phy_disable(sdsi->phy);
msm_dsi_phy_disable(mdsi->phy);
}
} else {
msm_dsi_phy_disable(phy);
}
}

int msm_dsi_manager_cmd_xfer(int id, const struct mipi_dsi_msg *msg)
{
struct msm_dsi *msm_dsi = dsi_mgr_get_dsi(id);
Expand Down
Loading

0 comments on commit b62aa70

Please sign in to comment.