xref: /openbsd-src/sys/dev/pci/drm/amd/display/dc/gpio/hw_ddc.c (revision 1bb76ff151c0aba8e3312a604e4cd2e5195cf4b7)
1fb4d8502Sjsg /*
2fb4d8502Sjsg  * Copyright 2012-15 Advanced Micro Devices, Inc.
3fb4d8502Sjsg  *
4fb4d8502Sjsg  * Permission is hereby granted, free of charge, to any person obtaining a
5fb4d8502Sjsg  * copy of this software and associated documentation files (the "Software"),
6fb4d8502Sjsg  * to deal in the Software without restriction, including without limitation
7fb4d8502Sjsg  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8fb4d8502Sjsg  * and/or sell copies of the Software, and to permit persons to whom the
9fb4d8502Sjsg  * Software is furnished to do so, subject to the following conditions:
10fb4d8502Sjsg  *
11fb4d8502Sjsg  * The above copyright notice and this permission notice shall be included in
12fb4d8502Sjsg  * all copies or substantial portions of the Software.
13fb4d8502Sjsg  *
14fb4d8502Sjsg  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15fb4d8502Sjsg  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16fb4d8502Sjsg  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
17fb4d8502Sjsg  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18fb4d8502Sjsg  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19fb4d8502Sjsg  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20fb4d8502Sjsg  * OTHER DEALINGS IN THE SOFTWARE.
21fb4d8502Sjsg  *
22fb4d8502Sjsg  * Authors: AMD
23fb4d8502Sjsg  *
24fb4d8502Sjsg  */
25fb4d8502Sjsg 
26fb4d8502Sjsg #include "dm_services.h"
27fb4d8502Sjsg 
28c349dbc7Sjsg #include "include/gpio_interface.h"
29fb4d8502Sjsg #include "include/gpio_types.h"
30fb4d8502Sjsg #include "hw_gpio.h"
31fb4d8502Sjsg #include "hw_ddc.h"
32fb4d8502Sjsg 
33fb4d8502Sjsg #include "reg_helper.h"
34fb4d8502Sjsg #include "gpio_regs.h"
35fb4d8502Sjsg 
36fb4d8502Sjsg 
37fb4d8502Sjsg #undef FN
38fb4d8502Sjsg #define FN(reg_name, field_name) \
39fb4d8502Sjsg 	ddc->shifts->field_name, ddc->masks->field_name
40fb4d8502Sjsg 
41fb4d8502Sjsg #define CTX \
42fb4d8502Sjsg 	ddc->base.base.ctx
43fb4d8502Sjsg #define REG(reg)\
44fb4d8502Sjsg 	(ddc->regs->reg)
45fb4d8502Sjsg 
46c349dbc7Sjsg struct gpio;
47c349dbc7Sjsg 
dal_hw_ddc_destruct(struct hw_ddc * pin)48c349dbc7Sjsg static void dal_hw_ddc_destruct(
49fb4d8502Sjsg 	struct hw_ddc *pin)
50fb4d8502Sjsg {
51fb4d8502Sjsg 	dal_hw_gpio_destruct(&pin->base);
52fb4d8502Sjsg }
53fb4d8502Sjsg 
dal_hw_ddc_destroy(struct hw_gpio_pin ** ptr)54c349dbc7Sjsg static void dal_hw_ddc_destroy(
55fb4d8502Sjsg 	struct hw_gpio_pin **ptr)
56fb4d8502Sjsg {
57fb4d8502Sjsg 	struct hw_ddc *pin = HW_DDC_FROM_BASE(*ptr);
58fb4d8502Sjsg 
59c349dbc7Sjsg 	dal_hw_ddc_destruct(pin);
60fb4d8502Sjsg 
61fb4d8502Sjsg 	kfree(pin);
62fb4d8502Sjsg 
63fb4d8502Sjsg 	*ptr = NULL;
64fb4d8502Sjsg }
65fb4d8502Sjsg 
set_config(struct hw_gpio_pin * ptr,const struct gpio_config_data * config_data)66fb4d8502Sjsg static enum gpio_result set_config(
67fb4d8502Sjsg 	struct hw_gpio_pin *ptr,
68fb4d8502Sjsg 	const struct gpio_config_data *config_data)
69fb4d8502Sjsg {
70fb4d8502Sjsg 	struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr);
71fb4d8502Sjsg 	struct hw_gpio *hw_gpio = NULL;
72fb4d8502Sjsg 	uint32_t regval;
73fb4d8502Sjsg 	uint32_t ddc_data_pd_en = 0;
74fb4d8502Sjsg 	uint32_t ddc_clk_pd_en = 0;
75fb4d8502Sjsg 	uint32_t aux_pad_mode = 0;
76fb4d8502Sjsg 
77fb4d8502Sjsg 	hw_gpio = &ddc->base;
78fb4d8502Sjsg 
79fb4d8502Sjsg 	if (hw_gpio == NULL) {
80fb4d8502Sjsg 		ASSERT_CRITICAL(false);
81fb4d8502Sjsg 		return GPIO_RESULT_NULL_HANDLE;
82fb4d8502Sjsg 	}
83fb4d8502Sjsg 
84fb4d8502Sjsg 	regval = REG_GET_3(gpio.MASK_reg,
85fb4d8502Sjsg 			DC_GPIO_DDC1DATA_PD_EN, &ddc_data_pd_en,
86fb4d8502Sjsg 			DC_GPIO_DDC1CLK_PD_EN, &ddc_clk_pd_en,
87fb4d8502Sjsg 			AUX_PAD1_MODE, &aux_pad_mode);
88fb4d8502Sjsg 
89fb4d8502Sjsg 	switch (config_data->config.ddc.type) {
90fb4d8502Sjsg 	case GPIO_DDC_CONFIG_TYPE_MODE_I2C:
91fb4d8502Sjsg 		/* On plug-in, there is a transient level on the pad
92fb4d8502Sjsg 		 * which must be discharged through the internal pull-down.
93fb4d8502Sjsg 		 * Enable internal pull-down, 2.5msec discharge time
94fb4d8502Sjsg 		 * is required for detection of AUX mode */
95fb4d8502Sjsg 		if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) {
96fb4d8502Sjsg 			if (!ddc_data_pd_en || !ddc_clk_pd_en) {
97*1bb76ff1Sjsg 				if (hw_gpio->base.en == GPIO_DDC_LINE_DDC_VGA) {
98*1bb76ff1Sjsg 					// bit 4 of mask has different usage in some cases
99*1bb76ff1Sjsg 					REG_SET(gpio.MASK_reg, regval, DC_GPIO_DDC1DATA_PD_EN, 1);
100*1bb76ff1Sjsg 				} else {
101fb4d8502Sjsg 					REG_SET_2(gpio.MASK_reg, regval,
102fb4d8502Sjsg 						DC_GPIO_DDC1DATA_PD_EN, 1,
103fb4d8502Sjsg 						DC_GPIO_DDC1CLK_PD_EN, 1);
104*1bb76ff1Sjsg 				}
105fb4d8502Sjsg 				if (config_data->type ==
106fb4d8502Sjsg 						GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
107fb4d8502Sjsg 					drm_msleep(3);
108fb4d8502Sjsg 			}
109fb4d8502Sjsg 		} else {
110fb4d8502Sjsg 			uint32_t sda_pd_dis = 0;
111fb4d8502Sjsg 			uint32_t scl_pd_dis = 0;
112fb4d8502Sjsg 
1135ca02815Sjsg 			REG_GET_2(gpio.MASK_reg,
114fb4d8502Sjsg 				  DC_GPIO_SDA_PD_DIS, &sda_pd_dis,
115fb4d8502Sjsg 				  DC_GPIO_SCL_PD_DIS, &scl_pd_dis);
116fb4d8502Sjsg 
117fb4d8502Sjsg 			if (sda_pd_dis) {
118fb4d8502Sjsg 				REG_SET(gpio.MASK_reg, regval,
119fb4d8502Sjsg 						DC_GPIO_SDA_PD_DIS, 0);
120fb4d8502Sjsg 
121fb4d8502Sjsg 				if (config_data->type ==
122fb4d8502Sjsg 						GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
123fb4d8502Sjsg 					drm_msleep(3);
124fb4d8502Sjsg 			}
125fb4d8502Sjsg 
126fb4d8502Sjsg 			if (!scl_pd_dis) {
127fb4d8502Sjsg 				REG_SET(gpio.MASK_reg, regval,
128fb4d8502Sjsg 						DC_GPIO_SCL_PD_DIS, 1);
129fb4d8502Sjsg 
130fb4d8502Sjsg 				if (config_data->type ==
131fb4d8502Sjsg 						GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
132fb4d8502Sjsg 					drm_msleep(3);
133fb4d8502Sjsg 			}
134fb4d8502Sjsg 		}
135fb4d8502Sjsg 
136fb4d8502Sjsg 		if (aux_pad_mode) {
137fb4d8502Sjsg 			/* let pins to get de-asserted
138fb4d8502Sjsg 			 * before setting pad to I2C mode */
139fb4d8502Sjsg 			if (config_data->config.ddc.data_en_bit_present ||
140fb4d8502Sjsg 				config_data->config.ddc.clock_en_bit_present)
141fb4d8502Sjsg 				/* [anaumov] in DAL2, there was
142fb4d8502Sjsg 				 * dc_service_delay_in_microseconds(2000); */
143fb4d8502Sjsg 				drm_msleep(2);
144fb4d8502Sjsg 
145fb4d8502Sjsg 			/* set the I2C pad mode */
146fb4d8502Sjsg 			/* read the register again,
147fb4d8502Sjsg 			 * some bits may have been changed */
148fb4d8502Sjsg 			REG_UPDATE(gpio.MASK_reg,
149fb4d8502Sjsg 					AUX_PAD1_MODE, 0);
150fb4d8502Sjsg 		}
151fb4d8502Sjsg 
152c349dbc7Sjsg 		if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) {
153c349dbc7Sjsg 				REG_UPDATE(dc_gpio_aux_ctrl_5, DDC_PAD_I2CMODE, 1);
154c349dbc7Sjsg 		}
155c349dbc7Sjsg 		//set  DC_IO_aux_rxsel = 2'b01
156c349dbc7Sjsg 		if (ddc->regs->phy_aux_cntl != 0) {
157c349dbc7Sjsg 				REG_UPDATE(phy_aux_cntl, AUX_PAD_RXSEL, 1);
158c349dbc7Sjsg 		}
159fb4d8502Sjsg 		return GPIO_RESULT_OK;
160fb4d8502Sjsg 	case GPIO_DDC_CONFIG_TYPE_MODE_AUX:
161fb4d8502Sjsg 		/* set the AUX pad mode */
162fb4d8502Sjsg 		if (!aux_pad_mode) {
163fb4d8502Sjsg 			REG_SET(gpio.MASK_reg, regval,
164fb4d8502Sjsg 					AUX_PAD1_MODE, 1);
165fb4d8502Sjsg 		}
166c349dbc7Sjsg 		if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) {
167c349dbc7Sjsg 			REG_UPDATE(dc_gpio_aux_ctrl_5,
168c349dbc7Sjsg 					DDC_PAD_I2CMODE, 0);
169c349dbc7Sjsg 		}
170fb4d8502Sjsg 
171fb4d8502Sjsg 		return GPIO_RESULT_OK;
172fb4d8502Sjsg 	case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT:
173fb4d8502Sjsg 		if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
174fb4d8502Sjsg 			(hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
175fb4d8502Sjsg 			REG_UPDATE_3(ddc_setup,
176fb4d8502Sjsg 				DC_I2C_DDC1_ENABLE, 1,
177fb4d8502Sjsg 				DC_I2C_DDC1_EDID_DETECT_ENABLE, 1,
178fb4d8502Sjsg 				DC_I2C_DDC1_EDID_DETECT_MODE, 0);
179fb4d8502Sjsg 			return GPIO_RESULT_OK;
180fb4d8502Sjsg 		}
181fb4d8502Sjsg 	break;
182fb4d8502Sjsg 	case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT:
183fb4d8502Sjsg 		if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
184fb4d8502Sjsg 			(hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
185fb4d8502Sjsg 			REG_UPDATE_3(ddc_setup,
186fb4d8502Sjsg 				DC_I2C_DDC1_ENABLE, 1,
187fb4d8502Sjsg 				DC_I2C_DDC1_EDID_DETECT_ENABLE, 1,
188fb4d8502Sjsg 				DC_I2C_DDC1_EDID_DETECT_MODE, 1);
189fb4d8502Sjsg 			return GPIO_RESULT_OK;
190fb4d8502Sjsg 		}
191fb4d8502Sjsg 	break;
192fb4d8502Sjsg 	case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING:
193fb4d8502Sjsg 		if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
194fb4d8502Sjsg 			(hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
195fb4d8502Sjsg 			REG_UPDATE_2(ddc_setup,
196fb4d8502Sjsg 				DC_I2C_DDC1_ENABLE, 0,
197fb4d8502Sjsg 				DC_I2C_DDC1_EDID_DETECT_ENABLE, 0);
198fb4d8502Sjsg 			return GPIO_RESULT_OK;
199fb4d8502Sjsg 		}
200fb4d8502Sjsg 	break;
201fb4d8502Sjsg 	}
202fb4d8502Sjsg 
203fb4d8502Sjsg 	BREAK_TO_DEBUGGER();
204fb4d8502Sjsg 
205fb4d8502Sjsg 	return GPIO_RESULT_NON_SPECIFIC_ERROR;
206fb4d8502Sjsg }
207fb4d8502Sjsg 
208fb4d8502Sjsg static const struct hw_gpio_pin_funcs funcs = {
209c349dbc7Sjsg 	.destroy = dal_hw_ddc_destroy,
210fb4d8502Sjsg 	.open = dal_hw_gpio_open,
211fb4d8502Sjsg 	.get_value = dal_hw_gpio_get_value,
212fb4d8502Sjsg 	.set_value = dal_hw_gpio_set_value,
213fb4d8502Sjsg 	.set_config = set_config,
214fb4d8502Sjsg 	.change_mode = dal_hw_gpio_change_mode,
215fb4d8502Sjsg 	.close = dal_hw_gpio_close,
216fb4d8502Sjsg };
217fb4d8502Sjsg 
dal_hw_ddc_construct(struct hw_ddc * ddc,enum gpio_id id,uint32_t en,struct dc_context * ctx)218c349dbc7Sjsg static void dal_hw_ddc_construct(
219fb4d8502Sjsg 	struct hw_ddc *ddc,
220fb4d8502Sjsg 	enum gpio_id id,
221fb4d8502Sjsg 	uint32_t en,
222fb4d8502Sjsg 	struct dc_context *ctx)
223fb4d8502Sjsg {
224fb4d8502Sjsg 	dal_hw_gpio_construct(&ddc->base, id, en, ctx);
225fb4d8502Sjsg 	ddc->base.base.funcs = &funcs;
226fb4d8502Sjsg }
227fb4d8502Sjsg 
dal_hw_ddc_init(struct hw_ddc ** hw_ddc,struct dc_context * ctx,enum gpio_id id,uint32_t en)228c349dbc7Sjsg void dal_hw_ddc_init(
229c349dbc7Sjsg 	struct hw_ddc **hw_ddc,
230fb4d8502Sjsg 	struct dc_context *ctx,
231fb4d8502Sjsg 	enum gpio_id id,
232fb4d8502Sjsg 	uint32_t en)
233fb4d8502Sjsg {
234fb4d8502Sjsg 	if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) {
235fb4d8502Sjsg 		ASSERT_CRITICAL(false);
236c349dbc7Sjsg 		*hw_ddc = NULL;
237fb4d8502Sjsg 	}
238fb4d8502Sjsg 
239c349dbc7Sjsg 	*hw_ddc = kzalloc(sizeof(struct hw_ddc), GFP_KERNEL);
240c349dbc7Sjsg 	if (!*hw_ddc) {
241fb4d8502Sjsg 		ASSERT_CRITICAL(false);
242c349dbc7Sjsg 		return;
243fb4d8502Sjsg 	}
244fb4d8502Sjsg 
245c349dbc7Sjsg 	dal_hw_ddc_construct(*hw_ddc, id, en, ctx);
246c349dbc7Sjsg }
247c349dbc7Sjsg 
dal_hw_ddc_get_pin(struct gpio * gpio)248c349dbc7Sjsg struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio)
249c349dbc7Sjsg {
250c349dbc7Sjsg 	struct hw_ddc *hw_ddc = dal_gpio_get_ddc(gpio);
251c349dbc7Sjsg 
252c349dbc7Sjsg 	return &hw_ddc->base.base;
253fb4d8502Sjsg }
254