241 lines · c
1/*2 * Copyright 2022 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/* FILE POLICY AND INTENDED USAGE:27 *28 * This file implements functions that manage basic HPD components such as gpio.29 * It also provides wrapper functions to execute HPD related programming. This30 * file only manages basic HPD functionality. It doesn't manage detection or31 * feature or signal specific HPD behaviors.32 */33#include "link_hpd.h"34#include "gpio_service_interface.h"35 36bool link_get_hpd_state(struct dc_link *link)37{38 uint32_t state = 0;39 40 dal_gpio_lock_pin(link->hpd_gpio);41 dal_gpio_get_value(link->hpd_gpio, &state);42 dal_gpio_unlock_pin(link->hpd_gpio);43 44 return state;45}46 47void link_enable_hpd(const struct dc_link *link)48{49 struct link_encoder *encoder = link->link_enc;50 51 if (encoder != NULL && encoder->funcs->enable_hpd != NULL)52 encoder->funcs->enable_hpd(encoder);53}54 55void link_disable_hpd(const struct dc_link *link)56{57 struct link_encoder *encoder = link->link_enc;58 59 if (encoder != NULL && encoder->funcs->enable_hpd != NULL)60 encoder->funcs->disable_hpd(encoder);61}62 63void link_enable_hpd_filter(struct dc_link *link, bool enable)64{65 struct gpio *hpd;66 67 if (enable) {68 link->is_hpd_filter_disabled = false;69 program_hpd_filter(link);70 } else {71 link->is_hpd_filter_disabled = true;72 /* Obtain HPD handle */73 hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, link->ctx->gpio_service);74 75 if (!hpd)76 return;77 78 /* Setup HPD filtering */79 if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {80 struct gpio_hpd_config config;81 82 config.delay_on_connect = 0;83 config.delay_on_disconnect = 0;84 85 dal_irq_setup_hpd_filter(hpd, &config);86 87 dal_gpio_close(hpd);88 } else {89 ASSERT_CRITICAL(false);90 }91 /* Release HPD handle */92 dal_gpio_destroy_irq(&hpd);93 }94}95 96struct gpio *link_get_hpd_gpio(struct dc_bios *dcb,97 struct graphics_object_id link_id,98 struct gpio_service *gpio_service)99{100 enum bp_result bp_result;101 struct graphics_object_hpd_info hpd_info;102 struct gpio_pin_info pin_info;103 104 if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK)105 return NULL;106 107 bp_result = dcb->funcs->get_gpio_pin_info(dcb,108 hpd_info.hpd_int_gpio_uid, &pin_info);109 110 if (bp_result != BP_RESULT_OK) {111 ASSERT(bp_result == BP_RESULT_NORECORD);112 return NULL;113 }114 115 return dal_gpio_service_create_irq(gpio_service,116 pin_info.offset,117 pin_info.mask);118}119 120bool query_hpd_status(struct dc_link *link, uint32_t *is_hpd_high)121{122 struct gpio *hpd_pin = link_get_hpd_gpio(123 link->ctx->dc_bios, link->link_id,124 link->ctx->gpio_service);125 if (!hpd_pin)126 return false;127 128 dal_gpio_open(hpd_pin, GPIO_MODE_INTERRUPT);129 dal_gpio_get_value(hpd_pin, is_hpd_high);130 dal_gpio_close(hpd_pin);131 dal_gpio_destroy_irq(&hpd_pin);132 return true;133}134 135enum hpd_source_id get_hpd_line(struct dc_link *link)136{137 struct gpio *hpd;138 enum hpd_source_id hpd_id;139 140 hpd_id = HPD_SOURCEID_UNKNOWN;141 142 hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,143 link->ctx->gpio_service);144 145 if (hpd) {146 switch (dal_irq_get_source(hpd)) {147 case DC_IRQ_SOURCE_HPD1:148 hpd_id = HPD_SOURCEID1;149 break;150 case DC_IRQ_SOURCE_HPD2:151 hpd_id = HPD_SOURCEID2;152 break;153 case DC_IRQ_SOURCE_HPD3:154 hpd_id = HPD_SOURCEID3;155 break;156 case DC_IRQ_SOURCE_HPD4:157 hpd_id = HPD_SOURCEID4;158 break;159 case DC_IRQ_SOURCE_HPD5:160 hpd_id = HPD_SOURCEID5;161 break;162 case DC_IRQ_SOURCE_HPD6:163 hpd_id = HPD_SOURCEID6;164 break;165 default:166 BREAK_TO_DEBUGGER();167 break;168 }169 170 dal_gpio_destroy_irq(&hpd);171 }172 173 return hpd_id;174}175 176bool program_hpd_filter(const struct dc_link *link)177{178 bool result = false;179 struct gpio *hpd;180 int delay_on_connect_in_ms = 0;181 int delay_on_disconnect_in_ms = 0;182 183 if (link->is_hpd_filter_disabled)184 return false;185 /* Verify feature is supported */186 switch (link->connector_signal) {187 case SIGNAL_TYPE_DVI_SINGLE_LINK:188 case SIGNAL_TYPE_DVI_DUAL_LINK:189 case SIGNAL_TYPE_HDMI_TYPE_A:190 /* Program hpd filter */191 delay_on_connect_in_ms = 500;192 delay_on_disconnect_in_ms = 100;193 break;194 case SIGNAL_TYPE_DISPLAY_PORT:195 case SIGNAL_TYPE_DISPLAY_PORT_MST:196 /* Program hpd filter to allow DP signal to settle */197 /* 500: not able to detect MST <-> SST switch as HPD is low for198 * only 100ms on DELL U2413199 * 0: some passive dongle still show aux mode instead of i2c200 * 20-50: not enough to hide bouncing HPD with passive dongle.201 * also see intermittent i2c read issues.202 */203 delay_on_connect_in_ms = 80;204 delay_on_disconnect_in_ms = 0;205 break;206 case SIGNAL_TYPE_LVDS:207 case SIGNAL_TYPE_EDP:208 default:209 /* Don't program hpd filter */210 return false;211 }212 213 /* Obtain HPD handle */214 hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id,215 link->ctx->gpio_service);216 217 if (!hpd)218 return result;219 220 /* Setup HPD filtering */221 if (dal_gpio_open(hpd, GPIO_MODE_INTERRUPT) == GPIO_RESULT_OK) {222 struct gpio_hpd_config config;223 224 config.delay_on_connect = delay_on_connect_in_ms;225 config.delay_on_disconnect = delay_on_disconnect_in_ms;226 227 dal_irq_setup_hpd_filter(hpd, &config);228 229 dal_gpio_close(hpd);230 231 result = true;232 } else {233 ASSERT_CRITICAL(false);234 }235 236 /* Release HPD handle */237 dal_gpio_destroy_irq(&hpd);238 239 return result;240}241