6625 lines · 165.0 KB · C
RawDownload
/* * 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t