blob: 3d33d1b4447ed8a8eab57853b31b18b7b94db282 [file] [log] [blame]
Subhash Jadavanicce6fbc2016-08-11 11:35:26 -07001/*
2 * Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include "ufshcd.h"
15#include "ufs_quirks.h"
16
Subhash Jadavanicce6fbc2016-08-11 11:35:26 -070017static struct ufs_card_fix ufs_fixups[] = {
18 /* UFS cards deviations table */
19 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
20 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
21 UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS),
22 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
23 UFS_DEVICE_NO_FASTAUTO),
Kyle Yan65be4a52016-10-31 15:05:00 -070024 UFS_FIX(UFS_VENDOR_SAMSUNG, UFS_ANY_MODEL,
25 UFS_DEVICE_QUIRK_HOST_PA_TACTIVATE),
Subhash Jadavanicce6fbc2016-08-11 11:35:26 -070026 UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9C8KBADG",
27 UFS_DEVICE_QUIRK_PA_TACTIVATE),
28 UFS_FIX(UFS_VENDOR_TOSHIBA, "THGLF2G9D8KBADG",
29 UFS_DEVICE_QUIRK_PA_TACTIVATE),
Kyle Yan65be4a52016-10-31 15:05:00 -070030 UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL,
Subhash Jadavanicce6fbc2016-08-11 11:35:26 -070031 UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME),
Kyle Yan65be4a52016-10-31 15:05:00 -070032 UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_NO_VCCQ),
Subhash Jadavanicce6fbc2016-08-11 11:35:26 -070033
34 END_FIX
35};
36
37static int ufs_get_device_info(struct ufs_hba *hba,
38 struct ufs_card_info *card_data)
39{
40 int err;
41 u8 model_index;
42 u8 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE + 1];
43 u8 desc_buf[QUERY_DESC_DEVICE_MAX_SIZE];
44
45 err = ufshcd_read_device_desc(hba, desc_buf,
46 QUERY_DESC_DEVICE_MAX_SIZE);
47 if (err)
48 goto out;
49
50 /*
51 * getting vendor (manufacturerID) and Bank Index in big endian
52 * format
53 */
54 card_data->wmanufacturerid = desc_buf[DEVICE_DESC_PARAM_MANF_ID] << 8 |
55 desc_buf[DEVICE_DESC_PARAM_MANF_ID + 1];
56
57 model_index = desc_buf[DEVICE_DESC_PARAM_PRDCT_NAME];
58
59 memset(str_desc_buf, 0, QUERY_DESC_STRING_MAX_SIZE);
60 err = ufshcd_read_string_desc(hba, model_index, str_desc_buf,
61 QUERY_DESC_STRING_MAX_SIZE, ASCII_STD);
62 if (err)
63 goto out;
64
65 str_desc_buf[QUERY_DESC_STRING_MAX_SIZE] = '\0';
66 strlcpy(card_data->model, (str_desc_buf + QUERY_DESC_HDR_SIZE),
67 min_t(u8, str_desc_buf[QUERY_DESC_LENGTH_OFFSET],
68 MAX_MODEL_LEN));
69 /* Null terminate the model string */
70 card_data->model[MAX_MODEL_LEN] = '\0';
71
72out:
73 return err;
74}
75
76void ufs_advertise_fixup_device(struct ufs_hba *hba)
77{
78 int err;
79 struct ufs_card_fix *f;
80 struct ufs_card_info card_data;
81
82 card_data.wmanufacturerid = 0;
83 card_data.model = kmalloc(MAX_MODEL_LEN + 1, GFP_KERNEL);
84 if (!card_data.model)
85 goto out;
86
87 /* get device data*/
88 err = ufs_get_device_info(hba, &card_data);
89 if (err) {
90 dev_err(hba->dev, "%s: Failed getting device info\n", __func__);
91 goto out;
92 }
93
94 for (f = ufs_fixups; f->quirk; f++) {
95 /* if same wmanufacturerid */
96 if (((f->card.wmanufacturerid == card_data.wmanufacturerid) ||
97 (f->card.wmanufacturerid == UFS_ANY_VENDOR)) &&
98 /* and same model */
99 (STR_PRFX_EQUAL(f->card.model, card_data.model) ||
100 !strcmp(f->card.model, UFS_ANY_MODEL)))
101 /* update quirks */
102 hba->dev_quirks |= f->quirk;
103 }
104out:
105 kfree(card_data.model);
106}