blob: 7e7538553e3f49b12c88c0100c5bac32cdd43705 [file] [log] [blame]
Mark Kettenis31d5f7b2022-01-22 20:38:18 +01001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * (C) Copyright 2021 Mark Kettenis <kettenis@openbsd.org>
4 */
5
Mark Kettenis31d5f7b2022-01-22 20:38:18 +01006#include <dm.h>
7#include <mailbox.h>
8#include <mapmem.h>
9#include "nvme.h"
10#include <reset.h>
11
12#include <asm/io.h>
13#include <asm/arch/rtkit.h>
Janne Grunaue3a438f2022-06-14 09:09:07 +020014#include <asm/arch/sart.h>
Mark Kettenis31d5f7b2022-01-22 20:38:18 +010015#include <linux/iopoll.h>
16
17/* ASC registers */
18#define REG_CPU_CTRL 0x0044
19#define REG_CPU_CTRL_RUN BIT(4)
20
21/* Apple NVMe registers */
22#define ANS_MAX_PEND_CMDS_CTRL 0x01210
23#define ANS_MAX_QUEUE_DEPTH 64
24#define ANS_BOOT_STATUS 0x01300
25#define ANS_BOOT_STATUS_OK 0xde71ce55
26#define ANS_MODESEL 0x01304
27#define ANS_UNKNOWN_CTRL 0x24008
28#define ANS_PRP_NULL_CHECK (1 << 11)
29#define ANS_LINEAR_SQ_CTRL 0x24908
30#define ANS_LINEAR_SQ_CTRL_EN (1 << 0)
31#define ANS_ASQ_DB 0x2490c
32#define ANS_IOSQ_DB 0x24910
33#define ANS_NVMMU_NUM 0x28100
34#define ANS_NVMMU_BASE_ASQ 0x28108
35#define ANS_NVMMU_BASE_IOSQ 0x28110
36#define ANS_NVMMU_TCB_INVAL 0x28118
37#define ANS_NVMMU_TCB_STAT 0x28120
38
39#define ANS_NVMMU_TCB_SIZE 0x4000
40#define ANS_NVMMU_TCB_PITCH 0x80
41
42/*
43 * The Apple NVMe controller includes an IOMMU known as NVMMU. The
44 * NVMMU is programmed through an array of TCBs. These TCBs are paired
45 * with the corresponding slot in the submission queues and need to be
46 * configured with the command details before a command is allowed to
47 * execute. This is necessary even for commands that don't do DMA.
48 */
49struct ans_nvmmu_tcb {
50 u8 opcode;
51 u8 flags;
52 u8 slot;
53 u8 pad0;
54 u32 prpl_len;
55 u8 pad1[16];
56 u64 prp1;
57 u64 prp2;
58};
59
60#define ANS_NVMMU_TCB_WRITE BIT(0)
61#define ANS_NVMMU_TCB_READ BIT(1)
62
63struct apple_nvme_priv {
64 struct nvme_dev ndev;
65 void *base; /* NVMe registers */
66 void *asc; /* ASC registers */
67 struct reset_ctl_bulk resets; /* ASC reset */
68 struct mbox_chan chan;
Janne Grunaue3a438f2022-06-14 09:09:07 +020069 struct apple_sart *sart;
70 struct apple_rtkit *rtk;
Mark Kettenis31d5f7b2022-01-22 20:38:18 +010071 struct ans_nvmmu_tcb *tcbs[NVME_Q_NUM]; /* Submission queue TCBs */
72 u32 __iomem *q_db[NVME_Q_NUM]; /* Submission queue doorbell */
73};
74
75static int apple_nvme_setup_queue(struct nvme_queue *nvmeq)
76{
77 struct apple_nvme_priv *priv =
78 container_of(nvmeq->dev, struct apple_nvme_priv, ndev);
79 struct nvme_dev *dev = nvmeq->dev;
80
81 switch (nvmeq->qid) {
82 case NVME_ADMIN_Q:
83 case NVME_IO_Q:
84 break;
85 default:
86 return -EINVAL;
87 }
88
89 priv->tcbs[nvmeq->qid] = (void *)memalign(4096, ANS_NVMMU_TCB_SIZE);
90 memset((void *)priv->tcbs[nvmeq->qid], 0, ANS_NVMMU_TCB_SIZE);
91
92 switch (nvmeq->qid) {
93 case NVME_ADMIN_Q:
94 priv->q_db[nvmeq->qid] =
95 ((void __iomem *)dev->bar) + ANS_ASQ_DB;
96 nvme_writeq((ulong)priv->tcbs[nvmeq->qid],
97 ((void __iomem *)dev->bar) + ANS_NVMMU_BASE_ASQ);
98 break;
99 case NVME_IO_Q:
100 priv->q_db[nvmeq->qid] =
101 ((void __iomem *)dev->bar) + ANS_IOSQ_DB;
102 nvme_writeq((ulong)priv->tcbs[nvmeq->qid],
103 ((void __iomem *)dev->bar) + ANS_NVMMU_BASE_IOSQ);
104 break;
105 }
106
107 return 0;
108}
109
110static void apple_nvme_submit_cmd(struct nvme_queue *nvmeq,
111 struct nvme_command *cmd)
112{
113 struct apple_nvme_priv *priv =
114 container_of(nvmeq->dev, struct apple_nvme_priv, ndev);
115 struct ans_nvmmu_tcb *tcb;
116 u16 tail = nvmeq->sq_tail;
117
118 tcb = ((void *)priv->tcbs[nvmeq->qid]) + tail * ANS_NVMMU_TCB_PITCH;
119 memset(tcb, 0, sizeof(*tcb));
120 tcb->opcode = cmd->common.opcode;
121 tcb->flags = ANS_NVMMU_TCB_WRITE | ANS_NVMMU_TCB_READ;
122 tcb->slot = tail;
123 tcb->prpl_len = cmd->rw.length;
124 tcb->prp1 = cmd->common.prp1;
125 tcb->prp2 = cmd->common.prp2;
126
127 writel(tail, priv->q_db[nvmeq->qid]);
128}
129
130static void apple_nvme_complete_cmd(struct nvme_queue *nvmeq,
131 struct nvme_command *cmd)
132{
133 struct apple_nvme_priv *priv =
134 container_of(nvmeq->dev, struct apple_nvme_priv, ndev);
135 struct ans_nvmmu_tcb *tcb;
136 u16 tail = nvmeq->sq_tail;
137
138 tcb = ((void *)priv->tcbs[nvmeq->qid]) + tail * ANS_NVMMU_TCB_PITCH;
139 memset(tcb, 0, sizeof(*tcb));
140 writel(tail, ((void __iomem *)nvmeq->dev->bar) + ANS_NVMMU_TCB_INVAL);
141 readl(((void __iomem *)nvmeq->dev->bar) + ANS_NVMMU_TCB_STAT);
142
143 if (++tail == nvmeq->q_depth)
144 tail = 0;
145 nvmeq->sq_tail = tail;
146}
147
Janne Grunaue3a438f2022-06-14 09:09:07 +0200148static int nvme_shmem_setup(void *cookie, struct apple_rtkit_buffer *buf)
149{
150 struct apple_nvme_priv *priv = (struct apple_nvme_priv *)cookie;
151
152 if (!buf || buf->dva || !buf->size)
153 return -1;
154
155 buf->buffer = memalign(SZ_16K, ALIGN(buf->size, SZ_16K));
156 if (!buf->buffer)
157 return -ENOMEM;
158
159 if (!sart_add_allowed_region(priv->sart, buf->buffer, buf->size)) {
160 free(buf->buffer);
161 buf->buffer = NULL;
162 buf->size = 0;
163 return -1;
164 }
165
166 buf->dva = (u64)buf->buffer;
167
168 return 0;
169}
170
171static void nvme_shmem_destroy(void *cookie, struct apple_rtkit_buffer *buf)
172{
173 struct apple_nvme_priv *priv = (struct apple_nvme_priv *)cookie;
174
175 if (!buf)
176 return;
177
178 if (buf->buffer) {
179 sart_remove_allowed_region(priv->sart, buf->buffer, buf->size);
180 free(buf->buffer);
181 buf->buffer = NULL;
182 buf->size = 0;
183 buf->dva = 0;
184 }
185}
186
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100187static int apple_nvme_probe(struct udevice *dev)
188{
189 struct apple_nvme_priv *priv = dev_get_priv(dev);
190 fdt_addr_t addr;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200191 ofnode of_sart;
192 u32 ctrl, stat, phandle;
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100193 int ret;
194
195 priv->base = dev_read_addr_ptr(dev);
196 if (!priv->base)
197 return -EINVAL;
198
199 addr = dev_read_addr_index(dev, 1);
200 if (addr == FDT_ADDR_T_NONE)
201 return -EINVAL;
202 priv->asc = map_sysmem(addr, 0);
203
204 ret = reset_get_bulk(dev, &priv->resets);
205 if (ret < 0)
206 return ret;
207
208 ret = mbox_get_by_index(dev, 0, &priv->chan);
209 if (ret < 0)
210 return ret;
211
Janne Grunaue3a438f2022-06-14 09:09:07 +0200212 ret = dev_read_u32(dev, "apple,sart", &phandle);
213 if (ret < 0)
214 return ret;
215
216 of_sart = ofnode_get_by_phandle(phandle);
217 priv->sart = sart_init(of_sart);
218 if (!priv->sart)
219 return -EINVAL;
220
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100221 ctrl = readl(priv->asc + REG_CPU_CTRL);
222 writel(ctrl | REG_CPU_CTRL_RUN, priv->asc + REG_CPU_CTRL);
223
Janne Grunaue3a438f2022-06-14 09:09:07 +0200224 priv->rtk = apple_rtkit_init(&priv->chan, priv, nvme_shmem_setup, nvme_shmem_destroy);
225 if (!priv->rtk)
226 return -ENOMEM;
227
228 ret = apple_rtkit_boot(priv->rtk);
229 if (ret < 0) {
230 printf("%s: NVMe apple_rtkit_boot returned: %d\n", __func__, ret);
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100231 return ret;
Janne Grunaue3a438f2022-06-14 09:09:07 +0200232 }
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100233
234 ret = readl_poll_sleep_timeout(priv->base + ANS_BOOT_STATUS, stat,
235 (stat == ANS_BOOT_STATUS_OK), 100,
236 500000);
237 if (ret < 0) {
238 printf("%s: NVMe firmware didn't boot\n", __func__);
239 return -ETIMEDOUT;
240 }
241
242 writel(ANS_LINEAR_SQ_CTRL_EN, priv->base + ANS_LINEAR_SQ_CTRL);
243 writel(((ANS_MAX_QUEUE_DEPTH << 16) | ANS_MAX_QUEUE_DEPTH),
244 priv->base + ANS_MAX_PEND_CMDS_CTRL);
245
246 writel(readl(priv->base + ANS_UNKNOWN_CTRL) & ~ANS_PRP_NULL_CHECK,
247 priv->base + ANS_UNKNOWN_CTRL);
248
249 strcpy(priv->ndev.vendor, "Apple");
250
251 writel((ANS_NVMMU_TCB_SIZE / ANS_NVMMU_TCB_PITCH) - 1,
252 priv->base + ANS_NVMMU_NUM);
253 writel(0, priv->base + ANS_MODESEL);
254
255 priv->ndev.bar = priv->base;
256 return nvme_init(dev);
257}
258
259static int apple_nvme_remove(struct udevice *dev)
260{
261 struct apple_nvme_priv *priv = dev_get_priv(dev);
262 u32 ctrl;
263
264 nvme_shutdown(dev);
265
Janne Grunaue3a438f2022-06-14 09:09:07 +0200266 apple_rtkit_shutdown(priv->rtk, APPLE_RTKIT_PWR_STATE_SLEEP);
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100267
268 ctrl = readl(priv->asc + REG_CPU_CTRL);
269 writel(ctrl & ~REG_CPU_CTRL_RUN, priv->asc + REG_CPU_CTRL);
270
Janne Grunaue3a438f2022-06-14 09:09:07 +0200271 apple_rtkit_free(priv->rtk);
272 priv->rtk = NULL;
273
274 sart_free(priv->sart);
275 priv->sart = NULL;
276
Mark Kettenis31d5f7b2022-01-22 20:38:18 +0100277 reset_assert_bulk(&priv->resets);
278 reset_deassert_bulk(&priv->resets);
279
280 return 0;
281}
282
283static const struct nvme_ops apple_nvme_ops = {
284 .setup_queue = apple_nvme_setup_queue,
285 .submit_cmd = apple_nvme_submit_cmd,
286 .complete_cmd = apple_nvme_complete_cmd,
287};
288
289static const struct udevice_id apple_nvme_ids[] = {
290 { .compatible = "apple,nvme-ans2" },
291 { /* sentinel */ }
292};
293
294U_BOOT_DRIVER(apple_nvme) = {
295 .name = "apple_nvme",
296 .id = UCLASS_NVME,
297 .of_match = apple_nvme_ids,
298 .priv_auto = sizeof(struct apple_nvme_priv),
299 .probe = apple_nvme_probe,
300 .remove = apple_nvme_remove,
301 .ops = &apple_nvme_ops,
302 .flags = DM_FLAG_OS_PREPARE,
303};