Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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
 36bool link_get_hpd_state(struct dc_link *link)
 37{
 38	uint32_t state;
 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 for
198		 * only 100ms on DELL U2413
199		 * 0: some passive dongle still show aux mode instead of i2c
200		 * 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}