summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/armv7/conf/GENERIC-IMX147
-rw-r--r--sys/arch/armv7/conf/RAMDISK-IMX164
-rw-r--r--sys/arch/armv7/conf/files.armv73
-rw-r--r--sys/arch/armv7/imx/files.imx51
-rw-r--r--sys/arch/armv7/imx/imx.c201
-rw-r--r--sys/arch/armv7/imx/imx6.c345
-rw-r--r--sys/arch/armv7/imx/imx_machdep.c982
-rw-r--r--sys/arch/armv7/imx/imxahci.c173
-rw-r--r--sys/arch/armv7/imx/imxccm.c563
-rw-r--r--sys/arch/armv7/imx/imxccmvar.h34
-rw-r--r--sys/arch/armv7/imx/imxdog.c90
-rw-r--r--sys/arch/armv7/imx/imxehci.c250
-rw-r--r--sys/arch/armv7/imx/imxenet.c964
-rw-r--r--sys/arch/armv7/imx/imxenet.h83
-rw-r--r--sys/arch/armv7/imx/imxesdhc.c963
-rw-r--r--sys/arch/armv7/imx/imxgpio.c241
-rw-r--r--sys/arch/armv7/imx/imxgpiovar.h41
-rw-r--r--sys/arch/armv7/imx/imxiic.c372
-rw-r--r--sys/arch/armv7/imx/imxiicvar.h44
-rw-r--r--sys/arch/armv7/imx/imxiomuxc.c262
-rw-r--r--sys/arch/armv7/imx/imxiomuxcvar.h27
-rw-r--r--sys/arch/armv7/imx/imxocotp.c82
-rw-r--r--sys/arch/armv7/imx/imxocotpvar.h18
-rw-r--r--sys/arch/armv7/imx/imxuart.c830
-rw-r--r--sys/arch/armv7/imx/imxuartreg.h130
-rw-r--r--sys/arch/armv7/imx/imxuartvar.h19
-rw-r--r--sys/arch/armv7/imx/imxvar.h55
27 files changed, 7133 insertions, 1 deletions
diff --git a/sys/arch/armv7/conf/GENERIC-IMX b/sys/arch/armv7/conf/GENERIC-IMX
new file mode 100644
index 00000000000..951f469aaf3
--- /dev/null
+++ b/sys/arch/armv7/conf/GENERIC-IMX
@@ -0,0 +1,147 @@
+# $OpenBSD: GENERIC-IMX,v 1.1 2013/09/06 20:45:53 patrick Exp $
+#
+# GENERIC machine description file
+#
+# This machine description file is used to generate the default OpenBSD
+# kernel. The generic kernel does not include all options, subsystems
+# and device drivers, but should be useful for most applications.
+#
+# The machine description file can be customised for your specific
+# machine to reduce the kernel size and improve its performance.
+#
+# For further information on compiling OpenBSD kernels, see the config(8)
+# man page.
+#
+# For further information on hardware support for this architecture, see
+# the intro(4) man page. For further information about kernel options
+# for this architecture, see the options(4) man page. For an explanation
+# of each device driver in this file see the section 4 man page for the
+# device.
+
+machine armv7 arm
+include "../../../conf/GENERIC"
+options TIMEZONE=0 # time zone to adjust RTC time by
+options DST=0 # daylight saving time used by RTC
+#options NFSCLIENT # NFS
+
+makeoptions KERNEL_BASE_PHYS="0x10800000"
+makeoptions KERNEL_BASE_VIRT="0xc0800000"
+options BUILD_STARTUP_PAGETABLE
+options STARTUP_PAGETABLE_ADDR=0x10200000
+options SDRAM_START="0x10000000"
+
+#options APERTURE
+
+#options BOOT_CONFIG # boot-time kernel config
+
+# estimated number of users
+
+maxusers 32
+
+# CPU options
+options CPU_ARMv7 # Support the ARMv7
+makeoptions CPUFLAGS="-mcpu=armv5" # dont have gcc v7 support yet.
+
+#option WSDISPLAY_COMPAT_USL # VT handling
+#option WSDISPLAY_COMPAT_RAWKBD # can get raw scancodes
+option WSDISPLAY_DEFAULTSCREENS=1
+#option WSDISPLAY_COMPAT_PCVT # emulate some ioctls
+
+config bsd root on sd0a swap on sd0b
+
+# The main bus device
+mainbus0 at root
+cpu0 at mainbus?
+
+# Cortex-A9 (iMX6)
+cortex0 at mainbus?
+ampintc* at cortex?
+amptimer* at cortex?
+armliicc* at cortex?
+
+# iMX SoC
+imx0 at mainbus?
+
+# iMX on-chip devices
+imxccm* at imx? # clock control module
+imxiomuxc* at imx? # iomux controller
+imxdog* at imx? # watchdog timer
+imxocotp* at imx? # on-chip otp controller
+imxgpio* at imx? # user-visible GPIO pins?
+imxesdhc* at imx? # SDHC controller
+imxenet* at imx? # ethernet
+imxuart* at imx? # onboard uarts
+imxiic* at imx? # i2c
+
+ahci* at imx? # AHCI/SATA
+
+ehci* at imx? # EHCI (shim)
+usb* at ehci?
+
+# USB bus support
+usb* at ehci? flags 0x1
+uhub* at usb?
+uhub* at uhub?
+
+uhub* at usb? # USB Hubs
+uhub* at uhub? # USB Hubs
+umodem* at uhub? # USB Modems/Serial
+ucom* at umodem?
+uvisor* at uhub? # Handspring Visor
+ucom* at uvisor?
+uvscom* at uhub? # SUNTAC Slipper U VS-10U serial
+ucom* at uvscom?
+ubsa* at uhub? # Belkin serial adapter
+ucom* at ubsa?
+uftdi* at uhub? # FTDI FT8U100AX serial adapter
+ucom* at uftdi?
+uplcom* at uhub? # I/O DATA USB-RSAQ2 serial adapter
+ucom* at uplcom?
+umct* at uhub? # MCT USB-RS232 serial adapter
+ucom* at umct?
+uaudio* at uhub? # USB Audio
+audio* at uaudio?
+umidi* at uhub? # USB MIDI
+midi* at umidi?
+ulpt* at uhub? # USB Printers
+umass* at uhub? # USB Mass Storage devices
+uhidev* at uhub? # Human Interface Devices
+ums* at uhidev? # USB mouse
+wsmouse* at ums? mux 0
+ukbd* at uhidev? # USB keyboard
+wskbd* at ukbd? mux 1
+uhid* at uhidev? # USB generic HID support
+aue* at uhub? # ADMtek AN986 Pegasus Ethernet
+atu* at uhub? # Atmel AT76c50x based 802.11b
+axe* at uhub? # ASIX Electronics AX88172 USB Ethernet
+cue* at uhub? # CATC USB-EL1201A based Ethernet
+kue* at uhub? # Kawasaki KL5KUSB101B based Ethernet
+smsc* at uhub? # SMSC LAN95xx Ethernet
+cdce* at uhub? # CDC Ethernet
+upl* at uhub? # Prolific PL2301/PL2302 host-to-host `network'
+udav* at uhub? # Davicom DM9601 based Ethernet
+url* at uhub? # Realtek RTL8150L based adapters
+wi* at uhub? # WaveLAN IEEE 802.11DS
+urio* at uhub? # Diamond Multimedia Rio 500
+#uyap* at uhub? # Y@P firmware loader
+udsbr* at uhub? # D-Link DSB-R100 radio
+radio* at udsbr? # USB radio
+#ubt* at uhub? disable # USB Bluetooth
+ugen* at uhub? # USB Generic driver
+
+ukphy* at mii? # "unknown" PHYs
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+ch* at scsibus?
+uk* at scsibus?
+
+sdmmc* at imxesdhc? # SD/MMC bus
+
+# I2C bus support
+iic* at imxiic?
+
+# Pseudo-Devices
+pseudo-device hotplug 1 # devices hot plugging
diff --git a/sys/arch/armv7/conf/RAMDISK-IMX b/sys/arch/armv7/conf/RAMDISK-IMX
new file mode 100644
index 00000000000..73345e25195
--- /dev/null
+++ b/sys/arch/armv7/conf/RAMDISK-IMX
@@ -0,0 +1,164 @@
+# $OpenBSD: RAMDISK-IMX,v 1.1 2013/09/06 20:45:53 patrick Exp $
+#
+# GENERIC machine description file
+#
+# This machine description file is used to generate the default OpenBSD
+# kernel. The generic kernel does not include all options, subsystems
+# and device drivers, but should be useful for most applications.
+#
+# The machine description file can be customised for your specific
+# machine to reduce the kernel size and improve its performance.
+#
+# For further information on compiling OpenBSD kernels, see the config(8)
+# man page.
+#
+# For further information on hardware support for this architecture, see
+# the intro(4) man page. For further information about kernel options
+# for this architecture, see the options(4) man page. For an explanation
+# of each device driver in this file see the section 4 man page for the
+# device.
+
+machine armv7 arm
+
+options TIMEZONE=0 # time zone to adjust RTC time by
+options DST=0 # daylight saving time used by RTC
+options FFS # UFS
+#options CD9660 # ISO 9660 + Rock Ridge file system
+options MSDOSFS # MS-DOS file system
+options INET # IP + ICMP + TCP + UDP
+options INET6 # IPv6 (needs INET)
+options DDB # kernel debugger
+options DIAGNOSTIC
+option DDB_SAFE_CONSOLE
+options FIFO # FIFOs; RECOMMENDED
+#options NFSCLIENT # NFS
+
+makeoptions KERNEL_BASE_PHYS="0x10800000"
+makeoptions KERNEL_BASE_VIRT="0xc0800000"
+options BUILD_STARTUP_PAGETABLE
+options STARTUP_PAGETABLE_ADDR=0x10200000
+options SDRAM_START="0x10000000"
+
+options APERTURE
+
+# estimated number of users
+
+maxusers 32
+
+# CPU options
+options CPU_ARMv7 # Support the ARMv7
+makeoptions CPUFLAGS="-mcpu=armv5" # dont have gcc v7 support yet.
+
+#option SYSCALL_DEBUG
+
+#option WSDISPLAY_COMPAT_USL # VT handling
+#option WSDISPLAY_COMPAT_RAWKBD # can get raw scancodes
+option WSDISPLAY_DEFAULTSCREENS=1
+#option WSDISPLAY_COMPAT_PCVT # emulate some ioctls
+
+config bsd root on rd0a swap on rd0b
+
+# The main bus device
+mainbus0 at root
+cpu0 at mainbus?
+
+# Cortex-A9 (iMX6)
+cortex0 at mainbus?
+ampintc* at cortex?
+amptimer* at cortex?
+armliicc* at cortex?
+
+# iMX SoC
+imx0 at mainbus?
+
+# iMX on-chip devices
+imxccm* at imx? # clock control module
+imxiomuxc* at imx? # iomux controller
+imxdog* at imx? # watchdog timer
+imxocotp* at imx? # on-chip otp controller
+imxgpio* at imx? # user-visible GPIO pins?
+imxesdhc* at imx? # SDHC controller
+imxenet* at imx? # ethernet
+imxuart* at imx? # onboard uarts
+imxiic* at imx? # i2c
+
+ahci* at imx? # AHCI/SATA
+
+ehci* at imx? # EHCI (shim)
+usb* at ehci?
+
+# USB bus support
+usb* at ehci? flags 0x1
+uhub* at usb?
+uhub* at uhub?
+
+uhub* at usb? # USB Hubs
+uhub* at uhub? # USB Hubs
+umodem* at uhub? # USB Modems/Serial
+ucom* at umodem?
+uvisor* at uhub? # Handspring Visor
+ucom* at uvisor?
+uvscom* at uhub? # SUNTAC Slipper U VS-10U serial
+ucom* at uvscom?
+ubsa* at uhub? # Belkin serial adapter
+ucom* at ubsa?
+uftdi* at uhub? # FTDI FT8U100AX serial adapter
+ucom* at uftdi?
+uplcom* at uhub? # I/O DATA USB-RSAQ2 serial adapter
+ucom* at uplcom?
+umct* at uhub? # MCT USB-RS232 serial adapter
+ucom* at umct?
+uaudio* at uhub? # USB Audio
+audio* at uaudio?
+umidi* at uhub? # USB MIDI
+midi* at umidi?
+ulpt* at uhub? # USB Printers
+umass* at uhub? # USB Mass Storage devices
+uhidev* at uhub? # Human Interface Devices
+ums* at uhidev? # USB mouse
+wsmouse* at ums? mux 0
+ukbd* at uhidev? # USB keyboard
+wskbd* at ukbd? mux 1
+uhid* at uhidev? # USB generic HID support
+aue* at uhub? # ADMtek AN986 Pegasus Ethernet
+atu* at uhub? # Atmel AT76c50x based 802.11b
+axe* at uhub? # ASIX Electronics AX88172 USB Ethernet
+cue* at uhub? # CATC USB-EL1201A based Ethernet
+kue* at uhub? # Kawasaki KL5KUSB101B based Ethernet
+smsc* at uhub? # SMSC LAN95xx Ethernet
+cdce* at uhub? # CDC Ethernet
+upl* at uhub? # Prolific PL2301/PL2302 host-to-host `network'
+udav* at uhub? # Davicom DM9601 based Ethernet
+url* at uhub? # Realtek RTL8150L based adapters
+wi* at uhub? # WaveLAN IEEE 802.11DS
+urio* at uhub? # Diamond Multimedia Rio 500
+#uyap* at uhub? # Y@P firmware loader
+udsbr* at uhub? # D-Link DSB-R100 radio
+radio* at udsbr? # USB radio
+#ubt* at uhub? disable # USB Bluetooth
+ugen* at uhub? # USB Generic driver
+
+ukphy* at mii? # "unknown" PHYs
+
+scsibus* at scsi?
+sd* at scsibus?
+st* at scsibus?
+cd* at scsibus?
+ch* at scsibus?
+uk* at scsibus?
+
+sdmmc* at imxesdhc? # SD/MMC bus
+
+# I2C bus support
+iic* at imxiic?
+
+# Pseudo-Devices
+#pseudo-device wsmux 2 # mouse & keyboard multiplexor
+#pseudo-device crypto 1
+pseudo-device loop 1 # network loopback
+pseudo-device bpfilter 1 # packet filter
+pseudo-device rd 1 # ram disk
+
+# RAMDISK stuff
+options MINIROOTSIZE=5120
+options RAMDISK_HOOKS
diff --git a/sys/arch/armv7/conf/files.armv7 b/sys/arch/armv7/conf/files.armv7
index 596d07ad382..9aeee82b9b2 100644
--- a/sys/arch/armv7/conf/files.armv7
+++ b/sys/arch/armv7/conf/files.armv7
@@ -1,4 +1,4 @@
-# $OpenBSD: files.armv7,v 1.2 2013/09/05 11:48:42 patrick Exp $
+# $OpenBSD: files.armv7,v 1.3 2013/09/06 20:45:53 patrick Exp $
maxpartitions 16
maxusers 2 8 64
@@ -57,4 +57,5 @@ include "dev/bluetooth/files.bluetooth"
include "dev/gpio/files.gpio"
# SoC includes
+include "arch/armv7/imx/files.imx"
include "arch/armv7/omap/files.omap"
diff --git a/sys/arch/armv7/imx/files.imx b/sys/arch/armv7/imx/files.imx
new file mode 100644
index 00000000000..a75f7414958
--- /dev/null
+++ b/sys/arch/armv7/imx/files.imx
@@ -0,0 +1,51 @@
+# $OpenBSD: files.imx,v 1.1 2013/09/06 20:45:53 patrick Exp $
+
+define imx {}
+device imx: imx
+attach imx at mainbus
+file arch/armv7/imx/imx_machdep.c imx
+file arch/armv7/imx/imx.c imx
+file arch/armv7/imx/imx6.c imx
+
+# serial ports
+device imxuart
+attach imxuart at imx
+file arch/armv7/imx/imxuart.c imxuart
+
+device imxccm
+attach imxccm at imx
+file arch/armv7/imx/imxccm.c imxccm
+
+device imxiomuxc
+attach imxiomuxc at imx
+file arch/armv7/imx/imxiomuxc.c imxiomuxc
+
+device imxdog
+attach imxdog at imx
+file arch/armv7/imx/imxdog.c imxdog
+
+device imxocotp
+attach imxocotp at imx
+file arch/armv7/imx/imxocotp.c imxocotp
+
+device imxgpio
+attach imxgpio at imx
+file arch/armv7/imx/imxgpio.c imxgpio
+
+device imxiic: i2cbus
+attach imxiic at imx
+file arch/armv7/imx/imxiic.c imxiic
+
+device imxenet: ether, ifnet, mii, ifmedia
+attach imxenet at imx
+file arch/armv7/imx/imxenet.c imxenet
+
+attach ehci at imx with imxehci
+file arch/armv7/imx/imxehci.c imxehci
+
+device imxesdhc: sdmmcbus
+attach imxesdhc at imx
+file arch/armv7/imx/imxesdhc.c imxesdhc
+
+attach ahci at imx with imxahci
+file arch/armv7/imx/imxahci.c imxahci
diff --git a/sys/arch/armv7/imx/imx.c b/sys/arch/armv7/imx/imx.c
new file mode 100644
index 00000000000..99014634976
--- /dev/null
+++ b/sys/arch/armv7/imx/imx.c
@@ -0,0 +1,201 @@
+/* $OpenBSD: imx.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/reboot.h>
+#define _ARM32_BUS_DMA_PRIVATE
+#include <machine/bus.h>
+#include <arch/arm/armv7/armv7var.h>
+#include <armv7/imx/imxvar.h>
+
+struct arm32_bus_dma_tag imx_bus_dma_tag = {
+ 0,
+ 0,
+ NULL,
+ _bus_dmamap_create,
+ _bus_dmamap_destroy,
+ _bus_dmamap_load,
+ _bus_dmamap_load_mbuf,
+ _bus_dmamap_load_uio,
+ _bus_dmamap_load_raw,
+ _bus_dmamap_unload,
+ _bus_dmamap_sync,
+ _bus_dmamem_alloc,
+ _bus_dmamem_free,
+ _bus_dmamem_map,
+ _bus_dmamem_unmap,
+ _bus_dmamem_mmap,
+};
+
+struct board_dev {
+ char *name;
+ int unit;
+};
+
+struct board_dev phyflex_imx6_devs[] = {
+ { "imxccm", 0 },
+ { "imxiomuxc", 0 },
+ { "imxdog", 0 },
+ { "imxocotp", 0 },
+ { "imxuart", 3 },
+ { "imxgpio", 0 },
+ { "imxgpio", 1 },
+ { "imxgpio", 2 },
+ { "imxgpio", 3 },
+ { "imxgpio", 4 },
+ { "imxgpio", 5 },
+ { "imxgpio", 6 },
+ { "imxesdhc", 1 },
+ { "imxesdhc", 2 },
+ { "ehci", 0 },
+ { "imxenet", 0 },
+ { "ahci", 0 },
+ { NULL, 0 }
+};
+
+struct board_dev sabrelite_devs[] = {
+ { "imxccm", 0 },
+ { "imxiomuxc", 0 },
+ { "imxdog", 0 },
+ { "imxocotp", 0 },
+ { "imxuart", 1 },
+ { "imxgpio", 0 },
+ { "imxgpio", 1 },
+ { "imxgpio", 2 },
+ { "imxgpio", 3 },
+ { "imxgpio", 4 },
+ { "imxgpio", 5 },
+ { "imxgpio", 6 },
+ { "imxesdhc", 2 },
+ { "imxesdhc", 3 },
+ { "ehci", 0 },
+ { "imxenet", 0 },
+ { "ahci", 0 },
+ { NULL, 0 }
+};
+
+struct board_dev *board_devs;
+
+struct imx_dev *imx_devs = NULL;
+
+struct imx_softc {
+ struct device sc_dv;
+};
+
+int imx_match(struct device *, void *, void *);
+void imx_attach(struct device *, struct device *, void *);
+int imx_submatch(struct device *, void *, void *);
+
+struct cfattach imx_ca = {
+ sizeof(struct imx_softc), imx_match, imx_attach, NULL,
+ config_activate_children
+};
+
+struct cfdriver imx_cd = {
+ NULL, "imx", DV_DULL
+};
+
+int
+imx_match(struct device *parent, void *cfdata, void *aux)
+{
+ return (1);
+}
+
+void
+imx_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct board_dev *bd;
+
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ printf(": PhyFLEX-i.MX6\n");
+ imx6_init();
+ board_devs = phyflex_imx6_devs;
+ break;
+ case BOARD_ID_IMX6_SABRELITE:
+ printf(": i.MX6 SABRE Lite\n");
+ imx6_init();
+ board_devs = sabrelite_devs;
+ break;
+ default:
+ printf("\n");
+ panic("%s: board type 0x%x unknown", __func__, board_id);
+ }
+
+ /* Directly configure on-board devices (dev* in config file). */
+ for (bd = board_devs; bd->name != NULL; bd++) {
+ struct imx_dev *id = imx_find_dev(bd->name, bd->unit);
+ struct imx_attach_args ia;
+
+ if (id == NULL)
+ printf("%s: device %s unit %d not found\n",
+ self->dv_xname, bd->name, bd->unit);
+
+ memset(&ia, 0, sizeof(ia));
+ ia.ia_dev = id;
+ ia.ia_iot = &armv7_bs_tag;
+ ia.ia_dmat = &imx_bus_dma_tag;
+
+ if (config_found_sm(self, &ia, NULL, imx_submatch) == NULL)
+ printf("%s: device %s unit %d not configured\n",
+ self->dv_xname, bd->name, bd->unit);
+ }
+}
+
+/*
+ * We do direct configuration of devices on this SoC "bus", so we
+ * never call the child device's match function at all (it can be
+ * NULL in the struct cfattach).
+ */
+int
+imx_submatch(struct device *parent, void *child, void *aux)
+{
+ struct cfdata *cf = child;
+ struct imx_attach_args *ia = aux;
+
+ if (strcmp(cf->cf_driver->cd_name, ia->ia_dev->name) == 0)
+ return (1);
+
+ /* "These are not the droids you are looking for." */
+ return (0);
+}
+
+void
+imx_set_devs(struct imx_dev *devs)
+{
+ imx_devs = devs;
+}
+
+struct imx_dev *
+imx_find_dev(const char *name, int unit)
+{
+ struct imx_dev *id;
+
+ if (imx_devs == NULL)
+ panic("%s: imx_devs == NULL", __func__);
+
+ for (id = imx_devs; id->name != NULL; id++) {
+ if (id->unit == unit && strcmp(id->name, name) == 0)
+ return (id);
+ }
+
+ return (NULL);
+}
diff --git a/sys/arch/armv7/imx/imx6.c b/sys/arch/armv7/imx/imx6.c
new file mode 100644
index 00000000000..75e69a3aebd
--- /dev/null
+++ b/sys/arch/armv7/imx/imx6.c
@@ -0,0 +1,345 @@
+/* $OpenBSD: imx6.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org>
+ * Copyright (c) 2012 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <machine/bus.h>
+#include <arch/arm/armv7/armv7var.h>
+
+#include <armv7/imx/imxvar.h>
+
+/* IRQs are defined without the 32 cpu IRQs */
+
+#define CCM_ADDR 0x020c4000
+#define CCM_SIZE 0x5000
+
+#define CCM_IRQ1 87
+#define CCM_IRQ2 88
+
+#define ANALOG_ADDR 0x020c8000
+#define ANALOG_SIZE 0x1000
+
+#define IOMUXC_ADDR 0x020e0000
+#define IOMUXC_SIZE 0x4000
+
+#define WD1_ADDR 0x020bc000
+#define WD1_SIZE 0x400
+#define WD2_ADDR 0x020c0000
+#define WD2_SIZE 0x400
+
+#define OCOTP_ADDR 0x021bc000
+#define OCOTP_SIZE 0x4000
+
+#define UARTx_SIZE 0x4000
+#define UART1_ADDR 0x02020000
+#define UART2_ADDR 0x021e8000
+#define UART3_ADDR 0x021ec000
+#define UART4_ADDR 0x021f0000
+#define UART5_ADDR 0x021f4000
+
+#define UART1_IRQ 26
+#define UART2_IRQ 27
+#define UART3_IRQ 28
+#define UART4_IRQ 29
+#define UART5_IRQ 30
+
+#define USBPHYx_SIZE 0x1000
+#define USBPHY1_ADDR 0x020c9000
+#define USBPHY2_ADDR 0x020ca000
+#define USBOTG_ADDR 0x02184000
+#define USBOTG_EHCI_ADDR 0x02184100
+#define USBUH1_ADDR 0x02184200
+#define USBUH1_EHCI_ADDR 0x02184300
+#define USBUH2_ADDR 0x02184400
+#define USBUH2_EHCI_ADDR 0x02184500
+#define USBUH3_ADDR 0x02184600
+#define USBUH3_EHCI_ADDR 0x02184700
+#define USBNC_ADDR 0x02184800
+#define USBx_SIZE 0x100
+
+#define USBH1_IRQ 40
+#define USBH2_IRQ 41
+#define USBH3_IRQ 42
+#define USBOTG_IRQ 43
+#define USBPHY0_IRQ 44
+#define USBPHY1_IRQ 45
+
+#define GPIOx_SIZE 0x4000
+#define GPIO1_ADDR 0x0209c000
+#define GPIO2_ADDR 0x020a0000
+#define GPIO3_ADDR 0x020a4000
+#define GPIO4_ADDR 0x020a8000
+#define GPIO5_ADDR 0x020ac000
+#define GPIO6_ADDR 0x020b0000
+#define GPIO7_ADDR 0x020b4000
+
+#define GPIO1_IRQ7 58
+#define GPIO1_IRQ6 59
+#define GPIO1_IRQ5 60
+#define GPIO1_IRQ4 61
+#define GPIO1_IRQ3 62
+#define GPIO1_IRQ2 63
+#define GPIO1_IRQ1 64
+#define GPIO1_IRQ0 65
+#define GPIO1_IRQ16 66
+#define GPIO1_IRQ32 67
+#define GPIO2_IRQ16 68
+#define GPIO2_IRQ32 69
+#define GPIO3_IRQ16 70
+#define GPIO3_IRQ32 71
+#define GPIO4_IRQ16 72
+#define GPIO4_IRQ32 73
+#define GPIO5_IRQ16 74
+#define GPIO5_IRQ32 75
+#define GPIO6_IRQ16 76
+#define GPIO6_IRQ32 77
+#define GPIO7_IRQ16 78
+#define GPIO7_IRQ32 79
+
+#define I2Cx_SIZE 0x4000
+#define I2C1_ADDR 0x021a0000
+#define I2C2_ADDR 0x021a4000
+#define I2C3_ADDR 0x021a8000
+
+#define I2C1_IRQ 36
+#define I2C2_IRQ 37
+#define I2C3_IRQ 38
+
+#define ESDHCx_SIZE 0x4000
+#define ESDHC1_ADDR 0x02190000
+#define ESDHC2_ADDR 0x02194000
+#define ESDHC3_ADDR 0x02198000
+#define ESDHC4_ADDR 0x0219c000
+
+#define ESDHC1_IRQ 22
+#define ESDHC2_IRQ 23
+#define ESDHC3_IRQ 24
+#define ESDHC4_IRQ 25
+
+#define ENET_ADDR 0x02188000
+#define ENET_SIZE 0x4000
+
+#define ENET_IRQ0 118
+#define ENET_IRQ1 119
+
+#define SATA_ADDR 0x02200000
+#define SATA_SIZE 0x4000
+
+#define SATA_IRQ 39
+
+#define PCIE_REG_ADDR 0x01ffc000
+#define PCIE_REG_SIZE 0x4000
+#define PCIE_MAP_ADDR 0x01000000
+#define PCIE_MAP_SIZE 0xffc000
+
+#define PCIE_IRQ0 120
+#define PCIE_IRQ1 121
+#define PCIE_IRQ2 122
+#define PCIE_IRQ3 123
+
+struct imx_dev imx6_devs[] = {
+
+ /*
+ * Clock Control Module
+ */
+ { .name = "imxccm",
+ .unit = 0,
+ .mem = { { CCM_ADDR, CCM_SIZE } },
+ },
+
+ /*
+ * IOMUX Controller
+ */
+ { .name = "imxiomuxc",
+ .unit = 0,
+ .mem = { { IOMUXC_ADDR, IOMUXC_SIZE } },
+ },
+
+ /*
+ * Watchdog Timer
+ */
+ { .name = "imxdog",
+ .unit = 0,
+ .mem = {
+ { WD1_ADDR, WD1_SIZE },
+ { WD2_ADDR, WD2_SIZE },
+ },
+ },
+
+ /*
+ * On-Chip OTP Controller
+ */
+ { .name = "imxocotp",
+ .unit = 0,
+ .mem = { { OCOTP_ADDR, OCOTP_SIZE } },
+ },
+
+ /*
+ * UART
+ */
+ { .name = "imxuart",
+ .unit = 0,
+ .mem = { { UART1_ADDR, UARTx_SIZE } },
+ .irq = { UART1_IRQ }
+ },
+ { .name = "imxuart",
+ .unit = 1,
+ .mem = { { UART2_ADDR, UARTx_SIZE } },
+ .irq = { UART2_IRQ }
+ },
+ { .name = "imxuart",
+ .unit = 2,
+ .mem = { { UART3_ADDR, UARTx_SIZE } },
+ .irq = { UART3_IRQ }
+ },
+ { .name = "imxuart",
+ .unit = 3,
+ .mem = { { UART4_ADDR, UARTx_SIZE } },
+ .irq = { UART4_IRQ }
+ },
+ { .name = "imxuart",
+ .unit = 4,
+ .mem = { { UART5_ADDR, UARTx_SIZE } },
+ .irq = { UART5_IRQ }
+ },
+
+ /*
+ * GPIO
+ */
+ { .name = "imxgpio",
+ .unit = 0,
+ .mem = { { GPIO1_ADDR, GPIOx_SIZE } },
+ },
+
+ { .name = "imxgpio",
+ .unit = 1,
+ .mem = { { GPIO2_ADDR, GPIOx_SIZE } },
+ },
+
+ { .name = "imxgpio",
+ .unit = 2,
+ .mem = { { GPIO3_ADDR, GPIOx_SIZE } },
+ },
+
+ { .name = "imxgpio",
+ .unit = 3,
+ .mem = { { GPIO4_ADDR, GPIOx_SIZE } },
+ },
+
+ { .name = "imxgpio",
+ .unit = 4,
+ .mem = { { GPIO5_ADDR, GPIOx_SIZE } },
+ },
+
+ { .name = "imxgpio",
+ .unit = 5,
+ .mem = { { GPIO6_ADDR, GPIOx_SIZE } },
+ },
+
+ { .name = "imxgpio",
+ .unit = 6,
+ .mem = { { GPIO7_ADDR, GPIOx_SIZE } },
+ },
+
+ /*
+ * I2C
+ */
+ { .name = "imxiic",
+ .unit = 0,
+ .mem = { { I2C1_ADDR, I2Cx_SIZE } },
+ .irq = { I2C1_IRQ },
+ },
+
+ { .name = "imxiic",
+ .unit = 1,
+ .mem = { { I2C2_ADDR, I2Cx_SIZE } },
+ .irq = { I2C2_IRQ },
+ },
+
+ { .name = "imxiic",
+ .unit = 2,
+ .mem = { { I2C3_ADDR, I2Cx_SIZE } },
+ .irq = { I2C3_IRQ },
+ },
+
+ /*
+ * ESDHC
+ */
+ { .name = "imxesdhc",
+ .unit = 0,
+ .mem = { { ESDHC1_ADDR, ESDHCx_SIZE } },
+ .irq = { ESDHC1_IRQ },
+ },
+
+ { .name = "imxesdhc",
+ .unit = 1,
+ .mem = { { ESDHC2_ADDR, ESDHCx_SIZE } },
+ .irq = { ESDHC2_IRQ },
+ },
+
+ { .name = "imxesdhc",
+ .unit = 2,
+ .mem = { { ESDHC3_ADDR, ESDHCx_SIZE } },
+ .irq = { ESDHC3_IRQ },
+ },
+
+ { .name = "imxesdhc",
+ .unit = 3,
+ .mem = { { ESDHC4_ADDR, ESDHCx_SIZE } },
+ .irq = { ESDHC4_IRQ },
+ },
+
+ /*
+ * USB
+ */
+ { .name = "ehci",
+ .unit = 0,
+ .mem = {
+ { USBUH1_EHCI_ADDR, USBx_SIZE },
+ { USBUH1_ADDR, USBx_SIZE },
+ { USBPHY2_ADDR, USBPHYx_SIZE },
+ { USBNC_ADDR, USBx_SIZE },
+ },
+ .irq = { USBH1_IRQ }
+ },
+
+ /*
+ * Ethernet
+ */
+ { .name = "imxenet",
+ .unit = 0,
+ .mem = { { ENET_ADDR, ENET_SIZE } },
+ .irq = { ENET_IRQ0, ENET_IRQ1 }
+ },
+
+ /*
+ * AHCI compatible SATA controller
+ */
+ { .name = "ahci",
+ .unit = 0,
+ .mem = { { SATA_ADDR, SATA_SIZE } },
+ .irq = { SATA_IRQ }
+ },
+};
+
+void
+imx6_init(void)
+{
+ imx_set_devs(imx6_devs);
+}
diff --git a/sys/arch/armv7/imx/imx_machdep.c b/sys/arch/armv7/imx/imx_machdep.c
new file mode 100644
index 00000000000..a5a135253c1
--- /dev/null
+++ b/sys/arch/armv7/imx/imx_machdep.c
@@ -0,0 +1,982 @@
+/* $OpenBSD: imx_machdep.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/* $NetBSD: lubbock_machdep.c,v 1.2 2003/07/15 00:25:06 lukem Exp $ */
+
+/*
+ * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved.
+ * Written by Hiroyuki Bessho for Genetec Corporation.
+ *
+ * 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.
+ * 3. The name of Genetec Corporation may not be used to endorse or
+ * promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION
+ * 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.
+ *
+ * Machine dependant functions for kernel setup for
+ * Intel DBPXA250 evaluation board (a.k.a. Lubbock).
+ * Based on iq80310_machhdep.c
+ */
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Jason R. Thorpe for Wasabi Systems, Inc.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
+ * 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.
+ */
+
+/*
+ * Copyright (c) 1997,1998 Mark Brinicombe.
+ * Copyright (c) 1997,1998 Causality Limited.
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by Mark Brinicombe
+ * for the NetBSD Project.
+ * 4. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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.
+ *
+ * Machine dependant functions for kernel setup for Intel IQ80310 evaluation
+ * boards using RedBoot firmware.
+ */
+
+/*
+ * DIP switches:
+ *
+ * S19: no-dot: set RB_KDB. enter kgdb session.
+ * S20: no-dot: set RB_SINGLE. don't go multi user mode.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/exec.h>
+#include <sys/proc.h>
+#include <sys/msgbuf.h>
+#include <sys/reboot.h>
+#include <sys/termios.h>
+
+#include <uvm/uvm_extern.h>
+
+#include <sys/conf.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <dev/cons.h>
+#include <dev/ic/smc91cxxreg.h>
+
+#include <machine/db_machdep.h>
+#include <ddb/db_sym.h>
+#include <ddb/db_extern.h>
+
+#include <machine/bootconfig.h>
+#include <machine/bus.h>
+#include <machine/cpu.h>
+#include <machine/frame.h>
+#include <arm/undefined.h>
+#include <arm/machdep.h>
+
+#include <arm/armv7/armv7reg.h>
+#include <arm/armv7/armv7var.h>
+
+#include <arm/cortex/smc.h>
+#include <machine/machine_reg.h>
+#include <armv7/imx/imxvar.h>
+
+#include "wsdisplay.h"
+
+/* Kernel text starts 2MB in from the bottom of the kernel address space. */
+#define KERNEL_TEXT_BASE (KERNEL_BASE + 0x00000000)
+#define KERNEL_VM_BASE (KERNEL_BASE + 0x04000000)
+
+/*
+ * The range 0xc1000000 - 0xccffffff is available for kernel VM space
+ * Core-logic registers and I/O mappings occupy 0xfd000000 - 0xffffffff
+ */
+/*
+#define KERNEL_VM_SIZE 0x0C000000
+*/
+#define KERNEL_VM_SIZE 0x10000000
+
+
+/*
+ * Address to call from cpu_reset() to reset the machine.
+ * This is machine architecture dependant as it varies depending
+ * on where the ROM appears when you turn the MMU off.
+ */
+
+u_int cpu_reset_address = 0;
+
+/* Define various stack sizes in pages */
+#define IRQ_STACK_SIZE 1
+#define ABT_STACK_SIZE 1
+#ifdef IPKDB
+#define UND_STACK_SIZE 2
+#else
+#define UND_STACK_SIZE 1
+#endif
+
+BootConfig bootconfig; /* Boot config storage */
+char *boot_args = NULL;
+char *boot_file = "";
+
+vaddr_t physical_start;
+vaddr_t physical_freestart;
+vaddr_t physical_freeend;
+vaddr_t physical_end;
+u_int free_pages;
+vaddr_t pagetables_start;
+int physmem = 0;
+
+/*int debug_flags;*/
+#ifndef PMAP_STATIC_L1S
+int max_processes = 64; /* Default number */
+#endif /* !PMAP_STATIC_L1S */
+
+/* Physical and virtual addresses for some global pages */
+pv_addr_t systempage;
+pv_addr_t irqstack;
+pv_addr_t undstack;
+pv_addr_t abtstack;
+extern pv_addr_t kernelstack;
+pv_addr_t minidataclean;
+
+vaddr_t msgbufphys;
+
+extern u_int data_abort_handler_address;
+extern u_int prefetch_abort_handler_address;
+extern u_int undefined_handler_address;
+
+#ifdef PMAP_DEBUG
+extern int pmap_debug_level;
+#endif
+
+uint32_t board_id;
+
+#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */
+#define KERNEL_PT_KERNEL 1 /* Page table for mapping kernel */
+#define KERNEL_PT_KERNEL_NUM 32
+#define KERNEL_PT_VMDATA (KERNEL_PT_KERNEL+KERNEL_PT_KERNEL_NUM)
+ /* Page tables for mapping kernel VM */
+#define KERNEL_PT_VMDATA_NUM 8 /* start with 16MB of KVM */
+#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM)
+
+pv_addr_t kernel_pt_table[NUM_KERNEL_PTS];
+
+extern struct user *proc0paddr;
+
+/*
+ * safepri is a safe priority for sleep to set for a spin-wait
+ * during autoconfiguration or after a panic.
+ */
+int safepri = 0;
+
+/* Prototypes */
+
+void imxdog_reset(void);
+void imx_powerdown(void);
+void imx_reset(void);
+
+char bootargs[MAX_BOOT_STRING];
+void process_kernel_args(char *);
+
+void consinit(void);
+void early_clkman(u_int, int);
+void kgdb_port_init(void);
+void change_clock(uint32_t v);
+
+bs_protos(bs_notimpl);
+
+#include <armv7/imx/imxuartvar.h>
+#include "com.h"
+#if NCOM > 0
+#include <dev/ic/comreg.h>
+#include <dev/ic/comvar.h>
+#endif
+
+#ifndef CONSPEED
+#define CONSPEED B115200 /* What u-boot */
+#endif
+#ifndef CONMODE
+#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */
+#endif
+
+int comcnspeed = CONSPEED;
+int comcnmode = CONMODE;
+
+extern int32_t amptimer_frequency;
+
+/*
+ *
+ */
+void
+imx_powerdown(void)
+{
+}
+
+/*
+ * void boot(int howto, char *bootstr)
+ *
+ * Reboots the system
+ *
+ * Deal with any syncing, unmounting, dumping and shutdown hooks,
+ * then reset the CPU.
+ */
+void
+boot(int howto)
+{
+#ifdef DIAGNOSTIC
+ /* info */
+ printf("boot: howto=%08x curproc=%p\n", howto, curproc);
+#endif
+
+ /*
+ * If we are still cold then hit the air brakes
+ * and crash to earth fast
+ */
+ if (cold) {
+ doshutdownhooks();
+ if ((howto & (RB_HALT | RB_USERREQ)) != RB_USERREQ) {
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ }
+ printf("rebooting...\n");
+ delay(500000);
+ imxdog_reset();
+ printf("reboot failed; spinning\n");
+ while(1);
+ /*NOTREACHED*/
+ }
+
+ /* Disable console buffering */
+/* cnpollc(1);*/
+
+ /*
+ * If RB_NOSYNC was not specified sync the discs.
+ * Note: Unless cold is set to 1 here, syslogd will die during the
+ * unmount. It looks like syslogd is getting woken up only to find
+ * that it cannot page part of the binary in as the filesystem has
+ * been unmounted.
+ */
+ if (!(howto & RB_NOSYNC))
+ bootsync(howto);
+
+ /* Say NO to interrupts */
+ splhigh();
+
+ /* Do a dump if requested. */
+ if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP)
+ dumpsys();
+
+ /* Run any shutdown hooks */
+ doshutdownhooks();
+ config_suspend(TAILQ_FIRST(&alldevs), DVACT_POWERDOWN);
+
+ /* Make sure IRQ's are disabled */
+ IRQdisable;
+
+ if (howto & RB_HALT) {
+ if (howto & RB_POWERDOWN) {
+
+ printf("\nAttempting to power down...\n");
+ delay(500000);
+ imx_powerdown();
+ }
+
+ printf("The operating system has halted.\n");
+ printf("Please press any key to reboot.\n\n");
+ cngetc();
+ }
+
+ printf("rebooting...\n");
+ delay(500000);
+ imxdog_reset();
+ printf("reboot failed; spinning\n");
+ while(1);
+ /*NOTREACHED*/
+}
+
+static __inline
+pd_entry_t *
+read_ttb(void)
+{
+ long ttb;
+
+ __asm __volatile("mrc p15, 0, %0, c2, c0, 0" : "=r" (ttb));
+
+
+ return (pd_entry_t *)(ttb & ~((1<<14)-1));
+}
+
+#if 1
+#define VERBOSE_INIT_ARM
+#endif
+
+/*
+ * simple memory mapping function used in early bootstrap stage
+ * before pmap is initialized.
+ * size and cacheability are ignored and map one section with nocache.
+ */
+static vaddr_t section_free = 0xfd000000; /* XXX - huh */
+
+int bootstrap_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp);
+int
+bootstrap_bs_map(void *t, bus_addr_t bpa, bus_size_t size,
+ int flags, bus_space_handle_t *bshp)
+{
+ u_long startpa;
+ vaddr_t va;
+ pd_entry_t *pagedir = read_ttb();
+ /* This assumes PA==VA for page directory */
+
+ va = section_free;
+ section_free += L1_S_SIZE;
+
+ /*
+ startpa = trunc_page(bpa);
+ */
+ startpa = bpa & ~L1_S_OFFSET;
+ pmap_map_section((vaddr_t)pagedir, va, startpa,
+ VM_PROT_READ | VM_PROT_WRITE, PTE_NOCACHE);
+ cpu_tlb_flushD();
+
+ *bshp = (bus_space_handle_t)(va + (bpa - startpa));
+
+ return(0);
+}
+
+static void
+copy_io_area_map(pd_entry_t *new_pd)
+{
+ pd_entry_t *cur_pd = read_ttb();
+ vaddr_t va;
+
+ for (va = MACHINE_IO_AREA_VBASE;
+ (cur_pd[va>>L1_S_SHIFT] & L1_TYPE_MASK) == L1_TYPE_S;
+ va += L1_S_SIZE) {
+
+ new_pd[va>>L1_S_SHIFT] = cur_pd[va>>L1_S_SHIFT];
+ if (va == (ARM_VECTORS_HIGH & ~(0x00400000 - 1)))
+ break; /* STUPID */
+
+ }
+}
+
+void parse_uboot_tags(void *);
+void imx_reset() {
+ uint16_t* wcr = (uint16_t*)0x020bc000;
+ uint16_t* wsr = (uint16_t*)0x020bc002;
+ *wcr = 0;
+ *wsr = 0x5555;
+ *wsr = 0xaaaa;
+ *wcr = 1;
+ *wcr = 1;
+}
+
+/*
+ * u_int initarm(...)
+ *
+ * Initial entry point on startup. This gets called before main() is
+ * entered.
+ * It should be responsible for setting up everything that must be
+ * in place when main is called.
+ * This includes
+ * Taking a copy of the boot configuration structure.
+ * Initialising the physical console so characters can be printed.
+ * Setting up page tables for the kernel
+ * Relocating the kernel to the bottom of physical memory
+ */
+u_int
+initarm(void *arg0, void *arg1, void *arg2)
+{
+ int loop;
+ int loop1;
+ u_int l1pagetable;
+ pv_addr_t kernel_l1pt;
+ paddr_t memstart;
+ psize_t memsize;
+
+#if 0
+ int led_data = 0;
+#endif
+ /* early bus_space_map support */
+ struct bus_space tmp_bs_tag;
+ int (*map_func_save)(void *, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+
+ board_id = (uint32_t)arg1;
+
+ /*
+ * Heads up ... Setup the CPU / MMU / TLB functions
+ */
+ if (set_cpufuncs())
+ panic("cpu not recognized!");
+
+#if 0
+ /* Calibrate the delay loop. */
+#endif
+
+ /*
+ * Temporarily replace bus_space_map() functions so that
+ * console devices can get mapped.
+ *
+ * Note that this relies upon the fact that both regular
+ * and a4x bus_space tags use the same map function.
+ */
+#if defined(CPU_ARMv7)
+ tmp_bs_tag = armv7_bs_tag;
+ map_func_save = armv7_bs_tag.bs_map;
+ armv7_bs_tag.bs_map = bootstrap_bs_map;
+ armv7_a4x_bs_tag.bs_map = bootstrap_bs_map;
+#endif
+ tmp_bs_tag.bs_map = bootstrap_bs_map;
+
+ /* setup a serial console for very early boot */
+ consinit();
+
+ /* Talk to the user */
+ printf("\nOpenBSD/imx booting ...\n");
+
+ printf("arg0 %p arg1 %p arg2 %p\n", arg0, arg1, arg2);
+ parse_uboot_tags(arg2);
+
+ /*
+ * Examine the boot args string for options we need to know about
+ * now.
+ */
+ process_kernel_args(bootconfig.bootstring);
+#ifdef RAMDISK_HOOKS
+ boothowto |= RB_DFLTROOT;
+#endif /* RAMDISK_HOOKS */
+
+ /* normally u-boot will set up bootconfig.dramblocks */
+ if (bootconfig.dramblocks == 0) {
+ memstart = SDRAM_START;
+ memsize = 0x10000000; /* 256 MB */
+ /* Fake bootconfig structure for the benefit of pmap.c */
+ /* XXX must make the memory description h/w independant */
+ bootconfig.dram[0].address = memstart;
+ bootconfig.dram[0].pages = memsize / PAGE_SIZE;
+ bootconfig.dramblocks = 1;
+ } else {
+ memstart = bootconfig.dram[0].address;
+ memsize = bootconfig.dram[0].pages * PAGE_SIZE;
+ }
+
+ /*
+ * Set up the variables that define the availablilty of
+ * physical memory. For now, we're going to set
+ * physical_freestart to 0xa0200000 (where the kernel
+ * was loaded), and allocate the memory we need downwards.
+ * If we get too close to the page tables that RedBoot
+ * set up, we will panic. We will update physical_freestart
+ * and physical_freeend later to reflect what pmap_bootstrap()
+ * wants to see.
+ *
+ * XXX pmap_bootstrap() needs an enema.
+ */
+ physical_start = bootconfig.dram[0].address;
+ physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE);
+
+ {
+ extern char _end[];
+ physical_freestart = (((unsigned long)_end - KERNEL_TEXT_BASE +0xfff) & ~0xfff) + memstart;
+ physical_freeend = memstart+memsize;
+ }
+
+ physmem = (physical_end - physical_start) / PAGE_SIZE;
+
+#ifdef DEBUG
+ /* Tell the user about the memory */
+ printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem,
+ physical_start, physical_end - 1);
+#endif
+
+ /*
+ * Okay, the kernel starts 2MB in from the bottom of physical
+ * memory. We are going to allocate our bootstrap pages downwards
+ * from there.
+ *
+ * We need to allocate some fixed page tables to get the kernel
+ * going. We allocate one page directory and a number of page
+ * tables and store the physical addresses in the kernel_pt_table
+ * array.
+ *
+ * The kernel page directory must be on a 16K boundary. The page
+ * tables must be on 4K bounaries. What we do is allocate the
+ * page directory on the first 16K boundary that we encounter, and
+ * the page tables on 4K boundaries otherwise. Since we allocate
+ * at least 3 L2 page tables, we are guaranteed to encounter at
+ * least one 16K aligned region.
+ */
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Allocating page tables\n");
+#endif
+
+ free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE;
+
+#ifdef VERBOSE_INIT_ARM
+ printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n",
+ physical_freestart, free_pages, free_pages);
+#endif
+
+ /* Define a macro to simplify memory allocation */
+#define valloc_pages(var, np) \
+ alloc_pages((var).pv_pa, (np)); \
+ (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start;
+
+#define alloc_pages(var, np) \
+ (var) = physical_freestart; \
+ physical_freestart += ((np) * PAGE_SIZE); \
+ if (physical_freeend < physical_freestart) \
+ panic("initarm: out of memory"); \
+ free_pages -= (np); \
+ memset((char *)(var), 0, ((np) * PAGE_SIZE));
+
+ loop1 = 0;
+ kernel_l1pt.pv_pa = 0;
+ for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) {
+ /* Are we 16KB aligned for an L1 ? */
+ if (((physical_freestart) & (L1_TABLE_SIZE - 1)) == 0
+ && kernel_l1pt.pv_pa == 0) {
+ valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE);
+ } else {
+ valloc_pages(kernel_pt_table[loop1],
+ L2_TABLE_SIZE / PAGE_SIZE);
+ ++loop1;
+ }
+ }
+
+ /* This should never be able to happen but better confirm that. */
+ if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0)
+ panic("initarm: Failed to align the kernel page directory");
+
+ /*
+ * Allocate a page for the system page mapped to V0x00000000
+ * This page will just contain the system vectors and can be
+ * shared by all processes.
+ */
+ vector_page = ARM_VECTORS_HIGH;
+ alloc_pages(systempage.pv_pa, 1);
+ systempage.pv_va = vector_page;
+
+ /* Allocate stacks for all modes */
+ valloc_pages(irqstack, IRQ_STACK_SIZE);
+ valloc_pages(abtstack, ABT_STACK_SIZE);
+ valloc_pages(undstack, UND_STACK_SIZE);
+ valloc_pages(kernelstack, UPAGES);
+
+ /* Allocate enough pages for cleaning the Mini-Data cache. */
+
+#ifdef VERBOSE_INIT_ARM
+ printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa,
+ irqstack.pv_va);
+ printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa,
+ abtstack.pv_va);
+ printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa,
+ undstack.pv_va);
+ printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa,
+ kernelstack.pv_va);
+#endif
+
+ /*
+ * XXX Defer this to later so that we can reclaim the memory
+ * XXX used by the RedBoot page tables.
+ */
+ alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE);
+
+ /*
+ * Ok we have allocated physical pages for the primary kernel
+ * page tables
+ */
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa);
+#endif
+
+ /*
+ * Now we start construction of the L1 page table
+ * We start by mapping the L2 page tables into the L1.
+ * This means that we can replace L1 mappings later on if necessary
+ */
+ l1pagetable = kernel_l1pt.pv_pa;
+
+ /* Map the L2 pages tables in the L1 page table */
+ pmap_link_l2pt(l1pagetable, vector_page & ~(0x00400000 - 1),
+ &kernel_pt_table[KERNEL_PT_SYS]);
+
+ for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++)
+ pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000,
+ &kernel_pt_table[KERNEL_PT_KERNEL + loop]);
+
+ for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++)
+ pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000,
+ &kernel_pt_table[KERNEL_PT_VMDATA + loop]);
+
+ /* update the top of the kernel VM */
+ pmap_curmaxkvaddr =
+ KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000);
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Mapping kernel\n");
+#endif
+
+ /* Now we fill in the L2 pagetable for the kernel static code/data */
+ {
+ extern char etext[], _end[];
+ size_t textsize = (u_int32_t) etext - KERNEL_TEXT_BASE;
+ size_t totalsize = (u_int32_t) _end - KERNEL_TEXT_BASE;
+ u_int logical;
+
+ textsize = (textsize + PGOFSET) & ~PGOFSET;
+ totalsize = (totalsize + PGOFSET) & ~PGOFSET;
+
+ logical = 0x00000000; /* offset of kernel in RAM */
+
+ logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical,
+ physical_start + logical, textsize,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+ logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical,
+ physical_start + logical, totalsize - textsize,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ }
+
+#ifdef VERBOSE_INIT_ARM
+ printf("Constructing L2 page tables\n");
+#endif
+
+ /* Map the stack pages */
+ pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa,
+ IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa,
+ ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa,
+ UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE);
+ pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa,
+ UPAGES * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE);
+
+ pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa,
+ L1_TABLE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_PAGETABLE);
+
+ for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) {
+ pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va,
+ kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE,
+ VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE);
+ }
+
+ /* Map the Mini-Data cache clean area. */
+
+ /* Map the vector page. */
+#if 0
+ /* MULTI-ICE requires that page 0 is NC/NB so that it can download the
+ * cache-clean code there. */
+ pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_NOCACHE);
+#else
+ pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa,
+ VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE);
+#endif
+
+ /*
+ * map integrated peripherals at same address in l1pagetable
+ * so that we can continue to use console.
+ */
+ copy_io_area_map((pd_entry_t *)l1pagetable);
+
+
+ /*
+ * Now we have the real page tables in place so we can switch to them.
+ * Once this is done we will be running with the REAL kernel page
+ * tables.
+ */
+
+ /* be a client to all domains */
+ cpu_domains(0x55555555);
+ /* Switch tables */
+
+ cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT);
+ setttb(kernel_l1pt.pv_pa);
+ cpu_tlb_flushID();
+ cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2));
+
+ /*
+ * Moved from cpu_startup() as data_abort_handler() references
+ * this during uvm init
+ */
+ proc0paddr = (struct user *)kernelstack.pv_va;
+ proc0.p_addr = proc0paddr;
+
+ arm32_vector_init(vector_page, ARM_VEC_ALL);
+
+ /*
+ * Pages were allocated during the secondary bootstrap for the
+ * stacks for different CPU modes.
+ * We must now set the r13 registers in the different CPU modes to
+ * point to these stacks.
+ * Since the ARM stacks use STMFD etc. we must set r13 to the top end
+ * of the stack memory.
+ */
+
+ set_stackptr(PSR_IRQ32_MODE,
+ irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE);
+ set_stackptr(PSR_ABT32_MODE,
+ abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE);
+ set_stackptr(PSR_UND32_MODE,
+ undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE);
+
+ /*
+ * Well we should set a data abort handler.
+ * Once things get going this will change as we will need a proper
+ * handler.
+ * Until then we will use a handler that just panics but tells us
+ * why.
+ * Initialisation of the vectors will just panic on a data abort.
+ * This just fills in a slighly better one.
+ */
+
+ data_abort_handler_address = (u_int)data_abort_handler;
+ prefetch_abort_handler_address = (u_int)prefetch_abort_handler;
+ undefined_handler_address = (u_int)undefinedinstruction_bounce;
+
+ /* Initialise the undefined instruction handlers */
+#ifdef VERBOSE_INIT_ARM
+ printf("undefined ");
+#endif
+ undefined_init();
+
+ /* Load memory into UVM. */
+#ifdef VERBOSE_INIT_ARM
+ printf("page ");
+#endif
+ uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */
+ uvm_page_physload(atop(physical_freestart), atop(physical_freeend),
+ atop(physical_freestart), atop(physical_freeend), 0);
+
+ /* Boot strap pmap telling it where the kernel page table is */
+#ifdef VERBOSE_INIT_ARM
+ printf("pmap ");
+#endif
+ pmap_bootstrap((pd_entry_t *)kernel_l1pt.pv_va, KERNEL_VM_BASE,
+ KERNEL_VM_BASE + KERNEL_VM_SIZE);
+
+#ifdef IPKDB
+ /* Initialise ipkdb */
+ ipkdb_init();
+ if (boothowto & RB_KDB)
+ ipkdb_connect(0);
+#endif
+
+ /*
+ * Restore proper bus_space operation, now that pmap is initialized.
+ */
+#if defined(CPU_ARMv7)
+ armv7_bs_tag.bs_map = map_func_save;
+ armv7_a4x_bs_tag.bs_map = map_func_save;
+#endif
+
+#ifdef DDB
+ db_machine_init();
+
+ /* Firmware doesn't load symbols. */
+ ddb_init();
+
+ if (boothowto & RB_KDB)
+ Debugger();
+#endif
+
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ amptimer_frequency = 396 * 1000 * 1000;
+ printf("board type: phyFLEX-i.MX6\n");
+ break;
+ case BOARD_ID_IMX6_SABRELITE:
+ amptimer_frequency = 396 * 1000 * 1000;
+ printf("board type: SABRE Lite\n");
+ break;
+ default:
+ printf("board type %x unknown\n", board_id);
+ }
+
+ /* We return the new stack pointer address */
+ return(kernelstack.pv_va + USPACE_SVC_STACK_TOP);
+}
+
+
+void
+process_kernel_args(char *args)
+{
+ char *cp = args;
+
+ if (cp == NULL) {
+ boothowto = RB_AUTOBOOT;
+ return;
+ }
+
+ boothowto = 0;
+
+ /* Make a local copy of the bootargs */
+ strncpy(bootargs, cp, MAX_BOOT_STRING - sizeof(int));
+
+ cp = bootargs;
+ boot_file = bootargs;
+
+ /* Skip the kernel image filename */
+ while (*cp != ' ' && *cp != 0)
+ ++cp;
+
+ if (*cp != 0)
+ *cp++ = 0;
+
+ while (*cp == ' ')
+ ++cp;
+
+ boot_args = cp;
+
+ printf("bootfile: %s\n", boot_file);
+ printf("bootargs: %s\n", boot_args);
+
+ /* Setup pointer to boot flags */
+ while (*cp != '-')
+ if (*cp++ == '\0')
+ return;
+
+ for (;*++cp;) {
+ int fl;
+
+ fl = 0;
+ switch(*cp) {
+ case 'a':
+ fl |= RB_ASKNAME;
+ break;
+ case 'c':
+ fl |= RB_CONFIG;
+ break;
+ case 'd':
+ fl |= RB_KDB;
+ break;
+ case 's':
+ fl |= RB_SINGLE;
+ break;
+ default:
+ printf("unknown option `%c'\n", *cp);
+ break;
+ }
+ boothowto |= fl;
+ }
+}
+
+void
+consinit(void)
+{
+ static int consinit_called = 0;
+ paddr_t paddr;
+
+ if (consinit_called != 0)
+ return;
+
+ consinit_called = 1;
+
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ paddr = 0x021f0000;
+ break;
+ case BOARD_ID_IMX6_SABRELITE:
+ paddr = 0x021e8000;
+ break;
+ default:
+ printf("board type %x unknown", board_id);
+ return;
+ /* XXX - HELP */
+ }
+ imxuartcnattach(&armv7_bs_tag, paddr, comcnspeed, comcnmode);
+}
+
+
+//int glass_console = 0;
+
+void
+board_startup(void)
+{
+ if (boothowto & RB_CONFIG) {
+#ifdef BOOT_CONFIG
+ user_config();
+#else
+ printf("kernel does not support -c; continuing..\n");
+#endif
+ }
+}
+
+void
+platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off,
+ uint32_t op, uint32_t val)
+{
+ bus_space_write_4(iot, ioh, off, val);
+}
diff --git a/sys/arch/armv7/imx/imxahci.c b/sys/arch/armv7/imx/imxahci.c
new file mode 100644
index 00000000000..ffe6f88845e
--- /dev/null
+++ b/sys/arch/armv7/imx/imxahci.c
@@ -0,0 +1,173 @@
+/* $OpenBSD: imxahci.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/queue.h>
+
+#include <machine/bus.h>
+
+#include <dev/ic/ahcivar.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxccmvar.h>
+#include <armv7/imx/imxiomuxcvar.h>
+
+/* registers */
+#define SATA_CAP 0x000
+#define SATA_GHC 0x004
+#define SATA_IS 0x008
+#define SATA_PI 0x00C
+#define SATA_VS 0x010
+#define SATA_CCC_CTL 0x014
+#define SATA_CCC_PORTS 0x018
+#define SATA_CAP2 0x024
+#define SATA_BISTAFR 0x0A0
+#define SATA_BISTCR 0x0A4
+#define SATA_BISTFCTR 0x0A8
+#define SATA_BSTSR 0x0AC
+#define SATA_OOBR 0x0BC
+#define SATA_GPCR 0x0D0
+#define SATA_GPSR 0x0D4
+#define SATA_TIMER1MS 0x0E0
+#define SATA_TESTR 0x0F4
+#define SATA_VERSIONR 0x0F8
+#define SATA_P0CLB 0x100
+#define SATA_P0FB 0x108
+#define SATA_P0IS 0x110
+#define SATA_P0IE 0x114
+#define SATA_P0CMD 0x118
+#define SATA_P0TFD 0x120
+#define SATA_P0SIG 0x124
+#define SATA_P0SSTS 0x128
+#define SATA_P0SCTL 0x12C
+#define SATA_P0SERR 0x130
+#define SATA_P0SACT 0x134
+#define SATA_P0CI 0x138
+#define SATA_P0SNTF 0x13C
+#define SATA_P0DMACR 0x170
+#define SATA_P0PHYCR 0x178
+#define SATA_P0PHYSR 0x17C
+
+#define SATA_CAP_SSS (1 << 27)
+#define SATA_GHC_HR (1 << 0)
+#define SATA_P0PHYCR_TEST_PDDQ (1 << 20)
+
+void imxahci_attach(struct device *, struct device *, void *);
+int imxahci_detach(struct device *, int);
+int imxahci_activate(struct device *, int);
+
+extern int ahci_intr(void *);
+
+struct imxahci_softc {
+ struct ahci_softc sc;
+};
+
+struct cfattach imxahci_ca = {
+ sizeof(struct imxahci_softc),
+ NULL,
+ imxahci_attach,
+ imxahci_detach,
+ imxahci_activate
+};
+
+struct cfdriver imxahci_cd = {
+ NULL, "ahci", DV_DULL
+};
+
+void
+imxahci_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
+ struct ahci_softc *sc = &imxsc->sc;
+ uint32_t timeout = 0x100000;
+
+ sc->sc_iot = ia->ia_iot;
+ sc->sc_ios = ia->ia_dev->mem[0].size;
+ sc->sc_dmat = ia->ia_dmat;
+
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxahci_attach: bus_space_map failed!");
+
+ sc->sc_ih = arm_intr_establish(ia->ia_dev->irq[0], IPL_BIO,
+ ahci_intr, sc, sc->sc_dev.dv_xname);
+ if (sc->sc_ih == NULL) {
+ printf(": unable to establish interrupt\n");
+ goto unmap;
+ }
+
+ /* power it up */
+ imxccm_enable_sata();
+ delay(100);
+
+ /* power phy up */
+ imxiomuxc_enable_sata();
+
+ /* setup */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0PHYCR) & ~SATA_P0PHYCR_TEST_PDDQ);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_GHC, SATA_GHC_HR);
+
+ while (!bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_VERSIONR));
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_CAP,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_CAP) | SATA_CAP_SSS);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_PI, 1);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, SATA_TIMER1MS, imxccm_get_ahbclk());
+
+ while (!(bus_space_read_4(sc->sc_iot, sc->sc_ioh, SATA_P0SSTS) & 0xF) && timeout--);
+
+ if (ahci_attach(sc) != 0) {
+ /* error printed by ahci_attach */
+ goto irq;
+ }
+
+ return;
+irq:
+ arm_intr_disestablish(sc->sc_ih);
+unmap:
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+}
+
+int
+imxahci_detach(struct device *self, int flags)
+{
+ struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
+ struct ahci_softc *sc = &imxsc->sc;
+
+ ahci_detach(sc, flags);
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+ return 0;
+}
+
+int
+imxahci_activate(struct device *self, int act)
+{
+ struct imxahci_softc *imxsc = (struct imxahci_softc *) self;
+ struct ahci_softc *sc = &imxsc->sc;
+
+ return ahci_activate((struct device *)sc, act);
+}
diff --git a/sys/arch/armv7/imx/imxccm.c b/sys/arch/armv7/imx/imxccm.c
new file mode 100644
index 00000000000..dc2daee6e58
--- /dev/null
+++ b/sys/arch/armv7/imx/imxccm.c
@@ -0,0 +1,563 @@
+/* $OpenBSD: imxccm.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/sysctl.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <armv7/imx/imxvar.h>
+
+/* registers */
+#define CCM_CCR 0x00
+#define CCM_CCDR 0x04
+#define CCM_CSR 0x08
+#define CCM_CCSR 0x0c
+#define CCM_CACRR 0x10
+#define CCM_CBCDR 0x14
+#define CCM_CBCMR 0x18
+#define CCM_CSCMR1 0x1c
+#define CCM_CSCMR2 0x20
+#define CCM_CSCDR1 0x24
+#define CCM_CS1CDR 0x28
+#define CCM_CS2CDR 0x2c
+#define CCM_CDCDR 0x30
+#define CCM_CHSCCDR 0x34
+#define CCM_CSCDR2 0x38
+#define CCM_CSCDR3 0x3c
+#define CCM_CSCDR4 0x40
+#define CCM_CDHIPR 0x48
+#define CCM_CDCR 0x4c
+#define CCM_CTOR 0x50
+#define CCM_CLPCR 0x54
+#define CCM_CISR 0x58
+#define CCM_CIMR 0x5c
+#define CCM_CCOSR 0x60
+#define CCM_CGPR 0x64
+#define CCM_CCGR0 0x68
+#define CCM_CCGR1 0x6c
+#define CCM_CCGR2 0x70
+#define CCM_CCGR3 0x74
+#define CCM_CCGR4 0x78
+#define CCM_CCGR5 0x7c
+#define CCM_CCGR6 0x80
+#define CCM_CCGR7 0x84
+#define CCM_CMEOR 0x88
+
+/* ANALOG */
+#define CCM_ANALOG_PLL_ARM 0x4000
+#define CCM_ANALOG_PLL_ARM_SET 0x4004
+#define CCM_ANALOG_PLL_ARM_CLR 0x4008
+#define CCM_ANALOG_PLL_USB1 0x4010
+#define CCM_ANALOG_PLL_USB1_SET 0x4014
+#define CCM_ANALOG_PLL_USB1_CLR 0x4018
+#define CCM_ANALOG_PLL_USB2 0x4020
+#define CCM_ANALOG_PLL_USB2_SET 0x4024
+#define CCM_ANALOG_PLL_USB2_CLR 0x4028
+#define CCM_ANALOG_PLL_SYS 0x4030
+#define CCM_ANALOG_USB2_CHRG_DETECT 0x4210
+#define CCM_ANALOG_USB2_CHRG_DETECT_SET 0x4214
+#define CCM_ANALOG_USB2_CHRG_DETECT_CLR 0x4218
+#define CCM_ANALOG_DIGPROG 0x4260
+#define CCM_ANALOG_PLL_ENET 0x40e0
+#define CCM_ANALOG_PLL_ENET_SET 0x40e4
+#define CCM_ANALOG_PLL_ENET_CLR 0x40e8
+#define CCM_ANALOG_PFD_480 0x40f0
+#define CCM_ANALOG_PFD_480_SET 0x40f4
+#define CCM_ANALOG_PFD_480_CLR 0x40f8
+#define CCM_ANALOG_PFD_528 0x4100
+#define CCM_ANALOG_PFD_528_SET 0x4104
+#define CCM_ANALOG_PFD_528_CLR 0x4108
+#define CCM_PMU_MISC1 0x4160
+
+/* bits and bytes */
+#define CCM_CCSR_PLL3_SW_CLK_SEL (1 << 0)
+#define CCM_CCSR_PLL2_SW_CLK_SEL (1 << 1)
+#define CCM_CCSR_PLL1_SW_CLK_SEL (1 << 2)
+#define CCM_CCSR_STEP_SEL (1 << 8)
+#define CCM_CBCDR_IPG_PODF_SHIFT 8
+#define CCM_CBCDR_IPG_PODF_MASK 0x3
+#define CCM_CBCDR_AHB_PODF_SHIFT 10
+#define CCM_CBCDR_AHB_PODF_MASK 0x7
+#define CCM_CBCDR_PERIPH_CLK_SEL_SHIFT 25
+#define CCM_CBCDR_PERIPH_CLK_SEL_MASK 0x1
+#define CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT 12
+#define CCM_CBCMR_PERIPH_CLK2_SEL_MASK 0x3
+#define CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT 18
+#define CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK 0x3
+#define CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x) ((x) + 15)
+#define CCM_CSCDR1_USDHCx_CLK_SEL_MASK 0x1
+#define CCM_CSCDR1_USDHCx_PODF_MASK 0x7
+#define CCM_CSCDR1_UART_PODF_MASK 0x7
+#define CCM_CCGR1_ENET (3 << 10)
+#define CCM_CCGR2_I2C(x) (3 << (6 + 2*x))
+#define CCM_CCGR4_125M_PCIE (3 << 0)
+#define CCM_CCGR5_100M_SATA (3 << 4)
+#define CCM_CCGR6_USBOH3 (3 << 0)
+#define CCM_CSCMR1_PERCLK_CLK_SEL_MASK 0x1f
+#define CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK 0x7f
+#define CCM_ANALOG_PLL_ARM_BYPASS (1 << 16)
+#define CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK 0x1
+#define CCM_ANALOG_PLL_USB2_EN_USB_CLKS (1 << 6)
+#define CCM_ANALOG_PLL_USB2_POWER (1 << 12)
+#define CCM_ANALOG_PLL_USB2_ENABLE (1 << 13)
+#define CCM_ANALOG_PLL_USB2_BYPASS (1 << 16)
+#define CCM_ANALOG_PLL_USB2_LOCK (1 << 31)
+#define CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK 0x1
+#define CCM_ANALOG_USB2_CHRG_DETECT_CHK_CHRG_B (1 << 19)
+#define CCM_ANALOG_USB2_CHRG_DETECT_EN_B (1 << 20)
+#define CCM_ANALOG_DIGPROG_MINOR_MASK 0xff
+#define CCM_ANALOG_PLL_ENET_DIV_125M (1 << 11)
+#define CCM_ANALOG_PLL_ENET_POWERDOWN (1 << 12)
+#define CCM_ANALOG_PLL_ENET_ENABLE (1 << 13)
+#define CCM_ANALOG_PLL_ENET_BYPASS (1 << 16)
+#define CCM_ANALOG_PLL_ENET_125M_PCIE (1 << 19)
+#define CCM_ANALOG_PLL_ENET_100M_SATA (1 << 20)
+#define CCM_ANALOG_PLL_ENET_LOCK (1 << 31)
+#define CCM_ANALOG_PFD_480_PFDx_FRAC(x, y) (((x) >> ((y) << 3)) & 0x3f)
+#define CCM_ANALOG_PFD_528_PFDx_FRAC(x, y) (((x) >> ((y) << 3)) & 0x3f)
+#define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_SATA (0xB << 0)
+#define CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_MASK (0x1f << 0)
+#define CCM_PMU_MISC1_LVDSCLK1_OBEN (1 << 10)
+#define CCM_PMU_MISC1_LVDSCLK1_IBEN (1 << 12)
+
+#define HCLK_FREQ 24000
+#define PLL3_80M 80000
+
+#define HREAD4(sc, reg) \
+ (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits) \
+ HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits) \
+ HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+struct imxccm_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+enum clocks {
+ /* OSC */
+ OSC, /* 24 MHz OSC */
+
+ /* PLLs */
+ ARM_PLL1, /* ARM core PLL */
+ SYS_PLL2, /* System PLL: 528 MHz */
+ USB1_PLL3, /* OTG USB PLL: 480 MHz */
+ USB2_PLL, /* Host USB PLL: 480 MHz */
+ AUD_PLL4, /* Audio PLL */
+ VID_PLL5, /* Video PLL */
+ ENET_PLL6, /* ENET PLL */
+ MLB_PLL, /* MLB PLL */
+
+ /* SYS_PLL2 PFDs */
+ SYS_PLL2_PFD0, /* 352 MHz */
+ SYS_PLL2_PFD1, /* 594 MHz */
+ SYS_PLL2_PFD2, /* 396 MHz */
+
+ /* USB1_PLL3 PFDs */
+ USB1_PLL3_PFD0, /* 720 MHz */
+ USB1_PLL3_PFD1, /* 540 MHz */
+ USB1_PLL3_PFD2, /* 508.2 MHz */
+ USB1_PLL3_PFD3, /* 454.7 MHz */
+};
+
+struct imxccm_softc *imxccm_sc;
+
+void imxccm_attach(struct device *parent, struct device *self, void *args);
+int imxccm_cpuspeed(int *);
+unsigned int imxccm_decode_pll(enum clocks, unsigned int);
+unsigned int imxccm_get_pll2_pfd(unsigned int);
+unsigned int imxccm_get_pll3_pfd(unsigned int);
+unsigned int imxccm_get_armclk(void);
+void imxccm_armclk_set_parent(enum clocks);
+void imxccm_armclk_set_freq(unsigned int);
+unsigned int imxccm_get_usdhx(int x);
+unsigned int imxccm_get_periphclk(void);
+unsigned int imxccm_get_fecclk(void);
+unsigned int imxccm_get_ahbclk(void);
+unsigned int imxccm_get_ipgclk(void);
+unsigned int imxccm_get_ipg_perclk(void);
+unsigned int imxccm_get_uartclk(void);
+void imxccm_enable_i2c(int x);
+void imxccm_enable_usboh3(void);
+void imxccm_disable_usb2_chrg_detect(void);
+void imxccm_enable_pll_usb2(void);
+void imxccm_enable_pll_enet(void);
+void imxccm_enable_enet(void);
+void imxccm_enable_sata(void);
+void imxccm_enable_pcie(void);
+
+struct cfattach imxccm_ca = {
+ sizeof (struct imxccm_softc), NULL, imxccm_attach
+};
+
+struct cfdriver imxccm_cd = {
+ NULL, "imxccm", DV_DULL
+};
+
+void
+imxccm_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxccm_softc *sc = (struct imxccm_softc *) self;
+
+ imxccm_sc = sc;
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxccm_attach: bus_space_map failed!");
+
+ printf(": imx6 rev 1.%d CPU freq: %d MHz",
+ HREAD4(sc, CCM_ANALOG_DIGPROG) & CCM_ANALOG_DIGPROG_MINOR_MASK,
+ imxccm_get_armclk() / 1000);
+
+ printf("\n");
+
+ cpu_cpuspeed = imxccm_cpuspeed;
+}
+
+int
+imxccm_cpuspeed(int *freq)
+{
+ *freq = imxccm_get_armclk() / 1000;
+ return (0);
+}
+
+unsigned int
+imxccm_decode_pll(enum clocks pll, unsigned int freq)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+ uint32_t div;
+
+ switch (pll) {
+ case ARM_PLL1:
+ if (HREAD4(sc, CCM_ANALOG_PLL_ARM)
+ & CCM_ANALOG_PLL_ARM_BYPASS)
+ return freq;
+ div = HREAD4(sc, CCM_ANALOG_PLL_ARM)
+ & CCM_ANALOG_PLL_ARM_DIV_SELECT_MASK;
+ return (freq * div) / 2;
+ case SYS_PLL2:
+ div = HREAD4(sc, CCM_ANALOG_PLL_SYS)
+ & CCM_ANALOG_PLL_SYS_DIV_SELECT_MASK;
+ return freq * (20 + (div << 1));
+ case USB1_PLL3:
+ div = HREAD4(sc, CCM_ANALOG_PLL_USB2)
+ & CCM_ANALOG_PLL_USB2_DIV_SELECT_MASK;
+ return freq * (20 + (div << 1));
+ default:
+ return 0;
+ }
+}
+
+unsigned int
+imxccm_get_pll2_pfd(unsigned int pfd)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ return imxccm_decode_pll(SYS_PLL2, HCLK_FREQ) * 18
+ / CCM_ANALOG_PFD_528_PFDx_FRAC(HREAD4(sc, CCM_ANALOG_PFD_528), pfd);
+}
+
+unsigned int
+imxccm_get_pll3_pfd(unsigned int pfd)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ return imxccm_decode_pll(USB1_PLL3, HCLK_FREQ) * 18
+ / CCM_ANALOG_PFD_480_PFDx_FRAC(HREAD4(sc, CCM_ANALOG_PFD_480), pfd);
+}
+
+unsigned int
+imxccm_get_armclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ uint32_t ccsr = HREAD4(sc, CCM_CCSR);
+
+ if (!(ccsr & CCM_CCSR_PLL1_SW_CLK_SEL))
+ return imxccm_decode_pll(ARM_PLL1, HCLK_FREQ);
+ else if (ccsr & CCM_CCSR_STEP_SEL)
+ return imxccm_get_pll2_pfd(2);
+ else
+ return HCLK_FREQ;
+}
+
+void
+imxccm_armclk_set_parent(enum clocks clock)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ switch (clock)
+ {
+ case ARM_PLL1:
+ /* jump onto pll1 */
+ HCLR4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
+ /* put step clk on OSC, power saving */
+ HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
+ break;
+ case OSC:
+ /* put step clk on OSC */
+ HCLR4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
+ /* jump onto step clk */
+ HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
+ break;
+ case SYS_PLL2_PFD2:
+ /* put step clk on pll2-pfd2 400 MHz */
+ HSET4(sc, CCM_CCSR, CCM_CCSR_STEP_SEL);
+ /* jump onto step clk */
+ HSET4(sc, CCM_CCSR, CCM_CCSR_PLL1_SW_CLK_SEL);
+ break;
+ default:
+ panic("%s: parent not possible for arm clk", __func__);
+ }
+}
+
+void
+imxccm_armclk_set_freq(unsigned int freq)
+{
+ if (freq > 1296000 || freq < 648000)
+ panic("%s: frequency must be between 648MHz and 1296MHz!",
+ __func__);
+}
+
+unsigned int
+imxccm_get_usdhx(int x)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ uint32_t cscmr1 = HREAD4(sc, CCM_CSCMR1);
+ uint32_t cscdr1 = HREAD4(sc, CCM_CSCDR1);
+ uint32_t podf, clkroot;
+
+ // Odd bitsetting. Damn you.
+ if (x == 1)
+ podf = ((cscdr1 >> 11) & CCM_CSCDR1_USDHCx_PODF_MASK);
+ else
+ podf = ((cscdr1 >> (10 + 3*x)) & CCM_CSCDR1_USDHCx_PODF_MASK);
+
+ if (cscmr1 & (1 << CCM_CSCDR1_USDHCx_CLK_SEL_SHIFT(x)))
+ clkroot = imxccm_get_pll2_pfd(0); // 352 MHz
+ else
+ clkroot = imxccm_get_pll2_pfd(2); // 396 MHz
+
+ return clkroot / (podf + 1);
+}
+
+unsigned int
+imxccm_get_uartclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ uint32_t clkroot = PLL3_80M;
+ uint32_t podf = HREAD4(sc, CCM_CSCDR1) & CCM_CSCDR1_UART_PODF_MASK;
+
+ return clkroot / (podf + 1);
+}
+
+unsigned int
+imxccm_get_periphclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ if ((HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_PERIPH_CLK_SEL_SHIFT)
+ & CCM_CBCDR_PERIPH_CLK_SEL_MASK) {
+ switch((HREAD4(sc, CCM_CBCMR)
+ >> CCM_CBCMR_PERIPH_CLK2_SEL_SHIFT) & CCM_CBCMR_PERIPH_CLK2_SEL_MASK) {
+ case 0:
+ return imxccm_decode_pll(USB1_PLL3, HCLK_FREQ);
+ case 1:
+ case 2:
+ return HCLK_FREQ;
+ default:
+ return 0;
+ }
+
+ } else {
+ switch((HREAD4(sc, CCM_CBCMR)
+ >> CCM_CBCMR_PRE_PERIPH_CLK_SEL_SHIFT) & CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK) {
+ default:
+ case 0:
+ return imxccm_decode_pll(SYS_PLL2, HCLK_FREQ);
+ case 1:
+ return imxccm_get_pll2_pfd(2); // 396 MHz
+ case 2:
+ return imxccm_get_pll2_pfd(0); // 352 MHz
+ case 3:
+ return imxccm_get_pll2_pfd(2) / 2; // 198 MHz
+ }
+ }
+}
+
+unsigned int
+imxccm_get_fecclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+ uint32_t div = 0;
+
+ switch (HREAD4(sc, CCM_ANALOG_PLL_ENET) & 0x3)
+ {
+ case 0:
+ div = 20;
+ case 1:
+ div = 10;
+ case 2:
+ div = 5;
+ case 3:
+ div = 4;
+ }
+
+ return 500000 / div ;
+}
+
+unsigned int
+imxccm_get_ahbclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+ uint32_t ahb_podf;
+
+ ahb_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_AHB_PODF_SHIFT)
+ & CCM_CBCDR_AHB_PODF_MASK;
+ return imxccm_get_periphclk() / (ahb_podf + 1);
+}
+
+unsigned int
+imxccm_get_ipgclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+ uint32_t ipg_podf;
+
+ ipg_podf = (HREAD4(sc, CCM_CBCDR) >> CCM_CBCDR_IPG_PODF_SHIFT)
+ & CCM_CBCDR_IPG_PODF_MASK;
+ return imxccm_get_ahbclk() / (ipg_podf + 1);
+}
+
+unsigned int
+imxccm_get_ipg_perclk()
+{
+ struct imxccm_softc *sc = imxccm_sc;
+ uint32_t ipg_podf;
+
+ ipg_podf = HREAD4(sc, CCM_CSCMR1) & CCM_CSCMR1_PERCLK_CLK_SEL_MASK;
+
+ return imxccm_get_ipgclk() / (ipg_podf + 1);
+}
+
+void
+imxccm_enable_i2c(int x)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ HSET4(sc, CCM_CCGR2, CCM_CCGR2_I2C(x));
+}
+
+void
+imxccm_enable_usboh3(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ HSET4(sc, CCM_CCGR6, CCM_CCGR6_USBOH3);
+}
+
+void
+imxccm_enable_pll_enet(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ if (HREAD4(sc, CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_ENABLE)
+ return;
+
+ HCLR4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_POWERDOWN);
+
+ HSET4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_ENABLE);
+
+ while(!(HREAD4(sc, CCM_ANALOG_PLL_ENET) & CCM_ANALOG_PLL_ENET_LOCK));
+
+ HCLR4(sc, CCM_ANALOG_PLL_ENET, CCM_ANALOG_PLL_ENET_BYPASS);
+}
+
+void
+imxccm_enable_enet(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ imxccm_enable_pll_enet();
+ HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_DIV_125M);
+
+ HSET4(sc, CCM_CCGR1, CCM_CCGR1_ENET);
+}
+
+void
+imxccm_enable_sata(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ imxccm_enable_pll_enet();
+ HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_100M_SATA);
+
+ HSET4(sc, CCM_CCGR5, CCM_CCGR5_100M_SATA);
+}
+
+void
+imxccm_enable_pcie(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ HWRITE4(sc, CCM_PMU_MISC1,
+ (HREAD4(sc, CCM_PMU_MISC1) & ~CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_MASK)
+ | CCM_PMU_MISC1_LVDSCLK1_CLK_SEL_SATA
+ | CCM_PMU_MISC1_LVDSCLK1_OBEN
+ | CCM_PMU_MISC1_LVDSCLK1_IBEN);
+
+ imxccm_enable_pll_enet();
+ HWRITE4(sc, CCM_ANALOG_PLL_ENET_SET, CCM_ANALOG_PLL_ENET_125M_PCIE);
+
+ HSET4(sc, CCM_CCGR4, CCM_CCGR4_125M_PCIE);
+}
+
+void
+imxccm_disable_usb2_chrg_detect(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ HWRITE4(sc, CCM_ANALOG_USB2_CHRG_DETECT_SET,
+ CCM_ANALOG_USB2_CHRG_DETECT_CHK_CHRG_B
+ | CCM_ANALOG_USB2_CHRG_DETECT_EN_B);
+}
+
+void
+imxccm_enable_pll_usb2(void)
+{
+ struct imxccm_softc *sc = imxccm_sc;
+
+ HWRITE4(sc, CCM_ANALOG_PLL_USB2_CLR, CCM_ANALOG_PLL_USB2_BYPASS);
+
+ HWRITE4(sc, CCM_ANALOG_PLL_USB2_SET,
+ CCM_ANALOG_PLL_USB2_ENABLE
+ | CCM_ANALOG_PLL_USB2_POWER
+ | CCM_ANALOG_PLL_USB2_EN_USB_CLKS);
+}
diff --git a/sys/arch/armv7/imx/imxccmvar.h b/sys/arch/armv7/imx/imxccmvar.h
new file mode 100644
index 00000000000..decfc2ae4b7
--- /dev/null
+++ b/sys/arch/armv7/imx/imxccmvar.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: imxccmvar.h,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IMXCCMVAR_H
+#define IMXCCMVAR_H
+
+unsigned int imxccm_get_usdhx(int x);
+unsigned int imxccm_get_fecclk(void);
+unsigned int imxccm_get_uartclk(void);
+unsigned int imxccm_get_ipg_perclk(void);
+unsigned int imxccm_get_ahbclk(void);
+void imxccm_enable_i2c(int x);
+void imxccm_enable_usboh3(void);
+void imxccm_disable_usb2_chrg_detect(void);
+void imxccm_enable_pll_usb2(void);
+void imxccm_enable_enet(void);
+void imxccm_enable_sata(void);
+void imxccm_enable_pcie(void);
+
+#endif /* IMXCCMVAR_H */
diff --git a/sys/arch/armv7/imx/imxdog.c b/sys/arch/armv7/imx/imxdog.c
new file mode 100644
index 00000000000..a6b32478d70
--- /dev/null
+++ b/sys/arch/armv7/imx/imxdog.c
@@ -0,0 +1,90 @@
+/* $OpenBSD: imxdog.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <armv7/imx/imxvar.h>
+
+/* registers */
+#define WCR 0x00
+#define WSR 0x02
+#define WRSR 0x04
+#define WICR 0x06
+#define WMCR 0x08
+
+struct imxdog_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+struct imxdog_softc *imxdog_sc;
+
+void imxdog_attach(struct device *parent, struct device *self, void *args);
+void imxdog_reset(void);
+
+struct cfattach imxdog_ca = {
+ sizeof (struct imxdog_softc), NULL, imxdog_attach
+};
+
+struct cfdriver imxdog_cd = {
+ NULL, "imxdog", DV_DULL
+};
+
+void
+imxdog_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxdog_softc *sc = (struct imxdog_softc *) self;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxdog_attach: bus_space_map failed!");
+
+ printf("\n");
+ imxdog_sc = sc;
+}
+
+void
+imxdog_reset()
+{
+ if (imxdog_sc == NULL)
+ return;
+
+ /* disable watchdog and set timeout to 0 */
+ bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WCR, 0);
+
+ /* sequence to reset timeout counter */
+ bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WSR, 0x5555);
+ bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WSR, 0xaaaa);
+
+ /* enable watchdog */
+ bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WCR, 1);
+ /* errata TKT039676 */
+ bus_space_write_2(imxdog_sc->sc_iot, imxdog_sc->sc_ioh, WCR, 1);
+
+ delay(100000);
+}
diff --git a/sys/arch/armv7/imx/imxehci.c b/sys/arch/armv7/imx/imxehci.c
new file mode 100644
index 00000000000..065316d4684
--- /dev/null
+++ b/sys/arch/armv7/imx/imxehci.c
@@ -0,0 +1,250 @@
+/* $OpenBSD: imxehci.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/rwlock.h>
+#include <sys/timeout.h>
+
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdivar.h>
+#include <dev/usb/usb_mem.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxccmvar.h>
+#include <armv7/imx/imxgpiovar.h>
+
+#include <dev/usb/ehcireg.h>
+#include <dev/usb/ehcivar.h>
+
+/* usb phy */
+#define USBPHY_PWD 0x00
+#define USBPHY_CTRL 0x30
+#define USBPHY_CTRL_SET 0x34
+#define USBPHY_CTRL_CLR 0x38
+#define USBPHY_CTRL_TOG 0x3c
+
+#define USBPHY_CTRL_ENUTMILEVEL2 (1 << 14)
+#define USBPHY_CTRL_ENUTMILEVEL3 (1 << 15)
+#define USBPHY_CTRL_CLKGATE (1 << 30)
+#define USBPHY_CTRL_SFTRST (1 << 31)
+
+/* ehci */
+#define EHCI_USBMODE 0x68
+
+#define EHCI_USBMODE_HOST (3 << 0)
+#define EHCI_PS_PTS_UTMI_MASK ((1 << 25) | (3 << 30))
+
+/* usb non-core */
+#define USBNC_USB_UH1_CTRL 0x04
+
+#define USBNC_USB_UH1_CTRL_OVER_CUR_POL (1 << 8)
+#define USBNC_USB_UH1_CTRL_OVER_CUR_DIS (1 << 7)
+
+/* board specific */
+#define EHCI_PHYFLEX_USB_H1_PWR 0
+#define EHCI_PHYFLEX_USB_OTG_PWR 111
+
+void imxehci_attach(struct device *, struct device *, void *);
+int imxehci_detach(struct device *, int);
+
+struct imxehci_softc {
+ struct ehci_softc sc;
+ void *sc_ih;
+ bus_space_handle_t uh_ioh;
+ bus_space_handle_t ph_ioh;
+ bus_space_handle_t nc_ioh;
+};
+
+struct cfattach imxehci_ca = {
+ sizeof (struct imxehci_softc), NULL, imxehci_attach,
+ imxehci_detach, NULL
+};
+
+void
+imxehci_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct imxehci_softc *sc = (struct imxehci_softc *)self;
+ struct imx_attach_args *ia = aux;
+ usbd_status r;
+ char *devname = sc->sc.sc_bus.bdev.dv_xname;
+
+ sc->sc.iot = ia->ia_iot;
+ sc->sc.sc_bus.dmatag = ia->ia_dmat;
+ sc->sc.sc_size = ia->ia_dev->mem[0].size;
+
+ /* Map I/O space */
+ if (bus_space_map(sc->sc.iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc.ioh)) {
+ printf(": cannot map mem space\n");
+ goto out;
+ }
+
+ if (bus_space_map(sc->sc.iot, ia->ia_dev->mem[1].addr,
+ ia->ia_dev->mem[1].size, 0, &sc->uh_ioh)) {
+ printf(": cannot map mem space\n");
+ goto mem0;
+ }
+
+ if (bus_space_map(sc->sc.iot, ia->ia_dev->mem[2].addr,
+ ia->ia_dev->mem[2].size, 0, &sc->ph_ioh)) {
+ printf(": cannot map mem space\n");
+ goto mem1;
+ }
+
+ if (bus_space_map(sc->sc.iot, ia->ia_dev->mem[3].addr,
+ ia->ia_dev->mem[3].size, 0, &sc->nc_ioh)) {
+ printf(": cannot map mem space\n");
+ goto mem2;
+ }
+
+ printf("\n");
+
+ /* enable usb port power */
+ switch (board_id)
+ {
+ case BOARD_ID_IMX6_PHYFLEX:
+ imxgpio_set_dir(EHCI_PHYFLEX_USB_H1_PWR, IMXGPIO_DIR_OUT);
+ delay(10);
+ imxgpio_set_bit(EHCI_PHYFLEX_USB_H1_PWR);
+ delay(10);
+ break;
+ }
+
+ imxccm_enable_usboh3();
+ delay(1000);
+ /* disable the carger detection, else signal on DP will be poor */
+ imxccm_disable_usb2_chrg_detect();
+ /* power host 1 */
+ imxccm_enable_pll_usb2();
+
+ /* over current and polarity setting */
+ bus_space_write_4(sc->sc.iot, sc->nc_ioh, USBNC_USB_UH1_CTRL,
+ bus_space_read_4(sc->sc.iot, sc->nc_ioh, USBNC_USB_UH1_CTRL) |
+ (USBNC_USB_UH1_CTRL_OVER_CUR_POL | USBNC_USB_UH1_CTRL_OVER_CUR_DIS));
+
+ bus_space_write_4(sc->sc.iot, sc->ph_ioh, USBPHY_CTRL_CLR,
+ USBPHY_CTRL_CLKGATE);
+
+ /* Disable interrupts, so we don't get any spurious ones. */
+ sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH);
+ EOWRITE2(&sc->sc, EHCI_USBINTR, 0);
+
+ /* Stop then Reset */
+ uint32_t val = EOREAD4(&sc->sc, EHCI_USBCMD);
+ val &= ~EHCI_CMD_RS;
+ EOWRITE4(&sc->sc, EHCI_USBCMD, val);
+
+ while (EOREAD4(&sc->sc, EHCI_USBCMD) & EHCI_CMD_RS)
+ ;
+
+ val = EOREAD4(&sc->sc, EHCI_USBCMD);
+ val |= EHCI_CMD_HCRESET;
+ EOWRITE4(&sc->sc, EHCI_USBCMD, val);
+
+ while (EOREAD4(&sc->sc, EHCI_USBCMD) & EHCI_CMD_HCRESET)
+ ;
+
+ /* Reset USBPHY module */
+ bus_space_write_4(sc->sc.iot, sc->ph_ioh, USBPHY_CTRL_SET, USBPHY_CTRL_SFTRST);
+
+ delay(10);
+
+ /* Remove CLKGATE and SFTRST */
+ bus_space_write_4(sc->sc.iot, sc->ph_ioh, USBPHY_CTRL_CLR,
+ USBPHY_CTRL_CLKGATE | USBPHY_CTRL_SFTRST);
+
+ delay(10);
+
+ /* Power up the PHY */
+ bus_space_write_4(sc->sc.iot, sc->ph_ioh, USBPHY_PWD, 0);
+
+ /* enable FS/LS device */
+ bus_space_write_4(sc->sc.iot, sc->ph_ioh, USBPHY_CTRL_SET,
+ USBPHY_CTRL_ENUTMILEVEL2 | USBPHY_CTRL_ENUTMILEVEL3);
+
+ /* set host mode */
+ EWRITE4(&sc->sc, EHCI_USBMODE,
+ EREAD4(&sc->sc, EHCI_USBMODE) | EHCI_USBMODE_HOST);
+
+ /* set to UTMI mode */
+ EOWRITE4(&sc->sc, EHCI_PORTSC(1),
+ EOREAD4(&sc->sc, EHCI_PORTSC(1)) & ~EHCI_PS_PTS_UTMI_MASK);
+
+ sc->sc_ih = arm_intr_establish(ia->ia_dev->irq[0], IPL_USB,
+ ehci_intr, &sc->sc, devname);
+ if (sc->sc_ih == NULL) {
+ printf(": unable to establish interrupt\n");
+ goto mem3;
+ }
+
+ strlcpy(sc->sc.sc_vendor, "i.MX6", sizeof(sc->sc.sc_vendor));
+ r = ehci_init(&sc->sc);
+ if (r != USBD_NORMAL_COMPLETION) {
+ printf("%s: init failed, error=%d\n", devname, r);
+ goto intr;
+ }
+
+ sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus,
+ usbctlprint);
+
+ goto out;
+
+intr:
+ arm_intr_disestablish(sc->sc_ih);
+ sc->sc_ih = NULL;
+mem3:
+ bus_space_unmap(sc->sc.iot, sc->nc_ioh, ia->ia_dev->mem[3].addr);
+mem2:
+ bus_space_unmap(sc->sc.iot, sc->ph_ioh, ia->ia_dev->mem[2].addr);
+mem1:
+ bus_space_unmap(sc->sc.iot, sc->uh_ioh, ia->ia_dev->mem[1].addr);
+mem0:
+ bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+ sc->sc.sc_size = 0;
+out:
+ return;
+}
+
+int
+imxehci_detach(struct device *self, int flags)
+{
+ struct imxehci_softc *sc = (struct imxehci_softc *)self;
+ int rv;
+
+ rv = ehci_detach(&sc->sc, flags);
+ if (rv)
+ return (rv);
+
+ if (sc->sc_ih != NULL) {
+ arm_intr_disestablish(sc->sc_ih);
+ sc->sc_ih = NULL;
+ }
+
+ if (sc->sc.sc_size) {
+ bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size);
+ sc->sc.sc_size = 0;
+ }
+
+ return (0);
+}
diff --git a/sys/arch/armv7/imx/imxenet.c b/sys/arch/armv7/imx/imxenet.c
new file mode 100644
index 00000000000..b1426b5285d
--- /dev/null
+++ b/sys/arch/armv7/imx/imxenet.c
@@ -0,0 +1,964 @@
+/* $OpenBSD: imxenet.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/sockio.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <sys/mbuf.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include "bpfilter.h"
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#if NBPFILTER > 0
+#include <net/bpf.h>
+#endif
+
+#ifdef INET
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/in_var.h>
+#include <netinet/ip.h>
+#include <netinet/if_ether.h>
+#endif
+
+#include <dev/mii/mii.h>
+#include <dev/mii/miivar.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxenet.h>
+#include <armv7/imx/imxccmvar.h>
+#include <armv7/imx/imxgpiovar.h>
+#include <armv7/imx/imxocotpvar.h>
+
+/* configuration registers */
+#define ENET_EIR 0x004
+#define ENET_EIMR 0x008
+#define ENET_RDAR 0x010
+#define ENET_TDAR 0x014
+#define ENET_ECR 0x024
+#define ENET_MMFR 0x040
+#define ENET_MSCR 0x044
+#define ENET_MIBC 0x064
+#define ENET_RCR 0x084
+#define ENET_TCR 0x0C4
+#define ENET_PALR 0x0E4
+#define ENET_PAUR 0x0E8
+#define ENET_OPD 0x0EC
+#define ENET_IAUR 0x118
+#define ENET_IALR 0x11C
+#define ENET_GAUR 0x120
+#define ENET_GALR 0x124
+#define ENET_TFWR 0x144
+#define ENET_RDSR 0x180
+#define ENET_TDSR 0x184
+#define ENET_MRBR 0x188
+#define ENET_RSFL 0x190
+#define ENET_RSEM 0x194
+#define ENET_RAEM 0x198
+#define ENET_RAFL 0x19C
+#define ENET_TSEM 0x1A0
+#define ENET_TAEM 0x1A4
+#define ENET_TAFL 0x1A8
+#define ENET_TIPG 0x1AC
+#define ENET_FTRL 0x1B0
+#define ENET_TACC 0x1C0
+#define ENET_RACC 0x1C4
+
+#define ENET_RDAR_RDAR (1 << 24)
+#define ENET_TDAR_TDAR (1 << 24)
+#define ENET_ECR_RESET (1 << 0)
+#define ENET_ECR_ETHEREN (1 << 1)
+#define ENET_ECR_EN1588 (1 << 4)
+#define ENET_ECR_SPEED (1 << 5)
+#define ENET_ECR_DBSWP (1 << 8)
+#define ENET_MMFR_TA (2 << 16)
+#define ENET_MMFR_RA_SHIFT 18
+#define ENET_MMFR_PA_SHIFT 23
+#define ENET_MMFR_OP_WR (1 << 28)
+#define ENET_MMFR_OP_RD (2 << 28)
+#define ENET_MMFR_ST (1 << 30)
+#define ENET_RCR_MII_MODE (1 << 2)
+#define ENET_RCR_PROM (1 << 3)
+#define ENET_RCR_FCE (1 << 5)
+#define ENET_RCR_RGMII_MODE (1 << 6)
+#define ENET_RCR_MAX_FL(x) (((x) & 0x3fff) << 16)
+#define ENET_TCR_FDEN (1 << 2)
+#define ENET_EIR_MII (1 << 23)
+#define ENET_EIR_RXF (1 << 25)
+#define ENET_EIR_TXF (1 << 27)
+#define ENET_TFWR_STRFWD (1 << 8)
+
+/* statistics counters */
+
+/* 1588 control */
+#define ENET_ATCR 0x400
+#define ENET_ATVR 0x404
+#define ENET_ATOFF 0x408
+#define ENET_ATPER 0x40C
+#define ENET_ATCOR 0x410
+#define ENET_ATINC 0x414
+#define ENET_ATSTMP 0x418
+
+/* capture / compare block */
+#define ENET_TGSR 0x604
+#define ENET_TCSR0 0x608
+#define ENET_TCCR0 0x60C
+#define ENET_TCSR1 0x610
+#define ENET_TCCR1 0x614
+#define ENET_TCSR2 0x618
+#define ENET_TCCR2 0x61C
+#define ENET_TCSR3 0x620
+#define ENET_TCCR3 0x624
+
+#define ENET_MII_CLK 2500
+#define ENET_ALIGNMENT 16
+
+#define ENET_SABRELITE_PHY 6
+#define ENET_PHYFLEX_PHY 3
+#define ENET_PHYFLEX_PHY_RST 87
+
+#define HREAD4(sc, reg) \
+ (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits) \
+ HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits) \
+ HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+struct imxenet_softc {
+ struct device sc_dev;
+ struct arpcom sc_ac;
+ struct mii_data sc_mii;
+ int sc_phyno;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ void *sc_ih; /* Interrupt handler */
+ bus_dma_tag_t sc_dma_tag;
+ uint32_t intr_status; /* soft interrupt status */
+ struct imxenet_dma_alloc txdma; /* bus_dma glue for tx desc */
+ struct imxenet_buf_desc *tx_desc_base;
+ struct imxenet_dma_alloc rxdma; /* bus_dma glue for rx desc */
+ struct imxenet_buf_desc *rx_desc_base;
+ struct imxenet_dma_alloc tbdma; /* bus_dma glue for packets */
+ struct imxenet_buffer *tx_buffer_base;
+ struct imxenet_dma_alloc rbdma; /* bus_dma glue for packets */
+ struct imxenet_buffer *rx_buffer_base;
+ int cur_tx;
+ int cur_rx;
+};
+
+struct imxenet_softc *imxenet_sc;
+
+void imxenet_attach(struct device *, struct device *, void *);
+void imxenet_chip_init(struct imxenet_softc *);
+int imxenet_ioctl(struct ifnet *, u_long, caddr_t);
+void imxenet_start(struct ifnet *);
+int imxenet_encap(struct imxenet_softc *, struct mbuf *);
+void imxenet_init_txd(struct imxenet_softc *);
+void imxenet_init_rxd(struct imxenet_softc *);
+void imxenet_init(struct imxenet_softc *);
+void imxenet_stop(struct imxenet_softc *);
+void imxenet_iff(struct imxenet_softc *);
+struct mbuf * imxenet_newbuf(void);
+int imxenet_intr(void *);
+void imxenet_recv(struct imxenet_softc *);
+int imxenet_wait_intr(struct imxenet_softc *, int, int);
+int imxenet_miibus_readreg(struct device *, int, int);
+void imxenet_miibus_writereg(struct device *, int, int, int);
+void imxenet_miibus_statchg(struct device *);
+int imxenet_ifmedia_upd(struct ifnet *);
+void imxenet_ifmedia_sts(struct ifnet *, struct ifmediareq *);
+int imxenet_dma_malloc(struct imxenet_softc *, bus_size_t, struct imxenet_dma_alloc *);
+void imxenet_dma_free(struct imxenet_softc *, struct imxenet_dma_alloc *);
+
+struct cfattach imxenet_ca = {
+ sizeof (struct imxenet_softc), NULL, imxenet_attach
+};
+
+struct cfdriver imxenet_cd = {
+ NULL, "imxenet", DV_DULL
+};
+
+void
+imxenet_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxenet_softc *sc = (struct imxenet_softc *) self;
+ struct mii_data *mii;
+ struct ifnet *ifp;
+ int tsize, rsize, tbsize, rbsize, s;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxenet_attach: bus_space_map failed!");
+
+ sc->sc_dma_tag = ia->ia_dmat;
+
+ /* power it up */
+ imxccm_enable_enet();
+
+ switch (board_id)
+ {
+ case BOARD_ID_IMX6_PHYFLEX:
+ case BOARD_ID_IMX6_SABRELITE:
+ /* phyFLEX i.MX6 and SABRE Lite PHY reset */
+ imxgpio_set_dir(ENET_PHYFLEX_PHY_RST, IMXGPIO_DIR_OUT);
+ delay(10);
+ imxgpio_set_bit(ENET_PHYFLEX_PHY_RST);
+ delay(10);
+ break;
+ }
+
+ /* reset the controller */
+ HSET4(sc, ENET_ECR, ENET_ECR_RESET);
+ while(HREAD4(sc, ENET_ECR) & ENET_ECR_RESET);
+
+ HWRITE4(sc, ENET_EIMR, 0);
+ HWRITE4(sc, ENET_EIR, 0xffffffff);
+
+ sc->sc_ih = arm_intr_establish(ia->ia_dev->irq[0], IPL_NET,
+ imxenet_intr, sc, sc->sc_dev.dv_xname);
+
+ tsize = ENET_MAX_TXD * sizeof(struct imxenet_buf_desc);
+ tsize = ENET_ROUNDUP(tsize, PAGE_SIZE);
+
+ if (imxenet_dma_malloc(sc, tsize, &sc->txdma)) {
+ printf("%s: Unable to allocate tx_desc memory\n",
+ sc->sc_dev.dv_xname);
+ goto bad;
+ }
+ sc->tx_desc_base = (struct imxenet_buf_desc *)sc->txdma.dma_vaddr;
+
+ rsize = ENET_MAX_RXD * sizeof(struct imxenet_buf_desc);
+ rsize = ENET_ROUNDUP(rsize, PAGE_SIZE);
+
+ if (imxenet_dma_malloc(sc, rsize, &sc->rxdma)) {
+ printf("%s: Unable to allocate rx_desc memory\n",
+ sc->sc_dev.dv_xname);
+ goto txdma;
+ }
+ sc->rx_desc_base = (struct imxenet_buf_desc *)sc->rxdma.dma_vaddr;
+
+ tbsize = ENET_MAX_TXD * ENET_MAX_PKT_SIZE;
+ tbsize = ENET_ROUNDUP(tbsize, PAGE_SIZE);
+
+ if (imxenet_dma_malloc(sc, tbsize, &sc->tbdma)) {
+ printf("%s: Unable to allocate tx_buffer memory\n",
+ sc->sc_dev.dv_xname);
+ goto rxdma;
+ }
+ sc->tx_buffer_base = (struct imxenet_buffer *)sc->tbdma.dma_vaddr;
+
+ rbsize = ENET_MAX_RXD * ENET_MAX_PKT_SIZE;
+ rbsize = ENET_ROUNDUP(rbsize, PAGE_SIZE);
+
+ if (imxenet_dma_malloc(sc, rbsize, &sc->rbdma)) {
+ printf("%s: Unable to allocate rx_buffer memory\n",
+ sc->sc_dev.dv_xname);
+ goto tbdma;
+ }
+ sc->rx_buffer_base = (struct imxenet_buffer *)sc->rbdma.dma_vaddr;
+
+ sc->cur_tx = 0;
+ sc->cur_rx = 0;
+
+ printf("\n");
+
+ s = splnet();
+
+ ifp = &sc->sc_ac.ac_if;
+ ifp->if_softc = sc;
+ strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = imxenet_ioctl;
+ ifp->if_start = imxenet_start;
+ ifp->if_capabilities = IFCAP_VLAN_MTU;
+
+ memset(sc->sc_ac.ac_enaddr, 0xff, ETHER_ADDR_LEN);
+ imxocotp_get_ethernet_address(sc->sc_ac.ac_enaddr);
+
+ printf("%s: address %s\n", sc->sc_dev.dv_xname,
+ ether_sprintf(sc->sc_ac.ac_enaddr));
+
+ /* initialize the chip */
+ imxenet_chip_init(sc);
+
+ IFQ_SET_READY(&ifp->if_snd);
+
+ /* Initialize MII/media info. */
+ mii = &sc->sc_mii;
+ mii->mii_ifp = ifp;
+ mii->mii_readreg = imxenet_miibus_readreg;
+ mii->mii_writereg = imxenet_miibus_writereg;
+ mii->mii_statchg = imxenet_miibus_statchg;
+ mii->mii_flags = MIIF_AUTOTSLEEP;
+
+ ifmedia_init(&mii->mii_media, 0, imxenet_ifmedia_upd, imxenet_ifmedia_sts);
+ mii_attach(self, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0);
+
+ if (LIST_FIRST(&mii->mii_phys) == NULL) {
+ ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_NONE, 0, NULL);
+ ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_NONE);
+ } else
+ ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
+
+ if_attach(ifp);
+ ether_ifattach(ifp);
+ splx(s);
+
+ imxenet_sc = sc;
+ return;
+
+tbdma:
+ imxenet_dma_free(sc, &sc->tbdma);
+rxdma:
+ imxenet_dma_free(sc, &sc->rxdma);
+txdma:
+ imxenet_dma_free(sc, &sc->txdma);
+bad:
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, ia->ia_dev->mem[0].size);
+}
+
+void
+imxenet_chip_init(struct imxenet_softc *sc)
+{
+ struct device *dev = (struct device *) sc;
+ int phy = 0;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, ENET_MSCR,
+ (((imxccm_get_fecclk() + (ENET_MII_CLK << 2) - 1) / (ENET_MII_CLK << 2)) << 1) | 0x100);
+
+ switch (board_id)
+ {
+ case BOARD_ID_IMX6_SABRELITE:
+ phy = ENET_SABRELITE_PHY;
+ break;
+ case BOARD_ID_IMX6_PHYFLEX:
+ phy = ENET_PHYFLEX_PHY;
+ break;
+ }
+
+ switch (board_id)
+ {
+ case BOARD_ID_IMX6_PHYFLEX:
+ case BOARD_ID_IMX6_SABRELITE:
+ /* prefer master mode */
+ imxenet_miibus_writereg(dev, phy, 0x9, 0x1f00);
+
+ /* min rx data delay */
+ imxenet_miibus_writereg(dev, phy, 0x0b, 0x8105);
+ imxenet_miibus_writereg(dev, phy, 0x0c, 0x0000);
+
+ /* min tx data delay */
+ imxenet_miibus_writereg(dev, phy, 0x0b, 0x8106);
+ imxenet_miibus_writereg(dev, phy, 0x0c, 0x0000);
+
+ /* max rx/tx clock delay, min rx/tx control delay */
+ imxenet_miibus_writereg(dev, phy, 0x0b, 0x8104);
+ imxenet_miibus_writereg(dev, phy, 0x0c, 0xf0f0);
+ imxenet_miibus_writereg(dev, phy, 0x0b, 0x104);
+
+ /* enable all interrupts */
+ imxenet_miibus_writereg(dev, phy, 0x1b, 0xff00);
+ break;
+ }
+}
+
+void
+imxenet_init_rxd(struct imxenet_softc *sc)
+{
+ int i;
+
+ memset(sc->rx_desc_base, 0, ENET_MAX_RXD * sizeof(struct imxenet_buf_desc));
+
+ for (i = 0; i < ENET_MAX_RXD; i++)
+ {
+ sc->rx_desc_base[i].status = ENET_RXD_EMPTY;
+ sc->rx_desc_base[i].data_pointer = sc->rbdma.dma_paddr + i * ENET_MAX_PKT_SIZE;
+#ifdef ENET_ENHANCED_BD
+ sc->rx_desc_base[i].enhanced_status = ENET_RXD_INT;
+#endif
+ }
+
+ sc->rx_desc_base[i - 1].status |= ENET_RXD_WRAP;
+}
+
+void
+imxenet_init_txd(struct imxenet_softc *sc)
+{
+ int i;
+
+ memset(sc->tx_desc_base, 0, ENET_MAX_TXD * sizeof(struct imxenet_buf_desc));
+
+ for (i = 0; i < ENET_MAX_TXD; i++)
+ {
+ sc->tx_desc_base[i].data_pointer = sc->tbdma.dma_paddr + i * ENET_MAX_PKT_SIZE;
+ }
+
+ sc->tx_desc_base[i - 1].status |= ENET_TXD_WRAP;
+}
+
+void
+imxenet_init(struct imxenet_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ int speed = 0;
+
+ /* reset the controller */
+ HSET4(sc, ENET_ECR, ENET_ECR_RESET);
+ while(HREAD4(sc, ENET_ECR) & ENET_ECR_RESET);
+
+ /* set hw address */
+ HWRITE4(sc, ENET_PALR,
+ (sc->sc_ac.ac_enaddr[0] << 24) |
+ (sc->sc_ac.ac_enaddr[1] << 16) |
+ (sc->sc_ac.ac_enaddr[2] << 8) |
+ sc->sc_ac.ac_enaddr[3]);
+ HWRITE4(sc, ENET_PAUR,
+ (sc->sc_ac.ac_enaddr[4] << 24) |
+ (sc->sc_ac.ac_enaddr[5] << 16));
+
+ /* clear outstanding interrupts */
+ HWRITE4(sc, ENET_EIR, 0xffffffff);
+
+ /* set address filter */
+ HWRITE4(sc, ENET_GAUR, 0);
+ HWRITE4(sc, ENET_GALR, 0);
+
+ /* set max receive buffer size, 3-0 bits always zero for alignment */
+ HWRITE4(sc, ENET_MRBR, ENET_MAX_PKT_SIZE);
+
+ /* set descriptor */
+ HWRITE4(sc, ENET_TDSR, sc->txdma.dma_paddr);
+ HWRITE4(sc, ENET_RDSR, sc->rxdma.dma_paddr);
+
+ /* init descriptor */
+ imxenet_init_txd(sc);
+ imxenet_init_rxd(sc);
+
+ /* set it to full-duplex */
+ HWRITE4(sc, ENET_TCR, ENET_TCR_FDEN);
+
+ /*
+ * Set max frame length to 1518 or 1522 with VLANs,
+ * pause frames and promisc mode.
+ * XXX: RGMII mode - phy dependant
+ */
+ HWRITE4(sc, ENET_RCR,
+ ENET_RCR_MAX_FL(1522) | ENET_RCR_RGMII_MODE | ENET_RCR_MII_MODE |
+ ENET_RCR_FCE);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, ENET_MSCR,
+ (((imxccm_get_fecclk() + (ENET_MII_CLK << 2) - 1) / (ENET_MII_CLK << 2)) << 1) | 0x100);
+
+ /* RX FIFO treshold and pause */
+ HWRITE4(sc, ENET_RSEM, 0x84);
+ HWRITE4(sc, ENET_RSFL, 16);
+ HWRITE4(sc, ENET_RAEM, 8);
+ HWRITE4(sc, ENET_RAFL, 8);
+ HWRITE4(sc, ENET_OPD, 0xFFF0);
+
+ /* do store and forward, only i.MX6, needs to be set correctly else */
+ HWRITE4(sc, ENET_TFWR, ENET_TFWR_STRFWD);
+
+ /* enable gigabit-ethernet and set it to support little-endian */
+ switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
+ case IFM_1000_T: /* Gigabit */
+ speed |= ENET_ECR_SPEED;
+ break;
+ default:
+ speed &= ~ENET_ECR_SPEED;
+ }
+ HWRITE4(sc, ENET_ECR, ENET_ECR_ETHEREN | speed | ENET_ECR_DBSWP);
+
+#ifdef ENET_ENHANCED_BD
+ HSET4(sc, ENET_ECR, ENET_ECR_EN1588);
+#endif
+
+ /* rx descriptors are ready */
+ HWRITE4(sc, ENET_RDAR, ENET_RDAR_RDAR);
+
+ /* enable interrupts for tx/rx */
+ HWRITE4(sc, ENET_EIMR, ENET_EIR_TXF | ENET_EIR_RXF);
+ HWRITE4(sc, ENET_EIMR, 0xffffffff);
+
+ /* Indicate we are up and running. */
+ ifp->if_flags |= IFF_RUNNING;
+ ifp->if_flags &= ~IFF_OACTIVE;
+}
+
+void
+imxenet_stop(struct imxenet_softc *sc)
+{
+ /* reset the controller */
+ HSET4(sc, ENET_ECR, ENET_ECR_RESET);
+ while(HREAD4(sc, ENET_ECR) & ENET_ECR_RESET);
+}
+
+void
+imxenet_iff(struct imxenet_softc *sc)
+{
+ // Set interface features
+}
+
+int
+imxenet_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ struct imxenet_softc *sc = ifp->if_softc;
+ struct ifreq *ifr = (struct ifreq *)data;
+ struct ifaddr *ifa = (struct ifaddr *)data;
+ int s, error = 0;
+
+ s = splnet();
+
+ switch (cmd) {
+ case SIOCSIFADDR:
+ ifp->if_flags |= IFF_UP;
+ if (!(ifp->if_flags & IFF_RUNNING))
+ imxenet_init(sc);
+#ifdef INET
+ if (ifa->ifa_addr->sa_family == AF_INET)
+ arp_ifinit(&sc->sc_ac, ifa);
+#endif
+ break;
+
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP) {
+ if (ifp->if_flags & IFF_RUNNING)
+ error = ENETRESET;
+ else
+ imxenet_init(sc);
+ } else {
+ if (ifp->if_flags & IFF_RUNNING)
+ imxenet_stop(sc);
+ }
+ break;
+
+ case SIOCGIFMEDIA:
+ case SIOCSIFMEDIA:
+ error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
+ break;
+
+ default:
+ error = ether_ioctl(ifp, &sc->sc_ac, cmd, data);
+ }
+
+ if (error == ENETRESET) {
+ if (ifp->if_flags & IFF_RUNNING)
+ imxenet_iff(sc);
+ error = 0;
+ }
+
+ splx(s);
+ return(error);
+}
+
+void
+imxenet_start(struct ifnet *ifp)
+{
+ struct imxenet_softc *sc = ifp->if_softc;
+ struct mbuf *m_head = NULL;
+
+ if ((ifp->if_flags & (IFF_OACTIVE | IFF_RUNNING)) != IFF_RUNNING)
+ return;
+
+ for (;;) {
+ IFQ_POLL(&ifp->if_snd, m_head);
+ if (m_head == NULL)
+ break;
+
+ if (imxenet_encap(sc, m_head)) {
+ ifp->if_flags |= IFF_OACTIVE;
+ break;
+ }
+
+ IFQ_DEQUEUE(&ifp->if_snd, m_head);
+
+ ifp->if_opackets++;
+
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
+#endif
+
+ m_freem(m_head);
+ }
+}
+
+int
+imxenet_encap(struct imxenet_softc *sc, struct mbuf *m)
+{
+ if (sc->tx_desc_base[sc->cur_tx].status & ENET_TXD_READY) {
+ printf("imxenet: tx queue full!\n");
+ return EIO;
+ }
+
+ if (m->m_pkthdr.len > ENET_MAX_PKT_SIZE) {
+ printf("imxenet: packet too big\n");
+ return EIO;
+ }
+
+ /* copy in the actual packet */
+ m_copydata(m, 0, m->m_pkthdr.len, (caddr_t)sc->tx_buffer_base[sc->cur_tx].data);
+
+ sc->tx_desc_base[sc->cur_tx].data_length = m->m_pkthdr.len;
+
+ sc->tx_desc_base[sc->cur_tx].status &= ~ENET_TXD_STATUS_MASK;
+ sc->tx_desc_base[sc->cur_tx].status |= (ENET_TXD_READY | ENET_TXD_LAST | ENET_TXD_TC);
+
+#ifdef ENET_ENHANCED_BD
+ sc->tx_desc_base[sc->cur_tx].enhanced_status = ENET_TXD_INT;
+ sc->tx_desc_base[sc->cur_tx].update_done = 0;
+#endif
+
+ bus_dmamap_sync(sc->tbdma.dma_tag, sc->tbdma.dma_map,
+ ENET_MAX_PKT_SIZE * sc->cur_tx, ENET_MAX_PKT_SIZE,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(sc->txdma.dma_tag, sc->txdma.dma_map,
+ sizeof(struct imxenet_buf_desc) * sc->cur_tx,
+ sizeof(struct imxenet_buf_desc),
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+
+ /* tx descriptors are ready */
+ HWRITE4(sc, ENET_TDAR, ENET_TDAR_TDAR);
+
+ if (sc->tx_desc_base[sc->cur_tx].status & ENET_TXD_WRAP)
+ sc->cur_tx = 0;
+ else
+ sc->cur_tx++;
+
+ return 0;
+}
+
+struct mbuf *
+imxenet_newbuf(void)
+{
+ struct mbuf *m;
+
+ MGETHDR(m, M_DONTWAIT, MT_DATA);
+ if (m == NULL)
+ return (NULL);
+
+ MCLGET(m, M_DONTWAIT);
+ if (!(m->m_flags & M_EXT)) {
+ m_freem(m);
+ return (NULL);
+ }
+
+ return (m);
+}
+
+/*
+ * Established by attachment driver at interrupt priority IPL_NET.
+ */
+int
+imxenet_intr(void *arg)
+{
+ struct imxenet_softc *sc = arg;
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+ u_int32_t status;
+
+ /* Find out which interrupts are pending. */
+ status = HREAD4(sc, ENET_EIR);
+
+ /* Acknowledge the interrupts we are about to handle. */
+ HWRITE4(sc, ENET_EIR, status);
+
+ /*
+ * Wake up the blocking process to service command
+ * related interrupt(s).
+ */
+ if (ISSET(status, ENET_EIR_MII)) {
+ sc->intr_status |= status;
+ wakeup(&sc->intr_status);
+ }
+
+ /*
+ * Handle incoming packets.
+ */
+ if (ISSET(status, ENET_EIR_RXF)) {
+ if (ifp->if_flags & IFF_RUNNING)
+ imxenet_recv(sc);
+ }
+
+ return 1;
+}
+
+void
+imxenet_recv(struct imxenet_softc *sc)
+{
+ struct ifnet *ifp = &sc->sc_ac.ac_if;
+
+ bus_dmamap_sync(sc->rbdma.dma_tag, sc->rbdma.dma_map,
+ 0, sc->rbdma.dma_size,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ bus_dmamap_sync(sc->rxdma.dma_tag, sc->rxdma.dma_map,
+ 0, sc->rxdma.dma_size,
+ BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
+
+ while (!(sc->rx_desc_base[sc->cur_rx].status & ENET_RXD_EMPTY))
+ {
+ struct mbuf *m;
+ m = imxenet_newbuf();
+
+ if (m == NULL) {
+ ifp->if_ierrors++;
+ goto done;
+ }
+
+ ifp->if_ipackets++;
+ m->m_pkthdr.rcvif = ifp;
+ m->m_pkthdr.len = m->m_len = sc->rx_desc_base[sc->cur_rx].data_length;
+ m_adj(m, ETHER_ALIGN);
+
+ memcpy(mtod(m, char *), sc->rx_buffer_base[sc->cur_rx].data,
+ sc->rx_desc_base[sc->cur_rx].data_length);
+
+ sc->rx_desc_base[sc->cur_rx].status |= ENET_RXD_EMPTY;
+ sc->rx_desc_base[sc->cur_rx].data_length = 0;
+
+ bus_dmamap_sync(sc->rbdma.dma_tag, sc->rbdma.dma_map,
+ ENET_MAX_PKT_SIZE * sc->cur_rx, ENET_MAX_PKT_SIZE,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ bus_dmamap_sync(sc->rxdma.dma_tag, sc->rxdma.dma_map,
+ sizeof(struct imxenet_buf_desc) * sc->cur_rx,
+ sizeof(struct imxenet_buf_desc),
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+
+ if (sc->rx_desc_base[sc->cur_rx].status & ENET_RXD_WRAP)
+ sc->cur_rx = 0;
+ else
+ sc->cur_rx++;
+
+ /* push the packet up */
+#if NBPFILTER > 0
+ if (ifp->if_bpf)
+ bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
+#endif
+ ether_input_mbuf(ifp, m);
+ }
+
+done:
+ /* rx descriptors are ready */
+ HWRITE4(sc, ENET_RDAR, ENET_RDAR_RDAR);
+}
+
+int
+imxenet_wait_intr(struct imxenet_softc *sc, int mask, int timo)
+{
+ int status;
+ int s;
+
+ s = splnet();
+
+ status = sc->intr_status;
+ while (status == 0) {
+ if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
+ == EWOULDBLOCK) {
+ break;
+ }
+ status = sc->intr_status;
+ }
+ sc->intr_status &= ~status;
+
+ splx(s);
+ return status;
+}
+
+/*
+ * MII
+ * Interrupts need ENET_ECR_ETHEREN to be set,
+ * so we just read the interrupt status registers.
+ */
+int
+imxenet_miibus_readreg(struct device *dev, int phy, int reg)
+{
+ int r = 0;
+ struct imxenet_softc *sc = (struct imxenet_softc *)dev;
+
+ HSET4(sc, ENET_EIR, ENET_EIR_MII);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, ENET_MMFR,
+ ENET_MMFR_ST | ENET_MMFR_OP_RD | ENET_MMFR_TA |
+ phy << ENET_MMFR_PA_SHIFT | reg << ENET_MMFR_RA_SHIFT);
+
+ while(!(HREAD4(sc, ENET_EIR) & ENET_EIR_MII));
+
+ r = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ENET_MMFR);
+
+ return (r & 0xffff);
+}
+
+void
+imxenet_miibus_writereg(struct device *dev, int phy, int reg, int val)
+{
+ struct imxenet_softc *sc = (struct imxenet_softc *)dev;
+
+ HSET4(sc, ENET_EIR, ENET_EIR_MII);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, ENET_MMFR,
+ ENET_MMFR_ST | ENET_MMFR_OP_WR | ENET_MMFR_TA |
+ phy << ENET_MMFR_PA_SHIFT | reg << ENET_MMFR_RA_SHIFT |
+ (val & 0xffff));
+
+ while(!(HREAD4(sc, ENET_EIR) & ENET_EIR_MII));
+
+ return;
+}
+
+void
+imxenet_miibus_statchg(struct device *dev)
+{
+ struct imxenet_softc *sc = (struct imxenet_softc *)dev;
+ int ecr;
+
+ ecr = HREAD4(sc, ENET_ECR);
+ switch (IFM_SUBTYPE(sc->sc_mii.mii_media_active)) {
+ case IFM_1000_T: /* Gigabit */
+ ecr |= ENET_ECR_SPEED;
+ break;
+ default:
+ ecr &= ~ENET_ECR_SPEED;
+ }
+ HWRITE4(sc, ENET_ECR, ecr);
+
+ return;
+}
+
+int
+imxenet_ifmedia_upd(struct ifnet *ifp)
+{
+ struct imxenet_softc *sc = ifp->if_softc;
+ struct mii_data *mii = &sc->sc_mii;
+ int err;
+ if (mii->mii_instance) {
+ struct mii_softc *miisc;
+
+ LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
+ mii_phy_reset(miisc);
+ }
+ err = mii_mediachg(mii);
+ return (err);
+}
+
+void
+imxenet_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
+{
+ struct imxenet_softc *sc = ifp->if_softc;
+ struct mii_data *mii = &sc->sc_mii;
+
+ mii_pollstat(mii);
+
+ ifmr->ifm_active = mii->mii_media_active;
+ ifmr->ifm_status = mii->mii_media_status;
+}
+
+/*
+ * Manage DMA'able memory.
+ */
+int
+imxenet_dma_malloc(struct imxenet_softc *sc, bus_size_t size,
+ struct imxenet_dma_alloc *dma)
+{
+ int r;
+
+ dma->dma_tag = sc->sc_dma_tag;
+ r = bus_dmamem_alloc(dma->dma_tag, size, ENET_ALIGNMENT, 0, &dma->dma_seg,
+ 1, &dma->dma_nseg, BUS_DMA_NOWAIT);
+ if (r != 0) {
+ printf("%s: imxenet_dma_malloc: bus_dmammem_alloc failed; "
+ "size %lu, error %d\n", sc->sc_dev.dv_xname,
+ (unsigned long)size, r);
+ goto fail_0;
+ }
+
+ r = bus_dmamem_map(dma->dma_tag, &dma->dma_seg, dma->dma_nseg, size,
+ &dma->dma_vaddr, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
+ if (r != 0) {
+ printf("%s: imxenet_dma_malloc: bus_dmammem_map failed; "
+ "size %lu, error %d\n", sc->sc_dev.dv_xname,
+ (unsigned long)size, r);
+ goto fail_1;
+ }
+
+ r = bus_dmamap_create(dma->dma_tag, size, 1,
+ size, 0, BUS_DMA_NOWAIT, &dma->dma_map);
+ if (r != 0) {
+ printf("%s: imxenet_dma_malloc: bus_dmamap_create failed; "
+ "error %u\n", sc->sc_dev.dv_xname, r);
+ goto fail_2;
+ }
+
+ r = bus_dmamap_load(dma->dma_tag, dma->dma_map,
+ dma->dma_vaddr, size, NULL,
+ BUS_DMA_NOWAIT);
+ if (r != 0) {
+ printf("%s: imxenet_dma_malloc: bus_dmamap_load failed; "
+ "error %u\n", sc->sc_dev.dv_xname, r);
+ goto fail_3;
+ }
+
+ dma->dma_size = size;
+ dma->dma_paddr = dma->dma_map->dm_segs[0].ds_addr;
+ return (0);
+
+fail_3:
+ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
+fail_2:
+ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size);
+fail_1:
+ bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg);
+fail_0:
+ dma->dma_map = NULL;
+ dma->dma_tag = NULL;
+
+ return (r);
+}
+
+void
+imxenet_dma_free(struct imxenet_softc *sc, struct imxenet_dma_alloc *dma)
+{
+ if (dma->dma_tag == NULL)
+ return;
+
+ if (dma->dma_map != NULL) {
+ bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0,
+ dma->dma_map->dm_mapsize,
+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
+ bus_dmamap_unload(dma->dma_tag, dma->dma_map);
+ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, dma->dma_size);
+ bus_dmamem_free(dma->dma_tag, &dma->dma_seg, dma->dma_nseg);
+ bus_dmamap_destroy(dma->dma_tag, dma->dma_map);
+ }
+ dma->dma_tag = NULL;
+}
diff --git a/sys/arch/armv7/imx/imxenet.h b/sys/arch/armv7/imx/imxenet.h
new file mode 100644
index 00000000000..880454b7aa6
--- /dev/null
+++ b/sys/arch/armv7/imx/imxenet.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: imxenet.h,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* what should we use? */
+#define ENET_MAX_TXD 32
+#define ENET_MAX_RXD 32
+
+#define ENET_MAX_PKT_SIZE 1536
+
+#define ENET_ROUNDUP(size, unit) (((size) + (unit) - 1) & ~((unit) - 1))
+
+/* buffer descriptor status bits */
+#define ENET_RXD_EMPTY (1 << 15)
+#define ENET_RXD_WRAP (1 << 13)
+#define ENET_RXD_LAST (1 << 11)
+#define ENET_RXD_MISS (1 << 8)
+#define ENET_RXD_BC (1 << 7)
+#define ENET_RXD_MC (1 << 6)
+#define ENET_RXD_LG (1 << 5)
+#define ENET_RXD_NO (1 << 4)
+#define ENET_RXD_CR (1 << 2)
+#define ENET_RXD_OV (1 << 1)
+#define ENET_RXD_TR (1 << 0)
+
+#define ENET_TXD_READY (1 << 15)
+#define ENET_TXD_WRAP (1 << 13)
+#define ENET_TXD_LAST (1 << 11)
+#define ENET_TXD_TC (1 << 10)
+#define ENET_TXD_ABC (1 << 9)
+#define ENET_TXD_STATUS_MASK 0x3ff
+
+#ifdef ENET_ENHANCED_BD
+/* enhanced */
+#define ENET_RXD_INT (1 << 23)
+
+#define ENET_TXD_INT (1 << 30)
+#endif
+
+
+/*
+ * Bus dma allocation structure used by
+ * imxenet_dma_malloc and imxenet_dma_free.
+ */
+struct imxenet_dma_alloc {
+ bus_addr_t dma_paddr;
+ caddr_t dma_vaddr;
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+ bus_dma_segment_t dma_seg;
+ bus_size_t dma_size;
+ int dma_nseg;
+};
+
+struct imxenet_buf_desc {
+ uint16_t data_length; /* payload's length in bytes */
+ uint16_t status; /* BD's status (see datasheet) */
+ uint32_t data_pointer; /* payload's buffer address */
+#ifdef ENET_ENHANCED_BD
+ uint32_t enhanced_status; /* enhanced status with IEEE 1588 */
+ uint32_t reserved0; /* reserved */
+ uint32_t update_done; /* buffer descriptor update done */
+ uint32_t timestamp; /* IEEE 1588 timestamp */
+ uint32_t reserved1[2]; /* reserved */
+#endif
+};
+
+struct imxenet_buffer {
+ uint8_t data[ENET_MAX_PKT_SIZE];
+};
diff --git a/sys/arch/armv7/imx/imxesdhc.c b/sys/arch/armv7/imx/imxesdhc.c
new file mode 100644
index 00000000000..7fec46214e8
--- /dev/null
+++ b/sys/arch/armv7/imx/imxesdhc.c
@@ -0,0 +1,963 @@
+/* $OpenBSD: imxesdhc.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* i.MX SD/MMC support derived from /sys/dev/sdmmc/sdhc.c */
+
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+
+#include <dev/sdmmc/sdmmcchip.h>
+#include <dev/sdmmc/sdmmcvar.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxccmvar.h>
+#include <armv7/imx/imxgpiovar.h>
+
+/* registers */
+#define SDHC_DS_ADDR 0x00
+#define SDHC_BLK_ATT 0x04
+#define SDHC_CMD_ARG 0x08
+#define SDHC_CMD_XFR_TYP 0x0c
+#define SDHC_CMD_RSP0 0x10
+#define SDHC_CMD_RSP1 0x14
+#define SDHC_CMD_RSP2 0x18
+#define SDHC_CMD_RSP3 0x1c
+#define SDHC_DATA_BUFF_ACC_PORT 0x20
+#define SDHC_PRES_STATE 0x24
+#define SDHC_PROT_CTRL 0x28
+#define SDHC_SYS_CTRL 0x2c
+#define SDHC_INT_STATUS 0x30
+#define SDHC_INT_STATUS_EN 0x34
+#define SDHC_INT_SIGNAL_EN 0x38
+#define SDHC_AUTOCMD12_ERR_STATUS 0x3c
+#define SDHC_HOST_CTRL_CAP 0x40
+#define SDHC_WTMK_LVL 0x44
+#define SDHC_MIX_CTRL 0x48
+#define SDHC_FORCE_EVENT 0x50
+#define SDHC_ADMA_ERR_STATUS 0x54
+#define SDHC_ADMA_SYS_ADDR 0x58
+#define SDHC_DLL_CTRL 0x60
+#define SDHC_DLL_STATUS 0x64
+#define SDHC_CLK_TUNE_CTRL_STATUS 0x68
+#define SDHC_VEND_SPEC 0xc0
+#define SDHC_MMC_BOOT 0xc4
+#define SDHC_VEND_SPEC2 0xc8
+#define SDHC_HOST_CTRL_VER 0xfc
+
+/* bits and bytes */
+#define SDHC_BLK_ATT_BLKCNT_MAX 0xffff
+#define SDHC_BLK_ATT_BLKCNT_SHIFT 16
+#define SDHC_BLK_ATT_BLKSIZE_SHIFT 0
+#define SDHC_CMD_XFR_TYP_CMDINDX_SHIFT 24
+#define SDHC_CMD_XFR_TYP_CMDINDX_SHIFT_MASK (0x3f << SDHC_CMD_XFR_TYP_CMDINDX_SHIFT)
+#define SDHC_CMD_XFR_TYP_CMDTYP_SHIFT 22
+#define SDHC_CMD_XFR_TYP_DPSEL_SHIFT 21
+#define SDHC_CMD_XFR_TYP_DPSEL (1 << SDHC_CMD_XFR_TYP_DPSEL_SHIFT)
+#define SDHC_CMD_XFR_TYP_CICEN_SHIFT 20
+#define SDHC_CMD_XFR_TYP_CICEN (1 << SDHC_CMD_XFR_TYP_CICEN_SHIFT)
+#define SDHC_CMD_XFR_TYP_CCCEN_SHIFT 19
+#define SDHC_CMD_XFR_TYP_CCCEN (1 << SDHC_CMD_XFR_TYP_CCCEN_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSPTYP_SHIFT 16
+#define SDHC_CMD_XFR_TYP_RSP_NONE (0x0 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSP136 (0x1 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSP48 (0x2 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_CMD_XFR_TYP_RSP48B (0x3 << SDHC_CMD_XFR_TYP_RSPTYP_SHIFT)
+#define SDHC_PRES_STATE_WPSPL (1 << 19)
+#define SDHC_PRES_STATE_BREN (1 << 11)
+#define SDHC_PRES_STATE_BWEN (1 << 10)
+#define SDHC_PRES_STATE_SDSTB (1 << 3)
+#define SDHC_PRES_STATE_DLA (1 << 2)
+#define SDHC_PRES_STATE_CDIHB (1 << 1)
+#define SDHC_PRES_STATE_CIHB (1 << 0)
+#define SDHC_SYS_CTRL_RSTA (1 << 24)
+#define SDHC_SYS_CTRL_RSTC (1 << 25)
+#define SDHC_SYS_CTRL_RSTD (1 << 26)
+#define SDHC_SYS_CTRL_CLOCK_MASK (0xfff << 4)
+#define SDHC_SYS_CTRL_CLOCK_DIV_SHIFT 4
+#define SDHC_SYS_CTRL_CLOCK_PRE_SHIFT 8
+#define SDHC_SYS_CTRL_DTOCV_SHIFT 16
+#define SDHC_INT_STATUS_CC (1 << 0)
+#define SDHC_INT_STATUS_TC (1 << 1)
+#define SDHC_INT_STATUS_BGE (1 << 2)
+#define SDHC_INT_STATUS_DINT (1 << 3)
+#define SDHC_INT_STATUS_BWR (1 << 4)
+#define SDHC_INT_STATUS_BRR (1 << 5)
+#define SDHC_INT_STATUS_CINS (1 << 6)
+#define SDHC_INT_STATUS_CRM (1 << 7)
+#define SDHC_INT_STATUS_CINT (1 << 8)
+#define SDHC_INT_STATUS_CTOE (1 << 16)
+#define SDHC_INT_STATUS_CCE (1 << 17)
+#define SDHC_INT_STATUS_CEBE (1 << 18)
+#define SDHC_INT_STATUS_CIC (1 << 19)
+#define SDHC_INT_STATUS_DTOE (1 << 20)
+#define SDHC_INT_STATUS_DCE (1 << 21)
+#define SDHC_INT_STATUS_DEBE (1 << 22)
+#define SDHC_INT_STATUS_DMAE (1 << 28)
+#define SDHC_INT_STATUS_CMD_ERR (SDHC_INT_STATUS_CIC | SDHC_INT_STATUS_CEBE | SDHC_INT_STATUS_CCE)
+#define SDHC_INT_STATUS_ERR (SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_CCE | SDHC_INT_STATUS_CEBE | \
+ SDHC_INT_STATUS_CIC | SDHC_INT_STATUS_DTOE | SDHC_INT_STATUS_DCE | \
+ SDHC_INT_STATUS_DEBE | SDHC_INT_STATUS_DMAE)
+#define SDHC_MIX_CTRL_DMAEN (1 << 0)
+#define SDHC_MIX_CTRL_BCEN (1 << 1)
+#define SDHC_MIX_CTRL_AC12EN (1 << 2)
+#define SDHC_MIX_CTRL_DTDSEL (1 << 4)
+#define SDHC_MIX_CTRL_MSBSEL (1 << 5)
+#define SDHC_PROT_CTRL_DMASEL_SDMA_MASK (0x3 << 8)
+#define SDHC_HOST_CTRL_CAP_MBL_SHIFT 16
+#define SDHC_HOST_CTRL_CAP_MBL_MASK 0x7
+#define SDHC_HOST_CTRL_CAP_VS33 (1 << 24)
+#define SDHC_HOST_CTRL_CAP_VS30 (1 << 25)
+#define SDHC_HOST_CTRL_CAP_VS18 (1 << 26)
+#define SDHC_VEND_SPEC_FRC_SDCLK_ON (1 << 8)
+#define SDHC_WTMK_LVL_RD_WML_SHIFT 0
+#define SDHC_WTMK_LVL_WR_WML_SHIFT 16
+
+#define SDHC_COMMAND_TIMEOUT hz
+#define SDHC_BUFFER_TIMEOUT hz
+#define SDHC_TRANSFER_TIMEOUT hz
+
+void imxesdhc_attach(struct device *parent, struct device *self, void *args);
+
+#include <machine/bus.h>
+
+struct imxesdhc_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ void *sc_ih; /* Interrupt handler */
+ u_int sc_flags;
+
+ int unit; /* unit id */
+ struct device *sdmmc; /* generic SD/MMC device */
+ int clockbit; /* clock control bit */
+ u_int clkbase; /* base clock frequency in KHz */
+ int maxblklen; /* maximum block length */
+ int flags; /* flags for this host */
+ uint32_t ocr; /* OCR value from capabilities */
+// u_int8_t regs[14]; /* host controller state */
+ uint32_t intr_status; /* soft interrupt status */
+ uint32_t intr_error_status; /* */
+};
+
+
+/* Host controller functions called by the attachment driver. */
+int imxesdhc_host_found(struct imxesdhc_softc *, bus_space_tag_t,
+ bus_space_handle_t, bus_size_t, int);
+void imxesdhc_power(int, void *);
+void imxesdhc_shutdown(void *);
+int imxesdhc_intr(void *);
+
+/* RESET MODES */
+#define MMC_RESET_DAT 1
+#define MMC_RESET_CMD 2
+#define MMC_RESET_ALL (MMC_RESET_CMD|MMC_RESET_DAT)
+
+#define HDEVNAME(sc) ((sc)->sc_dev.dv_xname)
+
+/* flag values */
+#define SHF_USE_DMA 0x0001
+
+/* SDHC should only be accessed with 4 byte reads or writes. */
+#define HREAD4(sc, reg) \
+ (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE4(sc, reg, val) \
+ bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET4(sc, reg, bits) \
+ HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
+#define HCLR4(sc, reg, bits) \
+ HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
+
+int imxesdhc_host_reset(sdmmc_chipset_handle_t);
+uint32_t imxesdhc_host_ocr(sdmmc_chipset_handle_t);
+int imxesdhc_host_maxblklen(sdmmc_chipset_handle_t);
+int imxesdhc_card_detect(sdmmc_chipset_handle_t);
+int imxesdhc_bus_power(sdmmc_chipset_handle_t, uint32_t);
+int imxesdhc_bus_clock(sdmmc_chipset_handle_t, int);
+void imxesdhc_card_intr_mask(sdmmc_chipset_handle_t, int);
+void imxesdhc_card_intr_ack(sdmmc_chipset_handle_t);
+void imxesdhc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *);
+int imxesdhc_start_command(struct imxesdhc_softc *, struct sdmmc_command *);
+int imxesdhc_wait_state(struct imxesdhc_softc *, uint32_t, uint32_t);
+int imxesdhc_soft_reset(struct imxesdhc_softc *, int);
+int imxesdhc_wait_intr(struct imxesdhc_softc *, int, int);
+void imxesdhc_transfer_data(struct imxesdhc_softc *, struct sdmmc_command *);
+void imxesdhc_read_data(struct imxesdhc_softc *, u_char *, int);
+void imxesdhc_write_data(struct imxesdhc_softc *, u_char *, int);
+
+//#define SDHC_DEBUG
+#ifdef SDHC_DEBUG
+int imxesdhcdebug = 20;
+#define DPRINTF(n,s) do { if ((n) <= imxesdhcdebug) printf s; } while (0)
+#else
+#define DPRINTF(n,s) do {} while(0)
+#endif
+
+struct sdmmc_chip_functions imxesdhc_functions = {
+ /* host controller reset */
+ imxesdhc_host_reset,
+ /* host controller capabilities */
+ imxesdhc_host_ocr,
+ imxesdhc_host_maxblklen,
+ /* card detection */
+ imxesdhc_card_detect,
+ /* bus power and clock frequency */
+ imxesdhc_bus_power,
+ imxesdhc_bus_clock,
+ /* command execution */
+ imxesdhc_exec_command,
+ /* card interrupt */
+ imxesdhc_card_intr_mask,
+ imxesdhc_card_intr_ack
+};
+
+struct cfdriver imxesdhc_cd = {
+ NULL, "imxesdhc", DV_DULL
+};
+
+struct cfattach imxesdhc_ca = {
+ sizeof(struct imxesdhc_softc), NULL, imxesdhc_attach
+};
+
+void
+imxesdhc_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imxesdhc_softc *sc = (struct imxesdhc_softc *) self;
+ struct imx_attach_args *ia = args;
+ struct sdmmcbus_attach_args saa;
+ int error = 1;
+ uint32_t caps;
+
+ sc->unit = ia->ia_dev->unit;
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxesdhc_attach: bus_space_map failed!");
+
+ printf("\n");
+
+ /* XXX DMA channels? */
+
+ sc->sc_ih = arm_intr_establish(ia->ia_dev->irq[0], IPL_SDMMC,
+ imxesdhc_intr, sc, sc->sc_dev.dv_xname);
+
+ /*
+ * Reset the host controller and enable interrupts.
+ */
+ if (imxesdhc_host_reset(sc))
+ goto err;
+
+ /* Determine host capabilities. */
+ caps = HREAD4(sc, SDHC_HOST_CTRL_CAP);
+
+ /*
+ * Determine the base clock frequency. (2.2.24)
+ */
+ sc->clkbase = imxccm_get_usdhx(ia->ia_dev->unit + 1);
+
+ /*
+ * Determine SD bus voltage levels supported by the controller.
+ */
+ if (caps & SDHC_HOST_CTRL_CAP_VS18)
+ SET(sc->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V);
+ if (caps & SDHC_HOST_CTRL_CAP_VS30)
+ SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V);
+ if (caps & SDHC_HOST_CTRL_CAP_VS33)
+ SET(sc->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V);
+
+ /*
+ * Determine max block size.
+ */
+ switch ((caps >> SDHC_HOST_CTRL_CAP_MBL_SHIFT)
+ & SDHC_HOST_CTRL_CAP_MBL_MASK) {
+ case 0:
+ sc->maxblklen = 512;
+ break;
+ case 1:
+ sc->maxblklen = 1024;
+ break;
+ case 2:
+ sc->maxblklen = 2048;
+ break;
+ case 3:
+ sc->maxblklen = 4096;
+ break;
+ default:
+ sc->maxblklen = 512;
+ printf("invalid capability blocksize in capa %08x,"
+ " trying 512\n", caps);
+ }
+
+ /* somewhere this blksize might be used instead of the device's */
+ sc->maxblklen = 512;
+
+ /*
+ * Attach the generic SD/MMC bus driver. (The bus driver must
+ * not invoke any chipset functions before it is attached.)
+ */
+
+ bzero(&saa, sizeof(saa));
+ saa.saa_busname = "sdmmc";
+ saa.sct = &imxesdhc_functions;
+ saa.sch = sc;
+
+ sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL);
+ if (sc->sdmmc == NULL) {
+ error = 0;
+ goto err;
+ }
+
+ return;
+
+err:
+ return;
+}
+
+
+/*
+ * Power hook established by or called from attachment driver.
+ */
+void
+imxesdhc_power(int why, void *arg)
+{
+}
+
+/*
+ * Shutdown hook established by or called from attachment driver.
+ */
+void
+imxesdhc_shutdown(void *arg)
+{
+ struct imxesdhc_softc *sc = arg;
+
+ /* XXX chip locks up if we don't disable it before reboot. */
+ (void)imxesdhc_host_reset(sc);
+}
+
+/*
+ * Reset the host controller. Called during initialization, when
+ * cards are removed, upon resume, and during error recovery.
+ */
+int
+imxesdhc_host_reset(sdmmc_chipset_handle_t sch)
+{
+ struct imxesdhc_softc *sc = sch;
+ u_int32_t imask;
+ int error;
+ int s;
+
+ s = splsdmmc();
+
+ /* Disable all interrupts. */
+ HWRITE4(sc, SDHC_INT_STATUS_EN, 0);
+ HWRITE4(sc, SDHC_INT_SIGNAL_EN, 0);
+
+ /*
+ * Reset the entire host controller and wait up to 100ms for
+ * the controller to clear the reset bit.
+ */
+ if ((error = imxesdhc_soft_reset(sc, SDHC_SYS_CTRL_RSTA)) != 0) {
+ splx(s);
+ return (error);
+ }
+
+ /* Set data timeout counter value to max for now. */
+ HSET4(sc, SDHC_SYS_CTRL, 0xe << SDHC_SYS_CTRL_DTOCV_SHIFT);
+
+ /* Enable interrupts. */
+ imask = SDHC_INT_STATUS_CC | SDHC_INT_STATUS_TC |
+ SDHC_INT_STATUS_BGE |
+#ifdef SDHC_DMA
+ SHDC_INT_STATUS_DINT;
+#else
+ SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR;
+#endif
+
+ imask |= SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_CCE |
+ SDHC_INT_STATUS_CEBE | SDHC_INT_STATUS_CIC |
+ SDHC_INT_STATUS_DTOE | SDHC_INT_STATUS_DCE |
+ SDHC_INT_STATUS_DEBE | SDHC_INT_STATUS_DMAE;
+
+ HWRITE4(sc, SDHC_INT_STATUS_EN, imask);
+ HWRITE4(sc, SDHC_INT_SIGNAL_EN, imask);
+
+ // Use no or simple DMA
+ HWRITE4(sc, SDHC_PROT_CTRL,
+ HREAD4(sc, SDHC_PROT_CTRL) & ~SDHC_PROT_CTRL_DMASEL_SDMA_MASK);
+
+ splx(s);
+ return 0;
+}
+
+uint32_t
+imxesdhc_host_ocr(sdmmc_chipset_handle_t sch)
+{
+ struct imxesdhc_softc *sc = sch;
+ return sc->ocr;
+}
+
+int
+imxesdhc_host_maxblklen(sdmmc_chipset_handle_t sch)
+{
+ struct imxesdhc_softc *sc = sch;
+ return sc->maxblklen;
+}
+
+/*
+ * Return non-zero if the card is currently inserted.
+ */
+int
+imxesdhc_card_detect(sdmmc_chipset_handle_t sch)
+{
+ struct imxesdhc_softc *sc = sch;
+ int gpio;
+
+ switch (board_id)
+ {
+ case BOARD_ID_IMX6_PHYFLEX:
+ switch (sc->unit) {
+ case 1:
+ gpio = 0*32 + 2;
+ break;
+ case 2:
+ gpio = 4*32 + 22;
+ break;
+ default:
+ return 0;
+ }
+ return imxgpio_get_bit(gpio) ? 0 : 1;
+ case BOARD_ID_IMX6_SABRELITE:
+ switch (sc->unit) {
+ case 2:
+ gpio = 6*32 + 0;
+ break;
+ case 3:
+ gpio = 1*32 + 6;
+ break;
+ default:
+ return 0;
+ }
+ return imxgpio_get_bit(gpio) ? 0 : 1;
+ default:
+ return 1;
+ }
+}
+
+/*
+ * Set or change SD bus voltage and enable or disable SD bus power.
+ * Return zero on success.
+ */
+int
+imxesdhc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr)
+{
+ return 0;
+}
+
+/*
+ * Set or change SDCLK frequency or disable the SD clock.
+ * Return zero on success.
+ */
+int
+imxesdhc_bus_clock(sdmmc_chipset_handle_t sch, int freq)
+{
+ struct imxesdhc_softc *sc = sch;
+ int div, pre_div, cur_freq, s;
+ int error = 0;
+
+ s = splsdmmc();
+
+ if (sc->clkbase / 16 > freq) {
+ for (pre_div = 2; pre_div < 256; pre_div *= 2)
+ if ((sc->clkbase / pre_div) <= (freq * 16))
+ break;
+ } else
+ pre_div = 2;
+
+ if (sc->clkbase == freq)
+ pre_div = 1;
+
+ for (div = 1; div <= 16; div++)
+ if ((sc->clkbase / (div * pre_div)) <= freq)
+ break;
+
+ div -= 1;
+ pre_div >>= 1;
+
+ cur_freq = sc->clkbase / (pre_div * 2) / (div + 1);
+
+ /* disable force CLK ouput active */
+ HCLR4(sc, SDHC_VEND_SPEC, SDHC_VEND_SPEC_FRC_SDCLK_ON);
+
+ /* wait while clock is unstable */
+ if ((error = imxesdhc_wait_state(sc, SDHC_PRES_STATE_SDSTB, SDHC_PRES_STATE_SDSTB)) != 0)
+ goto ret;
+
+ HCLR4(sc, SDHC_SYS_CTRL, SDHC_SYS_CTRL_CLOCK_MASK);
+ HSET4(sc, SDHC_SYS_CTRL, (div << SDHC_SYS_CTRL_CLOCK_DIV_SHIFT) | (pre_div << SDHC_SYS_CTRL_CLOCK_PRE_SHIFT));
+
+ /* wait while clock is unstable */
+ if ((error = imxesdhc_wait_state(sc, SDHC_PRES_STATE_SDSTB, SDHC_PRES_STATE_SDSTB)) != 0)
+ goto ret;
+
+ret:
+ splx(s);
+ return error;
+}
+
+void
+imxesdhc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable)
+{
+ printf("imxesdhc_card_intr_mask\n");
+ /* - this is SDIO card interrupt */
+ struct imxesdhc_softc *sc = sch;
+
+ if (enable) {
+ HSET4(sc, SDHC_INT_STATUS_EN, SDHC_INT_STATUS_CINT);
+ HSET4(sc, SDHC_INT_SIGNAL_EN, SDHC_INT_STATUS_CINT);
+ } else {
+ HCLR4(sc, SDHC_INT_STATUS_EN, SDHC_INT_STATUS_CINT);
+ HCLR4(sc, SDHC_INT_SIGNAL_EN, SDHC_INT_STATUS_CINT);
+ }
+}
+
+void
+imxesdhc_card_intr_ack(sdmmc_chipset_handle_t sch)
+{
+ printf("imxesdhc_card_intr_ack\n");
+ struct imxesdhc_softc *sc = sch;
+
+ HWRITE4(sc, SDHC_INT_STATUS, SDHC_INT_STATUS_CINT);
+}
+
+int
+imxesdhc_wait_state(struct imxesdhc_softc *sc, uint32_t mask, uint32_t value)
+{
+ uint32_t state;
+ int timeout;
+ state = HREAD4(sc, SDHC_PRES_STATE);
+ DPRINTF(3,("%s: wait_state %x %x %x)\n", HDEVNAME(sc),
+ mask, value, state));
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (((state = HREAD4(sc, SDHC_PRES_STATE)) & mask) == value)
+ return 0;
+ delay(10);
+ }
+ DPRINTF(0,("%s: timeout waiting for %x\n", HDEVNAME(sc),
+ value, state));
+ return ETIMEDOUT;
+}
+
+void
+imxesdhc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd)
+{
+ struct imxesdhc_softc *sc = sch;
+ int error;
+
+ /*
+ * Start the command, or mark `cmd' as failed and return.
+ */
+ error = imxesdhc_start_command(sc, cmd);
+ if (error != 0) {
+ cmd->c_error = error;
+ SET(cmd->c_flags, SCF_ITSDONE);
+ return;
+ }
+
+ /*
+ * Wait until the command phase is done, or until the command
+ * is marked done for any other reason.
+ */
+ if (!imxesdhc_wait_intr(sc, SDHC_INT_STATUS_CC, SDHC_COMMAND_TIMEOUT)) {
+ cmd->c_error = ETIMEDOUT;
+ SET(cmd->c_flags, SCF_ITSDONE);
+ return;
+ }
+
+ /*
+ * The host controller removes bits [0:7] from the response
+ * data (CRC) and we pass the data up unchanged to the bus
+ * driver (without padding).
+ */
+ if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) {
+ if (ISSET(cmd->c_flags, SCF_RSP_136)) {
+ cmd->c_resp[0] = HREAD4(sc, SDHC_CMD_RSP0);
+ cmd->c_resp[1] = HREAD4(sc, SDHC_CMD_RSP1);
+ cmd->c_resp[2] = HREAD4(sc, SDHC_CMD_RSP2);
+ cmd->c_resp[3] = HREAD4(sc, SDHC_CMD_RSP3);
+
+#ifdef SDHC_DEBUG
+ printf("resp[0] 0x%08x\nresp[1] 0x%08x\nresp[2] 0x%08x\nresp[3] 0x%08x\n", cmd->c_resp[0], cmd->c_resp[1], cmd->c_resp[2], cmd->c_resp[3]);
+#endif
+ } else {
+ cmd->c_resp[0] = HREAD4(sc, SDHC_CMD_RSP0);
+#ifdef SDHC_DEBUG
+ printf("resp[0] 0x%08x\n", cmd->c_resp[0]);
+#endif
+ }
+ }
+
+ /*
+ * If the command has data to transfer in any direction,
+ * execute the transfer now.
+ */
+ if (cmd->c_error == 0 && cmd->c_data)
+ imxesdhc_transfer_data(sc, cmd);
+
+ DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n",
+ HDEVNAME(sc), cmd->c_opcode, cmd->c_flags, cmd->c_error));
+ SET(cmd->c_flags, SCF_ITSDONE);
+}
+
+int
+imxesdhc_start_command(struct imxesdhc_softc *sc, struct sdmmc_command *cmd)
+{
+ u_int32_t blksize = 0;
+ u_int32_t blkcount = 0;
+ u_int32_t command;
+ int error;
+ int s;
+
+ DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x "
+ "proc=\"%s\"\n", HDEVNAME(sc), cmd->c_opcode, cmd->c_arg,
+ cmd->c_data, cmd->c_datalen, cmd->c_flags, curproc ?
+ curproc->p_comm : ""));
+
+ /*
+ * The maximum block length for commands should be the minimum
+ * of the host buffer size and the card buffer size. (1.7.2)
+ */
+
+ /* Fragment the data into proper blocks. */
+ if (cmd->c_datalen > 0) {
+ blksize = MIN(cmd->c_datalen, cmd->c_blklen);
+ blkcount = cmd->c_datalen / blksize;
+ if (cmd->c_datalen % blksize > 0) {
+ /* XXX: Split this command. (1.7.4) */
+ printf("%s: data not a multiple of %d bytes\n",
+ HDEVNAME(sc), blksize);
+ return EINVAL;
+ }
+ }
+
+ /* Check limit imposed by 9-bit block count. (1.7.2) */
+ if (blkcount > SDHC_BLK_ATT_BLKCNT_MAX) {
+ printf("%s: too much data\n", HDEVNAME(sc));
+ return EINVAL;
+ }
+
+ /* setup for PIO, check for write protection */
+ if (!ISSET(cmd->c_flags, SCF_CMD_READ)) {
+ if (!(HREAD4(sc, SDHC_PRES_STATE) & SDHC_PRES_STATE_WPSPL)) {
+ printf("%s: card is write protected\n",
+ HDEVNAME(sc));
+ return EINVAL;
+ }
+ }
+
+#ifdef SDHC_DMA
+ /* set watermark level */
+ uint32_t wml = blksize / sizeof(uint32_t);
+ if (ISSET(cmd->c_flags, SCF_CMD_READ)) {
+ if (wml > 16)
+ wml = 16;
+ HWRITE4(sc, SDHC_WTMK_LVL, wml << SDHC_WTMK_LVL_RD_WML_SHIFT);
+ } else {
+ if (wml > 128)
+ wml = 128;
+ HWRITE4(sc, SDHC_WTMK_LVL, wml << SDHC_WTMK_LVL_WR_WML_SHIFT);
+ }
+#endif
+
+ /* Prepare transfer mode register value. (2.2.5) */
+ command = 0;
+
+ if (ISSET(cmd->c_flags, SCF_CMD_READ))
+ command |= SDHC_MIX_CTRL_DTDSEL;
+ if (blkcount > 0) {
+ command |= SDHC_MIX_CTRL_BCEN;
+#ifdef SDHC_DMA
+ command |= SDHC_MIX_CTRL_DMAEN;
+#endif
+ if (blkcount > 1) {
+ command |= SDHC_MIX_CTRL_MSBSEL;
+ command |= SDHC_MIX_CTRL_AC12EN;
+ }
+ }
+
+ command |= (cmd->c_opcode << SDHC_CMD_XFR_TYP_CMDINDX_SHIFT) &
+ SDHC_CMD_XFR_TYP_CMDINDX_SHIFT_MASK;
+
+ if (ISSET(cmd->c_flags, SCF_RSP_CRC))
+ command |= SDHC_CMD_XFR_TYP_CCCEN;
+ if (ISSET(cmd->c_flags, SCF_RSP_IDX))
+ command |= SDHC_CMD_XFR_TYP_CICEN;
+ if (cmd->c_data != NULL)
+ command |= SDHC_CMD_XFR_TYP_DPSEL;
+
+ if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT))
+ command |= SDHC_CMD_XFR_TYP_RSP_NONE;
+ else if (ISSET(cmd->c_flags, SCF_RSP_136))
+ command |= SDHC_CMD_XFR_TYP_RSP136;
+ else if (ISSET(cmd->c_flags, SCF_RSP_BSY))
+ command |= SDHC_CMD_XFR_TYP_RSP48B;
+ else
+ command |= SDHC_CMD_XFR_TYP_RSP48;
+
+ /* Wait until command and data inhibit bits are clear. (1.5) */
+ if ((error = imxesdhc_wait_state(sc, SDHC_PRES_STATE_CIHB, 0)) != 0)
+ return error;
+
+ s = splsdmmc();
+
+ /*
+ * Start a CPU data transfer. Writing to the high order byte
+ * of the SDHC_COMMAND register triggers the SD command. (1.5)
+ */
+#ifdef SDHC_DMA
+ if (cmd->c_data)
+ HWRITE4(sc, SDHC_DS_ADDR, (uint32_t)cmd->c_data);
+#endif
+ HWRITE4(sc, SDHC_BLK_ATT, blkcount << SDHC_BLK_ATT_BLKCNT_SHIFT |
+ blksize << SDHC_BLK_ATT_BLKSIZE_SHIFT);
+ HWRITE4(sc, SDHC_CMD_ARG, cmd->c_arg);
+ HWRITE4(sc, SDHC_MIX_CTRL,
+ (HREAD4(sc, SDHC_MIX_CTRL) & (0xf << 22)) | (command & 0xffff));
+ HWRITE4(sc, SDHC_CMD_XFR_TYP, command);
+
+ splx(s);
+ return 0;
+}
+
+void
+imxesdhc_transfer_data(struct imxesdhc_softc *sc, struct sdmmc_command *cmd)
+{
+#ifndef SDHC_DMA
+ u_char *datap = cmd->c_data;
+ int i;
+#endif
+ int datalen;
+ int mask;
+ int error;
+
+ mask = ISSET(cmd->c_flags, SCF_CMD_READ) ?
+ SDHC_PRES_STATE_BREN : SDHC_PRES_STATE_BWEN;
+ error = 0;
+ datalen = cmd->c_datalen;
+
+ DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(sc),
+ MMC_R1(cmd->c_resp), datalen));
+
+#ifndef SDHC_DMA
+ while (datalen > 0) {
+ if (!imxesdhc_wait_intr(sc, SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR,
+ SDHC_BUFFER_TIMEOUT)) {
+ error = ETIMEDOUT;
+ break;
+ }
+
+ if ((error = imxesdhc_wait_state(sc, mask, mask)) != 0)
+ break;
+
+ /* FIXME: wait a bit, else it fails */
+ delay(100);
+ i = MIN(datalen, cmd->c_blklen);
+ if (ISSET(cmd->c_flags, SCF_CMD_READ))
+ imxesdhc_read_data(sc, datap, i);
+ else
+ imxesdhc_write_data(sc, datap, i);
+
+ datap += i;
+ datalen -= i;
+ }
+#endif
+
+ if (error == 0 && !imxesdhc_wait_intr(sc, SDHC_INT_STATUS_TC,
+ SDHC_TRANSFER_TIMEOUT))
+ error = ETIMEDOUT;
+
+ if (error != 0)
+ cmd->c_error = error;
+ SET(cmd->c_flags, SCF_ITSDONE);
+
+ DPRINTF(1,("%s: data transfer done (error=%d)\n",
+ HDEVNAME(sc), cmd->c_error));
+}
+
+void
+imxesdhc_read_data(struct imxesdhc_softc *sc, u_char *datap, int datalen)
+{
+ while (datalen > 3) {
+ *(uint32_t *)datap = HREAD4(sc, SDHC_DATA_BUFF_ACC_PORT);
+ datap += 4;
+ datalen -= 4;
+ }
+ if (datalen > 0) {
+ uint32_t rv = HREAD4(sc, SDHC_DATA_BUFF_ACC_PORT);
+ do {
+ *datap++ = rv & 0xff;
+ rv = rv >> 8;
+ } while (--datalen > 0);
+ }
+}
+
+void
+imxesdhc_write_data(struct imxesdhc_softc *sc, u_char *datap, int datalen)
+{
+ while (datalen > 3) {
+ DPRINTF(3,("%08x\n", *(uint32_t *)datap));
+ HWRITE4(sc, SDHC_DATA_BUFF_ACC_PORT, *((uint32_t *)datap));
+ datap += 4;
+ datalen -= 4;
+ }
+ if (datalen > 0) {
+ uint32_t rv = *datap++;
+ if (datalen > 1)
+ rv |= *datap++ << 8;
+ if (datalen > 2)
+ rv |= *datap++ << 16;
+ DPRINTF(3,("rv %08x\n", rv));
+ HWRITE4(sc, SDHC_DATA_BUFF_ACC_PORT, rv);
+ }
+}
+
+/* Prepare for another command. */
+int
+imxesdhc_soft_reset(struct imxesdhc_softc *sc, int mask)
+{
+ int timo;
+
+ DPRINTF(1,("%s: software reset reg=%#x\n", HDEVNAME(sc), mask));
+
+ /* disable force CLK ouput active */
+ HCLR4(sc, SDHC_VEND_SPEC, SDHC_VEND_SPEC_FRC_SDCLK_ON);
+
+ /* reset */
+ HSET4(sc, SDHC_SYS_CTRL, mask);
+ delay(10);
+
+ for (timo = 1000; timo > 0; timo--) {
+ if (!ISSET(HREAD4(sc, SDHC_SYS_CTRL), mask))
+ break;
+ delay(10);
+ }
+ if (timo == 0) {
+ DPRINTF(1,("%s: timeout reg=%#x\n", HDEVNAME(sc),
+ HREAD4(sc, SDHC_SYS_CTRL)));
+ return ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+int
+imxesdhc_wait_intr(struct imxesdhc_softc *sc, int mask, int timo)
+{
+ int status;
+ int s;
+
+ mask |= SDHC_INT_STATUS_ERR;
+ s = splsdmmc();
+
+ /* enable interrupts for brr and bwr */
+ if (mask & (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR))
+ HSET4(sc, SDHC_INT_SIGNAL_EN, (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR));
+
+ status = sc->intr_status & mask;
+ while (status == 0) {
+ if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
+ == EWOULDBLOCK) {
+ status |= SDHC_INT_STATUS_ERR;
+ break;
+ }
+ status = sc->intr_status & mask;
+ }
+ sc->intr_status &= ~status;
+ DPRINTF(2,("%s: intr status %#x error %#x\n", HDEVNAME(sc), status,
+ sc->intr_error_status));
+
+ /* Command timeout has higher priority than command complete. */
+ if (ISSET(status, SDHC_INT_STATUS_ERR)) {
+ sc->intr_error_status = 0;
+ (void)imxesdhc_soft_reset(sc, SDHC_SYS_CTRL_RSTC | SDHC_SYS_CTRL_RSTD);
+ status = 0;
+ }
+
+ splx(s);
+ return status;
+}
+
+/*
+ * Established by attachment driver at interrupt priority IPL_SDMMC.
+ */
+int
+imxesdhc_intr(void *arg)
+{
+ struct imxesdhc_softc *sc = arg;
+
+ u_int32_t status;
+
+ /* Find out which interrupts are pending. */
+ status = HREAD4(sc, SDHC_INT_STATUS);
+
+#ifndef SDHC_DMA
+ /* disable interrupts for brr and bwr, else we get flooded */
+ if (status & (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR))
+ HCLR4(sc, SDHC_INT_SIGNAL_EN, (SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR));
+#endif
+
+ /* Acknowledge the interrupts we are about to handle. */
+ HWRITE4(sc, SDHC_INT_STATUS, status);
+ DPRINTF(2,("%s: interrupt status=0x%08x\n", HDEVNAME(sc),
+ status, status));
+
+ /*
+ * Service error interrupts.
+ */
+ if (ISSET(status, SDHC_INT_STATUS_CMD_ERR |
+ SDHC_INT_STATUS_CTOE | SDHC_INT_STATUS_DTOE)) {
+ sc->intr_status |= status;
+ sc->intr_error_status |= status & 0xffff0000;
+ wakeup(&sc->intr_status);
+ }
+
+ /*
+ * Wake up the blocking process to service command
+ * related interrupt(s).
+ */
+ if (ISSET(status, SDHC_INT_STATUS_BRR | SDHC_INT_STATUS_BWR |
+ SDHC_INT_STATUS_TC | SDHC_INT_STATUS_CC)) {
+ sc->intr_status |= status;
+ wakeup(&sc->intr_status);
+ }
+
+ /*
+ * Service SD card interrupts.
+ */
+ if (ISSET(status, SDHC_INT_STATUS_CINT)) {
+ DPRINTF(0,("%s: card interrupt\n", HDEVNAME(sc)));
+ HCLR4(sc, SDHC_INT_STATUS, SDHC_INT_STATUS_CINT);
+ sdmmc_card_intr(sc->sdmmc);
+ }
+ return 1;
+}
diff --git a/sys/arch/armv7/imx/imxgpio.c b/sys/arch/armv7/imx/imxgpio.c
new file mode 100644
index 00000000000..fbaf91a8f85
--- /dev/null
+++ b/sys/arch/armv7/imx/imxgpio.c
@@ -0,0 +1,241 @@
+/* $OpenBSD: imxgpio.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/device.h>
+#include <sys/malloc.h>
+#include <sys/evcount.h>
+
+#include <arm/cpufunc.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxgpiovar.h>
+
+/* iMX6 registers */
+#define GPIO_DR 0x00
+#define GPIO_GDIR 0x04
+#define GPIO_PSR 0x08
+#define GPIO_ICR1 0x0C
+#define GPIO_ICR2 0x10
+#define GPIO_IMR 0x14
+#define GPIO_ISR 0x18
+#define GPIO_EDGE_SEL 0x1C
+
+#define GPIO_NUM_PINS 32
+
+struct intrhand {
+ int (*ih_func)(void *); /* handler */
+ void *ih_arg; /* arg for handler */
+ int ih_ipl; /* IPL_* */
+ int ih_irq; /* IRQ number */
+ int ih_gpio; /* gpio pin */
+ struct evcount ih_count;
+ char *ih_name;
+};
+
+struct imxgpio_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ void *sc_ih_h;
+ void *sc_ih_l;
+ int sc_max_il;
+ int sc_min_il;
+ int sc_irq;
+ struct intrhand *sc_handlers[GPIO_NUM_PINS];
+ unsigned int (*sc_get_bit)(struct imxgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_bit)(struct imxgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_clear_bit)(struct imxgpio_softc *sc,
+ unsigned int gpio);
+ void (*sc_set_dir)(struct imxgpio_softc *sc,
+ unsigned int gpio, unsigned int dir);
+};
+
+#define GPIO_PIN_TO_INST(x) ((x) >> 5)
+#define GPIO_PIN_TO_OFFSET(x) ((x) & 0x1f)
+
+int imxgpio_match(struct device *parent, void *v, void *aux);
+void imxgpio_attach(struct device *parent, struct device *self, void *args);
+void imxgpio_recalc_interrupts(struct imxgpio_softc *sc);
+int imxgpio_irq(void *);
+int imxgpio_irq_dummy(void *);
+
+unsigned int imxgpio_v6_get_bit(struct imxgpio_softc *, unsigned int);
+void imxgpio_v6_set_bit(struct imxgpio_softc *, unsigned int);
+void imxgpio_v6_clear_bit(struct imxgpio_softc *, unsigned int);
+void imxgpio_v6_set_dir(struct imxgpio_softc *, unsigned int, unsigned int);
+unsigned int imxgpio_v6_get_dir(struct imxgpio_softc *, unsigned int);
+
+
+struct cfattach imxgpio_ca = {
+ sizeof (struct imxgpio_softc), imxgpio_match, imxgpio_attach
+};
+
+struct cfdriver imxgpio_cd = {
+ NULL, "imxgpio", DV_DULL
+};
+
+int
+imxgpio_match(struct device *parent, void *v, void *aux)
+{
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ case BOARD_ID_IMX6_SABRELITE:
+ break; /* continue trying */
+ default:
+ return 0; /* unknown */
+ }
+ return (1);
+}
+
+void
+imxgpio_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxgpio_softc *sc = (struct imxgpio_softc *) self;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxgpio_attach: bus_space_map failed!");
+
+
+ switch (board_id) {
+ case BOARD_ID_IMX6_PHYFLEX:
+ case BOARD_ID_IMX6_SABRELITE:
+ sc->sc_get_bit = imxgpio_v6_get_bit;
+ sc->sc_set_bit = imxgpio_v6_set_bit;
+ sc->sc_clear_bit = imxgpio_v6_clear_bit;
+ sc->sc_set_dir = imxgpio_v6_set_dir;
+ break;
+ }
+
+ printf("\n");
+
+ /* XXX - IRQ */
+ /* XXX - SYSCONFIG */
+ /* XXX - CTRL */
+ /* XXX - DEBOUNCE */
+}
+
+unsigned int
+imxgpio_get_bit(unsigned int gpio)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ return sc->sc_get_bit(sc, gpio);
+
+}
+
+void
+imxgpio_set_bit(unsigned int gpio)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_set_bit(sc, gpio);
+}
+
+void
+imxgpio_clear_bit(unsigned int gpio)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_clear_bit(sc, gpio);
+}
+void
+imxgpio_set_dir(unsigned int gpio, unsigned int dir)
+{
+ struct imxgpio_softc *sc = imxgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)];
+
+ sc->sc_set_dir(sc, gpio, dir);
+}
+
+unsigned int
+imxgpio_v6_get_bit(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
+
+ return (val >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1;
+}
+
+void
+imxgpio_v6_set_bit(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR,
+ val | (1 << GPIO_PIN_TO_OFFSET(gpio)));
+}
+
+void
+imxgpio_v6_clear_bit(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ u_int32_t val;
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DR);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DR,
+ val & ~(1 << GPIO_PIN_TO_OFFSET(gpio)));
+}
+
+void
+imxgpio_v6_set_dir(struct imxgpio_softc *sc, unsigned int gpio, unsigned int dir)
+{
+ int s;
+ u_int32_t val;
+
+ s = splhigh();
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
+ if (dir == IMXGPIO_DIR_OUT)
+ val |= 1 << GPIO_PIN_TO_OFFSET(gpio);
+ else
+ val &= ~(1 << GPIO_PIN_TO_OFFSET(gpio));
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR, val);
+
+ splx(s);
+}
+
+unsigned int
+imxgpio_v6_get_dir(struct imxgpio_softc *sc, unsigned int gpio)
+{
+ int s;
+ u_int32_t val;
+
+ s = splhigh();
+
+ val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_GDIR);
+ if (val & (1 << GPIO_PIN_TO_OFFSET(gpio)))
+ val = IMXGPIO_DIR_OUT;
+ else
+ val = IMXGPIO_DIR_IN;
+
+ splx(s);
+ return val;
+}
diff --git a/sys/arch/armv7/imx/imxgpiovar.h b/sys/arch/armv7/imx/imxgpiovar.h
new file mode 100644
index 00000000000..1451624c58c
--- /dev/null
+++ b/sys/arch/armv7/imx/imxgpiovar.h
@@ -0,0 +1,41 @@
+/* $OpenBSD: imxgpiovar.h,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IMXGPIOVAR_H
+#define IMXGPIOVAR_H
+
+#define IMXGPIO_DIR_IN 0
+#define IMXGPIO_DIR_OUT 1
+
+unsigned int imxgpio_get_function(unsigned int gpio, unsigned int fn);
+void imxgpio_set_function(unsigned int gpio, unsigned int fn);
+unsigned int imxgpio_get_bit(unsigned int gpio);
+void imxgpio_set_bit(unsigned int gpio);
+void imxgpio_clear_bit(unsigned int gpio);
+void imxgpio_set_dir(unsigned int gpio, unsigned int dir);
+
+/* interrupts */
+void imxgpio_clear_intr(unsigned int gpio);
+void imxgpio_intr_mask(unsigned int gpio);
+void imxgpio_intr_unmask(unsigned int gpio);
+void imxgpio_intr_level(unsigned int gpio, unsigned int level);
+void *imxgpio_intr_establish(unsigned int gpio, int level, int spl,
+ int (*func)(void *), void *arg, char *name);
+void imxgpio_intr_disestablish(void *cookie);
+
+#endif /* IMXGPIOVAR_H */
diff --git a/sys/arch/armv7/imx/imxiic.c b/sys/arch/armv7/imx/imxiic.c
new file mode 100644
index 00000000000..5997967bc0d
--- /dev/null
+++ b/sys/arch/armv7/imx/imxiic.c
@@ -0,0 +1,372 @@
+/* $OpenBSD: imxiic.c,v 1.1 2013/09/06 20:45:53 patrick Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/kthread.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <machine/bus.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxiomuxcvar.h>
+#include <armv7/imx/imxccmvar.h>
+#include <armv7/imx/imxiicvar.h>
+
+/* registers */
+#define I2C_IADR 0x00
+#define I2C_IFDR 0x04
+#define I2C_I2CR 0x08
+#define I2C_I2SR 0x0C
+#define I2C_I2DR 0x10
+
+#define I2C_I2CR_RSTA (1 << 2)
+#define I2C_I2CR_TXAK (1 << 3)
+#define I2C_I2CR_MTX (1 << 4)
+#define I2C_I2CR_MSTA (1 << 5)
+#define I2C_I2CR_IIEN (1 << 6)
+#define I2C_I2CR_IEN (1 << 7)
+#define I2C_I2SR_RXAK (1 << 0)
+#define I2C_I2SR_IIF (1 << 1)
+#define I2C_I2SR_IBB (1 << 5)
+
+struct imxiic_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ bus_size_t sc_ios;
+ void *sc_ih;
+ int unit;
+
+ struct rwlock sc_buslock;
+ struct i2c_controller i2c_tag;
+
+ uint16_t frequency;
+ uint16_t intr_status;
+ uint16_t stopped;
+};
+
+void imxiic_attach(struct device *, struct device *, void *);
+int imxiic_detach(struct device *, int);
+void imxiic_setspeed(struct imxiic_softc *, u_int);
+int imxiic_intr(void *);
+int imxiic_wait_intr(struct imxiic_softc *, int, int);
+int imxiic_wait_state(struct imxiic_softc *, uint32_t, uint32_t);
+int imxiic_start(struct imxiic_softc *, int, int, void *, int);
+int imxiic_read(struct imxiic_softc *, int, int, void *, int);
+int imxiic_write(struct imxiic_softc *, int, int, const void *, int);
+
+int imxiic_i2c_acquire_bus(void *, int);
+void imxiic_i2c_release_bus(void *, int);
+int imxiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
+ void *, size_t, int);
+
+#define HREAD2(sc, reg) \
+ (bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg)))
+#define HWRITE2(sc, reg, val) \
+ bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
+#define HSET2(sc, reg, bits) \
+ HWRITE2((sc), (reg), HREAD2((sc), (reg)) | (bits))
+#define HCLR2(sc, reg, bits) \
+ HWRITE2((sc), (reg), HREAD2((sc), (reg)) & ~(bits))
+
+
+struct cfattach imxiic_ca = {
+ sizeof(struct imxiic_softc), NULL, imxiic_attach, imxiic_detach
+};
+
+struct cfdriver imxiic_cd = {
+ NULL, "imxiic", DV_DULL
+};
+
+void
+imxiic_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imxiic_softc *sc = (struct imxiic_softc *)self;
+ struct imx_attach_args *ia = args;
+
+ sc->sc_iot = ia->ia_iot;
+ sc->sc_ios = ia->ia_dev->mem[0].size;
+ sc->unit = ia->ia_dev->unit;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxiic_attach: bus_space_map failed!");
+
+#if 0
+ sc->sc_ih = arm_intr_establish(ia->ia_dev->irq[0], IPL_BIO,
+ imxiic_intr, sc, sc->sc_dev.dv_xname);
+#endif
+
+ printf("\n");
+
+ /* set iomux pins */
+ imxiomuxc_enable_i2c(sc->unit);
+
+ /* set speed to 100kHz */
+ imxiic_setspeed(sc, 100);
+
+ /* reset */
+ HWRITE2(sc, I2C_I2CR, 0);
+ HWRITE2(sc, I2C_I2SR, 0);
+
+ sc->stopped = 1;
+ rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
+
+ struct i2cbus_attach_args iba;
+
+ sc->i2c_tag.ic_cookie = sc;
+ sc->i2c_tag.ic_acquire_bus = imxiic_i2c_acquire_bus;
+ sc->i2c_tag.ic_release_bus = imxiic_i2c_release_bus;
+ sc->i2c_tag.ic_exec = imxiic_i2c_exec;
+
+ bzero(&iba, sizeof iba);
+ iba.iba_name = "iic";
+ iba.iba_tag = &sc->i2c_tag;
+ config_found(&sc->sc_dev, &iba, NULL);
+}
+
+void
+imxiic_setspeed(struct imxiic_softc *sc, u_int speed)
+{
+ if (!sc->frequency) {
+ uint32_t i2c_clk_rate;
+ uint32_t div;
+ int i;
+
+ i2c_clk_rate = imxccm_get_ipg_perclk();
+ div = (i2c_clk_rate + speed - 1) / speed;
+ if (div < imxiic_clk_div[0][0])
+ i = 0;
+ else if (div > imxiic_clk_div[49][0])
+ i = 49;
+ else
+ for (i = 0; imxiic_clk_div[i][0] < div; i++);
+
+ sc->frequency = imxiic_clk_div[i][1];
+ }
+
+ HWRITE2(sc, I2C_IFDR, sc->frequency);
+}
+
+#if 0
+int
+imxiic_intr(void *arg)
+{
+ struct imxiic_softc *sc = arg;
+ u_int16_t status;
+
+ status = HREAD2(sc, I2C_I2SR);
+
+ if (ISSET(status, I2C_I2SR_IIF)) {
+ /* acknowledge the interrupts */
+ HWRITE2(sc, I2C_I2SR,
+ HREAD2(sc, I2C_I2SR) & ~I2C_I2SR_IIF);
+
+ sc->intr_status |= status;
+ wakeup(&sc->intr_status);
+ }
+
+ return (0);
+}
+
+int
+imxiic_wait_intr(struct imxiic_softc *sc, int mask, int timo)
+{
+ int status;
+ int s;
+
+ s = splbio();
+
+ status = sc->intr_status & mask;
+ while (status == 0) {
+ if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo)
+ == EWOULDBLOCK) {
+ break;
+ }
+ status = sc->intr_status & mask;
+ }
+ status = sc->intr_status & mask;
+ sc->intr_status &= ~status;
+
+ splx(s);
+ return status;
+}
+#endif
+
+int
+imxiic_wait_state(struct imxiic_softc *sc, uint32_t mask, uint32_t value)
+{
+ uint32_t state;
+ int timeout;
+ state = HREAD2(sc, I2C_I2SR);
+ for (timeout = 1000; timeout > 0; timeout--) {
+ if (((state = HREAD2(sc, I2C_I2SR)) & mask) == value)
+ return 0;
+ delay(10);
+ }
+ return ETIMEDOUT;
+}
+
+int
+imxiic_read(struct imxiic_softc *sc, int addr, int subaddr, void *data, int len)
+{
+ int i;
+
+ HWRITE2(sc, I2C_I2DR, addr | 1);
+
+ if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
+ return (EIO);
+ while(!(HREAD2(sc, I2C_I2SR) & I2C_I2SR_IIF));
+ if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK)
+ return (EIO);
+
+ HCLR2(sc, I2C_I2CR, I2C_I2CR_MTX);
+ if (len)
+ HCLR2(sc, I2C_I2CR, I2C_I2CR_TXAK);
+
+ /* dummy read */
+ HREAD2(sc, I2C_I2DR);
+
+ for (i = 0; i < len; i++) {
+ if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
+ return (EIO);
+ if (i == (len - 1)) {
+ HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
+ imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
+ sc->stopped = 1;
+ } else if (i == (len - 2)) {
+ HSET2(sc, I2C_I2CR, I2C_I2CR_TXAK);
+ }
+ ((uint8_t*)data)[i] = HREAD2(sc, I2C_I2DR);
+ }
+
+ return 0;
+}
+
+int
+imxiic_write(struct imxiic_softc *sc, int addr, int subaddr, const void *data, int len)
+{
+ int i;
+
+ HWRITE2(sc, I2C_I2DR, addr);
+
+ if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
+ return (EIO);
+ if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK)
+ return (EIO);
+
+ for (i = 0; i < len; i++) {
+ HWRITE2(sc, I2C_I2DR, ((uint8_t*)data)[i]);
+ if (imxiic_wait_state(sc, I2C_I2SR_IIF, I2C_I2SR_IIF))
+ return (EIO);
+ if (HREAD2(sc, I2C_I2SR) & I2C_I2SR_RXAK)
+ return (EIO);
+ }
+ return 0;
+}
+
+int
+imxiic_i2c_acquire_bus(void *cookie, int flags)
+{
+ struct imxiic_softc *sc = cookie;
+
+ return (rw_enter(&sc->sc_buslock, RW_WRITE));
+}
+
+void
+imxiic_i2c_release_bus(void *cookie, int flags)
+{
+ struct imxiic_softc *sc = cookie;
+
+ (void) rw_exit(&sc->sc_buslock);
+}
+
+int
+imxiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
+ const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
+{
+ struct imxiic_softc *sc = cookie;
+ uint32_t ret = 0;
+ u_int8_t cmd = 0;
+
+ if (!I2C_OP_STOP_P(op) || cmdlen > 1)
+ return (EINVAL);
+
+ if (cmdlen > 0)
+ cmd = *(u_int8_t *)cmdbuf;
+
+ addr &= 0x7f;
+
+ /* clock gating */
+ imxccm_enable_i2c(sc->unit);
+
+ /* set speed to 100kHz */
+ imxiic_setspeed(sc, 100);
+
+ /* enable the controller */
+ HWRITE2(sc, I2C_I2SR, 0);
+ HWRITE2(sc, I2C_I2CR, I2C_I2CR_IEN);
+
+ /* wait for it to be stable */
+ delay(50);
+
+ /* start transaction */
+ HSET2(sc, I2C_I2CR, I2C_I2CR_MSTA);
+
+ if (imxiic_wait_state(sc, I2C_I2SR_IBB, I2C_I2SR_IBB)) {
+ ret = (EIO);
+ goto fail;
+ }
+
+ sc->stopped = 0;
+
+ HSET2(sc, I2C_I2CR, I2C_I2CR_IIEN | I2C_I2CR_MTX | I2C_I2CR_TXAK);
+
+ if (I2C_OP_READ_P(op)) {
+ if (imxiic_read(sc, (addr << 1), cmd, buf, len) != 0)
+ ret = (EIO);
+ } else {
+ if (imxiic_write(sc, (addr << 1), cmd, buf, len) != 0)
+ ret = (EIO);
+ }
+
+fail:
+ if (!sc->stopped) {
+ HCLR2(sc, I2C_I2CR, I2C_I2CR_MSTA | I2C_I2CR_MTX);
+ imxiic_wait_state(sc, I2C_I2SR_IBB, 0);
+ sc->stopped = 1;
+ }
+
+ HWRITE2(sc, I2C_I2CR, 0);
+
+ return ret;
+}
+
+int
+imxiic_detach(struct device *self, int flags)
+{
+ struct imxiic_softc *sc = (struct imxiic_softc *)self;
+
+ HWRITE2(sc, I2C_IADR, 0);
+ HWRITE2(sc, I2C_IFDR, 0);
+ HWRITE2(sc, I2C_I2CR, 0);
+ HWRITE2(sc, I2C_I2SR, 0);
+
+ bus_space_unmap(sc->sc_iot, sc->sc_ioh, sc->sc_ios);
+ return 0;
+}
diff --git a/sys/arch/armv7/imx/imxiicvar.h b/sys/arch/armv7/imx/imxiicvar.h
new file mode 100644
index 00000000000..cd703366bfa
--- /dev/null
+++ b/sys/arch/armv7/imx/imxiicvar.h
@@ -0,0 +1,44 @@
+/* $OpenBSD: imxiicvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IMXIICVAR_H
+#define IMXIICVAR_H
+
+#include <sys/param.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/rwlock.h>
+
+#include <dev/i2c/i2cvar.h>
+
+static uint16_t imxiic_clk_div[50][2] = {
+ { 22, 0x20 }, { 24, 0x21 }, { 26, 0x22 }, { 28, 0x23 },
+ { 30, 0x00 }, { 32, 0x24 }, { 36, 0x25 }, { 40, 0x26 },
+ { 42, 0x03 }, { 44, 0x27 }, { 48, 0x28 }, { 52, 0x05 },
+ { 56, 0x29 }, { 60, 0x06 }, { 64, 0x2A }, { 72, 0x2B },
+ { 80, 0x2C }, { 88, 0x09 }, { 96, 0x2D }, { 104, 0x0A },
+ { 112, 0x2E }, { 128, 0x2F }, { 144, 0x0C }, { 160, 0x30 },
+ { 192, 0x31 }, { 224, 0x32 }, { 240, 0x0F }, { 256, 0x33 },
+ { 288, 0x10 }, { 320, 0x34 }, { 384, 0x35 }, { 448, 0x36 },
+ { 480, 0x13 }, { 512, 0x37 }, { 576, 0x14 }, { 640, 0x38 },
+ { 768, 0x39 }, { 896, 0x3A }, { 960, 0x17 }, { 1024, 0x3B },
+ { 1152, 0x18 }, { 1280, 0x3C }, { 1536, 0x3D }, { 1792, 0x3E },
+ { 1920, 0x1B }, { 2048, 0x3F }, { 2304, 0x1C }, { 2560, 0x1D },
+ { 3072, 0x1E }, { 3840, 0x1F }
+};
+
+#endif
diff --git a/sys/arch/armv7/imx/imxiomuxc.c b/sys/arch/armv7/imx/imxiomuxc.c
new file mode 100644
index 00000000000..f1ec2a1b8a9
--- /dev/null
+++ b/sys/arch/armv7/imx/imxiomuxc.c
@@ -0,0 +1,262 @@
+/* $OpenBSD: imxiomuxc.c,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+#include <armv7/imx/imxvar.h>
+
+/* registers */
+#define IOMUXC_GPR1 0x004
+#define IOMUXC_GPR8 0x020
+#define IOMUXC_GPR12 0x030
+#define IOMUXC_GPR13 0x034
+
+#define IOMUXC_MUX_CTL_PAD_EIM_EB2 0x08C
+#define IOMUXC_MUX_CTL_PAD_EIM_DATA16 0x090
+#define IOMUXC_MUX_CTL_PAD_EIM_DATA17 0x094
+#define IOMUXC_MUX_CTL_PAD_EIM_DATA18 0x098
+#define IOMUXC_MUX_CTL_PAD_EIM_DATA21 0x0A4
+#define IOMUXC_MUX_CTL_PAD_EIM_DATA28 0x0C4
+
+#define IOMUXC_PAD_CTL_PAD_EIM_EB2 0x3A0
+#define IOMUXC_PAD_CTL_PAD_EIM_DATA16 0x3A4
+#define IOMUXC_PAD_CTL_PAD_EIM_DATA17 0x3A8
+#define IOMUXC_PAD_CTL_PAD_EIM_DATA18 0x3AC
+#define IOMUXC_PAD_CTL_PAD_EIM_DATA21 0x3B8
+#define IOMUXC_PAD_CTL_PAD_EIM_DATA28 0x3D8
+
+#define IOMUXC_I2C1_SCL_IN_SELECT_INPUT 0x898
+#define IOMUXC_I2C1_SDA_IN_SELECT_INPUT 0x89C
+#define IOMUXC_I2C2_SCL_IN_SELECT_INPUT 0x8A0
+#define IOMUXC_I2C2_SDA_IN_SELECT_INPUT 0x8A4
+#define IOMUXC_I2C3_SCL_IN_SELECT_INPUT 0x8A8
+#define IOMUXC_I2C3_SDA_IN_SELECT_INPUT 0x8AC
+
+/* bits and bytes */
+#define IOMUXC_GPR1_REF_SSP_EN (1 << 16)
+#define IOMUXC_GPR1_TEST_POWERDOWN (1 << 18)
+
+#define IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1 (0 << 0)
+#define IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB (0 << 6)
+#define IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB (20 << 12)
+#define IOMUXC_GPR8_PCS_TX_SWING_FULL (127 << 18)
+#define IOMUXC_GPR8_PCS_TX_SWING_LOW (127 << 25)
+
+#define IOMUXC_GPR12_LOS_LEVEL_MASK (0x1f << 4)
+#define IOMUXC_GPR12_LOS_LEVEL_9 (9 << 4)
+#define IOMUXC_GPR12_APPS_PM_XMT_PME (1 << 9)
+#define IOMUXC_GPR12_APPS_LTSSM_ENABLE (1 << 10)
+#define IOMUXC_GPR12_APPS_INIT_RST (1 << 11)
+#define IOMUXC_GPR12_DEVICE_TYPE_RC (2 << 12)
+#define IOMUXC_GPR12_DEVICE_TYPE_MASK (3 << 12)
+#define IOMUXC_GPR12_APPS_PM_XMT_TURNOFF (1 << 16)
+
+#define IOMUXC_GPR13_SATA_PHY_1_FAST_EDGE_RATE (0x00 << 0)
+#define IOMUXC_GPR13_SATA_PHY_1_SLOW_EDGE_RATE (0x02 << 0)
+#define IOMUXC_GPR13_SATA_PHY_1_EDGE_RATE_MASK 0x3
+#define IOMUXC_GPR13_SATA_PHY_2_1104V (0x11 << 2)
+#define IOMUXC_GPR13_SATA_PHY_3_333DB (0x00 << 7)
+#define IOMUXC_GPR13_SATA_PHY_4_9_16 (0x04 << 11)
+#define IOMUXC_GPR13_SATA_PHY_5_SS (0x01 << 14)
+#define IOMUXC_GPR13_SATA_SPEED_3G (0x01 << 15)
+#define IOMUXC_GPR13_SATA_PHY_6 (0x03 << 16)
+#define IOMUXC_GPR13_SATA_PHY_7_SATA2M (0x12 << 19)
+#define IOMUXC_GPR13_SATA_PHY_8_30DB (0x05 << 24)
+#define IOMUXC_GPR13_SATA_MASK 0x07FFFFFD
+
+#define IOMUXC_PAD_CTL_SRE_SLOW (1 << 0)
+#define IOMUXC_PAD_CTL_SRE_FAST (1 << 0)
+#define IOMUXC_PAD_CTL_DSE_HIZ (0 << 3)
+#define IOMUXC_PAD_CTL_DSE_240OHM (1 << 3)
+#define IOMUXC_PAD_CTL_DSE_120OHM (2 << 3)
+#define IOMUXC_PAD_CTL_DSE_80OHM (3 << 3)
+#define IOMUXC_PAD_CTL_DSE_60OHM (4 << 3)
+#define IOMUXC_PAD_CTL_DSE_48OHM (5 << 3)
+#define IOMUXC_PAD_CTL_DSE_40OHM (6 << 3)
+#define IOMUXC_PAD_CTL_DSE_34OHM (7 << 3)
+#define IOMUXC_PAD_CTL_SPEED_TBD (0 << 6)
+#define IOMUXC_PAD_CTL_SPEED_LOW (1 << 6)
+#define IOMUXC_PAD_CTL_SPEED_MED (2 << 6)
+#define IOMUXC_PAD_CTL_SPEED_MAX (3 << 6)
+#define IOMUXC_PAD_CTL_ODE_DISABLED (0 << 11)
+#define IOMUXC_PAD_CTL_ODE_ENABLED (1 << 11)
+#define IOMUXC_PAD_CTL_PKE_DISABLED (0 << 12)
+#define IOMUXC_PAD_CTL_PKE_ENABLED (1 << 12)
+#define IOMUXC_PAD_CTL_PUE_KEEP (0 << 13)
+#define IOMUXC_PAD_CTL_PUE_PULL (1 << 13)
+#define IOMUXC_PAD_CTL_PUS_100K_OHM_PD (0 << 14)
+#define IOMUXC_PAD_CTL_PUS_47K_OHM_PU (1 << 14)
+#define IOMUXC_PAD_CTL_PUS_100K_OHM_PU (2 << 14)
+#define IOMUXC_PAD_CTL_PUS_22K_OHM_PU (3 << 14)
+#define IOMUXC_PAD_CTL_HYS_DISABLED (0 << 16)
+#define IOMUXC_PAD_CTL_HYS_ENABLED (1 << 16)
+
+#define IOMUXC_IMX6Q_I2C_PAD_CTRL (IOMUXC_PAD_CTL_SRE_FAST | IOMUXC_PAD_CTL_ODE_ENABLED | \
+ IOMUXC_PAD_CTL_PKE_ENABLED | IOMUXC_PAD_CTL_PUE_PULL | IOMUXC_PAD_CTL_DSE_40OHM | \
+ IOMUXC_PAD_CTL_PUS_100K_OHM_PU | IOMUXC_PAD_CTL_HYS_ENABLED | IOMUXC_PAD_CTL_SPEED_MED)
+
+#define IOMUX_CONFIG_SION (1 << 4)
+
+struct imxiomuxc_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+struct imxiomuxc_softc *imxiomuxc_sc;
+
+void imxiomuxc_attach(struct device *parent, struct device *self, void *args);
+void imxiomuxc_enable_sata(void);
+void imxiomuxc_enable_i2c(int);
+void imxiomuxc_enable_pcie(void);
+void imxiomuxc_pcie_refclk(int);
+void imxiomuxc_pcie_test_powerdown(int);
+
+struct cfattach imxiomuxc_ca = {
+ sizeof (struct imxiomuxc_softc), NULL, imxiomuxc_attach
+};
+
+struct cfdriver imxiomuxc_cd = {
+ NULL, "imxiomuxc", DV_DULL
+};
+
+void
+imxiomuxc_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxiomuxc_softc *sc = (struct imxiomuxc_softc *) self;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxiomuxc_attach: bus_space_map failed!");
+
+ printf("\n");
+ imxiomuxc_sc = sc;
+}
+
+void
+imxiomuxc_enable_sata(void)
+{
+ struct imxiomuxc_softc *sc = imxiomuxc_sc;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13,
+ (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13) & ~IOMUXC_GPR13_SATA_MASK) |
+ IOMUXC_GPR13_SATA_PHY_1_FAST_EDGE_RATE | IOMUXC_GPR13_SATA_PHY_2_1104V |
+ IOMUXC_GPR13_SATA_PHY_3_333DB | IOMUXC_GPR13_SATA_PHY_4_9_16 |
+ IOMUXC_GPR13_SATA_SPEED_3G | IOMUXC_GPR13_SATA_PHY_6 |
+ IOMUXC_GPR13_SATA_PHY_7_SATA2M | IOMUXC_GPR13_SATA_PHY_8_30DB);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13,
+ (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR13) & ~IOMUXC_GPR13_SATA_PHY_1_SLOW_EDGE_RATE) |
+ IOMUXC_GPR13_SATA_PHY_1_SLOW_EDGE_RATE);
+}
+
+void
+imxiomuxc_enable_pcie(void)
+{
+ struct imxiomuxc_softc *sc = imxiomuxc_sc;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12) & ~IOMUXC_GPR12_APPS_LTSSM_ENABLE);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12,
+ (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12) & ~IOMUXC_GPR12_DEVICE_TYPE_MASK) |
+ IOMUXC_GPR12_DEVICE_TYPE_RC);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12,
+ (bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR12) & ~IOMUXC_GPR12_LOS_LEVEL_MASK) |
+ IOMUXC_GPR12_LOS_LEVEL_9);
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR8,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR8) |
+ IOMUXC_GPR8_PCS_TX_DEEMPH_GEN1 | IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_3P5DB |
+ IOMUXC_GPR8_PCS_TX_DEEMPH_GEN2_6DB | IOMUXC_GPR8_PCS_TX_SWING_FULL |
+ IOMUXC_GPR8_PCS_TX_SWING_LOW);
+}
+
+void
+imxiomuxc_pcie_refclk(int enable)
+{
+ struct imxiomuxc_softc *sc = imxiomuxc_sc;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) & ~IOMUXC_GPR1_REF_SSP_EN);
+
+ if (enable)
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) | IOMUXC_GPR1_REF_SSP_EN);
+}
+
+void
+imxiomuxc_pcie_test_powerdown(int enable)
+{
+ struct imxiomuxc_softc *sc = imxiomuxc_sc;
+
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) & ~IOMUXC_GPR1_TEST_POWERDOWN);
+
+ if (enable)
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1,
+ bus_space_read_4(sc->sc_iot, sc->sc_ioh, IOMUXC_GPR1) | IOMUXC_GPR1_TEST_POWERDOWN);
+}
+
+void
+imxiomuxc_enable_i2c(int x)
+{
+ struct imxiomuxc_softc *sc = imxiomuxc_sc;
+
+ /* let's just use EIM for those */
+ switch (x) {
+ case 0:
+ /* scl in select */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA21, IOMUX_CONFIG_SION | 6);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C1_SCL_IN_SELECT_INPUT, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA21, IOMUXC_IMX6Q_I2C_PAD_CTRL);
+ /* sda in select */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA28, IOMUX_CONFIG_SION | 1);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C1_SDA_IN_SELECT_INPUT, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA28, IOMUXC_IMX6Q_I2C_PAD_CTRL);
+ break;
+ case 1:
+ /* scl in select */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_EB2, IOMUX_CONFIG_SION | 6);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C2_SCL_IN_SELECT_INPUT, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_EB2, IOMUXC_IMX6Q_I2C_PAD_CTRL);
+ /* sda in select */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA16, IOMUX_CONFIG_SION | 6);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C2_SDA_IN_SELECT_INPUT, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA16, IOMUXC_IMX6Q_I2C_PAD_CTRL);
+ break;
+ case 2:
+ /* scl in select */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA17, IOMUX_CONFIG_SION | 6);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C3_SCL_IN_SELECT_INPUT, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA17, IOMUXC_IMX6Q_I2C_PAD_CTRL);
+ /* sda in select */
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_MUX_CTL_PAD_EIM_DATA18, IOMUX_CONFIG_SION | 6);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_I2C3_SDA_IN_SELECT_INPUT, 0);
+ bus_space_write_4(sc->sc_iot, sc->sc_ioh, IOMUXC_PAD_CTL_PAD_EIM_DATA18, IOMUXC_IMX6Q_I2C_PAD_CTRL);
+ break;
+ }
+}
diff --git a/sys/arch/armv7/imx/imxiomuxcvar.h b/sys/arch/armv7/imx/imxiomuxcvar.h
new file mode 100644
index 00000000000..682711eb12d
--- /dev/null
+++ b/sys/arch/armv7/imx/imxiomuxcvar.h
@@ -0,0 +1,27 @@
+/* $OpenBSD: imxiomuxcvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef IMXIOMUXCVAR_H
+#define IMXIOMUXCVAR_H
+
+void imxiomuxc_enable_sata(void);
+void imxiomuxc_enable_i2c(int);
+void imxiomuxc_enable_pcie(void);
+void imxiomuxc_pcie_refclk(int);
+void imxiomuxc_pcie_test_powerdown(int);
+
+#endif /* IMXIOMUXCVAR_H */
diff --git a/sys/arch/armv7/imx/imxocotp.c b/sys/arch/armv7/imx/imxocotp.c
new file mode 100644
index 00000000000..0e4ce9d7305
--- /dev/null
+++ b/sys/arch/armv7/imx/imxocotp.c
@@ -0,0 +1,82 @@
+/* $OpenBSD: imxocotp.c,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/device.h>
+#include <sys/evcount.h>
+#include <sys/socket.h>
+#include <sys/timeout.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
+
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxocotpvar.h>
+
+/* registers */
+#define OCOTP_MAC0 0x620
+#define OCOTP_MAC1 0x630
+
+struct imxocotp_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+};
+
+struct imxocotp_softc *imxocotp_sc;
+
+void imxocotp_attach(struct device *parent, struct device *self, void *args);
+
+struct cfattach imxocotp_ca = {
+ sizeof (struct imxocotp_softc), NULL, imxocotp_attach
+};
+
+struct cfdriver imxocotp_cd = {
+ NULL, "imxocotp", DV_DULL
+};
+
+void
+imxocotp_attach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxocotp_softc *sc = (struct imxocotp_softc *) self;
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxocotp_attach: bus_space_map failed!");
+
+ printf("\n");
+ imxocotp_sc = sc;
+}
+
+void
+imxocotp_get_ethernet_address(u_int8_t* mac)
+{
+ uint32_t value;
+
+ value = bus_space_read_4(imxocotp_sc->sc_iot, imxocotp_sc->sc_ioh, OCOTP_MAC0);
+ mac[5] = value & 0xff;
+ mac[4] = (value >> 8) & 0xff;
+ mac[3] = (value >> 16) & 0xff;
+ mac[2] = (value >> 24) & 0xff;
+ value = bus_space_read_4(imxocotp_sc->sc_iot, imxocotp_sc->sc_ioh, OCOTP_MAC1);
+ mac[1] = value & 0xff;
+ mac[0] = (value >> 8) & 0xff;
+}
diff --git a/sys/arch/armv7/imx/imxocotpvar.h b/sys/arch/armv7/imx/imxocotpvar.h
new file mode 100644
index 00000000000..b546638de5c
--- /dev/null
+++ b/sys/arch/armv7/imx/imxocotpvar.h
@@ -0,0 +1,18 @@
+/* $OpenBSD: imxocotpvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+void imxocotp_get_ethernet_address(u_int8_t* mac);
diff --git a/sys/arch/armv7/imx/imxuart.c b/sys/arch/armv7/imx/imxuart.c
new file mode 100644
index 00000000000..4e895b465fe
--- /dev/null
+++ b/sys/arch/armv7/imx/imxuart.c
@@ -0,0 +1,830 @@
+/* $OpenBSD: imxuart.c,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/proc.h>
+#include <sys/tty.h>
+#include <sys/uio.h>
+#include <sys/systm.h>
+#include <sys/time.h>
+#include <sys/device.h>
+#include <sys/syslog.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/select.h>
+#include <sys/kernel.h>
+
+#include <dev/cons.h>
+
+
+#ifdef DDB
+#include <ddb/db_var.h>
+#endif
+
+#include <machine/bus.h>
+#include <armv7/imx/imxuartreg.h>
+#include <armv7/imx/imxuartvar.h>
+#include <armv7/imx/imxvar.h>
+#include <armv7/imx/imxccmvar.h>
+
+#define DEVUNIT(x) (minor(x) & 0x7f)
+#define DEVCUA(x) (minor(x) & 0x80)
+
+struct imxuart_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ struct soft_intrhand *sc_si;
+ void *sc_irq;
+ struct tty *sc_tty;
+ struct timeout sc_diag_tmo;
+ struct timeout sc_dtr_tmo;
+ int sc_overflows;
+ int sc_floods;
+ int sc_errors;
+ int sc_halt;
+ u_int16_t sc_ucr1;
+ u_int16_t sc_ucr2;
+ u_int16_t sc_ucr3;
+ u_int16_t sc_ucr4;
+ u_int8_t sc_hwflags;
+#define COM_HW_NOIEN 0x01
+#define COM_HW_FIFO 0x02
+#define COM_HW_SIR 0x20
+#define COM_HW_CONSOLE 0x40
+#define COM_HW_KGDB 0x80
+ u_int8_t sc_swflags;
+#define COM_SW_SOFTCAR 0x01
+#define COM_SW_CLOCAL 0x02
+#define COM_SW_CRTSCTS 0x04
+#define COM_SW_MDMBUF 0x08
+#define COM_SW_PPS 0x10
+
+ u_int8_t sc_initialize;
+ u_int8_t sc_cua;
+ u_int16_t *sc_ibuf, *sc_ibufp, *sc_ibufhigh, *sc_ibufend;
+#define IMXUART_IBUFSIZE 128
+#define IMXUART_IHIGHWATER 100
+ u_int16_t sc_ibufs[2][IMXUART_IBUFSIZE];
+};
+
+
+int imxuartprobe(struct device *parent, void *self, void *aux);
+void imxuartattach(struct device *parent, struct device *self, void *aux);
+
+void imxuartcnprobe(struct consdev *cp);
+void imxuartcnprobe(struct consdev *cp);
+void imxuartcninit(struct consdev *cp);
+int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
+ tcflag_t cflag);
+int imxuartcngetc(dev_t dev);
+void imxuartcnputc(dev_t dev, int c);
+void imxuartcnpollc(dev_t dev, int on);
+int imxuart_param(struct tty *tp, struct termios *t);
+void imxuart_start(struct tty *);
+void imxuart_pwroff(struct imxuart_softc *sc);
+void imxuart_diag(void *arg);
+void imxuart_raisedtr(void *arg);
+void imxuart_softint(void *arg);
+struct imxuart_softc *imxuart_sc(dev_t dev);
+
+int imxuart_intr(void *);
+
+
+/* XXX - we imitate 'com' serial ports and take over their entry points */
+/* XXX: These belong elsewhere */
+cdev_decl(imxuart);
+
+struct cfdriver imxuart_cd = {
+ NULL, "imxuart", DV_TTY
+};
+
+struct cfattach imxuart_ca = {
+ sizeof(struct imxuart_softc), imxuartprobe, imxuartattach
+};
+
+bus_space_tag_t imxuartconsiot;
+bus_space_handle_t imxuartconsioh;
+bus_addr_t imxuartconsaddr;
+tcflag_t imxuartconscflag = TTYDEF_CFLAG;
+int imxuartdefaultrate = B115200;
+
+int
+imxuartprobe(struct device *parent, void *self, void *aux)
+{
+ return 1;
+}
+
+struct cdevsw imxuartdev =
+ cdev_tty_init(3/*XXX NIMXUART */ ,imxuart); /* 12: serial port */
+
+void
+imxuartattach(struct device *parent, struct device *self, void *args)
+{
+ struct imx_attach_args *ia = args;
+ struct imxuart_softc *sc = (struct imxuart_softc *) self;
+
+ sc->sc_irq = arm_intr_establish(ia->ia_dev->irq[0], IPL_TTY,
+ imxuart_intr, sc, sc->sc_dev.dv_xname);
+
+ sc->sc_iot = ia->ia_iot;
+ if (bus_space_map(sc->sc_iot, ia->ia_dev->mem[0].addr,
+ ia->ia_dev->mem[0].size, 0, &sc->sc_ioh))
+ panic("imxuartattach: bus_space_map failed!");
+
+ if (ia->ia_dev->mem[0].addr == imxuartconsaddr)
+ printf(" console");
+
+ timeout_set(&sc->sc_diag_tmo, imxuart_diag, sc);
+ timeout_set(&sc->sc_dtr_tmo, imxuart_raisedtr, sc);
+ sc->sc_si = softintr_establish(IPL_TTY, imxuart_softint, sc);
+
+ if(sc->sc_si == NULL)
+ panic("%s: can't establish soft interrupt.",
+ sc->sc_dev.dv_xname);
+
+ printf("\n");
+}
+
+int
+imxuart_intr(void *arg)
+{
+ struct imxuart_softc *sc = arg;
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct tty *tp = sc->sc_tty;
+ u_int16_t sr1;
+ u_int16_t *p;
+ u_int16_t c;
+
+ sr1 = bus_space_read_2(iot, ioh, IMXUART_USR1);
+ if (ISSET(sr1, IMXUART_SR1_TRDY) && ISSET(tp->t_state, TS_BUSY)) {
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+ if (sc->sc_halt > 0)
+ wakeup(&tp->t_outq);
+ (*linesw[tp->t_line].l_start)(tp);
+ }
+
+ if (sc->sc_tty == NULL)
+ return(0);
+
+ if(!ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR))
+ return 0;
+
+ p = sc->sc_ibufp;
+
+ while(ISSET(bus_space_read_2(iot, ioh, IMXUART_USR2), IMXUART_SR2_RDR)) {
+ c = bus_space_read_1(iot, ioh, IMXUART_URXD);
+ if (p >= sc->sc_ibufend) {
+ sc->sc_floods++;
+ if (sc->sc_errors++ == 0)
+ timeout_add(&sc->sc_diag_tmo, 60 * hz);
+ } else {
+ *p++ = c;
+ if (p == sc->sc_ibufhigh && ISSET(tp->t_cflag, CRTSCTS))
+ /* XXX */
+ CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
+ bus_space_write_2(iot, ioh, IMXUART_UCR3,
+ sc->sc_ucr3);
+
+ }
+ /* XXX - msr stuff ? */
+ }
+ sc->sc_ibufp = p;
+
+ softintr_schedule(sc->sc_si);
+
+ return 1;
+}
+
+int
+imxuart_param(struct tty *tp, struct termios *t)
+{
+ struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ int ospeed = t->c_ospeed;
+ int error;
+ tcflag_t oldcflag;
+
+
+ if (t->c_ospeed < 0 || (t->c_ispeed && t->c_ispeed != t->c_ospeed))
+ return EINVAL;
+
+ switch (ISSET(t->c_cflag, CSIZE)) {
+ case CS5:
+ return EINVAL;
+ case CS6:
+ return EINVAL;
+ case CS7:
+ CLR(sc->sc_ucr2, IMXUART_CR2_WS);
+ break;
+ case CS8:
+ SET(sc->sc_ucr2, IMXUART_CR2_WS);
+ break;
+ }
+// bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
+
+ if (ISSET(t->c_cflag, PARENB)) {
+ SET(sc->sc_ucr2, IMXUART_CR2_PREN);
+ bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
+ }
+ /* STOPB - XXX */
+ if (ospeed == 0) {
+ /* lower dtr */
+ }
+
+ if (ospeed != 0) {
+ while (ISSET(tp->t_state, TS_BUSY)) {
+ ++sc->sc_halt;
+ error = ttysleep(tp, &tp->t_outq,
+ TTOPRI | PCATCH, "imxuartprm", 0);
+ --sc->sc_halt;
+ if (error) {
+ imxuart_start(tp);
+ return (error);
+ }
+ }
+ /* set speed */
+ }
+
+ /* setup fifo */
+
+ /* When not using CRTSCTS, RTS follows DTR. */
+ /* sc->sc_dtr = MCR_DTR; */
+
+
+ /* and copy to tty */
+ tp->t_ispeed = t->c_ispeed;
+ tp->t_ospeed = t->c_ospeed;
+ oldcflag = tp->t_cflag;
+ tp->t_cflag = t->c_cflag;
+
+ /*
+ * If DCD is off and MDMBUF is changed, ask the tty layer if we should
+ * stop the device.
+ */
+ /* XXX */
+
+ imxuart_start(tp);
+
+ return 0;
+}
+
+void
+imxuart_start(struct tty *tp)
+{
+ struct imxuart_softc *sc = imxuart_cd.cd_devs[DEVUNIT(tp->t_dev)];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+
+ int s;
+ s = spltty();
+ if (ISSET(tp->t_state, TS_BUSY)) {
+ splx(s);
+ return;
+ }
+ if (ISSET(tp->t_state, TS_TIMEOUT | TS_TTSTOP))
+ goto stopped;
+#ifdef DAMNFUCKSHIT
+ /* clear to send (IE the RTS pin on this shit) is not directly \
+ * readable - skip check for now
+ */
+ if (ISSET(tp->t_cflag, CRTSCTS) && !ISSET(sc->sc_msr, IMXUART_CTS))
+ goto stopped;
+#endif
+ if (tp->t_outq.c_cc <= tp->t_lowat) {
+ if (ISSET(tp->t_state, TS_ASLEEP)) {
+ CLR(tp->t_state, TS_ASLEEP);
+ wakeup(&tp->t_outq);
+ }
+ if (tp->t_outq.c_cc == 0)
+ goto stopped;
+ selwakeup(&tp->t_wsel);
+ }
+ SET(tp->t_state, TS_BUSY);
+
+ if (!ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
+ SET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
+ bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
+ }
+
+ {
+ u_char buf[32];
+ int n = q_to_b(&tp->t_outq, buf, 32/*XXX*/);
+ int i;
+ for (i = 0; i < n; i++)
+ bus_space_write_1(iot, ioh, IMXUART_UTXD, buf[i]);
+ }
+ splx(s);
+ return;
+stopped:
+ if (ISSET(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN)) {
+ CLR(sc->sc_ucr1, IMXUART_CR1_TXMPTYEN);
+ bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
+ }
+ splx(s);
+}
+
+void
+imxuart_pwroff(struct imxuart_softc *sc)
+{
+}
+
+void
+imxuart_diag(void *arg)
+{
+ struct imxuart_softc *sc = arg;
+ int overflows, floods;
+ int s;
+
+ s = spltty();
+ sc->sc_errors = 0;
+ overflows = sc->sc_overflows;
+ sc->sc_overflows = 0;
+ floods = sc->sc_floods;
+ sc->sc_floods = 0;
+ splx(s);
+ log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf overflow%s\n",
+ sc->sc_dev.dv_xname,
+ overflows, overflows == 1 ? "" : "s",
+ floods, floods == 1 ? "" : "s");
+}
+
+void
+imxuart_raisedtr(void *arg)
+{
+ struct imxuart_softc *sc = arg;
+
+ SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3, sc->sc_ucr3);
+}
+
+void
+imxuart_softint(void *arg)
+{
+ struct imxuart_softc *sc = arg;
+ struct tty *tp;
+ u_int16_t *ibufp;
+ u_int16_t *ibufend;
+ int c;
+ int err;
+ int s;
+
+ if (sc == NULL || sc->sc_ibufp == sc->sc_ibuf)
+ return;
+
+ tp = sc->sc_tty;
+ s = spltty();
+
+ ibufp = sc->sc_ibuf;
+ ibufend = sc->sc_ibufp;
+
+ if (ibufp == ibufend || tp == NULL || !ISSET(tp->t_state, TS_ISOPEN)) {
+ splx(s);
+ return;
+ }
+
+ sc->sc_ibufp = sc->sc_ibuf = (ibufp == sc->sc_ibufs[0]) ?
+ sc->sc_ibufs[1] : sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;
+
+ if (ISSET(tp->t_cflag, CRTSCTS) &&
+ !ISSET(sc->sc_ucr3, IMXUART_CR3_DSR)) {
+ /* XXX */
+ SET(sc->sc_ucr3, IMXUART_CR3_DSR);
+ bus_space_write_2(sc->sc_iot, sc->sc_ioh, IMXUART_UCR3,
+ sc->sc_ucr3);
+ }
+
+ splx(s);
+
+ while (ibufp < ibufend) {
+ c = *ibufp++;
+ if (ISSET(c, IMXUART_RX_OVERRUN)) {
+ sc->sc_overflows++;
+ if (sc->sc_errors++ == 0)
+ timeout_add(&sc->sc_diag_tmo, 60 * hz);
+ }
+ /* This is ugly, but fast. */
+
+ err = 0;
+ if (ISSET(c, IMXUART_RX_PRERR))
+ err |= TTY_PE;
+ if (ISSET(c, IMXUART_RX_FRMERR))
+ err |= TTY_FE;
+ c = (c & 0xff) | err;
+ (*linesw[tp->t_line].l_rint)(c, tp);
+ }
+}
+
+int
+imxuartopen(dev_t dev, int flag, int mode, struct proc *p)
+{
+ int unit = DEVUNIT(dev);
+ struct imxuart_softc *sc;
+ bus_space_tag_t iot;
+ bus_space_handle_t ioh;
+ struct tty *tp;
+ int s;
+ int error = 0;
+
+ if (unit >= imxuart_cd.cd_ndevs)
+ return ENXIO;
+ sc = imxuart_cd.cd_devs[unit];
+ if (sc == NULL)
+ return ENXIO;
+
+ s = spltty();
+ if (sc->sc_tty == NULL)
+ tp = sc->sc_tty = ttymalloc(0);
+ else
+ tp = sc->sc_tty;
+
+ splx(s);
+
+ tp->t_oproc = imxuart_start;
+ tp->t_param = imxuart_param;
+ tp->t_dev = dev;
+
+ if (!ISSET(tp->t_state, TS_ISOPEN)) {
+ SET(tp->t_state, TS_WOPEN);
+ ttychars(tp);
+ tp->t_iflag = TTYDEF_IFLAG;
+ tp->t_oflag = TTYDEF_OFLAG;
+
+ if (ISSET(sc->sc_hwflags, COM_HW_CONSOLE))
+ tp->t_cflag = imxuartconscflag;
+ else
+ tp->t_cflag = TTYDEF_CFLAG;
+ if (ISSET(sc->sc_swflags, COM_SW_CLOCAL))
+ SET(tp->t_cflag, CLOCAL);
+ if (ISSET(sc->sc_swflags, COM_SW_CRTSCTS))
+ SET(tp->t_cflag, CRTSCTS);
+ if (ISSET(sc->sc_swflags, COM_SW_MDMBUF))
+ SET(tp->t_cflag, MDMBUF);
+ tp->t_lflag = TTYDEF_LFLAG;
+ tp->t_ispeed = tp->t_ospeed = imxuartdefaultrate;
+
+ s = spltty();
+
+ sc->sc_initialize = 1;
+ imxuart_param(tp, &tp->t_termios);
+ ttsetwater(tp);
+ sc->sc_ibufp = sc->sc_ibuf = sc->sc_ibufs[0];
+ sc->sc_ibufhigh = sc->sc_ibuf + IMXUART_IHIGHWATER;
+ sc->sc_ibufend = sc->sc_ibuf + IMXUART_IBUFSIZE;
+
+ iot = sc->sc_iot;
+ ioh = sc->sc_ioh;
+
+ sc->sc_ucr1 = bus_space_read_2(iot, ioh, IMXUART_UCR1);
+ sc->sc_ucr2 = bus_space_read_2(iot, ioh, IMXUART_UCR2);
+ sc->sc_ucr3 = bus_space_read_2(iot, ioh, IMXUART_UCR3);
+ sc->sc_ucr4 = bus_space_read_2(iot, ioh, IMXUART_UCR4);
+
+ /* interrupt after one char on tx/rx */
+ /* reference frequency divider: 1 */
+ bus_space_write_2(iot, ioh, IMXUART_UFCR,
+ 1 << IMXUART_FCR_TXTL_SH |
+ 5 << IMXUART_FCR_RFDIV_SH |
+ 1 << IMXUART_FCR_RXTL_SH);
+
+ bus_space_write_2(iot, ioh, IMXUART_UBIR,
+ (imxuartdefaultrate / 100) - 1);
+
+ /* formula: clk / (rfdiv * 1600) */
+ bus_space_write_2(iot, ioh, IMXUART_UBMR,
+ (imxccm_get_uartclk() * 1000) / 1600);
+
+ SET(sc->sc_ucr1, IMXUART_CR1_EN|IMXUART_CR1_RRDYEN);
+ SET(sc->sc_ucr2, IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
+ bus_space_write_2(iot, ioh, IMXUART_UCR1, sc->sc_ucr1);
+ bus_space_write_2(iot, ioh, IMXUART_UCR2, sc->sc_ucr2);
+
+ /* sc->sc_mcr = MCR_DTR | MCR_RTS; XXX */
+ SET(sc->sc_ucr3, IMXUART_CR3_DSR); /* XXX */
+ bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
+
+ SET(tp->t_state, TS_CARR_ON); /* XXX */
+
+
+ } else if (ISSET(tp->t_state, TS_XCLUDE) && p->p_ucred->cr_uid != 0)
+ return EBUSY;
+ else
+ s = spltty();
+
+ if (DEVCUA(dev)) {
+ if (ISSET(tp->t_state, TS_ISOPEN)) {
+ splx(s);
+ return EBUSY;
+ }
+ sc->sc_cua = 1;
+ } else {
+ /* tty (not cua) device; wait for carrier if necessary */
+ if (ISSET(flag, O_NONBLOCK)) {
+ if (sc->sc_cua) {
+ /* Opening TTY non-blocking... but the CUA is busy */
+ splx(s);
+ return EBUSY;
+ }
+ } else {
+ while (sc->sc_cua ||
+ (!ISSET(tp->t_cflag, CLOCAL) &&
+ !ISSET(tp->t_state, TS_CARR_ON))) {
+ SET(tp->t_state, TS_WOPEN);
+ error = ttysleep(tp, &tp->t_rawq,
+ TTIPRI | PCATCH, ttopen, 0);
+ /*
+ * If TS_WOPEN has been reset, that means the
+ * cua device has been closed. We don't want
+ * to fail in that case,
+ * so just go around again.
+ */
+ if (error && ISSET(tp->t_state, TS_WOPEN)) {
+ CLR(tp->t_state, TS_WOPEN);
+ if (!sc->sc_cua && !ISSET(tp->t_state,
+ TS_ISOPEN))
+ imxuart_pwroff(sc);
+ splx(s);
+ return error;
+ }
+ }
+ }
+ }
+ splx(s);
+ return (*linesw[tp->t_line].l_open)(dev,tp,p);
+}
+
+int
+imxuartclose(dev_t dev, int flag, int mode, struct proc *p)
+{
+ int unit = DEVUNIT(dev);
+ struct imxuart_softc *sc = imxuart_cd.cd_devs[unit];
+ bus_space_tag_t iot = sc->sc_iot;
+ bus_space_handle_t ioh = sc->sc_ioh;
+ struct tty *tp = sc->sc_tty;
+ int s;
+
+ /* XXX This is for cons.c. */
+ if (!ISSET(tp->t_state, TS_ISOPEN))
+ return 0;
+
+ (*linesw[tp->t_line].l_close)(tp, flag, p);
+ s = spltty();
+ if (ISSET(tp->t_state, TS_WOPEN)) {
+ /* tty device is waiting for carrier; drop dtr then re-raise */
+ CLR(sc->sc_ucr3, IMXUART_CR3_DSR);
+ bus_space_write_2(iot, ioh, IMXUART_UCR3, sc->sc_ucr3);
+ timeout_add(&sc->sc_dtr_tmo, hz * 2);
+ } else {
+ /* no one else waiting; turn off the uart */
+ imxuart_pwroff(sc);
+ }
+ CLR(tp->t_state, TS_BUSY | TS_FLUSH);
+
+ sc->sc_cua = 0;
+ splx(s);
+ ttyclose(tp);
+
+ return 0;
+}
+
+int
+imxuartread(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tty;
+
+ tty = imxuarttty(dev);
+ if (tty == NULL)
+ return ENODEV;
+
+ return((*linesw[tty->t_line].l_read)(tty, uio, flag));
+}
+
+int
+imxuartwrite(dev_t dev, struct uio *uio, int flag)
+{
+ struct tty *tty;
+
+ tty = imxuarttty(dev);
+ if (tty == NULL)
+ return ENODEV;
+
+ return((*linesw[tty->t_line].l_write)(tty, uio, flag));
+}
+
+int
+imxuartioctl( dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct imxuart_softc *sc;
+ struct tty *tp;
+ int error;
+
+ sc = imxuart_sc(dev);
+ if (sc == NULL)
+ return (ENODEV);
+
+ tp = sc->sc_tty;
+ if (tp == NULL)
+ return (ENXIO);
+
+ error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ error = ttioctl(tp, cmd, data, flag, p);
+ if (error >= 0)
+ return (error);
+
+ switch(cmd) {
+ case TIOCSBRK:
+ /* */
+ break;
+
+ case TIOCCBRK:
+ /* */
+ break;
+
+ case TIOCSDTR:
+#if 0
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIS);
+#endif
+ break;
+
+ case TIOCCDTR:
+#if 0
+ (void) clmctl(dev, TIOCM_DTR | TIOCM_RTS, DMBIC);
+#endif
+ break;
+
+ case TIOCMSET:
+#if 0
+ (void) clmctl(dev, *(int *) data, DMSET);
+#endif
+ break;
+
+ case TIOCMBIS:
+#if 0
+ (void) clmctl(dev, *(int *) data, DMBIS);
+#endif
+ break;
+
+ case TIOCMBIC:
+#if 0
+ (void) clmctl(dev, *(int *) data, DMBIC);
+#endif
+ break;
+
+ case TIOCMGET:
+#if 0
+ *(int *)data = clmctl(dev, 0, DMGET);
+#endif
+ break;
+
+ case TIOCGFLAGS:
+#if 0
+ *(int *)data = cl->cl_swflags;
+#endif
+ break;
+
+ case TIOCSFLAGS:
+ error = suser(p, 0);
+ if (error != 0)
+ return(EPERM);
+
+#if 0
+ cl->cl_swflags = *(int *)data;
+ cl->cl_swflags &= /* only allow valid flags */
+ (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS);
+#endif
+ break;
+ default:
+ return (ENOTTY);
+ }
+
+ return 0;
+}
+
+int
+imxuartstop(struct tty *tp, int flag)
+{
+ return 0;
+}
+
+struct tty *
+imxuarttty(dev_t dev)
+{
+ int unit;
+ struct imxuart_softc *sc;
+ unit = DEVUNIT(dev);
+ if (unit >= imxuart_cd.cd_ndevs)
+ return NULL;
+ sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
+ if (sc == NULL)
+ return NULL;
+ return sc->sc_tty;
+}
+
+struct imxuart_softc *
+imxuart_sc(dev_t dev)
+{
+ int unit;
+ struct imxuart_softc *sc;
+ unit = DEVUNIT(dev);
+ if (unit >= imxuart_cd.cd_ndevs)
+ return NULL;
+ sc = (struct imxuart_softc *)imxuart_cd.cd_devs[unit];
+ return sc;
+}
+
+
+/* serial console */
+void
+imxuartcnprobe(struct consdev *cp)
+{
+ cp->cn_dev = makedev(12 /* XXX */, 0);
+ cp->cn_pri = CN_MIDPRI;
+}
+
+void
+imxuartcninit(struct consdev *cp)
+{
+}
+
+int
+imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate, tcflag_t cflag)
+{
+ static struct consdev imxuartcons = {
+ NULL, NULL, imxuartcngetc, imxuartcnputc, imxuartcnpollc, NULL,
+ NODEV, CN_MIDPRI
+ };
+
+ if (bus_space_map(iot, iobase, IMXUART_SPACE, 0, &imxuartconsioh))
+ return ENOMEM;
+
+ cn_tab = &imxuartcons;
+ cn_tab->cn_dev = makedev(12 /* XXX */, 0);
+ cdevsw[12] = imxuartdev; /* KLUDGE */
+
+ imxuartconsiot = iot;
+ imxuartconsaddr = iobase;
+ imxuartconscflag = cflag;
+
+ // XXXX: Overwrites some sensitive bits, recheck later.
+ /*
+ bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR1,
+ IMXUART_CR1_EN);
+ bus_space_write_2(imxuartconsiot, imxuartconsioh, IMXUART_UCR2,
+ IMXUART_CR2_TXEN|IMXUART_CR2_RXEN);
+ */
+
+ return 0;
+}
+
+int
+imxuartcngetc(dev_t dev)
+{
+ int c;
+ int s;
+ s = splhigh();
+ while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
+ IMXUART_SR2_RDR) == 0)
+ ;
+ c = bus_space_read_1(imxuartconsiot, imxuartconsioh, IMXUART_URXD);
+ splx(s);
+ return c;
+}
+
+void
+imxuartcnputc(dev_t dev, int c)
+{
+ int s;
+ s = splhigh();
+ bus_space_write_1(imxuartconsiot, imxuartconsioh, IMXUART_UTXD, (uint8_t)c);
+ while((bus_space_read_2(imxuartconsiot, imxuartconsioh, IMXUART_USR2) &
+ IMXUART_SR2_TXDC) == 0)
+ ;
+ splx(s);
+}
+
+void
+imxuartcnpollc(dev_t dev, int on)
+{
+}
diff --git a/sys/arch/armv7/imx/imxuartreg.h b/sys/arch/armv7/imx/imxuartreg.h
new file mode 100644
index 00000000000..4518afd547c
--- /dev/null
+++ b/sys/arch/armv7/imx/imxuartreg.h
@@ -0,0 +1,130 @@
+/* $OpenBSD: imxuartreg.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#define IMXUART_URXD 0x000
+#define IMXUART_RX_ERR 0x4000
+#define IMXUART_RX_OVERRUN 0x2000
+#define IMXUART_RX_FRMERR 0x1000
+#define IMXUART_RX_BRK 0x0800
+#define IMXUART_RX_PRERR 0x0400
+#define IMXUART_RX_PRERR_SH 10
+#define IMXUART_UTXD 0x040
+#define IMXUART_UCR1 0x080
+#define IMXUART_CR1_ADEN 0x8000
+#define IMXUART_CR1_ADBR 0x4000
+#define IMXUART_CR1_TRDYEN 0x2000
+#define IMXUART_CR1_IDEN 0x1000
+#define IMXUART_CR1_ICD 0xc000
+#define IMXUART_CR1_RRDYEN 0x0200
+#define IMXUART_CR1_RXDMAEN 0x0100
+#define IMXUART_CR1_IREN 0x0080
+#define IMXUART_CR1_TXMPTYEN 0x0040
+#define IMXUART_CR1_RTSDEN 0x0020
+#define IMXUART_CR1_SNDBRK 0x0010
+#define IMXUART_CR1_TXDMAEN 0x0008
+#define IMXUART_CR1_ATDMAEN 0x0004
+#define IMXUART_CR1_DOZE 0x0002
+#define IMXUART_CR1_EN 0x0001
+#define IMXUART_UCR2 0x084
+#define IMXUART_CR2_ESCI 0x8000
+#define IMXUART_CR2_IRTS 0x4000
+#define IMXUART_CR2_CTSC 0x2000
+#define IMXUART_CR2_CTS 0x1000
+#define IMXUART_CR2_ESCEN 0x0800
+#define IMXUART_CR2_RTEC 0x0600
+#define IMXUART_CR2_PREN 0x0100
+#define IMXUART_CR2_PROE 0x0080
+#define IMXUART_CR2_STPB 0x0040
+#define IMXUART_CR2_WS 0x0020
+#define IMXUART_CR2_RTSEN 0x0010
+#define IMXUART_CR2_ATEN 0x0008
+#define IMXUART_CR2_TXEN 0x0004
+#define IMXUART_CR2_RXEN 0x0002
+#define IMXUART_CR2_SRTS 0x0001
+#define IMXUART_UCR3 0x088
+#define IMXUART_CR3_DPEC 0xc000
+#define IMXUART_CR3_DTREN 0x2000
+#define IMXUART_CR3_PARERREN 0x1000
+#define IMXUART_CR3_FRAERREN 0x0800
+#define IMXUART_CR3_DSR 0x0400
+#define IMXUART_CR3_DCD 0x0200
+#define IMXUART_CR3_RI 0x0100
+#define IMXUART_CR3_ADNIMP 0x0080
+#define IMXUART_CR3_RXDSEN 0x0040
+#define IMXUART_CR3_AIRINTEN 0x0020
+#define IMXUART_CR3_AWAKEN 0x0010
+#define IMXUART_CR3_DTRDEN 0x0008
+#define IMXUART_CR3_RXDMUXSEL 0x0004
+#define IMXUART_CR3_INVT 0x0002
+#define IMXUART_CR3_ACIEN 0x0001
+#define IMXUART_UCR4 0x08c
+#define IMXUART_CR4_CSTL 0xfc00
+#define IMXUART_CR4_INVR 0x0200
+#define IMXUART_CR4_ENIRI 0x0100
+#define IMXUART_CR4_WKEN 0x0080
+#define IMXUART_CR4_IDDMAEN 0x0040
+#define IMXUART_CR4_IRSC 0x0020
+#define IMXUART_CR4_LPBYP 0x0010
+#define IMXUART_CR4_TCEN 0x0008
+#define IMXUART_CR4_BKEN 0x0004
+#define IMXUART_CR4_OREN 0x0002
+#define IMXUART_CR4_DREN 0x0001
+#define IMXUART_UFCR 0x090
+#define IMXUART_FCR_TXTL_SH 10
+#define IMXUART_FCR_TXTL_M 0x3f
+#define IMXUART_FCR_RFDIV_SH 7
+#define IMXUART_FCR_RFDIV_M 0x07
+#define IMXUART_FCR_RXTL_SH 0
+#define IMXUART_FCR_RXTL_M 0x3f
+#define IMXUART_USR1 0x094
+#define IMXUART_SR1_PARITYERR 0x8000
+#define IMXUART_SR1_RTSS 0x4000
+#define IMXUART_SR1_TRDY 0x2000
+#define IMXUART_SR1_RTSD 0x1000
+#define IMXUART_SR1_ESCF 0x0800
+#define IMXUART_SR1_FRAMERR 0x0400
+#define IMXUART_SR1_RRDY 0x0200
+#define IMXUART_SR1_AGTIM 0x0100
+#define IMXUART_SR1_DTRD 0x0080
+#define IMXUART_SR1_RXDS 0x0040
+#define IMXUART_SR1_AIRINT 0x0020
+#define IMXUART_SR1_AWAKE 0x0010
+#define IMXUART_USR2 0x098
+#define IMXUART_SR2_ADET 0x8000
+#define IMXUART_SR2_TXFE 0x4000
+#define IMXUART_SR2_DTRF 0x2000
+#define IMXUART_SR2_IDLE 0x1000
+#define IMXUART_SR2_ACST 0x0800
+#define IMXUART_SR2_RIDELT 0x0400
+#define IMXUART_SR2_RIIN 0x0200
+#define IMXUART_SR2_IRINT 0x0100
+#define IMXUART_SR2_WAKE 0x0080
+#define IMXUART_SR2_DCDELT 0x0040
+#define IMXUART_SR2_DCDIN 0x0020
+#define IMXUART_SR2_RTSF 0x0010
+#define IMXUART_SR2_TXDC 0x0008
+#define IMXUART_SR2_BRCD 0x0004
+#define IMXUART_SR2_ORE 0x0002
+#define IMXUART_SR2_RDR 0x0001
+#define IMXUART_UESC 0x09c
+#define IMXUART_UTIM 0x0a0
+#define IMXUART_UBIR 0x0a4
+#define IMXUART_UBMR 0x0a8
+#define IMXUART_UBRC 0x0ac
+#define IMXUART_ONEMS 0x0b0
+#define IMXUART_UTS 0x0b4
+#define IMXUART_SPACE 0x0c0
diff --git a/sys/arch/armv7/imx/imxuartvar.h b/sys/arch/armv7/imx/imxuartvar.h
new file mode 100644
index 00000000000..66b9a4d2123
--- /dev/null
+++ b/sys/arch/armv7/imx/imxuartvar.h
@@ -0,0 +1,19 @@
+/* $OpenBSD: imxuartvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2005 Dale Rahn <drahn@motorola.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+int imxuartcnattach(bus_space_tag_t iot, bus_addr_t iobase, int rate,
+ tcflag_t cflag);
diff --git a/sys/arch/armv7/imx/imxvar.h b/sys/arch/armv7/imx/imxvar.h
new file mode 100644
index 00000000000..1a00bc99298
--- /dev/null
+++ b/sys/arch/armv7/imx/imxvar.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: imxvar.h,v 1.1 2013/09/06 20:45:54 patrick Exp $ */
+/*
+ * Copyright (c) 2005,2008 Dale Rahn <drahn@drahn.com>
+ * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/* Physical memory range for on-chip devices. */
+struct imx_mem {
+ u_int32_t addr; /* physical start address */
+ u_int32_t size; /* size of range in bytes */
+};
+
+#define IMX_DEV_NMEM 6 /* number of memory ranges */
+#define IMX_DEV_NIRQ 4 /* number of IRQs per device */
+
+/* Descriptor for all on-chip devices. */
+struct imx_dev {
+ char *name; /* driver name or made up name */
+ int unit; /* driver instance number or -1 */
+ struct imx_mem mem[IMX_DEV_NMEM]; /* memory ranges */
+ int irq[IMX_DEV_NIRQ]; /* IRQ number(s) */
+};
+
+/* Passed as third arg to attach functions. */
+struct imx_attach_args {
+ struct imx_dev *ia_dev;
+ bus_space_tag_t ia_iot;
+ bus_dma_tag_t ia_dmat;
+};
+
+void imx_set_devs(struct imx_dev *);
+struct imx_dev *imx_find_dev(const char *, int);
+
+void imx6_init(void);
+
+/* XXX */
+void *avic_intr_establish(int irqno, int level, int (*func)(void *),
+ void *arg, char *name);
+
+/* board identification - from uboot */
+#define BOARD_ID_IMX6_PHYFLEX 3529
+#define BOARD_ID_IMX6_SABRELITE 3769
+extern uint32_t board_id;