svn commit: r271186 - in head/sys: arm/altera/socfpga boot/fdt/dts/arm

Andrew Turner andrew at fubar.geek.nz
Sat Sep 6 10:45:31 UTC 2014


On Sat, 6 Sep 2014 08:48:58 +0000 (UTC)
Ruslan Bukin <br at FreeBSD.org> wrote:

> Author: br
> Date: Sat Sep  6 08:48:57 2014
> New Revision: 271186
> URL: http://svnweb.freebsd.org/changeset/base/271186
> 
> Log:
>   Add FPGA Manager driver. This driver allows to program FPGA core
>   from FreeBSD userspace running on ARM core.

A few comments below.

Andrew

...

> Added: head/sys/arm/altera/socfpga/socfpga_common.h
> ==============================================================================
> --- /dev/null	00:00:00 1970	(empty, because file is
> newly added) +++ head/sys/arm/altera/socfpga/socfpga_common.h
> Sat Sep  6 08:48:57 2014	(r271186) @@ -0,0 +1,44 @@
> +/*-
> + * Copyright (c) 2014 Ruslan Bukin <br at bsdpad.com>
> + * All rights reserved.
> + *
> + * This software was developed by SRI International and the
> University of
> + * Cambridge Computer Laboratory under DARPA/AFRL contract
> (FA8750-10-C-0237)
> + * ("CTSRD"), as part of the DARPA CRASH research programme.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above
> copyright
> + *    notice, this list of conditions and the following disclaimer
> in the
> + *    documentation and/or other materials provided with the
> distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
> IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
> LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> POSSIBILITY OF
> + * SUCH DAMAGE.
> + *
> + * $FreeBSD$
> + */
> +
> +#define	READ4(_sc, _reg)	\
> +	bus_space_read_4(_sc->bst, _sc->bsh, _reg)
> +#define	WRITE4(_sc, _reg, _val)	\
> +	bus_space_write_4(_sc->bst, _sc->bsh, _reg, _val)
> +#define	READ2(_sc, _reg)	\
> +	bus_space_read_2(_sc->bst, _sc->bsh, _reg)
> +#define	WRITE2(_sc, _reg, _val)	\
> +	bus_space_write_2(_sc->bst, _sc->bsh, _reg, _val)
> +#define	READ1(_sc, _reg)	\
> +	bus_space_read_1(_sc->bst, _sc->bsh, _reg)
> +#define	WRITE1(_sc, _reg, _val)	\
> +	bus_space_write_1(_sc->bst, _sc->bsh, _reg, _val)

Why are these in a header when the softc is in a .c file? Also why not
use bus_read_n, e.g. READ4 would become:

#define READ4(_sc, _reg) bus_read_4((_sc)->res[0], _reg)
> 
> Added: head/sys/arm/altera/socfpga/socfpga_manager.c
> ==============================================================================
> --- /dev/null	00:00:00 1970	(empty, because file is
> newly added) +++ head/sys/arm/altera/socfpga/socfpga_manager.c
> Sat Sep  6 08:48:57 2014	(r271186) @@ -0,0 +1,436 @@
> +/*-
> + * Copyright (c) 2014 Ruslan Bukin <br at bsdpad.com>
> + * All rights reserved.
> + *
> + * This software was developed by SRI International and the
> University of
> + * Cambridge Computer Laboratory under DARPA/AFRL contract
> (FA8750-10-C-0237)
> + * ("CTSRD"), as part of the DARPA CRASH research programme.
> + *
> + * Redistribution and use in source and binary forms, with or without
> + * modification, are permitted provided that the following conditions
> + * are met:
> + * 1. Redistributions of source code must retain the above copyright
> + *    notice, this list of conditions and the following disclaimer.
> + * 2. Redistributions in binary form must reproduce the above
> copyright
> + *    notice, this list of conditions and the following disclaimer
> in the
> + *    documentation and/or other materials provided with the
> distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
> IS'' AND
> + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
> THE
> + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
> PARTICULAR PURPOSE
> + * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
> LIABLE
> + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
> CONSEQUENTIAL
> + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
> GOODS
> + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> INTERRUPTION)
> + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
> CONTRACT, STRICT
> + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
> ANY WAY
> + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
> POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +/*
> + * Altera FPGA Manager.
> + * Chapter 4, Cyclone V Device Handbook (CV-5V2 2014.07.22)
> + */
> +
> +#include <sys/cdefs.h>
> +__FBSDID("$FreeBSD$");
> +
> +#include <sys/param.h>
> +#include <sys/systm.h>
> +#include <sys/bus.h>
> +#include <sys/kernel.h>
> +#include <sys/module.h>
> +#include <sys/malloc.h>
> +#include <sys/rman.h>
> +#include <sys/timeet.h>
> +#include <sys/timetc.h>
> +#include <sys/conf.h>
> +#include <sys/uio.h>
> +
> +#include <dev/fdt/fdt_common.h>
> +#include <dev/ofw/openfirm.h>
> +#include <dev/ofw/ofw_bus.h>
> +#include <dev/ofw/ofw_bus_subr.h>
> +
> +#include <machine/bus.h>
> +#include <machine/fdt.h>
> +#include <machine/cpu.h>
> +#include <machine/intr.h>
> +
> +#include <arm/altera/socfpga/socfpga_common.h>
> +
> +/* FPGA Manager Module Registers */
> +#define	FPGAMGR_STAT		0x0	/* Status
> Register */ +#define	 STAT_MSEL_MASK		0x1f
> +#define	 STAT_MSEL_SHIFT	3
> +#define	 STAT_MODE_SHIFT	0
> +#define	 STAT_MODE_MASK		0x7
> +#define	FPGAMGR_CTRL		0x4	/* Control
> Register */ +#define	 CTRL_AXICFGEN		(1 << 8)
> +#define	 CTRL_CDRATIO_MASK	0x3
> +#define	 CTRL_CDRATIO_SHIFT	6
> +#define	 CTRL_CFGWDTH_MASK	1
> +#define	 CTRL_CFGWDTH_SHIFT	9
> +#define	 CTRL_NCONFIGPULL	(1 << 2)
> +#define	 CTRL_NCE		(1 << 1)
> +#define	 CTRL_EN		(1 << 0)
> +#define	FPGAMGR_DCLKCNT		0x8	/* DCLK
> Count Register */ +#define	FPGAMGR_DCLKSTAT
> 0xC	/* DCLK Status Register */ +#define
> FPGAMGR_GPO		0x10	/* General-Purpose Output
> Register */ +#define	FPGAMGR_GPI		0x14	/*
> General-Purpose Input Register */ +#define
> FPGAMGR_MISCI		0x18	/* Miscellaneous Input
> Register */ + +/* Configuration Monitor (MON) Registers */
> +#define	GPIO_INTEN		0x830	/* Interrupt
> Enable Register */ +#define	GPIO_INTMASK
> 0x834	/* Interrupt Mask Register */ +#define
> GPIO_INTTYPE_LEVEL	0x838	/* Interrupt Level Register */
> +#define	GPIO_INT_POLARITY	0x83C	/* Interrupt
> Polarity Register */ +#define	GPIO_INTSTATUS
> 0x840	/* Interrupt Status Register */ +#define
> GPIO_RAW_INTSTATUS	0x844	/* Raw Interrupt Status
> Register */ +#define	GPIO_PORTA_EOI
> 0x84C	/* Clear Interrupt Register */ +#define
> PORTA_EOI_NS		(1 << 0) +#define
> GPIO_EXT_PORTA		0x850	/* External Port A
> Register */ +#define	GPIO_LS_SYNC
> 0x860	/* Synchronization Level Register */ +#define
> GPIO_VER_ID_CODE	0x86C	/* GPIO Version Register */
> +#define	GPIO_CONFIG_REG2	0x870	/* Configuration
> Register 2 */ +#define	GPIO_CONFIG_REG1	0x874	/*
> Configuration Register 1 */ + +#define
> MSEL_PP16_FAST_NOAES_NODC	0x0 +#define
> MSEL_PP16_FAST_AES_NODC		0x1 +#define
> MSEL_PP16_FAST_AESOPT_DC	0x2 +#define
> MSEL_PP16_SLOW_NOAES_NODC	0x4 +#define
> MSEL_PP16_SLOW_AES_NODC		0x5 +#define
> MSEL_PP16_SLOW_AESOPT_DC	0x6 +#define
> MSEL_PP32_FAST_NOAES_NODC	0x8 +#define
> MSEL_PP32_FAST_AES_NODC		0x9 +#define
> MSEL_PP32_FAST_AESOPT_DC	0xa +#define
> MSEL_PP32_SLOW_NOAES_NODC	0xc +#define
> MSEL_PP32_SLOW_AES_NODC		0xd +#define
> MSEL_PP32_SLOW_AESOPT_DC	0xe + +#define
> CFGWDTH_16	0 +#define	CFGWDTH_32	1 +
> +#define	CDRATIO_1	0 +#define	CDRATIO_2	1
> +#define	CDRATIO_4	2 +#define	CDRATIO_8	3
> +
> +#define	FPGAMGR_MODE_POWEROFF	0x0
> +#define	FPGAMGR_MODE_RESET	0x1
> +#define	FPGAMGR_MODE_CONFIG	0x2
> +#define	FPGAMGR_MODE_INIT	0x3
> +#define	FPGAMGR_MODE_USER	0x4
> +
> +struct cfgmgr_mode {
> +	int msel;
> +	int cfgwdth;
> +	int cdratio;
> +};
> +
> +static struct cfgmgr_mode cfgmgr_modes[] = {
> +	{ MSEL_PP16_FAST_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
> +	{ MSEL_PP16_FAST_AES_NODC,   CFGWDTH_16, CDRATIO_2 },
> +	{ MSEL_PP16_FAST_AESOPT_DC,  CFGWDTH_16, CDRATIO_4 },
> +	{ MSEL_PP16_SLOW_NOAES_NODC, CFGWDTH_16, CDRATIO_1 },
> +	{ MSEL_PP16_SLOW_AES_NODC,   CFGWDTH_16, CDRATIO_2 },
> +	{ MSEL_PP16_SLOW_AESOPT_DC,  CFGWDTH_16, CDRATIO_4 },
> +	{ MSEL_PP32_FAST_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
> +	{ MSEL_PP32_FAST_AES_NODC,   CFGWDTH_32, CDRATIO_4 },
> +	{ MSEL_PP32_FAST_AESOPT_DC,  CFGWDTH_32, CDRATIO_8 },
> +	{ MSEL_PP32_SLOW_NOAES_NODC, CFGWDTH_32, CDRATIO_1 },
> +	{ MSEL_PP32_SLOW_AES_NODC,   CFGWDTH_32, CDRATIO_4 },
> +	{ MSEL_PP32_SLOW_AESOPT_DC,  CFGWDTH_32, CDRATIO_8 },
> +	{ -1, -1, -1 },
> +};
> +
> +struct fpgamgr_softc {
> +	struct resource		*res[3];
> +	bus_space_tag_t		bst;
> +	bus_space_handle_t	bsh;
> +	bus_space_tag_t		bst_data;
> +	bus_space_handle_t	bsh_data;
> +	struct cdev		*mgr_cdev;
> +	device_t		dev;
> +};
> +
> +static struct resource_spec fpgamgr_spec[] = {
> +	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
> +	{ SYS_RES_MEMORY,	1,	RF_ACTIVE },
> +	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
> +	{ -1, 0 }
> +};
> +
> +static int
> +fpgamgr_probe(device_t dev)

You have probe here, but the attach function is a long way below? I
normally look for the attach straight after probe as they are somewhat
related.

> +{
> +
> +	if (!ofw_bus_status_okay(dev))
> +		return (ENXIO);
> +
> +	if (!ofw_bus_is_compatible(dev, "altr,fpga-mgr"))
> +		return (ENXIO);
> +
> +	device_set_desc(dev, "FPGA Manager");
> +	return (BUS_PROBE_DEFAULT);
> +}
> +

...

> +
> +static int
> +fpga_open(struct cdev *dev __unused, int flags __unused,
dev is used.

> +    int fmt __unused, struct thread *td __unused)
> +{
> +	struct fpgamgr_softc *sc;
> +	struct cfgmgr_mode *mode;
> +	int msel;
> +	int reg;
> +	int i;
> +
> +	sc = dev->si_drv1;
Here

> +
> +	msel = READ4(sc, FPGAMGR_STAT);
> +	msel >>= STAT_MSEL_SHIFT;
> +	msel &= STAT_MSEL_MASK;
> +
> +	mode = NULL;
> +	for (i = 0; cfgmgr_modes[i].msel != -1; i++) {
> +		if (msel == cfgmgr_modes[i].msel) {
> +			mode = &cfgmgr_modes[i];
> +			break;
> +		}
> +	}
> +	if (mode == NULL) {
> +		device_printf(sc->dev, "Can't configure: unknown
> mode\n");
> +		return (ENXIO);
> +	}
> +
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg &= ~(CTRL_CDRATIO_MASK << CTRL_CDRATIO_SHIFT);
> +	reg |= (mode->cdratio << CTRL_CDRATIO_SHIFT);
> +	reg &= ~(CTRL_CFGWDTH_MASK << CTRL_CFGWDTH_SHIFT);
> +	reg |= (mode->cfgwdth << CTRL_CFGWDTH_SHIFT);
> +	reg &= ~(CTRL_NCE);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	/* Enable configuration */
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg |= (CTRL_EN);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	/* Reset FPGA */
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg |= (CTRL_NCONFIGPULL);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	/* Wait reset state */
> +	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_RESET)) {
> +		device_printf(sc->dev, "Can't get RESET state\n");
> +		return (ENXIO);
> +	}
> +
> +	/* Release from reset */
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg &= ~(CTRL_NCONFIGPULL);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_CONFIG)) {
> +		device_printf(sc->dev, "Can't get CONFIG state\n");
> +		return (ENXIO);
> +	}
> +
> +	/* Clear nSTATUS edge interrupt */
> +	WRITE4(sc, GPIO_PORTA_EOI, PORTA_EOI_NS);
> +
> +	/* Enter configuration state */
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg |= (CTRL_AXICFGEN);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	return (0);
> +}
> +
> +static int
> +fpga_wait_dclk_pulses(struct fpgamgr_softc *sc, int npulses)
> +{
> +	int tout;
> +
> +	/* Clear done bit, if any */
> +	if (READ4(sc, FPGAMGR_DCLKSTAT) != 0)
> +		WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
> +
> +	/* Request DCLK pulses */
> +	WRITE4(sc, FPGAMGR_DCLKCNT, npulses);
> +
> +	/* Wait finish */
> +	tout = 1000;
> +	while (tout > 0) {
> +		if (READ4(sc, FPGAMGR_DCLKSTAT) == 1) {
> +			WRITE4(sc, FPGAMGR_DCLKSTAT, 0x1);
> +			break;
> +		}
> +		tout--;
> +		DELAY(10);
> +	}
> +	if (tout == 0) {
> +		return (1);
> +	}
> +
> +	return (0);
> +}
> +
> +static int
> +fpga_close(struct cdev *dev __unused, int flags __unused,
dev is also used in this function.

> +    int fmt __unused, struct thread *td __unused)
> +{
> +	struct fpgamgr_softc *sc;
> +	int reg;
> +
> +	sc = dev->si_drv1;
> +
> +	reg = READ4(sc, GPIO_EXT_PORTA);
> +	if ((reg & (1 << 10)) == 0) {
What is magic about bit 10?

> +		device_printf(sc->dev, "Err: configuration
> failed\n");
> +		return (ENXIO);
> +	}
> +
> +	/* Exit configuration state */
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg &= ~(CTRL_AXICFGEN);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	/* Wait dclk pulses */
> +	if (fpga_wait_dclk_pulses(sc, 4)) {
> +		device_printf(sc->dev, "Can't proceed 4 dclk
> pulses\n");
> +		return (ENXIO);
> +	}
> +
> +	if (fpgamgr_state_wait(sc, FPGAMGR_MODE_USER)) {
> +		device_printf(sc->dev, "Can't get USER mode\n");
> +		return (ENXIO);
> +	}
> +
> +	/* Disable configuration */
> +	reg = READ4(sc, FPGAMGR_CTRL);
> +	reg &= ~(CTRL_EN);
> +	WRITE4(sc, FPGAMGR_CTRL, reg);
> +
> +	return (0);
> +}
> +
> +static int
> +fpga_write(struct cdev *dev, struct uio *uio, int ioflag)
> +{
> +	struct fpgamgr_softc *sc;
> +	int buffer;
> +
> +	sc = dev->si_drv1;
> +
> +	/*
> +	 * Device supports 4-byte copy only.
> +	 * TODO: add padding for <4 bytes.
> +	 */
> +
> +	while (uio->uio_resid > 0) {
> +		uiomove(&buffer, 4, uio);
> +		bus_space_write_4(sc->bst_data, sc->bsh_data,
> +		    0x0, buffer);
> +	}
> +
> +	return (0);
> +}
> +
> +static int
> +fpga_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags,
> +    struct thread *td)
> +{
> +
> +	return (0);
> +}
> +
> +static struct cdevsw fpga_cdevsw = {
> +	.d_version =	D_VERSION,
> +	.d_open =	fpga_open,
> +	.d_close =	fpga_close,
> +	.d_write =	fpga_write,
> +	.d_ioctl =	fpga_ioctl,
> +	.d_name =	"FPGA Manager",
> +};
> +
> +static int
> +fpgamgr_attach(device_t dev)
> +{
> +	struct fpgamgr_softc *sc;
> +
> +	sc = device_get_softc(dev);
> +	sc->dev = dev;
> +
> +	if (bus_alloc_resources(dev, fpgamgr_spec, sc->res)) {
> +		device_printf(dev, "could not allocate resources\n");
> +		return (ENXIO);
> +	}
> +
> +	/* Memory interface */
> +	sc->bst = rman_get_bustag(sc->res[0]);
> +	sc->bsh = rman_get_bushandle(sc->res[0]);
These are unneeded if you use bus_read_n/bus_write_n.

> +	sc->bst_data = rman_get_bustag(sc->res[1]);
> +	sc->bsh_data = rman_get_bushandle(sc->res[1]);
> +
> +	sc->mgr_cdev = make_dev(&fpga_cdevsw, 0, UID_ROOT, GID_WHEEL,
> +	    0600, "fpga%d", device_get_unit(sc->dev));
> +
> +	if (sc->mgr_cdev == NULL) {
> +		device_printf(dev, "Failed to create character
> device.\n");
> +		return (ENXIO);
> +	}
> +
> +	sc->mgr_cdev->si_drv1 = sc;
> +
> +	return (0);
> +}
> +

...



More information about the svn-src-all mailing list