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

hw_ddc.c (6497B)


      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#include <linux/delay.h>
     27#include <linux/slab.h>
     28
     29#include "dm_services.h"
     30
     31#include "include/gpio_interface.h"
     32#include "include/gpio_types.h"
     33#include "hw_gpio.h"
     34#include "hw_ddc.h"
     35
     36#include "reg_helper.h"
     37#include "gpio_regs.h"
     38
     39
     40#undef FN
     41#define FN(reg_name, field_name) \
     42	ddc->shifts->field_name, ddc->masks->field_name
     43
     44#define CTX \
     45	ddc->base.base.ctx
     46#define REG(reg)\
     47	(ddc->regs->reg)
     48
     49struct gpio;
     50
     51static void dal_hw_ddc_destruct(
     52	struct hw_ddc *pin)
     53{
     54	dal_hw_gpio_destruct(&pin->base);
     55}
     56
     57static void dal_hw_ddc_destroy(
     58	struct hw_gpio_pin **ptr)
     59{
     60	struct hw_ddc *pin = HW_DDC_FROM_BASE(*ptr);
     61
     62	dal_hw_ddc_destruct(pin);
     63
     64	kfree(pin);
     65
     66	*ptr = NULL;
     67}
     68
     69static enum gpio_result set_config(
     70	struct hw_gpio_pin *ptr,
     71	const struct gpio_config_data *config_data)
     72{
     73	struct hw_ddc *ddc = HW_DDC_FROM_BASE(ptr);
     74	struct hw_gpio *hw_gpio = NULL;
     75	uint32_t regval;
     76	uint32_t ddc_data_pd_en = 0;
     77	uint32_t ddc_clk_pd_en = 0;
     78	uint32_t aux_pad_mode = 0;
     79
     80	hw_gpio = &ddc->base;
     81
     82	if (hw_gpio == NULL) {
     83		ASSERT_CRITICAL(false);
     84		return GPIO_RESULT_NULL_HANDLE;
     85	}
     86
     87	regval = REG_GET_3(gpio.MASK_reg,
     88			DC_GPIO_DDC1DATA_PD_EN, &ddc_data_pd_en,
     89			DC_GPIO_DDC1CLK_PD_EN, &ddc_clk_pd_en,
     90			AUX_PAD1_MODE, &aux_pad_mode);
     91
     92	switch (config_data->config.ddc.type) {
     93	case GPIO_DDC_CONFIG_TYPE_MODE_I2C:
     94		/* On plug-in, there is a transient level on the pad
     95		 * which must be discharged through the internal pull-down.
     96		 * Enable internal pull-down, 2.5msec discharge time
     97		 * is required for detection of AUX mode */
     98		if (hw_gpio->base.en != GPIO_DDC_LINE_VIP_PAD) {
     99			if (!ddc_data_pd_en || !ddc_clk_pd_en) {
    100
    101				REG_SET_2(gpio.MASK_reg, regval,
    102						DC_GPIO_DDC1DATA_PD_EN, 1,
    103						DC_GPIO_DDC1CLK_PD_EN, 1);
    104
    105				if (config_data->type ==
    106						GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
    107					msleep(3);
    108			}
    109		} else {
    110			uint32_t sda_pd_dis = 0;
    111			uint32_t scl_pd_dis = 0;
    112
    113			REG_GET_2(gpio.MASK_reg,
    114				  DC_GPIO_SDA_PD_DIS, &sda_pd_dis,
    115				  DC_GPIO_SCL_PD_DIS, &scl_pd_dis);
    116
    117			if (sda_pd_dis) {
    118				REG_SET(gpio.MASK_reg, regval,
    119						DC_GPIO_SDA_PD_DIS, 0);
    120
    121				if (config_data->type ==
    122						GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
    123					msleep(3);
    124			}
    125
    126			if (!scl_pd_dis) {
    127				REG_SET(gpio.MASK_reg, regval,
    128						DC_GPIO_SCL_PD_DIS, 1);
    129
    130				if (config_data->type ==
    131						GPIO_CONFIG_TYPE_I2C_AUX_DUAL_MODE)
    132					msleep(3);
    133			}
    134		}
    135
    136		if (aux_pad_mode) {
    137			/* let pins to get de-asserted
    138			 * before setting pad to I2C mode */
    139			if (config_data->config.ddc.data_en_bit_present ||
    140				config_data->config.ddc.clock_en_bit_present)
    141				/* [anaumov] in DAL2, there was
    142				 * dc_service_delay_in_microseconds(2000); */
    143				msleep(2);
    144
    145			/* set the I2C pad mode */
    146			/* read the register again,
    147			 * some bits may have been changed */
    148			REG_UPDATE(gpio.MASK_reg,
    149					AUX_PAD1_MODE, 0);
    150		}
    151
    152		if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) {
    153				REG_UPDATE(dc_gpio_aux_ctrl_5, DDC_PAD_I2CMODE, 1);
    154		}
    155		//set  DC_IO_aux_rxsel = 2'b01
    156		if (ddc->regs->phy_aux_cntl != 0) {
    157				REG_UPDATE(phy_aux_cntl, AUX_PAD_RXSEL, 1);
    158		}
    159		return GPIO_RESULT_OK;
    160	case GPIO_DDC_CONFIG_TYPE_MODE_AUX:
    161		/* set the AUX pad mode */
    162		if (!aux_pad_mode) {
    163			REG_SET(gpio.MASK_reg, regval,
    164					AUX_PAD1_MODE, 1);
    165		}
    166		if (ddc->regs->dc_gpio_aux_ctrl_5 != 0) {
    167			REG_UPDATE(dc_gpio_aux_ctrl_5,
    168					DDC_PAD_I2CMODE, 0);
    169		}
    170
    171		return GPIO_RESULT_OK;
    172	case GPIO_DDC_CONFIG_TYPE_POLL_FOR_CONNECT:
    173		if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
    174			(hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
    175			REG_UPDATE_3(ddc_setup,
    176				DC_I2C_DDC1_ENABLE, 1,
    177				DC_I2C_DDC1_EDID_DETECT_ENABLE, 1,
    178				DC_I2C_DDC1_EDID_DETECT_MODE, 0);
    179			return GPIO_RESULT_OK;
    180		}
    181	break;
    182	case GPIO_DDC_CONFIG_TYPE_POLL_FOR_DISCONNECT:
    183		if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
    184			(hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
    185			REG_UPDATE_3(ddc_setup,
    186				DC_I2C_DDC1_ENABLE, 1,
    187				DC_I2C_DDC1_EDID_DETECT_ENABLE, 1,
    188				DC_I2C_DDC1_EDID_DETECT_MODE, 1);
    189			return GPIO_RESULT_OK;
    190		}
    191	break;
    192	case GPIO_DDC_CONFIG_TYPE_DISABLE_POLLING:
    193		if ((hw_gpio->base.en >= GPIO_DDC_LINE_DDC1) &&
    194			(hw_gpio->base.en <= GPIO_DDC_LINE_DDC_VGA)) {
    195			REG_UPDATE_2(ddc_setup,
    196				DC_I2C_DDC1_ENABLE, 0,
    197				DC_I2C_DDC1_EDID_DETECT_ENABLE, 0);
    198			return GPIO_RESULT_OK;
    199		}
    200	break;
    201	}
    202
    203	BREAK_TO_DEBUGGER();
    204
    205	return GPIO_RESULT_NON_SPECIFIC_ERROR;
    206}
    207
    208static const struct hw_gpio_pin_funcs funcs = {
    209	.destroy = dal_hw_ddc_destroy,
    210	.open = dal_hw_gpio_open,
    211	.get_value = dal_hw_gpio_get_value,
    212	.set_value = dal_hw_gpio_set_value,
    213	.set_config = set_config,
    214	.change_mode = dal_hw_gpio_change_mode,
    215	.close = dal_hw_gpio_close,
    216};
    217
    218static void dal_hw_ddc_construct(
    219	struct hw_ddc *ddc,
    220	enum gpio_id id,
    221	uint32_t en,
    222	struct dc_context *ctx)
    223{
    224	dal_hw_gpio_construct(&ddc->base, id, en, ctx);
    225	ddc->base.base.funcs = &funcs;
    226}
    227
    228void dal_hw_ddc_init(
    229	struct hw_ddc **hw_ddc,
    230	struct dc_context *ctx,
    231	enum gpio_id id,
    232	uint32_t en)
    233{
    234	if ((en < GPIO_DDC_LINE_MIN) || (en > GPIO_DDC_LINE_MAX)) {
    235		ASSERT_CRITICAL(false);
    236		*hw_ddc = NULL;
    237	}
    238
    239	*hw_ddc = kzalloc(sizeof(struct hw_ddc), GFP_KERNEL);
    240	if (!*hw_ddc) {
    241		ASSERT_CRITICAL(false);
    242		return;
    243	}
    244
    245	dal_hw_ddc_construct(*hw_ddc, id, en, ctx);
    246}
    247
    248struct hw_gpio_pin *dal_hw_ddc_get_pin(struct gpio *gpio)
    249{
    250	struct hw_ddc *hw_ddc = dal_gpio_get_ddc(gpio);
    251
    252	return &hw_ddc->base.base;
    253}