1 /* 2 * Copyright 2022 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 /* 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. This 30 * file only manages basic HPD functionality. It doesn't manage detection or 31 * feature or signal specific HPD behaviors. 32 */ 33 #include "link_hpd.h" 34 #include "gpio_service_interface.h" 35 36 bool link_get_hpd_state(struct dc_link *link) 37 { 38 if (link->link_enc) 39 return link->link_enc->funcs->get_hpd_state(link->link_enc); 40 else 41 return false; 42 } 43 44 void link_enable_hpd(const struct dc_link *link) 45 { 46 if (link->link_enc) 47 link->link_enc->funcs->enable_hpd(link->link_enc); 48 } 49 50 void link_disable_hpd(const struct dc_link *link) 51 { 52 if (link->link_enc) 53 link->link_enc->funcs->disable_hpd(link->link_enc); 54 } 55 56 void link_enable_hpd_filter(struct dc_link *link, bool enable) 57 { 58 if (enable) { 59 link->is_hpd_filter_disabled = false; 60 program_hpd_filter(link); 61 } else { 62 link->is_hpd_filter_disabled = true; 63 if (link->link_enc) 64 link->link_enc->funcs->program_hpd_filter(link->link_enc, 0, 0); 65 } 66 } 67 68 bool program_hpd_filter(const struct dc_link *link) 69 { 70 int delay_on_connect_in_ms = 0; 71 int delay_on_disconnect_in_ms = 0; 72 73 if (link->is_hpd_filter_disabled || !link->link_enc) { 74 ASSERT(link->link_enc); 75 return false; 76 } 77 78 /* Verify feature is supported */ 79 switch (link->connector_signal) { 80 case SIGNAL_TYPE_DVI_SINGLE_LINK: 81 case SIGNAL_TYPE_DVI_DUAL_LINK: 82 case SIGNAL_TYPE_HDMI_TYPE_A: 83 case SIGNAL_TYPE_HDMI_FRL: 84 /* Program hpd filter */ 85 delay_on_connect_in_ms = 500; 86 delay_on_disconnect_in_ms = 100; 87 break; 88 case SIGNAL_TYPE_DISPLAY_PORT: 89 case SIGNAL_TYPE_DISPLAY_PORT_MST: 90 /* Program hpd filter to allow DP signal to settle */ 91 /* 500: not able to detect MST <-> SST switch as HPD is low for 92 * only 100ms on DELL U2413 93 * 0: some passive dongle still show aux mode instead of i2c 94 * 20-50: not enough to hide bouncing HPD with passive dongle. 95 * also see intermittent i2c read issues. 96 */ 97 delay_on_connect_in_ms = 80; 98 delay_on_disconnect_in_ms = 0; 99 break; 100 case SIGNAL_TYPE_LVDS: 101 case SIGNAL_TYPE_EDP: 102 default: 103 /* Don't program hpd filter */ 104 return false; 105 } 106 107 return link->link_enc->funcs->program_hpd_filter(link->link_enc, delay_on_connect_in_ms, delay_on_disconnect_in_ms); 108 } 109 110 struct gpio *link_get_hpd_gpio(struct dc_bios *dcb, 111 struct graphics_object_id link_id, 112 struct gpio_service *gpio_service) 113 { 114 enum bp_result bp_result; 115 struct graphics_object_hpd_info hpd_info; 116 struct gpio_pin_info pin_info; 117 118 if (dcb->funcs->get_hpd_info(dcb, link_id, &hpd_info) != BP_RESULT_OK) 119 return NULL; 120 121 bp_result = dcb->funcs->get_gpio_pin_info(dcb, 122 hpd_info.hpd_int_gpio_uid, &pin_info); 123 124 if (bp_result != BP_RESULT_OK) { 125 return NULL; 126 } 127 128 return dal_gpio_service_create_irq(gpio_service, 129 pin_info.offset, 130 pin_info.mask); 131 } 132 133 enum hpd_source_id get_hpd_line(struct dc_link *link) 134 { 135 struct gpio *hpd; 136 enum hpd_source_id hpd_id; 137 138 hpd_id = HPD_SOURCEID_UNKNOWN; 139 140 /* Use GPIO path where supported, otherwise use hardware encoder path */ 141 if (link->ctx && link->ctx->dce_version <= DCN_VERSION_4_01) { 142 hpd = link_get_hpd_gpio(link->ctx->dc_bios, link->link_id, 143 link->ctx->gpio_service); 144 } else { 145 hpd = NULL; 146 } 147 148 if (hpd) { 149 switch (dal_irq_get_source(hpd)) { 150 case DC_IRQ_SOURCE_HPD1: 151 hpd_id = HPD_SOURCEID1; 152 break; 153 case DC_IRQ_SOURCE_HPD2: 154 hpd_id = HPD_SOURCEID2; 155 break; 156 case DC_IRQ_SOURCE_HPD3: 157 hpd_id = HPD_SOURCEID3; 158 break; 159 case DC_IRQ_SOURCE_HPD4: 160 hpd_id = HPD_SOURCEID4; 161 break; 162 case DC_IRQ_SOURCE_HPD5: 163 hpd_id = HPD_SOURCEID5; 164 break; 165 case DC_IRQ_SOURCE_HPD6: 166 hpd_id = HPD_SOURCEID6; 167 break; 168 default: 169 BREAK_TO_DEBUGGER(); 170 break; 171 } 172 173 dal_gpio_destroy_irq(&hpd); 174 } 175 176 return hpd_id; 177 } 178