diff options
Diffstat (limited to 'drivers/gpu/drm/panel/panel-simple.c')
-rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 83 |
1 files changed, 81 insertions, 2 deletions
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; |