drm/panel: Changes for v4.1-rc1
This set of changes adds support for a whole bunch of new panels, mostly simple ones. There's now also support for panels to provide display timings rather than fixed modes, which should allow panels to work with a larger number of display drivers. Eventually drivers should migrate to this new interface and the fixed modes removed from panels. There are also a couple of sparse fixes for the PS8622 and PS8625 bridge drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJVHXdzAAoJEN0jrNd/PrOhWKgQAJGdicIa3B8CLohgAfyMI+in 1PxO2vBGgz7T02iFTOzwh5cvh8E7mog9/R5jVCyan22BHdws75FgL6RVMcqbllds c2ejPHhHlBEzOBtbZeEmvg1twmqKY5ejk1X7rtVHNCNaXVzSlpxYJF2jfK8DmhRF l7UmjKIpyeDSL+33t+Q0jZynU2mwLfstr/4lwMPPKU6kzz15lIo0gPAnOlagbGD3 L5GOm1+LaDXpxojDtIElzzhzDf1DhmD4nIA3KRGAmKHRxA1u/vZUsW5UNaCvJB0v eMVFdIk/aFfw4jizlAEute4sMKcXWNBMHmEr7e8Bakr+clie7BcXN9zeZ+B99t7A +pkRbWNN8Isr4FpGNVz0XdU2BzmJAaQ59ghmZ5ZJtOmZwMWJbJsG7vMw0p2+68w6 bxhrEoT7hQDUicoKhcM6/8jDCqLZdqN0co16NHIL+0/BiUuS9Q1qr3Y7dBFbiU6D iNKKeniODw8lA+Jv7wxVGbS2f5RvFeLvhgi4MgF78bEj8Mxf2EpB+mJT6WtEcX37 OMcg7xN7C6q2cu4Cpj7txF3gnKwB56lkJsX7xnyajtdHLDcw8Vx4CZprZCyA5gWP FWpDLkT7l3Fi3jRDoVBw3WRa+rIfSFvLuVf3iLyVuFE5vR0tqJKutYDeaez0cMQM nQqS1f2MYsKmNJf2DFhx =0aBn -----END PGP SIGNATURE----- Merge tag 'drm/panel/for-4.1-rc1' of git://anongit.freedesktop.org/tegra/linux into drm-next drm/panel: Changes for v4.1-rc1 This set of changes adds support for a whole bunch of new panels, mostly simple ones. There's now also support for panels to provide display timings rather than fixed modes, which should allow panels to work with a larger number of display drivers. Eventually drivers should migrate to this new interface and the fixed modes removed from panels. There are also a couple of sparse fixes for the PS8622 and PS8625 bridge drivers. * tag 'drm/panel/for-4.1-rc1' of git://anongit.freedesktop.org/tegra/linux: drm/panel: Add support for Ampire AM-800480R3TMQW-A1H 800x480 7" panel of: Add vendor prefix for Ampire Co., Ltd. drm/panel: Add display timing for HannStar HSD070PWW1 drm/panel: simple: Add display timing support drm/panel: Add display timing support drm/panel: Add support for OrtusTech COM43H4M85ULC panel of: Add vendor prefix for Ortus Technology Co., Ltd. drm/panel: Add bus format for Giantplus GPG482739QS5 panel drm/panel: simple: Add support for AUO b101ean01 panel drm/panel: simple: Add support for Innolux ZJ070NA-01P drm/panel: simple: Add support for Innolux AT043TN24 drm/panel: simple: Add support for Shelly SCA07010-BFN-LNN drm/panel: simple: Add support for Samsung LTN140AT29 panel drm: Remove unused DRM_MODE_OBJECT_BRIDGE drm/bridge: ptn3460: Fix sparse warnings drm/bridge: ps8622: Fix sparse warnings drm/bridge: Add I2C based driver for ps8622/ps8625 bridge
This commit is contained in:
		
						commit
						a08aad54be
					
				| @ -0,0 +1,7 @@ | ||||
| Ampire AM-800480R3TMQW-A1H 7.0" WVGA TFT LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "ampire,am800480r3tmqwa1h" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -0,0 +1,7 @@ | ||||
| AU Optronics Corporation 10.1" WSVGA TFT LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "auo,b101ean01" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -0,0 +1,7 @@ | ||||
| Innolux AT043TN24 4.3" WQVGA TFT LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "innolux,at043tn24" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -0,0 +1,7 @@ | ||||
| Innolux Corporation 7.0" WSVGA (1024x600) TFT LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "innolux,zj070na-01p" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -0,0 +1,7 @@ | ||||
| OrtusTech COM43H4M85ULC Blanview 3.7" TFT-LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "ortustech,com43h4m85ulc" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -0,0 +1,7 @@ | ||||
| Samsung Electronics 14" WXGA (1366x768) TFT LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "samsung,ltn140at29-301" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -0,0 +1,7 @@ | ||||
| Shelly SCA07010-BFN-LNN 7.0" WVGA TFT LCD panel | ||||
| 
 | ||||
| Required properties: | ||||
| - compatible: should be "shelly,sca07010-bfn-lnn" | ||||
| 
 | ||||
| This binding is compatible with the simple-panel binding, which is specified | ||||
| in simple-panel.txt in this directory. | ||||
| @ -17,6 +17,7 @@ altr	Altera Corp. | ||||
| amcc	Applied Micro Circuits Corporation (APM, formally AMCC) | ||||
| amd	Advanced Micro Devices (AMD), Inc. | ||||
| amlogic	Amlogic, Inc. | ||||
| ampire	Ampire Co., Ltd. | ||||
| ams	AMS AG | ||||
| amstaos	AMS-Taos Inc. | ||||
| apm	Applied Micro Circuits Corporation (APM) | ||||
| @ -132,6 +133,7 @@ nvidia	NVIDIA | ||||
| nxp	NXP Semiconductors | ||||
| onnn	ON Semiconductor Corp. | ||||
| opencores	OpenCores.org | ||||
| ortustech	Ortus Technology Co., Ltd. | ||||
| ovti	OmniVision Technologies | ||||
| panasonic	Panasonic Corporation | ||||
| parade	Parade Technologies Inc. | ||||
|  | ||||
| @ -11,3 +11,14 @@ config DRM_PTN3460 | ||||
| 	select DRM_PANEL | ||||
| 	---help--- | ||||
| 	  ptn3460 eDP-LVDS bridge chip driver. | ||||
| 
 | ||||
| config DRM_PS8622 | ||||
| 	tristate "Parade eDP/LVDS bridge" | ||||
| 	depends on DRM | ||||
| 	depends on OF | ||||
| 	select DRM_PANEL | ||||
| 	select DRM_KMS_HELPER | ||||
| 	select BACKLIGHT_LCD_SUPPORT | ||||
| 	select BACKLIGHT_CLASS_DEVICE | ||||
| 	---help--- | ||||
| 	  parade eDP-LVDS bridge chip driver. | ||||
|  | ||||
| @ -1,4 +1,5 @@ | ||||
| ccflags-y := -Iinclude/drm | ||||
| 
 | ||||
| obj-$(CONFIG_DRM_PS8622) += ps8622.o | ||||
| obj-$(CONFIG_DRM_PTN3460) += ptn3460.o | ||||
| obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o | ||||
|  | ||||
							
								
								
									
										684
									
								
								drivers/gpu/drm/bridge/ps8622.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										684
									
								
								drivers/gpu/drm/bridge/ps8622.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,684 @@ | ||||
| /*
 | ||||
|  * Parade PS8622 eDP/LVDS bridge driver | ||||
|  * | ||||
|  * Copyright (C) 2014 Google, Inc. | ||||
|  * | ||||
|  * This software is licensed under the terms of the GNU General Public | ||||
|  * License version 2, as published by the Free Software Foundation, and | ||||
|  * may be copied, distributed, and modified under those terms. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
|  * GNU General Public License for more details. | ||||
|  */ | ||||
| 
 | ||||
| #include <linux/backlight.h> | ||||
| #include <linux/delay.h> | ||||
| #include <linux/err.h> | ||||
| #include <linux/fb.h> | ||||
| #include <linux/gpio.h> | ||||
| #include <linux/i2c.h> | ||||
| #include <linux/module.h> | ||||
| #include <linux/of.h> | ||||
| #include <linux/of_device.h> | ||||
| #include <linux/of_graph.h> | ||||
| #include <linux/pm.h> | ||||
| #include <linux/regulator/consumer.h> | ||||
| 
 | ||||
| #include <drm/drm_panel.h> | ||||
| 
 | ||||
| #include "drmP.h" | ||||
| #include "drm_crtc.h" | ||||
| #include "drm_crtc_helper.h" | ||||
| 
 | ||||
| /* Brightness scale on the Parade chip */ | ||||
| #define PS8622_MAX_BRIGHTNESS 0xff | ||||
| 
 | ||||
| /* Timings taken from the version 1.7 datasheet for the PS8622/PS8625 */ | ||||
| #define PS8622_POWER_RISE_T1_MIN_US 10 | ||||
| #define PS8622_POWER_RISE_T1_MAX_US 10000 | ||||
| #define PS8622_RST_HIGH_T2_MIN_US 3000 | ||||
| #define PS8622_RST_HIGH_T2_MAX_US 30000 | ||||
| #define PS8622_PWMO_END_T12_MS 200 | ||||
| #define PS8622_POWER_FALL_T16_MAX_US 10000 | ||||
| #define PS8622_POWER_OFF_T17_MS 500 | ||||
| 
 | ||||
| #if ((PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US) > \ | ||||
| 	(PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US)) | ||||
| #error "T2.min + T1.max must be less than T2.max + T1.min" | ||||
| #endif | ||||
| 
 | ||||
| struct ps8622_bridge { | ||||
| 	struct drm_connector connector; | ||||
| 	struct i2c_client *client; | ||||
| 	struct drm_bridge bridge; | ||||
| 	struct drm_panel *panel; | ||||
| 	struct regulator *v12; | ||||
| 	struct backlight_device *bl; | ||||
| 
 | ||||
| 	struct gpio_desc *gpio_slp; | ||||
| 	struct gpio_desc *gpio_rst; | ||||
| 
 | ||||
| 	u32 max_lane_count; | ||||
| 	u32 lane_count; | ||||
| 
 | ||||
| 	bool enabled; | ||||
| }; | ||||
| 
 | ||||
| static inline struct ps8622_bridge * | ||||
| 		bridge_to_ps8622(struct drm_bridge *bridge) | ||||
| { | ||||
| 	return container_of(bridge, struct ps8622_bridge, bridge); | ||||
| } | ||||
| 
 | ||||
| static inline struct ps8622_bridge * | ||||
| 		connector_to_ps8622(struct drm_connector *connector) | ||||
| { | ||||
| 	return container_of(connector, struct ps8622_bridge, connector); | ||||
| } | ||||
| 
 | ||||
| static int ps8622_set(struct i2c_client *client, u8 page, u8 reg, u8 val) | ||||
| { | ||||
| 	int ret; | ||||
| 	struct i2c_adapter *adap = client->adapter; | ||||
| 	struct i2c_msg msg; | ||||
| 	u8 data[] = {reg, val}; | ||||
| 
 | ||||
| 	msg.addr = client->addr + page; | ||||
| 	msg.flags = 0; | ||||
| 	msg.len = sizeof(data); | ||||
| 	msg.buf = data; | ||||
| 
 | ||||
| 	ret = i2c_transfer(adap, &msg, 1); | ||||
| 	if (ret != 1) | ||||
| 		pr_warn("PS8622 I2C write (0x%02x,0x%02x,0x%02x) failed: %d\n", | ||||
| 			client->addr + page, reg, val, ret); | ||||
| 	return !(ret == 1); | ||||
| } | ||||
| 
 | ||||
| static int ps8622_send_config(struct ps8622_bridge *ps8622) | ||||
| { | ||||
| 	struct i2c_client *cl = ps8622->client; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	/* HPD low */ | ||||
| 	err = ps8622_set(cl, 0x02, 0xa1, 0x01); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* SW setting: [1:0] SW output 1.2V voltage is lower to 96% */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x14, 0x01); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* RCO SS setting: [5:4] = b01 0.5%, b10 1%, b11 1.5% */ | ||||
| 	err = ps8622_set(cl, 0x04, 0xe3, 0x20); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [7] RCO SS enable */ | ||||
| 	err = ps8622_set(cl, 0x04, 0xe2, 0x80); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* RPHY Setting
 | ||||
| 	 * [3:2] CDR tune wait cycle before measure for fine tune | ||||
| 	 * b00: 1us b01: 0.5us b10:2us, b11: 4us | ||||
| 	 */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x8a, 0x0c); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [3] RFD always on */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x89, 0x08); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* CTN lock in/out: 20000ppm/80000ppm. Lock out 2 times. */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x71, 0x2d); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* 2.7G CDR settings: NOF=40LSB for HBR CDR  setting */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x7d, 0x07); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [1:0] Fmin=+4bands */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x7b, 0x00); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [7:5] DCO_FTRNG=+-40% */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x7a, 0xfd); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* 1.62G CDR settings: [5:2]NOF=64LSB [1:0]DCO scale is 2/5 */ | ||||
| 	err = ps8622_set(cl, 0x04, 0xc0, 0x12); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Gitune=-37% */ | ||||
| 	err = ps8622_set(cl, 0x04, 0xc1, 0x92); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Fbstep=100% */ | ||||
| 	err = ps8622_set(cl, 0x04, 0xc2, 0x1c); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [7] LOS signal disable */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x32, 0x80); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* RPIO Setting: [7:4] LVDS driver bias current : 75% (250mV swing) */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x00, 0xb0); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [7:6] Right-bar GPIO output strength is 8mA */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x15, 0x40); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* EQ Training State Machine Setting, RCO calibration start */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x54, 0x10); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Logic, needs more than 10 I2C command */ | ||||
| 	/* [4:0] MAX_LANE_COUNT set to max supported lanes */ | ||||
| 	err = ps8622_set(cl, 0x01, 0x02, 0x80 | ps8622->max_lane_count); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [4:0] LANE_COUNT_SET set to chosen lane count */ | ||||
| 	err = ps8622_set(cl, 0x01, 0x21, 0x80 | ps8622->lane_count); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	err = ps8622_set(cl, 0x00, 0x52, 0x20); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* HPD CP toggle enable */ | ||||
| 	err = ps8622_set(cl, 0x00, 0xf1, 0x03); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	err = ps8622_set(cl, 0x00, 0x62, 0x41); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Counter number, add 1ms counter delay */ | ||||
| 	err = ps8622_set(cl, 0x00, 0xf6, 0x01); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* [6]PWM function control by DPCD0040f[7], default is PWM block */ | ||||
| 	err = ps8622_set(cl, 0x00, 0x77, 0x06); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* 04h Adjust VTotal toleranceto fix the 30Hz no display issue */ | ||||
| 	err = ps8622_set(cl, 0x00, 0x4c, 0x04); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD00400='h00, Parade OUI ='h001cf8 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc0, 0x00); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD00401='h1c */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc1, 0x1c); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD00402='hf8 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc2, 0xf8); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD403~408 = ASCII code, D2SLV5='h4432534c5635 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc3, 0x44); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD404 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc4, 0x32); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD405 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc5, 0x53); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD406 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc6, 0x4c); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD407 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc7, 0x56); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD408 */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xc8, 0x35); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD40A, Initial Code major revision '01' */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xca, 0x01); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* DPCD40B, Initial Code minor revision '05' */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xcb, 0x05); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 
 | ||||
| 	if (ps8622->bl) { | ||||
| 		/* DPCD720, internal PWM */ | ||||
| 		err = ps8622_set(cl, 0x01, 0xa5, 0xa0); | ||||
| 		if (err) | ||||
| 			goto error; | ||||
| 
 | ||||
| 		/* FFh for 100% brightness, 0h for 0% brightness */ | ||||
| 		err = ps8622_set(cl, 0x01, 0xa7, | ||||
| 				ps8622->bl->props.brightness); | ||||
| 		if (err) | ||||
| 			goto error; | ||||
| 	} else { | ||||
| 		/* DPCD720, external PWM */ | ||||
| 		err = ps8622_set(cl, 0x01, 0xa5, 0x80); | ||||
| 		if (err) | ||||
| 			goto error; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Set LVDS output as 6bit-VESA mapping, single LVDS channel */ | ||||
| 	err = ps8622_set(cl, 0x01, 0xcc, 0x13); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Enable SSC set by register */ | ||||
| 	err = ps8622_set(cl, 0x02, 0xb1, 0x20); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Set SSC enabled and +/-1% central spreading */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x10, 0x16); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* Logic end */ | ||||
| 	/* MPU Clock source: LC => RCO */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x59, 0x60); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* LC -> RCO */ | ||||
| 	err = ps8622_set(cl, 0x04, 0x54, 0x14); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
| 	/* HPD high */ | ||||
| 	err = ps8622_set(cl, 0x02, 0xa1, 0x91); | ||||
| 
 | ||||
| error: | ||||
| 	return err ? -EIO : 0; | ||||
| } | ||||
| 
 | ||||
| static int ps8622_backlight_update(struct backlight_device *bl) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = dev_get_drvdata(&bl->dev); | ||||
| 	int ret, brightness = bl->props.brightness; | ||||
| 
 | ||||
| 	if (bl->props.power != FB_BLANK_UNBLANK || | ||||
| 	    bl->props.state & (BL_CORE_SUSPENDED | BL_CORE_FBBLANK)) | ||||
| 		brightness = 0; | ||||
| 
 | ||||
| 	if (!ps8622->enabled) | ||||
| 		return -EINVAL; | ||||
| 
 | ||||
| 	ret = ps8622_set(ps8622->client, 0x01, 0xa7, brightness); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct backlight_ops ps8622_backlight_ops = { | ||||
| 	.update_status	= ps8622_backlight_update, | ||||
| }; | ||||
| 
 | ||||
| static void ps8622_pre_enable(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (ps8622->enabled) | ||||
| 		return; | ||||
| 
 | ||||
| 	gpiod_set_value(ps8622->gpio_rst, 0); | ||||
| 
 | ||||
| 	if (ps8622->v12) { | ||||
| 		ret = regulator_enable(ps8622->v12); | ||||
| 		if (ret) | ||||
| 			DRM_ERROR("fails to enable ps8622->v12"); | ||||
| 	} | ||||
| 
 | ||||
| 	if (drm_panel_prepare(ps8622->panel)) { | ||||
| 		DRM_ERROR("failed to prepare panel\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	gpiod_set_value(ps8622->gpio_slp, 1); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * T1 is the range of time that it takes for the power to rise after we | ||||
| 	 * enable the lcd/ps8622 fet. T2 is the range of time in which the | ||||
| 	 * data sheet specifies we should deassert the reset pin. | ||||
| 	 * | ||||
| 	 * If it takes T1.max for the power to rise, we need to wait atleast | ||||
| 	 * T2.min before deasserting the reset pin. If it takes T1.min for the | ||||
| 	 * power to rise, we need to wait at most T2.max before deasserting the | ||||
| 	 * reset pin. | ||||
| 	 */ | ||||
| 	usleep_range(PS8622_RST_HIGH_T2_MIN_US + PS8622_POWER_RISE_T1_MAX_US, | ||||
| 		     PS8622_RST_HIGH_T2_MAX_US + PS8622_POWER_RISE_T1_MIN_US); | ||||
| 
 | ||||
| 	gpiod_set_value(ps8622->gpio_rst, 1); | ||||
| 
 | ||||
| 	/* wait 20ms after RST high */ | ||||
| 	usleep_range(20000, 30000); | ||||
| 
 | ||||
| 	ret = ps8622_send_config(ps8622); | ||||
| 	if (ret) { | ||||
| 		DRM_ERROR("Failed to send config to bridge (%d)\n", ret); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->enabled = true; | ||||
| } | ||||
| 
 | ||||
| static void ps8622_enable(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | ||||
| 
 | ||||
| 	if (drm_panel_enable(ps8622->panel)) { | ||||
| 		DRM_ERROR("failed to enable panel\n"); | ||||
| 		return; | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| static void ps8622_disable(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | ||||
| 
 | ||||
| 	if (drm_panel_disable(ps8622->panel)) { | ||||
| 		DRM_ERROR("failed to disable panel\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 	msleep(PS8622_PWMO_END_T12_MS); | ||||
| } | ||||
| 
 | ||||
| static void ps8622_post_disable(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | ||||
| 
 | ||||
| 	if (!ps8622->enabled) | ||||
| 		return; | ||||
| 
 | ||||
| 	ps8622->enabled = false; | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * This doesn't matter if the regulators are turned off, but something | ||||
| 	 * else might keep them on. In that case, we want to assert the slp gpio | ||||
| 	 * to lower power. | ||||
| 	 */ | ||||
| 	gpiod_set_value(ps8622->gpio_slp, 0); | ||||
| 
 | ||||
| 	if (drm_panel_unprepare(ps8622->panel)) { | ||||
| 		DRM_ERROR("failed to unprepare panel\n"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	if (ps8622->v12) | ||||
| 		regulator_disable(ps8622->v12); | ||||
| 
 | ||||
| 	/*
 | ||||
| 	 * Sleep for at least the amount of time that it takes the power rail to | ||||
| 	 * fall to prevent asserting the rst gpio from doing anything. | ||||
| 	 */ | ||||
| 	usleep_range(PS8622_POWER_FALL_T16_MAX_US, | ||||
| 		     2 * PS8622_POWER_FALL_T16_MAX_US); | ||||
| 	gpiod_set_value(ps8622->gpio_rst, 0); | ||||
| 
 | ||||
| 	msleep(PS8622_POWER_OFF_T17_MS); | ||||
| } | ||||
| 
 | ||||
| static int ps8622_get_modes(struct drm_connector *connector) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622; | ||||
| 
 | ||||
| 	ps8622 = connector_to_ps8622(connector); | ||||
| 
 | ||||
| 	return drm_panel_get_modes(ps8622->panel); | ||||
| } | ||||
| 
 | ||||
| static struct drm_encoder *ps8622_best_encoder(struct drm_connector *connector) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622; | ||||
| 
 | ||||
| 	ps8622 = connector_to_ps8622(connector); | ||||
| 
 | ||||
| 	return ps8622->bridge.encoder; | ||||
| } | ||||
| 
 | ||||
| static const struct drm_connector_helper_funcs ps8622_connector_helper_funcs = { | ||||
| 	.get_modes = ps8622_get_modes, | ||||
| 	.best_encoder = ps8622_best_encoder, | ||||
| }; | ||||
| 
 | ||||
| static enum drm_connector_status ps8622_detect(struct drm_connector *connector, | ||||
| 								bool force) | ||||
| { | ||||
| 	return connector_status_connected; | ||||
| } | ||||
| 
 | ||||
| static void ps8622_connector_destroy(struct drm_connector *connector) | ||||
| { | ||||
| 	drm_connector_cleanup(connector); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_connector_funcs ps8622_connector_funcs = { | ||||
| 	.dpms = drm_helper_connector_dpms, | ||||
| 	.fill_modes = drm_helper_probe_single_connector_modes, | ||||
| 	.detect = ps8622_detect, | ||||
| 	.destroy = ps8622_connector_destroy, | ||||
| }; | ||||
| 
 | ||||
| static int ps8622_attach(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = bridge_to_ps8622(bridge); | ||||
| 	int ret; | ||||
| 
 | ||||
| 	if (!bridge->encoder) { | ||||
| 		DRM_ERROR("Parent encoder object not found"); | ||||
| 		return -ENODEV; | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->connector.polled = DRM_CONNECTOR_POLL_HPD; | ||||
| 	ret = drm_connector_init(bridge->dev, &ps8622->connector, | ||||
| 			&ps8622_connector_funcs, DRM_MODE_CONNECTOR_LVDS); | ||||
| 	if (ret) { | ||||
| 		DRM_ERROR("Failed to initialize connector with drm\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	drm_connector_helper_add(&ps8622->connector, | ||||
| 					&ps8622_connector_helper_funcs); | ||||
| 	drm_connector_register(&ps8622->connector); | ||||
| 	drm_mode_connector_attach_encoder(&ps8622->connector, | ||||
| 							bridge->encoder); | ||||
| 
 | ||||
| 	if (ps8622->panel) | ||||
| 		drm_panel_attach(ps8622->panel, &ps8622->connector); | ||||
| 
 | ||||
| 	drm_helper_hpd_irq_event(ps8622->connector.dev); | ||||
| 
 | ||||
| 	return ret; | ||||
| } | ||||
| 
 | ||||
| static const struct drm_bridge_funcs ps8622_bridge_funcs = { | ||||
| 	.pre_enable = ps8622_pre_enable, | ||||
| 	.enable = ps8622_enable, | ||||
| 	.disable = ps8622_disable, | ||||
| 	.post_disable = ps8622_post_disable, | ||||
| 	.attach = ps8622_attach, | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id ps8622_devices[] = { | ||||
| 	{.compatible = "parade,ps8622",}, | ||||
| 	{.compatible = "parade,ps8625",}, | ||||
| 	{} | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(of, ps8622_devices); | ||||
| 
 | ||||
| static int ps8622_probe(struct i2c_client *client, | ||||
| 					const struct i2c_device_id *id) | ||||
| { | ||||
| 	struct device *dev = &client->dev; | ||||
| 	struct device_node *endpoint, *panel_node; | ||||
| 	struct ps8622_bridge *ps8622; | ||||
| 	int ret; | ||||
| 
 | ||||
| 	ps8622 = devm_kzalloc(dev, sizeof(*ps8622), GFP_KERNEL); | ||||
| 	if (!ps8622) | ||||
| 		return -ENOMEM; | ||||
| 
 | ||||
| 	endpoint = of_graph_get_next_endpoint(dev->of_node, NULL); | ||||
| 	if (endpoint) { | ||||
| 		panel_node = of_graph_get_remote_port_parent(endpoint); | ||||
| 		if (panel_node) { | ||||
| 			ps8622->panel = of_drm_find_panel(panel_node); | ||||
| 			of_node_put(panel_node); | ||||
| 			if (!ps8622->panel) | ||||
| 				return -EPROBE_DEFER; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->client = client; | ||||
| 
 | ||||
| 	ps8622->v12 = devm_regulator_get(dev, "vdd12"); | ||||
| 	if (IS_ERR(ps8622->v12)) { | ||||
| 		dev_info(dev, "no 1.2v regulator found for PS8622\n"); | ||||
| 		ps8622->v12 = NULL; | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->gpio_slp = devm_gpiod_get(dev, "sleep"); | ||||
| 	if (IS_ERR(ps8622->gpio_slp)) { | ||||
| 		ret = PTR_ERR(ps8622->gpio_slp); | ||||
| 		dev_err(dev, "cannot get gpio_slp %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	ret = gpiod_direction_output(ps8622->gpio_slp, 1); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "cannot configure gpio_slp\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->gpio_rst = devm_gpiod_get(dev, "reset"); | ||||
| 	if (IS_ERR(ps8622->gpio_rst)) { | ||||
| 		ret = PTR_ERR(ps8622->gpio_rst); | ||||
| 		dev_err(dev, "cannot get gpio_rst %d\n", ret); | ||||
| 		return ret; | ||||
| 	} | ||||
| 	/*
 | ||||
| 	 * Assert the reset pin high to avoid the bridge being | ||||
| 	 * initialized prematurely | ||||
| 	 */ | ||||
| 	ret = gpiod_direction_output(ps8622->gpio_rst, 1); | ||||
| 	if (ret) { | ||||
| 		dev_err(dev, "cannot configure gpio_rst\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->max_lane_count = id->driver_data; | ||||
| 
 | ||||
| 	if (of_property_read_u32(dev->of_node, "lane-count", | ||||
| 						&ps8622->lane_count)) { | ||||
| 		ps8622->lane_count = ps8622->max_lane_count; | ||||
| 	} else if (ps8622->lane_count > ps8622->max_lane_count) { | ||||
| 		dev_info(dev, "lane-count property is too high," | ||||
| 						"using max_lane_count\n"); | ||||
| 		ps8622->lane_count = ps8622->max_lane_count; | ||||
| 	} | ||||
| 
 | ||||
| 	if (!of_find_property(dev->of_node, "use-external-pwm", NULL)) { | ||||
| 		ps8622->bl = backlight_device_register("ps8622-backlight", | ||||
| 				dev, ps8622, &ps8622_backlight_ops, | ||||
| 				NULL); | ||||
| 		if (IS_ERR(ps8622->bl)) { | ||||
| 			DRM_ERROR("failed to register backlight\n"); | ||||
| 			ret = PTR_ERR(ps8622->bl); | ||||
| 			ps8622->bl = NULL; | ||||
| 			return ret; | ||||
| 		} | ||||
| 		ps8622->bl->props.max_brightness = PS8622_MAX_BRIGHTNESS; | ||||
| 		ps8622->bl->props.brightness = PS8622_MAX_BRIGHTNESS; | ||||
| 	} | ||||
| 
 | ||||
| 	ps8622->bridge.funcs = &ps8622_bridge_funcs; | ||||
| 	ps8622->bridge.of_node = dev->of_node; | ||||
| 	ret = drm_bridge_add(&ps8622->bridge); | ||||
| 	if (ret) { | ||||
| 		DRM_ERROR("Failed to add bridge\n"); | ||||
| 		return ret; | ||||
| 	} | ||||
| 
 | ||||
| 	i2c_set_clientdata(client, ps8622); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ps8622_remove(struct i2c_client *client) | ||||
| { | ||||
| 	struct ps8622_bridge *ps8622 = i2c_get_clientdata(client); | ||||
| 
 | ||||
| 	if (ps8622->bl) | ||||
| 		backlight_device_unregister(ps8622->bl); | ||||
| 
 | ||||
| 	drm_bridge_remove(&ps8622->bridge); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static const struct i2c_device_id ps8622_i2c_table[] = { | ||||
| 	/* Device type, max_lane_count */ | ||||
| 	{"ps8622", 1}, | ||||
| 	{"ps8625", 2}, | ||||
| 	{}, | ||||
| }; | ||||
| MODULE_DEVICE_TABLE(i2c, ps8622_i2c_table); | ||||
| 
 | ||||
| static struct i2c_driver ps8622_driver = { | ||||
| 	.id_table	= ps8622_i2c_table, | ||||
| 	.probe		= ps8622_probe, | ||||
| 	.remove		= ps8622_remove, | ||||
| 	.driver		= { | ||||
| 		.name	= "ps8622", | ||||
| 		.owner	= THIS_MODULE, | ||||
| 		.of_match_table = ps8622_devices, | ||||
| 	}, | ||||
| }; | ||||
| module_i2c_driver(ps8622_driver); | ||||
| 
 | ||||
| MODULE_AUTHOR("Vincent Palatin <vpalatin@chromium.org>"); | ||||
| MODULE_DESCRIPTION("Parade ps8622/ps8625 eDP-LVDS converter driver"); | ||||
| MODULE_LICENSE("GPL v2"); | ||||
| @ -265,7 +265,7 @@ static struct drm_connector_funcs ptn3460_connector_funcs = { | ||||
| 	.destroy = ptn3460_connector_destroy, | ||||
| }; | ||||
| 
 | ||||
| int ptn3460_bridge_attach(struct drm_bridge *bridge) | ||||
| static int ptn3460_bridge_attach(struct drm_bridge *bridge) | ||||
| { | ||||
| 	struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge); | ||||
| 	int ret; | ||||
|  | ||||
| @ -11,6 +11,7 @@ config DRM_PANEL_SIMPLE | ||||
| 	tristate "support for simple panels" | ||||
| 	depends on OF | ||||
| 	depends on BACKLIGHT_CLASS_DEVICE | ||||
| 	select VIDEOMODE_HELPERS | ||||
| 	help | ||||
| 	  DRM panel driver for dumb panels that need at most a regulator and | ||||
| 	  a GPIO to be powered up. Optionally a backlight can be attached so | ||||
|  | ||||
| @ -33,9 +33,14 @@ | ||||
| #include <drm/drm_mipi_dsi.h> | ||||
| #include <drm/drm_panel.h> | ||||
| 
 | ||||
| #include <video/display_timing.h> | ||||
| #include <video/videomode.h> | ||||
| 
 | ||||
| struct panel_desc { | ||||
| 	const struct drm_display_mode *modes; | ||||
| 	unsigned int num_modes; | ||||
| 	const struct display_timing *timings; | ||||
| 	unsigned int num_timings; | ||||
| 
 | ||||
| 	unsigned int bpc; | ||||
| 
 | ||||
| @ -94,6 +99,25 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel) | ||||
| 	if (!panel->desc) | ||||
| 		return 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(drm); | ||||
| 		if (!mode) { | ||||
| 			dev_err(drm->dev, "failed to add mode %ux%u\n", | ||||
| 				dt->hactive.typ, dt->vactive.typ); | ||||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		drm_display_mode_from_videomode(&vm, mode); | ||||
| 		drm_mode_set_name(mode); | ||||
| 
 | ||||
| 		drm_mode_probed_add(connector, mode); | ||||
| 		num++; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < panel->desc->num_modes; i++) { | ||||
| 		const struct drm_display_mode *m = &panel->desc->modes[i]; | ||||
| 
 | ||||
| @ -226,12 +250,30 @@ static int panel_simple_get_modes(struct drm_panel *panel) | ||||
| 	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 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_timings = panel_simple_get_timings, | ||||
| }; | ||||
| 
 | ||||
| static int panel_simple_probe(struct device *dev, const struct panel_desc *desc) | ||||
| @ -327,6 +369,31 @@ static void panel_simple_shutdown(struct device *dev) | ||||
| 	panel_simple_disable(&panel->base); | ||||
| } | ||||
| 
 | ||||
| static const struct drm_display_mode ampire_am800480r3tmqwa1h_mode = { | ||||
| 	.clock = 33333, | ||||
| 	.hdisplay = 800, | ||||
| 	.hsync_start = 800 + 0, | ||||
| 	.hsync_end = 800 + 0 + 255, | ||||
| 	.htotal = 800 + 0 + 255 + 0, | ||||
| 	.vdisplay = 480, | ||||
| 	.vsync_start = 480 + 2, | ||||
| 	.vsync_end = 480 + 2 + 45, | ||||
| 	.vtotal = 480 + 2 + 45 + 0, | ||||
| 	.vrefresh = 60, | ||||
| 	.flags = DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc ampire_am800480r3tmqwa1h = { | ||||
| 	.modes = &ire_am800480r3tmqwa1h_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 6, | ||||
| 	.size = { | ||||
| 		.width = 152, | ||||
| 		.height = 91, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB666_1X18, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode auo_b101aw03_mode = { | ||||
| 	.clock = 51450, | ||||
| 	.hdisplay = 1024, | ||||
| @ -350,6 +417,29 @@ static const struct panel_desc auo_b101aw03 = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode auo_b101ean01_mode = { | ||||
| 	.clock = 72500, | ||||
| 	.hdisplay = 1280, | ||||
| 	.hsync_start = 1280 + 119, | ||||
| 	.hsync_end = 1280 + 119 + 32, | ||||
| 	.htotal = 1280 + 119 + 32 + 21, | ||||
| 	.vdisplay = 800, | ||||
| 	.vsync_start = 800 + 4, | ||||
| 	.vsync_end = 800 + 4 + 20, | ||||
| 	.vtotal = 800 + 4 + 20 + 8, | ||||
| 	.vrefresh = 60, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc auo_b101ean01 = { | ||||
| 	.modes = &auo_b101ean01_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 6, | ||||
| 	.size = { | ||||
| 		.width = 217, | ||||
| 		.height = 136, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode auo_b101xtn01_mode = { | ||||
| 	.clock = 72000, | ||||
| 	.hdisplay = 1366, | ||||
| @ -615,24 +705,25 @@ static const struct panel_desc giantplus_gpg482739qs5 = { | ||||
| 		.width = 95, | ||||
| 		.height = 54, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode hannstar_hsd070pww1_mode = { | ||||
| 	.clock = 71100, | ||||
| 	.hdisplay = 1280, | ||||
| 	.hsync_start = 1280 + 1, | ||||
| 	.hsync_end = 1280 + 1 + 158, | ||||
| 	.htotal = 1280 + 1 + 158 + 1, | ||||
| 	.vdisplay = 800, | ||||
| 	.vsync_start = 800 + 1, | ||||
| 	.vsync_end = 800 + 1 + 21, | ||||
| 	.vtotal = 800 + 1 + 21 + 1, | ||||
| 	.vrefresh = 60, | ||||
| static const struct display_timing hannstar_hsd070pww1_timing = { | ||||
| 	.pixelclock = { 64300000, 71100000, 82000000 }, | ||||
| 	.hactive = { 1280, 1280, 1280 }, | ||||
| 	.hfront_porch = { 1, 1, 10 }, | ||||
| 	.hback_porch = { 1, 1, 10 }, | ||||
| 	.hsync_len = { 52, 158, 661 }, | ||||
| 	.vactive = { 800, 800, 800 }, | ||||
| 	.vfront_porch = { 1, 1, 10 }, | ||||
| 	.vback_porch = { 1, 1, 10 }, | ||||
| 	.vsync_len = { 1, 21, 203 }, | ||||
| 	.flags = DISPLAY_FLAGS_DE_HIGH, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc hannstar_hsd070pww1 = { | ||||
| 	.modes = &hannstar_hsd070pww1_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.timings = &hannstar_hsd070pww1_timing, | ||||
| 	.num_timings = 1, | ||||
| 	.bpc = 6, | ||||
| 	.size = { | ||||
| 		.width = 151, | ||||
| @ -663,6 +754,31 @@ static const struct panel_desc hitachi_tx23d38vm0caa = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode innolux_at043tn24_mode = { | ||||
| 	.clock = 9000, | ||||
| 	.hdisplay = 480, | ||||
| 	.hsync_start = 480 + 2, | ||||
| 	.hsync_end = 480 + 2 + 41, | ||||
| 	.htotal = 480 + 2 + 41 + 2, | ||||
| 	.vdisplay = 272, | ||||
| 	.vsync_start = 272 + 2, | ||||
| 	.vsync_end = 272 + 2 + 11, | ||||
| 	.vtotal = 272 + 2 + 11 + 2, | ||||
| 	.vrefresh = 60, | ||||
| 	.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc innolux_at043tn24 = { | ||||
| 	.modes = &innolux_at043tn24_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 8, | ||||
| 	.size = { | ||||
| 		.width = 95, | ||||
| 		.height = 54, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode innolux_g121i1_l01_mode = { | ||||
| 	.clock = 71000, | ||||
| 	.hdisplay = 1280, | ||||
| @ -733,6 +849,29 @@ static const struct panel_desc innolux_n156bge_l21 = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode innolux_zj070na_01p_mode = { | ||||
| 	.clock = 51501, | ||||
| 	.hdisplay = 1024, | ||||
| 	.hsync_start = 1024 + 128, | ||||
| 	.hsync_end = 1024 + 128 + 64, | ||||
| 	.htotal = 1024 + 128 + 64 + 128, | ||||
| 	.vdisplay = 600, | ||||
| 	.vsync_start = 600 + 16, | ||||
| 	.vsync_end = 600 + 16 + 4, | ||||
| 	.vtotal = 600 + 16 + 4 + 16, | ||||
| 	.vrefresh = 60, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc innolux_zj070na_01p = { | ||||
| 	.modes = &innolux_zj070na_01p_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 6, | ||||
| 	.size = { | ||||
| 		.width = 1024, | ||||
| 		.height = 600, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode lg_lp129qe_mode = { | ||||
| 	.clock = 285250, | ||||
| 	.hdisplay = 2560, | ||||
| @ -756,6 +895,30 @@ static const struct panel_desc lg_lp129qe = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode ortustech_com43h4m85ulc_mode  = { | ||||
| 	.clock = 25000, | ||||
| 	.hdisplay = 480, | ||||
| 	.hsync_start = 480 + 10, | ||||
| 	.hsync_end = 480 + 10 + 10, | ||||
| 	.htotal = 480 + 10 + 10 + 15, | ||||
| 	.vdisplay = 800, | ||||
| 	.vsync_start = 800 + 3, | ||||
| 	.vsync_end = 800 + 3 + 3, | ||||
| 	.vtotal = 800 + 3 + 3 + 3, | ||||
| 	.vrefresh = 60, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc ortustech_com43h4m85ulc = { | ||||
| 	.modes = &ortustech_com43h4m85ulc_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 8, | ||||
| 	.size = { | ||||
| 		.width = 56, | ||||
| 		.height = 93, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB888_1X24, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode samsung_ltn101nt05_mode = { | ||||
| 	.clock = 54030, | ||||
| 	.hdisplay = 1024, | ||||
| @ -779,10 +942,62 @@ static const struct panel_desc samsung_ltn101nt05 = { | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode samsung_ltn140at29_301_mode = { | ||||
| 	.clock = 76300, | ||||
| 	.hdisplay = 1366, | ||||
| 	.hsync_start = 1366 + 64, | ||||
| 	.hsync_end = 1366 + 64 + 48, | ||||
| 	.htotal = 1366 + 64 + 48 + 128, | ||||
| 	.vdisplay = 768, | ||||
| 	.vsync_start = 768 + 2, | ||||
| 	.vsync_end = 768 + 2 + 5, | ||||
| 	.vtotal = 768 + 2 + 5 + 17, | ||||
| 	.vrefresh = 60, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc samsung_ltn140at29_301 = { | ||||
| 	.modes = &samsung_ltn140at29_301_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.bpc = 6, | ||||
| 	.size = { | ||||
| 		.width = 320, | ||||
| 		.height = 187, | ||||
| 	}, | ||||
| }; | ||||
| 
 | ||||
| static const struct drm_display_mode shelly_sca07010_bfn_lnn_mode = { | ||||
| 	.clock = 33300, | ||||
| 	.hdisplay = 800, | ||||
| 	.hsync_start = 800 + 1, | ||||
| 	.hsync_end = 800 + 1 + 64, | ||||
| 	.htotal = 800 + 1 + 64 + 64, | ||||
| 	.vdisplay = 480, | ||||
| 	.vsync_start = 480 + 1, | ||||
| 	.vsync_end = 480 + 1 + 23, | ||||
| 	.vtotal = 480 + 1 + 23 + 22, | ||||
| 	.vrefresh = 60, | ||||
| }; | ||||
| 
 | ||||
| static const struct panel_desc shelly_sca07010_bfn_lnn = { | ||||
| 	.modes = &shelly_sca07010_bfn_lnn_mode, | ||||
| 	.num_modes = 1, | ||||
| 	.size = { | ||||
| 		.width = 152, | ||||
| 		.height = 91, | ||||
| 	}, | ||||
| 	.bus_format = MEDIA_BUS_FMT_RGB666_1X18, | ||||
| }; | ||||
| 
 | ||||
| static const struct of_device_id platform_of_match[] = { | ||||
| 	{ | ||||
| 		.compatible = "ampire,am800480r3tmqwa1h", | ||||
| 		.data = &ire_am800480r3tmqwa1h, | ||||
| 	}, { | ||||
| 		.compatible = "auo,b101aw03", | ||||
| 		.data = &auo_b101aw03, | ||||
| 	}, { | ||||
| 		.compatible = "auo,b101ean01", | ||||
| 		.data = &auo_b101ean01, | ||||
| 	}, { | ||||
| 		.compatible = "auo,b101xtn01", | ||||
| 		.data = &auo_b101xtn01, | ||||
| @ -825,6 +1040,9 @@ static const struct of_device_id platform_of_match[] = { | ||||
| 	}, { | ||||
| 		.compatible = "hit,tx23d38vm0caa", | ||||
| 		.data = &hitachi_tx23d38vm0caa | ||||
| 	}, { | ||||
| 		.compatible = "innolux,at043tn24", | ||||
| 		.data = &innolux_at043tn24, | ||||
| 	}, { | ||||
| 		.compatible ="innolux,g121i1-l01", | ||||
| 		.data = &innolux_g121i1_l01 | ||||
| @ -834,12 +1052,24 @@ static const struct of_device_id platform_of_match[] = { | ||||
| 	}, { | ||||
| 		.compatible = "innolux,n156bge-l21", | ||||
| 		.data = &innolux_n156bge_l21, | ||||
| 	}, { | ||||
| 		.compatible = "innolux,zj070na-01p", | ||||
| 		.data = &innolux_zj070na_01p, | ||||
| 	}, { | ||||
| 		.compatible = "lg,lp129qe", | ||||
| 		.data = &lg_lp129qe, | ||||
| 	}, { | ||||
| 		.compatible = "ortustech,com43h4m85ulc", | ||||
| 		.data = &ortustech_com43h4m85ulc, | ||||
| 	}, { | ||||
| 		.compatible = "samsung,ltn101nt05", | ||||
| 		.data = &samsung_ltn101nt05, | ||||
| 	}, { | ||||
| 		.compatible = "samsung,ltn140at29-301", | ||||
| 		.data = &samsung_ltn140at29_301, | ||||
| 	}, { | ||||
| 		.compatible = "shelly,sca07010-bfn-lnn", | ||||
| 		.data = &shelly_sca07010_bfn_lnn, | ||||
| 	}, { | ||||
| 		/* sentinel */ | ||||
| 	} | ||||
|  | ||||
| @ -53,7 +53,6 @@ struct fence; | ||||
| #define DRM_MODE_OBJECT_FB 0xfbfbfbfb | ||||
| #define DRM_MODE_OBJECT_BLOB 0xbbbbbbbb | ||||
| #define DRM_MODE_OBJECT_PLANE 0xeeeeeeee | ||||
| #define DRM_MODE_OBJECT_BRIDGE 0xbdbdbdbd | ||||
| #define DRM_MODE_OBJECT_ANY 0 | ||||
| 
 | ||||
| struct drm_mode_object { | ||||
|  | ||||
| @ -29,6 +29,7 @@ | ||||
| struct drm_connector; | ||||
| struct drm_device; | ||||
| struct drm_panel; | ||||
| struct display_timing; | ||||
| 
 | ||||
| /**
 | ||||
|  * struct drm_panel_funcs - perform operations on a given panel | ||||
| @ -38,6 +39,8 @@ struct drm_panel; | ||||
|  * @enable: enable panel (turn on back light, etc.) | ||||
|  * @get_modes: add modes to the connector that the panel is attached to and | ||||
|  * return the number of modes added | ||||
|  * @get_timings: copy display timings into the provided array and return | ||||
|  * the number of display timings available | ||||
|  * | ||||
|  * The .prepare() function is typically called before the display controller | ||||
|  * starts to transmit video data. Panel drivers can use this to turn the panel | ||||
| @ -68,6 +71,8 @@ struct drm_panel_funcs { | ||||
| 	int (*prepare)(struct drm_panel *panel); | ||||
| 	int (*enable)(struct drm_panel *panel); | ||||
| 	int (*get_modes)(struct drm_panel *panel); | ||||
| 	int (*get_timings)(struct drm_panel *panel, unsigned int num_timings, | ||||
| 			   struct display_timing *timings); | ||||
| }; | ||||
| 
 | ||||
| struct drm_panel { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user