brintos

brintos / linux-shallow public Read only

0
0
Text · 12.8 KiB · f344478 Raw
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