1 /* 2 * Copyright 2012-15 Advanced Micro Devices, Inc. 3 * 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: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 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. 21 * 22 * Authors: AMD 23 * 24 */ 25 26 #include "dm_services.h" 27 28 #include "include/gpio_interface.h" 29 #include "include/gpio_types.h" 30 #include "hw_gpio.h" 31 #include "hw_ddc.h" 32 33 #include "reg_helper.h" 34 #include "gpio_regs.h" 35 36 37 #undef FN 38 #define FN(reg_name, field_name) \ 39 gpio_reg_shift(ddc->shifts->field_name), ddc->masks->field_name 40 41 #define CTX \ 42 ddc->base.base.ctx 43 #define REG(reg)\ 44 (ddc->regs->reg) 45 46 struct gpio; 47 48 static void dal_hw_ddc_destruct( 49 struct hw_ddc *pin) 50 { 51 dal_hw_gpio_destruct(&pin->base); 52 } 53 54 static void dal_hw_ddc_destroy( 55 struct hw_gpio_pin **ptr) 56 { 57 struct hw_ddc *pin = HW_DDC_FROM_BASE(*ptr); 58 59 dal_hw_ddc_destruct(pin); 60 61 kfree(pin); 62 63 *ptr = NULL; 64 } 65 66 static enum gpio_result set_config( 67 struct hw_gpio_pin *ptr, 68 const struct gpio_config_data *config_data) 69 { 70 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 71 struct hw_gpio *hw_gpio = NULL; 72 uint32_t regval; 73 uint32_t ddc_data_pd_en = 0; 74 uint32_t ddc_clk_pd_en = 0; 75 uint32_t aux_pad_mode = 0; 76 77 hw_gpio = &ddc->base; 78 79 if (hw_gpio == NULL) { 80 ASSERT_CRITICAL(false); 81 return GPIO_RESULT_NULL_HANDLE; 82 } 83 84 regval = REG_GET_3(gpio.MASK_reg, 85 DC_GPIO_DDC1DATA_PD_EN, &ddc_data_pd_en, 86 DC_GPIO_DDC1CLK_PD_EN, &ddc_clk_pd_en, 87 AUX_PAD1_MODE, &aux_pad_mode); 88 89 switch (config_data->config.ddc.type) { 90 case GPIO_DDC_CONFIG_TYPE_MODE_I2C: 91 /* On plug-in, there is a transient level on the pad 92 * which must be discharged through the internal pull-down. 93 * Enable internal pull-down, 2.5msec discharge time 94 * is required for detection of AUX mode */ 95 if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) { 96 if (!ddc_data_pd_en || !ddc_clk_pd_en) { 97 if (hw_gpio->base.en == GPIO_DDC_LINE_DDC_VGA) { 98 // bit 4 of mask has different usage in some cases 99 REG_SET(gpio.MASK_reg, regval, DC_GPIO_DDC1DATA_PD_EN, 1); 100 } else { 101 REG_SET_2(gpio.MASK_reg, regval, 102 DC_GPIO_DDC1DATA_PD_EN, 1, 103 DC_GPIO_DDC1CLK_PD_EN, 1); 104 } 105 if (config_data->type == 106 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) 107 msleep(3); 108 } 109 } else { 110 uint32_t sda_pd_dis = 0; 111 uint32_t scl_pd_dis = 0; 112 113 REG_GET_2(gpio.MASK_reg, 114 DC_GPIO_SDA_PD_DIS, &sda_pd_dis, 115 DC_GPIO_SCL_PD_DIS, &scl_pd_dis); 116 117 if (sda_pd_dis) { 118 REG_SET(gpio.MASK_reg, regval, 119 DC_GPIO_SDA_PD_DIS, 0); 120 121 if (config_data->type == 122 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) 123 msleep(3); 124 } 125 126 if (!scl_pd_dis) { 127 REG_SET(gpio.MASK_reg, regval, 128 DC_GPIO_SCL_PD_DIS, 1); 129 130 if (config_data->type == 131 GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE) 132 msleep(3); 133 } 134 } 135 136 if (aux_pad_mode) { 137 /* let pins to get de-asserted 138 * before setting pad to I2C mode */ 139 if (config_data->config.ddc.data_en_bit_present || 140 config_data->config.ddc.clock_en_bit_present) 141 /* [anaumov] in DAL2, there was 142 * dc_service_delay_in_microseconds(2000); */ 143 msleep(2); 144 145 /* set the I2C pad mode */ 146 /* read the register again, 147 * some bits may have been changed */ 148 REG_UPDATE(gpio.MASK_reg, 149 AUX_PAD1_MODE, 0); 150 } 151 152 if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) { 153 REG_UPDATE(dc_gpio_aux_ctrl_5, DDC_PAD_I2CMODE, 1); 154 } 155 //set DC_IO_aux_rxsel = 2'b01 156 if (ddc->regs->phy_aux_cntl != 0) { 157 REG_UPDATE(phy_aux_cntl, AUX_PAD_RXSEL, 1); 158 } 159 return GPIO_RESULT_OK; 160 case GPIO_DDC_CONFIG_TYPE_MODE_AUX: 161 /* set the AUX pad mode */ 162 if (!aux_pad_mode) { 163 REG_SET(gpio.MASK_reg, regval, 164 AUX_PAD1_MODE, 1); 165 } 166 if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) { 167 REG_UPDATE(dc_gpio_aux_ctrl_5, 168 DDC_PAD_I2CMODE, 0); 169 } 170 171 return GPIO_RESULT_OK; 172 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT: 173 if (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA) { 174 REG_UPDATE_3(ddc_setup, 175 DC_I2C_DDC1_ENABLE, 1, 176 DC_I2C_DDC1_EDID_DETECT_ENABLE, 1, 177 DC_I2C_DDC1_EDID_DETECT_MODE, 0); 178 return GPIO_RESULT_OK; 179 } 180 break; 181 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT: 182 if (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA) { 183 REG_UPDATE_3(ddc_setup, 184 DC_I2C_DDC1_ENABLE, 1, 185 DC_I2C_DDC1_EDID_DETECT_ENABLE, 1, 186 DC_I2C_DDC1_EDID_DETECT_MODE, 1); 187 return GPIO_RESULT_OK; 188 } 189 break; 190 case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING: 191 if (hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA) { 192 REG_UPDATE_2(ddc_setup, 193 DC_I2C_DDC1_ENABLE, 0, 194 DC_I2C_DDC1_EDID_DETECT_ENABLE, 0); 195 return GPIO_RESULT_OK; 196 } 197 break; 198 } 199 200 BREAK_TO_DEBUGGER(); 201 202 return GPIO_RESULT_NON_SPECIFIC_ERROR; 203 } 204 205 static const struct hw_gpio_pin_funcs funcs = { 206 .destroy = dal_hw_ddc_destroy, 207 .open = dal_hw_gpio_open, 208 .get_value = dal_hw_gpio_get_value, 209 .set_value = dal_hw_gpio_set_value, 210 .set_config = set_config, 211 .change_mode = dal_hw_gpio_change_mode, 212 .close = dal_hw_gpio_close, 213 }; 214 215 static void dal_hw_ddc_construct( 216 struct hw_ddc *ddc, 217 enum gpio_id id, 218 uint32_t en, 219 struct dc_context *ctx) 220 { 221 dal_hw_gpio_construct(&ddc->base, id, en, ctx); 222 ddc->base.base.funcs = &funcs; 223 } 224 225 void dal_hw_ddc_init( 226 struct hw_ddc **hw_ddc, 227 struct dc_context *ctx, 228 enum gpio_id id, 229 uint32_t en) 230 { 231 if (en > GPIO_DDC_LINE_MAX) { 232 ASSERT_CRITICAL(false); 233 *hw_ddc = NULL; 234 } 235 236 *hw_ddc = kzalloc_obj(struct hw_ddc); 237 if (!*hw_ddc) { 238 ASSERT_CRITICAL(false); 239 return; 240 } 241 242 dal_hw_ddc_construct(*hw_ddc, id, en, ctx); 243 } 244 245 struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio) 246 { 247 struct hw_ddc *hw_ddc = dal_gpio_get_ddc(gpio); 248 249 return &hw_ddc->base.base; 250 } 251 252 static void store_registers_ddc_i3cpad( 253 struct hw_ddc *ddc) 254 { 255 switch (ddc->base.base.id) { 256 case GPIO_ID_DDC_DATA: 257 REG_GET(dc_i3cpad_control0, DC_I3CPAD_DDCDATA_MASK, &ddc->base.store.mask); 258 REG_GET(dc_i3cpad_control0, DC_I3CPAD_DATA_A, &ddc->base.store.a); 259 REG_GET(dc_i3cpad_control0, DC_I3CPAD_DATA_EN, &ddc->base.store.en); 260 break; 261 case GPIO_ID_DDC_CLOCK: 262 REG_GET(dc_i3cpad_control0, DC_I3CPAD_DDCCLK_MASK, &ddc->base.store.mask); 263 REG_GET(dc_i3cpad_control0, DC_I3CPAD_CLK_A, &ddc->base.store.a); 264 REG_GET(dc_i3cpad_control0, DC_I3CPAD_CLK_EN, &ddc->base.store.en); 265 break; 266 default: 267 break; 268 } 269 } 270 271 static void restore_registers_ddc_i3cpad( 272 struct hw_ddc *ddc) 273 { 274 switch (ddc->base.base.id) { 275 case GPIO_ID_DDC_DATA: 276 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCDATA_MASK, ddc->base.store.mask); 277 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_A, ddc->base.store.a); 278 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_EN, ddc->base.store.en); 279 break; 280 case GPIO_ID_DDC_CLOCK: 281 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCCLK_MASK, ddc->base.store.mask); 282 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_A, ddc->base.store.a); 283 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_EN, ddc->base.store.en); 284 break; 285 default: 286 break; 287 } 288 } 289 290 bool dal_hw_ddc_open_i3cpad( 291 struct hw_gpio_pin *ptr, 292 enum gpio_mode mode) 293 { 294 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 295 296 store_registers_ddc_i3cpad(ddc); 297 298 ptr->opened = (dal_hw_ddc_config_mode_i3cpad(ddc, mode) == GPIO_RESULT_OK); 299 300 return ptr->opened; 301 } 302 303 enum gpio_result dal_hw_ddc_get_value_i3cpad( 304 const struct hw_gpio_pin *ptr, 305 uint32_t *value) 306 { 307 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 308 enum gpio_result result = GPIO_RESULT_OK; 309 310 switch (ptr->mode) { 311 case GPIO_MODE_INPUT: 312 case GPIO_MODE_OUTPUT: 313 case GPIO_MODE_HARDWARE: 314 case GPIO_MODE_FAST_OUTPUT: 315 switch (ddc->base.base.id) { 316 case GPIO_ID_DDC_DATA: 317 REG_GET(dc_i3cpad_control0, DC_I3CPAD_DATA_Y, value); 318 break; 319 case GPIO_ID_DDC_CLOCK: 320 REG_GET(dc_i3cpad_control0, DC_I3CPAD_CLK_Y, value); 321 break; 322 default: 323 break; 324 } 325 break; 326 default: 327 result = GPIO_RESULT_NON_SPECIFIC_ERROR; 328 } 329 return result; 330 } 331 332 enum gpio_result dal_hw_ddc_set_value_i3cpad( 333 const struct hw_gpio_pin *ptr, 334 uint32_t value) 335 { 336 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 337 338 switch (ptr->mode) { 339 case GPIO_MODE_OUTPUT: 340 switch (ddc->base.base.id) { 341 case GPIO_ID_DDC_DATA: 342 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_A, value); 343 break; 344 case GPIO_ID_DDC_CLOCK: 345 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_A, value); 346 break; 347 default: 348 break; 349 } 350 return GPIO_RESULT_OK; 351 case GPIO_MODE_FAST_OUTPUT: 352 /* We use (EN) to faster switch (used in DDC GPIO). 353 * So (A) is grounded, output is driven by (EN = 0) 354 * to pull the line down (output == 0) and (EN=1) 355 * then output is tri-state */ 356 switch (ddc->base.base.id) { 357 case GPIO_ID_DDC_DATA: 358 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_EN, value); 359 break; 360 case GPIO_ID_DDC_CLOCK: 361 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_EN, value); 362 break; 363 default: 364 break; 365 } 366 return GPIO_RESULT_OK; 367 default: 368 return GPIO_RESULT_NON_SPECIFIC_ERROR; 369 } 370 } 371 372 enum gpio_result dal_hw_ddc_change_mode_i3cpad( 373 struct hw_gpio_pin *ptr, 374 enum gpio_mode mode) 375 { 376 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 377 378 return dal_hw_ddc_config_mode_i3cpad(ddc, mode); 379 } 380 381 enum gpio_result dal_hw_ddc_config_mode_i3cpad( 382 struct hw_ddc *ddc, 383 enum gpio_mode mode) 384 { 385 ddc->base.base.mode = mode; 386 387 switch (mode) { 388 case GPIO_MODE_INPUT: 389 /* turn off output enable, act as input pin; 390 * program the pin as GPIO, mask out signal driven by HW 391 */ 392 switch (ddc->base.base.id) { 393 case GPIO_ID_DDC_DATA: 394 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_EN, 0); 395 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCDATA_MASK, 1); 396 break; 397 case GPIO_ID_DDC_CLOCK: 398 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_EN, 0); 399 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCCLK_MASK, 1); 400 break; 401 default: 402 break; 403 } 404 return GPIO_RESULT_OK; 405 406 case GPIO_MODE_OUTPUT: 407 /* turn on output enable, act as output pin; 408 * program the pin as GPIO, mask out signal driven by HW 409 */ 410 switch (ddc->base.base.id) { 411 case GPIO_ID_DDC_DATA: 412 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_A, 0); 413 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCDATA_MASK, 1); 414 break; 415 case GPIO_ID_DDC_CLOCK: 416 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_A, 0); 417 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCCLK_MASK, 1); 418 break; 419 default: 420 break; 421 } 422 return GPIO_RESULT_OK; 423 424 case GPIO_MODE_FAST_OUTPUT: 425 /* grounding the A register then use the EN register bit 426 * will have faster effect on the rise time 427 */ 428 switch (ddc->base.base.id) { 429 case GPIO_ID_DDC_DATA: 430 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DATA_A, 0); 431 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCDATA_MASK, 1); 432 break; 433 case GPIO_ID_DDC_CLOCK: 434 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_CLK_A, 0); 435 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCCLK_MASK, 1); 436 break; 437 default: 438 break; 439 } 440 return GPIO_RESULT_OK; 441 442 case GPIO_MODE_HARDWARE: 443 /* program the pin as tri-state, pin is driven by HW */ 444 switch (ddc->base.base.id) { 445 case GPIO_ID_DDC_DATA: 446 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCDATA_MASK, 0); 447 break; 448 case GPIO_ID_DDC_CLOCK: 449 REG_UPDATE(dc_i3cpad_control0, DC_I3CPAD_DDCCLK_MASK, 0); 450 break; 451 default: 452 break; 453 } 454 return GPIO_RESULT_OK; 455 456 default: 457 case GPIO_MODE_INTERRUPT: 458 /* Interrupt mode supported only by HPD (IrqGpio) old pins. */ 459 return GPIO_RESULT_NON_SPECIFIC_ERROR; 460 } 461 } 462 463 static enum gpio_result dal_hw_ddc_set_config_i3cpad( 464 struct hw_gpio_pin *ptr, 465 const struct gpio_config_data *config_data) 466 { 467 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 468 469 switch (config_data->config.ddc.type) { 470 /* For ASICs with i3cpad module there is no dual pad mode for i3cpads */ 471 case GPIO_DDC_CONFIG_TYPE_MODE_I2C: 472 /* Enable the RX for the PAD (it is disabled by default). */ 473 REG_UPDATE(dc_i3cpad_control1, DC_I3CPAD_RXSEL, 0); 474 return GPIO_RESULT_OK; 475 case GPIO_DDC_CONFIG_TYPE_MODE_AUX: 476 return GPIO_RESULT_OK; 477 478 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT: 479 REG_UPDATE_3(ddc_setup, 480 DC_I2C_DDC1_ENABLE, 1, 481 DC_I2C_DDC1_EDID_DETECT_ENABLE, 1, 482 DC_I2C_DDC1_EDID_DETECT_MODE, 0); 483 return GPIO_RESULT_OK; 484 485 case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT: 486 REG_UPDATE_3(ddc_setup, 487 DC_I2C_DDC1_ENABLE, 1, 488 DC_I2C_DDC1_EDID_DETECT_ENABLE, 1, 489 DC_I2C_DDC1_EDID_DETECT_MODE, 1); 490 return GPIO_RESULT_OK; 491 492 case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING: 493 REG_UPDATE_2(ddc_setup, 494 DC_I2C_DDC1_ENABLE, 0, 495 DC_I2C_DDC1_EDID_DETECT_ENABLE, 0); 496 return GPIO_RESULT_OK; 497 } 498 499 BREAK_TO_DEBUGGER(); 500 return GPIO_RESULT_NON_SPECIFIC_ERROR; 501 } 502 503 void dal_hw_ddc_close_i3cpad( 504 struct hw_gpio_pin *ptr) 505 { 506 struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr); 507 508 restore_registers_ddc_i3cpad(ddc); 509 510 ptr->mode = GPIO_MODE_UNKNOWN; 511 ptr->opened = false; 512 } 513 514 static const struct hw_gpio_pin_funcs funcs_i3cpad = { 515 .destroy = dal_hw_ddc_destroy, 516 .open = dal_hw_ddc_open_i3cpad, 517 .get_value = dal_hw_ddc_get_value_i3cpad, 518 .set_value = dal_hw_ddc_set_value_i3cpad, 519 .set_config = dal_hw_ddc_set_config_i3cpad, 520 .change_mode = dal_hw_ddc_change_mode_i3cpad, 521 .close = dal_hw_ddc_close_i3cpad, 522 }; 523 524 static void dal_hw_ddc_construct_i3cpad( 525 struct hw_ddc *ddc, 526 enum gpio_id id, 527 uint32_t en, 528 struct dc_context *ctx) 529 { 530 dal_hw_gpio_construct(&ddc->base, id, en, ctx); 531 ddc->base.base.funcs = &funcs_i3cpad; 532 } 533 534 void dal_hw_ddc_init_i3cpad( 535 struct hw_ddc **hw_ddc, 536 struct dc_context *ctx, 537 enum gpio_id id, 538 uint32_t en) 539 { 540 if (en > GPIO_DDC_LINE_MAX) { 541 ASSERT_CRITICAL(false); 542 *hw_ddc = NULL; 543 } 544 545 *hw_ddc = kzalloc_obj(struct hw_ddc); 546 if (!*hw_ddc) { 547 ASSERT_CRITICAL(false); 548 return; 549 } 550 551 dal_hw_ddc_construct_i3cpad(*hw_ddc, id, en, ctx); 552 } 553