Skip to content
Snippets Groups Projects
Commit 426f0642 authored by Robert Chiras's avatar Robert Chiras
Browse files

MLK-20718-5: drm/imx: nwl_dsi-imx: Correct clk usage


For QM and QXP, the PHY_REF clock was default ON on SCFW so it was not
handled by driver. Since now this clock is OFF in SCFW, it can be
correctly handled by kernel driver.
Now, the PHY_REF clock rate is set by the nwl-dsi bridge driver,
depending on the display mode used.
In this driver, the PIXEL and BYPASS clocks rates were set to the same
rate as the PHY_REF, but their rates need to be set to current display
mode clock.
Also, the order of the clocks matters, so make sure the BYPASS is
enabled before the PIXEL clock.

Signed-off-by: default avatarRobert Chiras <robert.chiras@nxp.com>
Reviewed-by: default avatarLaurentiu Palcu <laurentiu.palcu@nxp.com>
parent e3f863c3
No related merge requests found
...@@ -117,9 +117,9 @@ static struct devtype imx8qm_dev = { ...@@ -117,9 +117,9 @@ static struct devtype imx8qm_dev = {
.poweroff = &imx8qm_dsi_poweroff, .poweroff = &imx8qm_dsi_poweroff,
.clk_config = { .clk_config = {
{ .id = CLK_CORE, .present = false }, { .id = CLK_CORE, .present = false },
{ .id = CLK_PIXEL, .present = true },
{ .id = CLK_BYPASS, .present = true },
{ .id = CLK_PHYREF, .present = true }, { .id = CLK_PHYREF, .present = true },
{ .id = CLK_BYPASS, .present = true },
{ .id = CLK_PIXEL, .present = true },
}, },
.ext_regs = IMX_REG_CSR, .ext_regs = IMX_REG_CSR,
.tx_ulps_reg = 0x00, .tx_ulps_reg = 0x00,
...@@ -134,9 +134,9 @@ static struct devtype imx8qxp_dev = { ...@@ -134,9 +134,9 @@ static struct devtype imx8qxp_dev = {
.poweroff = &imx8qxp_dsi_poweroff, .poweroff = &imx8qxp_dsi_poweroff,
.clk_config = { .clk_config = {
{ .id = CLK_CORE, .present = false }, { .id = CLK_CORE, .present = false },
{ .id = CLK_PIXEL, .present = true },
{ .id = CLK_BYPASS, .present = true },
{ .id = CLK_PHYREF, .present = true }, { .id = CLK_PHYREF, .present = true },
{ .id = CLK_BYPASS, .present = true },
{ .id = CLK_PIXEL, .present = true },
}, },
.ext_regs = IMX_REG_CSR, .ext_regs = IMX_REG_CSR,
.tx_ulps_reg = 0x30, .tx_ulps_reg = 0x30,
...@@ -177,28 +177,10 @@ static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable) ...@@ -177,28 +177,10 @@ static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable)
struct device *dev = dsi->dev; struct device *dev = dsi->dev;
const char *id; const char *id;
struct clk *clk; struct clk *clk;
unsigned long new_rate, cur_rate, phy_rate = 0; unsigned long new_rate, cur_rate;
bool enabled; bool enabled;
size_t i; size_t i;
/*
* PHY_REF rate should be set by the nwl-dsi bridge, depending on the
* current mode used. We need that rate to set the PIXEL clock for
* QM or QXP.
*/
for (i = 0; i < dsi->clk_num; i++) {
if (!dsi->clk_config[i].present)
continue;
id = dsi->clk_config[i].id;
clk = dsi->clk_config[i].clk;
if (!strcmp(id, CLK_BYPASS) || !strcmp(id, CLK_PHYREF)) {
dsi->clk_config[i].rate = clk_get_rate(clk);
phy_rate = dsi->clk_config[i].rate;
break;
}
}
for (i = 0; i < dsi->clk_num; i++) { for (i = 0; i < dsi->clk_num; i++) {
if (!dsi->clk_config[i].present) if (!dsi->clk_config[i].present)
continue; continue;
...@@ -208,9 +190,6 @@ static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable) ...@@ -208,9 +190,6 @@ static void imx_nwl_dsi_set_clocks(struct imx_mipi_dsi *dsi, bool enable)
cur_rate = clk_get_rate(clk); cur_rate = clk_get_rate(clk);
enabled = dsi->clk_config[i].enabled; enabled = dsi->clk_config[i].enabled;
if (!strcmp(id, CLK_PIXEL) && phy_rate)
new_rate = phy_rate;
if (enable) { if (enable) {
if (enabled && new_rate != cur_rate) if (enabled && new_rate != cur_rate)
clk_disable_unprepare(clk); clk_disable_unprepare(clk);
...@@ -571,6 +550,25 @@ static bool imx_nwl_dsi_mode_fixup(struct imx_mipi_dsi *dsi, ...@@ -571,6 +550,25 @@ static bool imx_nwl_dsi_mode_fixup(struct imx_mipi_dsi *dsi,
return true; return true;
} }
static void imx_nwl_dsi_mode_set(struct imx_mipi_dsi *dsi,
struct drm_display_mode *mode)
{ const char *id;
struct clk *clk;
size_t i;
for (i = 0; i < dsi->clk_num; i++) {
if (!dsi->clk_config[i].present)
continue;
id = dsi->clk_config[i].id;
clk = dsi->clk_config[i].clk;
/* Set bypass and pixel clocks to mode clock rate */
if (!strcmp(id, CLK_BYPASS) || !strcmp(id, CLK_PIXEL))
dsi->clk_config[i].rate = mode->crtc_clock * 1000;
}
}
static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder, static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder,
struct drm_crtc_state *crtc_state, struct drm_crtc_state *crtc_state,
struct drm_connector_state *conn_state) struct drm_connector_state *conn_state)
...@@ -583,11 +581,21 @@ static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder, ...@@ -583,11 +581,21 @@ static int imx_nwl_dsi_encoder_atomic_check(struct drm_encoder *encoder,
return !imx_nwl_dsi_mode_fixup(dsi, &crtc_state->adjusted_mode); return !imx_nwl_dsi_mode_fixup(dsi, &crtc_state->adjusted_mode);
} }
static void imx_nwl_dsi_encoder_mode_set(struct drm_encoder *encoder,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
struct imx_mipi_dsi *dsi = encoder_to_dsi(encoder);
imx_nwl_dsi_mode_set(dsi, adjusted_mode);
}
static const struct drm_encoder_helper_funcs static const struct drm_encoder_helper_funcs
imx_nwl_dsi_encoder_helper_funcs = { imx_nwl_dsi_encoder_helper_funcs = {
.enable = imx_nwl_dsi_encoder_enable, .enable = imx_nwl_dsi_encoder_enable,
.disable = imx_nwl_dsi_encoder_disable, .disable = imx_nwl_dsi_encoder_disable,
.atomic_check = imx_nwl_dsi_encoder_atomic_check, .atomic_check = imx_nwl_dsi_encoder_atomic_check,
.mode_set = imx_nwl_dsi_encoder_mode_set,
}; };
static void imx_nwl_dsi_encoder_destroy(struct drm_encoder *encoder) static void imx_nwl_dsi_encoder_destroy(struct drm_encoder *encoder)
...@@ -625,6 +633,15 @@ static bool imx_nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge, ...@@ -625,6 +633,15 @@ static bool imx_nwl_dsi_bridge_mode_fixup(struct drm_bridge *bridge,
return imx_nwl_dsi_mode_fixup(dsi, adjusted); return imx_nwl_dsi_mode_fixup(dsi, adjusted);
} }
static void imx_nwl_dsi_bridge_mode_set(struct drm_bridge *bridge,
struct drm_display_mode *mode,
struct drm_display_mode *adjusted)
{
struct imx_mipi_dsi *dsi = bridge->driver_private;
imx_nwl_dsi_mode_set(dsi, adjusted);
}
static int imx_nwl_dsi_bridge_attach(struct drm_bridge *bridge) static int imx_nwl_dsi_bridge_attach(struct drm_bridge *bridge)
{ {
struct imx_mipi_dsi *dsi = bridge->driver_private; struct imx_mipi_dsi *dsi = bridge->driver_private;
...@@ -663,6 +680,7 @@ static const struct drm_bridge_funcs imx_nwl_dsi_bridge_funcs = { ...@@ -663,6 +680,7 @@ static const struct drm_bridge_funcs imx_nwl_dsi_bridge_funcs = {
.enable = imx_nwl_dsi_bridge_enable, .enable = imx_nwl_dsi_bridge_enable,
.disable = imx_nwl_dsi_bridge_disable, .disable = imx_nwl_dsi_bridge_disable,
.mode_fixup = imx_nwl_dsi_bridge_mode_fixup, .mode_fixup = imx_nwl_dsi_bridge_mode_fixup,
.mode_set = imx_nwl_dsi_bridge_mode_set,
.attach = imx_nwl_dsi_bridge_attach, .attach = imx_nwl_dsi_bridge_attach,
.detach = imx_nwl_dsi_bridge_detach, .detach = imx_nwl_dsi_bridge_detach,
}; };
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment