From 623b5fe32f6bb5e4994fc9c2e3a1348c136d2a52 Mon Sep 17 00:00:00 2001 From: hgchu Date: Fri, 12 Jan 2018 09:34:19 +0900 Subject: [PATCH] scsi: ufs: amend ufs host for exynos8890 evt1 Change-Id: Ic77815f6364bf42af7b7c51f410fcf6f51e7c980 Signed-off-by: hgchu --- drivers/scsi/ufs/mphy.h | 37 ++++++++++++++++++++ drivers/scsi/ufs/ufshcd.c | 72 +++++++++++++++++++++++++++++++++++---- drivers/scsi/ufs/ufshcd.h | 8 +++-- drivers/scsi/ufs/ufshci.h | 10 ++++++ 4 files changed, 117 insertions(+), 10 deletions(-) create mode 100644 drivers/scsi/ufs/mphy.h diff --git a/drivers/scsi/ufs/mphy.h b/drivers/scsi/ufs/mphy.h new file mode 100644 index 000000000000..093697a1d3ea --- /dev/null +++ b/drivers/scsi/ufs/mphy.h @@ -0,0 +1,37 @@ +/* + * drivers/scsi/ufs/mphy.h + * + * Copyright (C) 2014 Samsung Electronics Co., Ltd. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#ifndef _MPHY_H_ +#define _MPHY_H_ + +#define TX_HIBERN8TIME_CAP 0x0f +#define TX_MIN_ACTIVATE_TIME 0x33 + +#define RX_HS_G1_SYNC_LENGTH_CAP 0x8b +#define RX_HS_G1_PREP_LENGTH_CAP 0x8c +#define RX_HS_G2_SYNC_LENGTH_CAP 0x94 +#define RX_HS_G3_SYNC_LENGTH_CAP 0x95 +#define RX_HS_G2_PREP_LENGTH_CAP 0x96 +#define RX_HS_G3_PREP_LENGTH_CAP 0x97 + #define SYNC_RANGE_FINE (0 << 6) + #define SYNC_RANGE_COARSE (1 << 6) + #define SYNC_LEN(x) ((x) & 0x3f) + #define PREP_LEN(x) ((x) & 0xf) +#define RX_ADV_GRANULARITY_CAP 0x98 + #define RX_ADV_FINE_GRAN_STEP(x) ((((x) & 0x3) << 1) | 0x1) +#define TX_ADV_GRANULARITY_CAP 0x10 + #define TX_ADV_FINE_GRAN_STEP(x) ((((x) & 0x3) << 1) | 0x1) +#define RX_MIN_ACTIVATETIME_CAP 0x8f +#define RX_HIBERN8TIME_CAP 0x92 +#define RX_ADV_HIBERN8TIME_CAP 0x99 +#define RX_ADV_MIN_ACTIVATETIME_CAP 0x9a + +#endif /* _MPHY_H_ */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index d10b52c0cf56..fe59415b5ad1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -85,7 +85,11 @@ #define MASK_QUERY_UPIU_FLAG_LOC 0xFF /* Interrupt aggregation default timeout, unit: 40us */ -#define INT_AGGR_DEF_TO 0x02 +#define INT_AGGR_DEF_TO 0x01 + +/* Link Hibernation delay, msecs */ +#define LINK_H8_DELAY 20 + #define ufshcd_toggle_vreg(_dev, _vreg, _on) \ ({ \ @@ -231,8 +235,6 @@ static void ufshcd_suspend_clkscaling(struct ufs_hba *hba); static void __ufshcd_suspend_clkscaling(struct ufs_hba *hba); static int ufshcd_scale_clks(struct ufs_hba *hba, bool scale_up); static irqreturn_t ufshcd_intr(int irq, void *__hba); -static int ufshcd_config_pwr_mode(struct ufs_hba *hba, - struct ufs_pa_layer_attr *desired_pwr_mode); static int ufshcd_change_power_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *pwr_mode); static inline bool ufshcd_valid_tag(struct ufs_hba *hba, int tag) @@ -3431,6 +3433,37 @@ static inline void ufshcd_add_delay_before_dme_cmd(struct ufs_hba *hba) usleep_range(min_sleep_time_us, min_sleep_time_us + 50); } +static int ufshcd_dme_reset(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_RESET; + uic_cmd.argument1 = 0x1; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_err(hba->dev, + "dme-reset: error code %d\n", ret); + + return ret; +} + +static int ufshcd_dme_enable(struct ufs_hba *hba) +{ + struct uic_command uic_cmd = {0}; + int ret; + + uic_cmd.command = UIC_CMD_DME_ENABLE; + + ret = ufshcd_send_uic_cmd(hba, &uic_cmd); + if (ret) + dev_err(hba->dev, + "dme-enable: error code %d\n", ret); + + return ret; +} + /** * ufshcd_dme_set_attr - UIC command for DME_SET, DME_PEER_SET * @hba: per adapter instance @@ -3910,7 +3943,7 @@ static int ufshcd_change_power_mode(struct ufs_hba *hba, * @hba: per-adapter instance * @desired_pwr_mode: desired power configuration */ -static int ufshcd_config_pwr_mode(struct ufs_hba *hba, +int ufshcd_config_pwr_mode(struct ufs_hba *hba, struct ufs_pa_layer_attr *desired_pwr_mode) { struct ufs_pa_layer_attr final_params = { 0 }; @@ -3928,6 +3961,7 @@ static int ufshcd_config_pwr_mode(struct ufs_hba *hba, return ret; } +EXPORT_SYMBOL_GPL(ufshcd_config_pwr_mode); /** * ufshcd_complete_dev_init() - checks device readiness @@ -4045,7 +4079,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep) } /** - * ufshcd_hba_enable - initialize the controller + * _ufshcd_hba_enable - initialize the controller * @hba: per adapter instance * * The controller resets itself and controller firmware initialization @@ -4054,7 +4088,7 @@ static inline void ufshcd_hba_stop(struct ufs_hba *hba, bool can_sleep) * * Returns 0 on success, non-zero value on failure */ -static int ufshcd_hba_enable(struct ufs_hba *hba) +static int __ufshcd_hba_enable(struct ufs_hba *hba) { int retry; @@ -4145,6 +4179,24 @@ static inline int ufshcd_disable_device_tx_lcc(struct ufs_hba *hba) return ufshcd_disable_tx_lcc(hba, true); } +static int ufshcd_hba_enable(struct ufs_hba *hba) +{ + int ret; + if (hba->vops && hba->vops->host_reset) + hba->vops->host_reset(hba); + if (hba->quirks & UFSHCD_QUIRK_USE_OF_HCE) { + /* enable UIC related interrupts */ + ufshcd_enable_intr(hba, UFSHCD_UIC_MASK); + + ret = ufshcd_dme_reset(hba); + if (!ret) + ret = ufshcd_dme_enable(hba); + } else { + ret = __ufshcd_hba_enable(hba); + } + return ret; +} + /** * ufshcd_link_startup - Initialize unipro link startup * @hba: per adapter instance @@ -4405,6 +4457,7 @@ static int ufshcd_slave_configure(struct scsi_device *sdev) blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); blk_queue_max_segment_size(q, PRDT_DATA_BYTE_COUNT_MAX); + blk_queue_update_dma_alignment(q, PAGE_SIZE - 1); return 0; } @@ -4521,6 +4574,7 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) switch (ocs) { case OCS_SUCCESS: + case OCS_FATAL_ERROR: result = ufshcd_get_req_rsp(lrbp->ucd_rsp_ptr); hba->ufs_stats.last_hibern8_exit_tstamp = ktime_set(0, 0); switch (result) { @@ -4579,7 +4633,6 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) case OCS_MISMATCH_DATA_BUF_SIZE: case OCS_MISMATCH_RESP_UPIU_SIZE: case OCS_PEER_COMM_FAILURE: - case OCS_FATAL_ERROR: default: result |= DID_ERROR << 16; dev_err(hba->dev, @@ -6339,9 +6392,11 @@ static void ufshcd_def_desc_sizes(struct ufs_hba *hba) static int ufshcd_probe_hba(struct ufs_hba *hba) { struct ufs_dev_desc card = {0}; + int re_cnt = 0; int ret; ktime_t start = ktime_get(); +retry: ret = ufshcd_link_startup(hba); if (ret) goto out; @@ -6452,6 +6507,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) hba->is_init_prefetch = true; out: + if (ret) { + goto retry; + } /* * If we failed to initialize the device or the device is not * present, turn off the power/clocks etc. diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 96d579b1257c..08ddfe39ad12 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -325,8 +325,7 @@ struct ufs_hba_variant_ops { struct ufs_pa_layer_attr *); void (*setup_xfer_req)(struct ufs_hba *, int, bool); void (*setup_task_mgmt)(struct ufs_hba *, int, u8); - void (*hibern8_notify)(struct ufs_hba *, enum uic_cmd_dme, - enum ufs_notify_change_status); + void (*hibern8_notify)(struct ufs_hba *, u8, bool); int (*apply_dev_quirks)(struct ufs_hba *); int (*suspend)(struct ufs_hba *, enum ufs_pm_op); int (*resume)(struct ufs_hba *, enum ufs_pm_op); @@ -538,7 +537,7 @@ struct ufs_hba { int pm_op_in_progress; struct ufshcd_lrb *lrb; - unsigned long lrb_in_use; + volatile unsigned long lrb_in_use; unsigned long outstanding_tasks; unsigned long outstanding_reqs; @@ -599,6 +598,7 @@ struct ufs_hba { */ #define UFSHCD_QUIRK_PRDT_BYTE_GRAN UFS_BIT(7) + #define UFSHCD_QUIRK_USE_OF_HCE UFS_BIT(8) unsigned int quirks; /* Deviations from standard UFSHCI spec. */ /* Device deviations from standard UFS device spec. */ @@ -793,6 +793,8 @@ extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, u8 attr_set, u32 mib_val, u8 peer); extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, u32 *mib_val, u8 peer); +extern int ufshcd_config_pwr_mode(struct ufs_hba *hba, + struct ufs_pa_layer_attr *desired_pwr_mode); /* UIC command interfaces for DME primitives */ #define DME_LOCAL 0 diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index d338a851c393..37004df6d79d 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -197,10 +197,20 @@ enum { /* UECN - Host UIC Error Code Network Layer 40h */ #define UIC_NETWORK_LAYER_ERROR UFS_BIT(31) #define UIC_NETWORK_LAYER_ERROR_CODE_MASK 0x7 +#define UIC_NETWORK_UNSUPPORTED_HEADER_TYPE BIT(0) +#define UIC_NETWORK_BAD_DEVICEID_ENC BIT(1) +#define UIC_NETWORK_LHDR_TRAP_PACKET_DROPPING BIT(2) /* UECT - Host UIC Error Code Transport Layer 44h */ #define UIC_TRANSPORT_LAYER_ERROR UFS_BIT(31) #define UIC_TRANSPORT_LAYER_ERROR_CODE_MASK 0x7F +#define UIC_TRANSPORT_UNSUPPORTED_HEADER_TYPE BIT(0) +#define UIC_TRANSPORT_UNKNOWN_CPORTID BIT(1) +#define UIC_TRANSPORT_NO_CONNECTION_RX BIT(2) +#define UIC_TRANSPORT_CONTROLLED_SEGMENT_DROPPING BIT(3) +#define UIC_TRANSPORT_BAD_TC BIT(4) +#define UIC_TRANSPORT_E2E_CREDIT_OVERFOW BIT(5) +#define UIC_TRANSPORT_SAFETY_VALUE_DROPPING BIT(6) /* UECDME - Host UIC Error Code DME 48h */ #define UIC_DME_ERROR UFS_BIT(31) -- 2.20.1