xref: /freebsd/sys/arm/altera/socfpga/socfpga_a10_manager.c (revision b9f654b163bce26de79705e77b872427c9f2afa1)
1 /*-
2  * Copyright (c) 2017 Ruslan Bukin <br@bsdpad.com>
3  * All rights reserved.
4  *
5  * This software was developed by SRI International and the University of
6  * Cambridge Computer Laboratory under DARPA/AFRL contract FA8750-10-C-0237
7  * ("CTSRD"), as part of the DARPA CRASH research programme.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */
30 
31 /*
32  * Intel Arria 10 FPGA Manager.
33  * Chapter 4, Arria 10 Hard Processor System Technical Reference Manual.
34  * Chapter A, FPGA Reconfiguration.
35  */
36 
37 #include <sys/cdefs.h>
38 __FBSDID("$FreeBSD$");
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/bus.h>
43 #include <sys/kernel.h>
44 #include <sys/module.h>
45 #include <sys/malloc.h>
46 #include <sys/rman.h>
47 #include <sys/timeet.h>
48 #include <sys/timetc.h>
49 #include <sys/conf.h>
50 #include <sys/uio.h>
51 
52 #include <dev/ofw/openfirm.h>
53 #include <dev/ofw/ofw_bus.h>
54 #include <dev/ofw/ofw_bus_subr.h>
55 
56 #include <machine/bus.h>
57 #include <machine/cpu.h>
58 #include <machine/intr.h>
59 
60 #include <arm/altera/socfpga/socfpga_common.h>
61 
62 #define	FPGAMGR_DCLKCNT			0x8	/* DCLK Count Register */
63 #define	FPGAMGR_DCLKSTAT		0xC	/* DCLK Status Register */
64 #define	FPGAMGR_GPO			0x10	/* General-Purpose Output Register */
65 #define	FPGAMGR_GPI			0x14	/* General-Purpose Input Register */
66 #define	FPGAMGR_MISCI			0x18	/* Miscellaneous Input Register */
67 #define	IMGCFG_CTRL_00			0x70
68 #define	 S2F_CONDONE_OE			(1 << 24)
69 #define	 S2F_NSTATUS_OE			(1 << 16)
70 #define	 CTRL_00_NCONFIG		(1 << 8)
71 #define	 CTRL_00_NENABLE_CONDONE	(1 << 2)
72 #define	 CTRL_00_NENABLE_NSTATUS	(1 << 1)
73 #define	 CTRL_00_NENABLE_NCONFIG	(1 << 0)
74 #define	IMGCFG_CTRL_01			0x74
75 #define	 CTRL_01_S2F_NCE		(1 << 24)
76 #define	 CTRL_01_S2F_PR_REQUEST		(1 << 16)
77 #define	 CTRL_01_S2F_NENABLE_CONFIG	(1 << 0)
78 #define	IMGCFG_CTRL_02			0x78
79 #define	 CTRL_02_CDRATIO_S		16
80 #define	 CTRL_02_CDRATIO_M		(0x3 << CTRL_02_CDRATIO_S)
81 #define	 CTRL_02_CFGWIDTH_16		(0 << 24)
82 #define	 CTRL_02_CFGWIDTH_32		(1 << 24)
83 #define	 CTRL_02_EN_CFG_DATA		(1 << 8)
84 #define	 CTRL_02_EN_CFG_CTRL		(1 << 0)
85 #define	IMGCFG_STAT			0x80
86 #define	 F2S_PR_ERROR			(1 << 11)
87 #define	 F2S_PR_DONE			(1 << 10)
88 #define	 F2S_PR_READY			(1 << 9)
89 #define	 F2S_MSEL_S			16
90 #define	 F2S_MSEL_M			(0x7 << F2S_MSEL_S)
91 #define	 MSEL_PASSIVE_FAST		0
92 #define	 MSEL_PASSIVE_SLOW		1
93 #define	 F2S_NCONFIG_PIN		(1 << 12)
94 #define	 F2S_CONDONE_OE			(1 << 7)
95 #define	 F2S_NSTATUS_PIN		(1 << 4)
96 #define	 F2S_CONDONE_PIN		(1 << 6)
97 #define	 F2S_USERMODE			(1 << 2)
98 
99 struct fpgamgr_a10_softc {
100 	struct resource		*res[2];
101 	bus_space_tag_t		bst_data;
102 	bus_space_handle_t	bsh_data;
103 	struct cdev		*mgr_cdev;
104 	device_t		dev;
105 };
106 
107 static struct resource_spec fpgamgr_a10_spec[] = {
108 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
109 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
110 	{ -1, 0 }
111 };
112 
113 static int
114 fpga_wait_dclk_pulses(struct fpgamgr_a10_softc *sc, int npulses)
115 {
116 	int tout;
117 
118 	/* Clear done bit, if any */
119 	if (READ4(sc, FPGAMGR_DCLKSTAT) != 0)
120 		WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
121 
122 	/* Request DCLK pulses */
123 	WRITE4(sc, FPGAMGR_DCLKCNT, npulses);
124 
125 	/* Wait finish */
126 	tout = 1000;
127 	while (tout > 0) {
128 		if (READ4(sc, FPGAMGR_DCLKSTAT) == 1) {
129 			WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
130 			break;
131 		}
132 		tout--;
133 		DELAY(10);
134 	}
135 	if (tout == 0) {
136 		device_printf(sc->dev,
137 		    "Error: dclkpulses wait timeout\n");
138 		return (1);
139 	}
140 
141 	return (0);
142 }
143 
144 
145 static int
146 fpga_open(struct cdev *dev, int flags __unused,
147     int fmt __unused, struct thread *td __unused)
148 {
149 	struct fpgamgr_a10_softc *sc;
150 	int tout;
151 	int msel;
152 	int reg;
153 
154 	sc = dev->si_drv1;
155 
156 	/* Step 1 */
157 	reg = READ4(sc, IMGCFG_STAT);
158 	if ((reg & F2S_USERMODE) == 0) {
159 		device_printf(sc->dev, "Error: invalid mode\n");
160 		return (ENXIO);
161 	};
162 
163 	/* Step 2 */
164 	reg = READ4(sc, IMGCFG_STAT);
165 	msel = (reg & F2S_MSEL_M) >> F2S_MSEL_S;
166 	if ((msel != MSEL_PASSIVE_FAST) && \
167 	    (msel != MSEL_PASSIVE_SLOW)) {
168 		device_printf(sc->dev,
169 		    "Error: invalid msel %d\n", msel);
170 		return (ENXIO);
171 	};
172 
173 	/*
174 	 * Step 3.
175 	 * TODO: add support for compressed, encrypted images.
176 	 */
177 	reg = READ4(sc, IMGCFG_CTRL_02);
178 	reg &= ~(CTRL_02_CDRATIO_M);
179 	WRITE4(sc, IMGCFG_CTRL_02, reg);
180 
181 	reg = READ4(sc, IMGCFG_CTRL_02);
182 	reg &= ~CTRL_02_CFGWIDTH_32;
183 	WRITE4(sc, IMGCFG_CTRL_02, reg);
184 
185 	/* Step 4. a */
186 	reg = READ4(sc, IMGCFG_CTRL_01);
187 	reg &= ~CTRL_01_S2F_PR_REQUEST;
188 	WRITE4(sc, IMGCFG_CTRL_01, reg);
189 
190 	reg = READ4(sc, IMGCFG_CTRL_00);
191 	reg |= CTRL_00_NCONFIG;
192 	WRITE4(sc, IMGCFG_CTRL_00, reg);
193 
194 	/* b */
195 	reg = READ4(sc, IMGCFG_CTRL_01);
196 	reg &= ~CTRL_01_S2F_NCE;
197 	WRITE4(sc, IMGCFG_CTRL_01, reg);
198 
199 	/* c */
200 	reg = READ4(sc, IMGCFG_CTRL_02);
201 	reg |= CTRL_02_EN_CFG_CTRL;
202 	WRITE4(sc, IMGCFG_CTRL_02, reg);
203 
204 	/* d */
205 	reg = READ4(sc, IMGCFG_CTRL_00);
206 	reg &= ~S2F_CONDONE_OE;
207 	reg &= ~S2F_NSTATUS_OE;
208 	reg |= CTRL_00_NCONFIG;
209 	reg |= CTRL_00_NENABLE_NSTATUS;
210 	reg |= CTRL_00_NENABLE_CONDONE;
211 	reg &= ~CTRL_00_NENABLE_NCONFIG;
212 	WRITE4(sc, IMGCFG_CTRL_00, reg);
213 
214 	/* Step 5 */
215 	reg = READ4(sc, IMGCFG_CTRL_01);
216 	reg &= ~CTRL_01_S2F_NENABLE_CONFIG;
217 	WRITE4(sc, IMGCFG_CTRL_01, reg);
218 
219 	/* Step 6 */
220 	fpga_wait_dclk_pulses(sc, 0x100);
221 
222 	/* Step 7. a */
223 	reg = READ4(sc, IMGCFG_CTRL_01);
224 	reg |= CTRL_01_S2F_PR_REQUEST;
225 	WRITE4(sc, IMGCFG_CTRL_01, reg);
226 
227 	/* b, c */
228 	fpga_wait_dclk_pulses(sc, 0x7ff);
229 
230 	/* Step 8 */
231 	tout = 10;
232 	while (tout--) {
233 		reg = READ4(sc, IMGCFG_STAT);
234 		if (reg & F2S_PR_ERROR) {
235 			device_printf(sc->dev,
236 			    "Error: PR failed on open.\n");
237 			return (ENXIO);
238 		}
239 		if (reg & F2S_PR_READY) {
240 			break;
241 		}
242 	}
243 	if (tout == 0) {
244 		device_printf(sc->dev,
245 		    "Error: Timeout waiting PR ready bit.\n");
246 		return (ENXIO);
247 	}
248 
249 	return (0);
250 }
251 
252 static int
253 fpga_close(struct cdev *dev, int flags __unused,
254     int fmt __unused, struct thread *td __unused)
255 {
256 	struct fpgamgr_a10_softc *sc;
257 	int tout;
258 	int reg;
259 
260 	sc = dev->si_drv1;
261 
262 	/* Step 10 */
263 	tout = 10;
264 	while (tout--) {
265 		reg = READ4(sc, IMGCFG_STAT);
266 		if (reg & F2S_PR_ERROR) {
267 			device_printf(sc->dev,
268 			    "Error: PR failed.\n");
269 			return (ENXIO);
270 		}
271 		if (reg & F2S_PR_DONE) {
272 			break;
273 		}
274 	}
275 
276 	/* Step 11 */
277 	reg = READ4(sc, IMGCFG_CTRL_01);
278 	reg &= ~CTRL_01_S2F_PR_REQUEST;
279 	WRITE4(sc, IMGCFG_CTRL_01, reg);
280 
281 	/* Step 12, 13 */
282 	fpga_wait_dclk_pulses(sc, 0x100);
283 
284 	/* Step 14 */
285 	reg = READ4(sc, IMGCFG_CTRL_02);
286 	reg &= ~CTRL_02_EN_CFG_CTRL;
287 	WRITE4(sc, IMGCFG_CTRL_02, reg);
288 
289 	/* Step 15 */
290 	reg = READ4(sc, IMGCFG_CTRL_01);
291 	reg |= CTRL_01_S2F_NCE;
292 	WRITE4(sc, IMGCFG_CTRL_01, reg);
293 
294 	/* Step 16 */
295 	reg = READ4(sc, IMGCFG_CTRL_01);
296 	reg |= CTRL_01_S2F_NENABLE_CONFIG;
297 	WRITE4(sc, IMGCFG_CTRL_01, reg);
298 
299 	/* Step 17 */
300 	reg = READ4(sc, IMGCFG_STAT);
301 	if ((reg & F2S_USERMODE) == 0) {
302 		device_printf(sc->dev,
303 		    "Error: invalid mode\n");
304 		return (ENXIO);
305 	};
306 
307 	if ((reg & F2S_CONDONE_PIN) == 0) {
308 		device_printf(sc->dev,
309 		    "Error: configuration not done\n");
310 		return (ENXIO);
311 	};
312 
313 	if ((reg & F2S_NSTATUS_PIN) == 0) {
314 		device_printf(sc->dev,
315 		    "Error: nstatus pin\n");
316 		return (ENXIO);
317 	};
318 
319 	return (0);
320 }
321 
322 static int
323 fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
324 {
325 	struct fpgamgr_a10_softc *sc;
326 	uint32_t buffer;
327 
328 	sc = dev->si_drv1;
329 
330 	/*
331 	 * Step 9.
332 	 * Device supports 4-byte writes only.
333 	 */
334 
335 	while (uio->uio_resid >= 4) {
336 		uiomove(&buffer, 4, uio);
337 		bus_space_write_4(sc->bst_data, sc->bsh_data,
338 		    0x0, buffer);
339 	}
340 
341 	switch (uio->uio_resid) {
342 	case 3:
343 		uiomove(&buffer, 3, uio);
344 		buffer &= 0xffffff;
345 		bus_space_write_4(sc->bst_data, sc->bsh_data,
346 		    0x0, buffer);
347 		break;
348 	case 2:
349 		uiomove(&buffer, 2, uio);
350 		buffer &= 0xffff;
351 		bus_space_write_4(sc->bst_data, sc->bsh_data,
352 		    0x0, buffer);
353 		break;
354 	case 1:
355 		uiomove(&buffer, 1, uio);
356 		buffer &= 0xff;
357 		bus_space_write_4(sc->bst_data, sc->bsh_data,
358 		    0x0, buffer);
359 		break;
360 	default:
361 		break;
362 	};
363 
364 	return (0);
365 }
366 
367 static int
368 fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
369     struct thread *td)
370 {
371 
372 	return (0);
373 }
374 
375 static struct cdevsw fpga_cdevsw = {
376 	.d_version =	D_VERSION,
377 	.d_open =	fpga_open,
378 	.d_close =	fpga_close,
379 	.d_write =	fpga_write,
380 	.d_ioctl =	fpga_ioctl,
381 	.d_name =	"FPGA Manager",
382 };
383 
384 static int
385 fpgamgr_a10_probe(device_t dev)
386 {
387 
388 	if (!ofw_bus_status_okay(dev))
389 		return (ENXIO);
390 
391 	if (!ofw_bus_is_compatible(dev, "altr,socfpga-a10-fpga-mgr"))
392 		return (ENXIO);
393 
394 	device_set_desc(dev, "Arria 10 FPGA Manager");
395 
396 	return (BUS_PROBE_DEFAULT);
397 }
398 
399 static int
400 fpgamgr_a10_attach(device_t dev)
401 {
402 	struct fpgamgr_a10_softc *sc;
403 
404 	sc = device_get_softc(dev);
405 	sc->dev = dev;
406 
407 	if (bus_alloc_resources(dev, fpgamgr_a10_spec, sc->res)) {
408 		device_printf(dev, "Could not allocate resources.\n");
409 		return (ENXIO);
410 	}
411 
412 	/* Memory interface */
413 	sc->bst_data = rman_get_bustag(sc->res[1]);
414 	sc->bsh_data = rman_get_bushandle(sc->res[1]);
415 
416 	sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
417 	    0600, "fpga%d", device_get_unit(sc->dev));
418 
419 	if (sc->mgr_cdev == NULL) {
420 		device_printf(dev, "Failed to create character device.\n");
421 		return (ENXIO);
422 	}
423 
424 	sc->mgr_cdev->si_drv1 = sc;
425 
426 	return (0);
427 }
428 
429 static device_method_t fpgamgr_a10_methods[] = {
430 	DEVMETHOD(device_probe,		fpgamgr_a10_probe),
431 	DEVMETHOD(device_attach,	fpgamgr_a10_attach),
432 	{ 0, 0 }
433 };
434 
435 static driver_t fpgamgr_a10_driver = {
436 	"fpgamgr_a10",
437 	fpgamgr_a10_methods,
438 	sizeof(struct fpgamgr_a10_softc),
439 };
440 
441 static devclass_t fpgamgr_a10_devclass;
442 
443 DRIVER_MODULE(fpgamgr_a10, simplebus, fpgamgr_a10_driver,
444     fpgamgr_a10_devclass, 0, 0);
445