blob: d3b706532d50f7a880b77f80fcf54dcff1d00078 [file] [log] [blame]
Channagoud Kadabiab887302015-02-20 10:55:58 -08001/* 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 <reg.h>
31#include <ufs_hw.h>
32#include <utp.h>
33#include <upiu.h>
34#include <uic.h>
35#include <ucs.h>
36#include <dme.h>
Sridhar Parasuram3c0b0b82014-09-25 18:06:51 -070037#include <qgic.h>
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070038#include <string.h>
39#include <platform/iomap.h>
Sridhar Parasuram3c0b0b82014-09-25 18:06:51 -070040#include <platform/irqs.h>
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070041#include <kernel/mutex.h>
42
43static int ufs_dev_init(struct ufs_dev *dev)
44{
45 /* Init the mutexes. */
46 mutex_init(&(dev->uic_data.uic_mutex));
47 mutex_init(&(dev->utrd_data.bitmap_mutex));
48 mutex_init(&(dev->utmrd_data.bitmap_mutex));
49
50 /* Initialize wait lists. */
51 list_initialize(&(dev->utrd_data.list_head.list_node));
52 list_initialize(&(dev->utmrd_data.list_head.list_node));
53
54 /* Initialize the bitmaps. */
55 dev->utrd_data.bitmap = 0;
56 dev->utmrd_data.bitmap = 0;
57
58 /* Initialize task ids. */
59 dev->utrd_data.task_id = 0;
60 dev->utmrd_data.task_id = 0;
61
62 /* Allocate memory for lists. */
63 dev->utrd_data.list_base_addr = ufs_alloc_trans_req_list();
64 dev->utmrd_data.list_base_addr = ufs_alloc_task_mgmt_req_list();
65
66 if (!dev->utrd_data.list_base_addr || !dev->utmrd_data.list_base_addr)
67 return -UFS_FAILURE;
68
69 return UFS_SUCCESS;
70}
71
72static void ufs_setup_req_lists(struct ufs_dev *dev)
73{
74 uint32_t val;
75
76 writel(dev->utmrd_data.list_base_addr, UFS_UTMRLBA(dev->base));
77 writel(dev->utmrd_data.list_base_addr << 32, UFS_UTMRLBAU(dev->base));
78
79 writel(dev->utrd_data.list_base_addr, UFS_UTRLBA(dev->base));
80 writel(dev->utrd_data.list_base_addr << 32, UFS_UTRLBAU(dev->base));
81
82 writel(1, UFS_UTMRLRSR(dev->base));
83 writel(1, UFS_UTRLRSR(dev->base));
84
85 /* Enable the required irqs. */
Sridhar Parasuram7357e9b2014-10-01 12:19:11 -070086 val = UFS_IE_UEE | UFS_IE_UCCE ;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070087 ufs_irq_enable(dev, val);
Sridhar Parasuram3c0b0b82014-09-25 18:06:51 -070088 // Change UFS_IRQ to level based
89 qgic_change_interrupt_cfg(UFS_IRQ, INTERRUPT_LVL_N_TO_N);
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070090}
91
Channagoud Kadabi5890d9b2015-01-29 13:04:04 -080092void ufs_rpmb_init(struct ufs_dev *dev)
Sridhar Parasuramb66c9c32014-10-27 09:36:01 -070093{
94 int ret = 0;
95
Channagoud Kadabi5890d9b2015-01-29 13:04:04 -080096 /*
97 * Perform request sense on lun to clear
98 * attention pending, other wise all the read/write
99 * operations would fail with check condition error
100 */
101 ucs_do_request_sense(dev, UFS_WLUN_RPMB);
102
Sridhar Parasuramb66c9c32014-10-27 09:36:01 -0700103 // calculate the size of rpmb partition in sectors
104 ret = dme_read_unit_desc(dev, UFS_WLUN_RPMB);
105 if (ret != UFS_SUCCESS)
106 {
107 dprintf(CRITICAL, "UFS dme_read_unit_desc failed for RPMB Partition\n");
108 return;
109 }
110
111 // gets the number of rpmb frames allowed in a single UPIU commands
Sridhar Parasuramc02d1072014-11-06 12:55:42 -0800112 ret = dme_read_geo_desc(dev);
Sridhar Parasuramb66c9c32014-10-27 09:36:01 -0700113 if (ret != UFS_SUCCESS)
114 {
115 dprintf(CRITICAL, "UFS dme_read_geo_desc failed for RPMB Partition\n");
116 return;
117 }
118#ifdef DEBUG_UFS
119 dprintf(INFO, "RPMB: Logical Block Count: 0x%x\n", dev->rpmb_num_blocks);
120 dprintf(INFO, "RPMB: RPMB Read Write Size: 0x%x\n", dev->rpmb_rw_size);
121#endif
122}
123
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700124int ufs_read(struct ufs_dev* dev, uint64_t start_lba, addr_t buffer, uint32_t num_blocks)
125{
126 struct scsi_rdwr_req req;
127 int ret;
128
129 req.data_buffer_base = buffer;
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800130 req.lun = dev->current_lun;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700131 req.num_blocks = num_blocks;
132 req.start_lba = start_lba / dev->block_size;
133
134 ret = ucs_do_scsi_read(dev, &req);
135 if (ret)
136 {
137 dprintf(CRITICAL, "UFS read failed.\n");
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700138 ufs_dump_hc_registers(dev);
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700139 }
140
141 return ret;
142}
143
144int ufs_write(struct ufs_dev* dev, uint64_t start_lba, addr_t buffer, uint32_t num_blocks)
145{
146 struct scsi_rdwr_req req;
147 int ret;
148
149 req.data_buffer_base = buffer;
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800150 req.lun = dev->current_lun;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700151 req.num_blocks = num_blocks;
152 req.start_lba = start_lba / dev->block_size;
153
154 ret = ucs_do_scsi_write(dev, &req);
155 if (ret)
156 {
157 dprintf(CRITICAL, "UFS write failed.\n");
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700158 ufs_dump_hc_registers(dev);
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700159 }
160
161 return ret;
162}
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700163
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700164int ufs_erase(struct ufs_dev* dev, uint64_t start_lba, uint32_t num_blocks)
165{
166 struct scsi_unmap_req req;
167 int ret;
168
169 req.lun = dev->current_lun;
170 req.start_lba = start_lba / dev->block_size;
171 req.num_blocks = num_blocks;
172
173 ret = ucs_do_scsi_unmap(dev, &req);
174 if(ret)
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700175 {
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700176 dprintf(CRITICAL, "UFS erase failed \n");
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700177 }
Channagoud Kadabiab887302015-02-20 10:55:58 -0800178
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700179 return ret;
180}
181
182uint64_t ufs_get_dev_capacity(struct ufs_dev* dev)
183{
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800184 uint64_t capacity;
185 uint8_t lun = dev->current_lun;
186
187 capacity = dev->lun_cfg[lun].logical_blk_cnt * dev->block_size;
188
189 return capacity;
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700190}
191
192uint32_t ufs_get_erase_blk_size(struct ufs_dev* dev)
193{
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800194 uint32_t erase_blk_size;
195 uint8_t lun = dev->current_lun;
196
197 erase_blk_size = dev->lun_cfg[lun].erase_blk_size;
198
199 return erase_blk_size;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700200}
201
202uint32_t ufs_get_serial_num(struct ufs_dev* dev)
203{
204 int ret;
205
206 ret = dme_read_device_desc(dev);
207 if (ret)
208 {
209 dprintf(CRITICAL, "UFS get serial number failed.\n");
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700210 ufs_dump_hc_registers(dev);
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700211 }
212
213 return dev->serial_num;
214}
215
216uint32_t ufs_get_page_size(struct ufs_dev* dev)
217{
218 return dev->block_size;
219}
220
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800221uint8_t ufs_get_num_of_luns(struct ufs_dev* dev)
222{
223 return dev->num_lus;
224}
225
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700226int ufs_init(struct ufs_dev *dev)
227{
228 uint32_t ret = UFS_SUCCESS;
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800229 uint8_t lun = 0;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700230
231 dev->block_size = 4096;
232
233 /* Init dev struct. */
234 ret = ufs_dev_init(dev);
235 if (ret != UFS_SUCCESS)
236 {
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700237 dprintf(CRITICAL, "UFS dev_init failed\n");
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700238 goto ufs_init_err;
239 }
240
241 /* Perform Data link init. */
242 ret = uic_init(dev);
243 if (ret != UFS_SUCCESS)
244 {
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700245 dprintf(CRITICAL, "UFS uic_init failed\n");
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700246 goto ufs_init_err;
247 }
248
249 /* Setup request lists. */
250 ufs_setup_req_lists(dev);
251
252 /* Send NOP to check if device UTP layer is ready. */
253 ret = dme_send_nop_query(dev);
254 if (ret != UFS_SUCCESS)
255 {
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700256 dprintf(CRITICAL, "UFS dme_send_nop_query failed\n");
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700257 goto ufs_init_err;
258 }
259
260 ret = dme_set_fdeviceinit(dev);
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700261 if (ret != UFS_SUCCESS)
262 {
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700263 dprintf(CRITICAL, "UFS dme_set_fdeviceinit failed\n");
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700264 goto ufs_init_err;
265 }
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700266
267 ret = ucs_scsi_send_inquiry(dev);
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700268 if (ret != UFS_SUCCESS)
269 {
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700270 dprintf(CRITICAL, "UFS ucs_scsi_send_inquiry failed\n");
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700271 goto ufs_init_err;
272 }
273
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800274 ret = dme_read_device_desc(dev);
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700275 if (ret != UFS_SUCCESS)
276 {
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800277 dprintf(CRITICAL, "dme_read_dev_desc read failed\n");
Sundarajan Srinivasan54380a32013-10-25 17:38:38 -0700278 goto ufs_init_err;
279 }
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700280
Sundarajan Srinivasan332ce6a2013-12-04 17:27:46 -0800281
282 for(lun=0; lun < dev->num_lus; lun++)
283 {
284 ret = dme_read_unit_desc(dev, lun);
285 if (ret != UFS_SUCCESS)
286 {
287 dprintf(CRITICAL, "UFS dme_read_unit_desc failed\n");
288 goto ufs_init_err;
289 }
290 }
291
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700292 dprintf(CRITICAL,"UFS init success\n");
293
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700294ufs_init_err:
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700295
296 if(ret != UFS_SUCCESS)
297 {
298 ufs_dump_hc_registers(dev);
299 }
300
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700301 return ret;
302}
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700303
Sridhar Parasuram9ab24812014-10-01 10:51:23 -0700304void ufs_dump_is_register(struct ufs_dev *dev)
305{
306 uint32_t base = dev->base;
307 dprintf(CRITICAL,"UFS_IS 0x%x\n",readl(UFS_IS(base)));
308}
309
Sundarajan Srinivasan2fcaa982013-10-31 17:44:02 -0700310void ufs_dump_hc_registers(struct ufs_dev *dev)
311{
312 uint32_t base = dev->base;
313
314 dprintf(CRITICAL,"------Host controller register dump ---------\n");
315 dprintf(CRITICAL,"UFS_UECPA 0x%x\n",readl(UFS_UECPA(base)));
316 dprintf(CRITICAL,"UFS_UECDL 0x%x\n",readl(UFS_UECDL(base)));
317 dprintf(CRITICAL,"UFS_UECN 0x%x\n", readl(UFS_UECN(base)));
318 dprintf(CRITICAL,"UFS_UECT 0x%x\n",readl(UFS_UECT(base)));
319 dprintf(CRITICAL,"UFS_UECDME 0x%x\n",readl(UFS_UECDME(base)));
320 dprintf(CRITICAL,"UFS_HCS 0x%x\n", readl(UFS_HCS(base)));
321 dprintf(CRITICAL,"-----------End--------------------------------\n");
322}