aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2015-10-16 14:08:32 +0100
committerSrinivas Kandagatla <srinivas.kandagatla@linaro.org>2015-10-16 14:08:32 +0100
commit2258c04feae5511138eebb5f837e582718bdb678 (patch)
treeee6b9d0f68168bc61faeb3b05cdbed6027cebb88
parent9fb714f2dce7dd9e65332bc36fa4582eda02b0b4 (diff)
parent8d58a07475c27891142581147496e961cf21e39b (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.c12
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c77
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c83
-rw-r--r--include/drm/drm_crtc.h2
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);