diff --git a/sys/arm/conf/VYBRID b/sys/arm/conf/VYBRID
index 43cdac5940c0..ca2d93d8e096 100644
--- a/sys/arm/conf/VYBRID
+++ b/sys/arm/conf/VYBRID
@@ -141,6 +141,10 @@ device bpf # Berkeley packet filter
device sound
+# SPI
+device spibus
+device vf_spi
+
# Framebuffer
device vt
device kbdmux
diff --git a/sys/arm/freescale/vybrid/files.vybrid b/sys/arm/freescale/vybrid/files.vybrid
index 81928c3fb5f4..b054259ac1a6 100644
--- a/sys/arm/freescale/vybrid/files.vybrid
+++ b/sys/arm/freescale/vybrid/files.vybrid
@@ -31,4 +31,5 @@ arm/freescale/vybrid/vf_ehci.c optional ehci
arm/freescale/vybrid/vf_gpio.c optional gpio
arm/freescale/vybrid/vf_uart.c optional uart
arm/freescale/vybrid/vf_sai.c optional sound
+arm/freescale/vybrid/vf_spi.c optional vf_spi
dev/ffec/if_ffec.c optional ffec
diff --git a/sys/arm/freescale/vybrid/vf_spi.c b/sys/arm/freescale/vybrid/vf_spi.c
new file mode 100644
index 000000000000..222b96f89214
--- /dev/null
+++ b/sys/arm/freescale/vybrid/vf_spi.c
@@ -0,0 +1,293 @@
+/*-
+ * Copyright (c) 2014 Ruslan Bukin
+ * 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 Serial Peripheral Interface (SPI)
+ * Chapter 47, Vybrid Reference Manual, Rev. 5, 07/2013
+ */
+
+#include
+__FBSDID("$FreeBSD$");
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#include "spibus_if.h"
+
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include
+
+#define SPI_FIFO_SIZE 4
+
+#define SPI_MCR 0x00 /* Module Configuration */
+#define MCR_MSTR (1 << 31) /* Master/Slave Mode Select */
+#define MCR_CONT_SCKE (1 << 30) /* Continuous SCK Enable */
+#define MCR_FRZ (1 << 27) /* Freeze */
+#define MCR_PCSIS_S 16 /* Peripheral Chip Select */
+#define MCR_PCSIS_M 0x3f
+#define MCR_MDIS (1 << 14) /* Module Disable */
+#define MCR_CLR_TXF (1 << 11) /* Clear TX FIFO */
+#define MCR_CLR_RXF (1 << 10) /* Clear RX FIFO */
+#define MCR_HALT (1 << 0) /* Starts and stops SPI transfers */
+#define SPI_TCR 0x08 /* Transfer Count */
+#define SPI_CTAR0 0x0C /* Clock and Transfer Attributes */
+#define SPI_CTAR0_SLAVE 0x0C /* Clock and Transfer Attributes */
+#define SPI_CTAR1 0x10 /* Clock and Transfer Attributes */
+#define SPI_CTAR2 0x14 /* Clock and Transfer Attributes */
+#define SPI_CTAR3 0x18 /* Clock and Transfer Attributes */
+#define CTAR_FMSZ_M 0xf
+#define CTAR_FMSZ_S 27 /* Frame Size */
+#define CTAR_FMSZ_8 0x7 /* 8 bits */
+#define CTAR_CPOL (1 << 26) /* Clock Polarity */
+#define CTAR_CPHA (1 << 25) /* Clock Phase */
+#define CTAR_LSBFE (1 << 24) /* Less significant bit first */
+#define CTAR_PCSSCK_M 0x3
+#define CTAR_PCSSCK_S 22 /* PCS to SCK Delay Prescaler */
+#define CTAR_PBR_M 0x3
+#define CTAR_PBR_S 16 /* Baud Rate Prescaler */
+#define CTAR_PBR_7 0x3 /* Divide by 7 */
+#define CTAR_CSSCK_M 0xf
+#define CTAR_CSSCK_S 12 /* PCS to SCK Delay Scaler */
+#define CTAR_BR_M 0xf
+#define CTAR_BR_S 0 /* Baud Rate Scaler */
+#define SPI_SR 0x2C /* Status Register */
+#define SR_TCF (1 << 31) /* Transfer Complete Flag */
+#define SR_EOQF (1 << 28) /* End of Queue Flag */
+#define SR_TFFF (1 << 25) /* Transmit FIFO Fill Flag */
+#define SR_RFDF (1 << 17) /* Receive FIFO Drain Flag */
+#define SPI_RSER 0x30 /* DMA/Interrupt Select */
+#define RSER_EOQF_RE (1 << 28) /* Finished Request Enable */
+#define SPI_PUSHR 0x34 /* PUSH TX FIFO In Master Mode */
+#define PUSHR_CONT (1 << 31) /* Continuous Peripheral CS */
+#define PUSHR_EOQ (1 << 27) /* End Of Queue */
+#define PUSHR_CTCNT (1 << 26) /* Clear Transfer Counter */
+#define PUSHR_PCS_M 0x3f
+#define PUSHR_PCS_S 16 /* Select PCS signals */
+
+#define SPI_PUSHR_SLAVE 0x34 /* PUSH TX FIFO Register In Slave Mode */
+#define SPI_POPR 0x38 /* POP RX FIFO Register */
+#define SPI_TXFR0 0x3C /* Transmit FIFO Registers */
+#define SPI_TXFR1 0x40
+#define SPI_TXFR2 0x44
+#define SPI_TXFR3 0x48
+#define SPI_RXFR0 0x7C /* Receive FIFO Registers */
+#define SPI_RXFR1 0x80
+#define SPI_RXFR2 0x84
+#define SPI_RXFR3 0x88
+
+struct spi_softc {
+ struct resource *res[2];
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ void *ih;
+};
+
+static struct resource_spec spi_spec[] = {
+ { SYS_RES_MEMORY, 0, RF_ACTIVE },
+ { SYS_RES_IRQ, 0, RF_ACTIVE },
+ { -1, 0 }
+};
+
+static int
+spi_probe(device_t dev)
+{
+
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "fsl,mvf600-spi"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Vybrid Family Serial Peripheral Interface");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+spi_attach(device_t dev)
+{
+ struct spi_softc *sc;
+ uint32_t reg;
+
+ sc = device_get_softc(dev);
+
+ if (bus_alloc_resources(dev, spi_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]);
+
+ reg = READ4(sc, SPI_MCR);
+ reg |= MCR_MSTR;
+ reg &= ~(MCR_CONT_SCKE | MCR_MDIS | MCR_FRZ);
+ reg &= ~(MCR_PCSIS_M << MCR_PCSIS_S);
+ reg |= (MCR_PCSIS_M << MCR_PCSIS_S); /* PCS Active low */
+ reg |= (MCR_CLR_TXF | MCR_CLR_RXF);
+ WRITE4(sc, SPI_MCR, reg);
+
+ reg = READ4(sc, SPI_RSER);
+ reg |= RSER_EOQF_RE;
+ WRITE4(sc, SPI_RSER, reg);
+
+ reg = READ4(sc, SPI_MCR);
+ reg &= ~MCR_HALT;
+ WRITE4(sc, SPI_MCR, reg);
+
+ reg = READ4(sc, SPI_CTAR0);
+ reg &= ~(CTAR_FMSZ_M << CTAR_FMSZ_S);
+ reg |= (CTAR_FMSZ_8 << CTAR_FMSZ_S);
+ /*
+ * TODO: calculate BR
+ * SCK baud rate = ( fsys / PBR ) * (1 + DBR) / BR
+ *
+ * reg &= ~(CTAR_BR_M << CTAR_BR_S);
+ */
+ reg &= ~CTAR_CPOL; /* Polarity */
+ reg |= CTAR_CPHA;
+ /*
+ * Set LSB (Less significant bit first)
+ * must be used for some applications, e.g. some LCDs
+ */
+ reg |= CTAR_LSBFE;
+ WRITE4(sc, SPI_CTAR0, reg);
+
+ reg = READ4(sc, SPI_CTAR0);
+ reg &= ~(CTAR_PBR_M << CTAR_PBR_S);
+ reg |= (CTAR_PBR_7 << CTAR_PBR_S);
+ WRITE4(sc, SPI_CTAR0, reg);
+
+ device_add_child(dev, "spibus", 0);
+ return (bus_generic_attach(dev));
+}
+
+static int
+spi_txrx(struct spi_softc *sc, uint8_t *out_buf,
+ uint8_t *in_buf, int bufsz, int cs)
+{
+ uint32_t reg, wreg;
+ uint32_t txcnt;
+ uint32_t i;
+
+ txcnt = 0;
+
+ for (i = 0; i < bufsz; i++) {
+ txcnt++;
+ wreg = out_buf[i];
+ wreg |= PUSHR_CONT;
+ wreg |= (cs << PUSHR_PCS_S);
+ if (i == 0)
+ wreg |= PUSHR_CTCNT;
+ if (i == (bufsz - 1) || txcnt == SPI_FIFO_SIZE)
+ wreg |= PUSHR_EOQ;
+ WRITE4(sc, SPI_PUSHR, wreg);
+
+ if (i == (bufsz - 1) || txcnt == SPI_FIFO_SIZE) {
+ txcnt = 0;
+
+ /* Wait last entry in a queue to be transmitted */
+ while((READ4(sc, SPI_SR) & SR_EOQF) == 0)
+ continue;
+
+ reg = READ4(sc, SPI_SR);
+ reg |= (SR_TCF | SR_EOQF);
+ WRITE4(sc, SPI_SR, reg);
+ }
+
+ /* Wait until RX FIFO is empty */
+ while((READ4(sc, SPI_SR) & SR_RFDF) == 0)
+ continue;
+
+ in_buf[i] = READ1(sc, SPI_POPR);
+ }
+
+ return (0);
+}
+
+static int
+spi_transfer(device_t dev, device_t child, struct spi_command *cmd)
+{
+ struct spi_softc *sc;
+ uint32_t cs;
+
+ sc = device_get_softc(dev);
+
+ KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz,
+ ("%s: TX/RX command sizes should be equal", __func__));
+ KASSERT(cmd->tx_data_sz == cmd->rx_data_sz,
+ ("%s: TX/RX data sizes should be equal", __func__));
+
+ /* get the proper chip select */
+ spibus_get_cs(child, &cs);
+
+ /* Command */
+ spi_txrx(sc, cmd->tx_cmd, cmd->rx_cmd, cmd->tx_cmd_sz, cs);
+
+ /* Data */
+ spi_txrx(sc, cmd->tx_data, cmd->rx_data, cmd->tx_data_sz, cs);
+
+ return (0);
+}
+
+static device_method_t spi_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, spi_probe),
+ DEVMETHOD(device_attach, spi_attach),
+ /* SPI interface */
+ DEVMETHOD(spibus_transfer, spi_transfer),
+ { 0, 0 }
+};
+
+static driver_t spi_driver = {
+ "spi",
+ spi_methods,
+ sizeof(struct spi_softc),
+};
+
+static devclass_t spi_devclass;
+
+DRIVER_MODULE(spi, simplebus, spi_driver, spi_devclass, 0, 0);