The kernel has a device tree binding for panel-dpi which allows for the panel timings to be described in the device-tree, however it wasn't supported so far except in a (small) number of KMS drivers that had an ad-hoc solution for this (omapdrm for example).
Just like we've seen with panel-lvds, and even though the current dogma is to set the timings within the driver, having them in the device tree provides a number of benefits. The first is that it allows third party users to enable a random panel without having to modify and recompile their kernel of choice. This might sound like what we're trying to avoid in the first place, but it significantly lowers the barrier of entry, both technical and practical. Indeed, users might not have the knowledge on how to recompile and modify a kernel by their own, or might not have any documentation on the panel itself which would prevent any inclusion. But moderns systems also tend to move to mechanisms like secure boot which would prevent that kernel, provided that the kernel was able to do that, from running in the system, unless you would know how (and be able) to install custom keys into your system. While the DT itself might have the same constraints, mechanisms like the overlays allows to circumvent it. Another thing that panel-dpi allows to address is EMC, where even though the timings described in the driver could be functional on the board and for the panel, it would be better to use another arbitrary frequency on a particular board to increase the spread of the EM emissions. Signed-off-by: Maxime Ripard <[email protected]> --- drivers/gpu/drm/panel/panel-simple.c | 47 +++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 9e8218f6a3f2..9aee02f05a1d 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -34,6 +34,7 @@ #include <drm/drm_panel.h> #include <video/display_timing.h> +#include <video/of_display_timing.h> #include <video/videomode.h> struct panel_desc { @@ -396,6 +397,30 @@ static void panel_simple_shutdown(struct device *dev) panel_simple_unprepare(&panel->base); } +static struct panel_desc *panel_simple_of_parse(struct device *dev) +{ + struct display_timing *timings; + struct panel_desc *desc; + int ret; + + desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); + if (!desc) + return NULL; + + timings = devm_kzalloc(dev, sizeof(*timings), GFP_KERNEL); + if (!timings) + return NULL; + + ret = of_get_display_timing(dev->of_node, "panel-timing", timings); + if (ret) + return NULL; + + desc->timings = timings; + desc->num_timings = 1; + + return desc; +} + static const struct drm_display_mode ampire_am_480272h3tmqw_t01h_mode = { .clock = 9000, .hdisplay = 480, @@ -2808,6 +2833,8 @@ static const struct of_device_id platform_of_match[] = { }, { .compatible = "winstar,wf35ltiacd", .data = &winstar_wf35ltiacd, + }, { + .compatible = "panel-dpi", }, { /* sentinel */ } @@ -2816,13 +2843,23 @@ MODULE_DEVICE_TABLE(of, platform_of_match); static int panel_simple_platform_probe(struct platform_device *pdev) { - const struct of_device_id *id; + const struct panel_desc *desc; - id = of_match_node(platform_of_match, pdev->dev.of_node); - if (!id) - return -ENODEV; + if (of_device_is_compatible(pdev->dev.of_node, "panel-dpi")) { + desc = panel_simple_of_parse(&pdev->dev); + if (!desc) + return -EINVAL; + } else { + const struct of_device_id *id; - return panel_simple_probe(&pdev->dev, id->data); + id = of_match_node(platform_of_match, pdev->dev.of_node); + if (!id) + return -ENODEV; + + desc = id->data; + } + + return panel_simple_probe(&pdev->dev, desc); } static int panel_simple_platform_remove(struct platform_device *pdev) -- 2.20.1 _______________________________________________ dri-devel mailing list [email protected] https://lists.freedesktop.org/mailman/listinfo/dri-devel
