xref: /freebsd/sys/arm/altera/socfpga/socfpga_manager.c (revision fdafd315ad0d0f28a11b9fb4476a9ab059c62b92)
134a01893SRuslan Bukin /*-
234a01893SRuslan Bukin  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
334a01893SRuslan Bukin  * All rights reserved.
434a01893SRuslan Bukin  *
534a01893SRuslan Bukin  * This software was developed by SRI International and the University of
634a01893SRuslan Bukin  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
734a01893SRuslan Bukin  * ("CTSRD"), as part of the DARPA CRASH research programme.
834a01893SRuslan Bukin  *
934a01893SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
1034a01893SRuslan Bukin  * modification, are permitted provided that the following conditions
1134a01893SRuslan Bukin  * are met:
1234a01893SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
1334a01893SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
1434a01893SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
1534a01893SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
1634a01893SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
1734a01893SRuslan Bukin  *
1834a01893SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1934a01893SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2034a01893SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2134a01893SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2234a01893SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2334a01893SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2434a01893SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2534a01893SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2634a01893SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2734a01893SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2834a01893SRuslan Bukin  * SUCH DAMAGE.
2934a01893SRuslan Bukin  */
3034a01893SRuslan Bukin 
3134a01893SRuslan Bukin /*
3234a01893SRuslan Bukin  * Altera FPGA Manager.
3334a01893SRuslan Bukin  * Chapter 4, Cyclone V Device Handbook (CV-5V2 2014.07.22)
3434a01893SRuslan Bukin  */
3534a01893SRuslan Bukin 
3634a01893SRuslan Bukin #include <sys/param.h>
3734a01893SRuslan Bukin #include <sys/systm.h>
3834a01893SRuslan Bukin #include <sys/bus.h>
3934a01893SRuslan Bukin #include <sys/kernel.h>
4034a01893SRuslan Bukin #include <sys/module.h>
4134a01893SRuslan Bukin #include <sys/malloc.h>
4234a01893SRuslan Bukin #include <sys/rman.h>
4334a01893SRuslan Bukin #include <sys/timeet.h>
4434a01893SRuslan Bukin #include <sys/timetc.h>
4534a01893SRuslan Bukin #include <sys/conf.h>
4634a01893SRuslan Bukin #include <sys/uio.h>
4734a01893SRuslan Bukin 
4834a01893SRuslan Bukin #include <dev/ofw/openfirm.h>
4934a01893SRuslan Bukin #include <dev/ofw/ofw_bus.h>
5034a01893SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
5134a01893SRuslan Bukin 
5234a01893SRuslan Bukin #include <machine/bus.h>
5334a01893SRuslan Bukin #include <machine/cpu.h>
5434a01893SRuslan Bukin #include <machine/intr.h>
5534a01893SRuslan Bukin 
5634a01893SRuslan Bukin #include <arm/altera/socfpga/socfpga_common.h>
5734a01893SRuslan Bukin 
5834a01893SRuslan Bukin /* FPGA Manager Module Registers */
5934a01893SRuslan Bukin #define	FPGAMGR_STAT		0x0	/* Status Register */
6034a01893SRuslan Bukin #define	 STAT_MSEL_MASK		0x1f
6134a01893SRuslan Bukin #define	 STAT_MSEL_SHIFT	3
6234a01893SRuslan Bukin #define	 STAT_MODE_SHIFT	0
6334a01893SRuslan Bukin #define	 STAT_MODE_MASK		0x7
6434a01893SRuslan Bukin #define	FPGAMGR_CTRL		0x4	/* Control Register */
6534a01893SRuslan Bukin #define	 CTRL_AXICFGEN		(1 << 8)
6634a01893SRuslan Bukin #define	 CTRL_CDRATIO_MASK	0x3
6734a01893SRuslan Bukin #define	 CTRL_CDRATIO_SHIFT	6
6834a01893SRuslan Bukin #define	 CTRL_CFGWDTH_MASK	1
6934a01893SRuslan Bukin #define	 CTRL_CFGWDTH_SHIFT	9
7034a01893SRuslan Bukin #define	 CTRL_NCONFIGPULL	(1 << 2)
7134a01893SRuslan Bukin #define	 CTRL_NCE		(1 << 1)
7234a01893SRuslan Bukin #define	 CTRL_EN		(1 << 0)
7334a01893SRuslan Bukin #define	FPGAMGR_DCLKCNT		0x8	/* DCLK Count Register */
7434a01893SRuslan Bukin #define	FPGAMGR_DCLKSTAT	0xC	/* DCLK Status Register */
7534a01893SRuslan Bukin #define	FPGAMGR_GPO		0x10	/* General-Purpose Output Register */
7634a01893SRuslan Bukin #define	FPGAMGR_GPI		0x14	/* General-Purpose Input Register */
7734a01893SRuslan Bukin #define	FPGAMGR_MISCI		0x18	/* Miscellaneous Input Register */
7834a01893SRuslan Bukin 
7934a01893SRuslan Bukin /* Configuration Monitor (MON) Registers */
8034a01893SRuslan Bukin #define	GPIO_INTEN		0x830	/* Interrupt Enable Register */
8134a01893SRuslan Bukin #define	GPIO_INTMASK		0x834	/* Interrupt Mask Register */
8234a01893SRuslan Bukin #define	GPIO_INTTYPE_LEVEL	0x838	/* Interrupt Level Register */
8334a01893SRuslan Bukin #define	GPIO_INT_POLARITY	0x83C	/* Interrupt Polarity Register */
8434a01893SRuslan Bukin #define	GPIO_INTSTATUS		0x840	/* Interrupt Status Register */
8534a01893SRuslan Bukin #define	GPIO_RAW_INTSTATUS	0x844	/* Raw Interrupt Status Register */
8634a01893SRuslan Bukin #define	GPIO_PORTA_EOI		0x84C	/* Clear Interrupt Register */
8734a01893SRuslan Bukin #define	 PORTA_EOI_NS		(1 << 0)
8834a01893SRuslan Bukin #define	GPIO_EXT_PORTA		0x850	/* External Port A Register */
898aabb971SRuslan Bukin #define	 EXT_PORTA_CDP		(1 << 10) /* Configuration done */
9034a01893SRuslan Bukin #define	GPIO_LS_SYNC		0x860	/* Synchronization Level Register */
9134a01893SRuslan Bukin #define	GPIO_VER_ID_CODE	0x86C	/* GPIO Version Register */
9234a01893SRuslan Bukin #define	GPIO_CONFIG_REG2	0x870	/* Configuration Register 2 */
9334a01893SRuslan Bukin #define	GPIO_CONFIG_REG1	0x874	/* Configuration Register 1 */
9434a01893SRuslan Bukin 
9534a01893SRuslan Bukin #define	MSEL_PP16_FAST_NOAES_NODC	0x0
9634a01893SRuslan Bukin #define	MSEL_PP16_FAST_AES_NODC		0x1
9734a01893SRuslan Bukin #define	MSEL_PP16_FAST_AESOPT_DC	0x2
9834a01893SRuslan Bukin #define	MSEL_PP16_SLOW_NOAES_NODC	0x4
9934a01893SRuslan Bukin #define	MSEL_PP16_SLOW_AES_NODC		0x5
10034a01893SRuslan Bukin #define	MSEL_PP16_SLOW_AESOPT_DC	0x6
10134a01893SRuslan Bukin #define	MSEL_PP32_FAST_NOAES_NODC	0x8
10234a01893SRuslan Bukin #define	MSEL_PP32_FAST_AES_NODC		0x9
10334a01893SRuslan Bukin #define	MSEL_PP32_FAST_AESOPT_DC	0xa
10434a01893SRuslan Bukin #define	MSEL_PP32_SLOW_NOAES_NODC	0xc
10534a01893SRuslan Bukin #define	MSEL_PP32_SLOW_AES_NODC		0xd
10634a01893SRuslan Bukin #define	MSEL_PP32_SLOW_AESOPT_DC	0xe
10734a01893SRuslan Bukin 
10834a01893SRuslan Bukin #define	CFGWDTH_16	0
10934a01893SRuslan Bukin #define	CFGWDTH_32	1
11034a01893SRuslan Bukin 
11134a01893SRuslan Bukin #define	CDRATIO_1	0
11234a01893SRuslan Bukin #define	CDRATIO_2	1
11334a01893SRuslan Bukin #define	CDRATIO_4	2
11434a01893SRuslan Bukin #define	CDRATIO_8	3
11534a01893SRuslan Bukin 
11634a01893SRuslan Bukin #define	FPGAMGR_MODE_POWEROFF	0x0
11734a01893SRuslan Bukin #define	FPGAMGR_MODE_RESET	0x1
11834a01893SRuslan Bukin #define	FPGAMGR_MODE_CONFIG	0x2
11934a01893SRuslan Bukin #define	FPGAMGR_MODE_INIT	0x3
12034a01893SRuslan Bukin #define	FPGAMGR_MODE_USER	0x4
12134a01893SRuslan Bukin 
12234a01893SRuslan Bukin struct cfgmgr_mode {
12334a01893SRuslan Bukin 	int msel;
12434a01893SRuslan Bukin 	int cfgwdth;
12534a01893SRuslan Bukin 	int cdratio;
12634a01893SRuslan Bukin };
12734a01893SRuslan Bukin 
12834a01893SRuslan Bukin static struct cfgmgr_mode cfgmgr_modes[] = {
12934a01893SRuslan Bukin 	{ MSEL_PP16_FAST_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
13034a01893SRuslan Bukin 	{ MSEL_PP16_FAST_AES_NODC,   CFGWDTH_16, CDRATIO_2 },
13134a01893SRuslan Bukin 	{ MSEL_PP16_FAST_AESOPT_DC,  CFGWDTH_16, CDRATIO_4 },
13234a01893SRuslan Bukin 	{ MSEL_PP16_SLOW_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
13334a01893SRuslan Bukin 	{ MSEL_PP16_SLOW_AES_NODC,   CFGWDTH_16, CDRATIO_2 },
13434a01893SRuslan Bukin 	{ MSEL_PP16_SLOW_AESOPT_DC,  CFGWDTH_16, CDRATIO_4 },
13534a01893SRuslan Bukin 	{ MSEL_PP32_FAST_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
13634a01893SRuslan Bukin 	{ MSEL_PP32_FAST_AES_NODC,   CFGWDTH_32, CDRATIO_4 },
13734a01893SRuslan Bukin 	{ MSEL_PP32_FAST_AESOPT_DC,  CFGWDTH_32, CDRATIO_8 },
13834a01893SRuslan Bukin 	{ MSEL_PP32_SLOW_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
13934a01893SRuslan Bukin 	{ MSEL_PP32_SLOW_AES_NODC,   CFGWDTH_32, CDRATIO_4 },
14034a01893SRuslan Bukin 	{ MSEL_PP32_SLOW_AESOPT_DC,  CFGWDTH_32, CDRATIO_8 },
14134a01893SRuslan Bukin 	{ -1, -1, -1 },
14234a01893SRuslan Bukin };
14334a01893SRuslan Bukin 
14434a01893SRuslan Bukin struct fpgamgr_softc {
14534a01893SRuslan Bukin 	struct resource		*res[3];
14634a01893SRuslan Bukin 	bus_space_tag_t		bst_data;
14734a01893SRuslan Bukin 	bus_space_handle_t	bsh_data;
14834a01893SRuslan Bukin 	struct cdev		*mgr_cdev;
14934a01893SRuslan Bukin 	device_t		dev;
15034a01893SRuslan Bukin };
15134a01893SRuslan Bukin 
15234a01893SRuslan Bukin static struct resource_spec fpgamgr_spec[] = {
15334a01893SRuslan Bukin 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
15434a01893SRuslan Bukin 	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
15534a01893SRuslan Bukin 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
15634a01893SRuslan Bukin 	{ -1, 0 }
15734a01893SRuslan Bukin };
15834a01893SRuslan Bukin 
15934a01893SRuslan Bukin static int
fpgamgr_state_get(struct fpgamgr_softc * sc)16034a01893SRuslan Bukin fpgamgr_state_get(struct fpgamgr_softc *sc)
16134a01893SRuslan Bukin {
16234a01893SRuslan Bukin 	int reg;
16334a01893SRuslan Bukin 
16434a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_STAT);
16534a01893SRuslan Bukin 	reg >>= STAT_MODE_SHIFT;
16634a01893SRuslan Bukin 	reg &= STAT_MODE_MASK;
16734a01893SRuslan Bukin 
16834a01893SRuslan Bukin 	return reg;
16934a01893SRuslan Bukin }
17034a01893SRuslan Bukin 
17134a01893SRuslan Bukin static int
fpgamgr_state_wait(struct fpgamgr_softc * sc,int state)17234a01893SRuslan Bukin fpgamgr_state_wait(struct fpgamgr_softc *sc, int state)
17334a01893SRuslan Bukin {
17434a01893SRuslan Bukin 	int tout;
17534a01893SRuslan Bukin 
17634a01893SRuslan Bukin 	tout = 1000;
17734a01893SRuslan Bukin 	while (tout > 0) {
17834a01893SRuslan Bukin 		if (fpgamgr_state_get(sc) == state)
17934a01893SRuslan Bukin 			break;
18034a01893SRuslan Bukin 		tout--;
18134a01893SRuslan Bukin 		DELAY(10);
18234a01893SRuslan Bukin 	}
18334a01893SRuslan Bukin 	if (tout == 0) {
18434a01893SRuslan Bukin 		return (1);
18534a01893SRuslan Bukin 	}
18634a01893SRuslan Bukin 
18734a01893SRuslan Bukin 	return (0);
18834a01893SRuslan Bukin }
18934a01893SRuslan Bukin 
19034a01893SRuslan Bukin static int
fpga_open(struct cdev * dev,int flags __unused,int fmt __unused,struct thread * td __unused)1918aabb971SRuslan Bukin fpga_open(struct cdev *dev, int flags __unused,
19234a01893SRuslan Bukin     int fmt __unused, struct thread *td __unused)
19334a01893SRuslan Bukin {
19434a01893SRuslan Bukin 	struct fpgamgr_softc *sc;
19534a01893SRuslan Bukin 	struct cfgmgr_mode *mode;
19634a01893SRuslan Bukin 	int msel;
19734a01893SRuslan Bukin 	int reg;
19834a01893SRuslan Bukin 	int i;
19934a01893SRuslan Bukin 
20034a01893SRuslan Bukin 	sc = dev->si_drv1;
20134a01893SRuslan Bukin 
20234a01893SRuslan Bukin 	msel = READ4(sc, FPGAMGR_STAT);
20334a01893SRuslan Bukin 	msel >>= STAT_MSEL_SHIFT;
20434a01893SRuslan Bukin 	msel &= STAT_MSEL_MASK;
20534a01893SRuslan Bukin 
20634a01893SRuslan Bukin 	mode = NULL;
20734a01893SRuslan Bukin 	for (i = 0; cfgmgr_modes[i].msel != -1; i++) {
20834a01893SRuslan Bukin 		if (msel == cfgmgr_modes[i].msel) {
20934a01893SRuslan Bukin 			mode = &cfgmgr_modes[i];
21034a01893SRuslan Bukin 			break;
21134a01893SRuslan Bukin 		}
21234a01893SRuslan Bukin 	}
21334a01893SRuslan Bukin 	if (mode == NULL) {
21434a01893SRuslan Bukin 		device_printf(sc->dev, "Can't configure: unknown mode\n");
21534a01893SRuslan Bukin 		return (ENXIO);
21634a01893SRuslan Bukin 	}
21734a01893SRuslan Bukin 
21834a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
21934a01893SRuslan Bukin 	reg &= ~(CTRL_CDRATIO_MASK << CTRL_CDRATIO_SHIFT);
22034a01893SRuslan Bukin 	reg |= (mode->cdratio << CTRL_CDRATIO_SHIFT);
22134a01893SRuslan Bukin 	reg &= ~(CTRL_CFGWDTH_MASK << CTRL_CFGWDTH_SHIFT);
22234a01893SRuslan Bukin 	reg |= (mode->cfgwdth << CTRL_CFGWDTH_SHIFT);
22334a01893SRuslan Bukin 	reg &= ~(CTRL_NCE);
22434a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
22534a01893SRuslan Bukin 
22634a01893SRuslan Bukin 	/* Enable configuration */
22734a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
22834a01893SRuslan Bukin 	reg |= (CTRL_EN);
22934a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
23034a01893SRuslan Bukin 
23134a01893SRuslan Bukin 	/* Reset FPGA */
23234a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
23334a01893SRuslan Bukin 	reg |= (CTRL_NCONFIGPULL);
23434a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
23534a01893SRuslan Bukin 
23634a01893SRuslan Bukin 	/* Wait reset state */
23734a01893SRuslan Bukin 	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_RESET)) {
23834a01893SRuslan Bukin 		device_printf(sc->dev, "Can't get RESET state\n");
23934a01893SRuslan Bukin 		return (ENXIO);
24034a01893SRuslan Bukin 	}
24134a01893SRuslan Bukin 
24234a01893SRuslan Bukin 	/* Release from reset */
24334a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
24434a01893SRuslan Bukin 	reg &= ~(CTRL_NCONFIGPULL);
24534a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
24634a01893SRuslan Bukin 
24734a01893SRuslan Bukin 	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_CONFIG)) {
24834a01893SRuslan Bukin 		device_printf(sc->dev, "Can't get CONFIG state\n");
24934a01893SRuslan Bukin 		return (ENXIO);
25034a01893SRuslan Bukin 	}
25134a01893SRuslan Bukin 
25234a01893SRuslan Bukin 	/* Clear nSTATUS edge interrupt */
25334a01893SRuslan Bukin 	WRITE4(sc, GPIO_PORTA_EOI, PORTA_EOI_NS);
25434a01893SRuslan Bukin 
25534a01893SRuslan Bukin 	/* Enter configuration state */
25634a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
25734a01893SRuslan Bukin 	reg |= (CTRL_AXICFGEN);
25834a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
25934a01893SRuslan Bukin 
26034a01893SRuslan Bukin 	return (0);
26134a01893SRuslan Bukin }
26234a01893SRuslan Bukin 
26334a01893SRuslan Bukin static int
fpga_wait_dclk_pulses(struct fpgamgr_softc * sc,int npulses)26434a01893SRuslan Bukin fpga_wait_dclk_pulses(struct fpgamgr_softc *sc, int npulses)
26534a01893SRuslan Bukin {
26634a01893SRuslan Bukin 	int tout;
26734a01893SRuslan Bukin 
26834a01893SRuslan Bukin 	/* Clear done bit, if any */
26934a01893SRuslan Bukin 	if (READ4(sc, FPGAMGR_DCLKSTAT) != 0)
27034a01893SRuslan Bukin 		WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
27134a01893SRuslan Bukin 
27234a01893SRuslan Bukin 	/* Request DCLK pulses */
27334a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_DCLKCNT, npulses);
27434a01893SRuslan Bukin 
27534a01893SRuslan Bukin 	/* Wait finish */
27634a01893SRuslan Bukin 	tout = 1000;
27734a01893SRuslan Bukin 	while (tout > 0) {
27834a01893SRuslan Bukin 		if (READ4(sc, FPGAMGR_DCLKSTAT) == 1) {
27934a01893SRuslan Bukin 			WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
28034a01893SRuslan Bukin 			break;
28134a01893SRuslan Bukin 		}
28234a01893SRuslan Bukin 		tout--;
28334a01893SRuslan Bukin 		DELAY(10);
28434a01893SRuslan Bukin 	}
28534a01893SRuslan Bukin 	if (tout == 0) {
28634a01893SRuslan Bukin 		return (1);
28734a01893SRuslan Bukin 	}
28834a01893SRuslan Bukin 
28934a01893SRuslan Bukin 	return (0);
29034a01893SRuslan Bukin }
29134a01893SRuslan Bukin 
29234a01893SRuslan Bukin static int
fpga_close(struct cdev * dev,int flags __unused,int fmt __unused,struct thread * td __unused)2938aabb971SRuslan Bukin fpga_close(struct cdev *dev, int flags __unused,
29434a01893SRuslan Bukin     int fmt __unused, struct thread *td __unused)
29534a01893SRuslan Bukin {
29634a01893SRuslan Bukin 	struct fpgamgr_softc *sc;
29734a01893SRuslan Bukin 	int reg;
29834a01893SRuslan Bukin 
29934a01893SRuslan Bukin 	sc = dev->si_drv1;
30034a01893SRuslan Bukin 
30134a01893SRuslan Bukin 	reg = READ4(sc, GPIO_EXT_PORTA);
3028aabb971SRuslan Bukin 	if ((reg & EXT_PORTA_CDP) == 0) {
30334a01893SRuslan Bukin 		device_printf(sc->dev, "Err: configuration failed\n");
30434a01893SRuslan Bukin 		return (ENXIO);
30534a01893SRuslan Bukin 	}
30634a01893SRuslan Bukin 
30734a01893SRuslan Bukin 	/* Exit configuration state */
30834a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
30934a01893SRuslan Bukin 	reg &= ~(CTRL_AXICFGEN);
31034a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
31134a01893SRuslan Bukin 
31234a01893SRuslan Bukin 	/* Wait dclk pulses */
31334a01893SRuslan Bukin 	if (fpga_wait_dclk_pulses(sc, 4)) {
31434a01893SRuslan Bukin 		device_printf(sc->dev, "Can't proceed 4 dclk pulses\n");
31534a01893SRuslan Bukin 		return (ENXIO);
31634a01893SRuslan Bukin 	}
31734a01893SRuslan Bukin 
31834a01893SRuslan Bukin 	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_USER)) {
31934a01893SRuslan Bukin 		device_printf(sc->dev, "Can't get USER mode\n");
32034a01893SRuslan Bukin 		return (ENXIO);
32134a01893SRuslan Bukin 	}
32234a01893SRuslan Bukin 
32334a01893SRuslan Bukin 	/* Disable configuration */
32434a01893SRuslan Bukin 	reg = READ4(sc, FPGAMGR_CTRL);
32534a01893SRuslan Bukin 	reg &= ~(CTRL_EN);
32634a01893SRuslan Bukin 	WRITE4(sc, FPGAMGR_CTRL, reg);
32734a01893SRuslan Bukin 
32834a01893SRuslan Bukin 	return (0);
32934a01893SRuslan Bukin }
33034a01893SRuslan Bukin 
33134a01893SRuslan Bukin static int
fpga_write(struct cdev * dev,struct uio * uio,int ioflag)33234a01893SRuslan Bukin fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
33334a01893SRuslan Bukin {
33434a01893SRuslan Bukin 	struct fpgamgr_softc *sc;
33534a01893SRuslan Bukin 	int buffer;
33634a01893SRuslan Bukin 
33734a01893SRuslan Bukin 	sc = dev->si_drv1;
33834a01893SRuslan Bukin 
33934a01893SRuslan Bukin 	/*
34034a01893SRuslan Bukin 	 * Device supports 4-byte copy only.
34134a01893SRuslan Bukin 	 * TODO: add padding for <4 bytes.
34234a01893SRuslan Bukin 	 */
34334a01893SRuslan Bukin 
34434a01893SRuslan Bukin 	while (uio->uio_resid > 0) {
34534a01893SRuslan Bukin 		uiomove(&buffer, 4, uio);
34634a01893SRuslan Bukin 		bus_space_write_4(sc->bst_data, sc->bsh_data,
34734a01893SRuslan Bukin 		    0x0, buffer);
34834a01893SRuslan Bukin 	}
34934a01893SRuslan Bukin 
35034a01893SRuslan Bukin 	return (0);
35134a01893SRuslan Bukin }
35234a01893SRuslan Bukin 
35334a01893SRuslan Bukin static int
fpga_ioctl(struct cdev * dev,u_long cmd,caddr_t addr,int flags,struct thread * td)35434a01893SRuslan Bukin fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
35534a01893SRuslan Bukin     struct thread *td)
35634a01893SRuslan Bukin {
35734a01893SRuslan Bukin 
35834a01893SRuslan Bukin 	return (0);
35934a01893SRuslan Bukin }
36034a01893SRuslan Bukin 
36134a01893SRuslan Bukin static struct cdevsw fpga_cdevsw = {
36234a01893SRuslan Bukin 	.d_version =	D_VERSION,
36334a01893SRuslan Bukin 	.d_open =	fpga_open,
36434a01893SRuslan Bukin 	.d_close =	fpga_close,
36534a01893SRuslan Bukin 	.d_write =	fpga_write,
36634a01893SRuslan Bukin 	.d_ioctl =	fpga_ioctl,
36734a01893SRuslan Bukin 	.d_name =	"FPGA Manager",
36834a01893SRuslan Bukin };
36934a01893SRuslan Bukin 
37034a01893SRuslan Bukin static int
fpgamgr_probe(device_t dev)3718aabb971SRuslan Bukin fpgamgr_probe(device_t dev)
3728aabb971SRuslan Bukin {
3738aabb971SRuslan Bukin 
3748aabb971SRuslan Bukin 	if (!ofw_bus_status_okay(dev))
3758aabb971SRuslan Bukin 		return (ENXIO);
3768aabb971SRuslan Bukin 
37742815783SRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "altr,socfpga-fpga-mgr"))
3788aabb971SRuslan Bukin 		return (ENXIO);
3798aabb971SRuslan Bukin 
3808aabb971SRuslan Bukin 	device_set_desc(dev, "FPGA Manager");
3818aabb971SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
3828aabb971SRuslan Bukin }
3838aabb971SRuslan Bukin 
3848aabb971SRuslan Bukin static int
fpgamgr_attach(device_t dev)38534a01893SRuslan Bukin fpgamgr_attach(device_t dev)
38634a01893SRuslan Bukin {
38734a01893SRuslan Bukin 	struct fpgamgr_softc *sc;
38834a01893SRuslan Bukin 
38934a01893SRuslan Bukin 	sc = device_get_softc(dev);
39034a01893SRuslan Bukin 	sc->dev = dev;
39134a01893SRuslan Bukin 
39234a01893SRuslan Bukin 	if (bus_alloc_resources(dev, fpgamgr_spec, sc->res)) {
39334a01893SRuslan Bukin 		device_printf(dev, "could not allocate resources\n");
39434a01893SRuslan Bukin 		return (ENXIO);
39534a01893SRuslan Bukin 	}
39634a01893SRuslan Bukin 
39734a01893SRuslan Bukin 	/* Memory interface */
39834a01893SRuslan Bukin 	sc->bst_data = rman_get_bustag(sc->res[1]);
39934a01893SRuslan Bukin 	sc->bsh_data = rman_get_bushandle(sc->res[1]);
40034a01893SRuslan Bukin 
40134a01893SRuslan Bukin 	sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
40234a01893SRuslan Bukin 	    0600, "fpga%d", device_get_unit(sc->dev));
40334a01893SRuslan Bukin 
40434a01893SRuslan Bukin 	if (sc->mgr_cdev == NULL) {
40534a01893SRuslan Bukin 		device_printf(dev, "Failed to create character device.\n");
40634a01893SRuslan Bukin 		return (ENXIO);
40734a01893SRuslan Bukin 	}
40834a01893SRuslan Bukin 
40934a01893SRuslan Bukin 	sc->mgr_cdev->si_drv1 = sc;
41034a01893SRuslan Bukin 
41134a01893SRuslan Bukin 	return (0);
41234a01893SRuslan Bukin }
41334a01893SRuslan Bukin 
41434a01893SRuslan Bukin static device_method_t fpgamgr_methods[] = {
41534a01893SRuslan Bukin 	DEVMETHOD(device_probe,		fpgamgr_probe),
41634a01893SRuslan Bukin 	DEVMETHOD(device_attach,	fpgamgr_attach),
41734a01893SRuslan Bukin 	{ 0, 0 }
41834a01893SRuslan Bukin };
41934a01893SRuslan Bukin 
42034a01893SRuslan Bukin static driver_t fpgamgr_driver = {
42134a01893SRuslan Bukin 	"fpgamgr",
42234a01893SRuslan Bukin 	fpgamgr_methods,
42334a01893SRuslan Bukin 	sizeof(struct fpgamgr_softc),
42434a01893SRuslan Bukin };
42534a01893SRuslan Bukin 
426*75996aa1SJohn Baldwin DRIVER_MODULE(fpgamgr, simplebus, fpgamgr_driver, 0, 0);
427