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-head
mailing list