blob: 8b22384ebed8f007a6fea71fed849becf4df3e57 [file] [log] [blame]
Sridhar Parasuram88bd9dd2014-09-23 15:15:05 -07001/* Copyright (c) 2013-2014, The Linux Foundation. All rights reserved.
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -07002 *
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>
Sridhar Parasuram9374faa2014-10-23 19:56:12 -070040#include <ucs.h>
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070041
42int dme_send_linkstartup_req(struct ufs_dev *dev)
43{
44 struct uic_cmd cmd;
45
46 cmd.uiccmd = UICCMDR_DME_LINKSTARTUP;
47 cmd.num_args = UICCMD_NO_ARGS;
48 cmd.timeout_msecs = DME_LINK_START_TIMEOUT;
49
50 if (uic_send_cmd(dev, &cmd) || cmd.gen_err_code == UICCMD_FAILURE)
51 goto dme_send_linkstartup_req_err;
52
53 return UFS_SUCCESS;
54
55dme_send_linkstartup_req_err:
56 dprintf(CRITICAL, "DME_LINKSTARTUP command failed.\n");
57 return -UFS_FAILURE;
58}
59
60int dme_get_req(struct ufs_dev *dev, struct dme_get_req_type *req)
61{
62 struct uic_cmd cmd;
63
64 cmd.uiccmd = UICCMDR_DME_GET;
65 cmd.num_args = UICCMD_ONE_ARGS;
66 cmd.uiccmdarg1 = req->attribute << 16 | req->index;
67 cmd.timeout_msecs = INFINITE_TIME;
68
69 if (uic_send_cmd(dev, &cmd) || cmd.gen_err_code == UICCMD_FAILURE)
70 goto dme_get_req_err;
71
72 /* Return the result. */
73 *(req->mibval) = cmd.uiccmdarg3;
74
75 return UFS_SUCCESS;
76
77dme_get_req_err:
78 dprintf(CRITICAL, "DME_GET command failed.\n");
79 return -UFS_FAILURE;
80}
81
82static int dme_get_query_resp(struct ufs_dev *dev,
83 struct upiu_req_build_type *req_upiu,
84 addr_t buffer,
85 size_t buf_len)
86{
87 struct upiu_trans_mgmt_query_hdr *resp_upiu;
88
89 resp_upiu = (struct upiu_trans_mgmt_query_hdr *) req_upiu->resp_ptr;
90
91 if (resp_upiu->opcode != req_upiu->opcode)
92 return -UFS_FAILURE;
93 if (resp_upiu->basic_hdr.response != UPIU_QUERY_RESP_SUCCESS)
94 return -UFS_FAILURE;
95
96 switch (resp_upiu->opcode)
97 {
98 case UPIU_QUERY_OP_READ_FLAG:
99 case UPIU_QUERY_OP_SET_FLAG:
100 if (buf_len < sizeof(uint32_t))
101 {
102 dprintf(CRITICAL, "Insufficient buffer space.\n");
103 return -UFS_FAILURE;
104 }
105
106 *((uint32_t *) buffer) = resp_upiu->flag_value;
107 break;
108 case UPIU_QUERY_OP_TOGGLE_FLAG:
109 case UPIU_QUERY_OP_CLEAR_FLAG:
110 case UPIU_QUERY_OP_READ_DESCRIPTOR:
111 break;
112 default: dprintf(CRITICAL, "UPIU query opcode not supported.\n");
113 return -UFS_FAILURE;
114 }
115
116 return UFS_SUCCESS;
117}
118
119static int dme_send_query_upiu(struct ufs_dev *dev, struct utp_query_req_upiu_type *query)
120{
121 struct upiu_trans_mgmt_query_hdr resp_upiu;
122 struct upiu_req_build_type req_upiu;
123 int ret;
124
125 memset(&req_upiu, 0, sizeof(req_upiu));
126
127 req_upiu.opcode = query->opcode;
128 req_upiu.selector = query->selector;
129 req_upiu.index = query->index;
130 req_upiu.idn = query->idn;
131 req_upiu.trans_type = UPIU_TYPE_QUERY_REQ;
132 req_upiu.dd = UTRD_NO_DATA_TRANSFER;
133 req_upiu.resp_ptr = (struct upiu_basic_hdr *) &resp_upiu;
134 req_upiu.resp_len = sizeof(resp_upiu);
135 req_upiu.resp_data_ptr = query->buf;
136 req_upiu.timeout_msecs = UTP_GENERIC_CMD_TIMEOUT;
137
138 if (query->opcode == UPIU_QUERY_OP_READ_DESCRIPTOR)
139 {
140 req_upiu.resp_data_len = query->buf_len;
141 }
142
143 ret = utp_enqueue_upiu(dev, &req_upiu);
144 if (ret)
145 goto utp_send_query_upiu_err;
146
147 ret = dme_get_query_resp(dev, &req_upiu, query->buf, query->buf_len);
148 if (ret)
149 goto utp_send_query_upiu_err;
150
151utp_send_query_upiu_err:
152 return ret;
153}
154
Sridhar Parasuram88bd9dd2014-09-23 15:15:05 -0700155int dme_set_fpoweronwpen(struct ufs_dev *dev)
156{
157 STACKBUF_DMA_ALIGN(result, sizeof(uint32_t));
158 uint32_t try_again = DME_FPOWERONWPEN_RETRIES;
159 struct utp_query_req_upiu_type read_query = {UPIU_QUERY_OP_READ_FLAG,
160 UFS_IDX_fPowerOnWPEn,
161 0,
162 0,
163 (addr_t) result,
164 sizeof(uint32_t)};
165 struct utp_query_req_upiu_type set_query = {UPIU_QUERY_OP_SET_FLAG,
166 UFS_IDX_fPowerOnWPEn,
167 0,
168 0,
169 (addr_t) result,
170 sizeof(uint32_t)};
171
172
173 if (dme_send_query_upiu(dev, &read_query))
174 return -UFS_FAILURE;
175
176 arch_invalidate_cache_range((addr_t) result, sizeof(uint32_t));
177
178 if (*result == 1)
179 goto utp_set_fpoweronwpen_done;
180
181 do
182 {
183 try_again--;
184 dprintf(CRITICAL, "Power on Write Protect request failed. Retrying again.\n");
185
186 if (dme_send_query_upiu(dev, &set_query))
187 return -UFS_FAILURE;
188 if (dme_send_query_upiu(dev, &read_query))
189 return -UFS_FAILURE;
190
191 if (*result == 1)
192 break;
193 } while (try_again);
194
195utp_set_fpoweronwpen_done:
196 dprintf(INFO,"Power on Write Protect status: %u\n", *result);
197 return UFS_SUCCESS;
198}
199
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700200int dme_set_fdeviceinit(struct ufs_dev *dev)
201{
202 STACKBUF_DMA_ALIGN(result, sizeof(uint32_t));
203 uint32_t try_again = DME_FDEVICEINIT_RETRIES;
204 struct utp_query_req_upiu_type read_query = {UPIU_QUERY_OP_READ_FLAG,
205 UFS_IDX_fDeviceInit,
206 0,
207 0,
208 (addr_t) result,
209 sizeof(uint32_t)};
210 struct utp_query_req_upiu_type set_query = {UPIU_QUERY_OP_SET_FLAG,
211 UFS_IDX_fDeviceInit,
212 0,
213 0,
214 (addr_t) result,
215 sizeof(uint32_t)};
216
217
218 if (dme_send_query_upiu(dev, &read_query))
219 return -UFS_FAILURE;
220
221 arch_invalidate_cache_range((addr_t) result, sizeof(uint32_t));
222
223 if (*result == 1)
224 goto utp_set_fdeviceinit_done;
225
226 do
227 {
228 try_again--;
229
230 if (dme_send_query_upiu(dev, &set_query))
231 return -UFS_FAILURE;
232
233 if (dme_send_query_upiu(dev, &read_query))
234 return -UFS_FAILURE;
235
236 if (*result == 1)
237 break;
238 } while (try_again);
239
240utp_set_fdeviceinit_done:
241 return UFS_SUCCESS;
242}
243
244int dme_read_string_desc(struct ufs_dev *dev, uint8_t index, struct ufs_string_desc *desc)
245{
246 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
247 UFS_DESC_IDN_STRING,
248 index,
249 0,
250 (addr_t) desc,
251 sizeof(struct ufs_string_desc)};
252
253 if (dme_send_query_upiu(dev, &query))
254 return -UFS_FAILURE;
255
256 if (desc->desc_len != 0)
257 return UFS_SUCCESS;
258
259 return -UFS_FAILURE;
260}
261
Sundarajan Srinivasanf7517cf2013-09-30 15:44:43 -0700262static uint32_t dme_parse_serial_no(struct ufs_string_desc *desc)
263{
264 uint32_t serial_no=0;
265 uint16_t *ptr;
266 int index=0,len=0;
267
268 if(desc->desc_len <= 0)
269 return -UFS_FAILURE;
270
271 ptr = desc->serial_num;
272 len = (desc->desc_len-2)/2;
273
274 for(index=0; index<len; index++)
275 {
276 serial_no += *ptr;
277 ptr++;
278 }
279
280 return serial_no;
281}
282
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700283int dme_read_device_desc(struct ufs_dev *dev)
284{
285 STACKBUF_DMA_ALIGN(dev_desc, sizeof(struct ufs_dev_desc));
286 STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_string_desc));
287 struct ufs_dev_desc *device_desc = dev_desc;
288 struct ufs_string_desc *str_desc = desc;
289 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
290 UFS_DESC_IDN_DEVICE,
291 0,
292 0,
293 (addr_t) dev_desc,
294 sizeof(struct ufs_dev_desc)};
295
296 if (dme_send_query_upiu(dev, &query))
297 return -UFS_FAILURE;
298
299 /* Flush buffer. */
300 arch_invalidate_cache_range((addr_t) device_desc, sizeof(struct ufs_dev_desc));
301
302 /* Store all relevant data */
303 dev->num_lus = device_desc->num_lu;
304
305 /* Get serial number for the device based on the string index. */
306 if (dme_read_string_desc(dev, device_desc->serial_num, desc))
307 return -UFS_FAILURE;
308
309 /* Flush buffer. */
310 arch_invalidate_cache_range((addr_t) str_desc, sizeof(struct ufs_string_desc));
311
Sundarajan Srinivasanf7517cf2013-09-30 15:44:43 -0700312 dev->serial_num = dme_parse_serial_no(str_desc);
Sridhar Parasuram9374faa2014-10-23 19:56:12 -0700313
314 return UFS_SUCCESS;
315}
316
317
318int dme_read_geo_desc(struct ufs_dev *dev)
319{
320 struct ufs_geometry_desc *desc;
321 STACKBUF_DMA_ALIGN(geometry_desc, sizeof(struct ufs_geometry_desc));
322 desc = geometry_desc;
323 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
324 UFS_DESC_IDN_GEOMETRY,
325 0,
326 0,
327 (addr_t) geometry_desc,
328 sizeof(struct ufs_geometry_desc)};
329
330 if (dme_send_query_upiu(dev, &query))
331 return -UFS_FAILURE;
332
333 // Flush buffer.
334 arch_invalidate_cache_range((addr_t) desc, sizeof(struct ufs_geometry_desc));
335 dev->rpmb_rw_size = desc->rpmb_read_write_size;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700336 return UFS_SUCCESS;
337}
338
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700339int dme_read_unit_desc(struct ufs_dev *dev, uint8_t index)
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700340{
341 STACKBUF_DMA_ALIGN(unit_desc, sizeof(struct ufs_unit_desc));
342 struct ufs_unit_desc *desc = unit_desc;
343 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
344 UFS_DESC_IDN_UNIT,
345 index,
346 0,
347 (addr_t) unit_desc,
348 sizeof(struct ufs_unit_desc)};
349
350 if (dme_send_query_upiu(dev, &query))
351 return -UFS_FAILURE;
352
353 /* Flush buffer. */
354 arch_invalidate_cache_range((addr_t) desc, sizeof(struct ufs_unit_desc));
355
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800356 dev->lun_cfg[index].logical_blk_cnt = BE64(desc->logical_blk_cnt);
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700357
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800358 dev->lun_cfg[index].erase_blk_size = BE32(desc->erase_blk_size);
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700359
Sridhar Parasuram9374faa2014-10-23 19:56:12 -0700360 // use only the lower 32 bits for rpmb partition size
361 if (index == UFS_WLUN_RPMB)
362 dev->rpmb_num_blocks = BE32(desc->logical_blk_cnt >> 32);
363
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700364 return UFS_SUCCESS;
365}
366
367int dme_read_config_desc(struct ufs_dev *dev)
368{
369 STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_config_desc));
370 struct ufs_config_desc *config_desc = desc;
371 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
372 UFS_DESC_IDN_CONFIGURATION,
373 0,
374 0,
375 (addr_t) config_desc,
376 sizeof(struct ufs_config_desc)};
377
378 if (dme_send_query_upiu(dev, &query))
379 return -UFS_FAILURE;
380
381 /* Flush buffer. */
382 arch_invalidate_cache_range((addr_t) config_desc, sizeof(struct ufs_config_desc));
383
384 return UFS_SUCCESS;
385}
386
387int dme_send_nop_query(struct ufs_dev *dev)
388{
389 struct upiu_req_build_type req_upiu;
390 struct upiu_basic_hdr resp_upiu;
391 int ret;
392 unsigned try_again;
393
394 ret = UFS_SUCCESS;
395 try_again = DME_NOP_NUM_RETRIES;
396
397 memset(&req_upiu, 0 , sizeof(struct upiu_req_build_type));
398
399 req_upiu.trans_type = UPIU_TYPE_NOP_OUT;
400 req_upiu.flags = 0;
401 req_upiu.query_mgmt_func = 0;
402 req_upiu.cmd_type = UTRD_DEV_MGMT_FUNC;
403 req_upiu.dd = UTRD_NO_DATA_TRANSFER;
404 req_upiu.resp_ptr = &resp_upiu;
405 req_upiu.resp_len = sizeof(struct upiu_basic_hdr);
406 req_upiu.timeout_msecs = DME_NOP_QUERY_TIMEOUT;
407
408 while (try_again)
409 {
410 try_again--;
411
412 ret = utp_enqueue_upiu(dev, &req_upiu);
413
414 if (ret == -UFS_RETRY)
415 {
416 continue;
417 }
418 else if (ret == -UFS_FAILURE)
419 {
420 dprintf(CRITICAL, "sending nop out failed.\n");
421 goto upiu_send_nop_out_err;
422 }
423
424 /* Check response UPIU */
425 if (resp_upiu.trans_type != UPIU_TYPE_NOP_IN)
426 {
427 dprintf(CRITICAL, "Command failed. command = %x. Invalid response.\n", req_upiu.trans_type);
428 ret = -UFS_FAILURE;
429 goto upiu_send_nop_out_err;
430 }
431 else
432 break;
433 }
434
435upiu_send_nop_out_err:
436 return ret;
437}
438
439int utp_build_query_req_upiu(struct upiu_trans_mgmt_query_hdr *req_upiu,
440 struct upiu_req_build_type *upiu_data)
441{
442 req_upiu->opcode = upiu_data->opcode;
443 req_upiu->idn = upiu_data->idn;
444 req_upiu->index = upiu_data->index;
445 req_upiu->selector = upiu_data->selector;
446 req_upiu->resp_len = BE16(upiu_data->resp_data_len);
447
448 switch (upiu_data->opcode)
449 {
450 case UPIU_QUERY_OP_READ_FLAG:
451 case UPIU_QUERY_OP_READ_DESCRIPTOR:
452 req_upiu->basic_hdr.query_task_mgmt_func = UPIU_QUERY_FUNC_STD_READ_REQ;
453 break;
454 case UPIU_QUERY_OP_TOGGLE_FLAG:
455 case UPIU_QUERY_OP_CLEAR_FLAG:
456 case UPIU_QUERY_OP_SET_FLAG:
457 req_upiu->basic_hdr.query_task_mgmt_func = UPIU_QUERY_FUNC_STD_WRITE_REQ;
458 break;
459 default: dprintf(CRITICAL, "UPIU query opcode not supported.\n");
460 return -UFS_FAILURE;
461 }
462
463 return UFS_SUCCESS;
464}