663 lines · c
1/*2 * Copyright 2012-15 Advanced Micro Devices, Inc.3 *4 * Permission is hereby granted, free of charge, to any person obtaining a5 * copy of this software and associated documentation files (the "Software"),6 * to deal in the Software without restriction, including without limitation7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,8 * and/or sell copies of the Software, and to permit persons to whom the9 * Software is furnished to do so, subject to the following conditions:10 *11 * The above copyright notice and this permission notice shall be included in12 * all copies or substantial portions of the Software.13 *14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR18 * 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 OR20 * OTHER DEALINGS IN THE SOFTWARE.21 *22 * Authors: AMD23 *24 */25 26/*27 * Pre-requisites: headers required by header of this unit28 */29 30#include "dm_services.h"31#include "include/gpio_interface.h"32#include "include/gpio_service_interface.h"33#include "hw_translate.h"34#include "hw_factory.h"35 36/*37 * Header of this unit38 */39 40#include "gpio_service.h"41 42/*43 * Post-requisites: headers required by this unit44 */45 46#include "hw_gpio.h"47 48/*49 * @brief50 * Public API.51 */52 53struct gpio_service *dal_gpio_service_create(54 enum dce_version dce_version,55 enum dce_environment dce_environment,56 struct dc_context *ctx)57{58 struct gpio_service *service;59 int32_t index_of_id;60 61 service = kzalloc(sizeof(struct gpio_service), GFP_KERNEL);62 63 if (!service) {64 BREAK_TO_DEBUGGER();65 return NULL;66 }67 68 if (!dal_hw_translate_init(&service->translate, dce_version,69 dce_environment)) {70 BREAK_TO_DEBUGGER();71 goto failure_1;72 }73 74 if (!dal_hw_factory_init(&service->factory, dce_version,75 dce_environment)) {76 BREAK_TO_DEBUGGER();77 goto failure_1;78 }79 80 /* allocate and initialize busyness storage */81 {82 index_of_id = 0;83 service->ctx = ctx;84 85 do {86 uint32_t number_of_bits =87 service->factory.number_of_pins[index_of_id];88 uint32_t i = 0;89 90 if (number_of_bits) {91 service->busyness[index_of_id] =92 kcalloc(number_of_bits, sizeof(char),93 GFP_KERNEL);94 95 if (!service->busyness[index_of_id]) {96 BREAK_TO_DEBUGGER();97 goto failure_2;98 }99 100 do {101 service->busyness[index_of_id][i] = 0;102 ++i;103 } while (i < number_of_bits);104 } else {105 service->busyness[index_of_id] = NULL;106 }107 108 ++index_of_id;109 } while (index_of_id < GPIO_ID_COUNT);110 }111 112 return service;113 114failure_2:115 while (index_of_id > 0) {116 --index_of_id;117 kfree(service->busyness[index_of_id]);118 }119 120failure_1:121 kfree(service);122 123 return NULL;124}125 126struct gpio *dal_gpio_service_create_irq(127 struct gpio_service *service,128 uint32_t offset,129 uint32_t mask)130{131 enum gpio_id id = 0;132 uint32_t en;133 134 if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {135 ASSERT_CRITICAL(false);136 return NULL;137 }138 139 return dal_gpio_create_irq(service, id, en);140}141 142struct gpio *dal_gpio_service_create_generic_mux(143 struct gpio_service *service,144 uint32_t offset,145 uint32_t mask)146{147 enum gpio_id id = 0;148 uint32_t en;149 struct gpio *generic;150 151 if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en)) {152 ASSERT_CRITICAL(false);153 return NULL;154 }155 156 generic = dal_gpio_create(157 service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);158 159 return generic;160}161 162void dal_gpio_destroy_generic_mux(163 struct gpio **mux)164{165 if (!mux || !*mux) {166 ASSERT_CRITICAL(false);167 return;168 }169 170 dal_gpio_destroy(mux);171 kfree(*mux);172 173 *mux = NULL;174}175 176struct gpio_pin_info dal_gpio_get_generic_pin_info(177 struct gpio_service *service,178 enum gpio_id id,179 uint32_t en)180{181 struct gpio_pin_info pin = {0};182 183 if (service->translate.funcs->id_to_offset) {184 service->translate.funcs->id_to_offset(id, en, &pin);185 } else {186 pin.mask = 0xFFFFFFFF;187 pin.offset = 0xFFFFFFFF;188 }189 190 return pin;191}192 193void dal_gpio_service_destroy(194 struct gpio_service **ptr)195{196 if (!ptr || !*ptr) {197 BREAK_TO_DEBUGGER();198 return;199 }200 201 /* free business storage */202 {203 uint32_t index_of_id = 0;204 205 do {206 kfree((*ptr)->busyness[index_of_id]);207 208 ++index_of_id;209 } while (index_of_id < GPIO_ID_COUNT);210 }211 212 kfree(*ptr);213 214 *ptr = NULL;215}216 217enum gpio_result dal_mux_setup_config(218 struct gpio *mux,219 struct gpio_generic_mux_config *config)220{221 struct gpio_config_data config_data;222 223 if (!config)224 return GPIO_RESULT_INVALID_DATA;225 226 config_data.config.generic_mux = *config;227 config_data.type = GPIO_CONFIG_TYPE_GENERIC_MUX;228 229 return dal_gpio_set_config(mux, &config_data);230}231 232/*233 * @brief234 * Private API.235 */236 237static bool is_pin_busy(238 const struct gpio_service *service,239 enum gpio_id id,240 uint32_t en)241{242 if (id == GPIO_ID_UNKNOWN)243 return false;244 245 return service->busyness[id][en];246}247 248static void set_pin_busy(249 struct gpio_service *service,250 enum gpio_id id,251 uint32_t en)252{253 if (id == GPIO_ID_UNKNOWN)254 return;255 256 service->busyness[id][en] = true;257}258 259static void set_pin_free(260 struct gpio_service *service,261 enum gpio_id id,262 uint32_t en)263{264 if (id == GPIO_ID_UNKNOWN)265 return;266 267 service->busyness[id][en] = false;268}269 270enum gpio_result dal_gpio_service_lock(271 struct gpio_service *service,272 enum gpio_id id,273 uint32_t en)274{275 if (id != GPIO_ID_UNKNOWN && !service->busyness[id]) {276 ASSERT_CRITICAL(false);277 return GPIO_RESULT_OPEN_FAILED;278 }279 280 set_pin_busy(service, id, en);281 return GPIO_RESULT_OK;282}283 284enum gpio_result dal_gpio_service_unlock(285 struct gpio_service *service,286 enum gpio_id id,287 uint32_t en)288{289 if (id != GPIO_ID_UNKNOWN && !service->busyness[id]) {290 ASSERT_CRITICAL(false);291 return GPIO_RESULT_OPEN_FAILED;292 }293 294 set_pin_free(service, id, en);295 return GPIO_RESULT_OK;296}297 298enum gpio_result dal_gpio_service_open(299 struct gpio *gpio)300{301 struct gpio_service *service = gpio->service;302 enum gpio_id id = gpio->id;303 uint32_t en = gpio->en;304 enum gpio_mode mode = gpio->mode;305 306 struct hw_gpio_pin **pin = &gpio->pin;307 308 309 if (!service->busyness[id]) {310 ASSERT_CRITICAL(false);311 return GPIO_RESULT_OPEN_FAILED;312 }313 314 if (is_pin_busy(service, id, en)) {315 ASSERT_CRITICAL(false);316 return GPIO_RESULT_DEVICE_BUSY;317 }318 319 switch (id) {320 case GPIO_ID_DDC_DATA:321 *pin = service->factory.funcs->get_ddc_pin(gpio);322 service->factory.funcs->define_ddc_registers(*pin, en);323 break;324 case GPIO_ID_DDC_CLOCK:325 *pin = service->factory.funcs->get_ddc_pin(gpio);326 service->factory.funcs->define_ddc_registers(*pin, en);327 break;328 case GPIO_ID_GENERIC:329 *pin = service->factory.funcs->get_generic_pin(gpio);330 service->factory.funcs->define_generic_registers(*pin, en);331 break;332 case GPIO_ID_HPD:333 *pin = service->factory.funcs->get_hpd_pin(gpio);334 service->factory.funcs->define_hpd_registers(*pin, en);335 break;336 337 //TODO: gsl and sync support? create_sync and create_gsl are NULL338 case GPIO_ID_SYNC:339 case GPIO_ID_GSL:340 break;341 default:342 ASSERT_CRITICAL(false);343 return GPIO_RESULT_NON_SPECIFIC_ERROR;344 }345 346 if (!*pin) {347 ASSERT_CRITICAL(false);348 return GPIO_RESULT_NON_SPECIFIC_ERROR;349 }350 351 if (!(*pin)->funcs->open(*pin, mode)) {352 ASSERT_CRITICAL(false);353 dal_gpio_service_close(service, pin);354 return GPIO_RESULT_OPEN_FAILED;355 }356 357 set_pin_busy(service, id, en);358 return GPIO_RESULT_OK;359}360 361void dal_gpio_service_close(362 struct gpio_service *service,363 struct hw_gpio_pin **ptr)364{365 struct hw_gpio_pin *pin;366 367 if (!ptr) {368 ASSERT_CRITICAL(false);369 return;370 }371 372 pin = *ptr;373 374 if (pin) {375 set_pin_free(service, pin->id, pin->en);376 377 pin->funcs->close(pin);378 379 *ptr = NULL;380 }381}382 383enum dc_irq_source dal_irq_get_source(384 const struct gpio *irq)385{386 enum gpio_id id = dal_gpio_get_id(irq);387 388 switch (id) {389 case GPIO_ID_HPD:390 return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1 +391 dal_gpio_get_enum(irq));392 case GPIO_ID_GPIO_PAD:393 return (enum dc_irq_source)(DC_IRQ_SOURCE_GPIOPAD0 +394 dal_gpio_get_enum(irq));395 default:396 return DC_IRQ_SOURCE_INVALID;397 }398}399 400enum dc_irq_source dal_irq_get_rx_source(401 const struct gpio *irq)402{403 enum gpio_id id = dal_gpio_get_id(irq);404 405 switch (id) {406 case GPIO_ID_HPD:407 return (enum dc_irq_source)(DC_IRQ_SOURCE_HPD1RX +408 dal_gpio_get_enum(irq));409 default:410 return DC_IRQ_SOURCE_INVALID;411 }412}413 414enum gpio_result dal_irq_setup_hpd_filter(415 struct gpio *irq,416 struct gpio_hpd_config *config)417{418 struct gpio_config_data config_data;419 420 if (!config)421 return GPIO_RESULT_INVALID_DATA;422 423 config_data.type = GPIO_CONFIG_TYPE_HPD;424 config_data.config.hpd = *config;425 426 return dal_gpio_set_config(irq, &config_data);427}428 429/*430 * @brief431 * Creation and destruction432 */433 434struct gpio *dal_gpio_create_irq(435 struct gpio_service *service,436 enum gpio_id id,437 uint32_t en)438{439 struct gpio *irq;440 441 switch (id) {442 case GPIO_ID_HPD:443 case GPIO_ID_GPIO_PAD:444 break;445 default:446 id = GPIO_ID_HPD;447 ASSERT_CRITICAL(false);448 return NULL;449 }450 451 irq = dal_gpio_create(452 service, id, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);453 454 if (irq)455 return irq;456 457 ASSERT_CRITICAL(false);458 return NULL;459}460 461void dal_gpio_destroy_irq(462 struct gpio **irq)463{464 if (!irq || !*irq) {465 ASSERT_CRITICAL(false);466 return;467 }468 469 dal_gpio_destroy(irq);470 kfree(*irq);471 472 *irq = NULL;473}474 475struct ddc *dal_gpio_create_ddc(476 struct gpio_service *service,477 uint32_t offset,478 uint32_t mask,479 struct gpio_ddc_hw_info *info)480{481 enum gpio_id id;482 uint32_t en;483 struct ddc *ddc;484 485 if (!service->translate.funcs->offset_to_id(offset, mask, &id, &en))486 return NULL;487 488 ddc = kzalloc(sizeof(struct ddc), GFP_KERNEL);489 490 if (!ddc) {491 BREAK_TO_DEBUGGER();492 return NULL;493 }494 495 ddc->pin_data = dal_gpio_create(496 service, GPIO_ID_DDC_DATA, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);497 498 if (!ddc->pin_data) {499 BREAK_TO_DEBUGGER();500 goto failure_1;501 }502 503 ddc->pin_clock = dal_gpio_create(504 service, GPIO_ID_DDC_CLOCK, en, GPIO_PIN_OUTPUT_STATE_DEFAULT);505 506 if (!ddc->pin_clock) {507 BREAK_TO_DEBUGGER();508 goto failure_2;509 }510 511 ddc->hw_info = *info;512 513 ddc->ctx = service->ctx;514 515 return ddc;516 517failure_2:518 dal_gpio_destroy(&ddc->pin_data);519 520failure_1:521 kfree(ddc);522 523 return NULL;524}525 526void dal_gpio_destroy_ddc(527 struct ddc **ddc)528{529 if (!ddc || !*ddc) {530 BREAK_TO_DEBUGGER();531 return;532 }533 534 dal_ddc_close(*ddc);535 dal_gpio_destroy(&(*ddc)->pin_data);536 dal_gpio_destroy(&(*ddc)->pin_clock);537 kfree(*ddc);538 539 *ddc = NULL;540}541 542enum gpio_result dal_ddc_open(543 struct ddc *ddc,544 enum gpio_mode mode,545 enum gpio_ddc_config_type config_type)546{547 enum gpio_result result;548 549 struct gpio_config_data config_data;550 struct hw_gpio *hw_data;551 struct hw_gpio *hw_clock;552 553 result = dal_gpio_open_ex(ddc->pin_data, mode);554 555 if (result != GPIO_RESULT_OK) {556 BREAK_TO_DEBUGGER();557 return result;558 }559 560 result = dal_gpio_open_ex(ddc->pin_clock, mode);561 562 if (result != GPIO_RESULT_OK) {563 BREAK_TO_DEBUGGER();564 goto failure;565 }566 567 /* DDC clock and data pins should belong568 * to the same DDC block id,569 * we use the data pin to set the pad mode. */570 571 if (mode == GPIO_MODE_INPUT)572 /* this is from detect_sink_type,573 * we need extra delay there */574 config_data.type = GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE;575 else576 config_data.type = GPIO_CONFIG_TYPE_DDC;577 578 config_data.config.ddc.type = config_type;579 580 hw_data = FROM_HW_GPIO_PIN(ddc->pin_data->pin);581 hw_clock = FROM_HW_GPIO_PIN(ddc->pin_clock->pin);582 583 config_data.config.ddc.data_en_bit_present = hw_data->store.en != 0;584 config_data.config.ddc.clock_en_bit_present = hw_clock->store.en != 0;585 586 result = dal_gpio_set_config(ddc->pin_data, &config_data);587 588 if (result == GPIO_RESULT_OK)589 return result;590 591 BREAK_TO_DEBUGGER();592 593 dal_gpio_close(ddc->pin_clock);594 595failure:596 dal_gpio_close(ddc->pin_data);597 598 return result;599}600 601enum gpio_result dal_ddc_change_mode(602 struct ddc *ddc,603 enum gpio_mode mode)604{605 enum gpio_result result;606 607 enum gpio_mode original_mode =608 dal_gpio_get_mode(ddc->pin_data);609 610 result = dal_gpio_change_mode(ddc->pin_data, mode);611 612 /* [anaumov] DAL2 code returns GPIO_RESULT_NON_SPECIFIC_ERROR613 * in case of failures;614 * set_mode() is so that, in case of failure,615 * we must explicitly set original mode */616 617 if (result != GPIO_RESULT_OK)618 goto failure;619 620 result = dal_gpio_change_mode(ddc->pin_clock, mode);621 622 if (result == GPIO_RESULT_OK)623 return result;624 625 dal_gpio_change_mode(ddc->pin_clock, original_mode);626 627failure:628 dal_gpio_change_mode(ddc->pin_data, original_mode);629 630 return result;631}632 633enum gpio_ddc_line dal_ddc_get_line(634 const struct ddc *ddc)635{636 return (enum gpio_ddc_line)dal_gpio_get_enum(ddc->pin_data);637}638 639enum gpio_result dal_ddc_set_config(640 struct ddc *ddc,641 enum gpio_ddc_config_type config_type)642{643 struct gpio_config_data config_data;644 645 config_data.type = GPIO_CONFIG_TYPE_DDC;646 647 config_data.config.ddc.type = config_type;648 config_data.config.ddc.data_en_bit_present = false;649 config_data.config.ddc.clock_en_bit_present = false;650 651 return dal_gpio_set_config(ddc->pin_data, &config_data);652}653 654void dal_ddc_close(655 struct ddc *ddc)656{657 if (ddc != NULL) {658 dal_gpio_close(ddc->pin_clock);659 dal_gpio_close(ddc->pin_data);660 }661}662 663