drivers:ufs: fix hynix ufs bug with quirk on hi36xx SoC
authorfengbaopeng <fengbaopeng@hisilicon.com>
Mon, 12 Feb 2018 12:53:54 +0000 (20:53 +0800)
committerwei li <liwei213@huawei.com>
Sat, 24 Feb 2018 01:30:41 +0000 (09:30 +0800)
Hynix ufs has deviations on hi36xx platform which will result
in ufs bursts transfer failures at a very low probability.

To fix the problem, the Hynix device must set the register
VS_DebugSaveConfigTime to 0x10, which will set time reference
for SaveConfigTime is 250 ns. The time reference for SaveConfigTime
is 40 ns by default.

Signed-off-by: fengbaopeng <fengbaopeng@hisilicon.com>
drivers/synopsys/ufs/dw_ufs.c
drivers/ufs/ufs.c
include/drivers/ufs.h

index d8ed5b6c70aa358dcf0a849a910cce97f5ca690f..b0ea3e7377ab8eceb8b7e5ee0fcd7c17309d8b4b 100644 (file)
@@ -97,10 +97,21 @@ static int dwufs_phy_set_pwr_mode(ufs_params_t *params)
        int result;
        unsigned int data, tx_lanes, rx_lanes;
        uintptr_t base;
+       unsigned int flags;
 
        assert((params != NULL) && (params->reg_base != 0));
 
        base = params->reg_base;
+       flags = params->flags;
+       if ((flags & UFS_FLAGS_VENDOR_SKHYNIX) != 0U) {
+               NOTICE("ufs: H**** device must set VS_DebugSaveConfigTime 0x10\n");
+               /* VS_DebugSaveConfigTime */
+               result = ufshc_dme_set(0xd0a0, 0x0, 0x10);
+               assert(result == 0);
+               /* sync length */
+               result = ufshc_dme_set(0x1556, 0x0, 0x48);
+               assert(result == 0);
+       }
 
        result = ufshc_dme_get(PA_TACTIVATE_OFFSET, 0, &data);
        assert(result == 0);
index d513d0a55837fda092e407fc4a9dbe5ba20a5697..254866f8c6efe8dcf34460c953ca70cada6d3c06 100644 (file)
@@ -705,11 +705,27 @@ static void ufs_enum(void)
        }
 }
 
+static void ufs_get_device_info(struct ufs_dev_desc *card_data)
+{
+       uint8_t desc_buf[DESC_DEVICE_MAX_SIZE];
+
+       ufs_query(QUERY_READ_DESC, DESC_TYPE_DEVICE, 0, 0,
+                               (uintptr_t)desc_buf, DESC_DEVICE_MAX_SIZE);
+
+       /*
+        * getting vendor (manufacturerID) and Bank Index in big endian
+        * format
+        */
+       card_data->wmanufacturerid = (uint16_t)((desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8) |
+                                    (desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1]));
+}
+
 int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
 {
        int result;
        unsigned int data;
        uic_cmd_t cmd;
+       struct ufs_dev_desc card = {0};
 
        assert((params != NULL) &&
               (params->reg_base != 0) &&
@@ -750,10 +766,17 @@ int ufs_init(const ufs_ops_t *ops, ufs_params_t *params)
                ops->phy_init(&ufs_params);
                result = ufshc_link_startup(ufs_params.reg_base);
                assert(result == 0);
+
+               ufs_enum();
+
+               ufs_get_device_info(&card);
+               if (card.wmanufacturerid == UFS_VENDOR_SKHYNIX) {
+                       ufs_params.flags |= UFS_FLAGS_VENDOR_SKHYNIX;
+               }
+
                ops->phy_set_pwr_mode(&ufs_params);
        }
 
-       ufs_enum();
        (void)result;
        return 0;
 }
index 3a4f1c780f7e837cd26dbc1b3abd5ffb9e0caeb3..88dedc5aeb16b423a47d29c0ef4cd829c05a78fb 100644 (file)
@@ -7,6 +7,8 @@
 #ifndef __UFS_H__
 #define __UFS_H__
 
+#include <utils_def.h>
+
 /* register map of UFSHCI */
 /* Controller Capabilities */
 #define CAP                            0x00
 #define DESC_TYPE_INTERCONNECT         0x04
 #define DESC_TYPE_STRING               0x05
 
+#define DESC_DEVICE_MAX_SIZE           0x1F
+#define DEVICE_DESC_PARAM_MANF_ID      0x18
+
 #define ATTR_CUR_PWR_MODE              0x02    /* bCurrentPowerMode */
 #define ATTR_ACTIVECC                  0x03    /* bActiveICCLevel */
 
 
 #define FLAG_DEVICE_INIT               0x01
 
+#define UFS_VENDOR_SKHYNIX             U(0x1AD)
+
+#define MAX_MODEL_LEN 16
+/**
+ * ufs_dev_desc - ufs device details from the device descriptor
+ * @wmanufacturerid: card details
+ * @model: card model
+ */
+struct ufs_dev_desc {
+       uint16_t wmanufacturerid;
+       int8_t model[MAX_MODEL_LEN + 1];
+};
+
 /* UFS Driver Flags */
 #define UFS_FLAGS_SKIPINIT             (1 << 0)
+#define UFS_FLAGS_VENDOR_SKHYNIX       (U(1) << 2)
 
 typedef struct sense_data {
        uint8_t         resp_code : 7;