cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

gpio_service.c (12930B)


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