summaryrefslogtreecommitdiffstats
path: root/sys/arm/freescale
diff options
context:
space:
mode:
authorian <ian@FreeBSD.org>2014-05-16 23:27:18 +0000
committerian <ian@FreeBSD.org>2014-05-16 23:27:18 +0000
commit8c5245706ff09e86526d43eedb7d37926a47d7d9 (patch)
treebd9466354d65aa13fa69cfdc30267c99cdf40c18 /sys/arm/freescale
parent3fad78482e066ba9e0e11e5ab0b65ed6a51f5c2e (diff)
downloadFreeBSD-src-8c5245706ff09e86526d43eedb7d37926a47d7d9.zip
FreeBSD-src-8c5245706ff09e86526d43eedb7d37926a47d7d9.tar.gz
MFC 262695, 262708, 262709, 262710, 262711, 262728, 262870, 262877, 262880,
262885, 262891, 262903, imx6: Add a tunable to set the number of active cores, enable SMP by default. ffec: Fix multicast filtering. Allwinner a10/a20... - Add gpio and clock bits for A10/A20's EMAC ethernet controller driver - EMAC gpio configuration - EMAC clock activation - Add Static Random Access Memory controller driver for A10/A20. A10/A20's SRAM is used by devices, such as CPU, EMAC, for extra fast memory or as cache. - Add EMAC 10/100 Ethernet controller driver for A10/A20. It is available mostly in A10 devices like Hackberry, Marsboard, Mele A1000, A2000, A100 HTPC, cubieboard1 and A20 device like cubieboard2. TX performance can be improved using both channels 0 and 1. RX performance is poor and needs improvement with the assistance of external DMA controller in case there - Add EMAC and SRAM controller entries to FDT. - Add EMAC device to kernel config files and enable EMAC, SRAM drivers. OMAP: When calculating the MPU freq, make sure not to overflow. Vybrid: - Add driver for Port control and interrupts (PORT). - Export panel info to DTS - Reset all the layers before setup first one - Enable display nandfs: Slight code reordering to make error branch last. Add option TMPFS to arm/conf/DEFAULTS, remove it from the few configs that have it individually. Concensus on freebsd-arm@ is that it should be included in all ARM kernels. Fix the arm sys_sigreturn(): its argument is a struct ucontext, not a struct sigframe containing the struct ucontext.
Diffstat (limited to 'sys/arm/freescale')
-rw-r--r--sys/arm/freescale/imx/imx6_mp.c12
-rw-r--r--sys/arm/freescale/vybrid/files.vybrid1
-rw-r--r--sys/arm/freescale/vybrid/vf_dcu4.c134
-rw-r--r--sys/arm/freescale/vybrid/vf_gpio.c38
-rw-r--r--sys/arm/freescale/vybrid/vf_port.c250
-rw-r--r--sys/arm/freescale/vybrid/vf_port.h43
6 files changed, 430 insertions, 48 deletions
diff --git a/sys/arm/freescale/imx/imx6_mp.c b/sys/arm/freescale/imx/imx6_mp.c
index 5b5136b..dfa435b 100644
--- a/sys/arm/freescale/imx/imx6_mp.c
+++ b/sys/arm/freescale/imx/imx6_mp.c
@@ -29,6 +29,7 @@ __FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
+#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/smp.h>
@@ -72,6 +73,7 @@ void
platform_mp_setmaxid(void)
{
bus_space_handle_t scu;
+ int hwcpu, ncpu;
uint32_t val;
/* If we've already set the global vars don't bother to do it again. */
@@ -81,10 +83,16 @@ platform_mp_setmaxid(void)
if (bus_space_map(fdtbus_bs_tag, SCU_PHYSBASE, SCU_SIZE, 0, &scu) != 0)
panic("Couldn't map the SCU\n");
val = bus_space_read_4(fdtbus_bs_tag, scu, SCU_CONFIG_REG);
+ hwcpu = (val & SCU_CONFIG_REG_NCPU_MASK) + 1;
bus_space_unmap(fdtbus_bs_tag, scu, SCU_SIZE);
- mp_maxid = (val & SCU_CONFIG_REG_NCPU_MASK);
- mp_ncpus = mp_maxid + 1;
+ ncpu = hwcpu;
+ TUNABLE_INT_FETCH("hw.ncpu", &ncpu);
+ if (ncpu < 1 || ncpu > hwcpu)
+ ncpu = hwcpu;
+
+ mp_ncpus = ncpu;
+ mp_maxid = ncpu - 1;
}
int
diff --git a/sys/arm/freescale/vybrid/files.vybrid b/sys/arm/freescale/vybrid/files.vybrid
index 1103f13..9bcd8bc 100644
--- a/sys/arm/freescale/vybrid/files.vybrid
+++ b/sys/arm/freescale/vybrid/files.vybrid
@@ -23,6 +23,7 @@ arm/freescale/vybrid/vf_mscm.c standard
arm/freescale/vybrid/vf_src.c standard
arm/freescale/vybrid/vf_edma.c standard
arm/freescale/vybrid/vf_dmamux.c standard
+arm/freescale/vybrid/vf_port.c standard
arm/freescale/vybrid/vf_i2c.c optional iicbus
arm/freescale/vybrid/vf_tcon.c optional vt
arm/freescale/vybrid/vf_dcu4.c optional vt
diff --git a/sys/arm/freescale/vybrid/vf_dcu4.c b/sys/arm/freescale/vybrid/vf_dcu4.c
index 8976427..d2ddddc 100644
--- a/sys/arm/freescale/vybrid/vf_dcu4.c
+++ b/sys/arm/freescale/vybrid/vf_dcu4.c
@@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/fbio.h>
#include <sys/consio.h>
#include <sys/eventhandler.h>
+#include <sys/gpio.h>
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
@@ -54,6 +55,8 @@ __FBSDID("$FreeBSD$");
#include <dev/vt/vt.h>
#include <dev/vt/colors/vt_termcolors.h>
+#include "gpio_if.h"
+
#include <machine/bus.h>
#include <machine/fdt.h>
#include <machine/cpu.h>
@@ -74,6 +77,9 @@ __FBSDID("$FreeBSD$");
#define DCU_MODE_TEST 0x2
#define DCU_MODE_COLBAR 0x3
#define RASTER_EN (1 << 14) /* Raster scan of pixel data */
+#define PDI_EN (1 << 13)
+#define PDI_DE_MODE (1 << 11)
+#define PDI_MODE_M 2
#define DCU_BGND 0x014 /* Background */
#define DCU_DISP_SIZE 0x018 /* Display Size */
#define DELTA_M 0x7ff
@@ -90,6 +96,9 @@ __FBSDID("$FreeBSD$");
#define DCU_SYNPOL 0x024 /* Synchronize Polarity */
#define INV_HS (1 << 0)
#define INV_VS (1 << 1)
+#define INV_PDI_VS (1 << 8) /* Polarity of PDI input VSYNC. */
+#define INV_PDI_HS (1 << 9) /* Polarity of PDI input HSYNC. */
+#define INV_PDI_DE (1 << 10) /* Polarity of PDI input DE. */
#define DCU_THRESHOLD 0x028 /* Threshold */
#define LS_BF_VS_SHIFT 16
#define OUT_BUF_HIGH_SHIFT 8
@@ -160,8 +169,20 @@ __FBSDID("$FreeBSD$");
#define DCU_CTRLDESCLn_8(n) DCU_CTRLDESCL(n, 8)
#define DCU_CTRLDESCLn_9(n) DCU_CTRLDESCL(n, 9)
-#define DISPLAY_WIDTH 480
-#define DISPLAY_HEIGHT 272
+#define NUM_LAYERS 64
+
+struct panel_info {
+ uint32_t width;
+ uint32_t height;
+ uint32_t h_back_porch;
+ uint32_t h_pulse_width;
+ uint32_t h_front_porch;
+ uint32_t v_back_porch;
+ uint32_t v_pulse_width;
+ uint32_t v_front_porch;
+ uint32_t clk_div;
+ uint32_t backlight_pin;
+};
struct dcu_softc {
struct resource *res[2];
@@ -171,6 +192,7 @@ struct dcu_softc {
device_t dev;
device_t sc_fbd; /* fbd child */
struct fb_info sc_info;
+ struct panel_info *panel;
};
static struct resource_spec dcu_spec[] = {
@@ -209,33 +231,84 @@ dcu_intr(void *arg)
}
static int
+get_panel_info(struct dcu_softc *sc, struct panel_info *panel)
+{
+ phandle_t node;
+ pcell_t dts_value[3];
+ int len;
+
+ if ((node = ofw_bus_get_node(sc->dev)) == -1)
+ return (ENXIO);
+
+ /* panel size */
+ if ((len = OF_getproplen(node, "panel-size")) <= 0)
+ return (ENXIO);
+ OF_getprop(node, "panel-size", &dts_value, len);
+ panel->width = fdt32_to_cpu(dts_value[0]);
+ panel->height = fdt32_to_cpu(dts_value[1]);
+
+ /* hsync */
+ if ((len = OF_getproplen(node, "panel-hsync")) <= 0)
+ return (ENXIO);
+ OF_getprop(node, "panel-hsync", &dts_value, len);
+ panel->h_back_porch = fdt32_to_cpu(dts_value[0]);
+ panel->h_pulse_width = fdt32_to_cpu(dts_value[1]);
+ panel->h_front_porch = fdt32_to_cpu(dts_value[2]);
+
+ /* vsync */
+ if ((len = OF_getproplen(node, "panel-vsync")) <= 0)
+ return (ENXIO);
+ OF_getprop(node, "panel-vsync", &dts_value, len);
+ panel->v_back_porch = fdt32_to_cpu(dts_value[0]);
+ panel->v_pulse_width = fdt32_to_cpu(dts_value[1]);
+ panel->v_front_porch = fdt32_to_cpu(dts_value[2]);
+
+ /* clk divider */
+ if ((len = OF_getproplen(node, "panel-clk-div")) <= 0)
+ return (ENXIO);
+ OF_getprop(node, "panel-clk-div", &dts_value, len);
+ panel->clk_div = fdt32_to_cpu(dts_value[0]);
+
+ /* backlight pin */
+ if ((len = OF_getproplen(node, "panel-backlight-pin")) <= 0)
+ return (ENXIO);
+ OF_getprop(node, "panel-backlight-pin", &dts_value, len);
+ panel->backlight_pin = fdt32_to_cpu(dts_value[0]);
+
+ return (0);
+}
+
+static int
dcu_init(struct dcu_softc *sc)
{
+ struct panel_info *panel;
int reg;
+ int i;
+
+ panel = sc->panel;
/* Configure DCU */
reg = ((sc->sc_info.fb_height) << DELTA_Y_S);
reg |= (sc->sc_info.fb_width / 16);
WRITE4(sc, DCU_DISP_SIZE, reg);
- /* TODO: export panel info to FDT */
-
- reg = (2 << BP_H_SHIFT);
- reg |= (41 << PW_H_SHIFT);
- reg |= (2 << FP_H_SHIFT);
+ reg = (panel->h_back_porch << BP_H_SHIFT);
+ reg |= (panel->h_pulse_width << PW_H_SHIFT);
+ reg |= (panel->h_front_porch << FP_H_SHIFT);
WRITE4(sc, DCU_HSYN_PARA, reg);
- reg = (2 << BP_V_SHIFT);
- reg |= (10 << PW_V_SHIFT);
- reg |= (2 << FP_V_SHIFT);
+ reg = (panel->v_back_porch << BP_V_SHIFT);
+ reg |= (panel->v_pulse_width << PW_V_SHIFT);
+ reg |= (panel->v_front_porch << FP_V_SHIFT);
WRITE4(sc, DCU_VSYN_PARA, reg);
WRITE4(sc, DCU_BGND, 0);
- WRITE4(sc, DCU_DIV_RATIO, 30);
+ WRITE4(sc, DCU_DIV_RATIO, panel->clk_div);
reg = (INV_VS | INV_HS);
WRITE4(sc, DCU_SYNPOL, reg);
+ /* TODO: export to panel info */
reg = (0x3 << LS_BF_VS_SHIFT);
reg |= (0x78 << OUT_BUF_HIGH_SHIFT);
reg |= (0 << OUT_BUF_LOW_SHIFT);
@@ -244,6 +317,19 @@ dcu_init(struct dcu_softc *sc)
/* Mask all the interrupts */
WRITE4(sc, DCU_INT_MASK, 0xffffffff);
+ /* Reset all layers */
+ for (i = 0; i < NUM_LAYERS; i++) {
+ WRITE4(sc, DCU_CTRLDESCLn_1(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_2(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_3(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_4(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_5(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_6(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_7(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_8(i), 0x0);
+ WRITE4(sc, DCU_CTRLDESCLn_9(i), 0x0);
+ }
+
/* Setup first layer */
reg = (sc->sc_info.fb_width | (sc->sc_info.fb_height << 16));
WRITE4(sc, DCU_CTRLDESCLn_1(0), reg);
@@ -273,10 +359,13 @@ dcu_init(struct dcu_softc *sc)
static int
dcu_attach(device_t dev)
{
+ struct panel_info panel;
struct dcu_softc *sc;
+ device_t gpio_dev;
int err;
sc = device_get_softc(dev);
+ sc->dev = dev;
if (bus_alloc_resources(dev, dcu_spec, sc->res)) {
device_printf(dev, "could not allocate resources\n");
@@ -295,11 +384,30 @@ dcu_attach(device_t dev)
return (ENXIO);
}
+ if (get_panel_info(sc, &panel)) {
+ device_printf(dev, "Can't get panel info\n");
+ return (ENXIO);
+ }
+
+ sc->panel = &panel;
+
/* Bypass timing control (used for raw lcd panels) */
tcon_bypass();
- sc->sc_info.fb_width = DISPLAY_WIDTH;
- sc->sc_info.fb_height = DISPLAY_HEIGHT;
+ /* Get the GPIO device, we need this to give power to USB */
+ gpio_dev = devclass_get_device(devclass_find("gpio"), 0);
+ if (gpio_dev == NULL) {
+ device_printf(sc->dev, "Error: failed to get the GPIO dev\n");
+ return (1);
+ }
+
+ /* Turn on backlight */
+ /* TODO: Use FlexTimer/PWM */
+ GPIO_PIN_SETFLAGS(gpio_dev, panel.backlight_pin, GPIO_PIN_OUTPUT);
+ GPIO_PIN_SET(gpio_dev, panel.backlight_pin, GPIO_PIN_HIGH);
+
+ sc->sc_info.fb_width = panel.width;
+ sc->sc_info.fb_height = panel.height;
sc->sc_info.fb_stride = sc->sc_info.fb_width * 3;
sc->sc_info.fb_bpp = sc->sc_info.fb_depth = 24;
sc->sc_info.fb_size = sc->sc_info.fb_height * sc->sc_info.fb_stride;
diff --git a/sys/arm/freescale/vybrid/vf_gpio.c b/sys/arm/freescale/vybrid/vf_gpio.c
index 3b8afc2..11db795 100644
--- a/sys/arm/freescale/vybrid/vf_gpio.c
+++ b/sys/arm/freescale/vybrid/vf_gpio.c
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD$");
#include "gpio_if.h"
#include <arm/freescale/vybrid/vf_common.h>
+#include <arm/freescale/vybrid/vf_port.h>
#define GPIO_PDOR(n) (0x00 + 0x40 * (n >> 5))
#define GPIO_PSOR(n) (0x04 + 0x40 * (n >> 5))
@@ -68,8 +69,6 @@ __FBSDID("$FreeBSD$");
#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx)
#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx)
-#define NPORTS 5
-#define NGPIO (NPORTS * 32)
#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)
/*
@@ -85,41 +84,23 @@ static int vf_gpio_pin_get(device_t, uint32_t, unsigned int *);
static int vf_gpio_pin_toggle(device_t, uint32_t pin);
struct vf_gpio_softc {
- struct resource *res[6];
+ struct resource *res[1];
bus_space_tag_t bst;
bus_space_handle_t bsh;
struct mtx sc_mtx;
int gpio_npins;
struct gpio_pin gpio_pins[NGPIO];
- void *gpio_ih[NPORTS];
};
struct vf_gpio_softc *gpio_sc;
static struct resource_spec vf_gpio_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
- { SYS_RES_IRQ, 0, RF_ACTIVE },
- { SYS_RES_IRQ, 1, RF_ACTIVE },
- { SYS_RES_IRQ, 2, RF_ACTIVE },
- { SYS_RES_IRQ, 3, RF_ACTIVE },
- { SYS_RES_IRQ, 4, RF_ACTIVE },
{ -1, 0 }
};
static int
-vf_gpio_intr(void *arg)
-{
- struct vf_gpio_softc *sc;
- sc = arg;
-
- /* TODO: interrupt handling */
-
- return (FILTER_HANDLED);
-}
-
-
-static int
vf_gpio_probe(device_t dev)
{
@@ -137,7 +118,7 @@ static int
vf_gpio_attach(device_t dev)
{
struct vf_gpio_softc *sc;
- int irq, i;
+ int i;
sc = device_get_softc(dev);
mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF);
@@ -147,22 +128,13 @@ vf_gpio_attach(device_t dev)
return (ENXIO);
}
- gpio_sc = sc;
-
/* Memory interface */
sc->bst = rman_get_bustag(sc->res[0]);
sc->bsh = rman_get_bushandle(sc->res[0]);
- sc->gpio_npins = NGPIO;
+ gpio_sc = sc;
- for (irq = 0; irq < NPORTS; irq ++) {
- if ((bus_setup_intr(dev, sc->res[1 + irq], INTR_TYPE_MISC,
- vf_gpio_intr, NULL, sc, &sc->gpio_ih[irq]))) {
- device_printf(dev,
- "WARNING: unable to register interrupt handler\n");
- return (ENXIO);
- }
- }
+ sc->gpio_npins = NGPIO;
for (i = 0; i < sc->gpio_npins; i++) {
sc->gpio_pins[i].gp_pin = i;
diff --git a/sys/arm/freescale/vybrid/vf_port.c b/sys/arm/freescale/vybrid/vf_port.c
new file mode 100644
index 0000000..0e1a2db
--- /dev/null
+++ b/sys/arm/freescale/vybrid/vf_port.c
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * 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.
+ */
+
+/*
+ * Vybrid Family Port control and interrupts (PORT)
+ * Chapter 6, Vybrid Reference Manual, Rev. 5, 07/2013
+ */
+
+#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/watchdog.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/freescale/vybrid/vf_port.h>
+#include <arm/freescale/vybrid/vf_common.h>
+
+/* Pin Control Register */
+#define PORT_PCR(n) (0x1000 * (n >> 5) + 0x4 * (n % 32))
+#define PCR_IRQC_S 16
+#define PCR_IRQC_M 0xF
+#define PCR_DMA_RE 0x1
+#define PCR_DMA_FE 0x2
+#define PCR_DMA_EE 0x3
+#define PCR_INT_LZ 0x8
+#define PCR_INT_RE 0x9
+#define PCR_INT_FE 0xA
+#define PCR_INT_EE 0xB
+#define PCR_INT_LO 0xC
+#define PCR_ISF (1 << 24)
+#define PORT0_ISFR 0xA0 /* Interrupt Status Flag Register */
+#define PORT0_DFER 0xC0 /* Digital Filter Enable Register */
+#define PORT0_DFCR 0xC4 /* Digital Filter Clock Register */
+#define PORT0_DFWR 0xC8 /* Digital Filter Width Register */
+
+struct port_event {
+ uint32_t enabled;
+ uint32_t mux_num;
+ uint32_t mux_src;
+ uint32_t mux_chn;
+ void (*ih) (void *);
+ void *ih_user;
+ enum ev_type pevt;
+};
+
+static struct port_event event_map[NGPIO];
+
+struct port_softc {
+ struct resource *res[6];
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ void *gpio_ih[NGPIO];
+};
+
+struct port_softc *port_sc;
+
+static struct resource_spec port_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 1, RF_ACTIVE },
+ { SYS_RES_IRQ, 2, RF_ACTIVE },
+ { SYS_RES_IRQ, 3, RF_ACTIVE },
+ { SYS_RES_IRQ, 4, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static int
+port_intr(void *arg)
+{
+ struct port_event *pev;
+ struct port_softc *sc;
+ int reg;
+ int i;
+
+ sc = arg;
+
+ for (i = 0; i < NGPIO; i++) {
+ reg = READ4(sc, PORT_PCR(i));
+ if (reg & PCR_ISF) {
+
+ /* Clear interrupt */
+ WRITE4(sc, PORT_PCR(i), reg);
+
+ /* Handle event */
+ pev = &event_map[i];
+ if (pev->enabled == 1) {
+ if (pev->ih != NULL) {
+ pev->ih(pev->ih_user);
+ }
+ }
+ }
+ }
+
+ return (FILTER_HANDLED);
+}
+
+int
+port_setup(int pnum, enum ev_type pevt, void (*ih)(void *), void *ih_user)
+{
+ struct port_event *pev;
+ struct port_softc *sc;
+ int reg;
+ int val;
+
+ sc = port_sc;
+
+ switch (pevt) {
+ case DMA_RISING_EDGE:
+ val = PCR_DMA_RE;
+ break;
+ case DMA_FALLING_EDGE:
+ val = PCR_DMA_FE;
+ break;
+ case DMA_EITHER_EDGE:
+ val = PCR_DMA_EE;
+ break;
+ case INT_LOGIC_ZERO:
+ val = PCR_INT_LZ;
+ break;
+ case INT_RISING_EDGE:
+ val = PCR_INT_RE;
+ break;
+ case INT_FALLING_EDGE:
+ val = PCR_INT_FE;
+ break;
+ case INT_EITHER_EDGE:
+ val = PCR_INT_RE;
+ break;
+ case INT_LOGIC_ONE:
+ val = PCR_INT_LO;
+ break;
+ default:
+ return (-1);
+ };
+
+ reg = READ4(sc, PORT_PCR(pnum));
+ reg &= ~(PCR_IRQC_M << PCR_IRQC_S);
+ reg |= (val << PCR_IRQC_S);
+ WRITE4(sc, PORT_PCR(pnum), reg);
+
+ pev = &event_map[pnum];
+ pev->ih = ih;
+ pev->ih_user = ih_user;
+ pev->pevt = pevt;
+ pev->enabled = 1;
+
+ return (0);
+}
+
+static int
+port_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "fsl,mvf600-port"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Vybrid Family Port control and interrupts");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+port_attach(device_t dev)
+{
+ struct port_softc *sc;
+ int irq;
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, port_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]);
+
+ port_sc = sc;
+
+ for (irq = 0; irq < NPORTS; irq ++) {
+ if ((bus_setup_intr(dev, sc->res[1 + irq], INTR_TYPE_MISC,
+ port_intr, NULL, sc, &sc->gpio_ih[irq]))) {
+ device_printf(dev,
+ "ERROR: Unable to register interrupt handler\n");
+ return (ENXIO);
+ }
+ }
+
+ return (0);
+}
+
+static device_method_t port_methods[] = {
+ DEVMETHOD(device_probe, port_probe),
+ DEVMETHOD(device_attach, port_attach),
+ { 0, 0 }
+};
+
+static driver_t port_driver = {
+ "port",
+ port_methods,
+ sizeof(struct port_softc),
+};
+
+static devclass_t port_devclass;
+
+DRIVER_MODULE(port, simplebus, port_driver, port_devclass, 0, 0);
diff --git a/sys/arm/freescale/vybrid/vf_port.h b/sys/arm/freescale/vybrid/vf_port.h
new file mode 100644
index 0000000..a2fd360
--- /dev/null
+++ b/sys/arm/freescale/vybrid/vf_port.h
@@ -0,0 +1,43 @@
+/*-
+ * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
+ * All rights reserved.
+ *
+ * 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 NPORTS 5
+#define NGPIO (NPORTS * 32)
+
+enum ev_type {
+ DMA_RISING_EDGE,
+ DMA_FALLING_EDGE,
+ DMA_EITHER_EDGE,
+ INT_LOGIC_ZERO,
+ INT_RISING_EDGE,
+ INT_FALLING_EDGE,
+ INT_EITHER_EDGE,
+ INT_LOGIC_ONE,
+};
+
+int port_setup(int, enum ev_type, void (*ih)(void *), void *ih_user);
OpenPOWER on IntegriCloud