xref: /openbmc/linux/drivers/gpu/drm/i915/display/intel_dsi_vbt.c (revision c900529f3d9161bfde5cca0754f83b4d3c3e0220)
1379bc100SJani Nikula /*
2379bc100SJani Nikula  * Copyright © 2014 Intel Corporation
3379bc100SJani Nikula  *
4379bc100SJani Nikula  * Permission is hereby granted, free of charge, to any person obtaining a
5379bc100SJani Nikula  * copy of this software and associated documentation files (the "Software"),
6379bc100SJani Nikula  * to deal in the Software without restriction, including without limitation
7379bc100SJani Nikula  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8379bc100SJani Nikula  * and/or sell copies of the Software, and to permit persons to whom the
9379bc100SJani Nikula  * Software is furnished to do so, subject to the following conditions:
10379bc100SJani Nikula  *
11379bc100SJani Nikula  * The above copyright notice and this permission notice (including the next
12379bc100SJani Nikula  * paragraph) shall be included in all copies or substantial portions of the
13379bc100SJani Nikula  * Software.
14379bc100SJani Nikula  *
15379bc100SJani Nikula  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16379bc100SJani Nikula  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17379bc100SJani Nikula  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18379bc100SJani Nikula  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19379bc100SJani Nikula  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20379bc100SJani Nikula  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21379bc100SJani Nikula  * DEALINGS IN THE SOFTWARE.
22379bc100SJani Nikula  *
23379bc100SJani Nikula  * Author: Shobhit Kumar <shobhit.kumar@intel.com>
24379bc100SJani Nikula  *
25379bc100SJani Nikula  */
26379bc100SJani Nikula 
27379bc100SJani Nikula #include <linux/gpio/consumer.h>
28067d1cf7SHans de Goede #include <linux/gpio/machine.h>
29379bc100SJani Nikula #include <linux/mfd/intel_soc_pmic.h>
3025e8a383SHans de Goede #include <linux/pinctrl/consumer.h>
3125e8a383SHans de Goede #include <linux/pinctrl/machine.h>
32379bc100SJani Nikula #include <linux/slab.h>
33ff9fbe7cSLucas De Marchi #include <linux/string_helpers.h>
34379bc100SJani Nikula 
35379bc100SJani Nikula #include <asm/unaligned.h>
36379bc100SJani Nikula 
37379bc100SJani Nikula #include <drm/drm_crtc.h>
38379bc100SJani Nikula #include <drm/drm_edid.h>
39379bc100SJani Nikula 
40379bc100SJani Nikula #include <video/mipi_display.h>
41379bc100SJani Nikula 
42379bc100SJani Nikula #include "i915_drv.h"
43ce2fce25SMatt Roper #include "i915_reg.h"
44f087cfe6SJani Nikula #include "intel_de.h"
451d455f8dSJani Nikula #include "intel_display_types.h"
46379bc100SJani Nikula #include "intel_dsi.h"
47aebdd742SJani Nikula #include "intel_dsi_vbt.h"
48f087cfe6SJani Nikula #include "intel_gmbus_regs.h"
49065695b3SJani Nikula #include "intel_pps_regs.h"
507570d06dSJani Nikula #include "vlv_dsi.h"
512b72a38cSJani Nikula #include "vlv_dsi_regs.h"
521eecf31eSJani Nikula #include "vlv_sideband.h"
53379bc100SJani Nikula 
54379bc100SJani Nikula #define MIPI_TRANSFER_MODE_SHIFT	0
55379bc100SJani Nikula #define MIPI_VIRTUAL_CHANNEL_SHIFT	1
56379bc100SJani Nikula #define MIPI_PORT_SHIFT			3
57379bc100SJani Nikula 
58379bc100SJani Nikula /* base offsets for gpio pads */
59379bc100SJani Nikula #define VLV_GPIO_NC_0_HV_DDI0_HPD	0x4130
60379bc100SJani Nikula #define VLV_GPIO_NC_1_HV_DDI0_DDC_SDA	0x4120
61379bc100SJani Nikula #define VLV_GPIO_NC_2_HV_DDI0_DDC_SCL	0x4110
62379bc100SJani Nikula #define VLV_GPIO_NC_3_PANEL0_VDDEN	0x4140
63379bc100SJani Nikula #define VLV_GPIO_NC_4_PANEL0_BKLTEN	0x4150
64379bc100SJani Nikula #define VLV_GPIO_NC_5_PANEL0_BKLTCTL	0x4160
65379bc100SJani Nikula #define VLV_GPIO_NC_6_HV_DDI1_HPD	0x4180
66379bc100SJani Nikula #define VLV_GPIO_NC_7_HV_DDI1_DDC_SDA	0x4190
67379bc100SJani Nikula #define VLV_GPIO_NC_8_HV_DDI1_DDC_SCL	0x4170
68379bc100SJani Nikula #define VLV_GPIO_NC_9_PANEL1_VDDEN	0x4100
69379bc100SJani Nikula #define VLV_GPIO_NC_10_PANEL1_BKLTEN	0x40E0
70379bc100SJani Nikula #define VLV_GPIO_NC_11_PANEL1_BKLTCTL	0x40F0
71379bc100SJani Nikula 
72379bc100SJani Nikula #define VLV_GPIO_PCONF0(base_offset)	(base_offset)
73379bc100SJani Nikula #define VLV_GPIO_PAD_VAL(base_offset)	((base_offset) + 8)
74379bc100SJani Nikula 
75379bc100SJani Nikula struct gpio_map {
76379bc100SJani Nikula 	u16 base_offset;
77379bc100SJani Nikula 	bool init;
78379bc100SJani Nikula };
79379bc100SJani Nikula 
80379bc100SJani Nikula static struct gpio_map vlv_gpio_table[] = {
81379bc100SJani Nikula 	{ VLV_GPIO_NC_0_HV_DDI0_HPD },
82379bc100SJani Nikula 	{ VLV_GPIO_NC_1_HV_DDI0_DDC_SDA },
83379bc100SJani Nikula 	{ VLV_GPIO_NC_2_HV_DDI0_DDC_SCL },
84379bc100SJani Nikula 	{ VLV_GPIO_NC_3_PANEL0_VDDEN },
85379bc100SJani Nikula 	{ VLV_GPIO_NC_4_PANEL0_BKLTEN },
86379bc100SJani Nikula 	{ VLV_GPIO_NC_5_PANEL0_BKLTCTL },
87379bc100SJani Nikula 	{ VLV_GPIO_NC_6_HV_DDI1_HPD },
88379bc100SJani Nikula 	{ VLV_GPIO_NC_7_HV_DDI1_DDC_SDA },
89379bc100SJani Nikula 	{ VLV_GPIO_NC_8_HV_DDI1_DDC_SCL },
90379bc100SJani Nikula 	{ VLV_GPIO_NC_9_PANEL1_VDDEN },
91379bc100SJani Nikula 	{ VLV_GPIO_NC_10_PANEL1_BKLTEN },
92379bc100SJani Nikula 	{ VLV_GPIO_NC_11_PANEL1_BKLTCTL },
93379bc100SJani Nikula };
94379bc100SJani Nikula 
958cbf89dbSVivek Kasireddy struct i2c_adapter_lookup {
968cbf89dbSVivek Kasireddy 	u16 slave_addr;
978cbf89dbSVivek Kasireddy 	struct intel_dsi *intel_dsi;
988cbf89dbSVivek Kasireddy 	acpi_handle dev_handle;
998cbf89dbSVivek Kasireddy };
1008cbf89dbSVivek Kasireddy 
101379bc100SJani Nikula #define CHV_GPIO_IDX_START_N		0
102379bc100SJani Nikula #define CHV_GPIO_IDX_START_E		73
103379bc100SJani Nikula #define CHV_GPIO_IDX_START_SW		100
104379bc100SJani Nikula #define CHV_GPIO_IDX_START_SE		198
105379bc100SJani Nikula 
106379bc100SJani Nikula #define CHV_VBT_MAX_PINS_PER_FMLY	15
107379bc100SJani Nikula 
108379bc100SJani Nikula #define CHV_GPIO_PAD_CFG0(f, i)		(0x4400 + (f) * 0x400 + (i) * 8)
109379bc100SJani Nikula #define  CHV_GPIO_GPIOEN		(1 << 15)
110379bc100SJani Nikula #define  CHV_GPIO_GPIOCFG_GPIO		(0 << 8)
111379bc100SJani Nikula #define  CHV_GPIO_GPIOCFG_GPO		(1 << 8)
112379bc100SJani Nikula #define  CHV_GPIO_GPIOCFG_GPI		(2 << 8)
113379bc100SJani Nikula #define  CHV_GPIO_GPIOCFG_HIZ		(3 << 8)
114379bc100SJani Nikula #define  CHV_GPIO_GPIOTXSTATE(state)	((!!(state)) << 1)
115379bc100SJani Nikula 
116379bc100SJani Nikula #define CHV_GPIO_PAD_CFG1(f, i)		(0x4400 + (f) * 0x400 + (i) * 8 + 4)
117379bc100SJani Nikula #define  CHV_GPIO_CFGLOCK		(1 << 31)
118379bc100SJani Nikula 
119379bc100SJani Nikula /* ICL DSI Display GPIO Pins */
120379bc100SJani Nikula #define  ICL_GPIO_DDSP_HPD_A		0
121379bc100SJani Nikula #define  ICL_GPIO_L_VDDEN_1		1
122379bc100SJani Nikula #define  ICL_GPIO_L_BKLTEN_1		2
123379bc100SJani Nikula #define  ICL_GPIO_DDPA_CTRLCLK_1	3
124379bc100SJani Nikula #define  ICL_GPIO_DDPA_CTRLDATA_1	4
125379bc100SJani Nikula #define  ICL_GPIO_DDSP_HPD_B		5
126379bc100SJani Nikula #define  ICL_GPIO_L_VDDEN_2		6
127379bc100SJani Nikula #define  ICL_GPIO_L_BKLTEN_2		7
128379bc100SJani Nikula #define  ICL_GPIO_DDPA_CTRLCLK_2	8
129379bc100SJani Nikula #define  ICL_GPIO_DDPA_CTRLDATA_2	9
130379bc100SJani Nikula 
intel_dsi_seq_port_to_port(struct intel_dsi * intel_dsi,u8 seq_port)13108c59ddeSJani Nikula static enum port intel_dsi_seq_port_to_port(struct intel_dsi *intel_dsi,
13208c59ddeSJani Nikula 					    u8 seq_port)
133379bc100SJani Nikula {
13408c59ddeSJani Nikula 	/*
13508c59ddeSJani Nikula 	 * If single link DSI is being used on any port, the VBT sequence block
13608c59ddeSJani Nikula 	 * send packet apparently always has 0 for the port. Just use the port
13708c59ddeSJani Nikula 	 * we have configured, and ignore the sequence block port.
13808c59ddeSJani Nikula 	 */
13908c59ddeSJani Nikula 	if (hweight8(intel_dsi->ports) == 1)
14008c59ddeSJani Nikula 		return ffs(intel_dsi->ports) - 1;
14108c59ddeSJani Nikula 
14208c59ddeSJani Nikula 	if (seq_port) {
1438d58bb79SMikko Kovanen 		if (intel_dsi->ports & BIT(PORT_B))
14408c59ddeSJani Nikula 			return PORT_B;
1458d58bb79SMikko Kovanen 		else if (intel_dsi->ports & BIT(PORT_C))
14608c59ddeSJani Nikula 			return PORT_C;
14708c59ddeSJani Nikula 	}
14808c59ddeSJani Nikula 
14908c59ddeSJani Nikula 	return PORT_A;
150379bc100SJani Nikula }
151379bc100SJani Nikula 
mipi_exec_send_packet(struct intel_dsi * intel_dsi,const u8 * data)152379bc100SJani Nikula static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
153379bc100SJani Nikula 				       const u8 *data)
154379bc100SJani Nikula {
155379bc100SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
156379bc100SJani Nikula 	struct mipi_dsi_device *dsi_device;
157379bc100SJani Nikula 	u8 type, flags, seq_port;
158379bc100SJani Nikula 	u16 len;
159379bc100SJani Nikula 	enum port port;
160379bc100SJani Nikula 
161e8441414SWambui Karuga 	drm_dbg_kms(&dev_priv->drm, "\n");
162379bc100SJani Nikula 
163379bc100SJani Nikula 	flags = *data++;
164379bc100SJani Nikula 	type = *data++;
165379bc100SJani Nikula 
166379bc100SJani Nikula 	len = *((u16 *) data);
167379bc100SJani Nikula 	data += 2;
168379bc100SJani Nikula 
169379bc100SJani Nikula 	seq_port = (flags >> MIPI_PORT_SHIFT) & 3;
170379bc100SJani Nikula 
17108c59ddeSJani Nikula 	port = intel_dsi_seq_port_to_port(intel_dsi, seq_port);
17208c59ddeSJani Nikula 
17308c59ddeSJani Nikula 	if (drm_WARN_ON(&dev_priv->drm, !intel_dsi->dsi_hosts[port]))
17408c59ddeSJani Nikula 		goto out;
175379bc100SJani Nikula 
176379bc100SJani Nikula 	dsi_device = intel_dsi->dsi_hosts[port]->device;
177379bc100SJani Nikula 	if (!dsi_device) {
178e8441414SWambui Karuga 		drm_dbg_kms(&dev_priv->drm, "no dsi device for port %c\n",
179e8441414SWambui Karuga 			    port_name(port));
180379bc100SJani Nikula 		goto out;
181379bc100SJani Nikula 	}
182379bc100SJani Nikula 
183379bc100SJani Nikula 	if ((flags >> MIPI_TRANSFER_MODE_SHIFT) & 1)
184379bc100SJani Nikula 		dsi_device->mode_flags &= ~MIPI_DSI_MODE_LPM;
185379bc100SJani Nikula 	else
186379bc100SJani Nikula 		dsi_device->mode_flags |= MIPI_DSI_MODE_LPM;
187379bc100SJani Nikula 
188379bc100SJani Nikula 	dsi_device->channel = (flags >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 3;
189379bc100SJani Nikula 
190379bc100SJani Nikula 	switch (type) {
191379bc100SJani Nikula 	case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
192379bc100SJani Nikula 		mipi_dsi_generic_write(dsi_device, NULL, 0);
193379bc100SJani Nikula 		break;
194379bc100SJani Nikula 	case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
195379bc100SJani Nikula 		mipi_dsi_generic_write(dsi_device, data, 1);
196379bc100SJani Nikula 		break;
197379bc100SJani Nikula 	case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
198379bc100SJani Nikula 		mipi_dsi_generic_write(dsi_device, data, 2);
199379bc100SJani Nikula 		break;
200379bc100SJani Nikula 	case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
201379bc100SJani Nikula 	case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
202379bc100SJani Nikula 	case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
203e8441414SWambui Karuga 		drm_dbg(&dev_priv->drm,
204e8441414SWambui Karuga 			"Generic Read not yet implemented or used\n");
205379bc100SJani Nikula 		break;
206379bc100SJani Nikula 	case MIPI_DSI_GENERIC_LONG_WRITE:
207379bc100SJani Nikula 		mipi_dsi_generic_write(dsi_device, data, len);
208379bc100SJani Nikula 		break;
209379bc100SJani Nikula 	case MIPI_DSI_DCS_SHORT_WRITE:
210379bc100SJani Nikula 		mipi_dsi_dcs_write_buffer(dsi_device, data, 1);
211379bc100SJani Nikula 		break;
212379bc100SJani Nikula 	case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
213379bc100SJani Nikula 		mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
214379bc100SJani Nikula 		break;
215379bc100SJani Nikula 	case MIPI_DSI_DCS_READ:
216e8441414SWambui Karuga 		drm_dbg(&dev_priv->drm,
217e8441414SWambui Karuga 			"DCS Read not yet implemented or used\n");
218379bc100SJani Nikula 		break;
219379bc100SJani Nikula 	case MIPI_DSI_DCS_LONG_WRITE:
220379bc100SJani Nikula 		mipi_dsi_dcs_write_buffer(dsi_device, data, len);
221379bc100SJani Nikula 		break;
222379bc100SJani Nikula 	}
223379bc100SJani Nikula 
224005e9537SMatt Roper 	if (DISPLAY_VER(dev_priv) < 11)
225379bc100SJani Nikula 		vlv_dsi_wait_for_fifo_empty(intel_dsi, port);
226379bc100SJani Nikula 
227379bc100SJani Nikula out:
228379bc100SJani Nikula 	data += len;
229379bc100SJani Nikula 
230379bc100SJani Nikula 	return data;
231379bc100SJani Nikula }
232379bc100SJani Nikula 
mipi_exec_delay(struct intel_dsi * intel_dsi,const u8 * data)233379bc100SJani Nikula static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data)
234379bc100SJani Nikula {
235e8441414SWambui Karuga 	struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev);
236379bc100SJani Nikula 	u32 delay = *((const u32 *) data);
237379bc100SJani Nikula 
238*ad522086SVille Syrjälä 	drm_dbg_kms(&i915->drm, "%d usecs\n", delay);
239379bc100SJani Nikula 
240379bc100SJani Nikula 	usleep_range(delay, delay + 10);
241379bc100SJani Nikula 	data += 4;
242379bc100SJani Nikula 
243379bc100SJani Nikula 	return data;
244379bc100SJani Nikula }
245379bc100SJani Nikula 
vlv_exec_gpio(struct intel_connector * connector,u8 gpio_source,u8 gpio_index,bool value)2463cf05076SVille Syrjälä static void vlv_exec_gpio(struct intel_connector *connector,
247379bc100SJani Nikula 			  u8 gpio_source, u8 gpio_index, bool value)
248379bc100SJani Nikula {
2493cf05076SVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
250379bc100SJani Nikula 	struct gpio_map *map;
251379bc100SJani Nikula 	u16 pconf0, padval;
252379bc100SJani Nikula 	u32 tmp;
253379bc100SJani Nikula 	u8 port;
254379bc100SJani Nikula 
255379bc100SJani Nikula 	if (gpio_index >= ARRAY_SIZE(vlv_gpio_table)) {
256e8441414SWambui Karuga 		drm_dbg_kms(&dev_priv->drm, "unknown gpio index %u\n",
257e8441414SWambui Karuga 			    gpio_index);
258379bc100SJani Nikula 		return;
259379bc100SJani Nikula 	}
260379bc100SJani Nikula 
261379bc100SJani Nikula 	map = &vlv_gpio_table[gpio_index];
262379bc100SJani Nikula 
2633cf05076SVille Syrjälä 	if (connector->panel.vbt.dsi.seq_version >= 3) {
264379bc100SJani Nikula 		/* XXX: this assumes vlv_gpio_table only has NC GPIOs. */
265379bc100SJani Nikula 		port = IOSF_PORT_GPIO_NC;
266379bc100SJani Nikula 	} else {
267379bc100SJani Nikula 		if (gpio_source == 0) {
268379bc100SJani Nikula 			port = IOSF_PORT_GPIO_NC;
269379bc100SJani Nikula 		} else if (gpio_source == 1) {
270e8441414SWambui Karuga 			drm_dbg_kms(&dev_priv->drm, "SC gpio not supported\n");
271379bc100SJani Nikula 			return;
272379bc100SJani Nikula 		} else {
273e8441414SWambui Karuga 			drm_dbg_kms(&dev_priv->drm,
274e8441414SWambui Karuga 				    "unknown gpio source %u\n", gpio_source);
275379bc100SJani Nikula 			return;
276379bc100SJani Nikula 		}
277379bc100SJani Nikula 	}
278379bc100SJani Nikula 
279379bc100SJani Nikula 	pconf0 = VLV_GPIO_PCONF0(map->base_offset);
280379bc100SJani Nikula 	padval = VLV_GPIO_PAD_VAL(map->base_offset);
281379bc100SJani Nikula 
282379bc100SJani Nikula 	vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO));
283379bc100SJani Nikula 	if (!map->init) {
284379bc100SJani Nikula 		/* FIXME: remove constant below */
285379bc100SJani Nikula 		vlv_iosf_sb_write(dev_priv, port, pconf0, 0x2000CC00);
286379bc100SJani Nikula 		map->init = true;
287379bc100SJani Nikula 	}
288379bc100SJani Nikula 
289379bc100SJani Nikula 	tmp = 0x4 | value;
290379bc100SJani Nikula 	vlv_iosf_sb_write(dev_priv, port, padval, tmp);
291379bc100SJani Nikula 	vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO));
292379bc100SJani Nikula }
293379bc100SJani Nikula 
chv_exec_gpio(struct intel_connector * connector,u8 gpio_source,u8 gpio_index,bool value)2943cf05076SVille Syrjälä static void chv_exec_gpio(struct intel_connector *connector,
295379bc100SJani Nikula 			  u8 gpio_source, u8 gpio_index, bool value)
296379bc100SJani Nikula {
2973cf05076SVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
298379bc100SJani Nikula 	u16 cfg0, cfg1;
299379bc100SJani Nikula 	u16 family_num;
300379bc100SJani Nikula 	u8 port;
301379bc100SJani Nikula 
3023cf05076SVille Syrjälä 	if (connector->panel.vbt.dsi.seq_version >= 3) {
303379bc100SJani Nikula 		if (gpio_index >= CHV_GPIO_IDX_START_SE) {
304379bc100SJani Nikula 			/* XXX: it's unclear whether 255->57 is part of SE. */
305379bc100SJani Nikula 			gpio_index -= CHV_GPIO_IDX_START_SE;
306379bc100SJani Nikula 			port = CHV_IOSF_PORT_GPIO_SE;
307379bc100SJani Nikula 		} else if (gpio_index >= CHV_GPIO_IDX_START_SW) {
308379bc100SJani Nikula 			gpio_index -= CHV_GPIO_IDX_START_SW;
309379bc100SJani Nikula 			port = CHV_IOSF_PORT_GPIO_SW;
310379bc100SJani Nikula 		} else if (gpio_index >= CHV_GPIO_IDX_START_E) {
311379bc100SJani Nikula 			gpio_index -= CHV_GPIO_IDX_START_E;
312379bc100SJani Nikula 			port = CHV_IOSF_PORT_GPIO_E;
313379bc100SJani Nikula 		} else {
314379bc100SJani Nikula 			port = CHV_IOSF_PORT_GPIO_N;
315379bc100SJani Nikula 		}
316379bc100SJani Nikula 	} else {
317379bc100SJani Nikula 		/* XXX: The spec is unclear about CHV GPIO on seq v2 */
318379bc100SJani Nikula 		if (gpio_source != 0) {
319e8441414SWambui Karuga 			drm_dbg_kms(&dev_priv->drm,
320e8441414SWambui Karuga 				    "unknown gpio source %u\n", gpio_source);
321379bc100SJani Nikula 			return;
322379bc100SJani Nikula 		}
323379bc100SJani Nikula 
324379bc100SJani Nikula 		if (gpio_index >= CHV_GPIO_IDX_START_E) {
325e8441414SWambui Karuga 			drm_dbg_kms(&dev_priv->drm,
326e8441414SWambui Karuga 				    "invalid gpio index %u for GPIO N\n",
327379bc100SJani Nikula 				    gpio_index);
328379bc100SJani Nikula 			return;
329379bc100SJani Nikula 		}
330379bc100SJani Nikula 
331379bc100SJani Nikula 		port = CHV_IOSF_PORT_GPIO_N;
332379bc100SJani Nikula 	}
333379bc100SJani Nikula 
334379bc100SJani Nikula 	family_num = gpio_index / CHV_VBT_MAX_PINS_PER_FMLY;
335379bc100SJani Nikula 	gpio_index = gpio_index % CHV_VBT_MAX_PINS_PER_FMLY;
336379bc100SJani Nikula 
337379bc100SJani Nikula 	cfg0 = CHV_GPIO_PAD_CFG0(family_num, gpio_index);
338379bc100SJani Nikula 	cfg1 = CHV_GPIO_PAD_CFG1(family_num, gpio_index);
339379bc100SJani Nikula 
340379bc100SJani Nikula 	vlv_iosf_sb_get(dev_priv, BIT(VLV_IOSF_SB_GPIO));
341379bc100SJani Nikula 	vlv_iosf_sb_write(dev_priv, port, cfg1, 0);
342379bc100SJani Nikula 	vlv_iosf_sb_write(dev_priv, port, cfg0,
343379bc100SJani Nikula 			  CHV_GPIO_GPIOEN | CHV_GPIO_GPIOCFG_GPO |
344379bc100SJani Nikula 			  CHV_GPIO_GPIOTXSTATE(value));
345379bc100SJani Nikula 	vlv_iosf_sb_put(dev_priv, BIT(VLV_IOSF_SB_GPIO));
346379bc100SJani Nikula }
347379bc100SJani Nikula 
bxt_exec_gpio(struct intel_connector * connector,u8 gpio_source,u8 gpio_index,bool value)3483cf05076SVille Syrjälä static void bxt_exec_gpio(struct intel_connector *connector,
349379bc100SJani Nikula 			  u8 gpio_source, u8 gpio_index, bool value)
350379bc100SJani Nikula {
3513cf05076SVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
352379bc100SJani Nikula 	/* XXX: this table is a quick ugly hack. */
353379bc100SJani Nikula 	static struct gpio_desc *bxt_gpio_table[U8_MAX + 1];
354379bc100SJani Nikula 	struct gpio_desc *gpio_desc = bxt_gpio_table[gpio_index];
355379bc100SJani Nikula 
356379bc100SJani Nikula 	if (!gpio_desc) {
357379bc100SJani Nikula 		gpio_desc = devm_gpiod_get_index(dev_priv->drm.dev,
358379bc100SJani Nikula 						 NULL, gpio_index,
359379bc100SJani Nikula 						 value ? GPIOD_OUT_LOW :
360379bc100SJani Nikula 						 GPIOD_OUT_HIGH);
361379bc100SJani Nikula 
362379bc100SJani Nikula 		if (IS_ERR_OR_NULL(gpio_desc)) {
363e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
364e8441414SWambui Karuga 				"GPIO index %u request failed (%ld)\n",
365379bc100SJani Nikula 				gpio_index, PTR_ERR(gpio_desc));
366379bc100SJani Nikula 			return;
367379bc100SJani Nikula 		}
368379bc100SJani Nikula 
369379bc100SJani Nikula 		bxt_gpio_table[gpio_index] = gpio_desc;
370379bc100SJani Nikula 	}
371379bc100SJani Nikula 
372379bc100SJani Nikula 	gpiod_set_value(gpio_desc, value);
373379bc100SJani Nikula }
374379bc100SJani Nikula 
icl_exec_gpio(struct intel_connector * connector,u8 gpio_source,u8 gpio_index,bool value)3753cf05076SVille Syrjälä static void icl_exec_gpio(struct intel_connector *connector,
376379bc100SJani Nikula 			  u8 gpio_source, u8 gpio_index, bool value)
377379bc100SJani Nikula {
3783cf05076SVille Syrjälä 	struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
3793cf05076SVille Syrjälä 
380e8441414SWambui Karuga 	drm_dbg_kms(&dev_priv->drm, "Skipping ICL GPIO element execution\n");
381379bc100SJani Nikula }
382379bc100SJani Nikula 
383f087cfe6SJani Nikula enum {
384f087cfe6SJani Nikula 	MIPI_RESET_1 = 0,
385f087cfe6SJani Nikula 	MIPI_AVDD_EN_1,
386f087cfe6SJani Nikula 	MIPI_BKLT_EN_1,
387f087cfe6SJani Nikula 	MIPI_AVEE_EN_1,
388f087cfe6SJani Nikula 	MIPI_VIO_EN_1,
389f087cfe6SJani Nikula 	MIPI_RESET_2,
390f087cfe6SJani Nikula 	MIPI_AVDD_EN_2,
391f087cfe6SJani Nikula 	MIPI_BKLT_EN_2,
392f087cfe6SJani Nikula 	MIPI_AVEE_EN_2,
393f087cfe6SJani Nikula 	MIPI_VIO_EN_2,
394f087cfe6SJani Nikula };
395f087cfe6SJani Nikula 
icl_native_gpio_set_value(struct drm_i915_private * dev_priv,int gpio,bool value)396f087cfe6SJani Nikula static void icl_native_gpio_set_value(struct drm_i915_private *dev_priv,
397f087cfe6SJani Nikula 				      int gpio, bool value)
398f087cfe6SJani Nikula {
399f087cfe6SJani Nikula 	int index;
400f087cfe6SJani Nikula 
401f087cfe6SJani Nikula 	if (drm_WARN_ON(&dev_priv->drm, DISPLAY_VER(dev_priv) == 11 && gpio >= MIPI_RESET_2))
402f087cfe6SJani Nikula 		return;
403f087cfe6SJani Nikula 
404f087cfe6SJani Nikula 	switch (gpio) {
405f087cfe6SJani Nikula 	case MIPI_RESET_1:
406f087cfe6SJani Nikula 	case MIPI_RESET_2:
407f087cfe6SJani Nikula 		index = gpio == MIPI_RESET_1 ? HPD_PORT_A : HPD_PORT_B;
408f087cfe6SJani Nikula 
409f087cfe6SJani Nikula 		/*
410f087cfe6SJani Nikula 		 * Disable HPD to set the pin to output, and set output
411f087cfe6SJani Nikula 		 * value. The HPD pin should not be enabled for DSI anyway,
412f087cfe6SJani Nikula 		 * assuming the board design and VBT are sane, and the pin isn't
413f087cfe6SJani Nikula 		 * used by a non-DSI encoder.
414f087cfe6SJani Nikula 		 *
415f087cfe6SJani Nikula 		 * The locking protects against concurrent SHOTPLUG_CTL_DDI
416f087cfe6SJani Nikula 		 * modifications in irq setup and handling.
417f087cfe6SJani Nikula 		 */
418f087cfe6SJani Nikula 		spin_lock_irq(&dev_priv->irq_lock);
419f087cfe6SJani Nikula 		intel_de_rmw(dev_priv, SHOTPLUG_CTL_DDI,
420f087cfe6SJani Nikula 			     SHOTPLUG_CTL_DDI_HPD_ENABLE(index) |
421f087cfe6SJani Nikula 			     SHOTPLUG_CTL_DDI_HPD_OUTPUT_DATA(index),
422f087cfe6SJani Nikula 			     value ? SHOTPLUG_CTL_DDI_HPD_OUTPUT_DATA(index) : 0);
423f087cfe6SJani Nikula 		spin_unlock_irq(&dev_priv->irq_lock);
424f087cfe6SJani Nikula 		break;
425f087cfe6SJani Nikula 	case MIPI_AVDD_EN_1:
426f087cfe6SJani Nikula 	case MIPI_AVDD_EN_2:
427f087cfe6SJani Nikula 		index = gpio == MIPI_AVDD_EN_1 ? 0 : 1;
428f087cfe6SJani Nikula 
429f087cfe6SJani Nikula 		intel_de_rmw(dev_priv, PP_CONTROL(index), PANEL_POWER_ON,
430f087cfe6SJani Nikula 			     value ? PANEL_POWER_ON : 0);
431f087cfe6SJani Nikula 		break;
432f087cfe6SJani Nikula 	case MIPI_BKLT_EN_1:
433f087cfe6SJani Nikula 	case MIPI_BKLT_EN_2:
434a561933cSJani Nikula 		index = gpio == MIPI_BKLT_EN_1 ? 0 : 1;
435f087cfe6SJani Nikula 
436f087cfe6SJani Nikula 		intel_de_rmw(dev_priv, PP_CONTROL(index), EDP_BLC_ENABLE,
437f087cfe6SJani Nikula 			     value ? EDP_BLC_ENABLE : 0);
438f087cfe6SJani Nikula 		break;
439f087cfe6SJani Nikula 	case MIPI_AVEE_EN_1:
440f087cfe6SJani Nikula 	case MIPI_AVEE_EN_2:
441f087cfe6SJani Nikula 		index = gpio == MIPI_AVEE_EN_1 ? 1 : 2;
442f087cfe6SJani Nikula 
443f087cfe6SJani Nikula 		intel_de_rmw(dev_priv, GPIO(dev_priv, index),
444f087cfe6SJani Nikula 			     GPIO_CLOCK_VAL_OUT,
445f087cfe6SJani Nikula 			     GPIO_CLOCK_DIR_MASK | GPIO_CLOCK_DIR_OUT |
446f087cfe6SJani Nikula 			     GPIO_CLOCK_VAL_MASK | (value ? GPIO_CLOCK_VAL_OUT : 0));
447f087cfe6SJani Nikula 		break;
448f087cfe6SJani Nikula 	case MIPI_VIO_EN_1:
449f087cfe6SJani Nikula 	case MIPI_VIO_EN_2:
450f087cfe6SJani Nikula 		index = gpio == MIPI_VIO_EN_1 ? 1 : 2;
451f087cfe6SJani Nikula 
452f087cfe6SJani Nikula 		intel_de_rmw(dev_priv, GPIO(dev_priv, index),
453f087cfe6SJani Nikula 			     GPIO_DATA_VAL_OUT,
454f087cfe6SJani Nikula 			     GPIO_DATA_DIR_MASK | GPIO_DATA_DIR_OUT |
455f087cfe6SJani Nikula 			     GPIO_DATA_VAL_MASK | (value ? GPIO_DATA_VAL_OUT : 0));
456f087cfe6SJani Nikula 		break;
457f087cfe6SJani Nikula 	default:
458f087cfe6SJani Nikula 		MISSING_CASE(gpio);
459f087cfe6SJani Nikula 	}
460f087cfe6SJani Nikula }
461f087cfe6SJani Nikula 
mipi_exec_gpio(struct intel_dsi * intel_dsi,const u8 * data)462379bc100SJani Nikula static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
463379bc100SJani Nikula {
464379bc100SJani Nikula 	struct drm_device *dev = intel_dsi->base.base.dev;
465379bc100SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(dev);
4663cf05076SVille Syrjälä 	struct intel_connector *connector = intel_dsi->attached_connector;
467379bc100SJani Nikula 	u8 gpio_source, gpio_index = 0, gpio_number;
468379bc100SJani Nikula 	bool value;
469f087cfe6SJani Nikula 	bool native = DISPLAY_VER(dev_priv) >= 11;
470379bc100SJani Nikula 
4713cf05076SVille Syrjälä 	if (connector->panel.vbt.dsi.seq_version >= 3)
472379bc100SJani Nikula 		gpio_index = *data++;
473379bc100SJani Nikula 
474379bc100SJani Nikula 	gpio_number = *data++;
475379bc100SJani Nikula 
476379bc100SJani Nikula 	/* gpio source in sequence v2 only */
4773cf05076SVille Syrjälä 	if (connector->panel.vbt.dsi.seq_version == 2)
478379bc100SJani Nikula 		gpio_source = (*data >> 1) & 3;
479379bc100SJani Nikula 	else
480379bc100SJani Nikula 		gpio_source = 0;
481379bc100SJani Nikula 
482f087cfe6SJani Nikula 	if (connector->panel.vbt.dsi.seq_version >= 4 && *data & BIT(1))
483f087cfe6SJani Nikula 		native = false;
484f087cfe6SJani Nikula 
485379bc100SJani Nikula 	/* pull up/down */
486379bc100SJani Nikula 	value = *data++ & 1;
487379bc100SJani Nikula 
488f087cfe6SJani Nikula 	drm_dbg_kms(&dev_priv->drm, "GPIO index %u, number %u, source %u, native %s, set to %s\n",
489f087cfe6SJani Nikula 		    gpio_index, gpio_number, gpio_source, str_yes_no(native), str_on_off(value));
490f087cfe6SJani Nikula 
491f087cfe6SJani Nikula 	if (native)
492f087cfe6SJani Nikula 		icl_native_gpio_set_value(dev_priv, gpio_number, value);
493f087cfe6SJani Nikula 	else if (DISPLAY_VER(dev_priv) >= 11)
4943cf05076SVille Syrjälä 		icl_exec_gpio(connector, gpio_source, gpio_index, value);
495379bc100SJani Nikula 	else if (IS_VALLEYVIEW(dev_priv))
4963cf05076SVille Syrjälä 		vlv_exec_gpio(connector, gpio_source, gpio_number, value);
497379bc100SJani Nikula 	else if (IS_CHERRYVIEW(dev_priv))
4983cf05076SVille Syrjälä 		chv_exec_gpio(connector, gpio_source, gpio_number, value);
499379bc100SJani Nikula 	else
5003cf05076SVille Syrjälä 		bxt_exec_gpio(connector, gpio_source, gpio_index, value);
501379bc100SJani Nikula 
502379bc100SJani Nikula 	return data;
503379bc100SJani Nikula }
504379bc100SJani Nikula 
505960287caSVivek Kasireddy #ifdef CONFIG_ACPI
i2c_adapter_lookup(struct acpi_resource * ares,void * data)5068cbf89dbSVivek Kasireddy static int i2c_adapter_lookup(struct acpi_resource *ares, void *data)
5078cbf89dbSVivek Kasireddy {
5088cbf89dbSVivek Kasireddy 	struct i2c_adapter_lookup *lookup = data;
5098cbf89dbSVivek Kasireddy 	struct intel_dsi *intel_dsi = lookup->intel_dsi;
5108cbf89dbSVivek Kasireddy 	struct acpi_resource_i2c_serialbus *sb;
5118cbf89dbSVivek Kasireddy 	struct i2c_adapter *adapter;
5128cbf89dbSVivek Kasireddy 	acpi_handle adapter_handle;
5138cbf89dbSVivek Kasireddy 	acpi_status status;
5148cbf89dbSVivek Kasireddy 
515de409661SVivek Kasireddy 	if (!i2c_acpi_get_i2c_resource(ares, &sb))
5168cbf89dbSVivek Kasireddy 		return 1;
5178cbf89dbSVivek Kasireddy 
5188cbf89dbSVivek Kasireddy 	if (lookup->slave_addr != sb->slave_address)
5198cbf89dbSVivek Kasireddy 		return 1;
5208cbf89dbSVivek Kasireddy 
5218cbf89dbSVivek Kasireddy 	status = acpi_get_handle(lookup->dev_handle,
5228cbf89dbSVivek Kasireddy 				 sb->resource_source.string_ptr,
5238cbf89dbSVivek Kasireddy 				 &adapter_handle);
5248cbf89dbSVivek Kasireddy 	if (ACPI_FAILURE(status))
5258cbf89dbSVivek Kasireddy 		return 1;
5268cbf89dbSVivek Kasireddy 
5278cbf89dbSVivek Kasireddy 	adapter = i2c_acpi_find_adapter_by_handle(adapter_handle);
5288cbf89dbSVivek Kasireddy 	if (adapter)
5298cbf89dbSVivek Kasireddy 		intel_dsi->i2c_bus_num = adapter->nr;
5308cbf89dbSVivek Kasireddy 
5318cbf89dbSVivek Kasireddy 	return 1;
5328cbf89dbSVivek Kasireddy }
5338cbf89dbSVivek Kasireddy 
i2c_acpi_find_adapter(struct intel_dsi * intel_dsi,const u16 slave_addr)534960287caSVivek Kasireddy static void i2c_acpi_find_adapter(struct intel_dsi *intel_dsi,
535960287caSVivek Kasireddy 				  const u16 slave_addr)
536379bc100SJani Nikula {
5378cbf89dbSVivek Kasireddy 	struct drm_device *drm_dev = intel_dsi->base.base.dev;
538f7747be1SAndy Shevchenko 	struct acpi_device *adev = ACPI_COMPANION(drm_dev->dev);
539f7747be1SAndy Shevchenko 	struct i2c_adapter_lookup lookup = {
540f7747be1SAndy Shevchenko 		.slave_addr = slave_addr,
541f7747be1SAndy Shevchenko 		.intel_dsi = intel_dsi,
542f7747be1SAndy Shevchenko 		.dev_handle = acpi_device_handle(adev),
543f7747be1SAndy Shevchenko 	};
544f7747be1SAndy Shevchenko 	LIST_HEAD(resource_list);
5458cbf89dbSVivek Kasireddy 
546f7747be1SAndy Shevchenko 	acpi_dev_get_resources(adev, &resource_list, i2c_adapter_lookup, &lookup);
5478cbf89dbSVivek Kasireddy 	acpi_dev_free_resource_list(&resource_list);
5488cbf89dbSVivek Kasireddy }
549960287caSVivek Kasireddy #else
i2c_acpi_find_adapter(struct intel_dsi * intel_dsi,const u16 slave_addr)550960287caSVivek Kasireddy static inline void i2c_acpi_find_adapter(struct intel_dsi *intel_dsi,
551960287caSVivek Kasireddy 					 const u16 slave_addr)
552960287caSVivek Kasireddy {
553960287caSVivek Kasireddy }
554960287caSVivek Kasireddy #endif
555960287caSVivek Kasireddy 
mipi_exec_i2c(struct intel_dsi * intel_dsi,const u8 * data)556960287caSVivek Kasireddy static const u8 *mipi_exec_i2c(struct intel_dsi *intel_dsi, const u8 *data)
557960287caSVivek Kasireddy {
558dd10a80fSJani Nikula 	struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev);
559960287caSVivek Kasireddy 	struct i2c_adapter *adapter;
560960287caSVivek Kasireddy 	struct i2c_msg msg;
561960287caSVivek Kasireddy 	int ret;
562960287caSVivek Kasireddy 	u8 vbt_i2c_bus_num = *(data + 2);
563960287caSVivek Kasireddy 	u16 slave_addr = *(u16 *)(data + 3);
564960287caSVivek Kasireddy 	u8 reg_offset = *(data + 5);
565960287caSVivek Kasireddy 	u8 payload_size = *(data + 6);
566960287caSVivek Kasireddy 	u8 *payload_data;
567960287caSVivek Kasireddy 
568960287caSVivek Kasireddy 	if (intel_dsi->i2c_bus_num < 0) {
569960287caSVivek Kasireddy 		intel_dsi->i2c_bus_num = vbt_i2c_bus_num;
570960287caSVivek Kasireddy 		i2c_acpi_find_adapter(intel_dsi, slave_addr);
571960287caSVivek Kasireddy 	}
5728cbf89dbSVivek Kasireddy 
5738cbf89dbSVivek Kasireddy 	adapter = i2c_get_adapter(intel_dsi->i2c_bus_num);
5748cbf89dbSVivek Kasireddy 	if (!adapter) {
575dd10a80fSJani Nikula 		drm_err(&i915->drm, "Cannot find a valid i2c bus for xfer\n");
5768cbf89dbSVivek Kasireddy 		goto err_bus;
5778cbf89dbSVivek Kasireddy 	}
5788cbf89dbSVivek Kasireddy 
5798cbf89dbSVivek Kasireddy 	payload_data = kzalloc(payload_size + 1, GFP_KERNEL);
5808cbf89dbSVivek Kasireddy 	if (!payload_data)
5818cbf89dbSVivek Kasireddy 		goto err_alloc;
5828cbf89dbSVivek Kasireddy 
5838cbf89dbSVivek Kasireddy 	payload_data[0] = reg_offset;
5848cbf89dbSVivek Kasireddy 	memcpy(&payload_data[1], (data + 7), payload_size);
5858cbf89dbSVivek Kasireddy 
5868cbf89dbSVivek Kasireddy 	msg.addr = slave_addr;
5878cbf89dbSVivek Kasireddy 	msg.flags = 0;
5888cbf89dbSVivek Kasireddy 	msg.len = payload_size + 1;
5898cbf89dbSVivek Kasireddy 	msg.buf = payload_data;
5908cbf89dbSVivek Kasireddy 
5918cbf89dbSVivek Kasireddy 	ret = i2c_transfer(adapter, &msg, 1);
5928cbf89dbSVivek Kasireddy 	if (ret < 0)
593dd10a80fSJani Nikula 		drm_err(&i915->drm,
5948cbf89dbSVivek Kasireddy 			"Failed to xfer payload of size (%u) to reg (%u)\n",
5958cbf89dbSVivek Kasireddy 			payload_size, reg_offset);
5968cbf89dbSVivek Kasireddy 
5978cbf89dbSVivek Kasireddy 	kfree(payload_data);
5988cbf89dbSVivek Kasireddy err_alloc:
5998cbf89dbSVivek Kasireddy 	i2c_put_adapter(adapter);
6008cbf89dbSVivek Kasireddy err_bus:
6018cbf89dbSVivek Kasireddy 	return data + payload_size + 7;
602379bc100SJani Nikula }
603379bc100SJani Nikula 
mipi_exec_spi(struct intel_dsi * intel_dsi,const u8 * data)604379bc100SJani Nikula static const u8 *mipi_exec_spi(struct intel_dsi *intel_dsi, const u8 *data)
605379bc100SJani Nikula {
606e8441414SWambui Karuga 	struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev);
607e8441414SWambui Karuga 
608e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Skipping SPI element execution\n");
609379bc100SJani Nikula 
610379bc100SJani Nikula 	return data + *(data + 5) + 6;
611379bc100SJani Nikula }
612379bc100SJani Nikula 
mipi_exec_pmic(struct intel_dsi * intel_dsi,const u8 * data)613379bc100SJani Nikula static const u8 *mipi_exec_pmic(struct intel_dsi *intel_dsi, const u8 *data)
614379bc100SJani Nikula {
615e8441414SWambui Karuga 	struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev);
616379bc100SJani Nikula #ifdef CONFIG_PMIC_OPREGION
617379bc100SJani Nikula 	u32 value, mask, reg_address;
618379bc100SJani Nikula 	u16 i2c_address;
619379bc100SJani Nikula 	int ret;
620379bc100SJani Nikula 
621379bc100SJani Nikula 	/* byte 0 aka PMIC Flag is reserved */
622379bc100SJani Nikula 	i2c_address	= get_unaligned_le16(data + 1);
623379bc100SJani Nikula 	reg_address	= get_unaligned_le32(data + 3);
624379bc100SJani Nikula 	value		= get_unaligned_le32(data + 7);
625379bc100SJani Nikula 	mask		= get_unaligned_le32(data + 11);
626379bc100SJani Nikula 
627379bc100SJani Nikula 	ret = intel_soc_pmic_exec_mipi_pmic_seq_element(i2c_address,
628379bc100SJani Nikula 							reg_address,
629379bc100SJani Nikula 							value, mask);
630379bc100SJani Nikula 	if (ret)
631e8441414SWambui Karuga 		drm_err(&i915->drm, "%s failed, error: %d\n", __func__, ret);
632379bc100SJani Nikula #else
633e8441414SWambui Karuga 	drm_err(&i915->drm,
634e8441414SWambui Karuga 		"Your hardware requires CONFIG_PMIC_OPREGION and it is not set\n");
635379bc100SJani Nikula #endif
636379bc100SJani Nikula 
637379bc100SJani Nikula 	return data + 15;
638379bc100SJani Nikula }
639379bc100SJani Nikula 
640379bc100SJani Nikula typedef const u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi,
641379bc100SJani Nikula 					const u8 *data);
642379bc100SJani Nikula static const fn_mipi_elem_exec exec_elem[] = {
643379bc100SJani Nikula 	[MIPI_SEQ_ELEM_SEND_PKT] = mipi_exec_send_packet,
644379bc100SJani Nikula 	[MIPI_SEQ_ELEM_DELAY] = mipi_exec_delay,
645379bc100SJani Nikula 	[MIPI_SEQ_ELEM_GPIO] = mipi_exec_gpio,
646379bc100SJani Nikula 	[MIPI_SEQ_ELEM_I2C] = mipi_exec_i2c,
647379bc100SJani Nikula 	[MIPI_SEQ_ELEM_SPI] = mipi_exec_spi,
648379bc100SJani Nikula 	[MIPI_SEQ_ELEM_PMIC] = mipi_exec_pmic,
649379bc100SJani Nikula };
650379bc100SJani Nikula 
651379bc100SJani Nikula /*
652379bc100SJani Nikula  * MIPI Sequence from VBT #53 parsing logic
653379bc100SJani Nikula  * We have already separated each seqence during bios parsing
654379bc100SJani Nikula  * Following is generic execution function for any sequence
655379bc100SJani Nikula  */
656379bc100SJani Nikula 
657379bc100SJani Nikula static const char * const seq_name[] = {
658379bc100SJani Nikula 	[MIPI_SEQ_DEASSERT_RESET] = "MIPI_SEQ_DEASSERT_RESET",
659379bc100SJani Nikula 	[MIPI_SEQ_INIT_OTP] = "MIPI_SEQ_INIT_OTP",
660379bc100SJani Nikula 	[MIPI_SEQ_DISPLAY_ON] = "MIPI_SEQ_DISPLAY_ON",
661379bc100SJani Nikula 	[MIPI_SEQ_DISPLAY_OFF]  = "MIPI_SEQ_DISPLAY_OFF",
662379bc100SJani Nikula 	[MIPI_SEQ_ASSERT_RESET] = "MIPI_SEQ_ASSERT_RESET",
663379bc100SJani Nikula 	[MIPI_SEQ_BACKLIGHT_ON] = "MIPI_SEQ_BACKLIGHT_ON",
664379bc100SJani Nikula 	[MIPI_SEQ_BACKLIGHT_OFF] = "MIPI_SEQ_BACKLIGHT_OFF",
665379bc100SJani Nikula 	[MIPI_SEQ_TEAR_ON] = "MIPI_SEQ_TEAR_ON",
666379bc100SJani Nikula 	[MIPI_SEQ_TEAR_OFF] = "MIPI_SEQ_TEAR_OFF",
667379bc100SJani Nikula 	[MIPI_SEQ_POWER_ON] = "MIPI_SEQ_POWER_ON",
668379bc100SJani Nikula 	[MIPI_SEQ_POWER_OFF] = "MIPI_SEQ_POWER_OFF",
669379bc100SJani Nikula };
670379bc100SJani Nikula 
sequence_name(enum mipi_seq seq_id)671379bc100SJani Nikula static const char *sequence_name(enum mipi_seq seq_id)
672379bc100SJani Nikula {
673379bc100SJani Nikula 	if (seq_id < ARRAY_SIZE(seq_name) && seq_name[seq_id])
674379bc100SJani Nikula 		return seq_name[seq_id];
675379bc100SJani Nikula 	else
676379bc100SJani Nikula 		return "(unknown)";
677379bc100SJani Nikula }
678379bc100SJani Nikula 
intel_dsi_vbt_exec(struct intel_dsi * intel_dsi,enum mipi_seq seq_id)679ea0fe672SHans de Goede static void intel_dsi_vbt_exec(struct intel_dsi *intel_dsi,
680379bc100SJani Nikula 			       enum mipi_seq seq_id)
681379bc100SJani Nikula {
682379bc100SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(intel_dsi->base.base.dev);
6833cf05076SVille Syrjälä 	struct intel_connector *connector = intel_dsi->attached_connector;
684379bc100SJani Nikula 	const u8 *data;
685379bc100SJani Nikula 	fn_mipi_elem_exec mipi_elem_exec;
686379bc100SJani Nikula 
687f4224a4cSPankaj Bharadiya 	if (drm_WARN_ON(&dev_priv->drm,
6883cf05076SVille Syrjälä 			seq_id >= ARRAY_SIZE(connector->panel.vbt.dsi.sequence)))
689379bc100SJani Nikula 		return;
690379bc100SJani Nikula 
6913cf05076SVille Syrjälä 	data = connector->panel.vbt.dsi.sequence[seq_id];
692379bc100SJani Nikula 	if (!data)
693379bc100SJani Nikula 		return;
694379bc100SJani Nikula 
695f4224a4cSPankaj Bharadiya 	drm_WARN_ON(&dev_priv->drm, *data != seq_id);
696379bc100SJani Nikula 
697e8441414SWambui Karuga 	drm_dbg_kms(&dev_priv->drm, "Starting MIPI sequence %d - %s\n",
698379bc100SJani Nikula 		    seq_id, sequence_name(seq_id));
699379bc100SJani Nikula 
700379bc100SJani Nikula 	/* Skip Sequence Byte. */
701379bc100SJani Nikula 	data++;
702379bc100SJani Nikula 
703379bc100SJani Nikula 	/* Skip Size of Sequence. */
7043cf05076SVille Syrjälä 	if (connector->panel.vbt.dsi.seq_version >= 3)
705379bc100SJani Nikula 		data += 4;
706379bc100SJani Nikula 
707379bc100SJani Nikula 	while (1) {
708379bc100SJani Nikula 		u8 operation_byte = *data++;
709379bc100SJani Nikula 		u8 operation_size = 0;
710379bc100SJani Nikula 
711379bc100SJani Nikula 		if (operation_byte == MIPI_SEQ_ELEM_END)
712379bc100SJani Nikula 			break;
713379bc100SJani Nikula 
714379bc100SJani Nikula 		if (operation_byte < ARRAY_SIZE(exec_elem))
715379bc100SJani Nikula 			mipi_elem_exec = exec_elem[operation_byte];
716379bc100SJani Nikula 		else
717379bc100SJani Nikula 			mipi_elem_exec = NULL;
718379bc100SJani Nikula 
719379bc100SJani Nikula 		/* Size of Operation. */
7203cf05076SVille Syrjälä 		if (connector->panel.vbt.dsi.seq_version >= 3)
721379bc100SJani Nikula 			operation_size = *data++;
722379bc100SJani Nikula 
723379bc100SJani Nikula 		if (mipi_elem_exec) {
724379bc100SJani Nikula 			const u8 *next = data + operation_size;
725379bc100SJani Nikula 
726379bc100SJani Nikula 			data = mipi_elem_exec(intel_dsi, data);
727379bc100SJani Nikula 
728379bc100SJani Nikula 			/* Consistency check if we have size. */
729379bc100SJani Nikula 			if (operation_size && data != next) {
730e8441414SWambui Karuga 				drm_err(&dev_priv->drm,
731e8441414SWambui Karuga 					"Inconsistent operation size\n");
732379bc100SJani Nikula 				return;
733379bc100SJani Nikula 			}
734379bc100SJani Nikula 		} else if (operation_size) {
735379bc100SJani Nikula 			/* We have size, skip. */
736e8441414SWambui Karuga 			drm_dbg_kms(&dev_priv->drm,
737e8441414SWambui Karuga 				    "Unsupported MIPI operation byte %u\n",
738379bc100SJani Nikula 				    operation_byte);
739379bc100SJani Nikula 			data += operation_size;
740379bc100SJani Nikula 		} else {
741379bc100SJani Nikula 			/* No size, can't skip without parsing. */
742e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
743e8441414SWambui Karuga 				"Unsupported MIPI operation byte %u\n",
744379bc100SJani Nikula 				operation_byte);
745379bc100SJani Nikula 			return;
746379bc100SJani Nikula 		}
747379bc100SJani Nikula 	}
748379bc100SJani Nikula }
749379bc100SJani Nikula 
intel_dsi_vbt_exec_sequence(struct intel_dsi * intel_dsi,enum mipi_seq seq_id)750ea0fe672SHans de Goede void intel_dsi_vbt_exec_sequence(struct intel_dsi *intel_dsi,
751ea0fe672SHans de Goede 				 enum mipi_seq seq_id)
752ea0fe672SHans de Goede {
753ea0fe672SHans de Goede 	if (seq_id == MIPI_SEQ_POWER_ON && intel_dsi->gpio_panel)
754ea0fe672SHans de Goede 		gpiod_set_value_cansleep(intel_dsi->gpio_panel, 1);
75525e8a383SHans de Goede 	if (seq_id == MIPI_SEQ_BACKLIGHT_ON && intel_dsi->gpio_backlight)
75625e8a383SHans de Goede 		gpiod_set_value_cansleep(intel_dsi->gpio_backlight, 1);
757ea0fe672SHans de Goede 
758ea0fe672SHans de Goede 	intel_dsi_vbt_exec(intel_dsi, seq_id);
759ea0fe672SHans de Goede 
760ea0fe672SHans de Goede 	if (seq_id == MIPI_SEQ_POWER_OFF && intel_dsi->gpio_panel)
761ea0fe672SHans de Goede 		gpiod_set_value_cansleep(intel_dsi->gpio_panel, 0);
76225e8a383SHans de Goede 	if (seq_id == MIPI_SEQ_BACKLIGHT_OFF && intel_dsi->gpio_backlight)
76325e8a383SHans de Goede 		gpiod_set_value_cansleep(intel_dsi->gpio_backlight, 0);
764ea0fe672SHans de Goede }
765ea0fe672SHans de Goede 
intel_dsi_log_params(struct intel_dsi * intel_dsi)766379bc100SJani Nikula void intel_dsi_log_params(struct intel_dsi *intel_dsi)
767379bc100SJani Nikula {
768e8441414SWambui Karuga 	struct drm_i915_private *i915 = to_i915(intel_dsi->base.base.dev);
769e8441414SWambui Karuga 
770e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Pclk %d\n", intel_dsi->pclk);
771e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Pixel overlap %d\n",
772e8441414SWambui Karuga 		    intel_dsi->pixel_overlap);
773e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Lane count %d\n", intel_dsi->lane_count);
774e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "DPHY param reg 0x%x\n", intel_dsi->dphy_reg);
775e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Video mode format %s\n",
7768f0991ccSJani Nikula 		    intel_dsi->video_mode == NON_BURST_SYNC_PULSE ?
777379bc100SJani Nikula 		    "non-burst with sync pulse" :
7788f0991ccSJani Nikula 		    intel_dsi->video_mode == NON_BURST_SYNC_EVENTS ?
779379bc100SJani Nikula 		    "non-burst with sync events" :
7808f0991ccSJani Nikula 		    intel_dsi->video_mode == BURST_MODE ?
781379bc100SJani Nikula 		    "burst" : "<unknown>");
782e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Burst mode ratio %d\n",
783e8441414SWambui Karuga 		    intel_dsi->burst_mode_ratio);
784e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Reset timer %d\n", intel_dsi->rst_timer_val);
785e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Eot %s\n",
786ff9fbe7cSLucas De Marchi 		    str_enabled_disabled(intel_dsi->eotp_pkt));
787e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Clockstop %s\n",
788ff9fbe7cSLucas De Marchi 		    str_enabled_disabled(!intel_dsi->clock_stop));
789e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Mode %s\n",
790e8441414SWambui Karuga 		    intel_dsi->operation_mode ? "command" : "video");
791379bc100SJani Nikula 	if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
792e8441414SWambui Karuga 		drm_dbg_kms(&i915->drm,
793e8441414SWambui Karuga 			    "Dual link: DSI_DUAL_LINK_FRONT_BACK\n");
794379bc100SJani Nikula 	else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT)
795e8441414SWambui Karuga 		drm_dbg_kms(&i915->drm,
796e8441414SWambui Karuga 			    "Dual link: DSI_DUAL_LINK_PIXEL_ALT\n");
797379bc100SJani Nikula 	else
798e8441414SWambui Karuga 		drm_dbg_kms(&i915->drm, "Dual link: NONE\n");
799e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Pixel Format %d\n", intel_dsi->pixel_format);
800e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "TLPX %d\n", intel_dsi->escape_clk_div);
801e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "LP RX Timeout 0x%x\n",
802e8441414SWambui Karuga 		    intel_dsi->lp_rx_timeout);
803e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Turnaround Timeout 0x%x\n",
804e8441414SWambui Karuga 		    intel_dsi->turn_arnd_val);
805e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "Init Count 0x%x\n", intel_dsi->init_count);
806e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "HS to LP Count 0x%x\n",
807e8441414SWambui Karuga 		    intel_dsi->hs_to_lp_count);
808e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "LP Byte Clock %d\n", intel_dsi->lp_byte_clk);
809e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "DBI BW Timer 0x%x\n", intel_dsi->bw_timer);
810e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "LP to HS Clock Count 0x%x\n",
811e8441414SWambui Karuga 		    intel_dsi->clk_lp_to_hs_count);
812e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "HS to LP Clock Count 0x%x\n",
813e8441414SWambui Karuga 		    intel_dsi->clk_hs_to_lp_count);
814e8441414SWambui Karuga 	drm_dbg_kms(&i915->drm, "BTA %s\n",
815ff9fbe7cSLucas De Marchi 		    str_enabled_disabled(!(intel_dsi->video_frmt_cfg_bits & DISABLE_VIDEO_BTA)));
816379bc100SJani Nikula }
817379bc100SJani Nikula 
intel_dsi_vbt_init(struct intel_dsi * intel_dsi,u16 panel_id)818379bc100SJani Nikula bool intel_dsi_vbt_init(struct intel_dsi *intel_dsi, u16 panel_id)
819379bc100SJani Nikula {
820379bc100SJani Nikula 	struct drm_device *dev = intel_dsi->base.base.dev;
821379bc100SJani Nikula 	struct drm_i915_private *dev_priv = to_i915(dev);
8223cf05076SVille Syrjälä 	struct intel_connector *connector = intel_dsi->attached_connector;
8233cf05076SVille Syrjälä 	struct mipi_config *mipi_config = connector->panel.vbt.dsi.config;
8243cf05076SVille Syrjälä 	struct mipi_pps_data *pps = connector->panel.vbt.dsi.pps;
8253cf05076SVille Syrjälä 	struct drm_display_mode *mode = connector->panel.vbt.lfp_lvds_vbt_mode;
826379bc100SJani Nikula 	u16 burst_mode_ratio;
827379bc100SJani Nikula 	enum port port;
828379bc100SJani Nikula 
829e8441414SWambui Karuga 	drm_dbg_kms(&dev_priv->drm, "\n");
830379bc100SJani Nikula 
831379bc100SJani Nikula 	intel_dsi->eotp_pkt = mipi_config->eot_pkt_disabled ? 0 : 1;
832379bc100SJani Nikula 	intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
833379bc100SJani Nikula 	intel_dsi->lane_count = mipi_config->lane_cnt + 1;
834379bc100SJani Nikula 	intel_dsi->pixel_format =
835379bc100SJani Nikula 			pixel_format_from_register_bits(
836379bc100SJani Nikula 				mipi_config->videomode_color_format << 7);
837379bc100SJani Nikula 
838379bc100SJani Nikula 	intel_dsi->dual_link = mipi_config->dual_link;
839379bc100SJani Nikula 	intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
840379bc100SJani Nikula 	intel_dsi->operation_mode = mipi_config->is_cmd_mode;
8418f0991ccSJani Nikula 	intel_dsi->video_mode = mipi_config->video_transfer_mode;
842379bc100SJani Nikula 	intel_dsi->escape_clk_div = mipi_config->byte_clk_sel;
843379bc100SJani Nikula 	intel_dsi->lp_rx_timeout = mipi_config->lp_rx_timeout;
844379bc100SJani Nikula 	intel_dsi->hs_tx_timeout = mipi_config->hs_tx_timeout;
845379bc100SJani Nikula 	intel_dsi->turn_arnd_val = mipi_config->turn_around_timeout;
846379bc100SJani Nikula 	intel_dsi->rst_timer_val = mipi_config->device_reset_timer;
847379bc100SJani Nikula 	intel_dsi->init_count = mipi_config->master_init_timer;
848379bc100SJani Nikula 	intel_dsi->bw_timer = mipi_config->dbi_bw_timer;
849379bc100SJani Nikula 	intel_dsi->video_frmt_cfg_bits =
850379bc100SJani Nikula 		mipi_config->bta_enabled ? DISABLE_VIDEO_BTA : 0;
851379bc100SJani Nikula 	intel_dsi->bgr_enabled = mipi_config->rgb_flip;
852379bc100SJani Nikula 
853379bc100SJani Nikula 	/* Starting point, adjusted depending on dual link and burst mode */
854379bc100SJani Nikula 	intel_dsi->pclk = mode->clock;
855379bc100SJani Nikula 
856379bc100SJani Nikula 	/* In dual link mode each port needs half of pixel clock */
857379bc100SJani Nikula 	if (intel_dsi->dual_link) {
858379bc100SJani Nikula 		intel_dsi->pclk /= 2;
859379bc100SJani Nikula 
860379bc100SJani Nikula 		/* we can enable pixel_overlap if needed by panel. In this
861379bc100SJani Nikula 		 * case we need to increase the pixelclock for extra pixels
862379bc100SJani Nikula 		 */
863379bc100SJani Nikula 		if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
864379bc100SJani Nikula 			intel_dsi->pclk += DIV_ROUND_UP(mode->vtotal * intel_dsi->pixel_overlap * 60, 1000);
865379bc100SJani Nikula 		}
866379bc100SJani Nikula 	}
867379bc100SJani Nikula 
868379bc100SJani Nikula 	/* Burst Mode Ratio
869379bc100SJani Nikula 	 * Target ddr frequency from VBT / non burst ddr freq
870379bc100SJani Nikula 	 * multiply by 100 to preserve remainder
871379bc100SJani Nikula 	 */
8728f0991ccSJani Nikula 	if (intel_dsi->video_mode == BURST_MODE) {
873379bc100SJani Nikula 		if (mipi_config->target_burst_mode_freq) {
874379bc100SJani Nikula 			u32 bitrate = intel_dsi_bitrate(intel_dsi);
875379bc100SJani Nikula 
876379bc100SJani Nikula 			/*
877379bc100SJani Nikula 			 * Sometimes the VBT contains a slightly lower clock,
878379bc100SJani Nikula 			 * then the bitrate we have calculated, in this case
879379bc100SJani Nikula 			 * just replace it with the calculated bitrate.
880379bc100SJani Nikula 			 */
881379bc100SJani Nikula 			if (mipi_config->target_burst_mode_freq < bitrate &&
882379bc100SJani Nikula 			    intel_fuzzy_clock_check(
883379bc100SJani Nikula 					mipi_config->target_burst_mode_freq,
884379bc100SJani Nikula 					bitrate))
885379bc100SJani Nikula 				mipi_config->target_burst_mode_freq = bitrate;
886379bc100SJani Nikula 
887379bc100SJani Nikula 			if (mipi_config->target_burst_mode_freq < bitrate) {
888e8441414SWambui Karuga 				drm_err(&dev_priv->drm,
889e8441414SWambui Karuga 					"Burst mode freq is less than computed\n");
890379bc100SJani Nikula 				return false;
891379bc100SJani Nikula 			}
892379bc100SJani Nikula 
893379bc100SJani Nikula 			burst_mode_ratio = DIV_ROUND_UP(
894379bc100SJani Nikula 				mipi_config->target_burst_mode_freq * 100,
895379bc100SJani Nikula 				bitrate);
896379bc100SJani Nikula 
897379bc100SJani Nikula 			intel_dsi->pclk = DIV_ROUND_UP(intel_dsi->pclk * burst_mode_ratio, 100);
898379bc100SJani Nikula 		} else {
899e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
900e8441414SWambui Karuga 				"Burst mode target is not set\n");
901379bc100SJani Nikula 			return false;
902379bc100SJani Nikula 		}
903379bc100SJani Nikula 	} else
904379bc100SJani Nikula 		burst_mode_ratio = 100;
905379bc100SJani Nikula 
906379bc100SJani Nikula 	intel_dsi->burst_mode_ratio = burst_mode_ratio;
907379bc100SJani Nikula 
908379bc100SJani Nikula 	/* delays in VBT are in unit of 100us, so need to convert
909379bc100SJani Nikula 	 * here in ms
910379bc100SJani Nikula 	 * Delay (100us) * 100 /1000 = Delay / 10 (ms) */
911379bc100SJani Nikula 	intel_dsi->backlight_off_delay = pps->bl_disable_delay / 10;
912379bc100SJani Nikula 	intel_dsi->backlight_on_delay = pps->bl_enable_delay / 10;
913379bc100SJani Nikula 	intel_dsi->panel_on_delay = pps->panel_on_delay / 10;
914379bc100SJani Nikula 	intel_dsi->panel_off_delay = pps->panel_off_delay / 10;
915379bc100SJani Nikula 	intel_dsi->panel_pwr_cycle_delay = pps->panel_power_cycle_delay / 10;
916379bc100SJani Nikula 
9178cbf89dbSVivek Kasireddy 	intel_dsi->i2c_bus_num = -1;
9188cbf89dbSVivek Kasireddy 
919379bc100SJani Nikula 	/* a regular driver would get the device in probe */
920379bc100SJani Nikula 	for_each_dsi_port(port, intel_dsi->ports) {
921379bc100SJani Nikula 		mipi_dsi_attach(intel_dsi->dsi_hosts[port]->device);
922379bc100SJani Nikula 	}
923379bc100SJani Nikula 
924379bc100SJani Nikula 	return true;
925379bc100SJani Nikula }
926ea0fe672SHans de Goede 
927ea0fe672SHans de Goede /*
928ea0fe672SHans de Goede  * On some BYT/CHT devs some sequences are incomplete and we need to manually
929067d1cf7SHans de Goede  * control some GPIOs. We need to add a GPIO lookup table before we get these.
93025e8a383SHans de Goede  * If the GOP did not initialize the panel (HDMI inserted) we may need to also
93125e8a383SHans de Goede  * change the pinmux for the SoC's PWM0 pin from GPIO to PWM.
932ea0fe672SHans de Goede  */
933067d1cf7SHans de Goede static struct gpiod_lookup_table pmic_panel_gpio_table = {
934067d1cf7SHans de Goede 	/* Intel GFX is consumer */
935067d1cf7SHans de Goede 	.dev_id = "0000:00:02.0",
936067d1cf7SHans de Goede 	.table = {
937067d1cf7SHans de Goede 		/* Panel EN/DISABLE */
938067d1cf7SHans de Goede 		GPIO_LOOKUP("gpio_crystalcove", 94, "panel", GPIO_ACTIVE_HIGH),
939067d1cf7SHans de Goede 		{ }
940067d1cf7SHans de Goede 	},
941067d1cf7SHans de Goede };
942067d1cf7SHans de Goede 
94325e8a383SHans de Goede static struct gpiod_lookup_table soc_panel_gpio_table = {
94425e8a383SHans de Goede 	.dev_id = "0000:00:02.0",
94525e8a383SHans de Goede 	.table = {
94625e8a383SHans de Goede 		GPIO_LOOKUP("INT33FC:01", 10, "backlight", GPIO_ACTIVE_HIGH),
94725e8a383SHans de Goede 		GPIO_LOOKUP("INT33FC:01", 11, "panel", GPIO_ACTIVE_HIGH),
94825e8a383SHans de Goede 		{ }
94925e8a383SHans de Goede 	},
95025e8a383SHans de Goede };
95125e8a383SHans de Goede 
95225e8a383SHans de Goede static const struct pinctrl_map soc_pwm_pinctrl_map[] = {
95325e8a383SHans de Goede 	PIN_MAP_MUX_GROUP("0000:00:02.0", "soc_pwm0", "INT33FC:00",
95425e8a383SHans de Goede 			  "pwm0_grp", "pwm"),
95525e8a383SHans de Goede };
95625e8a383SHans de Goede 
intel_dsi_vbt_gpio_init(struct intel_dsi * intel_dsi,bool panel_is_on)9576c0a878eSHans de Goede void intel_dsi_vbt_gpio_init(struct intel_dsi *intel_dsi, bool panel_is_on)
958ea0fe672SHans de Goede {
959ea0fe672SHans de Goede 	struct drm_device *dev = intel_dsi->base.base.dev;
960ea0fe672SHans de Goede 	struct drm_i915_private *dev_priv = to_i915(dev);
9613cf05076SVille Syrjälä 	struct intel_connector *connector = intel_dsi->attached_connector;
9623cf05076SVille Syrjälä 	struct mipi_config *mipi_config = connector->panel.vbt.dsi.config;
9636c0a878eSHans de Goede 	enum gpiod_flags flags = panel_is_on ? GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
96425e8a383SHans de Goede 	bool want_backlight_gpio = false;
96525e8a383SHans de Goede 	bool want_panel_gpio = false;
96625e8a383SHans de Goede 	struct pinctrl *pinctrl;
96725e8a383SHans de Goede 	int ret;
968ea0fe672SHans de Goede 
969ea0fe672SHans de Goede 	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
970ea0fe672SHans de Goede 	    mipi_config->pwm_blc == PPS_BLC_PMIC) {
971067d1cf7SHans de Goede 		gpiod_add_lookup_table(&pmic_panel_gpio_table);
97225e8a383SHans de Goede 		want_panel_gpio = true;
97325e8a383SHans de Goede 	}
974067d1cf7SHans de Goede 
97525e8a383SHans de Goede 	if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) {
97625e8a383SHans de Goede 		gpiod_add_lookup_table(&soc_panel_gpio_table);
97725e8a383SHans de Goede 		want_panel_gpio = true;
97825e8a383SHans de Goede 		want_backlight_gpio = true;
97925e8a383SHans de Goede 
98025e8a383SHans de Goede 		/* Ensure PWM0 pin is muxed as PWM instead of GPIO */
98125e8a383SHans de Goede 		ret = pinctrl_register_mappings(soc_pwm_pinctrl_map,
98225e8a383SHans de Goede 					     ARRAY_SIZE(soc_pwm_pinctrl_map));
98325e8a383SHans de Goede 		if (ret)
984e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
985e8441414SWambui Karuga 				"Failed to register pwm0 pinmux mapping\n");
98625e8a383SHans de Goede 
98725e8a383SHans de Goede 		pinctrl = devm_pinctrl_get_select(dev->dev, "soc_pwm0");
98825e8a383SHans de Goede 		if (IS_ERR(pinctrl))
989e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
990e8441414SWambui Karuga 				"Failed to set pinmux to PWM\n");
99125e8a383SHans de Goede 	}
99225e8a383SHans de Goede 
99325e8a383SHans de Goede 	if (want_panel_gpio) {
9946c0a878eSHans de Goede 		intel_dsi->gpio_panel = gpiod_get(dev->dev, "panel", flags);
995ea0fe672SHans de Goede 		if (IS_ERR(intel_dsi->gpio_panel)) {
996e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
997e8441414SWambui Karuga 				"Failed to own gpio for panel control\n");
998ea0fe672SHans de Goede 			intel_dsi->gpio_panel = NULL;
999ea0fe672SHans de Goede 		}
1000ea0fe672SHans de Goede 	}
100125e8a383SHans de Goede 
100225e8a383SHans de Goede 	if (want_backlight_gpio) {
100325e8a383SHans de Goede 		intel_dsi->gpio_backlight =
100425e8a383SHans de Goede 			gpiod_get(dev->dev, "backlight", flags);
100525e8a383SHans de Goede 		if (IS_ERR(intel_dsi->gpio_backlight)) {
1006e8441414SWambui Karuga 			drm_err(&dev_priv->drm,
1007e8441414SWambui Karuga 				"Failed to own gpio for backlight control\n");
100825e8a383SHans de Goede 			intel_dsi->gpio_backlight = NULL;
100925e8a383SHans de Goede 		}
101025e8a383SHans de Goede 	}
1011ea0fe672SHans de Goede }
1012ea0fe672SHans de Goede 
intel_dsi_vbt_gpio_cleanup(struct intel_dsi * intel_dsi)1013ea0fe672SHans de Goede void intel_dsi_vbt_gpio_cleanup(struct intel_dsi *intel_dsi)
1014ea0fe672SHans de Goede {
1015067d1cf7SHans de Goede 	struct drm_device *dev = intel_dsi->base.base.dev;
1016067d1cf7SHans de Goede 	struct drm_i915_private *dev_priv = to_i915(dev);
10173cf05076SVille Syrjälä 	struct intel_connector *connector = intel_dsi->attached_connector;
10183cf05076SVille Syrjälä 	struct mipi_config *mipi_config = connector->panel.vbt.dsi.config;
1019067d1cf7SHans de Goede 
1020ea0fe672SHans de Goede 	if (intel_dsi->gpio_panel) {
1021ea0fe672SHans de Goede 		gpiod_put(intel_dsi->gpio_panel);
1022ea0fe672SHans de Goede 		intel_dsi->gpio_panel = NULL;
1023ea0fe672SHans de Goede 	}
1024067d1cf7SHans de Goede 
102525e8a383SHans de Goede 	if (intel_dsi->gpio_backlight) {
102625e8a383SHans de Goede 		gpiod_put(intel_dsi->gpio_backlight);
102725e8a383SHans de Goede 		intel_dsi->gpio_backlight = NULL;
102825e8a383SHans de Goede 	}
102925e8a383SHans de Goede 
1030067d1cf7SHans de Goede 	if ((IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
1031067d1cf7SHans de Goede 	    mipi_config->pwm_blc == PPS_BLC_PMIC)
1032067d1cf7SHans de Goede 		gpiod_remove_lookup_table(&pmic_panel_gpio_table);
103325e8a383SHans de Goede 
103425e8a383SHans de Goede 	if (IS_VALLEYVIEW(dev_priv) && mipi_config->pwm_blc == PPS_BLC_SOC) {
103525e8a383SHans de Goede 		pinctrl_unregister_mappings(soc_pwm_pinctrl_map);
103625e8a383SHans de Goede 		gpiod_remove_lookup_table(&soc_panel_gpio_table);
103725e8a383SHans de Goede 	}
1038ea0fe672SHans de Goede }
1039