Author: ian
Date: Sun May 24 18:59:45 2015
New Revision: 283500
URL: https://svnweb.freebsd.org/changeset/base/283500

Log:
  MFC r268838, r277644:
  
    Add support for Toradex Apalis i.MX6 development board.
  
    Add support for imx6 audio transmitting, include drivers for:
    o Digital Audio Multiplexer (AUDMUX)
    o Smart Direct Memory Access Controller (SDMA)
    o Synchronous Serial Interface (SSI)

Added:
  stable/10/sys/arm/conf/APALIS-IMX6
     - copied, changed from r268838, head/sys/arm/conf/APALIS-IMX6
  stable/10/sys/arm/freescale/imx/imx6_audmux.c
     - copied unchanged from r277644, head/sys/arm/freescale/imx/imx6_audmux.c
  stable/10/sys/arm/freescale/imx/imx6_sdma.c
     - copied unchanged from r277644, head/sys/arm/freescale/imx/imx6_sdma.c
  stable/10/sys/arm/freescale/imx/imx6_sdma.h
     - copied unchanged from r277644, head/sys/arm/freescale/imx/imx6_sdma.h
  stable/10/sys/arm/freescale/imx/imx6_ssi.c
     - copied unchanged from r277644, head/sys/arm/freescale/imx/imx6_ssi.c
  stable/10/sys/boot/fdt/dts/arm/apalis-imx6.dts
     - copied, changed from r268838, head/sys/boot/fdt/dts/arm/apalis-imx6.dts
Modified:
  stable/10/sys/arm/freescale/imx/files.imx6
  stable/10/sys/arm/freescale/imx/imx6_anatop.c
  stable/10/sys/arm/freescale/imx/imx6_anatopreg.h
  stable/10/sys/arm/freescale/imx/imx6_anatopvar.h
  stable/10/sys/arm/freescale/imx/imx6_ccm.c
  stable/10/sys/arm/freescale/imx/imx6_ccmreg.h
  stable/10/sys/arm/freescale/imx/imx_ccmvar.h
  stable/10/sys/boot/fdt/dts/arm/imx6.dtsi
Directory Properties:
  stable/10/   (props changed)

Copied and modified: stable/10/sys/arm/conf/APALIS-IMX6 (from r268838, 
head/sys/arm/conf/APALIS-IMX6)
==============================================================================
--- head/sys/arm/conf/APALIS-IMX6       Fri Jul 18 08:23:53 2014        
(r268838, copy source)
+++ stable/10/sys/arm/conf/APALIS-IMX6  Sun May 24 18:59:45 2015        
(r283500)
@@ -19,13 +19,13 @@
 
 #NO_UNIVERSE
 
-include        "IMX6"
+include        "IMX6"
 ident          APALIS-IMX6
 
 makeoptions    MODULES_OVERRIDE=""
 makeoptions    WITHOUT_MODULES="ahc"
 
 # Flattened Device Tree
-options        FDT
-options        FDT_DTB_STATIC
-makeoptions    FDT_DTS_FILE=apalis-imx6.dts
+options        FDT
+options        FDT_DTB_STATIC
+makeoptions    FDT_DTS_FILE=apalis-imx6.dts

Modified: stable/10/sys/arm/freescale/imx/files.imx6
==============================================================================
--- stable/10/sys/arm/freescale/imx/files.imx6  Sun May 24 18:23:57 2015        
(r283499)
+++ stable/10/sys/arm/freescale/imx/files.imx6  Sun May 24 18:59:45 2015        
(r283500)
@@ -28,6 +28,9 @@ arm/freescale/imx/imx_machdep.c               standar
 arm/freescale/imx/imx_gpt.c            standard
 arm/freescale/imx/imx_gpio.c           optional gpio
 arm/freescale/imx/imx_i2c.c            optional fsliic
+arm/freescale/imx/imx6_sdma.c          optional sdma
+arm/freescale/imx/imx6_audmux.c                optional sound
+arm/freescale/imx/imx6_ssi.c           optional sound
 
 #
 # Optional devices.
@@ -52,3 +55,19 @@ arm/freescale/imx/imx6_usbphy.c              optiona
 # Not ready yet...
 #
 #arm/freescale/imx/imx51_ipuv3.c       optional sc
+
+# SDMA firmware
+sdma_fw.c                              optional sdma_fw                \
+       compile-with    "${AWK} -f $S/tools/fw_stub.awk 
sdma-imx6q-to1.bin:sdma_fw -msdma -c${.TARGET}" \
+       no-implicit-rule before-depend local                            \
+       clean           "sdma_fw.c"
+sdma-imx6q-to1.fwo                     optional sdma_fw                \
+       dependency      "sdma-imx6q-to1.bin"                            \
+       compile-with    "${LD} -b binary -d -warn-common -r -d -o ${.TARGET} 
sdma-imx6q-to1.bin" \
+       no-implicit-rule                                                \
+       clean           "sdma-imx6q-to1.fwo"
+sdma-imx6q-to1.bin                     optional sdma_fw                \
+       dependency      "$S/contrib/dev/imx/sdma-imx6q-to1.bin.uu"      \
+       compile-with    "uudecode < $S/contrib/dev/imx/sdma-imx6q-to1.bin.uu" \
+       no-obj no-implicit-rule                                         \
+       clean           "sdma-imx6q-to1.bin"

Modified: stable/10/sys/arm/freescale/imx/imx6_anatop.c
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_anatop.c       Sun May 24 18:23:57 
2015        (r283499)
+++ stable/10/sys/arm/freescale/imx/imx6_anatop.c       Sun May 24 18:59:45 
2015        (r283500)
@@ -713,6 +713,27 @@ out:
        return (err);
 }
 
+uint32_t
+pll4_configure_output(uint32_t mfi, uint32_t mfn, uint32_t mfd)
+{
+       int reg;
+
+       /*
+        * Audio PLL (PLL4).
+        * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM)
+        */
+
+       reg = (IMX6_ANALOG_CCM_PLL_AUDIO_ENABLE);
+       reg &= ~(IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_MASK << \
+               IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT);
+       reg |= (mfi << IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT);
+       imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO, reg);
+       imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_NUM, mfn);
+       imx6_anatop_write_4(IMX6_ANALOG_CCM_PLL_AUDIO_DENOM, mfd);
+
+       return (0);
+}
+
 static int
 imx6_anatop_probe(device_t dev)
 {

Modified: stable/10/sys/arm/freescale/imx/imx6_anatopreg.h
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_anatopreg.h    Sun May 24 18:23:57 
2015        (r283499)
+++ stable/10/sys/arm/freescale/imx/imx6_anatopreg.h    Sun May 24 18:59:45 
2015        (r283500)
@@ -58,6 +58,9 @@
 #define        IMX6_ANALOG_CCM_PLL_SYS_NUM                     0x050
 #define        IMX6_ANALOG_CCM_PLL_SYS_DENOM                   0x060
 #define        IMX6_ANALOG_CCM_PLL_AUDIO                       0x070
+#define           IMX6_ANALOG_CCM_PLL_AUDIO_ENABLE               (1 << 13)
+#define           IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_SHIFT     0
+#define           IMX6_ANALOG_CCM_PLL_AUDIO_DIV_SELECT_MASK      0x7f
 #define        IMX6_ANALOG_CCM_PLL_AUDIO_SET                   0x074
 #define        IMX6_ANALOG_CCM_PLL_AUDIO_CLR                   0x078
 #define        IMX6_ANALOG_CCM_PLL_AUDIO_TOG                   0x07C

Modified: stable/10/sys/arm/freescale/imx/imx6_anatopvar.h
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_anatopvar.h    Sun May 24 18:23:57 
2015        (r283499)
+++ stable/10/sys/arm/freescale/imx/imx6_anatopvar.h    Sun May 24 18:59:45 
2015        (r283500)
@@ -42,4 +42,6 @@ void imx6_anatop_write_4(bus_size_t _off
 
 uint32_t imx6_get_cpu_clock(void);
 
+uint32_t pll4_configure_output(uint32_t mfi, uint32_t mfn, uint32_t mfd);
+
 #endif

Copied: stable/10/sys/arm/freescale/imx/imx6_audmux.c (from r277644, 
head/sys/arm/freescale/imx/imx6_audmux.c)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/10/sys/arm/freescale/imx/imx6_audmux.c       Sun May 24 18:59:45 
2015        (r283500, copy of r277644, head/sys/arm/freescale/imx/imx6_audmux.c)
@@ -0,0 +1,159 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <b...@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.
+ */
+
+/*
+ * i.MX6 Digital Audio Multiplexer (AUDMUX)
+ * Chapter 16, i.MX 6Dual/6Quad Applications Processor Reference Manual,
+ * Rev. 1, 04/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/endian.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.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>
+
+#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        AUDMUX_PTCR(n)  (0x8 * (n - 1)) /* Port Timing Control Register 
*/
+#define         PTCR_TFS_DIR   (1 << 31)       /* Transmit Frame Sync 
Direction Control */
+#define         PTCR_TFSEL_S   27              /* Transmit Frame Sync Select */
+#define         PTCR_TFSEL_M   0xf
+#define         PTCR_TCLKDIR   (1 << 26)       /* Transmit Clock Direction 
Control */
+#define         PTCR_TCSEL_S   22              /* Transmit Clock Select. */
+#define         PTCR_TCSEL_M   0xf
+#define         PTCR_RFS_DIR   (1 << 21)       /* Receive Frame Sync Direction 
Control */
+#define         PTCR_SYN       (1 << 11)
+#define        AUDMUX_PDCR(n)  (0x8 * (n - 1) + 0x4)   /* Port Data Control 
Reg */
+#define         PDCR_RXDSEL_S          13      /* Receive Data Select */
+#define         PDCR_RXDSEL_M          0x3
+#define         PDCR_RXDSEL_PORT(n)    (n - 1)
+
+struct audmux_softc {
+       struct resource         *res[1];
+       bus_space_tag_t         bst;
+       bus_space_handle_t      bsh;
+       void                    *ih;
+};
+
+static struct resource_spec audmux_spec[] = {
+       { SYS_RES_MEMORY,       0,      RF_ACTIVE },
+       { -1, 0 }
+};
+
+static int
+audmux_probe(device_t dev)
+{
+
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
+
+       if (!ofw_bus_is_compatible(dev, "fsl,imx6q-audmux"))
+               return (ENXIO);
+
+       device_set_desc(dev, "i.MX6 Digital Audio Multiplexer");
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+audmux_configure(struct audmux_softc *sc,
+       int ssi_port, int audmux_port)
+{
+       uint32_t reg;
+
+       /* Direction: output */
+       reg = (PTCR_TFS_DIR | PTCR_TCLKDIR | PTCR_SYN);
+       WRITE4(sc, AUDMUX_PTCR(audmux_port), reg);
+
+       /* Select source */
+       reg = (PDCR_RXDSEL_PORT(ssi_port) << PDCR_RXDSEL_S);
+       WRITE4(sc, AUDMUX_PDCR(audmux_port), reg);
+
+       return (0);
+}
+
+static int
+audmux_attach(device_t dev)
+{
+       struct audmux_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       if (bus_alloc_resources(dev, audmux_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]);
+
+       /*
+        * Direct SSI1 output to AUDMUX5 pins.
+        * TODO: dehardcore this.
+        */
+       audmux_configure(sc, 1, 5);
+
+       return (0);
+};
+
+static device_method_t audmux_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         audmux_probe),
+       DEVMETHOD(device_attach,        audmux_attach),
+       { 0, 0 }
+};
+
+static driver_t audmux_driver = {
+       "audmux",
+       audmux_methods,
+       sizeof(struct audmux_softc),
+};
+
+static devclass_t audmux_devclass;
+
+DRIVER_MODULE(audmux, simplebus, audmux_driver, audmux_devclass, 0, 0);

Modified: stable/10/sys/arm/freescale/imx/imx6_ccm.c
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_ccm.c  Sun May 24 18:23:57 2015        
(r283499)
+++ stable/10/sys/arm/freescale/imx/imx6_ccm.c  Sun May 24 18:59:45 2015        
(r283500)
@@ -94,7 +94,7 @@ ccm_init_gates(struct ccm_softc *sc)
        WR4(sc, CCM_CCGR2, 0x0fffffc0); /* ipmux & ipsync (bridges), iomux, i2c 
*/
        WR4(sc, CCM_CCGR3, 0x3ff00000); /* DDR memory controller */
        WR4(sc, CCM_CCGR4, 0x0000f300); /* pl301 bus crossbar */
-       WR4(sc, CCM_CCGR5, 0x0f000000); /* uarts */
+       WR4(sc, CCM_CCGR5, 0x0ffc00c0); /* uarts, ssi, sdma */
        WR4(sc, CCM_CCGR6, 0x000000ff); /* usdhc 1-4 */
 }
 
@@ -180,6 +180,58 @@ ccm_probe(device_t dev)
 }
 
 void
+imx_ccm_ssi_configure(device_t _ssidev)
+{
+       struct ccm_softc *sc;
+       uint32_t reg;
+
+       sc = ccm_sc;
+
+       /*
+        * Select PLL4 (Audio PLL) clock multiplexer as source.
+        * PLL output frequency = Fref * (DIV_SELECT + NUM/DENOM).
+        */
+
+       reg = RD4(sc, CCM_CSCMR1);
+       reg &= ~(SSI_CLK_SEL_M << SSI1_CLK_SEL_S);
+       reg |= (SSI_CLK_SEL_PLL4 << SSI1_CLK_SEL_S);
+       reg &= ~(SSI_CLK_SEL_M << SSI2_CLK_SEL_S);
+       reg |= (SSI_CLK_SEL_PLL4 << SSI2_CLK_SEL_S);
+       reg &= ~(SSI_CLK_SEL_M << SSI3_CLK_SEL_S);
+       reg |= (SSI_CLK_SEL_PLL4 << SSI3_CLK_SEL_S);
+       WR4(sc, CCM_CSCMR1, reg);
+
+       /*
+        * Ensure we have set hardware-default values
+        * for pre and post dividers.
+        */
+
+       /* SSI1 and SSI3 */
+       reg = RD4(sc, CCM_CS1CDR);
+       /* Divide by 2 */
+       reg &= ~(SSI_CLK_PODF_MASK << SSI1_CLK_PODF_SHIFT);
+       reg &= ~(SSI_CLK_PODF_MASK << SSI3_CLK_PODF_SHIFT);
+       reg |= (0x1 << SSI1_CLK_PODF_SHIFT);
+       reg |= (0x1 << SSI3_CLK_PODF_SHIFT);
+       /* Divide by 4 */
+       reg &= ~(SSI_CLK_PRED_MASK << SSI1_CLK_PRED_SHIFT);
+       reg &= ~(SSI_CLK_PRED_MASK << SSI3_CLK_PRED_SHIFT);
+       reg |= (0x3 << SSI1_CLK_PRED_SHIFT);
+       reg |= (0x3 << SSI3_CLK_PRED_SHIFT);
+       WR4(sc, CCM_CS1CDR, reg);
+
+       /* SSI2 */
+       reg = RD4(sc, CCM_CS2CDR);
+       /* Divide by 2 */
+       reg &= ~(SSI_CLK_PODF_MASK << SSI2_CLK_PODF_SHIFT);
+       reg |= (0x1 << SSI2_CLK_PODF_SHIFT);
+       /* Divide by 4 */
+       reg &= ~(SSI_CLK_PRED_MASK << SSI2_CLK_PRED_SHIFT);
+       reg |= (0x3 << SSI2_CLK_PRED_SHIFT);
+       WR4(sc, CCM_CS2CDR, reg);
+}
+
+void
 imx_ccm_usb_enable(device_t _usbdev)
 {
 

Modified: stable/10/sys/arm/freescale/imx/imx6_ccmreg.h
==============================================================================
--- stable/10/sys/arm/freescale/imx/imx6_ccmreg.h       Sun May 24 18:23:57 
2015        (r283499)
+++ stable/10/sys/arm/freescale/imx/imx6_ccmreg.h       Sun May 24 18:59:45 
2015        (r283500)
@@ -29,6 +29,26 @@
 #ifndef        IMX6_CCMREG_H
 #define        IMX6_CCMREG_H
 
+#define        CCM_CSCMR1                      0x01C
+#define          SSI1_CLK_SEL_S                  10
+#define          SSI2_CLK_SEL_S                  12
+#define          SSI3_CLK_SEL_S                  14
+#define          SSI_CLK_SEL_M                   0x3
+#define          SSI_CLK_SEL_508_PFD             0
+#define          SSI_CLK_SEL_454_PFD             1
+#define          SSI_CLK_SEL_PLL4                2
+#define        CCM_CSCMR2                      0x020
+#define        CCM_CS1CDR                      0x028
+#define          SSI1_CLK_PODF_SHIFT             0
+#define          SSI1_CLK_PRED_SHIFT             6
+#define          SSI3_CLK_PODF_SHIFT             16
+#define          SSI3_CLK_PRED_SHIFT             22
+#define          SSI_CLK_PODF_MASK               0x3f
+#define          SSI_CLK_PRED_MASK               0x7
+#define        CCM_CS2CDR                      0x02C
+#define          SSI2_CLK_PODF_SHIFT             0
+#define          SSI2_CLK_PRED_SHIFT             6
+#define        CCM_CSCDR2                      0x038
 #define        CCM_CLPCR                       0x054
 #define          CCM_CLPCR_LPM_MASK              0x03
 #define          CCM_CLPCR_LPM_RUN               0x00

Copied: stable/10/sys/arm/freescale/imx/imx6_sdma.c (from r277644, 
head/sys/arm/freescale/imx/imx6_sdma.c)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/10/sys/arm/freescale/imx/imx6_sdma.c Sun May 24 18:59:45 2015        
(r283500, copy of r277644, head/sys/arm/freescale/imx/imx6_sdma.c)
@@ -0,0 +1,518 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <b...@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.
+ */
+
+/*
+ * i.MX6 Smart Direct Memory Access Controller (sDMA)
+ * Chapter 41, i.MX 6Dual/6Quad Applications Processor Reference Manual,
+ * Rev. 1, 04/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/endian.h>
+#include <sys/rman.h>
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/firmware.h>
+
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.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/imx/imx6_sdma.h>
+
+#define        MAX_BD  (PAGE_SIZE / sizeof(struct sdma_buffer_descriptor))
+
+#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)
+
+struct sdma_softc *sdma_sc;
+
+static struct resource_spec sdma_spec[] = {
+       { SYS_RES_MEMORY,       0,      RF_ACTIVE },
+       { SYS_RES_IRQ,          0,      RF_ACTIVE },
+       { -1, 0 }
+};
+
+static void
+sdma_intr(void *arg)
+{
+       struct sdma_buffer_descriptor *bd;
+       struct sdma_channel *channel;
+       struct sdma_conf *conf;
+       struct sdma_softc *sc;
+       int pending;
+       int i;
+       int j;
+
+       sc = arg;
+
+       pending = READ4(sc, SDMAARM_INTR);
+
+       /* Ack intr */
+       WRITE4(sc, SDMAARM_INTR, pending);
+
+       for (i = 0; i < SDMA_N_CHANNELS; i++) {
+               if ((pending & (1 << i)) == 0)
+                       continue;
+               channel = &sc->channel[i];
+               conf = channel->conf;
+               if (!conf)
+                       continue;
+               for (j = 0; j < conf->num_bd; j++) {
+                       bd = &channel->bd[j];
+                       bd->mode.status |= BD_DONE;
+                       if (bd->mode.status & BD_RROR)
+                               printf("sDMA error\n");
+               }
+
+               conf->ih(conf->ih_user, 1);
+
+               WRITE4(sc, SDMAARM_HSTART, (1 << i));
+       }
+}
+
+static int
+sdma_probe(device_t dev)
+{
+
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
+
+       if (!ofw_bus_is_compatible(dev, "fsl,imx6q-sdma"))
+               return (ENXIO);
+
+       device_set_desc(dev, "i.MX6 Smart Direct Memory Access Controller");
+       return (BUS_PROBE_DEFAULT);
+}
+
+int
+sdma_start(int chn)
+{
+       struct sdma_softc *sc;
+
+       sc = sdma_sc;
+
+       WRITE4(sc, SDMAARM_HSTART, (1 << chn));
+
+       return (0);
+}
+
+int
+sdma_stop(int chn)
+{
+       struct sdma_softc *sc;
+
+       sc = sdma_sc;
+
+       WRITE4(sc, SDMAARM_STOP_STAT, (1 << chn));
+
+       return (0);
+}
+
+int
+sdma_alloc(void)
+{
+       struct sdma_channel *channel;
+       struct sdma_softc *sc;
+       int found;
+       int chn;
+       int i;
+
+       sc = sdma_sc;
+       found = 0;
+
+       /* Channel 0 can't be used */
+       for (i = 1; i < SDMA_N_CHANNELS; i++) {
+               channel = &sc->channel[i];
+               if (channel->in_use == 0) {
+                       channel->in_use = 1;
+                       found = 1;
+                       break;
+               }
+       }
+
+       if (!found)
+               return (-1);
+
+       chn = i;
+
+       /* Allocate area for buffer descriptors */
+       channel->bd = (void *)kmem_alloc_contig(kernel_arena,
+           PAGE_SIZE, M_ZERO, 0, ~0, PAGE_SIZE, 0,
+           VM_MEMATTR_UNCACHEABLE);
+
+       return (chn);
+}
+
+int
+sdma_free(int chn)
+{
+       struct sdma_channel *channel;
+       struct sdma_softc *sc;
+
+       sc = sdma_sc;
+
+       channel = &sc->channel[chn];
+       channel->in_use = 0;
+
+       kmem_free(kernel_arena, (vm_offset_t)channel->bd,
+                       PAGE_SIZE);
+
+       return (0);
+}
+
+static int
+sdma_overrides(struct sdma_softc *sc, int chn,
+               int evt, int host, int dsp)
+{
+       int reg;
+
+       /* Ignore sDMA requests */
+       reg = READ4(sc, SDMAARM_EVTOVR);
+       if (evt)
+               reg |= (1 << chn);
+       else
+               reg &= ~(1 << chn);
+       WRITE4(sc, SDMAARM_EVTOVR, reg);
+
+       /* Ignore enable bit (HE) */
+       reg = READ4(sc, SDMAARM_HOSTOVR);
+       if (host)
+               reg |= (1 << chn);
+       else
+               reg &= ~(1 << chn);
+       WRITE4(sc, SDMAARM_HOSTOVR, reg);
+
+       /* Prevent sDMA channel from starting */
+       reg = READ4(sc, SDMAARM_DSPOVR);
+       if (!dsp)
+               reg |= (1 << chn);
+       else
+               reg &= ~(1 << chn);
+       WRITE4(sc, SDMAARM_DSPOVR, reg);
+
+       return (0);
+}
+
+int
+sdma_configure(int chn, struct sdma_conf *conf)
+{
+       struct sdma_buffer_descriptor *bd0;
+       struct sdma_buffer_descriptor *bd;
+       struct sdma_context_data *context;
+       struct sdma_channel *channel;
+       struct sdma_softc *sc;
+#if 0
+       int timeout;
+       int ret;
+#endif
+       int i;
+
+       sc = sdma_sc;
+
+       channel = &sc->channel[chn];
+       channel->conf = conf;
+
+       /* Ensure operation has stopped */
+       sdma_stop(chn);
+
+       /* Set priority and enable the channel */
+       WRITE4(sc, SDMAARM_SDMA_CHNPRI(chn), 1);
+       WRITE4(sc, SDMAARM_CHNENBL(conf->event), (1 << chn));
+
+       sdma_overrides(sc, chn, 0, 0, 0);
+
+       if (conf->num_bd > MAX_BD) {
+               device_printf(sc->dev, "Error: too much buffer"
+                               " descriptors requested\n");
+               return (-1);
+       }
+
+       for (i = 0; i < conf->num_bd; i++) {
+               bd = &channel->bd[i];
+               bd->mode.command = conf->command;
+               bd->mode.status = BD_DONE | BD_EXTD | BD_CONT | BD_INTR;
+               if (i == (conf->num_bd - 1))
+                       bd->mode.status |= BD_WRAP;
+               bd->mode.count = conf->period;
+               bd->buffer_addr = conf->saddr + (conf->period * i);
+               bd->ext_buffer_addr = 0;
+       }
+
+       sc->ccb[chn].base_bd_ptr = vtophys(channel->bd);
+       sc->ccb[chn].current_bd_ptr = vtophys(channel->bd);
+
+       /*
+        * Load context.
+        *
+        * i.MX6 Reference Manual: Appendix A SDMA Scripts
+        * A.3.1.7.1 (mcu_2_app)
+        */
+
+       /*
+        * TODO: allow using other scripts
+        */
+       context = sc->context;
+       memset(context, 0, sizeof(*context));
+       context->channel_state.pc = sc->fw_scripts->mcu_2_app_addr;
+
+       /*
+        * Tx FIFO 0 address (r6)
+        * Event_mask (r1)
+        * Event2_mask (r0)
+        * Watermark level (r7)
+        */
+
+       if (conf->event > 32) {
+               context->gReg[0] = (1 << (conf->event % 32));
+               context->gReg[1] = 0;
+       } else {
+               context->gReg[0] = 0;
+               context->gReg[1] = (1 << conf->event);
+       }
+
+       context->gReg[6] = conf->daddr;
+       context->gReg[7] = conf->word_length;
+
+       bd0 = sc->bd0;
+       bd0->mode.command = C0_SETDM;
+       bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+       bd0->mode.count = sizeof(*context) / 4;
+       bd0->buffer_addr = sc->context_phys;
+       bd0->ext_buffer_addr = 2048 + (sizeof(*context) / 4) * chn;
+
+       WRITE4(sc, SDMAARM_HSTART, 1);
+
+#if 0
+       /* Debug purposes */
+
+       timeout = 1000;
+       while (!(ret = READ4(sc, SDMAARM_INTR) & 1)) {
+               if (timeout-- <= 0)
+                       break;
+               DELAY(10);
+       };
+
+       if (!ret) {
+               device_printf(sc->dev, "Failed to load context.\n");
+               return (-1);
+       }
+
+       WRITE4(sc, SDMAARM_INTR, ret);
+
+       device_printf(sc->dev, "Context loaded successfully.\n");
+#endif
+
+       return (0);
+}
+
+static int
+load_firmware(struct sdma_softc *sc)
+{
+       struct sdma_firmware_header *header;
+       const struct firmware *fp;
+
+       fp = firmware_get("sdma_fw");
+       if (fp == NULL) {
+               device_printf(sc->dev, "Can't get firmware.\n");
+               return (-1);
+       }
+
+       header = (struct sdma_firmware_header *)fp->data;
+       if (header->magic != FW_HEADER_MAGIC) {
+               device_printf(sc->dev, "Can't use firmware.\n");
+               return (-1);
+       }
+
+       sc->fw_header = header;
+       sc->fw_scripts = (void *)((char *)header +
+                               header->script_addrs_start);
+
+       return (0);
+}
+
+static int
+boot_firmware(struct sdma_softc *sc)
+{
+       struct sdma_buffer_descriptor *bd0;
+       uint32_t *ram_code;
+       int timeout;
+       int ret;
+       int chn;
+       int sz;
+       int i;
+
+       ram_code = (void *)((char *)sc->fw_header +
+                       sc->fw_header->ram_code_start);
+
+       /* Make sure SDMA has not started yet */
+       WRITE4(sc, SDMAARM_MC0PTR, 0);
+
+       sz = SDMA_N_CHANNELS * sizeof(struct sdma_channel_control) + \
+           sizeof(struct sdma_context_data);
+       sc->ccb = (void *)kmem_alloc_contig(kernel_arena,
+           sz, M_ZERO, 0, ~0, PAGE_SIZE, 0, VM_MEMATTR_UNCACHEABLE);
+       sc->ccb_phys = vtophys(sc->ccb);
+
+       sc->context = (void *)((char *)sc->ccb + \
+           SDMA_N_CHANNELS * sizeof(struct sdma_channel_control));
+       sc->context_phys = vtophys(sc->context);
+
+       /* Disable all the channels */
+       for (i = 0; i < SDMA_N_EVENTS; i++)
+               WRITE4(sc, SDMAARM_CHNENBL(i), 0);
+
+       /* All channels have priority 0 */
+       for (i = 0; i < SDMA_N_CHANNELS; i++)
+               WRITE4(sc, SDMAARM_SDMA_CHNPRI(i), 0);
+
+       /* Channel 0 is used for booting firmware */
+       chn = 0;
+
+       sc->bd0 = (void *)kmem_alloc_contig(kernel_arena,
+           PAGE_SIZE, M_ZERO, 0, ~0, PAGE_SIZE, 0,
+           VM_MEMATTR_UNCACHEABLE);
+       bd0 = sc->bd0;
+       sc->ccb[chn].base_bd_ptr = vtophys(bd0);
+       sc->ccb[chn].current_bd_ptr = vtophys(bd0);
+
+       WRITE4(sc, SDMAARM_SDMA_CHNPRI(chn), 1);
+
+       sdma_overrides(sc, chn, 1, 0, 0);
+
+       /* XXX: not sure what is that */
+       WRITE4(sc, SDMAARM_CHN0ADDR, 0x4050);
+
+       WRITE4(sc, SDMAARM_CONFIG, 0);
+       WRITE4(sc, SDMAARM_MC0PTR, sc->ccb_phys);
+       WRITE4(sc, SDMAARM_CONFIG, CONFIG_CSM);
+       WRITE4(sc, SDMAARM_SDMA_CHNPRI(chn), 1);
+
+       bd0->mode.command = C0_SETPM;
+       bd0->mode.status = BD_DONE | BD_INTR | BD_WRAP | BD_EXTD;
+       bd0->mode.count = sc->fw_header->ram_code_size / 2;
+       bd0->buffer_addr = vtophys(ram_code);
+       bd0->ext_buffer_addr = sc->fw_scripts->ram_code_start_addr;
+
+       WRITE4(sc, SDMAARM_HSTART, 1);
+
+       timeout = 100;
+       while (!(ret = READ4(sc, SDMAARM_INTR) & 1)) {
+               if (timeout-- <= 0)
+                       break;
+               DELAY(10);
+       };
+
+       if (ret == 0) {
+               device_printf(sc->dev, "SDMA failed to boot\n");
+               return (-1);
+       }
+
+       WRITE4(sc, SDMAARM_INTR, ret);
+
+#if 0
+       device_printf(sc->dev, "SDMA booted successfully.\n");
+#endif
+
+       /* Debug is disabled */
+       WRITE4(sc, SDMAARM_ONCE_ENB, 0);
+
+       return (0);
+}
+
+static int
+sdma_attach(device_t dev)
+{
+       struct sdma_softc *sc;
+       int err;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+
+       if (bus_alloc_resources(dev, sdma_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]);
+
+       sdma_sc = sc;
+
+       /* Setup interrupt handler */
+       err = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE,
+           NULL, sdma_intr, sc, &sc->ih);
+       if (err) {
+               device_printf(dev, "Unable to alloc interrupt resource.\n");
+               return (ENXIO);
+       }
+
+       if (load_firmware(sc) == -1)
+               return (ENXIO);
+
+       if (boot_firmware(sc) == -1)
+               return (ENXIO);
+
+       return (0);
+};
+
+static device_method_t sdma_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         sdma_probe),
+       DEVMETHOD(device_attach,        sdma_attach),
+       { 0, 0 }
+};
+
+static driver_t sdma_driver = {
+       "sdma",
+       sdma_methods,
+       sizeof(struct sdma_softc),
+};
+
+static devclass_t sdma_devclass;
+
+DRIVER_MODULE(sdma, simplebus, sdma_driver, sdma_devclass, 0, 0);

Copied: stable/10/sys/arm/freescale/imx/imx6_sdma.h (from r277644, 
head/sys/arm/freescale/imx/imx6_sdma.h)
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ stable/10/sys/arm/freescale/imx/imx6_sdma.h Sun May 24 18:59:45 2015        
(r283500, copy of r277644, head/sys/arm/freescale/imx/imx6_sdma.h)
@@ -0,0 +1,245 @@
+/*-
+ * Copyright (c) 2015 Ruslan Bukin <b...@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        SDMAARM_MC0PTR          0x00    /* ARM platform Channel 0 
Pointer */
+#define        SDMAARM_INTR            0x04    /* Channel Interrupts */
+#define        SDMAARM_STOP_STAT       0x08    /* Channel Stop/Channel Status 
*/
+#define        SDMAARM_HSTART          0x0C    /* Channel Start */
+#define        SDMAARM_EVTOVR          0x10    /* Channel Event Override */
+#define        SDMAARM_DSPOVR          0x14    /* Channel BP Override */
+#define        SDMAARM_HOSTOVR         0x18    /* Channel ARM platform 
Override */
+#define        SDMAARM_EVTPEND         0x1C    /* Channel Event Pending */
+#define        SDMAARM_RESET           0x24    /* Reset Register */
+#define        SDMAARM_EVTERR          0x28    /* DMA Request Error Register */
+#define        SDMAARM_INTRMASK        0x2C    /* Channel ARM platform 
Interrupt Mask */
+#define        SDMAARM_PSW             0x30    /* Schedule Status */
+#define        SDMAARM_EVTERRDBG       0x34    /* DMA Request Error Register */
+#define        SDMAARM_CONFIG          0x38    /* Configuration Register */
+#define         CONFIG_CSM             0x3
+#define        SDMAARM_SDMA_LOCK       0x3C    /* SDMA LOCK */
+#define        SDMAARM_ONCE_ENB        0x40    /* OnCE Enable */
+#define        SDMAARM_ONCE_DATA       0x44    /* OnCE Data Register */
+#define        SDMAARM_ONCE_INSTR      0x48    /* OnCE Instruction Register */
+#define        SDMAARM_ONCE_STAT       0x4C    /* OnCE Status Register */
+#define        SDMAARM_ONCE_CMD        0x50    /* OnCE Command Register */
+#define        SDMAARM_ILLINSTADDR     0x58    /* Illegal Instruction Trap 
Address */
+#define        SDMAARM_CHN0ADDR        0x5C    /* Channel 0 Boot Address */
+#define        SDMAARM_EVT_MIRROR      0x60    /* DMA Requests */
+#define        SDMAARM_EVT_MIRROR2     0x64    /* DMA Requests 2 */
+#define        SDMAARM_XTRIG_CONF1     0x70    /* Cross-Trigger Events 
Configuration Register 1 */
+#define        SDMAARM_XTRIG_CONF2     0x74    /* Cross-Trigger Events 
Configuration Register 2 */
+#define        SDMAARM_SDMA_CHNPRI(n)  (0x100 + 0x4 * n)       /* Channel 
Priority Registers */
+#define        SDMAARM_CHNENBL(n)      (0x200 + 0x4 * n)       /* Channel 
Enable RAM */
+
+/* SDMA Event Mappings */
+#define        SSI1_RX_1       35
+#define        SSI1_TX_1       36
+#define        SSI1_RX_0       37
+#define        SSI1_TX_0       38
+#define        SSI2_RX_1       39
+#define        SSI2_TX_1       40
+#define        SSI2_RX_0       41
+#define        SSI2_TX_0       42
+#define        SSI3_RX_1       43
+#define        SSI3_TX_1       44
+#define        SSI3_RX_0       45
+#define        SSI3_TX_0       46
+
+#define        C0_ADDR         0x01
+#define        C0_LOAD         0x02
+#define        C0_DUMP         0x03
+#define        C0_SETCTX       0x07
+#define        C0_GETCTX       0x03
+#define        C0_SETDM        0x01
+#define        C0_SETPM        0x04
+#define        C0_GETDM        0x02
+#define        C0_GETPM        0x08
+
+#define        BD_DONE         0x01
+#define        BD_WRAP         0x02
+#define        BD_CONT         0x04
+#define        BD_INTR         0x08
+#define        BD_RROR         0x10
+#define        BD_LAST         0x20
+#define        BD_EXTD         0x80
+
+/* sDMA data transfer length */
+#define        CMD_4BYTES      0
+#define        CMD_3BYTES      3
+#define        CMD_2BYTES      2
+#define        CMD_1BYTES      1
+
+struct sdma_firmware_header {
+       uint32_t        magic;
+       uint32_t        version_major;
+       uint32_t        version_minor;
+       uint32_t        script_addrs_start;
+       uint32_t        num_script_addrs;
+       uint32_t        ram_code_start;
+       uint32_t        ram_code_size;
+};
+
+struct sdma_mode_count {
+       uint16_t count;
+       uint8_t status;
+       uint8_t command;
+};
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to