2 * Copyright 2012-15 Advanced Micro Devices, Inc.
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
26 #include "dm_services.h"
28 #include "include/gpio_types.h"
32 #include "reg_helper.h"
33 #include "gpio_regs.h"
37 #define FN(reg_name, field_name) \
38 ddc->shifts->field_name, ddc->masks->field_name
48 dal_hw_gpio_destruct(&pin
->base
);
52 struct hw_gpio_pin
**ptr
)
54 struct hw_ddc
*pin
= HW_DDC_FROM_BASE(*ptr
);
63 static enum gpio_result
set_config(
64 struct hw_gpio_pin
*ptr
,
65 const struct gpio_config_data
*config_data
)
67 struct hw_ddc
*ddc
= HW_DDC_FROM_BASE(ptr
);
68 struct hw_gpio
*hw_gpio
= NULL
;
70 uint32_t ddc_data_pd_en
= 0;
71 uint32_t ddc_clk_pd_en
= 0;
72 uint32_t aux_pad_mode
= 0;
76 if (hw_gpio
== NULL
) {
77 ASSERT_CRITICAL(false);
78 return GPIO_RESULT_NULL_HANDLE
;
81 regval
= REG_GET_3(gpio
.MASK_reg
,
82 DC_GPIO_DDC1DATA_PD_EN
, &ddc_data_pd_en
,
83 DC_GPIO_DDC1CLK_PD_EN
, &ddc_clk_pd_en
,
84 AUX_PAD1_MODE
, &aux_pad_mode
);
86 switch (config_data
->config
.ddc
.type
) {
87 case GPIO_DDC_CONFIG_TYPE_MODE_I2C
:
88 /* On plug-in, there is a transient level on the pad
89 * which must be discharged through the internal pull-down.
90 * Enable internal pull-down, 2.5msec discharge time
91 * is required for detection of AUX mode */
92 if (hw_gpio
->base
.en
!= GPIO_DDC_LINE_VIP_PAD
) {
93 if (!ddc_data_pd_en
|| !ddc_clk_pd_en
) {
95 REG_SET_2(gpio
.MASK_reg
, regval
,
96 DC_GPIO_DDC1DATA_PD_EN
, 1,
97 DC_GPIO_DDC1CLK_PD_EN
, 1);
99 if (config_data
->type
==
100 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
)
105 uint32_t sda_pd_dis
= 0;
106 uint32_t scl_pd_dis
= 0;
108 reg2
= REG_GET_2(gpio
.MASK_reg
,
109 DC_GPIO_SDA_PD_DIS
, &sda_pd_dis
,
110 DC_GPIO_SCL_PD_DIS
, &scl_pd_dis
);
113 REG_SET(gpio
.MASK_reg
, regval
,
114 DC_GPIO_SDA_PD_DIS
, 0);
116 if (config_data
->type
==
117 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
)
122 REG_SET(gpio
.MASK_reg
, regval
,
123 DC_GPIO_SCL_PD_DIS
, 1);
125 if (config_data
->type
==
126 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE
)
132 /* let pins to get de-asserted
133 * before setting pad to I2C mode */
134 if (config_data
->config
.ddc
.data_en_bit_present
||
135 config_data
->config
.ddc
.clock_en_bit_present
)
136 /* [anaumov] in DAL2, there was
137 * dc_service_delay_in_microseconds(2000); */
140 /* set the I2C pad mode */
141 /* read the register again,
142 * some bits may have been changed */
143 REG_UPDATE(gpio
.MASK_reg
,
147 return GPIO_RESULT_OK
;
148 case GPIO_DDC_CONFIG_TYPE_MODE_AUX
:
149 /* set the AUX pad mode */
151 REG_SET(gpio
.MASK_reg
, regval
,
155 return GPIO_RESULT_OK
;
156 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT
:
157 if ((hw_gpio
->base
.en
>= GPIO_DDC_LINE_DDC1
) &&
158 (hw_gpio
->base
.en
<= GPIO_DDC_LINE_DDC_VGA
)) {
159 REG_UPDATE_3(ddc_setup
,
160 DC_I2C_DDC1_ENABLE
, 1,
161 DC_I2C_DDC1_EDID_DETECT_ENABLE
, 1,
162 DC_I2C_DDC1_EDID_DETECT_MODE
, 0);
163 return GPIO_RESULT_OK
;
166 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT
:
167 if ((hw_gpio
->base
.en
>= GPIO_DDC_LINE_DDC1
) &&
168 (hw_gpio
->base
.en
<= GPIO_DDC_LINE_DDC_VGA
)) {
169 REG_UPDATE_3(ddc_setup
,
170 DC_I2C_DDC1_ENABLE
, 1,
171 DC_I2C_DDC1_EDID_DETECT_ENABLE
, 1,
172 DC_I2C_DDC1_EDID_DETECT_MODE
, 1);
173 return GPIO_RESULT_OK
;
176 case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING
:
177 if ((hw_gpio
->base
.en
>= GPIO_DDC_LINE_DDC1
) &&
178 (hw_gpio
->base
.en
<= GPIO_DDC_LINE_DDC_VGA
)) {
179 REG_UPDATE_2(ddc_setup
,
180 DC_I2C_DDC1_ENABLE
, 0,
181 DC_I2C_DDC1_EDID_DETECT_ENABLE
, 0);
182 return GPIO_RESULT_OK
;
189 return GPIO_RESULT_NON_SPECIFIC_ERROR
;
192 static const struct hw_gpio_pin_funcs funcs
= {
194 .open
= dal_hw_gpio_open
,
195 .get_value
= dal_hw_gpio_get_value
,
196 .set_value
= dal_hw_gpio_set_value
,
197 .set_config
= set_config
,
198 .change_mode
= dal_hw_gpio_change_mode
,
199 .close
= dal_hw_gpio_close
,
202 static bool construct(
206 struct dc_context
*ctx
)
208 if ((en
< GPIO_DDC_LINE_MIN
) || (en
> GPIO_DDC_LINE_MAX
)) {
209 ASSERT_CRITICAL(false);
213 if (!dal_hw_gpio_construct(&ddc
->base
, id
, en
, ctx
)) {
214 ASSERT_CRITICAL(false);
218 ddc
->base
.base
.funcs
= &funcs
;
223 struct hw_gpio_pin
*dal_hw_ddc_create(
224 struct dc_context
*ctx
,
228 struct hw_ddc
*pin
= dm_alloc(sizeof(struct hw_ddc
));
231 ASSERT_CRITICAL(false);
235 if (construct(pin
, id
, en
, ctx
))
236 return &pin
->base
.base
;
238 ASSERT_CRITICAL(false);