blob: db930edbce7cbf5a911a261c79bc10fa64899000 [file] [log] [blame]
Sridhar Parasuramc6fb2ef2014-09-18 09:50:30 -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 <stdlib.h>
30#include <arch/ops.h>
31#include <sys/types.h>
32#include <reg.h>
33#include <platform/interrupts.h>
34#include <platform/iomap.h>
35#include <platform/irqs.h>
36#include <ufs_hw.h>
37#include <utp.h>
Sridhar Parasuramc6fb2ef2014-09-18 09:50:30 -070038#include <ufs.h>
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070039
40uint64_t ufs_alloc_trans_req_list()
41{
42 void *ptr;
43
44 ptr = memalign(lcm(CACHE_LINE, 1024), 32 * sizeof(struct utp_trans_req_desc));
45
46 if (!ptr)
47 {
48 dprintf(CRITICAL, "Failed to allocate utrd list.\n");
49 }
50
51 return (addr_t) ptr;
52}
53
54uint64_t ufs_alloc_task_mgmt_req_list()
55{
56 addr_t ptr = (addr_t) memalign(1024, 1024);
57
58 if (!ptr)
59 {
60 dprintf(CRITICAL, "Failed to allocate memory for Task mamagement request list.\n");
61 }
62
63 return ptr;
64}
65
66int ufs_enable_hci(struct ufs_dev *dev)
67{
68 int ret;
69
70 /* Enable host controller */
71 writel(UFS_HCE_ENABLE, UFS_HCE(dev->base));
72
73 /* Wait until host controller is enabled. */
74 ret = ufs_reg_target_val_timeout_loop(UFS_HCE(dev->base), 1, UFS_HCE_TIMEOUT);
75 if (ret)
76 {
77 dprintf(CRITICAL, "Failed to enable UFS host controller.\n");
78 }
79
80 return ret;
81}
82
83void ufs_irq_enable(struct ufs_dev *dev, uint32_t irq)
84{
85 /* Clear all irqs. */
86 writel(0xFFFFFFFF, UFS_IS(dev->base));
87
88 writel(irq, UFS_IE(dev->base));
89 register_int_handler(UFS_IRQ, ufs_irq_handler, dev);
90 unmask_interrupt(UFS_IRQ);
91}
92
93enum handler_return ufs_irq_handler(void* data)
94{
Sridhar Parasuram2c03af42014-09-22 13:39:01 -070095 uint32_t val, val_uecpa, val_uecdl, base;
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -070096 struct ufs_dev *dev = (struct ufs_dev *) data;
97 struct ufs_req_irq_type irq;
Sridhar Parasuram2c03af42014-09-22 13:39:01 -070098 base = dev->base;
99 val = readl(UFS_IS(base));
Sridhar Parasuramc6fb2ef2014-09-18 09:50:30 -0700100 if (val & UFS_IS_SBFES)
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700101 {
102 /* Controller might be in a bad state, unrecoverable error. */
Sridhar Parasuramc6fb2ef2014-09-18 09:50:30 -0700103 dprintf(CRITICAL, "UFS error: System Bus Fatal Error\n");
104 ASSERT(0);
105 }
106 else if (val & UFS_IS_UTPES)
107 {
108 /* Unrecoverable error occured at the utp layer */
109 dprintf(CRITICAL, "UFS error: UTP Error\n");
110 ASSERT(0);
111 }
112 else if ((val & UFS_IS_HCFES) || (val & UFS_IS_DFES))
113 {
114 /* Controller might be in a bad state, unrecoverable error. */
115 /* HCFES: Host Controller Fatal Error Status */
116 /* DFES: Device Fatal Error Status */
117 dprintf(CRITICAL, "UFS error: HCFES:0x%x DFES:0x%x\n",
118 val & UFS_IS_HCFES, val & UFS_IS_DFES);
119 ASSERT(0);
120 }
121 else if (val & UFS_IS_UE)
122 {
123 /* Error in one of the layers in the UniPro stack */
Sridhar Parasuram2c03af42014-09-22 13:39:01 -0700124 dprintf(CRITICAL, "UFS error: UE.\n");
125 /* Check if the error is because of UECPA or UECDL */
126 val_uecpa = readl(UFS_UECPA(base));
127 val_uecdl = readl(UFS_UECDL(base));
128 if((val_uecpa & UFS_IS_UECPA) || (val_uecdl & UFS_IS_UECDL))
129 {
130 dprintf(CRITICAL, "UIC non-fatal error. IS: 0x%x UECPA: 0x%x UECDL: 0x%x\n",
131 val, val_uecpa, val_uecdl);
132 irq.irq_handled = BIT(2);
133 val &= ~UFS_IS_UE;
134 writel(irq.irq_handled, UFS_IS(dev->base));
135 dprintf(CRITICAL, "UIC non-fatal error handled. Pending interrupt mask: 0x%x\n", val);
136 }
137 else
138 {
139 dprintf(CRITICAL, "UIC fatal error.\n");
140 ufs_dump_hc_registers(dev);
141 ASSERT(0);
142 }
Deepa Dinamaniab9c2b92013-09-12 11:30:58 -0700143 }
144
145 while (val)
146 {
147 irq.irq_handled = 0;
148
149 if (val & UFS_IS_UCCS)
150 {
151 /* UIC command */
152 event_signal(&(dev->uic_data.uic_event), false);
153 /* Clear irq. */
154 writel(UFS_IS_UCCS, UFS_IS(dev->base));
155 val &= ~UFS_IS_UCCS;
156 irq.irq_handled = UFS_IS_UCCS;
157 continue;
158 }
159 else if (val & UFS_IS_UTRCS)
160 {
161 /* UTRD completion. */
162 irq.list = &(dev->utrd_data.list_head.list_node);
163 irq.irq_handled = UFS_IS_UTRCS;
164 irq.door_bell_reg = UFS_UTRLDBR(dev->base);
165
166 /* Clear irq. */
167 writel(irq.irq_handled, UFS_IS(dev->base));
168 val &= ~irq.irq_handled;
169
170 utp_process_req_completion(&irq);
171 }
172 else if (val & UFS_IS_UTMRCS)
173 {
174 /* UTMRD completion. */
175 irq.list = &(dev->utmrd_data.list_head.list_node);
176 irq.irq_handled = UFS_IS_UTMRCS;
177 /* TODO: Fill in door bell reg for management requests. */
178
179 /* Clear irq. */
180 writel(irq.irq_handled, UFS_IS(dev->base));
181 val &= ~irq.irq_handled;
182
183 utp_process_req_completion(&irq);
184 }
185 else
186 {
187 dprintf(CRITICAL, "Unknown irq.\n");
188 ASSERT(0);
189 }
190 }
191
192 return INT_NO_RESCHEDULE;
193}
194
195int ufs_reg_target_val_timeout_loop(uint32_t reg_addr, uint32_t target_val, uint32_t timeout)
196{
197 uint32_t try_again;
198 uint32_t val;
199
200 try_again = timeout;
201
202 do
203 {
204 try_again--;
205 val = readl(reg_addr);
206 } while (!(val & target_val) && try_again);
207
208 if (!(val & target_val))
209 return -UFS_FAILURE;
210 else
211 return UFS_SUCCESS;
212}