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