From: Sam Ravnborg sam@ravnborg.org
[ Upstream commit 60e5e48dba72c6b59a7a9c7686ba320766913368 ]
When a device tree set a display-timing using native-mode then according to the bindings doc this should:
native-mode: The native mode for the display, in case multiple modes are provided. When omitted, assume the first node is the native.
The atmel_lcdfb used the last timing subnode and did not respect the timing mode specified with native-mode.
Introduce use of of_get_videomode() which allowed a nice simplification of the code while also added support for native-mode.
As a nice side-effect this fixes a memory leak where the data used for timings and the display_np was not freed.
Signed-off-by: Sam Ravnborg sam@ravnborg.org Cc: Nicolas Ferre nicolas.ferre@microchip.com Cc: Alexandre Belloni alexandre.belloni@bootlin.com Signed-off-by: Bartlomiej Zolnierkiewicz b.zolnierkie@samsung.com Signed-off-by: Sasha Levin sashal@kernel.org --- drivers/video/fbdev/atmel_lcdfb.c | 43 +++++++------------------------ 1 file changed, 9 insertions(+), 34 deletions(-)
diff --git a/drivers/video/fbdev/atmel_lcdfb.c b/drivers/video/fbdev/atmel_lcdfb.c index 076d24afbd728..4ed55e6bbb840 100644 --- a/drivers/video/fbdev/atmel_lcdfb.c +++ b/drivers/video/fbdev/atmel_lcdfb.c @@ -22,6 +22,7 @@ #include <linux/module.h> #include <linux/of.h> #include <linux/of_device.h> +#include <video/of_videomode.h> #include <video/of_display_timing.h> #include <linux/regulator/consumer.h> #include <video/videomode.h> @@ -1028,11 +1029,11 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) struct device *dev = &sinfo->pdev->dev; struct device_node *np =dev->of_node; struct device_node *display_np; - struct device_node *timings_np; - struct display_timings *timings; struct atmel_lcdfb_power_ctrl_gpio *og; bool is_gpio_power = false; + struct fb_videomode fb_vm; struct gpio_desc *gpiod; + struct videomode vm; int ret = -ENOENT; int i;
@@ -1105,44 +1106,18 @@ static int atmel_lcdfb_of_init(struct atmel_lcdfb_info *sinfo) pdata->lcdcon_is_backlight = of_property_read_bool(display_np, "atmel,lcdcon-backlight"); pdata->lcdcon_pol_negative = of_property_read_bool(display_np, "atmel,lcdcon-backlight-inverted");
- timings = of_get_display_timings(display_np); - if (!timings) { - dev_err(dev, "failed to get display timings\n"); - ret = -EINVAL; + ret = of_get_videomode(display_np, &vm, OF_USE_NATIVE_MODE); + if (ret) { + dev_err(dev, "failed to get videomode from DT\n"); goto put_display_node; }
- timings_np = of_get_child_by_name(display_np, "display-timings"); - if (!timings_np) { - dev_err(dev, "failed to find display-timings node\n"); - ret = -ENODEV; + ret = fb_videomode_from_videomode(&vm, &fb_vm); + if (ret < 0) goto put_display_node; - }
- for (i = 0; i < of_get_child_count(timings_np); i++) { - struct videomode vm; - struct fb_videomode fb_vm; - - ret = videomode_from_timings(timings, &vm, i); - if (ret < 0) - goto put_timings_node; - ret = fb_videomode_from_videomode(&vm, &fb_vm); - if (ret < 0) - goto put_timings_node; - - fb_add_videomode(&fb_vm, &info->modelist); - } - - /* - * FIXME: Make sure we are not referencing any fields in display_np - * and timings_np and drop our references to them before returning to - * avoid leaking the nodes on probe deferral and driver unbind. - */ - - return 0; + fb_add_videomode(&fb_vm, &info->modelist);
-put_timings_node: - of_node_put(timings_np); put_display_node: of_node_put(display_np); return ret;