1/*-
2 * Copyright (c) 2014 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 * Altera FPGA Manager.
33 * Chapter 4, Cyclone V Device Handbook (CV-5V2 2014.07.22)
34 */
35
36#include <sys/cdefs.h>
37__FBSDID("$FreeBSD$");
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/bus.h>
42#include <sys/kernel.h>
43#include <sys/module.h>
44#include <sys/malloc.h>
45#include <sys/rman.h>
46#include <sys/timeet.h>
47#include <sys/timetc.h>
48#include <sys/conf.h>
49#include <sys/uio.h>
50
51#include <dev/ofw/openfirm.h>
52#include <dev/ofw/ofw_bus.h>
53#include <dev/ofw/ofw_bus_subr.h>
54
55#include <machine/bus.h>
56#include <machine/cpu.h>
57#include <machine/intr.h>
58
59#include <arm/altera/socfpga/socfpga_common.h>
60
61/* FPGA Manager Module Registers */
62#define	FPGAMGR_STAT		0x0	/* Status Register */
63#define	 STAT_MSEL_MASK		0x1f
64#define	 STAT_MSEL_SHIFT	3
65#define	 STAT_MODE_SHIFT	0
66#define	 STAT_MODE_MASK		0x7
67#define	FPGAMGR_CTRL		0x4	/* Control Register */
68#define	 CTRL_AXICFGEN		(1 << 8)
69#define	 CTRL_CDRATIO_MASK	0x3
70#define	 CTRL_CDRATIO_SHIFT	6
71#define	 CTRL_CFGWDTH_MASK	1
72#define	 CTRL_CFGWDTH_SHIFT	9
73#define	 CTRL_NCONFIGPULL	(1 << 2)
74#define	 CTRL_NCE		(1 << 1)
75#define	 CTRL_EN		(1 << 0)
76#define	FPGAMGR_DCLKCNT		0x8	/* DCLK Count Register */
77#define	FPGAMGR_DCLKSTAT	0xC	/* DCLK Status Register */
78#define	FPGAMGR_GPO		0x10	/* General-Purpose Output Register */
79#define	FPGAMGR_GPI		0x14	/* General-Purpose Input Register */
80#define	FPGAMGR_MISCI		0x18	/* Miscellaneous Input Register */
81
82/* Configuration Monitor (MON) Registers */
83#define	GPIO_INTEN		0x830	/* Interrupt Enable Register */
84#define	GPIO_INTMASK		0x834	/* Interrupt Mask Register */
85#define	GPIO_INTTYPE_LEVEL	0x838	/* Interrupt Level Register */
86#define	GPIO_INT_POLARITY	0x83C	/* Interrupt Polarity Register */
87#define	GPIO_INTSTATUS		0x840	/* Interrupt Status Register */
88#define	GPIO_RAW_INTSTATUS	0x844	/* Raw Interrupt Status Register */
89#define	GPIO_PORTA_EOI		0x84C	/* Clear Interrupt Register */
90#define	 PORTA_EOI_NS		(1 << 0)
91#define	GPIO_EXT_PORTA		0x850	/* External Port A Register */
92#define	 EXT_PORTA_CDP		(1 << 10) /* Configuration done */
93#define	GPIO_LS_SYNC		0x860	/* Synchronization Level Register */
94#define	GPIO_VER_ID_CODE	0x86C	/* GPIO Version Register */
95#define	GPIO_CONFIG_REG2	0x870	/* Configuration Register 2 */
96#define	GPIO_CONFIG_REG1	0x874	/* Configuration Register 1 */
97
98#define	MSEL_PP16_FAST_NOAES_NODC	0x0
99#define	MSEL_PP16_FAST_AES_NODC		0x1
100#define	MSEL_PP16_FAST_AESOPT_DC	0x2
101#define	MSEL_PP16_SLOW_NOAES_NODC	0x4
102#define	MSEL_PP16_SLOW_AES_NODC		0x5
103#define	MSEL_PP16_SLOW_AESOPT_DC	0x6
104#define	MSEL_PP32_FAST_NOAES_NODC	0x8
105#define	MSEL_PP32_FAST_AES_NODC		0x9
106#define	MSEL_PP32_FAST_AESOPT_DC	0xa
107#define	MSEL_PP32_SLOW_NOAES_NODC	0xc
108#define	MSEL_PP32_SLOW_AES_NODC		0xd
109#define	MSEL_PP32_SLOW_AESOPT_DC	0xe
110
111#define	CFGWDTH_16	0
112#define	CFGWDTH_32	1
113
114#define	CDRATIO_1	0
115#define	CDRATIO_2	1
116#define	CDRATIO_4	2
117#define	CDRATIO_8	3
118
119#define	FPGAMGR_MODE_POWEROFF	0x0
120#define	FPGAMGR_MODE_RESET	0x1
121#define	FPGAMGR_MODE_CONFIG	0x2
122#define	FPGAMGR_MODE_INIT	0x3
123#define	FPGAMGR_MODE_USER	0x4
124
125struct cfgmgr_mode {
126	int msel;
127	int cfgwdth;
128	int cdratio;
129};
130
131static struct cfgmgr_mode cfgmgr_modes[] = {
132	{ MSEL_PP16_FAST_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
133	{ MSEL_PP16_FAST_AES_NODC,   CFGWDTH_16, CDRATIO_2 },
134	{ MSEL_PP16_FAST_AESOPT_DC,  CFGWDTH_16, CDRATIO_4 },
135	{ MSEL_PP16_SLOW_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
136	{ MSEL_PP16_SLOW_AES_NODC,   CFGWDTH_16, CDRATIO_2 },
137	{ MSEL_PP16_SLOW_AESOPT_DC,  CFGWDTH_16, CDRATIO_4 },
138	{ MSEL_PP32_FAST_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
139	{ MSEL_PP32_FAST_AES_NODC,   CFGWDTH_32, CDRATIO_4 },
140	{ MSEL_PP32_FAST_AESOPT_DC,  CFGWDTH_32, CDRATIO_8 },
141	{ MSEL_PP32_SLOW_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
142	{ MSEL_PP32_SLOW_AES_NODC,   CFGWDTH_32, CDRATIO_4 },
143	{ MSEL_PP32_SLOW_AESOPT_DC,  CFGWDTH_32, CDRATIO_8 },
144	{ -1, -1, -1 },
145};
146
147struct fpgamgr_softc {
148	struct resource		*res[3];
149	bus_space_tag_t		bst_data;
150	bus_space_handle_t	bsh_data;
151	struct cdev		*mgr_cdev;
152	device_t		dev;
153};
154
155static struct resource_spec fpgamgr_spec[] = {
156	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
157	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
158	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
159	{ -1, 0 }
160};
161
162static int
163fpgamgr_state_get(struct fpgamgr_softc *sc)
164{
165	int reg;
166
167	reg = READ4(sc, FPGAMGR_STAT);
168	reg >>= STAT_MODE_SHIFT;
169	reg &= STAT_MODE_MASK;
170
171	return reg;
172}
173
174static int
175fpgamgr_state_wait(struct fpgamgr_softc *sc, int state)
176{
177	int tout;
178
179	tout = 1000;
180	while (tout > 0) {
181		if (fpgamgr_state_get(sc) == state)
182			break;
183		tout--;
184		DELAY(10);
185	}
186	if (tout == 0) {
187		return (1);
188	}
189
190	return (0);
191}
192
193static int
194fpga_open(struct cdev *dev, int flags __unused,
195    int fmt __unused, struct thread *td __unused)
196{
197	struct fpgamgr_softc *sc;
198	struct cfgmgr_mode *mode;
199	int msel;
200	int reg;
201	int i;
202
203	sc = dev->si_drv1;
204
205	msel = READ4(sc, FPGAMGR_STAT);
206	msel >>= STAT_MSEL_SHIFT;
207	msel &= STAT_MSEL_MASK;
208
209	mode = NULL;
210	for (i = 0; cfgmgr_modes[i].msel != -1; i++) {
211		if (msel == cfgmgr_modes[i].msel) {
212			mode = &cfgmgr_modes[i];
213			break;
214		}
215	}
216	if (mode == NULL) {
217		device_printf(sc->dev, "Can't configure: unknown mode\n");
218		return (ENXIO);
219	}
220
221	reg = READ4(sc, FPGAMGR_CTRL);
222	reg &= ~(CTRL_CDRATIO_MASK << CTRL_CDRATIO_SHIFT);
223	reg |= (mode->cdratio << CTRL_CDRATIO_SHIFT);
224	reg &= ~(CTRL_CFGWDTH_MASK << CTRL_CFGWDTH_SHIFT);
225	reg |= (mode->cfgwdth << CTRL_CFGWDTH_SHIFT);
226	reg &= ~(CTRL_NCE);
227	WRITE4(sc, FPGAMGR_CTRL, reg);
228
229	/* Enable configuration */
230	reg = READ4(sc, FPGAMGR_CTRL);
231	reg |= (CTRL_EN);
232	WRITE4(sc, FPGAMGR_CTRL, reg);
233
234	/* Reset FPGA */
235	reg = READ4(sc, FPGAMGR_CTRL);
236	reg |= (CTRL_NCONFIGPULL);
237	WRITE4(sc, FPGAMGR_CTRL, reg);
238
239	/* Wait reset state */
240	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_RESET)) {
241		device_printf(sc->dev, "Can't get RESET state\n");
242		return (ENXIO);
243	}
244
245	/* Release from reset */
246	reg = READ4(sc, FPGAMGR_CTRL);
247	reg &= ~(CTRL_NCONFIGPULL);
248	WRITE4(sc, FPGAMGR_CTRL, reg);
249
250	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_CONFIG)) {
251		device_printf(sc->dev, "Can't get CONFIG state\n");
252		return (ENXIO);
253	}
254
255	/* Clear nSTATUS edge interrupt */
256	WRITE4(sc, GPIO_PORTA_EOI, PORTA_EOI_NS);
257
258	/* Enter configuration state */
259	reg = READ4(sc, FPGAMGR_CTRL);
260	reg |= (CTRL_AXICFGEN);
261	WRITE4(sc, FPGAMGR_CTRL, reg);
262
263	return (0);
264}
265
266static int
267fpga_wait_dclk_pulses(struct fpgamgr_softc *sc, int npulses)
268{
269	int tout;
270
271	/* Clear done bit, if any */
272	if (READ4(sc, FPGAMGR_DCLKSTAT) != 0)
273		WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
274
275	/* Request DCLK pulses */
276	WRITE4(sc, FPGAMGR_DCLKCNT, npulses);
277
278	/* Wait finish */
279	tout = 1000;
280	while (tout > 0) {
281		if (READ4(sc, FPGAMGR_DCLKSTAT) == 1) {
282			WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
283			break;
284		}
285		tout--;
286		DELAY(10);
287	}
288	if (tout == 0) {
289		return (1);
290	}
291
292	return (0);
293}
294
295static int
296fpga_close(struct cdev *dev, int flags __unused,
297    int fmt __unused, struct thread *td __unused)
298{
299	struct fpgamgr_softc *sc;
300	int reg;
301
302	sc = dev->si_drv1;
303
304	reg = READ4(sc, GPIO_EXT_PORTA);
305	if ((reg & EXT_PORTA_CDP) == 0) {
306		device_printf(sc->dev, "Err: configuration failed\n");
307		return (ENXIO);
308	}
309
310	/* Exit configuration state */
311	reg = READ4(sc, FPGAMGR_CTRL);
312	reg &= ~(CTRL_AXICFGEN);
313	WRITE4(sc, FPGAMGR_CTRL, reg);
314
315	/* Wait dclk pulses */
316	if (fpga_wait_dclk_pulses(sc, 4)) {
317		device_printf(sc->dev, "Can't proceed 4 dclk pulses\n");
318		return (ENXIO);
319	}
320
321	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_USER)) {
322		device_printf(sc->dev, "Can't get USER mode\n");
323		return (ENXIO);
324	}
325
326	/* Disable configuration */
327	reg = READ4(sc, FPGAMGR_CTRL);
328	reg &= ~(CTRL_EN);
329	WRITE4(sc, FPGAMGR_CTRL, reg);
330
331	return (0);
332}
333
334static int
335fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
336{
337	struct fpgamgr_softc *sc;
338	int buffer;
339
340	sc = dev->si_drv1;
341
342	/*
343	 * Device supports 4-byte copy only.
344	 * TODO: add padding for <4 bytes.
345	 */
346
347	while (uio->uio_resid > 0) {
348		uiomove(&buffer, 4, uio);
349		bus_space_write_4(sc->bst_data, sc->bsh_data,
350		    0x0, buffer);
351	}
352
353	return (0);
354}
355
356static int
357fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
358    struct thread *td)
359{
360
361	return (0);
362}
363
364static struct cdevsw fpga_cdevsw = {
365	.d_version =	D_VERSION,
366	.d_open =	fpga_open,
367	.d_close =	fpga_close,
368	.d_write =	fpga_write,
369	.d_ioctl =	fpga_ioctl,
370	.d_name =	"FPGA Manager",
371};
372
373static int
374fpgamgr_probe(device_t dev)
375{
376
377	if (!ofw_bus_status_okay(dev))
378		return (ENXIO);
379
380	if (!ofw_bus_is_compatible(dev, "altr,socfpga-fpga-mgr"))
381		return (ENXIO);
382
383	device_set_desc(dev, "FPGA Manager");
384	return (BUS_PROBE_DEFAULT);
385}
386
387static int
388fpgamgr_attach(device_t dev)
389{
390	struct fpgamgr_softc *sc;
391
392	sc = device_get_softc(dev);
393	sc->dev = dev;
394
395	if (bus_alloc_resources(dev, fpgamgr_spec, sc->res)) {
396		device_printf(dev, "could not allocate resources\n");
397		return (ENXIO);
398	}
399
400	/* Memory interface */
401	sc->bst_data = rman_get_bustag(sc->res[1]);
402	sc->bsh_data = rman_get_bushandle(sc->res[1]);
403
404	sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
405	    0600, "fpga%d", device_get_unit(sc->dev));
406
407	if (sc->mgr_cdev == NULL) {
408		device_printf(dev, "Failed to create character device.\n");
409		return (ENXIO);
410	}
411
412	sc->mgr_cdev->si_drv1 = sc;
413
414	return (0);
415}
416
417static device_method_t fpgamgr_methods[] = {
418	DEVMETHOD(device_probe,		fpgamgr_probe),
419	DEVMETHOD(device_attach,	fpgamgr_attach),
420	{ 0, 0 }
421};
422
423static driver_t fpgamgr_driver = {
424	"fpgamgr",
425	fpgamgr_methods,
426	sizeof(struct fpgamgr_softc),
427};
428
429static devclass_t fpgamgr_devclass;
430
431DRIVER_MODULE(fpgamgr, simplebus, fpgamgr_driver, fpgamgr_devclass, 0, 0);
432