Commit | Line | Data |
---|---|---|
e0eca63e VH |
1 | /* |
2 | * Universal Flash Storage Host controller driver | |
3 | * | |
4 | * This code is based on drivers/scsi/ufs/ufshcd.h | |
5 | * Copyright (C) 2011-2013 Samsung India Software Operations | |
6 | * | |
7 | * Authors: | |
8 | * Santosh Yaraganavi <santosh.sy@samsung.com> | |
9 | * Vinayak Holikatti <h.vinayak@samsung.com> | |
10 | * | |
11 | * This program is free software; you can redistribute it and/or | |
12 | * modify it under the terms of the GNU General Public License | |
13 | * as published by the Free Software Foundation; either version 2 | |
14 | * of the License, or (at your option) any later version. | |
15 | * See the COPYING file in the top-level directory or visit | |
16 | * <http://www.gnu.org/licenses/gpl-2.0.html> | |
17 | * | |
18 | * This program is distributed in the hope that it will be useful, | |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
21 | * GNU General Public License for more details. | |
22 | * | |
23 | * This program is provided "AS IS" and "WITH ALL FAULTS" and | |
24 | * without warranty of any kind. You are solely responsible for | |
25 | * determining the appropriateness of using and distributing | |
26 | * the program and assume all risks associated with your exercise | |
27 | * of rights with respect to the program, including but not limited | |
28 | * to infringement of third party rights, the risks and costs of | |
29 | * program errors, damage to or loss of data, programs or equipment, | |
30 | * and unavailability or interruption of operations. Under no | |
31 | * circumstances will the contributor of this Program be liable for | |
32 | * any damages of any kind arising from your use or distribution of | |
33 | * this program. | |
34 | */ | |
35 | ||
36 | #ifndef _UFSHCD_H | |
37 | #define _UFSHCD_H | |
38 | ||
39 | #include <linux/module.h> | |
40 | #include <linux/kernel.h> | |
41 | #include <linux/init.h> | |
42 | #include <linux/interrupt.h> | |
43 | #include <linux/io.h> | |
44 | #include <linux/delay.h> | |
45 | #include <linux/slab.h> | |
46 | #include <linux/spinlock.h> | |
47 | #include <linux/workqueue.h> | |
48 | #include <linux/errno.h> | |
49 | #include <linux/types.h> | |
50 | #include <linux/wait.h> | |
51 | #include <linux/bitops.h> | |
52 | #include <linux/pm_runtime.h> | |
53 | #include <linux/clk.h> | |
6ccf44fe | 54 | #include <linux/completion.h> |
e0eca63e VH |
55 | |
56 | #include <asm/irq.h> | |
57 | #include <asm/byteorder.h> | |
58 | #include <scsi/scsi.h> | |
59 | #include <scsi/scsi_cmnd.h> | |
60 | #include <scsi/scsi_host.h> | |
61 | #include <scsi/scsi_tcq.h> | |
62 | #include <scsi/scsi_dbg.h> | |
63 | #include <scsi/scsi_eh.h> | |
64 | ||
65 | #include "ufs.h" | |
66 | #include "ufshci.h" | |
67 | ||
68 | #define UFSHCD "ufshcd" | |
69 | #define UFSHCD_DRIVER_VERSION "0.2" | |
70 | ||
5a0b0cb9 SRT |
71 | enum dev_cmd_type { |
72 | DEV_CMD_TYPE_NOP = 0x0, | |
68078d5c | 73 | DEV_CMD_TYPE_QUERY = 0x1, |
5a0b0cb9 SRT |
74 | }; |
75 | ||
e0eca63e VH |
76 | /** |
77 | * struct uic_command - UIC command structure | |
78 | * @command: UIC command | |
79 | * @argument1: UIC command argument 1 | |
80 | * @argument2: UIC command argument 2 | |
81 | * @argument3: UIC command argument 3 | |
82 | * @cmd_active: Indicate if UIC command is outstanding | |
83 | * @result: UIC command result | |
6ccf44fe | 84 | * @done: UIC command completion |
e0eca63e VH |
85 | */ |
86 | struct uic_command { | |
87 | u32 command; | |
88 | u32 argument1; | |
89 | u32 argument2; | |
90 | u32 argument3; | |
91 | int cmd_active; | |
92 | int result; | |
6ccf44fe | 93 | struct completion done; |
e0eca63e VH |
94 | }; |
95 | ||
96 | /** | |
97 | * struct ufshcd_lrb - local reference block | |
98 | * @utr_descriptor_ptr: UTRD address of the command | |
5a0b0cb9 | 99 | * @ucd_req_ptr: UCD address of the command |
e0eca63e VH |
100 | * @ucd_rsp_ptr: Response UPIU address for this command |
101 | * @ucd_prdt_ptr: PRDT address of the command | |
102 | * @cmd: pointer to SCSI command | |
103 | * @sense_buffer: pointer to sense buffer address of the SCSI command | |
104 | * @sense_bufflen: Length of the sense buffer | |
105 | * @scsi_status: SCSI status of the command | |
106 | * @command_type: SCSI, UFS, Query. | |
107 | * @task_tag: Task tag of the command | |
108 | * @lun: LUN of the command | |
5a0b0cb9 | 109 | * @intr_cmd: Interrupt command (doesn't participate in interrupt aggregation) |
e0eca63e VH |
110 | */ |
111 | struct ufshcd_lrb { | |
112 | struct utp_transfer_req_desc *utr_descriptor_ptr; | |
5a0b0cb9 | 113 | struct utp_upiu_req *ucd_req_ptr; |
e0eca63e VH |
114 | struct utp_upiu_rsp *ucd_rsp_ptr; |
115 | struct ufshcd_sg_entry *ucd_prdt_ptr; | |
116 | ||
117 | struct scsi_cmnd *cmd; | |
118 | u8 *sense_buffer; | |
119 | unsigned int sense_bufflen; | |
120 | int scsi_status; | |
121 | ||
122 | int command_type; | |
123 | int task_tag; | |
124 | unsigned int lun; | |
5a0b0cb9 | 125 | bool intr_cmd; |
e0eca63e VH |
126 | }; |
127 | ||
68078d5c DR |
128 | /** |
129 | * struct ufs_query - holds relevent data structures for query request | |
130 | * @request: request upiu and function | |
131 | * @descriptor: buffer for sending/receiving descriptor | |
132 | * @response: response upiu and response | |
133 | */ | |
134 | struct ufs_query { | |
135 | struct ufs_query_req request; | |
136 | u8 *descriptor; | |
137 | struct ufs_query_res response; | |
138 | }; | |
139 | ||
5a0b0cb9 SRT |
140 | /** |
141 | * struct ufs_dev_cmd - all assosiated fields with device management commands | |
142 | * @type: device management command type - Query, NOP OUT | |
143 | * @lock: lock to allow one command at a time | |
144 | * @complete: internal commands completion | |
145 | * @tag_wq: wait queue until free command slot is available | |
146 | */ | |
147 | struct ufs_dev_cmd { | |
148 | enum dev_cmd_type type; | |
149 | struct mutex lock; | |
150 | struct completion *complete; | |
151 | wait_queue_head_t tag_wq; | |
68078d5c | 152 | struct ufs_query query; |
5a0b0cb9 | 153 | }; |
e0eca63e VH |
154 | |
155 | /** | |
156 | * struct ufs_hba - per adapter private structure | |
157 | * @mmio_base: UFSHCI base register address | |
158 | * @ucdl_base_addr: UFS Command Descriptor base address | |
159 | * @utrdl_base_addr: UTP Transfer Request Descriptor base address | |
160 | * @utmrdl_base_addr: UTP Task Management Descriptor base address | |
161 | * @ucdl_dma_addr: UFS Command Descriptor DMA address | |
162 | * @utrdl_dma_addr: UTRDL DMA address | |
163 | * @utmrdl_dma_addr: UTMRDL DMA address | |
164 | * @host: Scsi_Host instance of the driver | |
165 | * @dev: device handle | |
166 | * @lrb: local reference block | |
5a0b0cb9 | 167 | * @lrb_in_use: lrb in use |
e0eca63e VH |
168 | * @outstanding_tasks: Bits representing outstanding task requests |
169 | * @outstanding_reqs: Bits representing outstanding transfer requests | |
170 | * @capabilities: UFS Controller Capabilities | |
171 | * @nutrs: Transfer Request Queue depth supported by controller | |
172 | * @nutmrs: Task Management Queue depth supported by controller | |
173 | * @ufs_version: UFS Version to which controller complies | |
174 | * @irq: Irq number of the controller | |
175 | * @active_uic_cmd: handle of active UIC command | |
6ccf44fe | 176 | * @uic_cmd_mutex: mutex for uic command |
e0eca63e VH |
177 | * @ufshcd_tm_wait_queue: wait queue for task management |
178 | * @tm_condition: condition variable for task management | |
179 | * @ufshcd_state: UFSHCD states | |
2fbd009b | 180 | * @intr_mask: Interrupt Mask Bits |
66ec6d59 | 181 | * @ee_ctrl_mask: Exception event control mask |
e0eca63e | 182 | * @feh_workq: Work queue for fatal controller error handling |
66ec6d59 | 183 | * @eeh_work: Worker to handle exception events |
e0eca63e | 184 | * @errors: HBA errors |
5a0b0cb9 | 185 | * @dev_cmd: ufs device management command information |
66ec6d59 | 186 | * @auto_bkops_enabled: to track whether bkops is enabled in device |
e0eca63e VH |
187 | */ |
188 | struct ufs_hba { | |
189 | void __iomem *mmio_base; | |
190 | ||
191 | /* Virtual memory reference */ | |
192 | struct utp_transfer_cmd_desc *ucdl_base_addr; | |
193 | struct utp_transfer_req_desc *utrdl_base_addr; | |
194 | struct utp_task_req_desc *utmrdl_base_addr; | |
195 | ||
196 | /* DMA memory reference */ | |
197 | dma_addr_t ucdl_dma_addr; | |
198 | dma_addr_t utrdl_dma_addr; | |
199 | dma_addr_t utmrdl_dma_addr; | |
200 | ||
201 | struct Scsi_Host *host; | |
202 | struct device *dev; | |
203 | ||
204 | struct ufshcd_lrb *lrb; | |
5a0b0cb9 | 205 | unsigned long lrb_in_use; |
e0eca63e VH |
206 | |
207 | unsigned long outstanding_tasks; | |
208 | unsigned long outstanding_reqs; | |
209 | ||
210 | u32 capabilities; | |
211 | int nutrs; | |
212 | int nutmrs; | |
213 | u32 ufs_version; | |
214 | unsigned int irq; | |
215 | ||
6ccf44fe SJ |
216 | struct uic_command *active_uic_cmd; |
217 | struct mutex uic_cmd_mutex; | |
218 | ||
e0eca63e VH |
219 | wait_queue_head_t ufshcd_tm_wait_queue; |
220 | unsigned long tm_condition; | |
221 | ||
222 | u32 ufshcd_state; | |
2fbd009b | 223 | u32 intr_mask; |
66ec6d59 | 224 | u16 ee_ctrl_mask; |
e0eca63e VH |
225 | |
226 | /* Work Queues */ | |
e0eca63e | 227 | struct work_struct feh_workq; |
66ec6d59 | 228 | struct work_struct eeh_work; |
e0eca63e VH |
229 | |
230 | /* HBA Errors */ | |
231 | u32 errors; | |
5a0b0cb9 SRT |
232 | |
233 | /* Device management request data */ | |
234 | struct ufs_dev_cmd dev_cmd; | |
66ec6d59 SRT |
235 | |
236 | bool auto_bkops_enabled; | |
e0eca63e VH |
237 | }; |
238 | ||
b873a275 SJ |
239 | #define ufshcd_writel(hba, val, reg) \ |
240 | writel((val), (hba)->mmio_base + (reg)) | |
241 | #define ufshcd_readl(hba, reg) \ | |
242 | readl((hba)->mmio_base + (reg)) | |
243 | ||
e0eca63e VH |
244 | int ufshcd_init(struct device *, struct ufs_hba ** , void __iomem * , |
245 | unsigned int); | |
246 | void ufshcd_remove(struct ufs_hba *); | |
247 | ||
248 | /** | |
249 | * ufshcd_hba_stop - Send controller to reset state | |
250 | * @hba: per adapter instance | |
251 | */ | |
252 | static inline void ufshcd_hba_stop(struct ufs_hba *hba) | |
253 | { | |
b873a275 | 254 | ufshcd_writel(hba, CONTROLLER_DISABLE, REG_CONTROLLER_ENABLE); |
e0eca63e VH |
255 | } |
256 | ||
68078d5c DR |
257 | static inline void check_upiu_size(void) |
258 | { | |
259 | BUILD_BUG_ON(ALIGNED_UPIU_SIZE < | |
260 | GENERAL_UPIU_REQUEST_SIZE + QUERY_DESC_MAX_SIZE); | |
261 | } | |
262 | ||
66ec6d59 SRT |
263 | extern int ufshcd_runtime_suspend(struct ufs_hba *hba); |
264 | extern int ufshcd_runtime_resume(struct ufs_hba *hba); | |
265 | extern int ufshcd_runtime_idle(struct ufs_hba *hba); | |
12b4fdb4 SJ |
266 | extern int ufshcd_dme_set_attr(struct ufs_hba *hba, u32 attr_sel, |
267 | u8 attr_set, u32 mib_val, u8 peer); | |
268 | extern int ufshcd_dme_get_attr(struct ufs_hba *hba, u32 attr_sel, | |
269 | u32 *mib_val, u8 peer); | |
270 | ||
271 | /* UIC command interfaces for DME primitives */ | |
272 | #define DME_LOCAL 0 | |
273 | #define DME_PEER 1 | |
274 | #define ATTR_SET_NOR 0 /* NORMAL */ | |
275 | #define ATTR_SET_ST 1 /* STATIC */ | |
276 | ||
277 | static inline int ufshcd_dme_set(struct ufs_hba *hba, u32 attr_sel, | |
278 | u32 mib_val) | |
279 | { | |
280 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR, | |
281 | mib_val, DME_LOCAL); | |
282 | } | |
283 | ||
284 | static inline int ufshcd_dme_st_set(struct ufs_hba *hba, u32 attr_sel, | |
285 | u32 mib_val) | |
286 | { | |
287 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_ST, | |
288 | mib_val, DME_LOCAL); | |
289 | } | |
290 | ||
291 | static inline int ufshcd_dme_peer_set(struct ufs_hba *hba, u32 attr_sel, | |
292 | u32 mib_val) | |
293 | { | |
294 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_NOR, | |
295 | mib_val, DME_PEER); | |
296 | } | |
297 | ||
298 | static inline int ufshcd_dme_peer_st_set(struct ufs_hba *hba, u32 attr_sel, | |
299 | u32 mib_val) | |
300 | { | |
301 | return ufshcd_dme_set_attr(hba, attr_sel, ATTR_SET_ST, | |
302 | mib_val, DME_PEER); | |
303 | } | |
304 | ||
305 | static inline int ufshcd_dme_get(struct ufs_hba *hba, | |
306 | u32 attr_sel, u32 *mib_val) | |
307 | { | |
308 | return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_LOCAL); | |
309 | } | |
310 | ||
311 | static inline int ufshcd_dme_peer_get(struct ufs_hba *hba, | |
312 | u32 attr_sel, u32 *mib_val) | |
313 | { | |
314 | return ufshcd_dme_get_attr(hba, attr_sel, mib_val, DME_PEER); | |
315 | } | |
316 | ||
e0eca63e | 317 | #endif /* End of Header */ |