diff options
Diffstat (limited to 'drivers/gpu/drm/panel/panel-simple.c')
| -rw-r--r-- | drivers/gpu/drm/panel/panel-simple.c | 87 | 
1 files changed, 80 insertions, 7 deletions
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c index 4e2dad314c79..be312b5c04dd 100644 --- a/drivers/gpu/drm/panel/panel-simple.c +++ b/drivers/gpu/drm/panel/panel-simple.c @@ -376,12 +376,13 @@ static int panel_simple_get_hpd_gpio(struct device *dev,  	return 0;  } -static int panel_simple_prepare(struct drm_panel *panel) +static int panel_simple_prepare_once(struct drm_panel *panel)  {  	struct panel_simple *p = to_panel_simple(panel);  	unsigned int delay;  	int err;  	int hpd_asserted; +	unsigned long hpd_wait_us;  	if (p->prepared_time != 0)  		return 0; @@ -406,25 +407,63 @@ static int panel_simple_prepare(struct drm_panel *panel)  		if (IS_ERR(p->hpd_gpio)) {  			err = panel_simple_get_hpd_gpio(panel->dev, p, false);  			if (err) -				return err; +				goto error;  		} +		if (p->desc->delay.hpd_absent_delay) +			hpd_wait_us = p->desc->delay.hpd_absent_delay * 1000UL; +		else +			hpd_wait_us = 2000000; +  		err = readx_poll_timeout(gpiod_get_value_cansleep, p->hpd_gpio,  					 hpd_asserted, hpd_asserted, -					 1000, 2000000); +					 1000, hpd_wait_us);  		if (hpd_asserted < 0)  			err = hpd_asserted;  		if (err) { -			dev_err(panel->dev, -				"error waiting for hpd GPIO: %d\n", err); -			return err; +			if (err != -ETIMEDOUT) +				dev_err(panel->dev, +					"error waiting for hpd GPIO: %d\n", err); +			goto error;  		}  	}  	p->prepared_time = ktime_get();  	return 0; + +error: +	gpiod_set_value_cansleep(p->enable_gpio, 0); +	regulator_disable(p->supply); +	p->unprepared_time = ktime_get(); + +	return err; +} + +/* + * Some panels simply don't always come up and need to be power cycled to + * work properly.  We'll allow for a handful of retries. + */ +#define MAX_PANEL_PREPARE_TRIES		5 + +static int panel_simple_prepare(struct drm_panel *panel) +{ +	int ret; +	int try; + +	for (try = 0; try < MAX_PANEL_PREPARE_TRIES; try++) { +		ret = panel_simple_prepare_once(panel); +		if (ret != -ETIMEDOUT) +			break; +	} + +	if (ret == -ETIMEDOUT) +		dev_err(panel->dev, "Prepare timeout after %d tries\n", try); +	else if (try) +		dev_warn(panel->dev, "Prepare needed %d retries\n", try); + +	return ret;  }  static int panel_simple_enable(struct drm_panel *panel) @@ -1445,6 +1484,7 @@ static const struct panel_desc boe_nv110wtm_n61 = {  	.delay = {  		.hpd_absent_delay = 200,  		.prepare_to_enable = 80, +		.enable = 50,  		.unprepare = 500,  	},  	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, @@ -2368,6 +2408,36 @@ static const struct panel_desc innolux_g121x1_l03 = {  	},  }; +static const struct drm_display_mode innolux_n116bca_ea1_mode = { +	.clock = 76420, +	.hdisplay = 1366, +	.hsync_start = 1366 + 136, +	.hsync_end = 1366 + 136 + 30, +	.htotal = 1366 + 136 + 30 + 60, +	.vdisplay = 768, +	.vsync_start = 768 + 8, +	.vsync_end = 768 + 8 + 12, +	.vtotal = 768 + 8 + 12 + 12, +	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, +}; + +static const struct panel_desc innolux_n116bca_ea1 = { +	.modes = &innolux_n116bca_ea1_mode, +	.num_modes = 1, +	.bpc = 6, +	.size = { +		.width = 256, +		.height = 144, +	}, +	.delay = { +		.hpd_absent_delay = 200, +		.prepare_to_enable = 80, +		.unprepare = 500, +	}, +	.bus_format = MEDIA_BUS_FMT_RGB666_1X18, +	.connector_type = DRM_MODE_CONNECTOR_eDP, +}; +  /*   * Datasheet specifies that at 60 Hz refresh rate:   * - total horizontal time: { 1506, 1592, 1716 } @@ -4284,6 +4354,9 @@ static const struct of_device_id platform_of_match[] = {  		.compatible = "innolux,g121x1-l03",  		.data = &innolux_g121x1_l03,  	}, { +		.compatible = "innolux,n116bca-ea1", +		.data = &innolux_n116bca_ea1, +	}, {  		.compatible = "innolux,n116bge",  		.data = &innolux_n116bge,  	}, { @@ -4800,7 +4873,7 @@ static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)  	err = mipi_dsi_attach(dsi);  	if (err) { -		struct panel_simple *panel = dev_get_drvdata(&dsi->dev); +		struct panel_simple *panel = mipi_dsi_get_drvdata(dsi);  		drm_panel_remove(&panel->base);  	}  |