blob: bc564f2789917e2cb6149c378a8deca81567652a [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
Sundarajan Srinivasanf7517cf2013-09-30 15:44:43 -0700216static uint32_t dme_parse_serial_no(struct ufs_string_desc *desc)
217{
218 uint32_t serial_no=0;
219 uint16_t *ptr;
220 int index=0,len=0;
221
222 if(desc->desc_len <= 0)
223 return -UFS_FAILURE;
224
225 ptr = desc->serial_num;
226 len = (desc->desc_len-2)/2;
227
228 for(index=0; index<len; index++)
229 {
230 serial_no += *ptr;
231 ptr++;
232 }
233
234 return serial_no;
235}
236
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700237int dme_read_device_desc(struct ufs_dev *dev)
238{
239 STACKBUF_DMA_ALIGN(dev_desc, sizeof(struct ufs_dev_desc));
240 STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_string_desc));
241 struct ufs_dev_desc *device_desc = dev_desc;
242 struct ufs_string_desc *str_desc = desc;
243 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
244 UFS_DESC_IDN_DEVICE,
245 0,
246 0,
247 (addr_t) dev_desc,
248 sizeof(struct ufs_dev_desc)};
249
250 if (dme_send_query_upiu(dev, &query))
251 return -UFS_FAILURE;
252
253 /* Flush buffer. */
254 arch_invalidate_cache_range((addr_t) device_desc, sizeof(struct ufs_dev_desc));
255
256 /* Store all relevant data */
257 dev->num_lus = device_desc->num_lu;
258
259 /* Get serial number for the device based on the string index. */
260 if (dme_read_string_desc(dev, device_desc->serial_num, desc))
261 return -UFS_FAILURE;
262
263 /* Flush buffer. */
264 arch_invalidate_cache_range((addr_t) str_desc, sizeof(struct ufs_string_desc));
265
Sundarajan Srinivasanf7517cf2013-09-30 15:44:43 -0700266 dev->serial_num = dme_parse_serial_no(str_desc);
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700267
268 return UFS_SUCCESS;
269}
270
271int dme_read_unit_desc(struct ufs_dev *dev, uint8_t index, uint64_t *capacity)
272{
273 STACKBUF_DMA_ALIGN(unit_desc, sizeof(struct ufs_unit_desc));
274 struct ufs_unit_desc *desc = unit_desc;
275 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
276 UFS_DESC_IDN_UNIT,
277 index,
278 0,
279 (addr_t) unit_desc,
280 sizeof(struct ufs_unit_desc)};
281
282 if (dme_send_query_upiu(dev, &query))
283 return -UFS_FAILURE;
284
285 /* Flush buffer. */
286 arch_invalidate_cache_range((addr_t) desc, sizeof(struct ufs_unit_desc));
287
288 *capacity = BE64(desc->logical_blk_cnt) * dev->block_size;
289
290 return UFS_SUCCESS;
291}
292
293int dme_read_config_desc(struct ufs_dev *dev)
294{
295 STACKBUF_DMA_ALIGN(desc, sizeof(struct ufs_config_desc));
296 struct ufs_config_desc *config_desc = desc;
297 struct utp_query_req_upiu_type query = {UPIU_QUERY_OP_READ_DESCRIPTOR,
298 UFS_DESC_IDN_CONFIGURATION,
299 0,
300 0,
301 (addr_t) config_desc,
302 sizeof(struct ufs_config_desc)};
303
304 if (dme_send_query_upiu(dev, &query))
305 return -UFS_FAILURE;
306
307 /* Flush buffer. */
308 arch_invalidate_cache_range((addr_t) config_desc, sizeof(struct ufs_config_desc));
309
310 return UFS_SUCCESS;
311}
312
313int dme_send_nop_query(struct ufs_dev *dev)
314{
315 struct upiu_req_build_type req_upiu;
316 struct upiu_basic_hdr resp_upiu;
317 int ret;
318 unsigned try_again;
319
320 ret = UFS_SUCCESS;
321 try_again = DME_NOP_NUM_RETRIES;
322
323 memset(&req_upiu, 0 , sizeof(struct upiu_req_build_type));
324
325 req_upiu.trans_type = UPIU_TYPE_NOP_OUT;
326 req_upiu.flags = 0;
327 req_upiu.query_mgmt_func = 0;
328 req_upiu.cmd_type = UTRD_DEV_MGMT_FUNC;
329 req_upiu.dd = UTRD_NO_DATA_TRANSFER;
330 req_upiu.resp_ptr = &resp_upiu;
331 req_upiu.resp_len = sizeof(struct upiu_basic_hdr);
332 req_upiu.timeout_msecs = DME_NOP_QUERY_TIMEOUT;
333
334 while (try_again)
335 {
336 try_again--;
337
338 ret = utp_enqueue_upiu(dev, &req_upiu);
339
340 if (ret == -UFS_RETRY)
341 {
342 continue;
343 }
344 else if (ret == -UFS_FAILURE)
345 {
346 dprintf(CRITICAL, "sending nop out failed.\n");
347 goto upiu_send_nop_out_err;
348 }
349
350 /* Check response UPIU */
351 if (resp_upiu.trans_type != UPIU_TYPE_NOP_IN)
352 {
353 dprintf(CRITICAL, "Command failed. command = %x. Invalid response.\n", req_upiu.trans_type);
354 ret = -UFS_FAILURE;
355 goto upiu_send_nop_out_err;
356 }
357 else
358 break;
359 }
360
361upiu_send_nop_out_err:
362 return ret;
363}
364
365int utp_build_query_req_upiu(struct upiu_trans_mgmt_query_hdr *req_upiu,
366 struct upiu_req_build_type *upiu_data)
367{
368 req_upiu->opcode = upiu_data->opcode;
369 req_upiu->idn = upiu_data->idn;
370 req_upiu->index = upiu_data->index;
371 req_upiu->selector = upiu_data->selector;
372 req_upiu->resp_len = BE16(upiu_data->resp_data_len);
373
374 switch (upiu_data->opcode)
375 {
376 case UPIU_QUERY_OP_READ_FLAG:
377 case UPIU_QUERY_OP_READ_DESCRIPTOR:
378 req_upiu->basic_hdr.query_task_mgmt_func = UPIU_QUERY_FUNC_STD_READ_REQ;
379 break;
380 case UPIU_QUERY_OP_TOGGLE_FLAG:
381 case UPIU_QUERY_OP_CLEAR_FLAG:
382 case UPIU_QUERY_OP_SET_FLAG:
383 req_upiu->basic_hdr.query_task_mgmt_func = UPIU_QUERY_FUNC_STD_WRITE_REQ;
384 break;
385 default: dprintf(CRITICAL, "UPIU query opcode not supported.\n");
386 return -UFS_FAILURE;
387 }
388
389 return UFS_SUCCESS;
390}