blob: 479c0ffa24d93a75dcc188b7cc139b2e382b7373 [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 <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>
38
39uint64_t ufs_alloc_trans_req_list()
40{
41 void *ptr;
42
43 ptr = memalign(lcm(CACHE_LINE, 1024), 32 * sizeof(struct utp_trans_req_desc));
44
45 if (!ptr)
46 {
47 dprintf(CRITICAL, "Failed to allocate utrd list.\n");
48 }
49
50 return (addr_t) ptr;
51}
52
53uint64_t ufs_alloc_task_mgmt_req_list()
54{
55 addr_t ptr = (addr_t) memalign(1024, 1024);
56
57 if (!ptr)
58 {
59 dprintf(CRITICAL, "Failed to allocate memory for Task mamagement request list.\n");
60 }
61
62 return ptr;
63}
64
65int ufs_enable_hci(struct ufs_dev *dev)
66{
67 int ret;
68
69 /* Enable host controller */
70 writel(UFS_HCE_ENABLE, UFS_HCE(dev->base));
71
72 /* Wait until host controller is enabled. */
73 ret = ufs_reg_target_val_timeout_loop(UFS_HCE(dev->base), 1, UFS_HCE_TIMEOUT);
74 if (ret)
75 {
76 dprintf(CRITICAL, "Failed to enable UFS host controller.\n");
77 }
78
79 return ret;
80}
81
82void ufs_irq_enable(struct ufs_dev *dev, uint32_t irq)
83{
84 /* Clear all irqs. */
85 writel(0xFFFFFFFF, UFS_IS(dev->base));
86
87 writel(irq, UFS_IE(dev->base));
88 register_int_handler(UFS_IRQ, ufs_irq_handler, dev);
89 unmask_interrupt(UFS_IRQ);
90}
91
92enum handler_return ufs_irq_handler(void* data)
93{
94 uint32_t val;
95 struct ufs_dev *dev = (struct ufs_dev *) data;
96 struct ufs_req_irq_type irq;
97
98 val = readl(UFS_IS(dev->base));
99
100 if (val & UFS_IS_SBFES || val & UFS_IS_HCFES || val & UFS_IS_UTPES || val & UFS_IS_DFES || val & UFS_IS_UE)
101 {
102 /* Controller might be in a bad state, unrecoverable error. */
103 dprintf(CRITICAL, "UFS error\n");
104 ASSERT(0);
105 }
106
107 while (val)
108 {
109 irq.irq_handled = 0;
110
111 if (val & UFS_IS_UCCS)
112 {
113 /* UIC command */
114 event_signal(&(dev->uic_data.uic_event), false);
115 /* Clear irq. */
116 writel(UFS_IS_UCCS, UFS_IS(dev->base));
117 val &= ~UFS_IS_UCCS;
118 irq.irq_handled = UFS_IS_UCCS;
119 continue;
120 }
121 else if (val & UFS_IS_UTRCS)
122 {
123 /* UTRD completion. */
124 irq.list = &(dev->utrd_data.list_head.list_node);
125 irq.irq_handled = UFS_IS_UTRCS;
126 irq.door_bell_reg = UFS_UTRLDBR(dev->base);
127
128 /* Clear irq. */
129 writel(irq.irq_handled, UFS_IS(dev->base));
130 val &= ~irq.irq_handled;
131
132 utp_process_req_completion(&irq);
133 }
134 else if (val & UFS_IS_UTMRCS)
135 {
136 /* UTMRD completion. */
137 irq.list = &(dev->utmrd_data.list_head.list_node);
138 irq.irq_handled = UFS_IS_UTMRCS;
139 /* TODO: Fill in door bell reg for management requests. */
140
141 /* Clear irq. */
142 writel(irq.irq_handled, UFS_IS(dev->base));
143 val &= ~irq.irq_handled;
144
145 utp_process_req_completion(&irq);
146 }
147 else
148 {
149 dprintf(CRITICAL, "Unknown irq.\n");
150 ASSERT(0);
151 }
152 }
153
154 return INT_NO_RESCHEDULE;
155}
156
157int ufs_reg_target_val_timeout_loop(uint32_t reg_addr, uint32_t target_val, uint32_t timeout)
158{
159 uint32_t try_again;
160 uint32_t val;
161
162 try_again = timeout;
163
164 do
165 {
166 try_again--;
167 val = readl(reg_addr);
168 } while (!(val & target_val) && try_again);
169
170 if (!(val & target_val))
171 return -UFS_FAILURE;
172 else
173 return UFS_SUCCESS;
174}