/* * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include <linux/delay.h>#include <linux/gpio/consumer.h>#include <linux/i2c.h>#include <linux/media-bus-format.h>#include <linux/module.h>#include <linux/of_device.h>#include <linux/of_platform.h>#include <linux/platform_device.h>#include <linux/pm_runtime.h>#include <linux/regulator/consumer.h> #include <video/display_timing.h>#include <video/of_display_timing.h>#include <video/videomode.h> #include <drm/drm_crtc.h>#include <drm/drm_device.h>#include <drm/drm_edid.h>#include <drm/drm_mipi_dsi.h>#include <drm/drm_panel.h>#include <drm/drm_of.h> /** * struct panel_desc - Describes a simple panel. */struct panel_desc { /** * @modes: Pointer to array of fixed modes appropriate for this panel. * * If only one mode then this can just be the address of the mode. * NOTE: cannot be used with "timings" and also if this is specified * then you cannot override the mode in the device tree. */ const struct drm_display_mode *modes; /** @num_modes: Number of elements in modes array. */ unsigned int num_modes; /** * @timings: Pointer to array of display timings * * NOTE: cannot be used with "modes" and also these will be used to * validate a device tree override if one is present. */ const struct display_timing *timings; /** @num_timings: Number of elements in timings array. */ unsigned int num_timings; /** @bpc: Bits per color. */ unsigned int bpc; /** @size: Structure containing the physical size of this panel. */ struct { /** * @size.width: Width (in mm) of the active display area. */ unsigned int width; /** * @size.height: Height (in mm) of the active display area. */ unsigned int height; } size; /** @delay: Structure containing various delay values for this panel. */ struct { /** * @delay.prepare: Time for the panel to become ready. * * The time (in milliseconds) that it takes for the panel to * become ready and start receiving video data */ unsigned int prepare; /** * @delay.enable: Time for the panel to display a valid frame. * * The time (in milliseconds) that it takes for the panel to * display the first valid frame after starting to receive * video data. */ unsigned int enable; /** * @delay.disable: Time for the panel to turn the display off. * * The time (in milliseconds) that it takes for the panel to * turn the display off (no content is visible). */ unsigned int disable; /** * @delay.unprepare: Time to power down completely. * * The time (in milliseconds) that it takes for the panel * to power itself down completely. * * This time is used to prevent a future "prepare" from * starting until at least this many milliseconds has passed. * If at prepare time less time has passed since unprepare * finished, the driver waits for the remaining time. */ unsigned int unprepare; } delay; /** @bus_format: See MEDIA_BUS_FMT_... defines. */ u32 bus_format; /** @bus_flags: See DRM_BUS_FLAG_... defines. */ u32 bus_flags; /** @connector_type: LVDS, eDP, DSI, DPI, etc. */ int connector_type;}; struct panel_desc_dsi { struct panel_desc desc; unsigned long flags; enum mipi_dsi_pixel_format format; unsigned int lanes;}; struct panel_simple { struct drm_panel base; ktime_t unprepared_time; const struct panel_desc *desc; struct regulator *supply; struct i2c_adapter *ddc; struct gpio_desc *enable_gpio; const struct drm_edid *drm_edid; struct drm_display_mode override_mode; enum drm_panel_orientation orientation;}; static inline struct panel_simple *to_panel_simple(struct drm_panel *panel){ return container_of(panel, struct panel_simple, base);} static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel, struct drm_connector *connector){ struct drm_display_mode *mode; unsigned int i, num = 0; for (i = 0; i < panel->desc->num_timings; i++) { const struct display_timing *dt = &panel->desc->timings[i]; struct videomode vm; videomode_from_timing(dt, &vm); mode = drm_mode_create(connector->dev); if (!mode) { dev_err(panel->base.dev, "failed to add mode %ux%u\n", dt->hactive.typ, dt->vactive.typ); continue; } drm_display_mode_from_videomode(&vm, mode); mode->type |= DRM_MODE_TYPE_DRIVER; if (panel->desc->num_timings == 1) mode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); num++; } return num;} static unsigned int panel_simple_get_display_modes(struct panel_simple *panel, struct drm_connector *connector){ struct drm_display_mode *mode; unsigned int i, num = 0; for (i = 0; i < panel->desc->num_modes; i++) { const struct drm_display_mode *m = &panel->desc->modes[i]; mode = drm_mode_duplicate(connector->dev, m); if (!mode) { dev_err(panel->base.dev, "failed to add mode %ux%u@%u\n", m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); continue; } mode->type |= DRM_MODE_TYPE_DRIVER; if (panel->desc->num_modes == 1) mode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_set_name(mode); drm_mode_probed_add(connector, mode); num++; } return num;} static int panel_simple_get_non_edid_modes(struct panel_simple *panel, struct drm_connector *connector){ struct drm_display_mode *mode; bool has_override = panel->override_mode.type; unsigned int num = 0; if (!panel->desc) return 0; if (has_override) { mode = drm_mode_duplicate(connector->dev, &panel->override_mode); if (mode) { drm_mode_probed_add(connector, mode); num = 1; } else { dev_err(panel->base.dev, "failed to add override mode\n"); } } /* Only add timings if override was not there or failed to validate */ if (num == 0 && panel->desc->num_timings) num = panel_simple_get_timings_modes(panel, connector); /* * Only add fixed modes if timings/override added no mode. * * We should only ever have either the display timings specified * or a fixed mode. Anything else is rather bogus. */ WARN_ON(panel->desc->num_timings && panel->desc->num_modes); if (num == 0) num = panel_simple_get_display_modes(panel, connector); connector->display_info.bpc = panel->desc->bpc; connector->display_info.width_mm = panel->desc->size.width; connector->display_info.height_mm = panel->desc->size.height; if (panel->desc->bus_format) drm_display_info_set_bus_formats(&connector->display_info, &panel->desc->bus_format, 1); connector->display_info.bus_flags = panel->desc->bus_flags; return num;} static void panel_simple_wait(ktime_t start_ktime, unsigned int min_ms){ ktime_t now_ktime, min_ktime; if (!min_ms) return; min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms)); now_ktime = ktime_get_boottime(); if (ktime_before(now_ktime, min_ktime)) msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1);} static int panel_simple_disable(struct drm_panel *panel){ struct panel_simple *p = to_panel_simple(panel); if (p->desc->delay.disable) msleep(p->desc->delay.disable); return 0;} static int panel_simple_suspend(struct device *dev){ struct panel_simple *p = dev_get_drvdata(dev); gpiod_set_value_cansleep(p->enable_gpio, 0); regulator_disable(p->supply); p->unprepared_time = ktime_get_boottime(); drm_edid_free(p->drm_edid); p->drm_edid = NULL; return 0;} static int panel_simple_unprepare(struct drm_panel *panel){ int ret; pm_runtime_mark_last_busy(panel->dev); ret = pm_runtime_put_autosuspend(panel->dev); if (ret < 0) return ret; return 0;} static int panel_simple_resume(struct device *dev){ struct panel_simple *p = dev_get_drvdata(dev); int err; panel_simple_wait(p->unprepared_time, p->desc->delay.unprepare); err = regulator_enable(p->supply); if (err < 0) { dev_err(dev, "failed to enable supply: %d\n", err); return err; } gpiod_set_value_cansleep(p->enable_gpio, 1); if (p->desc->delay.prepare) msleep(p->desc->delay.prepare); return 0;} static int panel_simple_prepare(struct drm_panel *panel){ int ret; ret = pm_runtime_get_sync(panel->dev); if (ret < 0) { pm_runtime_put_autosuspend(panel->dev); return ret; } return 0;} static int panel_simple_enable(struct drm_panel *panel){ struct panel_simple *p = to_panel_simple(panel); if (p->desc->delay.enable) msleep(p->desc->delay.enable); return 0;} static int panel_simple_get_modes(struct drm_panel *panel, struct drm_connector *connector){ struct panel_simple *p = to_panel_simple(panel); int num = 0; /* probe EDID if a DDC bus is available */ if (p->ddc) { pm_runtime_get_sync(panel->dev); if (!p->drm_edid) p->drm_edid = drm_edid_read_ddc(connector, p->ddc); drm_edid_connector_update(connector, p->drm_edid); num += drm_edid_connector_add_modes(connector); pm_runtime_mark_last_busy(panel->dev); pm_runtime_put_autosuspend(panel->dev); } /* add hard-coded panel modes */ num += panel_simple_get_non_edid_modes(p, connector); /* * TODO: Remove once all drm drivers call * drm_connector_set_orientation_from_panel() */ drm_connector_set_panel_orientation(connector, p->orientation); return num;} static int panel_simple_get_timings(struct drm_panel *panel, unsigned int num_timings, struct display_timing *timings){ struct panel_simple *p = to_panel_simple(panel); unsigned int i; if (p->desc->num_timings < num_timings) num_timings = p->desc->num_timings; if (timings) for (i = 0; i < num_timings; i++) timings[i] = p->desc->timings[i]; return p->desc->num_timings;} static enum drm_panel_orientation panel_simple_get_orientation(struct drm_panel *panel){ struct panel_simple *p = to_panel_simple(panel); return p->orientation;} static const struct drm_panel_funcs panel_simple_funcs = { .disable = panel_simple_disable, .unprepare = panel_simple_unprepare, .prepare = panel_simple_prepare, .enable = panel_simple_enable, .get_modes = panel_simple_get_modes, .get_orientation = panel_simple_get_orientation, .get_timings = panel_simple_get_timings,}; static struct panel_desc *panel_dpi_probe(struct device *dev){ struct display_timing *timing; const struct device_node *np; struct panel_desc *desc; unsigned int bus_flags; struct videomode vm; int ret; np = dev->of_node; desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); if (!desc) return ERR_PTR(-ENOMEM); timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); if (!timing) return ERR_PTR(-ENOMEM); ret = of_get_display_timing(np, "panel-timing", timing); if (ret < 0) { dev_err(dev, "%pOF: no panel-timing node found for \"panel-dpi\" binding\n", np); return ERR_PTR(ret); } desc->timings = timing; desc->num_timings = 1; of_property_read_u32(np, "width-mm", &desc->size.width); of_property_read_u32(np, "height-mm", &desc->size.height); /* Extract bus_flags from display_timing */ bus_flags = 0; vm.flags = timing->flags; drm_bus_flags_from_videomode(&vm, &bus_flags); desc->bus_flags = bus_flags; /* We do not know the connector for the DT node, so guess it */ desc->connector_type = DRM_MODE_CONNECTOR_DPI; return desc;} #define PANEL_SIMPLE_BOUNDS_CHECK(to_check, bounds, field) \ (to_check->field.typ >= bounds->field.min && \ to_check->field.typ <= bounds->field.max)static void panel_simple_parse_panel_timing_node(struct device *dev, struct panel_simple *panel, const struct display_timing *ot){ const struct panel_desc *desc = panel->desc; struct videomode vm; unsigned int i; if (WARN_ON(desc->num_modes)) { dev_err(dev, "Reject override mode: panel has a fixed mode\n"); return; } if (WARN_ON(!desc->num_timings)) {Lines 1–500 of 6625. Load more
/* * Copyright (C) 2013, NVIDIA Corporation. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sub license, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the * next paragraph) shall be included in all copies or substantial portions * of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include <linux/delay.h> #include <linux/gpio/consumer.h> #include <linux/i2c.h> #include <linux/media-bus-format.h> #include <linux/module.h> #include <linux/of_device.h> #include <linux/of_platform.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> #include <linux/regulator/consumer.h> #include <video/display_timing.h> #include <video/of_display_timing.h> #include <video/videomode.h> #include <drm/drm_crtc.h> #include <drm/drm_device.h> #include <drm/drm_edid.h> #include <drm/drm_mipi_dsi.h> #include <drm/drm_panel.h> #include <drm/drm_of.h> /** * struct panel_desc - Describes a simple panel. */ struct panel_desc { /** * @modes: Pointer to array of fixed modes appropriate for this panel. * * If only one mode then this can just be the address of the mode. * NOTE: cannot be used with "timings" and also if this is specified * then you cannot override the mode in the device tree. */ const struct drm_display_mode *modes; /** @num_modes: Number of elements in modes array. */ unsigned int num_modes; /** * @timings: Pointer to array of display timings * * NOTE: cannot be used with "modes" and also these will be used to * validate a device tree override if one is present. */ const struct display_timing *timings; /** @num_timings: Number of elements in timings array. */ unsigned int num_timings; /** @bpc: Bits per color. */ unsigned int bpc; /** @size: Structure containing the physical size of this panel. */ struct { /** * @size.width: Width (in mm) of the active display area. */ unsigned int width; /** * @size.height: Height (in mm) of the active display area. */ unsigned int height; } size; /** @delay: Structure containing various delay values for this panel. */ struct { /** * @delay.prepare: Time for the panel to become ready. * * The time (in milliseconds) that it takes for the panel to * become ready and start receiving video data */ unsigned int prepare; /** * @delay.enable: Time for the panel to display a valid frame. * * The time (in milliseconds) that it takes for the panel to * display the first valid frame after starting to receive * video data. */ unsigned int enable; /** * @delay.disable: Time for the panel to turn the display off. * * The time (in milliseconds) that it takes for the panel to * turn the display off (no content is visible). */ unsigned int disable; /** * @delay.unprepare: Time to power down completely. * * The time (in milliseconds) that it takes for the panel * to power itself down completely. * * This time is used to prevent a future "prepare" from * starting until at least this many milliseconds has passed. * If at prepare time less time has passed since unprepare * finished, the driver waits for the remaining time. */ unsigned int unprepare; } delay; /** @bus_format: See MEDIA_BUS_FMT_... defines. */ u32 bus_format; /** @bus_flags: See DRM_BUS_FLAG_... defines. */ u32 bus_flags; /** @connector_type: LVDS, eDP, DSI, DPI, etc. */ int connector_type; }; struct panel_desc_dsi { struct panel_desc desc; unsigned long flags; enum mipi_dsi_pixel_format format; unsigned int lanes; }; struct panel_simple { struct drm_panel base; ktime_t unprepared_time; const struct panel_desc *desc; struct regulator *supply; struct i2c_adapter *ddc; struct gpio_desc *enable_gpio; const struct drm_edid *drm_edid; struct drm_display_mode override_mode; enum drm_panel_orientation orientation; }; static inline struct panel_simple *to_panel_simple(struct drm_panel *panel) { return container_of(panel, struct panel_simple, base); } static unsigned int panel_simple_get_timings_modes(struct panel_simple *panel, struct drm_connector *connector) { struct drm_display_mode *mode; unsigned int i, num = 0; for (i = 0; i < panel->desc->num_timings; i++) { const struct display_timing *dt = &panel->desc->timings[i]; struct videomode vm; videomode_from_timing(dt, &vm); mode = drm_mode_create(connector->dev); if (!mode) { dev_err(panel->base.dev, "failed to add mode %ux%u\n", dt->hactive.typ, dt->vactive.typ); continue; } drm_display_mode_from_videomode(&vm, mode); mode->type |= DRM_MODE_TYPE_DRIVER; if (panel->desc->num_timings == 1) mode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_probed_add(connector, mode); num++; } return num; } static unsigned int panel_simple_get_display_modes(struct panel_simple *panel, struct drm_connector *connector) { struct drm_display_mode *mode; unsigned int i, num = 0; for (i = 0; i < panel->desc->num_modes; i++) { const struct drm_display_mode *m = &panel->desc->modes[i]; mode = drm_mode_duplicate(connector->dev, m); if (!mode) { dev_err(panel->base.dev, "failed to add mode %ux%u@%u\n", m->hdisplay, m->vdisplay, drm_mode_vrefresh(m)); continue; } mode->type |= DRM_MODE_TYPE_DRIVER; if (panel->desc->num_modes == 1) mode->type |= DRM_MODE_TYPE_PREFERRED; drm_mode_set_name(mode); drm_mode_probed_add(connector, mode); num++; } return num; } static int panel_simple_get_non_edid_modes(struct panel_simple *panel, struct drm_connector *connector) { struct drm_display_mode *mode; bool has_override = panel->override_mode.type; unsigned int num = 0; if (!panel->desc) return 0; if (has_override) { mode = drm_mode_duplicate(connector->dev, &panel->override_mode); if (mode) { drm_mode_probed_add(connector, mode); num = 1; } else { dev_err(panel->base.dev, "failed to add override mode\n"); } } /* Only add timings if override was not there or failed to validate */ if (num == 0 && panel->desc->num_timings) num = panel_simple_get_timings_modes(panel, connector); /* * Only add fixed modes if timings/override added no mode. * * We should only ever have either the display timings specified * or a fixed mode. Anything else is rather bogus. */ WARN_ON(panel->desc->num_timings && panel->desc->num_modes); if (num == 0) num = panel_simple_get_display_modes(panel, connector); connector->display_info.bpc = panel->desc->bpc; connector->display_info.width_mm = panel->desc->size.width; connector->display_info.height_mm = panel->desc->size.height; if (panel->desc->bus_format) drm_display_info_set_bus_formats(&connector->display_info, &panel->desc->bus_format, 1); connector->display_info.bus_flags = panel->desc->bus_flags; return num; } static void panel_simple_wait(ktime_t start_ktime, unsigned int min_ms) { ktime_t now_ktime, min_ktime; if (!min_ms) return; min_ktime = ktime_add(start_ktime, ms_to_ktime(min_ms)); now_ktime = ktime_get_boottime(); if (ktime_before(now_ktime, min_ktime)) msleep(ktime_to_ms(ktime_sub(min_ktime, now_ktime)) + 1); } static int panel_simple_disable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); if (p->desc->delay.disable) msleep(p->desc->delay.disable); return 0; } static int panel_simple_suspend(struct device *dev) { struct panel_simple *p = dev_get_drvdata(dev); gpiod_set_value_cansleep(p->enable_gpio, 0); regulator_disable(p->supply); p->unprepared_time = ktime_get_boottime(); drm_edid_free(p->drm_edid); p->drm_edid = NULL; return 0; } static int panel_simple_unprepare(struct drm_panel *panel) { int ret; pm_runtime_mark_last_busy(panel->dev); ret = pm_runtime_put_autosuspend(panel->dev); if (ret < 0) return ret; return 0; } static int panel_simple_resume(struct device *dev) { struct panel_simple *p = dev_get_drvdata(dev); int err; panel_simple_wait(p->unprepared_time, p->desc->delay.unprepare); err = regulator_enable(p->supply); if (err < 0) { dev_err(dev, "failed to enable supply: %d\n", err); return err; } gpiod_set_value_cansleep(p->enable_gpio, 1); if (p->desc->delay.prepare) msleep(p->desc->delay.prepare); return 0; } static int panel_simple_prepare(struct drm_panel *panel) { int ret; ret = pm_runtime_get_sync(panel->dev); if (ret < 0) { pm_runtime_put_autosuspend(panel->dev); return ret; } return 0; } static int panel_simple_enable(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); if (p->desc->delay.enable) msleep(p->desc->delay.enable); return 0; } static int panel_simple_get_modes(struct drm_panel *panel, struct drm_connector *connector) { struct panel_simple *p = to_panel_simple(panel); int num = 0; /* probe EDID if a DDC bus is available */ if (p->ddc) { pm_runtime_get_sync(panel->dev); if (!p->drm_edid) p->drm_edid = drm_edid_read_ddc(connector, p->ddc); drm_edid_connector_update(connector, p->drm_edid); num += drm_edid_connector_add_modes(connector); pm_runtime_mark_last_busy(panel->dev); pm_runtime_put_autosuspend(panel->dev); } /* add hard-coded panel modes */ num += panel_simple_get_non_edid_modes(p, connector); /* * TODO: Remove once all drm drivers call * drm_connector_set_orientation_from_panel() */ drm_connector_set_panel_orientation(connector, p->orientation); return num; } static int panel_simple_get_timings(struct drm_panel *panel, unsigned int num_timings, struct display_timing *timings) { struct panel_simple *p = to_panel_simple(panel); unsigned int i; if (p->desc->num_timings < num_timings) num_timings = p->desc->num_timings; if (timings) for (i = 0; i < num_timings; i++) timings[i] = p->desc->timings[i]; return p->desc->num_timings; } static enum drm_panel_orientation panel_simple_get_orientation(struct drm_panel *panel) { struct panel_simple *p = to_panel_simple(panel); return p->orientation; } static const struct drm_panel_funcs panel_simple_funcs = { .disable = panel_simple_disable, .unprepare = panel_simple_unprepare, .prepare = panel_simple_prepare, .enable = panel_simple_enable, .get_modes = panel_simple_get_modes, .get_orientation = panel_simple_get_orientation, .get_timings = panel_simple_get_timings, }; static struct panel_desc *panel_dpi_probe(struct device *dev) { struct display_timing *timing; const struct device_node *np; struct panel_desc *desc; unsigned int bus_flags; struct videomode vm; int ret; np = dev->of_node; desc = devm_kzalloc(dev, sizeof(*desc), GFP_KERNEL); if (!desc) return ERR_PTR(-ENOMEM); timing = devm_kzalloc(dev, sizeof(*timing), GFP_KERNEL); if (!timing) return ERR_PTR(-ENOMEM); ret = of_get_display_timing(np, "panel-timing", timing); if (ret < 0) { dev_err(dev, "%pOF: no panel-timing node found for \"panel-dpi\" binding\n", np); return ERR_PTR(ret); } desc->timings = timing; desc->num_timings = 1; of_property_read_u32(np, "width-mm", &desc->size.width); of_property_read_u32(np, "height-mm", &desc->size.height); /* Extract bus_flags from display_timing */ bus_flags = 0; vm.flags = timing->flags; drm_bus_flags_from_videomode(&vm, &bus_flags); desc->bus_flags = bus_flags; /* We do not know the connector for the DT node, so guess it */ desc->connector_type = DRM_MODE_CONNECTOR_DPI; return desc; } #define PANEL_SIMPLE_BOUNDS_CHECK(to_check, bounds, field) \ (to_check->field.typ >= bounds->field.min && \ to_check->field.typ <= bounds->field.max) static void panel_simple_parse_panel_timing_node(struct device *dev, struct panel_simple *panel, const struct display_timing *ot) { const struct panel_desc *desc = panel->desc; struct videomode vm; unsigned int i; if (WARN_ON(desc->num_modes)) { dev_err(dev, "Reject override mode: panel has a fixed mode\n"); return; } if (WARN_ON(!desc->num_timings)) {