Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 24 May 2015 18:59:45 +0000 (UTC)
From:      Ian Lepore <ian@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-10@freebsd.org
Subject:   svn commit: r283500 - in stable/10/sys: arm/conf arm/freescale/imx boot/fdt/dts/arm
Message-ID:  <201505241859.t4OIxjIQ071786@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 <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.
+ */
+
+/*
+ * 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 <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.
+ */
+
+/*
+ * 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 <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	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 ***



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201505241859.t4OIxjIQ071786>