Commit a6bf7f63 authored by Archit Taneja's avatar Archit Taneja Committed by Rob Clark

drm/msm/mdp4: Initialize LCDC encoder even if panel driver isn't available

Currently, the driver defers if it doesn't find a drm_panel. This forces
us to have a drm_panel, if not, the driver isn't usable.

Make the lcdc encoder initialization independent of the availability of
the drm panel. We only check if there is a panel node specified in DT. If
it isn't, then we don't initialize the encoder at all. The panel node is
passed to the lcdc encoder and lvds connector drivers.

The connector driver takes the responsibility to retrieve the drm_panel
from the panel node, and update the status on whether the panel is
connected or not. This makes the panel usable even if the drm_panel
driver is inserted as a module later on.
Signed-off-by: default avatarArchit Taneja <architt@codeaurora.org>
Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent ec141af6
......@@ -240,18 +240,18 @@ int mdp4_enable(struct mdp4_kms *mdp4_kms)
return 0;
}
static struct drm_panel *detect_panel(struct drm_device *dev)
static struct device_node *mdp4_detect_lcdc_panel(struct drm_device *dev)
{
struct device_node *endpoint, *panel_node;
struct device_node *np = dev->dev->of_node;
struct drm_panel *panel = NULL;
endpoint = of_graph_get_next_endpoint(np, NULL);
if (!endpoint) {
dev_err(dev->dev, "no valid endpoint\n");
return ERR_PTR(-ENODEV);
DBG("no endpoint in MDP4 to fetch LVDS panel\n");
return NULL;
}
/* don't proceed if we have an endpoint but no panel_node tied to it */
panel_node = of_graph_get_remote_port_parent(endpoint);
if (!panel_node) {
dev_err(dev->dev, "no valid panel node\n");
......@@ -261,13 +261,7 @@ static struct drm_panel *detect_panel(struct drm_device *dev)
of_node_put(endpoint);
panel = of_drm_find_panel(panel_node);
if (!panel) {
of_node_put(panel_node);
return ERR_PTR(-EPROBE_DEFER);
}
return panel;
return panel_node;
}
static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
......@@ -277,18 +271,22 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
struct msm_drm_private *priv = dev->dev_private;
struct drm_encoder *encoder;
struct drm_connector *connector;
struct drm_panel *panel;
struct device_node *panel_node;
int ret;
switch (intf_type) {
case DRM_MODE_ENCODER_LVDS:
panel = detect_panel(dev);
if (IS_ERR(panel)) {
dev_err(dev->dev, "failed to detect LVDS panel\n");
return PTR_ERR(panel);
}
encoder = mdp4_lcdc_encoder_init(dev, panel);
/*
* bail out early if:
* - there is no panel node (no need to initialize lcdc
* encoder and lvds connector), or
* - panel node is a bad pointer
*/
panel_node = mdp4_detect_lcdc_panel(dev);
if (IS_ERR_OR_NULL(panel_node))
return PTR_ERR(panel_node);
encoder = mdp4_lcdc_encoder_init(dev, panel_node);
if (IS_ERR(encoder)) {
dev_err(dev->dev, "failed to construct LCDC encoder\n");
return PTR_ERR(encoder);
......@@ -297,7 +295,7 @@ static int mdp4_modeset_init_intf(struct mdp4_kms *mdp4_kms,
/* LCDC can be hooked to DMA_P (TODO: Add DMA_S later?) */
encoder->possible_crtcs = 1 << DMA_P;
connector = mdp4_lvds_connector_init(dev, panel, encoder);
connector = mdp4_lvds_connector_init(dev, panel_node, encoder);
if (IS_ERR(connector)) {
dev_err(dev->dev, "failed to initialize LVDS connector\n");
return PTR_ERR(connector);
......
......@@ -212,10 +212,10 @@ struct drm_encoder *mdp4_dtv_encoder_init(struct drm_device *dev);
long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate);
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
struct drm_panel *panel);
struct device_node *panel_node);
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
struct drm_panel *panel, struct drm_encoder *encoder);
struct device_node *panel_node, struct drm_encoder *encoder);
#ifdef CONFIG_COMMON_CLK
struct clk *mpd4_lvds_pll_init(struct drm_device *dev);
......
......@@ -23,6 +23,7 @@
struct mdp4_lcdc_encoder {
struct drm_encoder base;
struct device_node *panel_node;
struct drm_panel *panel;
struct clk *lcdc_clk;
unsigned long int pixclock;
......@@ -338,7 +339,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
to_mdp4_lcdc_encoder(encoder);
struct mdp4_kms *mdp4_kms = get_kms(encoder);
struct drm_panel *panel = mdp4_lcdc_encoder->panel;
struct drm_panel *panel;
int i, ret;
if (WARN_ON(!mdp4_lcdc_encoder->enabled))
......@@ -346,6 +347,7 @@ static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
if (panel) {
drm_panel_disable(panel);
drm_panel_unprepare(panel);
......@@ -381,7 +383,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
to_mdp4_lcdc_encoder(encoder);
unsigned long pc = mdp4_lcdc_encoder->pixclock;
struct mdp4_kms *mdp4_kms = get_kms(encoder);
struct drm_panel *panel = mdp4_lcdc_encoder->panel;
struct drm_panel *panel;
int i, ret;
if (WARN_ON(mdp4_lcdc_encoder->enabled))
......@@ -414,6 +416,7 @@ static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
if (ret)
dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
panel = of_drm_find_panel(mdp4_lcdc_encoder->panel_node);
if (panel) {
drm_panel_prepare(panel);
drm_panel_enable(panel);
......@@ -442,7 +445,7 @@ long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
/* initialize encoder */
struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
struct drm_panel *panel)
struct device_node *panel_node)
{
struct drm_encoder *encoder = NULL;
struct mdp4_lcdc_encoder *mdp4_lcdc_encoder;
......@@ -455,7 +458,7 @@ struct drm_encoder *mdp4_lcdc_encoder_init(struct drm_device *dev,
goto fail;
}
mdp4_lcdc_encoder->panel = panel;
mdp4_lcdc_encoder->panel_node = panel_node;
encoder = &mdp4_lcdc_encoder->base;
......
......@@ -23,6 +23,7 @@
struct mdp4_lvds_connector {
struct drm_connector base;
struct drm_encoder *encoder;
struct device_node *panel_node;
struct drm_panel *panel;
};
#define to_mdp4_lvds_connector(x) container_of(x, struct mdp4_lvds_connector, base)
......@@ -33,6 +34,10 @@ static enum drm_connector_status mdp4_lvds_connector_detect(
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
if (!mdp4_lvds_connector->panel)
mdp4_lvds_connector->panel =
of_drm_find_panel(mdp4_lvds_connector->panel_node);
return mdp4_lvds_connector->panel ?
connector_status_connected :
connector_status_disconnected;
......@@ -42,10 +47,6 @@ static void mdp4_lvds_connector_destroy(struct drm_connector *connector)
{
struct mdp4_lvds_connector *mdp4_lvds_connector =
to_mdp4_lvds_connector(connector);
struct drm_panel *panel = mdp4_lvds_connector->panel;
if (panel)
drm_panel_detach(panel);
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
......@@ -60,9 +61,14 @@ static int mdp4_lvds_connector_get_modes(struct drm_connector *connector)
struct drm_panel *panel = mdp4_lvds_connector->panel;
int ret = 0;
if (panel)
if (panel) {
drm_panel_attach(panel, connector);
ret = panel->funcs->get_modes(panel);
drm_panel_detach(panel);
}
return ret;
}
......@@ -111,7 +117,7 @@ static const struct drm_connector_helper_funcs mdp4_lvds_connector_helper_funcs
/* initialize connector */
struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
struct drm_panel *panel, struct drm_encoder *encoder)
struct device_node *panel_node, struct drm_encoder *encoder)
{
struct drm_connector *connector = NULL;
struct mdp4_lvds_connector *mdp4_lvds_connector;
......@@ -124,7 +130,7 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
}
mdp4_lvds_connector->encoder = encoder;
mdp4_lvds_connector->panel = panel;
mdp4_lvds_connector->panel_node = panel_node;
connector = &mdp4_lvds_connector->base;
......@@ -141,9 +147,6 @@ struct drm_connector *mdp4_lvds_connector_init(struct drm_device *dev,
drm_mode_connector_attach_encoder(connector, encoder);
if (panel)
drm_panel_attach(panel, connector);
return connector;
fail:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment