/* * Copyright (C) 2012 Samsung Electronics * * Author: Donghwa Lee * * SPDX-License-Identifier: GPL-2.0+ */ #include #include #include #include #include #include #include #include #include #include #include "exynos_dp_lowlevel.h" DECLARE_GLOBAL_DATA_PTR; static struct exynos_dp_platform_data *dp_pd; void __exynos_set_dp_phy(unsigned int onoff) { } void exynos_set_dp_phy(unsigned int onoff) __attribute__((weak, alias("__exynos_set_dp_phy"))); static void exynos_dp_disp_info(struct edp_disp_info *disp_info) { disp_info->h_total = disp_info->h_res + disp_info->h_sync_width + disp_info->h_back_porch + disp_info->h_front_porch; disp_info->v_total = disp_info->v_res + disp_info->v_sync_width + disp_info->v_back_porch + disp_info->v_front_porch; return; } static int exynos_dp_init_dp(void) { int ret; exynos_dp_reset(); /* SW defined function Normal operation */ exynos_dp_enable_sw_func(DP_ENABLE); ret = exynos_dp_init_analog_func(); if (ret != EXYNOS_DP_SUCCESS) return ret; exynos_dp_init_hpd(); exynos_dp_init_aux(); return ret; } static unsigned char exynos_dp_calc_edid_check_sum(unsigned char *edid_data) { int i; unsigned char sum = 0; for (i = 0; i < EDID_BLOCK_LENGTH; i++) sum = sum + edid_data[i]; return sum; } static unsigned int exynos_dp_read_edid(void) { unsigned char edid[EDID_BLOCK_LENGTH * 2]; unsigned int extend_block = 0; unsigned char sum; unsigned char test_vector; int retval; /* * EDID device address is 0x50. * However, if necessary, you must have set upper address * into E-EDID in I2C device, 0x30. */ /* Read Extension Flag, Number of 128-byte EDID extension blocks */ exynos_dp_read_byte_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_EXTENSION_FLAG, &extend_block); if (extend_block > 0) { printf("DP EDID data includes a single extension!\n"); /* Read EDID data */ retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); if (retval != 0) { printf("DP EDID Read failed!\n"); return -1; } sum = exynos_dp_calc_edid_check_sum(edid); if (sum != 0) { printf("DP EDID bad checksum!\n"); return -1; } /* Read additional EDID data */ retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_BLOCK_LENGTH, EDID_BLOCK_LENGTH, &edid[EDID_BLOCK_LENGTH]); if (retval != 0) { printf("DP EDID Read failed!\n"); return -1; } sum = exynos_dp_calc_edid_check_sum(&edid[EDID_BLOCK_LENGTH]); if (sum != 0) { printf("DP EDID bad checksum!\n"); return -1; } exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, &test_vector); if (test_vector & DPCD_TEST_EDID_READ) { exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, edid[EDID_BLOCK_LENGTH + EDID_CHECKSUM]); exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); } } else { debug("DP EDID data does not include any extensions.\n"); /* Read EDID data */ retval = exynos_dp_read_bytes_from_i2c(I2C_EDID_DEVICE_ADDR, EDID_HEADER_PATTERN, EDID_BLOCK_LENGTH, &edid[EDID_HEADER_PATTERN]); if (retval != 0) { printf("DP EDID Read failed!\n"); return -1; } sum = exynos_dp_calc_edid_check_sum(edid); if (sum != 0) { printf("DP EDID bad checksum!\n"); return -1; } exynos_dp_read_byte_from_dpcd(DPCD_TEST_REQUEST, &test_vector); if (test_vector & DPCD_TEST_EDID_READ) { exynos_dp_write_byte_to_dpcd(DPCD_TEST_EDID_CHECKSUM, edid[EDID_CHECKSUM]); exynos_dp_write_byte_to_dpcd(DPCD_TEST_RESPONSE, DPCD_TEST_EDID_CHECKSUM_WRITE); } } debug("DP EDID Read success!\n"); return 0; } static unsigned int exynos_dp_handle_edid(struct edp_device_info *edp_info) { unsigned char buf[12]; unsigned int ret; unsigned char temp; unsigned char retry_cnt; unsigned char dpcd_rev[16]; unsigned char lane_bw[16]; unsigned char lane_cnt[16]; memset(dpcd_rev, 0, 16); memset(lane_bw, 0, 16); memset(lane_cnt, 0, 16); memset(buf, 0, 12); retry_cnt = 5; while (retry_cnt) { /* Read DPCD 0x0000-0x000b */ ret = exynos_dp_read_bytes_from_dpcd(DPCD_DPCD_REV, 12, buf); if (ret != EXYNOS_DP_SUCCESS) { if (retry_cnt == 0) { printf("DP read_byte_from_dpcd() failed\n"); return ret; } retry_cnt--; } else break; } /* */ temp = buf[DPCD_DPCD_REV]; if (temp == DP_DPCD_REV_10 || temp == DP_DPCD_REV_11) edp_info->dpcd_rev = temp; else { printf("DP Wrong DPCD Rev : %x\n", temp); return -ENODEV; } temp = buf[DPCD_MAX_LINK_RATE]; if (temp == DP_LANE_BW_1_62 || temp == DP_LANE_BW_2_70) edp_info->lane_bw = temp; else { printf("DP Wrong MAX LINK RATE : %x\n", temp); return -EINVAL; } /*Refer VESA Display Port Stnadard Ver1.1a Page 120 */ if (edp_info->dpcd_rev == DP_DPCD_REV_11) { temp = buf[DPCD_MAX_LANE_COUNT] & 0x1f; if (buf[DPCD_MAX_LANE_COUNT] & 0x80) edp_info->dpcd_efc = 1; else edp_info->dpcd_efc = 0; } else { temp = buf[DPCD_MAX_LANE_COUNT]; edp_info->dpcd_efc = 0; } if (temp == DP_LANE_CNT_1 || temp == DP_LANE_CNT_2 || temp == DP_LANE_CNT_4) { edp_info->lane_cnt = temp; } else { printf("DP Wrong MAX LANE COUNT : %x\n", temp); return -EINVAL; } ret = exynos_dp_read_edid(); if (ret != EXYNOS_DP_SUCCESS) { printf("DP exynos_dp_read_edid() failed\n"); return -EINVAL; } return ret; } static void exynos_dp_init_training(void) { /* * MACRO_RST must be applied after the PLL_LOCK to avoid * the DP inter pair skew issue for at least 10 us */ exynos_dp_reset_macro(); /* All DP analog module power up */ exynos_dp_set_analog_power_down(POWER_ALL, 0); } static unsigned int exynos_dp_link_start(struct edp_device_info *edp_info) { unsigned char buf[5]; unsigned int ret = 0; debug("DP: %s was called\n", __func__); edp_info->lt_info.lt_status = DP_LT_CR; edp_info->lt_info.ep_loop = 0; edp_info->lt_info.cr_loop[0] = 0; edp_info->lt_info.cr_loop[1] = 0; edp_info->lt_info.cr_loop[2] = 0; edp_info->lt_info.cr_loop[3] = 0; /* Set sink to D0 (Sink Not Ready) mode. */ ret = exynos_dp_write_byte_to_dpcd(DPCD_SINK_POWER_STATE, DPCD_SET_POWER_STATE_D0); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; } /* Set link rate and count as you want to establish*/ exynos_dp_set_link_bandwidth(edp_info->lane_bw); exynos_dp_set_lane_count(edp_info->lane_cnt); /* Setup RX configuration */ buf[0] = edp_info->lane_bw; buf[1] = edp_info->lane_cnt; ret = exynos_dp_write_bytes_to_dpcd(DPCD_LINK_BW_SET, 2, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; } exynos_dp_set_lane_pre_emphasis(PRE_EMPHASIS_LEVEL_0, edp_info->lane_cnt); /* Set training pattern 1 */ exynos_dp_set_training_pattern(TRAINING_PTN1); /* Set RX training pattern */ buf[0] = DPCD_SCRAMBLING_DISABLED | DPCD_TRAINING_PATTERN_1; buf[1] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; buf[2] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; buf[3] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; buf[4] = DPCD_PRE_EMPHASIS_SET_PATTERN_2_LEVEL_0 | DPCD_VOLTAGE_SWING_SET_PATTERN_1_LEVEL_0; ret = exynos_dp_write_bytes_to_dpcd(DPCD_TRAINING_PATTERN_SET, 5, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_dpcd_byte failed\n"); return ret; } return ret; } static unsigned int exynos_dp_training_pattern_dis(void) { unsigned int ret = EXYNOS_DP_SUCCESS; exynos_dp_set_training_pattern(DP_NONE); ret = exynos_dp_write_byte_to_dpcd(DPCD_TRAINING_PATTERN_SET, DPCD_TRAINING_PATTERN_DISABLED); if (ret != EXYNOS_DP_SUCCESS) { printf("DP requst_link_traninig_req failed\n"); return -EAGAIN; } return ret; } static unsigned int exynos_dp_enable_rx_to_enhanced_mode(unsigned char enable) { unsigned char data; unsigned int ret = EXYNOS_DP_SUCCESS; ret = exynos_dp_read_byte_from_dpcd(DPCD_LANE_COUNT_SET, &data); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read_from_dpcd failed\n"); return -EAGAIN; } if (enable) data = DPCD_ENHANCED_FRAME_EN | DPCD_LN_COUNT_SET(data); else data = DPCD_LN_COUNT_SET(data); ret = exynos_dp_write_byte_to_dpcd(DPCD_LANE_COUNT_SET, data); if (ret != EXYNOS_DP_SUCCESS) { printf("DP write_to_dpcd failed\n"); return -EAGAIN; } return ret; } static unsigned int exynos_dp_set_enhanced_mode(unsigned char enhance_mode) { unsigned int ret = EXYNOS_DP_SUCCESS; ret = exynos_dp_enable_rx_to_enhanced_mode(enhance_mode); if (ret != EXYNOS_DP_SUCCESS) { printf("DP rx_enhance_mode failed\n"); return -EAGAIN; } exynos_dp_enable_enhanced_mode(enhance_mode); return ret; } static int exynos_dp_read_dpcd_lane_stat(struct edp_device_info *edp_info, unsigned char *status) { unsigned int ret, i; unsigned char buf[2]; unsigned char lane_stat[DP_LANE_CNT_4] = {0,}; unsigned char shift_val[DP_LANE_CNT_4] = {0,}; shift_val[0] = 0; shift_val[1] = 4; shift_val[2] = 0; shift_val[3] = 4; ret = exynos_dp_read_bytes_from_dpcd(DPCD_LANE0_1_STATUS, 2, buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read lane status failed\n"); return ret; } for (i = 0; i < edp_info->lane_cnt; i++) { lane_stat[i] = (buf[(i / 2)] >> shift_val[i]) & 0x0f; if (lane_stat[0] != lane_stat[i]) { printf("Wrong lane status\n"); return -EINVAL; } } *status = lane_stat[0]; return ret; } static unsigned int exynos_dp_read_dpcd_adj_req(unsigned char lane_num, unsigned char *sw, unsigned char *em) { unsigned int ret = EXYNOS_DP_SUCCESS; unsigned char buf; unsigned int dpcd_addr; unsigned char shift_val[DP_LANE_CNT_4] = {0, 4, 0, 4}; /*lane_num value is used as arry index, so this range 0 ~ 3 */ dpcd_addr = DPCD_ADJUST_REQUEST_LANE0_1 + (lane_num / 2); ret = exynos_dp_read_byte_from_dpcd(dpcd_addr, &buf); if (ret != EXYNOS_DP_SUCCESS) { printf("DP read adjust request failed\n"); return -EAGAIN; } *sw = ((buf >> shift_val[lane_num]) & 0x03); *em = ((buf >> shift_val[lane_num]) & 0x0c) >> 2; return ret; } static int exynos_dp_equalizer_err_link(struct edp_device_info *edp_info) { int ret; ret = exynos_dp_training_pattern_dis(); if (ret != EXYNOS_DP_SUCCESS) { printf("DP training_patter_disable() failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; } ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); if (ret != EXYNOS_DP_SUCCESS) { printf("DP set_enhanced_mode() failed\n"); edp_info->lt_info.lt_status = DP_LT_FAIL; } return ret; } static int exynos_dp_reduce_link_rate(struct edp_device_info *edp_info) { int ret; if (edp_info->lane_bw == DP_LANE_BW_2_70) { edp_info->lane_bw = DP_LANE_BW_1_62; printf("DP Change lane bw to 1.62Gbps\n"); edp_info->lt_info.lt_status = DP_LT_START; ret = EXYNOS_DP_SUCCESS; } else { ret = exynos_dp_training_pattern_dis(); if (ret != EXYNOS_DP_SUCCESS) printf("DP training_patter_disable() failed\n"); ret = exynos_dp_set_enhanced_mode(edp_info->dpcd_efc); if (ret != EXYNOS_DP_SUCCESS) printf("DP set_enhanced_mode() failed\n"); edp_in
/*
 * Functions related to generic timeout handling of requests.
 */
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/blkdev.h>
#include <linux/fault-inject.h>

#include "blk.h"
#include "blk-mq.h"

#ifdef CONFIG_FAIL_IO_TIMEOUT

static DECLARE_FAULT_ATTR(fail_io_timeout);

static int __init setup_fail_io_timeout(char *str)
{
	return setup_fault_attr(&fail_io_timeout, str);
}
__setup("fail_io_timeout=", setup_fail_io_timeout);

int blk_should_fake_timeout(struct request_queue *q)
{
	if (!test_bit(QUEUE_FLAG_FAIL_IO, &q->queue_flags))
		return 0;

	return should_fail(&fail_io_timeout, 1);
}

static int __init fail_io_timeout_debugfs(void)
{
	struct dentry *dir = fault_create_debugfs_attr("fail_io_timeout",
						NULL, &fail_io_timeout);

	return PTR_ERR_OR_ZERO(dir);
}

late_initcall(fail_io_timeout_debugfs);

ssize_t part_timeout_show(struct device *dev, struct device_attribute *attr,
			  char *buf)
{
	struct gendisk *disk = dev_to_disk(dev);
	int set = test_bit(QUEUE_FLAG_FAIL_IO, &disk->