diff options
author | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2015-10-16 14:08:32 +0100 |
---|---|---|
committer | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2015-10-16 14:08:32 +0100 |
commit | 2258c04feae5511138eebb5f837e582718bdb678 (patch) | |
tree | ee6b9d0f68168bc61faeb3b05cdbed6027cebb88 | |
parent | 9fb714f2dce7dd9e65332bc36fa4582eda02b0b4 (diff) | |
parent | 8d58a07475c27891142581147496e961cf21e39b (diff) |
Merge branch 'tracking-qcomlt-panelpicker' into integration-linux-qcomlt
* tracking-qcomlt-panelpicker:
drm/msm: mdp4 lvds: Check the panel node in detect_panel()
drm/msm: mdp4 lvds: continue if the panel is not connected
drm/panel: simple-panel: Add panel picker support.
drm/edid: export edid_vendor()
drm/edid: Add support to get edid early
-rw-r--r-- | drivers/gpu/drm/drm_edid.c | 12 | ||||
-rw-r--r-- | drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c | 77 | ||||
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 83 | ||||
-rw-r--r-- | include/drm/drm_crtc.h | 2 |
4 files changed, 139 insertions, 35 deletions
diff --git a/drivers/gpu/drm/drm_edid.c b/drivers/gpu/drm/drm_edid.c index 05bb7311ac5d..f32e090b3d85 100644 --- a/drivers/gpu/drm/drm_edid.c +++ b/drivers/gpu/drm/drm_edid.c @@ -1388,6 +1388,14 @@ struct edid *drm_get_edid(struct drm_connector *connector, } EXPORT_SYMBOL(drm_get_edid); +struct edid *drm_get_edid_early(struct i2c_adapter *adapter) +{ + struct drm_connector dummy_connector; + + return drm_get_edid(&dummy_connector, adapter); +} +EXPORT_SYMBOL(drm_get_edid_early); + /** * drm_edid_duplicate - duplicate an EDID and the extensions * @edid: EDID to duplicate @@ -1409,7 +1417,7 @@ EXPORT_SYMBOL(drm_edid_duplicate); * * Returns true if @vendor is in @edid, false otherwise */ -static bool edid_vendor(struct edid *edid, char *vendor) +bool edid_vendor(struct edid *edid, char *vendor) { char edid_vendor[3]; @@ -1420,7 +1428,7 @@ static bool edid_vendor(struct edid *edid, char *vendor) return !strncmp(edid_vendor, vendor, 3); } - +EXPORT_SYMBOL(edid_vendor); /** * edid_get_quirks - return quirk flags for a given EDID * @edid: EDID to process diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c index 077f7521a971..65571bd9c574 100644 --- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c +++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c @@ -262,6 +262,11 @@ static struct drm_panel *detect_panel(struct drm_device *dev) of_node_put(endpoint); + if (!of_device_is_available(panel_node)) { + dev_err(dev->dev, "panel is not enabled in DT\n"); + return ERR_PTR(-ENODEV); + } + panel = of_drm_find_panel(panel_node); if (!panel) { of_node_put(panel_node); @@ -313,45 +318,55 @@ static int modeset_init(struct mdp4_kms *mdp4_kms) if (IS_ERR(panel)) { ret = PTR_ERR(panel); dev_err(dev->dev, "failed to detect LVDS panel: %d\n", ret); - goto fail; - } + /** + * Only fail if there is panel but not ready yet + * continue with other stuff if there is no panel connected. + */ + if (ret == -EPROBE_DEFER) + goto fail; + } else { + plane = mdp4_plane_init(dev, RGB2, true); + if (IS_ERR(plane)) { + dev_err(dev->dev, + "failed to construct plane for RGB2\n"); + ret = PTR_ERR(plane); + goto fail; + } - plane = mdp4_plane_init(dev, RGB2, true); - if (IS_ERR(plane)) { - dev_err(dev->dev, "failed to construct plane for RGB2\n"); - ret = PTR_ERR(plane); - goto fail; - } + crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, 0, DMA_P); + if (IS_ERR(crtc)) { + dev_err(dev->dev, + "failed to construct crtc for DMA_P\n"); + ret = PTR_ERR(crtc); + goto fail; + } - crtc = mdp4_crtc_init(dev, plane, priv->num_crtcs, 0, DMA_P); - if (IS_ERR(crtc)) { - dev_err(dev->dev, "failed to construct crtc for DMA_P\n"); - ret = PTR_ERR(crtc); - goto fail; - } + encoder = mdp4_lcdc_encoder_init(dev, panel); + if (IS_ERR(encoder)) { + dev_err(dev->dev, + "failed to construct LCDC encoder\n"); + ret = PTR_ERR(encoder); + goto fail; + } - encoder = mdp4_lcdc_encoder_init(dev, panel); - if (IS_ERR(encoder)) { - dev_err(dev->dev, "failed to construct LCDC encoder\n"); - ret = PTR_ERR(encoder); - goto fail; - } + /* LCDC can be hooked to DMA_P: */ + encoder->possible_crtcs = 1 << priv->num_crtcs; - /* LCDC can be hooked to DMA_P: */ - encoder->possible_crtcs = 1 << priv->num_crtcs; + priv->crtcs[priv->num_crtcs++] = crtc; + priv->encoders[priv->num_encoders++] = encoder; - priv->crtcs[priv->num_crtcs++] = crtc; - priv->encoders[priv->num_encoders++] = encoder; + connector = mdp4_lvds_connector_init(dev, panel, encoder); + if (IS_ERR(connector)) { + ret = PTR_ERR(connector); + dev_err(dev->dev, + "failed to initialize LVDS connector: %d\n", + ret); + goto fail; + } - connector = mdp4_lvds_connector_init(dev, panel, encoder); - if (IS_ERR(connector)) { - ret = PTR_ERR(connector); - dev_err(dev->dev, "failed to initialize LVDS connector: %d\n", ret); - goto fail; + priv->connectors[priv->num_connectors++] = connector; } - priv->connectors[priv->num_connectors++] = connector; - /* * Setup DTV/HDMI path: RGB1 -> DMA_E -> DTV -> HDMI: */ diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index f97b73ec4713..34d73a32e78a 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -32,6 +32,7 @@ #include <drm/drm_crtc.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> +#include <drm/drm_edid.h> #include <video/display_timing.h> #include <video/videomode.h> @@ -70,6 +71,18 @@ struct panel_desc { u32 bus_format; }; +#define PANEL_PICKER_ENTRY(vend, pid, pdesc) \ + .vendor = vend, \ + .product_id = (pid), \ + .data = (pdesc) + +/* Panel picker entry with vendor and product id */ +struct panel_picker_entry { + char vendor[4]; /* Vendor string */ + int product_id; /* product id field */ + const struct panel_desc *data; +}; + struct panel_simple { struct drm_panel base; bool prepared; @@ -84,6 +97,8 @@ struct panel_simple { struct gpio_desc *enable_gpio; }; +static const struct panel_desc *panel_picker_find_panel(struct edid *edid); + static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) { return container_of(panel, struct panel_simple, base); @@ -276,11 +291,28 @@ static const struct drm_panel_funcs panel_simple_funcs = { .get_timings = panel_simple_get_timings, }; +static void __init simple_panel_node_disable(struct device_node *node) +{ + struct property *prop; + + prop = kzalloc(sizeof(*prop), GFP_KERNEL); + if (!prop) + return; + + prop->name = "status"; + prop->value = "disabled"; + prop->length = strlen((char *)prop->value)+1; + + of_update_property(node, prop); +} + + static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) { struct device_node *backlight, *ddc; struct panel_simple *panel; int err; + struct edid *edid; panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL); if (!panel) @@ -288,7 +320,6 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel->enabled = false; panel->prepared = false; - panel->desc = desc; panel->supply = devm_regulator_get(dev, "power"); if (IS_ERR(panel->supply)) @@ -316,7 +347,25 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) panel->ddc = of_find_i2c_adapter_by_node(ddc); of_node_put(ddc); - if (!panel->ddc) { + if (panel->ddc) { + /* detect panel presence */ + if (!drm_probe_ddc(panel->ddc)) { + err = -ENODEV; + goto nodev; + } + + /* get panel from edid */ + if (of_device_is_compatible(dev->of_node, + "panel-simple")) { + edid = drm_get_edid_early(panel->ddc); + if (edid) { + desc = panel_picker_find_panel(edid); + } else { + err = -ENODEV; + goto nodev; + } + } + } else { err = -EPROBE_DEFER; goto free_backlight; } @@ -325,6 +374,7 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) drm_panel_init(&panel->base); panel->base.dev = dev; panel->base.funcs = &panel_simple_funcs; + panel->desc = desc; err = drm_panel_add(&panel->base); if (err < 0) @@ -334,6 +384,10 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) return 0; +nodev: + /* mark the dt as disabled */ + simple_panel_node_disable(dev->of_node); + free_ddc: if (panel->ddc) put_device(&panel->ddc->dev); @@ -1096,6 +1150,10 @@ static const struct panel_desc shelly_sca07010_bfn_lnn = { .bus_format = MEDIA_BUS_FMT_RGB666_1X18, }; +static const struct panel_picker_entry panel_picker_list[] = { + { PANEL_PICKER_ENTRY("AUO", 0x10dc, &auo_b101xtn01) }, +}; + static const struct of_device_id platform_of_match[] = { { .compatible = "ampire,am800480r3tmqwa1h", @@ -1191,11 +1249,32 @@ static const struct of_device_id platform_of_match[] = { .compatible = "shelly,sca07010-bfn-lnn", .data = &shelly_sca07010_bfn_lnn, }, { + /* Panel Picker Vendor ID and Product ID based Lookup */ + .compatible = "panel-simple", + }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, platform_of_match); +static const struct panel_desc *panel_picker_find_panel(struct edid *edid) +{ + int i; + const struct panel_desc *desc = NULL; + + for (i = 0; i < ARRAY_SIZE(panel_picker_list); i++) { + const struct panel_picker_entry *vp = &panel_picker_list[i]; + + if (edid_vendor(edid, (char *)vp->vendor) && + (EDID_PRODUCT_ID(edid) == vp->product_id)) { + desc = vp->data; + break; + } + } + + return desc; +} + static int panel_simple_platform_probe(struct platform_device *pdev) { const struct of_device_id *id; diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h index faaeff7db684..f07ee6b6cb47 100644 --- a/include/drm/drm_crtc.h +++ b/include/drm/drm_crtc.h @@ -1304,7 +1304,9 @@ extern void drm_property_destroy_user_blobs(struct drm_device *dev, extern bool drm_probe_ddc(struct i2c_adapter *adapter); extern struct edid *drm_get_edid(struct drm_connector *connector, struct i2c_adapter *adapter); +extern struct edid *drm_get_edid_early(struct i2c_adapter *adapter); extern struct edid *drm_edid_duplicate(const struct edid *edid); +extern bool edid_vendor(struct edid *edid, char *vendor); extern int drm_add_edid_modes(struct drm_connector *connector, struct edid *edid); extern void drm_mode_config_init(struct drm_device *dev); extern void drm_mode_config_reset(struct drm_device *dev); |