diff options
author | Joao Pinto <Joao.Pinto@synopsys.com> | 2016-05-11 07:21:30 -0400 |
---|---|---|
committer | Martin K. Petersen <martin.petersen@oracle.com> | 2016-07-12 23:16:31 -0400 |
commit | 4b9ffb5a353bdee49f1f477ffe2b95ab3f9cbc0c (patch) | |
tree | 0560ae666ca38ed447984c9a7a3d0396ef312a8a | |
parent | 79fcc03349b5766dbd15b169c762b442296fbf6b (diff) |
ufs: add support for DesignWare Controller
This patch has the goal to add support for DesignWare UFS Controller
specific operations.
Signed-off-by: Joao Pinto <jpinto@synopsys.com>
Reviewed-by: Hannes Reinicke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r-- | MAINTAINERS | 6 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd-dwc.c | 150 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd-dwc.h | 26 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshcd.h | 7 | ||||
-rw-r--r-- | drivers/scsi/ufs/ufshci-dwc.h | 36 |
5 files changed, 225 insertions, 0 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 1209323b7e43..368121753b85 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -11770,6 +11770,12 @@ S: Supported | |||
11770 | F: Documentation/scsi/ufs.txt | 11770 | F: Documentation/scsi/ufs.txt |
11771 | F: drivers/scsi/ufs/ | 11771 | F: drivers/scsi/ufs/ |
11772 | 11772 | ||
11773 | UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER DWC HOOKS | ||
11774 | M: Joao Pinto <Joao.Pinto@synopsys.com> | ||
11775 | L: linux-scsi@vger.kernel.org | ||
11776 | S: Supported | ||
11777 | F: drivers/scsi/ufs/*dwc* | ||
11778 | |||
11773 | UNSORTED BLOCK IMAGES (UBI) | 11779 | UNSORTED BLOCK IMAGES (UBI) |
11774 | M: Artem Bityutskiy <dedekind1@gmail.com> | 11780 | M: Artem Bityutskiy <dedekind1@gmail.com> |
11775 | M: Richard Weinberger <richard@nod.at> | 11781 | M: Richard Weinberger <richard@nod.at> |
diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c new file mode 100644 index 000000000000..9b3ca7f15d35 --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-dwc.c | |||
@@ -0,0 +1,150 @@ | |||
1 | /* | ||
2 | * UFS Host driver for Synopsys Designware Core | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) | ||
5 | * | ||
6 | * Authors: Joao Pinto <jpinto@synopsys.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #include "ufshcd.h" | ||
14 | #include "unipro.h" | ||
15 | |||
16 | #include "ufshcd-dwc.h" | ||
17 | #include "ufshci-dwc.h" | ||
18 | |||
19 | int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, | ||
20 | const struct ufshcd_dme_attr_val *v, int n) | ||
21 | { | ||
22 | int ret = 0; | ||
23 | int attr_node = 0; | ||
24 | |||
25 | for (attr_node = 0; attr_node < n; attr_node++) { | ||
26 | ret = ufshcd_dme_set_attr(hba, v[attr_node].attr_sel, | ||
27 | ATTR_SET_NOR, v[attr_node].mib_val, v[attr_node].peer); | ||
28 | |||
29 | if (ret) | ||
30 | return ret; | ||
31 | } | ||
32 | |||
33 | return 0; | ||
34 | } | ||
35 | EXPORT_SYMBOL(ufshcd_dwc_dme_set_attrs); | ||
36 | |||
37 | /** | ||
38 | * ufshcd_dwc_program_clk_div() | ||
39 | * This function programs the clk divider value. This value is needed to | ||
40 | * provide 1 microsecond tick to unipro layer. | ||
41 | * @hba: Private Structure pointer | ||
42 | * @divider_val: clock divider value to be programmed | ||
43 | * | ||
44 | */ | ||
45 | static void ufshcd_dwc_program_clk_div(struct ufs_hba *hba, u32 divider_val) | ||
46 | { | ||
47 | ufshcd_writel(hba, divider_val, DWC_UFS_REG_HCLKDIV); | ||
48 | } | ||
49 | |||
50 | /** | ||
51 | * ufshcd_dwc_link_is_up() | ||
52 | * Check if link is up | ||
53 | * @hba: private structure poitner | ||
54 | * | ||
55 | * Returns 0 on success, non-zero value on failure | ||
56 | */ | ||
57 | static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) | ||
58 | { | ||
59 | int dme_result = 0; | ||
60 | |||
61 | ufshcd_dme_get(hba, UIC_ARG_MIB(VS_POWERSTATE), &dme_result); | ||
62 | |||
63 | if (dme_result == UFSHCD_LINK_IS_UP) { | ||
64 | ufshcd_set_link_active(hba); | ||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | return 1; | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * ufshcd_dwc_connection_setup() | ||
73 | * This function configures both the local side (host) and the peer side | ||
74 | * (device) unipro attributes to establish the connection to application/ | ||
75 | * cport. | ||
76 | * This function is not required if the hardware is properly configured to | ||
77 | * have this connection setup on reset. But invoking this function does no | ||
78 | * harm and should be fine even working with any ufs device. | ||
79 | * | ||
80 | * @hba: pointer to drivers private data | ||
81 | * | ||
82 | * Returns 0 on success non-zero value on failure | ||
83 | */ | ||
84 | static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) | ||
85 | { | ||
86 | const struct ufshcd_dme_attr_val setup_attrs[] = { | ||
87 | { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL }, | ||
88 | { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL }, | ||
89 | { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL }, | ||
90 | { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_LOCAL }, | ||
91 | { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_LOCAL }, | ||
92 | { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_LOCAL }, | ||
93 | { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_LOCAL }, | ||
94 | { UIC_ARG_MIB(T_CPORTMODE), 1, DME_LOCAL }, | ||
95 | { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_LOCAL }, | ||
96 | { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_PEER }, | ||
97 | { UIC_ARG_MIB(N_DEVICEID), 1, DME_PEER }, | ||
98 | { UIC_ARG_MIB(N_DEVICEID_VALID), 1, DME_PEER }, | ||
99 | { UIC_ARG_MIB(T_PEERDEVICEID), 1, DME_PEER }, | ||
100 | { UIC_ARG_MIB(T_PEERCPORTID), 0, DME_PEER }, | ||
101 | { UIC_ARG_MIB(T_TRAFFICCLASS), 0, DME_PEER }, | ||
102 | { UIC_ARG_MIB(T_CPORTFLAGS), 0x6, DME_PEER }, | ||
103 | { UIC_ARG_MIB(T_CPORTMODE), 1, DME_PEER }, | ||
104 | { UIC_ARG_MIB(T_CONNECTIONSTATE), 1, DME_PEER } | ||
105 | }; | ||
106 | |||
107 | return ufshcd_dwc_dme_set_attrs(hba, setup_attrs, ARRAY_SIZE(setup_attrs)); | ||
108 | } | ||
109 | |||
110 | /** | ||
111 | * ufshcd_dwc_link_startup_notify() | ||
112 | * UFS Host DWC specific link startup sequence | ||
113 | * @hba: private structure poitner | ||
114 | * @status: Callback notify status | ||
115 | * | ||
116 | * Returns 0 on success, non-zero value on failure | ||
117 | */ | ||
118 | int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, | ||
119 | enum ufs_notify_change_status status) | ||
120 | { | ||
121 | int err = 0; | ||
122 | |||
123 | if (status == PRE_CHANGE) { | ||
124 | ufshcd_dwc_program_clk_div(hba, DWC_UFS_REG_HCLKDIV_DIV_125); | ||
125 | |||
126 | if (hba->vops->phy_initialization) { | ||
127 | err = hba->vops->phy_initialization(hba); | ||
128 | if (err) { | ||
129 | dev_err(hba->dev, "Phy setup failed (%d)\n", | ||
130 | err); | ||
131 | goto out; | ||
132 | } | ||
133 | } | ||
134 | } else { /* POST_CHANGE */ | ||
135 | err = ufshcd_dwc_link_is_up(hba); | ||
136 | if (err) { | ||
137 | dev_err(hba->dev, "Link is not up\n"); | ||
138 | goto out; | ||
139 | } | ||
140 | |||
141 | err = ufshcd_dwc_connection_setup(hba); | ||
142 | if (err) | ||
143 | dev_err(hba->dev, "Connection setup failed (%d)\n", | ||
144 | err); | ||
145 | } | ||
146 | |||
147 | out: | ||
148 | return err; | ||
149 | } | ||
150 | EXPORT_SYMBOL(ufshcd_dwc_link_startup_notify); | ||
diff --git a/drivers/scsi/ufs/ufshcd-dwc.h b/drivers/scsi/ufs/ufshcd-dwc.h new file mode 100644 index 000000000000..c8be295e0ebe --- /dev/null +++ b/drivers/scsi/ufs/ufshcd-dwc.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /* | ||
2 | * UFS Host driver for Synopsys Designware Core | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) | ||
5 | * | ||
6 | * Authors: Joao Pinto <jpinto@synopsys.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _UFSHCD_DWC_H | ||
14 | #define _UFSHCD_DWC_H | ||
15 | |||
16 | struct ufshcd_dme_attr_val { | ||
17 | u32 attr_sel; | ||
18 | u32 mib_val; | ||
19 | u8 peer; | ||
20 | }; | ||
21 | |||
22 | int ufshcd_dwc_link_startup_notify(struct ufs_hba *hba, | ||
23 | enum ufs_notify_change_status status); | ||
24 | int ufshcd_dwc_dme_set_attrs(struct ufs_hba *hba, | ||
25 | const struct ufshcd_dme_attr_val *v, int n); | ||
26 | #endif /* End of Header */ | ||
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index 4bb65669f052..430bef111293 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h | |||
@@ -264,6 +264,7 @@ struct ufs_pwr_mode_info { | |||
264 | * @suspend: called during host controller PM callback | 264 | * @suspend: called during host controller PM callback |
265 | * @resume: called during host controller PM callback | 265 | * @resume: called during host controller PM callback |
266 | * @dbg_register_dump: used to dump controller debug information | 266 | * @dbg_register_dump: used to dump controller debug information |
267 | * @phy_initialization: used to initialize phys | ||
267 | */ | 268 | */ |
268 | struct ufs_hba_variant_ops { | 269 | struct ufs_hba_variant_ops { |
269 | const char *name; | 270 | const char *name; |
@@ -285,6 +286,7 @@ struct ufs_hba_variant_ops { | |||
285 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); | 286 | int (*suspend)(struct ufs_hba *, enum ufs_pm_op); |
286 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); | 287 | int (*resume)(struct ufs_hba *, enum ufs_pm_op); |
287 | void (*dbg_register_dump)(struct ufs_hba *hba); | 288 | void (*dbg_register_dump)(struct ufs_hba *hba); |
289 | int (*phy_initialization)(struct ufs_hba *); | ||
288 | }; | 290 | }; |
289 | 291 | ||
290 | /* clock gating state */ | 292 | /* clock gating state */ |
@@ -567,11 +569,16 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba) | |||
567 | 569 | ||
568 | static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba) | 570 | static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba) |
569 | { | 571 | { |
572 | /* DWC UFS Core has the Interrupt aggregation feature but is not detectable*/ | ||
573 | #ifndef CONFIG_SCSI_UFS_DWC | ||
570 | if ((hba->caps & UFSHCD_CAP_INTR_AGGR) && | 574 | if ((hba->caps & UFSHCD_CAP_INTR_AGGR) && |
571 | !(hba->quirks & UFSHCD_QUIRK_BROKEN_INTR_AGGR)) | 575 | !(hba->quirks & UFSHCD_QUIRK_BROKEN_INTR_AGGR)) |
572 | return true; | 576 | return true; |
573 | else | 577 | else |
574 | return false; | 578 | return false; |
579 | #else | ||
580 | return true; | ||
581 | #endif | ||
575 | } | 582 | } |
576 | 583 | ||
577 | #define ufshcd_writel(hba, val, reg) \ | 584 | #define ufshcd_writel(hba, val, reg) \ |
diff --git a/drivers/scsi/ufs/ufshci-dwc.h b/drivers/scsi/ufs/ufshci-dwc.h new file mode 100644 index 000000000000..ca341fece310 --- /dev/null +++ b/drivers/scsi/ufs/ufshci-dwc.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* | ||
2 | * UFS Host driver for Synopsys Designware Core | ||
3 | * | ||
4 | * Copyright (C) 2015-2016 Synopsys, Inc. (www.synopsys.com) | ||
5 | * | ||
6 | * Authors: Joao Pinto <jpinto@synopsys.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | */ | ||
12 | |||
13 | #ifndef _UFSHCI_DWC_H | ||
14 | #define _UFSHCI_DWC_H | ||
15 | |||
16 | /* DWC HC UFSHCI specific Registers */ | ||
17 | enum dwc_specific_registers { | ||
18 | DWC_UFS_REG_HCLKDIV = 0xFC, | ||
19 | }; | ||
20 | |||
21 | /* Clock Divider Values: Hex equivalent of frequency in MHz */ | ||
22 | enum clk_div_values { | ||
23 | DWC_UFS_REG_HCLKDIV_DIV_62_5 = 0x3e, | ||
24 | DWC_UFS_REG_HCLKDIV_DIV_125 = 0x7d, | ||
25 | DWC_UFS_REG_HCLKDIV_DIV_200 = 0xc8, | ||
26 | }; | ||
27 | |||
28 | /* Selector Index */ | ||
29 | enum selector_index { | ||
30 | SELIND_LN0_TX = 0x00, | ||
31 | SELIND_LN1_TX = 0x01, | ||
32 | SELIND_LN0_RX = 0x04, | ||
33 | SELIND_LN1_RX = 0x05, | ||
34 | }; | ||
35 | |||
36 | #endif /* End of Header */ | ||