blob: da2f9ecad32cf1c335f6ede096dc7d1cb72a91a6 [file] [log] [blame]
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -07001/* Copyright (c) 2013, The Linux Foundation. All rights reserved.
2 *
3 * Redistribution and use in source and binary forms, with or without
4 * modification, are permitted provided that the following conditions are
5 * met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above
9 * copyright notice, this list of conditions and the following
10 * disclaimer in the documentation and/or other materials provided
11 * with the distribution.
12 * * Neither the name of The Linux Foundation nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#include <debug.h>
30#include <string.h>
31#include <reg.h>
32#include <arch/defines.h>
33#include <sys/types.h>
34#include <stdlib.h>
35#include <endian.h>
36#include <ufs.h>
37#include <dme.h>
38#include <uic.h>
39#include <utp.h>
40
41int dme_send_linkstartup_req(struct ufs_dev *dev)
42{
43 struct uic_cmd cmd;
44
45 cmd.uiccmd = UICCMDR_DME_LINKSTARTUP;
46 cmd.num_args = UICCMD_NO_ARGS;
47 cmd.timeout_msecs = DME_LINK_START_TIMEOUT;
48
49 if (uic_send_cmd(dev, &cmd) || cmd.gen_err_code == UICCMD_FAILURE)
50 goto dme_send_linkstartup_req_err;
51
52 return UFS_SUCCESS;
53
54dme_send_linkstartup_req_err:
55 dprintf(CRITICAL, "DME_LINKSTARTUP command failed.\n");
56 return -UFS_FAILURE;
57}
58
59int dme_get_req(struct ufs_dev *dev, struct dme_get_req_type *req)
60{
61 struct uic_cmd cmd;
62
63 cmd.uiccmd = UICCMDR_DME_GET;
64 cmd.num_args = UICCMD_ONE_ARGS;
65 cmd.uiccmdarg1 = req->attribute << 16 | req->index;
66 cmd.timeout_msecs = INFINITE_TIME;
67
68 if (uic_send_cmd(dev, &cmd) || cmd.gen_err_code == UICCMD_FAILURE)
69 goto dme_get_req_err;
70
71 /* Return the result. */
72 *(req->mibval) = cmd.uiccmdarg3;
73
74 return UFS_SUCCESS;
75
76dme_get_req_err:
77 dprintf(CRITICAL, "DME_GET command failed.\n");
78 return -UFS_FAILURE;
79}
80
81static int dme_get_query_resp(struct ufs_dev *dev,
82 struct upiu_req_build_type *req_upiu,
83 addr_t buffer,
84 size_t buf_len)
85{
86 struct upiu_trans_mgmt_query_hdr *resp_upiu;
87
88 resp_upiu = (struct upiu_trans_mgmt_query_hdr *) req_upiu->resp_ptr;
89
90 if (resp_upiu->opcode != req_upiu->opcode)
91 return -UFS_FAILURE;
92 if (resp_upiu->basic_hdr.response != UPIU_QUERY_RESP_SUCCESS)
93 return -UFS_FAILURE;
94
95 switch (resp_upiu->opcode)
96 {
97 case UPIU_QUERY_OP_READ_FLAG:
98 case UPIU_QUERY_OP_SET_FLAG:
99 if (buf_len < sizeof(uint32_t))
100 {
101 dprintf(CRITICAL, "Insufficient buffer space.\n");
102 return -UFS_FAILURE;
103 }
104
105 *((uint32_t *) buffer) = resp_upiu->flag_value;
106 break;
107 case UPIU_QUERY_OP_TOGGLE_FLAG:
108 case UPIU_QUERY_OP_CLEAR_FLAG:
109 case UPIU_QUERY_OP_READ_DESCRIPTOR:
110 break;
111 default: dprintf(CRITICAL, "UPIU query opcode not supported.\n");
112 return -UFS_FAILURE;
113 }
114
115 return UFS_SUCCESS;
116}
117
118static int dme_send_query_upiu(struct ufs_dev *dev, struct utp_query_req_upiu_type *query)
119{
120 struct upiu_trans_mgmt_query_hdr resp_upiu;
121 struct upiu_req_build_type req_upiu;
122 int ret;
123
124 memset(&req_upiu, 0, sizeof(req_upiu));
125
126 req_upiu.opcode = query->opcode;
127 req_upiu.selector = query->selector;
128 req_upiu.index = query->index;
129 req_upiu.idn = query->idn;
130 req_upiu.trans_type = UPIU_TYPE_QUERY_REQ;
131 req_upiu.dd = UTRD_NO_DATA_TRANSFER;
132 req_upiu.resp_ptr = (struct upiu_basic_hdr *) &resp_upiu;
133 req_upiu.resp_len = sizeof(resp_upiu);
134 req_upiu.resp_data_ptr = query->buf;
135 req_upiu.timeout_msecs = UTP_GENERIC_CMD_TIMEOUT;
136
137 if (query->opcode == UPIU_QUERY_OP_READ_DESCRIPTOR)
138 {
139 req_upiu.resp_data_len = query->buf_len;
140 }
141
142 ret = utp_enqueue_upiu(dev, &req_upiu);
143 if (ret)
144 goto utp_send_query_upiu_err;
145
146 ret = dme_get_query_resp(dev, &req_upiu, query->buf, query->buf_len);
147 if (ret)
148 goto utp_send_query_upiu_err;
149
150utp_send_query_upiu_err:
151 return ret;
152}
153
154int dme_set_fdeviceinit(struct ufs_dev *dev)
155{
156 STACKBUF_DMA_ALIGN(result, sizeof(uint32_t));
157 uint32_t try_again = DME_FDEVICEINIT_RETRIES;
158 struct utp_query_req_upiu_type read_query = {UPIU_QUERY_OP_READ_FLAG,
159 UFS_IDX_fDeviceInit,
160 0,
161 0,
162 (addr_t) result,
163 sizeof(uint32_t)};
164 struct utp_query_req_upiu_type set_query = {UPIU_QUERY_OP_SET_FLAG,
165 UFS_IDX_fDeviceInit,
166 0,
167 0,
168 (addr_t) result,
169 sizeof(uint32_t)};
170
171
172 if (dme_send_query_upiu(dev, &read_query))
173 return -UFS_FAILURE;
174
175 arch_invalidate_cache_range((addr_t) result, sizeof(uint32_t));
176
177 if (*result == 1)
178 goto utp_set_fdeviceinit_done;
179
180 do
181 {
182 try_again--;
183
184 if (dme_send_query_upiu(dev, &set_query))
185 return -UFS_FAILURE;
186
187 if (dme_send_query_upiu(dev, &read_query))
188 return -UFS_FAILURE;
189
190 if (*result == 1)
191 break;
192 } while (try_again);
193
194utp_set_fdeviceinit_done:
195 return UFS_SUCCESS;
196}
197
198int dme_read_string_desc(struct ufs_dev *dev, uint8_t index, struct ufs_string_desc *desc)
199{
200 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
201 UFS_DESC_IDN_STRING,
202 index,
203 0,
204 (addr_t) desc,
205 sizeof(struct ufs_string_desc)};
206
207 if (dme_send_query_upiu(dev, &query))
208 return -UFS_FAILURE;
209
210 if (desc->desc_len != 0)
211 return UFS_SUCCESS;
212
213 return -UFS_FAILURE;
214}
215
216int dme_read_device_desc(struct ufs_dev *dev)
217{
218 STACKBUF_DMA_ALIGN(dev_desc, sizeof(struct ufs_dev_desc));
219 STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_string_desc));
220 struct ufs_dev_desc *device_desc = dev_desc;
221 struct ufs_string_desc *str_desc = desc;
222 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
223 UFS_DESC_IDN_DEVICE,
224 0,
225 0,
226 (addr_t) dev_desc,
227 sizeof(struct ufs_dev_desc)};
228
229 if (dme_send_query_upiu(dev, &query))
230 return -UFS_FAILURE;
231
232 /* Flush buffer. */
233 arch_invalidate_cache_range((addr_t) device_desc, sizeof(struct ufs_dev_desc));
234
235 /* Store all relevant data */
236 dev->num_lus = device_desc->num_lu;
237
238 /* Get serial number for the device based on the string index. */
239 if (dme_read_string_desc(dev, device_desc->serial_num, desc))
240 return -UFS_FAILURE;
241
242 /* Flush buffer. */
243 arch_invalidate_cache_range((addr_t) str_desc, sizeof(struct ufs_string_desc));
244
245 dev->serial_num = 0;
246
247 return UFS_SUCCESS;
248}
249
250int dme_read_unit_desc(struct ufs_dev *dev, uint8_t index, uint64_t *capacity)
251{
252 STACKBUF_DMA_ALIGN(unit_desc, sizeof(struct ufs_unit_desc));
253 struct ufs_unit_desc *desc = unit_desc;
254 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
255 UFS_DESC_IDN_UNIT,
256 index,
257 0,
258 (addr_t) unit_desc,
259 sizeof(struct ufs_unit_desc)};
260
261 if (dme_send_query_upiu(dev, &query))
262 return -UFS_FAILURE;
263
264 /* Flush buffer. */
265 arch_invalidate_cache_range((addr_t) desc, sizeof(struct ufs_unit_desc));
266
267 *capacity = BE64(desc->logical_blk_cnt) * dev->block_size;
268
269 return UFS_SUCCESS;
270}
271
272int dme_read_config_desc(struct ufs_dev *dev)
273{
274 STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_config_desc));
275 struct ufs_config_desc *config_desc = desc;
276 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
277 UFS_DESC_IDN_CONFIGURATION,
278 0,
279 0,
280 (addr_t) config_desc,
281 sizeof(struct ufs_config_desc)};
282
283 if (dme_send_query_upiu(dev, &query))
284 return -UFS_FAILURE;
285
286 /* Flush buffer. */
287 arch_invalidate_cache_range((addr_t) config_desc, sizeof(struct ufs_config_desc));
288
289 return UFS_SUCCESS;
290}
291
292int dme_send_nop_query(struct ufs_dev *dev)
293{
294 struct upiu_req_build_type req_upiu;
295 struct upiu_basic_hdr resp_upiu;
296 int ret;
297 unsigned try_again;
298
299 ret = UFS_SUCCESS;
300 try_again = DME_NOP_NUM_RETRIES;
301
302 memset(&req_upiu, 0 , sizeof(struct upiu_req_build_type));
303
304 req_upiu.trans_type = UPIU_TYPE_NOP_OUT;
305 req_upiu.flags = 0;
306 req_upiu.query_mgmt_func = 0;
307 req_upiu.cmd_type = UTRD_DEV_MGMT_FUNC;
308 req_upiu.dd = UTRD_NO_DATA_TRANSFER;
309 req_upiu.resp_ptr = &resp_upiu;
310 req_upiu.resp_len = sizeof(struct upiu_basic_hdr);
311 req_upiu.timeout_msecs = DME_NOP_QUERY_TIMEOUT;
312
313 while (try_again)
314 {
315 try_again--;
316
317 ret = utp_enqueue_upiu(dev, &req_upiu);
318
319 if (ret == -UFS_RETRY)
320 {
321 continue;
322 }
323 else if (ret == -UFS_FAILURE)
324 {
325 dprintf(CRITICAL, "sending nop out failed.\n");
326 goto upiu_send_nop_out_err;
327 }
328
329 /* Check response UPIU */
330 if (resp_upiu.trans_type != UPIU_TYPE_NOP_IN)
331 {
332 dprintf(CRITICAL, "Command failed. command = %x. Invalid response.\n", req_upiu.trans_type);
333 ret = -UFS_FAILURE;
334 goto upiu_send_nop_out_err;
335 }
336 else
337 break;
338 }
339
340upiu_send_nop_out_err:
341 return ret;
342}
343
344int utp_build_query_req_upiu(struct upiu_trans_mgmt_query_hdr *req_upiu,
345 struct upiu_req_build_type *upiu_data)
346{
347 req_upiu->opcode = upiu_data->opcode;
348 req_upiu->idn = upiu_data->idn;
349 req_upiu->index = upiu_data->index;
350 req_upiu->selector = upiu_data->selector;
351 req_upiu->resp_len = BE16(upiu_data->resp_data_len);
352
353 switch (upiu_data->opcode)
354 {
355 case UPIU_QUERY_OP_READ_FLAG:
356 case UPIU_QUERY_OP_READ_DESCRIPTOR:
357 req_upiu->basic_hdr.query_task_mgmt_func = UPIU_QUERY_FUNC_STD_READ_REQ;
358 break;
359 case UPIU_QUERY_OP_TOGGLE_FLAG:
360 case UPIU_QUERY_OP_CLEAR_FLAG:
361 case UPIU_QUERY_OP_SET_FLAG:
362 req_upiu->basic_hdr.query_task_mgmt_func = UPIU_QUERY_FUNC_STD_WRITE_REQ;
363 break;
364 default: dprintf(CRITICAL, "UPIU query opcode not supported.\n");
365 return -UFS_FAILURE;
366 }
367
368 return UFS_SUCCESS;
369}