summaryrefslogtreecommitdiffstats
path: root/sys/arm
diff options
context:
space:
mode:
authorwkoszek <wkoszek@FreeBSD.org>2013-04-27 22:38:29 +0000
committerwkoszek <wkoszek@FreeBSD.org>2013-04-27 22:38:29 +0000
commit1497a98f71419ff66d08ad2b8c90530e65521ac2 (patch)
treebd70a5f310bc059b61bc7c71f1f51e07a04e58ae /sys/arm
parent84376c209e05ed70bdeb154f77a6a6d030d7a66d (diff)
downloadFreeBSD-src-1497a98f71419ff66d08ad2b8c90530e65521ac2.zip
FreeBSD-src-1497a98f71419ff66d08ad2b8c90530e65521ac2.tar.gz
Add Xilinx Zynq ARM/FPGA SoC support to FreeBSD/arm port.
Submitted by: Thomas Skibo <ThomasSkibo (at) sbcglobal.net> Reviewed by: wkoszek, freebsd-arm@ (no objections raised)
Diffstat (limited to 'sys/arm')
-rw-r--r--sys/arm/conf/ZEDBOARD98
-rw-r--r--sys/arm/xilinx/files.zynq731
-rw-r--r--sys/arm/xilinx/std.zynq723
-rw-r--r--sys/arm/xilinx/uart_dev_cdnc.c684
-rw-r--r--sys/arm/xilinx/zedboard/files.zedboard9
-rw-r--r--sys/arm/xilinx/zedboard/std.zedboard8
-rw-r--r--sys/arm/xilinx/zy7_bus_space.c113
-rw-r--r--sys/arm/xilinx/zy7_devcfg.c650
-rw-r--r--sys/arm/xilinx/zy7_ehci.c360
-rw-r--r--sys/arm/xilinx/zy7_gpio.c384
-rw-r--r--sys/arm/xilinx/zy7_l2cache.c56
-rw-r--r--sys/arm/xilinx/zy7_machdep.c161
-rw-r--r--sys/arm/xilinx/zy7_reg.h78
-rw-r--r--sys/arm/xilinx/zy7_slcr.c301
-rw-r--r--sys/arm/xilinx/zy7_slcr.h280
15 files changed, 3236 insertions, 0 deletions
diff --git a/sys/arm/conf/ZEDBOARD b/sys/arm/conf/ZEDBOARD
new file mode 100644
index 0000000..1008125
--- /dev/null
+++ b/sys/arm/conf/ZEDBOARD
@@ -0,0 +1,98 @@
+# ZEDBOARD -- Custom configuration for the Xilinx Zynq-7000 based
+# ZedBoard (www.zedboard.org)
+#
+# For more information on this file, please read the handbook section on
+# Kernel Configuration Files:
+#
+# http://www.FreeBSD.org/doc/en_US.ISO8859-1/books/handbook/kernelconfig-config.html
+#
+# The handbook is also available locally in /usr/share/doc/handbook
+# if you've installed the doc distribution, otherwise always see the
+# FreeBSD World Wide Web server (http://www.FreeBSD.org/) for the
+# latest information.
+#
+# An exhaustive list of options and more detailed explanations of the
+# device lines is also present in the ../../conf/NOTES and NOTES files.
+# If you are in doubt as to the purpose or necessity of a line, check first
+# in NOTES.
+#
+# $FreeBSD$
+
+ident ZEDBOARD
+
+include "../xilinx/zedboard/std.zedboard"
+
+makeoptions MODULES_OVERRIDE=""
+makeoptions WITHOUT_MODULES="ahc"
+
+options SCHED_4BSD #4BSD scheduler
+options INET #InterNETworking
+options INET6 #IPv6 communications protocols
+options FFS #Berkeley Fast Filesystem
+options SOFTUPDATES #Enable FFS soft updates support
+options UFS_ACL #Support for access control lists
+options UFS_DIRHASH #Improve performance on big directories
+# options ROOTDEVNAME=\"ufs:mmcsd0s2a\"
+
+options NFSCL #Network Filesystem Client
+# options NFSSD #Network Filesystem Server
+# options NFSLOCKD #Network Lock Manager
+# options NFS_ROOT #NFS usable as /, requires NFSCL
+# options BOOTP_NFSROOT
+# options BOOTP
+
+options MSDOSFS #MSDOS Filesystem
+options CD9660 #ISO 9660 Filesystem
+options PROCFS #Process filesystem (requires PSEUDOFS)
+options PSEUDOFS #Pseudo-filesystem framework
+options SCSI_DELAY=5000 #Delay (in ms) before probing SCSI
+options KTRACE #ktrace(1) support
+options SYSVSHM #SYSV-style shared memory
+options SYSVMSG #SYSV-style message queues
+options SYSVSEM #SYSV-style semaphores
+options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions
+options FREEBSD_BOOT_LOADER
+
+# Debugging
+makeoptions DEBUG=-g
+options DDB
+options KDB
+# options BREAK_TO_DEBUGGER
+
+# options INVARIANTS #Enable calls of extra sanity checking
+# options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS
+# options WITNESS #Enable checks to detect deadlocks and cycles
+# options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed
+
+device loop
+device random
+device ether
+device if_cgem # Zynq-7000 gig ethernet device
+device mii
+device pty
+device uart
+device gpio
+
+device md
+device mmc # mmc/sd bus
+device mmcsd # mmc/sd flash cards
+device sdhci # generic sdhci
+device bpf # Berkeley packet filter
+
+# USB support
+device usb
+options USB_DEBUG
+#options USB_REQ_DEBUG
+#options USB_VERBOSE
+device ehci
+device umass
+device scbus # SCSI bus (required for SCSI)
+device da # Direct Access (disks)
+device axe # USB-Ethernet
+
+
+# Flattened Device Tree
+options FDT
+# options FDT_DTB_STATIC
+# makeoptions FDT_DTS_FILE=zedboard.dts
+
diff --git a/sys/arm/xilinx/files.zynq7 b/sys/arm/xilinx/files.zynq7
new file mode 100644
index 0000000..1be012f
--- /dev/null
+++ b/sys/arm/xilinx/files.zynq7
@@ -0,0 +1,31 @@
+#
+# files.zynq7
+#
+# $FreeBSD$
+
+kern/kern_clocksource.c standard
+
+arm/arm/bus_space_generic.c standard
+arm/arm/bus_space_asm_generic.S standard
+arm/arm/cpufunc_asm_armv5.S standard
+arm/arm/cpufunc_asm_arm10.S standard
+arm/arm/cpufunc_asm_arm11.S standard
+arm/arm/cpufunc_asm_armv7.S standard
+arm/arm/irq_dispatch.S standard
+
+arm/arm/gic.c standard
+arm/arm/mpcore_timer.c standard
+arm/arm/pl310.c standard
+
+arm/xilinx/zy7_machdep.c standard
+arm/xilinx/zy7_l2cache.c standard
+arm/xilinx/zy7_bus_space.c standard
+arm/xilinx/zy7_slcr.c standard
+arm/xilinx/zy7_devcfg.c standard
+
+dev/cadence/if_cgem.c optional if_cgem
+dev/sdhci/sdhci_fdt.c optional sdhci
+arm/xilinx/zy7_ehci.c optional ehci
+arm/xilinx/uart_dev_cdnc.c optional uart
+arm/xilinx/zy7_gpio.c optional gpio
+
diff --git a/sys/arm/xilinx/std.zynq7 b/sys/arm/xilinx/std.zynq7
new file mode 100644
index 0000000..76a21e2
--- /dev/null
+++ b/sys/arm/xilinx/std.zynq7
@@ -0,0 +1,23 @@
+#
+# std.zynq7 - Generic configuration for Xilinx Zynq-7000 PS.
+#
+# $FreeBSD$
+
+cpu CPU_CORTEXA
+machine arm armv6
+
+files "../xilinx/files.zynq7"
+
+# Physical memory starts at 0x00000000. We assume images are loaded at
+# 0x00100000, e.g. from u-boot with 'fatload mmc 0 0x100000 kernel.bin'
+#
+#
+options PHYSADDR=0x00000000
+options KERNPHYSADDR=0x00100000
+makeoptions KERNPHYSADDR=0x00100000
+options KERNVIRTADDR=0xc0100000 # Used in ldscript.arm
+makeoptions KERNVIRTADDR=0xc0100000
+
+options STARTUP_PAGETABLE_ADDR=0x000f0000
+options ARM_L2_PIPT
+
diff --git a/sys/arm/xilinx/uart_dev_cdnc.c b/sys/arm/xilinx/uart_dev_cdnc.c
new file mode 100644
index 0000000..a008853
--- /dev/null
+++ b/sys/arm/xilinx/uart_dev_cdnc.c
@@ -0,0 +1,684 @@
+/*-
+ * Copyright (c) 2005 M. Warner Losh
+ * Copyright (c) 2005 Olivier Houchard
+ * Copyright (c) 2012 Thomas Skibo
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL 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.
+ */
+
+/* A driver for the Cadence AMBA UART as used by the Xilinx Zynq-7000.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585. UART is covered in Ch. 19
+ * and register definitions are in appendix B.33.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_global.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/cons.h>
+#include <sys/tty.h>
+#include <machine/bus.h>
+
+#include <dev/uart/uart.h>
+#include <dev/uart/uart_cpu.h>
+#include <dev/uart/uart_bus.h>
+
+#include "uart_if.h"
+
+#define UART_FIFO_SIZE 64
+
+#define RD4(bas, reg) \
+ bus_space_read_4((bas)->bst, (bas)->bsh, uart_regofs((bas), (reg)))
+#define WR4(bas, reg, value) \
+ bus_space_write_4((bas)->bst, (bas)->bsh, uart_regofs((bas), (reg)), \
+ (value))
+
+/* Register definitions for Cadence UART Controller.
+ */
+#define CDNC_UART_CTRL_REG 0x00 /* Control Register. */
+#define CDNC_UART_CTRL_REG_STOPBRK (1<<8)
+#define CDNC_UART_CTRL_REG_STARTBRK (1<<7)
+#define CDNC_UART_CTRL_REG_TORST (1<<6)
+#define CDNC_UART_CTRL_REG_TX_DIS (1<<5)
+#define CDNC_UART_CTRL_REG_TX_EN (1<<4)
+#define CDNC_UART_CTRL_REG_RX_DIS (1<<3)
+#define CDNC_UART_CTRL_REG_RX_EN (1<<2)
+#define CDNC_UART_CTRL_REG_TXRST (1<<1)
+#define CDNC_UART_CTRL_REG_RXRST (1<<0)
+
+#define CDNC_UART_MODE_REG 0x04 /* Mode Register. */
+#define CDNC_UART_MODE_REG_CHMOD_R_LOOP (3<<8) /* [9:8] - channel mode */
+#define CDNC_UART_MODE_REG_CHMOD_L_LOOP (2<<8)
+#define CDNC_UART_MODE_REG_CHMOD_AUTECHO (1<<8)
+#define CDNC_UART_MODE_REG_STOP2 (2<<6) /* [7:6] - stop bits */
+#define CDNC_UART_MODE_REG_PAR_NONE (4<<3) /* [5:3] - parity type */
+#define CDNC_UART_MODE_REG_PAR_MARK (3<<3)
+#define CDNC_UART_MODE_REG_PAR_SPACE (2<<3)
+#define CDNC_UART_MODE_REG_PAR_ODD (1<<3)
+#define CDNC_UART_MODE_REG_PAR_EVEN (0<<3)
+#define CDNC_UART_MODE_REG_6BIT (3<<1) /* [2:1] - character len */
+#define CDNC_UART_MODE_REG_7BIT (2<<1)
+#define CDNC_UART_MODE_REG_8BIT (0<<1)
+#define CDNC_UART_MODE_REG_CLKSEL (1<<0)
+
+#define CDNC_UART_IEN_REG 0x08 /* Interrupt registers. */
+#define CDNC_UART_IDIS_REG 0x0C
+#define CDNC_UART_IMASK_REG 0x10
+#define CDNC_UART_ISTAT_REG 0x14
+#define CDNC_UART_INT_TXOVR (1<<12)
+#define CDNC_UART_INT_TXNRLYFUL (1<<11) /* tx "nearly" full */
+#define CDNC_UART_INT_TXTRIG (1<<10)
+#define CDNC_UART_INT_DMSI (1<<9) /* delta modem status */
+#define CDNC_UART_INT_RXTMOUT (1<<8)
+#define CDNC_UART_INT_PARITY (1<<7)
+#define CDNC_UART_INT_FRAMING (1<<6)
+#define CDNC_UART_INT_RXOVR (1<<5)
+#define CDNC_UART_INT_TXFULL (1<<4)
+#define CDNC_UART_INT_TXEMPTY (1<<3)
+#define CDNC_UART_INT_RXFULL (1<<2)
+#define CDNC_UART_INT_RXEMPTY (1<<1)
+#define CDNC_UART_INT_RXTRIG (1<<0)
+#define CDNC_UART_INT_ALL 0x1FFF
+
+#define CDNC_UART_BAUDGEN_REG 0x18
+#define CDNC_UART_RX_TIMEO_REG 0x1C
+#define CDNC_UART_RX_WATER_REG 0x20
+
+#define CDNC_UART_MODEM_CTRL_REG 0x24
+#define CDNC_UART_MODEM_CTRL_REG_FCM (1<<5) /* automatic flow control */
+#define CDNC_UART_MODEM_CTRL_REG_RTS (1<<1)
+#define CDNC_UART_MODEM_CTRL_REG_DTR (1<<0)
+
+#define CDNC_UART_MODEM_STAT_REG 0x28
+#define CDNC_UART_MODEM_STAT_REG_FCMS (1<<8) /* flow control mode (rw) */
+#define CDNC_UART_MODEM_STAT_REG_DCD (1<<7)
+#define CDNC_UART_MODEM_STAT_REG_RI (1<<6)
+#define CDNC_UART_MODEM_STAT_REG_DSR (1<<5)
+#define CDNC_UART_MODEM_STAT_REG_CTS (1<<4)
+#define CDNC_UART_MODEM_STAT_REG_DDCD (1<<3) /* change in DCD (w1tc) */
+#define CDNC_UART_MODEM_STAT_REG_TERI (1<<2) /* trail edge ring (w1tc) */
+#define CDNC_UART_MODEM_STAT_REG_DDSR (1<<1) /* change in DSR (w1tc) */
+#define CDNC_UART_MODEM_STAT_REG_DCTS (1<<0) /* change in CTS (w1tc) */
+
+#define CDNC_UART_CHAN_STAT_REG 0x2C /* Channel status register. */
+#define CDNC_UART_CHAN_STAT_REG_TXNRLYFUL (1<<14) /* tx "nearly" full */
+#define CDNC_UART_CHAN_STAT_REG_TXTRIG (1<<13)
+#define CDNC_UART_CHAN_STAT_REG_FDELT (1<<12)
+#define CDNC_UART_CHAN_STAT_REG_TXACTIVE (1<<11)
+#define CDNC_UART_CHAN_STAT_REG_RXACTIVE (1<<10)
+#define CDNC_UART_CHAN_STAT_REG_TXFULL (1<<4)
+#define CDNC_UART_CHAN_STAT_REG_TXEMPTY (1<<3)
+#define CDNC_UART_CHAN_STAT_REG_RXEMPTY (1<<1)
+#define CDNC_UART_CHAN_STAT_REG_RXTRIG (1<<0)
+
+#define CDNC_UART_FIFO 0x30 /* Data FIFO (tx and rx) */
+#define CDNC_UART_BAUDDIV_REG 0x34
+#define CDNC_UART_FLOWDEL_REG 0x38
+#define CDNC_UART_TX_WATER_REG 0x44
+
+
+/*
+ * Low-level UART interface.
+ */
+static int cdnc_uart_probe(struct uart_bas *bas);
+static void cdnc_uart_init(struct uart_bas *bas, int, int, int, int);
+static void cdnc_uart_term(struct uart_bas *bas);
+static void cdnc_uart_putc(struct uart_bas *bas, int);
+static int cdnc_uart_rxready(struct uart_bas *bas);
+static int cdnc_uart_getc(struct uart_bas *bas, struct mtx *mtx);
+
+extern SLIST_HEAD(uart_devinfo_list, uart_devinfo) uart_sysdevs;
+
+static struct uart_ops cdnc_uart_ops = {
+ .probe = cdnc_uart_probe,
+ .init = cdnc_uart_init,
+ .term = cdnc_uart_term,
+ .putc = cdnc_uart_putc,
+ .rxready = cdnc_uart_rxready,
+ .getc = cdnc_uart_getc,
+};
+
+#define SIGCHG(c, i, s, d) \
+ if (c) { \
+ i |= (i & s) ? s : s | d; \
+ } else { \
+ i = (i & s) ? (i & ~s) | d : i; \
+ }
+
+static int
+cdnc_uart_probe(struct uart_bas *bas)
+{
+
+ return (0);
+}
+
+static int
+cdnc_uart_set_baud(struct uart_bas *bas, int baudrate)
+{
+ uint32_t baudgen, bauddiv;
+ uint32_t best_bauddiv, best_baudgen, best_error;
+ uint32_t baud_out, err;
+
+ best_bauddiv = 0;
+ best_baudgen = 0;
+ best_error = ~0;
+
+ /* Try all possible bauddiv values and pick best match. */
+ for (bauddiv = 4; bauddiv <= 255; bauddiv++) {
+ baudgen = (bas->rclk + (baudrate * (bauddiv + 1)) / 2) /
+ (baudrate * (bauddiv + 1));
+ if (baudgen < 1 || baudgen > 0xffff)
+ continue;
+
+ baud_out = bas->rclk / (baudgen * (bauddiv + 1));
+ err = baud_out > baudrate ?
+ baud_out - baudrate : baudrate - baud_out;
+
+ if (err < best_error) {
+ best_error = err;
+ best_bauddiv = bauddiv;
+ best_baudgen = baudgen;
+ }
+ }
+
+ if (best_bauddiv > 0) {
+ WR4(bas, CDNC_UART_BAUDDIV_REG, best_bauddiv);
+ WR4(bas, CDNC_UART_BAUDGEN_REG, best_baudgen);
+ return (0);
+ } else
+ return (-1); /* out of range */
+}
+
+static int
+cdnc_uart_set_params(struct uart_bas *bas, int baudrate, int databits,
+ int stopbits, int parity)
+{
+ uint32_t mode_reg_value = 0;
+
+ switch (databits) {
+ case 6:
+ mode_reg_value |= CDNC_UART_MODE_REG_6BIT;
+ break;
+ case 7:
+ mode_reg_value |= CDNC_UART_MODE_REG_7BIT;
+ break;
+ case 8:
+ default:
+ mode_reg_value |= CDNC_UART_MODE_REG_8BIT;
+ break;
+ }
+
+ if (stopbits == 2)
+ mode_reg_value |= CDNC_UART_MODE_REG_STOP2;
+
+ switch (parity) {
+ case UART_PARITY_MARK:
+ mode_reg_value |= CDNC_UART_MODE_REG_PAR_MARK;
+ break;
+ case UART_PARITY_SPACE:
+ mode_reg_value |= CDNC_UART_MODE_REG_PAR_SPACE;
+ break;
+ case UART_PARITY_ODD:
+ mode_reg_value |= CDNC_UART_MODE_REG_PAR_ODD;
+ break;
+ case UART_PARITY_EVEN:
+ mode_reg_value |= CDNC_UART_MODE_REG_PAR_EVEN;
+ break;
+ case UART_PARITY_NONE:
+ default:
+ mode_reg_value |= CDNC_UART_MODE_REG_PAR_NONE;
+ break;
+ }
+
+ WR4(bas, CDNC_UART_MODE_REG, mode_reg_value);
+
+ if (baudrate > 0 && cdnc_uart_set_baud(bas, baudrate) < 0)
+ return (EINVAL);
+
+ return(0);
+}
+
+static void
+cdnc_uart_hw_init(struct uart_bas *bas)
+{
+
+ /* Reset RX and TX. */
+ WR4(bas, CDNC_UART_CTRL_REG,
+ CDNC_UART_CTRL_REG_RXRST | CDNC_UART_CTRL_REG_TXRST);
+
+ /* Interrupts all off. */
+ WR4(bas, CDNC_UART_IDIS_REG, CDNC_UART_INT_ALL);
+ WR4(bas, CDNC_UART_ISTAT_REG, CDNC_UART_INT_ALL);
+
+ /* Clear delta bits. */
+ WR4(bas, CDNC_UART_MODEM_STAT_REG,
+ CDNC_UART_MODEM_STAT_REG_DDCD | CDNC_UART_MODEM_STAT_REG_TERI |
+ CDNC_UART_MODEM_STAT_REG_DDSR | CDNC_UART_MODEM_STAT_REG_DCTS);
+
+ /* RX FIFO water level, stale timeout */
+ WR4(bas, CDNC_UART_RX_WATER_REG, UART_FIFO_SIZE/2);
+ WR4(bas, CDNC_UART_RX_TIMEO_REG, 10);
+
+ /* TX FIFO water level (not used.) */
+ WR4(bas, CDNC_UART_TX_WATER_REG, UART_FIFO_SIZE/2);
+
+ /* Bring RX and TX online. */
+ WR4(bas, CDNC_UART_CTRL_REG,
+ CDNC_UART_CTRL_REG_RX_EN | CDNC_UART_CTRL_REG_TX_EN |
+ CDNC_UART_CTRL_REG_TORST | CDNC_UART_CTRL_REG_STOPBRK);
+
+ /* Set DTR and RTS. */
+ WR4(bas, CDNC_UART_MODEM_CTRL_REG, CDNC_UART_MODEM_CTRL_REG_DTR |
+ CDNC_UART_MODEM_CTRL_REG_RTS);
+}
+
+/*
+ * Initialize this device for use as a console.
+ */
+static void
+cdnc_uart_init(struct uart_bas *bas, int baudrate, int databits, int stopbits,
+ int parity)
+{
+
+ /* Initialize hardware. */
+ cdnc_uart_hw_init(bas);
+
+ /* Set baudrate, parameters. */
+ (void)cdnc_uart_set_params(bas, baudrate, databits, stopbits, parity);
+}
+
+/*
+ * Free resources now that we're no longer the console. This appears to
+ * be never called, and I'm unsure quite what to do if I am called.
+ */
+static void
+cdnc_uart_term(struct uart_bas *bas)
+{
+
+ /* XXX */
+}
+
+/*
+ * Put a character of console output (so we do it here polling rather than
+ * interrutp driven).
+ */
+static void
+cdnc_uart_putc(struct uart_bas *bas, int c)
+{
+
+ /* Wait for room. */
+ while ((RD4(bas,CDNC_UART_CHAN_STAT_REG) &
+ CDNC_UART_CHAN_STAT_REG_TXFULL) != 0)
+ ;
+
+ WR4(bas, CDNC_UART_FIFO, c);
+
+ while ((RD4(bas,CDNC_UART_CHAN_STAT_REG) &
+ CDNC_UART_CHAN_STAT_REG_TXEMPTY) == 0)
+ ;
+}
+
+/*
+ * Check for a character available.
+ */
+static int
+cdnc_uart_rxready(struct uart_bas *bas)
+{
+
+ return ((RD4(bas, CDNC_UART_CHAN_STAT_REG) &
+ CDNC_UART_CHAN_STAT_REG_RXEMPTY) == 0);
+}
+
+/*
+ * Block waiting for a character.
+ */
+static int
+cdnc_uart_getc(struct uart_bas *bas, struct mtx *mtx)
+{
+ int c;
+
+ uart_lock(mtx);
+
+ while ((RD4(bas, CDNC_UART_CHAN_STAT_REG) &
+ CDNC_UART_CHAN_STAT_REG_RXEMPTY) != 0) {
+ uart_unlock(mtx);
+ DELAY(4);
+ uart_lock(mtx);
+ }
+
+ c = RD4(bas, CDNC_UART_FIFO);
+
+ uart_unlock(mtx);
+
+ c &= 0xff;
+ return (c);
+}
+
+/*****************************************************************************/
+/*
+ * High-level UART interface.
+ */
+
+static int cdnc_uart_bus_probe(struct uart_softc *sc);
+static int cdnc_uart_bus_attach(struct uart_softc *sc);
+static int cdnc_uart_bus_flush(struct uart_softc *, int);
+static int cdnc_uart_bus_getsig(struct uart_softc *);
+static int cdnc_uart_bus_ioctl(struct uart_softc *, int, intptr_t);
+static int cdnc_uart_bus_ipend(struct uart_softc *);
+static int cdnc_uart_bus_param(struct uart_softc *, int, int, int, int);
+static int cdnc_uart_bus_receive(struct uart_softc *);
+static int cdnc_uart_bus_setsig(struct uart_softc *, int);
+static int cdnc_uart_bus_transmit(struct uart_softc *);
+
+static kobj_method_t cdnc_uart_bus_methods[] = {
+ KOBJMETHOD(uart_probe, cdnc_uart_bus_probe),
+ KOBJMETHOD(uart_attach, cdnc_uart_bus_attach),
+ KOBJMETHOD(uart_flush, cdnc_uart_bus_flush),
+ KOBJMETHOD(uart_getsig, cdnc_uart_bus_getsig),
+ KOBJMETHOD(uart_ioctl, cdnc_uart_bus_ioctl),
+ KOBJMETHOD(uart_ipend, cdnc_uart_bus_ipend),
+ KOBJMETHOD(uart_param, cdnc_uart_bus_param),
+ KOBJMETHOD(uart_receive, cdnc_uart_bus_receive),
+ KOBJMETHOD(uart_setsig, cdnc_uart_bus_setsig),
+ KOBJMETHOD(uart_transmit, cdnc_uart_bus_transmit),
+
+ KOBJMETHOD_END
+};
+
+int
+cdnc_uart_bus_probe(struct uart_softc *sc)
+{
+
+ sc->sc_txfifosz = UART_FIFO_SIZE;
+ sc->sc_rxfifosz = UART_FIFO_SIZE;
+ sc->sc_hwiflow = 0;
+ sc->sc_hwoflow = 0;
+
+ device_set_desc(sc->sc_dev, "Cadence UART");
+
+ return (0);
+}
+
+static int
+cdnc_uart_bus_attach(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ struct uart_devinfo *di;
+
+ if (sc->sc_sysdev != NULL) {
+ di = sc->sc_sysdev;
+ (void)cdnc_uart_set_params(bas, di->baudrate, di->databits,
+ di->stopbits, di->parity);
+ } else
+ cdnc_uart_hw_init(bas);
+
+ (void)cdnc_uart_bus_getsig(sc);
+
+ /* Enable interrupts. */
+ WR4(bas, CDNC_UART_IEN_REG,
+ CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT |
+ CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR |
+ CDNC_UART_INT_DMSI);
+
+ return (0);
+}
+
+static int
+cdnc_uart_bus_transmit(struct uart_softc *sc)
+{
+ int i;
+ struct uart_bas *bas = &sc->sc_bas;
+
+ uart_lock(sc->sc_hwmtx);
+
+ /* Clear sticky TXEMPTY status bit. */
+ WR4(bas, CDNC_UART_ISTAT_REG, CDNC_UART_INT_TXEMPTY);
+
+ for (i = 0; i < sc->sc_txdatasz; i++)
+ WR4(bas, CDNC_UART_FIFO, sc->sc_txbuf[i]);
+
+ /* Enable TX empty interrupt. */
+ WR4(bas, CDNC_UART_IEN_REG, CDNC_UART_INT_TXEMPTY);
+ sc->sc_txbusy = 1;
+
+ uart_unlock(sc->sc_hwmtx);
+
+ return (0);
+}
+
+static int
+cdnc_uart_bus_setsig(struct uart_softc *sc, int sig)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ uint32_t new, old, modem_ctrl;
+
+ do {
+ old = sc->sc_hwsig;
+ new = old;
+ if (sig & SER_DDTR) {
+ SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
+ }
+ if (sig & SER_DRTS) {
+ SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
+ }
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ uart_lock(sc->sc_hwmtx);
+ modem_ctrl = RD4(bas, CDNC_UART_MODEM_CTRL_REG) &
+ ~(CDNC_UART_MODEM_CTRL_REG_DTR | CDNC_UART_MODEM_CTRL_REG_RTS);
+ if ((new & SER_DTR) != 0)
+ modem_ctrl |= CDNC_UART_MODEM_CTRL_REG_DTR;
+ if ((new & SER_RTS) != 0)
+ modem_ctrl |= CDNC_UART_MODEM_CTRL_REG_RTS;
+ WR4(bas, CDNC_UART_MODEM_CTRL_REG, modem_ctrl);
+
+ uart_unlock(sc->sc_hwmtx);
+ return (0);
+}
+
+static int
+cdnc_uart_bus_receive(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ uint32_t status;
+ int c, c_status = 0;
+
+ uart_lock(sc->sc_hwmtx);
+
+ /* Check for parity or framing errors and clear the status bits. */
+ status = RD4(bas, CDNC_UART_ISTAT_REG);
+ if ((status & (CDNC_UART_INT_FRAMING | CDNC_UART_INT_PARITY)) != 0) {
+ WR4(bas, CDNC_UART_ISTAT_REG,
+ status & (CDNC_UART_INT_FRAMING | CDNC_UART_INT_PARITY));
+ if ((status & CDNC_UART_INT_PARITY) != 0)
+ c_status |= UART_STAT_PARERR;
+ if ((status & CDNC_UART_INT_FRAMING) != 0)
+ c_status |= UART_STAT_FRAMERR;
+ }
+
+ while ((RD4(bas, CDNC_UART_CHAN_STAT_REG) &
+ CDNC_UART_CHAN_STAT_REG_RXEMPTY) == 0) {
+ c = RD4(bas, CDNC_UART_FIFO) & 0xff;
+#ifdef KDB
+ /* Detect break and drop into debugger. */
+ if (c == 0 && (c_status & UART_STAT_FRAMERR) != 0 &&
+ sc->sc_sysdev != NULL &&
+ sc->sc_sysdev->type == UART_DEV_CONSOLE) {
+ kdb_break();
+ WR4(bas, CDNC_UART_ISTAT_REG, CDNC_UART_INT_FRAMING);
+ }
+#endif
+ uart_rx_put(sc, c | c_status);
+ }
+
+ uart_unlock(sc->sc_hwmtx);
+
+ return (0);
+}
+
+static int
+cdnc_uart_bus_param(struct uart_softc *sc, int baudrate, int databits,
+ int stopbits, int parity)
+{
+
+ return (cdnc_uart_set_params(&sc->sc_bas, baudrate,
+ databits, stopbits, parity));
+}
+
+static int
+cdnc_uart_bus_ipend(struct uart_softc *sc)
+{
+ int ipend = 0;
+ struct uart_bas *bas = &sc->sc_bas;
+ uint32_t istatus;
+
+ uart_lock(sc->sc_hwmtx);
+
+ istatus = RD4(bas, CDNC_UART_ISTAT_REG);
+
+ /* Clear interrupt bits. */
+ WR4(bas, CDNC_UART_ISTAT_REG, istatus &
+ (CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT |
+ CDNC_UART_INT_TXOVR | CDNC_UART_INT_RXOVR |
+ CDNC_UART_INT_TXEMPTY | CDNC_UART_INT_DMSI));
+
+ /* Receive data. */
+ if ((istatus & (CDNC_UART_INT_RXTRIG | CDNC_UART_INT_RXTMOUT)) != 0)
+ ipend |= SER_INT_RXREADY;
+
+ /* Transmit fifo empty. */
+ if (sc->sc_txbusy && (istatus & CDNC_UART_INT_TXEMPTY) != 0) {
+ /* disable txempty interrupt. */
+ WR4(bas, CDNC_UART_IDIS_REG, CDNC_UART_INT_TXEMPTY);
+ ipend |= SER_INT_TXIDLE;
+ }
+
+ /* TX Overflow. */
+ if ((istatus & CDNC_UART_INT_TXOVR) != 0)
+ ipend |= SER_INT_OVERRUN;
+
+ /* RX Overflow. */
+ if ((istatus & CDNC_UART_INT_RXOVR) != 0)
+ ipend |= SER_INT_OVERRUN;
+
+ /* Modem signal change. */
+ if ((istatus & CDNC_UART_INT_DMSI) != 0) {
+ WR4(bas, CDNC_UART_MODEM_STAT_REG,
+ CDNC_UART_MODEM_STAT_REG_DDCD |
+ CDNC_UART_MODEM_STAT_REG_TERI |
+ CDNC_UART_MODEM_STAT_REG_DDSR |
+ CDNC_UART_MODEM_STAT_REG_DCTS);
+ ipend |= SER_INT_SIGCHG;
+ }
+
+ uart_unlock(sc->sc_hwmtx);
+ return (ipend);
+}
+
+static int
+cdnc_uart_bus_flush(struct uart_softc *sc, int what)
+{
+
+ return (0);
+}
+
+static int
+cdnc_uart_bus_getsig(struct uart_softc *sc)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ uint32_t new, old, sig;
+ uint8_t modem_status;
+
+ do {
+ old = sc->sc_hwsig;
+ sig = old;
+ uart_lock(sc->sc_hwmtx);
+ modem_status = RD4(bas, CDNC_UART_MODEM_STAT_REG);
+ uart_unlock(sc->sc_hwmtx);
+ SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_DSR,
+ sig, SER_DSR, SER_DDSR);
+ SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_CTS,
+ sig, SER_CTS, SER_DCTS);
+ SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_DCD,
+ sig, SER_DCD, SER_DDCD);
+ SIGCHG(modem_status & CDNC_UART_MODEM_STAT_REG_RI,
+ sig, SER_RI, SER_DRI);
+ new = sig & ~SER_MASK_DELTA;
+ } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
+ return (sig);
+}
+
+static int
+cdnc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
+{
+ struct uart_bas *bas = &sc->sc_bas;
+ uint32_t uart_ctrl, modem_ctrl;
+ int error = 0;
+
+ uart_lock(sc->sc_hwmtx);
+
+ switch (request) {
+ case UART_IOCTL_BREAK:
+ uart_ctrl = RD4(bas, CDNC_UART_CTRL_REG);
+ if (data) {
+ uart_ctrl |= CDNC_UART_CTRL_REG_STARTBRK;
+ uart_ctrl &= ~CDNC_UART_CTRL_REG_STOPBRK;
+ } else {
+ uart_ctrl |= CDNC_UART_CTRL_REG_STOPBRK;
+ uart_ctrl &= ~CDNC_UART_CTRL_REG_STARTBRK;
+ }
+ WR4(bas, CDNC_UART_CTRL_REG, uart_ctrl);
+ break;
+ case UART_IOCTL_IFLOW:
+ modem_ctrl = RD4(bas, CDNC_UART_MODEM_CTRL_REG);
+ if (data)
+ modem_ctrl |= CDNC_UART_MODEM_CTRL_REG_RTS;
+ else
+ modem_ctrl &= ~CDNC_UART_MODEM_CTRL_REG_RTS;
+ WR4(bas, CDNC_UART_MODEM_CTRL_REG, modem_ctrl);
+ break;
+ default:
+ error = EINVAL;
+ break;
+ }
+
+ uart_unlock(sc->sc_hwmtx);
+
+ return (error);
+}
+
+struct uart_class uart_cdnc_class = {
+ "cdnc_uart",
+ cdnc_uart_bus_methods,
+ sizeof(struct uart_softc),
+ .uc_ops = &cdnc_uart_ops,
+ .uc_range = 8
+};
diff --git a/sys/arm/xilinx/zedboard/files.zedboard b/sys/arm/xilinx/zedboard/files.zedboard
new file mode 100644
index 0000000..8a1af16
--- /dev/null
+++ b/sys/arm/xilinx/zedboard/files.zedboard
@@ -0,0 +1,9 @@
+#
+# files.zedboard
+#
+# $FreeBSD$
+
+# We'll need board specific files once we start implementing drivers
+# for Zedboard PL peripherals such as HDMI, VGA, or Audio Codecs. For
+# now, nothing is needed.
+#
diff --git a/sys/arm/xilinx/zedboard/std.zedboard b/sys/arm/xilinx/zedboard/std.zedboard
new file mode 100644
index 0000000..86f04f1
--- /dev/null
+++ b/sys/arm/xilinx/zedboard/std.zedboard
@@ -0,0 +1,8 @@
+#
+# std.zedboard
+#
+# $FreeBSD$
+
+include "../xilinx/std.zynq7"
+files "../xilinx/zedboard/files.zedboard"
+
diff --git a/sys/arm/xilinx/zy7_bus_space.c b/sys/arm/xilinx/zy7_bus_space.c
new file mode 100644
index 0000000..4cce820
--- /dev/null
+++ b/sys/arm/xilinx/zy7_bus_space.c
@@ -0,0 +1,113 @@
+/*-
+ * Copyright (C) 2012 FreeBSD Foundation
+ * 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. Neither the name of MARVELL nor the names of contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+
+/* Prototypes for all the bus_space structure functions */
+bs_protos(generic);
+bs_protos(generic_armv4);
+
+struct bus_space _base_tag = {
+ /* cookie */
+ .bs_cookie = (void *) 0,
+
+ /* mapping/unmapping */
+ .bs_map = generic_bs_map,
+ .bs_unmap = generic_bs_unmap,
+ .bs_subregion = generic_bs_subregion,
+
+ /* allocation/deallocation */
+ .bs_alloc = generic_bs_alloc,
+ .bs_free = generic_bs_free,
+
+ /* barrier */
+ .bs_barrier = generic_bs_barrier,
+
+ /* read (single) */
+ .bs_r_1 = generic_bs_r_1,
+ .bs_r_2 = generic_armv4_bs_r_2,
+ .bs_r_4 = generic_bs_r_4,
+ .bs_r_8 = NULL,
+
+ /* read multiple */
+ .bs_rm_1 = generic_bs_rm_1,
+ .bs_rm_2 = generic_armv4_bs_rm_2,
+ .bs_rm_4 = generic_bs_rm_4,
+ .bs_rm_8 = NULL,
+
+ /* read region */
+ .bs_rr_1 = generic_bs_rr_1,
+ .bs_rr_2 = generic_armv4_bs_rr_2,
+ .bs_rr_4 = generic_bs_rr_4,
+ .bs_rr_8 = NULL,
+
+ /* write (single) */
+ .bs_w_1 = generic_bs_w_1,
+ .bs_w_2 = generic_armv4_bs_w_2,
+ .bs_w_4 = generic_bs_w_4,
+ .bs_w_8 = NULL,
+
+ /* write multiple */
+ .bs_wm_1 = generic_bs_wm_1,
+ .bs_wm_2 = generic_armv4_bs_wm_2,
+ .bs_wm_4 = generic_bs_wm_4,
+ .bs_wm_8 = NULL,
+
+ /* write region */
+ .bs_wr_1 = generic_bs_wr_1,
+ .bs_wr_2 = generic_armv4_bs_wr_2,
+ .bs_wr_4 = generic_bs_wr_4,
+ .bs_wr_8 = NULL,
+
+ /* set multiple */
+ /* XXX not implemented */
+
+ /* set region */
+ .bs_sr_1 = NULL,
+ .bs_sr_2 = generic_armv4_bs_sr_2,
+ .bs_sr_4 = generic_bs_sr_4,
+ .bs_sr_8 = NULL,
+
+ /* copy */
+ .bs_c_1 = NULL,
+ .bs_c_2 = generic_armv4_bs_c_2,
+ .bs_c_4 = NULL,
+ .bs_c_8 = NULL,
+};
+
+bus_space_tag_t fdtbus_bs_tag = &_base_tag;
diff --git a/sys/arm/xilinx/zy7_devcfg.c b/sys/arm/xilinx/zy7_devcfg.c
new file mode 100644
index 0000000..45b72de9
--- /dev/null
+++ b/sys/arm/xilinx/zy7_devcfg.c
@@ -0,0 +1,650 @@
+/*-
+ * Copyright (C) 2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS 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.
+ *
+ */
+
+/* Zynq-7000 Devcfg driver. This allows programming the PL (FPGA) section
+ * of Zynq.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585. PL Configuration is
+ * covered in section 6.4.5.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/uio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/xilinx/zy7_slcr.h>
+
+struct zy7_devcfg_softc {
+ device_t dev;
+ struct mtx sc_mtx;
+ struct resource *mem_res;
+ struct resource *irq_res;
+ struct cdev *sc_ctl_dev;
+ void *intrhandle;
+
+ bus_dma_tag_t dma_tag;
+ bus_dmamap_t dma_map;
+
+ int is_open;
+};
+
+static struct zy7_devcfg_softc *zy7_devcfg_softc_p;
+
+#define DEVCFG_SC_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define DEVCFG_SC_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define DEVCFG_SC_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
+ "zy7_devcfg", MTX_DEF)
+#define DEVCFG_SC_LOCK_DESTROY(sc) mtx_destroy(&(sc)->sc_mtx);
+#define DEVCFG_SC_ASSERT_LOCKED(sc) mtx_assert(&(sc)->sc_mtx, MA_OWNED);
+
+#define RD4(sc, off) (bus_read_4((sc)->mem_res, (off)))
+#define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val)))
+
+SYSCTL_NODE(_hw, OID_AUTO, fpga, CTLFLAG_RD, 0, \
+ "Xilinx Zynq-7000 PL (FPGA) section");
+
+static int zy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS);
+SYSCTL_PROC(_hw_fpga, OID_AUTO, pl_done, CTLTYPE_INT | CTLFLAG_RD, NULL, 0,
+ zy7_devcfg_sysctl_pl_done, "I", "PL section config DONE signal");
+
+static int zy7_en_level_shifters = 1;
+SYSCTL_INT(_hw_fpga, OID_AUTO, en_level_shifters, CTLFLAG_RW,
+ &zy7_en_level_shifters, 0,
+ "Enable PS-PL level shifters after device config");
+
+static int zy7_ps_vers = 0;
+SYSCTL_INT(_hw, OID_AUTO, ps_vers, CTLFLAG_RD, &zy7_ps_vers, 0,
+ "Zynq-7000 PS version");
+
+
+/* cdev entry points. */
+static int zy7_devcfg_open(struct cdev *, int, int, struct thread *);
+static int zy7_devcfg_write(struct cdev *, struct uio *, int);
+static int zy7_devcfg_close(struct cdev *, int, int, struct thread *);
+
+
+struct cdevsw zy7_devcfg_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = zy7_devcfg_open,
+ .d_write = zy7_devcfg_write,
+ .d_close = zy7_devcfg_close,
+ .d_name = "devcfg",
+};
+
+/* Devcfg block registers. */
+#define ZY7_DEVCFG_CTRL 0x0000
+#define ZY7_DEVCFG_CTRL_FORCE_RST (1<<31)
+#define ZY7_DEVCFG_CTRL_PCFG_PROG_B (1<<30)
+#define ZY7_DEVCFG_CTRL_PCFG_POR_CNT_4K (1<<29)
+#define ZY7_DEVCFG_CTRL_PCAP_PR (1<<27)
+#define ZY7_DEVCFG_CTRL_PCAP_MODE (1<<26)
+#define ZY7_DEVCFG_CTRL_QTR_PCAP_RATE_EN (1<<25)
+#define ZY7_DEVCFG_CTRL_MULTIBOOT_EN (1<<24)
+#define ZY7_DEVCFG_CTRL_JTAG_CHAIN_DIS (1<<23)
+#define ZY7_DEVCFG_CTRL_USER_MODE (1<<15)
+#define ZY7_DEVCFG_CTRL_RESVD_WR11 (3<<13) /* always write 11 */
+#define ZY7_DEVCFG_CTRL_PCFG_AES_FUSE (1<<12)
+#define ZY7_DEVCFG_CTRL_PCFG_AES_EN_MASK (7<<9) /* all 1's or 0's */
+#define ZY7_DEVCFG_CTRL_SEU_EN (1<<8)
+#define ZY7_DEVCFG_CTRL_SEC_EN (1<<7)
+#define ZY7_DEVCFG_CTRL_SPNIDEN (1<<6)
+#define ZY7_DEVCFG_CTRL_SPIDEN (1<<5)
+#define ZY7_DEVCFG_CTRL_NIDEN (1<<4)
+#define ZY7_DEVCFG_CTRL_DBGEN (1<<3)
+#define ZY7_DEVCFG_CTRL_DAP_EN_MASK (7<<0) /* all 1's to enable */
+
+#define ZY7_DEVCFG_LOCK 0x004
+#define ZY7_DEVCFG_LOCK_AES_FUSE_LOCK (1<<4)
+#define ZY7_DEVCFG_LOCK_AES_EN (1<<3)
+#define ZY7_DEVCFG_LOCK_SEU_LOCK (1<<2)
+#define ZY7_DEVCFG_LOCK_SEC_LOCK (1<<1)
+#define ZY7_DEVCFG_LOCK_DBG_LOCK (1<<0)
+
+#define ZY7_DEVCFG_CFG 0x008
+#define ZY7_DEVCFG_CFG_RFIFO_TH_MASK (3<<10)
+#define ZY7_DEVCFG_CFG_WFIFO_TH_MASK (3<<8)
+#define ZY7_DEVCFG_CFG_RCLK_EDGE (1<<7)
+#define ZY7_DEVCFG_CFG_WCLK_EDGE (1<<6)
+#define ZY7_DEVCFG_CFG_DIS_SRC_INC (1<<5)
+#define ZY7_DEVCFG_CFG_DIS_DST_INC (1<<4)
+
+#define ZY7_DEVCFG_INT_STATUS 0x00C
+#define ZY7_DEVCFG_INT_MASK 0x010
+#define ZY7_DEVCFG_INT_PSS_GTS_USR_B (1<<31)
+#define ZY7_DEVCFG_INT_PSS_FST_CFG_B (1<<30)
+#define ZY7_DEVCFG_INT_PSS_GPWRDWN_B (1<<29)
+#define ZY7_DEVCFG_INT_PSS_GTS_CFG_B (1<<28)
+#define ZY7_DEVCFG_INT_CFG_RESET_B (1<<27)
+#define ZY7_DEVCFG_INT_AXI_WTO (1<<23) /* axi write timeout */
+#define ZY7_DEVCFG_INT_AXI_WERR (1<<22) /* axi write err */
+#define ZY7_DEVCFG_INT_AXI_RTO (1<<21) /* axi read timeout */
+#define ZY7_DEVCFG_INT_AXI_RERR (1<<20) /* axi read err */
+#define ZY7_DEVCFG_INT_RX_FIFO_OV (1<<18) /* rx fifo overflow */
+#define ZY7_DEVCFG_INT_WR_FIFO_LVL (1<<17) /* wr fifo < level */
+#define ZY7_DEVCFG_INT_RD_FIFO_LVL (1<<16) /* rd fifo >= level */
+#define ZY7_DEVCFG_INT_DMA_CMD_ERR (1<<15)
+#define ZY7_DEVCFG_INT_DMA_Q_OV (1<<14)
+#define ZY7_DEVCFG_INT_DMA_DONE (1<<13)
+#define ZY7_DEVCFG_INT_DMA_PCAP_DONE (1<<12)
+#define ZY7_DEVCFG_INT_P2D_LEN_ERR (1<<11)
+#define ZY7_DEVCFG_INT_PCFG_HMAC_ERR (1<<6)
+#define ZY7_DEVCFG_INT_PCFG_SEU_ERR (1<<5)
+#define ZY7_DEVCFG_INT_PCFG_POR_B (1<<4)
+#define ZY7_DEVCFG_INT_PCFG_CFG_RST (1<<3)
+#define ZY7_DEVCFG_INT_PCFG_DONE (1<<2)
+#define ZY7_DEVCFG_INT_PCFG_INIT_PE (1<<1)
+#define ZY7_DEVCFG_INT_PCFG_INIT_NE (1<<0)
+#define ZY7_DEVCFG_INT_ERRORS 0x00f0f860
+#define ZY7_DEVCFG_INT_ALL 0xf8f7f87f
+
+#define ZY7_DEVCFG_STATUS 0x014
+#define ZY7_DEVCFG_STATUS_DMA_CMD_Q_F (1<<31) /* cmd queue full */
+#define ZY7_DEVCFG_STATUS_DMA_CMD_Q_E (1<<30) /* cmd queue empty */
+#define ZY7_DEVCFG_STATUS_DONE_COUNT_MASK (3<<28)
+#define ZY7_DEVCFG_STATUS_DONE_COUNT_SHIFT 28
+#define ZY7_DEVCFG_STATUS_RX_FIFO_LVL_MASK (0x1f<<20)
+#define ZY7_DEVCFG_STATUS_RX_FIFO_LVL_SHIFT 20
+#define ZY7_DEVCFG_STATUS_TX_FIFO_LVL_MASK (0x7f<<12)
+#define ZY7_DEVCFG_STATUS_TX_FIFO_LVL_SHIFT 12
+#define ZY7_DEVCFG_STATUS_PSS_GTS_USR_B (1<<11)
+#define ZY7_DEVCFG_STATUS_PSS_FST_CFG_B (1<<10)
+#define ZY7_DEVCFG_STATUS_PSS_GPWRDWN_B (1<<9)
+#define ZY7_DEVCFG_STATUS_PSS_GTS_CFG_B (1<<8)
+#define ZY7_DEVCFG_STATUS_ILL_APB_ACCE (1<<6)
+#define ZY7_DEVCFG_STATUS_PSS_CFG_RESET_B (1<<5)
+#define ZY7_DEVCFG_STATUS_PCFG_INIT (1<<4)
+#define ZY7_DEVCFG_STATUS_EFUSE_BBRAM_KEY_DIS (1<<3)
+#define ZY7_DEVCFG_STATUS_EFUSE_SEC_EN (1<<2)
+#define ZY7_DEVCFG_STATUS_EFUSE_JTAG_DIS (1<<1)
+
+#define ZY7_DEVCFG_DMA_SRC_ADDR 0x018
+#define ZY7_DEVCFG_DMA_DST_ADDR 0x01c
+#define ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP 1
+#define ZY7_DEVCFG_DMA_ADDR_ILLEGAL 0xffffffff
+
+#define ZY7_DEVCFG_DMA_SRC_LEN 0x020 /* in 4-byte words. */
+#define ZY7_DEVCFG_DMA_SRC_LEN_MAX 0x7ffffff
+#define ZY7_DEVCFG_DMA_DST_LEN 0x024
+#define ZY7_DEVCFG_ROM_SHADOW 0x028
+#define ZY7_DEVCFG_MULTIBOOT_ADDR 0x02c
+#define ZY7_DEVCFG_SW_ID 0x030
+#define ZY7_DEVCFG_UNLOCK 0x034
+#define ZY7_DEVCFG_UNLOCK_MAGIC 0x757bdf0d
+#define ZY7_DEVCFG_MCTRL 0x080
+#define ZY7_DEVCFG_MCTRL_PS_VERS_MASK (0xf<<28)
+#define ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT 28
+#define ZY7_DEVCFG_MCTRL_PCFG_POR_B (1<<8)
+#define ZY7_DEVCFG_MCTRL_INT_PCAP_LPBK (1<<4)
+#define ZY7_DEVCFG_XADCIF_CFG 0x100
+#define ZY7_DEVCFG_XADCIF_INT_STAT 0x104
+#define ZY7_DEVCFG_XADCIF_INT_MASK 0x108
+#define ZY7_DEVCFG_XADCIF_MSTS 0x10c
+#define ZY7_DEVCFG_XADCIF_CMD_FIFO 0x110
+#define ZY7_DEVCFG_XADCIF_RD_FIFO 0x114
+#define ZY7_DEVCFG_XADCIF_MCTL 0x118
+
+
+/* Enable programming the PL through PCAP. */
+static void
+zy7_devcfg_init_hw(struct zy7_devcfg_softc *sc)
+{
+
+ DEVCFG_SC_ASSERT_LOCKED(sc);
+
+ /* Set devcfg control register. */
+ WR4(sc, ZY7_DEVCFG_CTRL,
+ ZY7_DEVCFG_CTRL_PCFG_PROG_B |
+ ZY7_DEVCFG_CTRL_PCAP_PR |
+ ZY7_DEVCFG_CTRL_PCAP_MODE |
+ ZY7_DEVCFG_CTRL_USER_MODE |
+ ZY7_DEVCFG_CTRL_RESVD_WR11 |
+ ZY7_DEVCFG_CTRL_SPNIDEN |
+ ZY7_DEVCFG_CTRL_SPIDEN |
+ ZY7_DEVCFG_CTRL_NIDEN |
+ ZY7_DEVCFG_CTRL_DBGEN |
+ ZY7_DEVCFG_CTRL_DAP_EN_MASK);
+
+ /* Turn off internal PCAP loopback. */
+ WR4(sc, ZY7_DEVCFG_MCTRL, RD4(sc, ZY7_DEVCFG_MCTRL) &
+ ~ZY7_DEVCFG_MCTRL_INT_PCAP_LPBK);
+}
+
+/* Clear previous configuration of the PL by asserting PROG_B. */
+static int
+zy7_devcfg_reset_pl(struct zy7_devcfg_softc *sc)
+{
+ uint32_t devcfg_ctl;
+ int tries, err;
+
+ DEVCFG_SC_ASSERT_LOCKED(sc);
+
+ devcfg_ctl = RD4(sc, ZY7_DEVCFG_CTRL);
+
+ /* Deassert PROG_B (active low). */
+ devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B;
+ WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);
+
+ /* Wait for INIT_B deasserted (active low). */
+ tries = 0;
+ while ((RD4(sc, ZY7_DEVCFG_STATUS) &
+ ZY7_DEVCFG_STATUS_PCFG_INIT) == 0) {
+ if (++tries >= 100)
+ return (EIO);
+ DELAY(5);
+ }
+
+ /* Reassert PROG_B. */
+ devcfg_ctl &= ~ZY7_DEVCFG_CTRL_PCFG_PROG_B;
+ WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);
+
+ /* Wait for INIT_B asserted. */
+ tries = 0;
+ while ((RD4(sc, ZY7_DEVCFG_STATUS) &
+ ZY7_DEVCFG_STATUS_PCFG_INIT) != 0) {
+ if (++tries >= 100)
+ return (EIO);
+ DELAY(5);
+ }
+
+ /* Clear sticky bits and set up INIT_B positive edge interrupt. */
+ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
+ WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_PCFG_INIT_PE);
+
+ /* Deassert PROG_B again. */
+ devcfg_ctl |= ZY7_DEVCFG_CTRL_PCFG_PROG_B;
+ WR4(sc, ZY7_DEVCFG_CTRL, devcfg_ctl);
+
+ /* Wait for INIT_B deasserted indicating FPGA internal initialization
+ * is complete. This takes much longer than the previous waits for
+ * INIT_B transition (on the order of 700us).
+ */
+ err = mtx_sleep(sc, &sc->sc_mtx, PCATCH, "zy7in", hz);
+ if (err != 0)
+ return (err);
+
+ /* Clear sticky DONE bit in interrupt status. */
+ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
+
+ return (0);
+}
+
+/* Callback function for bus_dmamap_load(). */
+static void
+zy7_dma_cb2(void *arg, bus_dma_segment_t *seg, int nsegs, int error)
+{
+ if (!error && nsegs == 1)
+ *(bus_addr_t *)arg = seg[0].ds_addr;
+}
+
+
+static int
+zy7_devcfg_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+ struct zy7_devcfg_softc *sc = dev->si_drv1;
+ int err;
+
+ DEVCFG_SC_LOCK(sc);
+ if (sc->is_open) {
+ DEVCFG_SC_UNLOCK(sc);
+ return (EBUSY);
+ }
+
+ sc->dma_map = NULL;
+ err = bus_dma_tag_create(bus_get_dma_tag(sc->dev), 4, 0,
+ BUS_SPACE_MAXADDR_32BIT,
+ BUS_SPACE_MAXADDR,
+ NULL, NULL,
+ PAGE_SIZE,
+ 1,
+ PAGE_SIZE,
+ 0,
+ busdma_lock_mutex,
+ &sc->sc_mtx,
+ &sc->dma_tag);
+ if (err) {
+ DEVCFG_SC_UNLOCK(sc);
+ return (err);
+ }
+
+ sc->is_open = 1;
+ DEVCFG_SC_UNLOCK(sc);
+ return (0);
+}
+
+static int
+zy7_devcfg_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct zy7_devcfg_softc *sc = dev->si_drv1;
+ void *dma_mem;
+ bus_addr_t dma_physaddr;
+ int segsz, err;
+
+ DEVCFG_SC_LOCK(sc);
+
+ /* First write? Reset PL. */
+ if (uio->uio_offset == 0 && uio->uio_resid > 0) {
+ zy7_devcfg_init_hw(sc);
+ zy7_slcr_preload_pl();
+ err = zy7_devcfg_reset_pl(sc);
+ if (err != 0) {
+ DEVCFG_SC_UNLOCK(sc);
+ return (err);
+ }
+ }
+
+ /* Allocate dma memory and load. */
+ err = bus_dmamem_alloc(sc->dma_tag, &dma_mem, BUS_DMA_NOWAIT,
+ &sc->dma_map);
+ if (err != 0) {
+ DEVCFG_SC_UNLOCK(sc);
+ return (err);
+ }
+ err = bus_dmamap_load(sc->dma_tag, sc->dma_map, dma_mem, PAGE_SIZE,
+ zy7_dma_cb2, &dma_physaddr, 0);
+ if (err != 0) {
+ bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map);
+ DEVCFG_SC_UNLOCK(sc);
+ return (err);
+ }
+
+ while (uio->uio_resid > 0) {
+ /* If DONE signal has been set, we shouldn't write anymore. */
+ if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) &
+ ZY7_DEVCFG_INT_PCFG_DONE) != 0) {
+ err = EIO;
+ break;
+ }
+
+ /* uiomove the data from user buffer to our dma map. */
+ segsz = MIN(PAGE_SIZE, uio->uio_resid);
+ err = uiomove(dma_mem, segsz, uio);
+ if (err != 0)
+ break;
+
+ /* Flush the cache to memory. */
+ bus_dmamap_sync(sc->dma_tag, sc->dma_map,
+ BUS_DMASYNC_PREWRITE);
+
+ /* Program devcfg's DMA engine. The ordering of these
+ * register writes is critical.
+ */
+ if (uio->uio_resid > segsz)
+ WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR,
+ (uint32_t) dma_physaddr);
+ else
+ WR4(sc, ZY7_DEVCFG_DMA_SRC_ADDR,
+ (uint32_t) dma_physaddr |
+ ZY7_DEVCFG_DMA_ADDR_WAIT_PCAP);
+ WR4(sc, ZY7_DEVCFG_DMA_DST_ADDR, ZY7_DEVCFG_DMA_ADDR_ILLEGAL);
+ WR4(sc, ZY7_DEVCFG_DMA_SRC_LEN, (segsz+3)/4);
+ WR4(sc, ZY7_DEVCFG_DMA_DST_LEN, 0);
+
+ /* Now clear done bit and set up DMA done interrupt. */
+ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
+ WR4(sc, ZY7_DEVCFG_INT_MASK, ~ZY7_DEVCFG_INT_DMA_DONE);
+
+ /* Wait for DMA done interrupt. */
+ err = mtx_sleep(sc->dma_map, &sc->sc_mtx, PCATCH,
+ "zy7dma", hz);
+ if (err != 0)
+ break;
+
+ bus_dmamap_sync(sc->dma_tag, sc->dma_map,
+ BUS_DMASYNC_POSTWRITE);
+
+ /* Check DONE signal. */
+ if ((RD4(sc, ZY7_DEVCFG_INT_STATUS) &
+ ZY7_DEVCFG_INT_PCFG_DONE) != 0)
+ zy7_slcr_postload_pl(zy7_en_level_shifters);
+ }
+
+ bus_dmamap_unload(sc->dma_tag, sc->dma_map);
+ bus_dmamem_free(sc->dma_tag, dma_mem, sc->dma_map);
+ DEVCFG_SC_UNLOCK(sc);
+ return (err);
+}
+
+static int
+zy7_devcfg_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct zy7_devcfg_softc *sc = dev->si_drv1;
+
+ DEVCFG_SC_LOCK(sc);
+ sc->is_open = 0;
+ bus_dma_tag_destroy(sc->dma_tag);
+ DEVCFG_SC_UNLOCK(sc);
+
+ return (0);
+}
+
+
+static void
+zy7_devcfg_intr(void *arg)
+{
+ struct zy7_devcfg_softc *sc = (struct zy7_devcfg_softc *)arg;
+ uint32_t istatus, imask;
+
+ DEVCFG_SC_LOCK(sc);
+
+ istatus = RD4(sc, ZY7_DEVCFG_INT_STATUS);
+ imask = ~RD4(sc, ZY7_DEVCFG_INT_MASK);
+
+ /* Turn interrupt off. */
+ WR4(sc, ZY7_DEVCFG_INT_MASK, ~0);
+
+ if ((istatus & imask) == 0) {
+ DEVCFG_SC_UNLOCK(sc);
+ return;
+ }
+
+ /* DMA done? */
+ if ((istatus & ZY7_DEVCFG_INT_DMA_DONE) != 0)
+ wakeup(sc->dma_map);
+
+ /* INIT_B positive edge? */
+ if ((istatus & ZY7_DEVCFG_INT_PCFG_INIT_PE) != 0)
+ wakeup(sc);
+
+ DEVCFG_SC_UNLOCK(sc);
+}
+
+/* zy7_devcfg_sysctl_pl_done() returns status of the PL_DONE signal.
+ */
+static int
+zy7_devcfg_sysctl_pl_done(SYSCTL_HANDLER_ARGS)
+{
+ struct zy7_devcfg_softc *sc = zy7_devcfg_softc_p;
+ int pl_done = 0;
+
+ if (sc) {
+ DEVCFG_SC_LOCK(sc);
+
+ /* PCFG_DONE bit is sticky. Clear it before checking it. */
+ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_PCFG_DONE);
+ pl_done = ((RD4(sc, ZY7_DEVCFG_INT_STATUS) &
+ ZY7_DEVCFG_INT_PCFG_DONE) != 0);
+
+ DEVCFG_SC_UNLOCK(sc);
+ }
+ return (sysctl_handle_int(oidp, &pl_done, 0, req));
+}
+
+static int
+zy7_devcfg_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "xlnx,zy7_devcfg"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Zynq devcfg block");
+ return (0);
+}
+
+static int zy7_devcfg_detach(device_t dev);
+
+static int
+zy7_devcfg_attach(device_t dev)
+{
+ struct zy7_devcfg_softc *sc = device_get_softc(dev);
+ int rid, err;
+
+ /* Allow only one attach. */
+ if (zy7_devcfg_softc_p != NULL)
+ return (ENXIO);
+
+ sc->dev = dev;
+
+ DEVCFG_SC_LOCK_INIT(sc);
+
+ /* Get memory resource. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "could not allocate memory resources.\n");
+ zy7_devcfg_detach(dev);
+ return (ENOMEM);
+ }
+
+ /* Allocate IRQ. */
+ rid = 0;
+ sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->irq_res == NULL) {
+ device_printf(dev, "cannot allocate IRQ\n");
+ zy7_devcfg_detach(dev);
+ return (ENOMEM);
+ }
+
+ /* Activate the interrupt. */
+ err = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
+ NULL, zy7_devcfg_intr, sc, &sc->intrhandle);
+ if (err) {
+ device_printf(dev, "cannot setup IRQ\n");
+ zy7_devcfg_detach(dev);
+ return (err);
+ }
+
+ /* Create /dev/devcfg */
+ sc->sc_ctl_dev = make_dev(&zy7_devcfg_cdevsw, 0,
+ UID_ROOT, GID_WHEEL, 0600, "devcfg");
+ if (sc->sc_ctl_dev == NULL) {
+ device_printf(dev, "failed to create /dev/devcfg");
+ zy7_devcfg_detach(dev);
+ return (ENXIO);
+ }
+ sc->sc_ctl_dev->si_drv1 = sc;
+
+ zy7_devcfg_softc_p = sc;
+
+ /* Unlock devcfg registers. */
+ WR4(sc, ZY7_DEVCFG_UNLOCK, ZY7_DEVCFG_UNLOCK_MAGIC);
+
+ /* Make sure interrupts are completely disabled. */
+ WR4(sc, ZY7_DEVCFG_INT_STATUS, ZY7_DEVCFG_INT_ALL);
+ WR4(sc, ZY7_DEVCFG_INT_MASK, 0xffffffff);
+
+ /* Get PS_VERS for SYSCTL. */
+ zy7_ps_vers = (RD4(sc, ZY7_DEVCFG_MCTRL) &
+ ZY7_DEVCFG_MCTRL_PS_VERS_MASK) >>
+ ZY7_DEVCFG_MCTRL_PS_VERS_SHIFT;
+
+ return (0);
+}
+
+static int
+zy7_devcfg_detach(device_t dev)
+{
+ struct zy7_devcfg_softc *sc = device_get_softc(dev);
+
+ if (device_is_attached(dev))
+ bus_generic_detach(dev);
+
+ /* Get rid of /dev/devcfg0. */
+ if (sc->sc_ctl_dev != NULL)
+ destroy_dev(sc->sc_ctl_dev);
+
+ /* Teardown and release interrupt. */
+ if (sc->irq_res != NULL) {
+ if (sc->intrhandle)
+ bus_teardown_intr(dev, sc->irq_res, sc->intrhandle);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->irq_res), sc->irq_res);
+ }
+
+ /* Release memory resource. */
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+
+ zy7_devcfg_softc_p = NULL;
+
+ DEVCFG_SC_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t zy7_devcfg_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, zy7_devcfg_probe),
+ DEVMETHOD(device_attach, zy7_devcfg_attach),
+ DEVMETHOD(device_detach, zy7_devcfg_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t zy7_devcfg_driver = {
+ "zy7_devcfg",
+ zy7_devcfg_methods,
+ sizeof(struct zy7_devcfg_softc),
+};
+static devclass_t zy7_devcfg_devclass;
+
+DRIVER_MODULE(zy7_devcfg, simplebus, zy7_devcfg_driver, zy7_devcfg_devclass, \
+ 0, 0);
+MODULE_DEPEND(zy7_devcfg, zy7_slcr, 1, 1, 1);
diff --git a/sys/arm/xilinx/zy7_ehci.c b/sys/arm/xilinx/zy7_ehci.c
new file mode 100644
index 0000000..2ccb93a
--- /dev/null
+++ b/sys/arm/xilinx/zy7_ehci.c
@@ -0,0 +1,360 @@
+/*-
+ * Copyright (C) 2012-2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS 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.
+ *
+ */
+
+/* A host-controller driver for Zynq-7000's USB OTG controller.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585. Ch. 15 covers the USB
+ * controller and register definitions are in appendix B.34.
+ */
+
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+
+#include <dev/usb/usb_core.h>
+#include <dev/usb/usb_busdma.h>
+#include <dev/usb/usb_process.h>
+#include <dev/usb/usb_util.h>
+
+#include <dev/usb/usb_controller.h>
+#include <dev/usb/usb_bus.h>
+#include <dev/usb/controller/ehci.h>
+#include <dev/usb/controller/ehcireg.h>
+
+
+/* Register definitions. */
+#define ZY7_USB_ID 0x0000
+#define ZY7_USB_HWGENERAL 0x0004
+#define ZY7_USB_HWHOST 0x0008
+#define ZY7_USB_HWDEVICE 0x000c
+#define ZY7_USB_HWTXBUF 0x0010
+#define ZY7_USB_HWRXBUF 0x0014
+#define ZY7_USB_GPTIMER0LD 0x0080
+#define ZY7_USB_GPTIMER0CTRL 0x0084
+#define ZY7_USB_GPTIMER1LD 0x0088
+#define ZY7_USB_GPTIMER1CTRL 0x008c
+#define ZY7_USB_SBUSCFG 0x0090
+#define ZY7_USB_CAPLENGTH_HCIVERSION 0x0100
+#define ZY7_USB_HCSPARAMS 0x0104
+#define ZY7_USB_HCCPARAMS 0x0108
+#define ZY7_USB_DCIVERSION 0x0120
+#define ZY7_USB_DCCPARAMS 0x0124
+#define ZY7_USB_USBCMD 0x0140
+#define ZY7_USB_USBSTS 0x0144
+#define ZY7_USB_USBINTR 0x0148
+#define ZY7_USB_FRINDEX 0x014c
+#define ZY7_USB_PERIODICLISTBASE_DEICEADDR 0x0154
+#define ZY7_USB_ASYNCLISTADDR_ENDPOINTLISTADDR 0x0158
+#define ZY7_USB_TTCTRL 0x015c
+#define ZY7_USB_BURSTSIZE 0x0160
+#define ZY7_USB_TXFILLTUNING 0x0164
+#define ZY7_USB_TXFILLTUNING_TXFIFOTHRES_SHFT 16
+#define ZY7_USB_TXFILLTUNING_TXFIFOTHRES_MASK (0x3f<<16)
+#define ZY7_USB_TXTFILLTUNING 0x0168
+#define ZY7_USB_IC_USB 0x016c
+#define ZY7_USB_ULPI_VIEWPORT 0x0170
+#define ZY7_USB_ULPI_VIEWPORT_WU (1<<31)
+#define ZY7_USB_ULPI_VIEWPORT_RUN (1<<30)
+#define ZY7_USB_ULPI_VIEWPORT_RW (1<<29)
+#define ZY7_USB_ULPI_VIEWPORT_SS (1<<27)
+#define ZY7_USB_ULPI_VIEWPORT_PORT_MASK (7<<24)
+#define ZY7_USB_ULPI_VIEWPORT_PORT_SHIFT 24
+#define ZY7_USB_ULPI_VIEWPORT_ADDR_MASK (0xff<<16)
+#define ZY7_USB_ULPI_VIEWPORT_ADDR_SHIFT 16
+#define ZY7_USB_ULPI_VIEWPORT_DATARD_MASK (0xff<<8)
+#define ZY7_USB_ULPI_VIEWPORT_DATARD_SHIFT 8
+#define ZY7_USB_ULPI_VIEWPORT_DATAWR_MASK (0xff<<0)
+#define ZY7_USB_ULPI_VIEWPORT_DATAWR_SHIFT 0
+#define ZY7_USB_ENDPTNAK 0x0178
+#define ZY7_USB_ENDPTNAKEN 0x017c
+#define ZY7_USB_CONFIGFLAG 0x0180
+#define ZY7_USB_PORTSC(n) (0x0180+4*(n))
+#define ZY7_USB_PORTSC_PTS_MASK (3<<30)
+#define ZY7_USB_PORTSC_PTS_SHIFT 30
+#define ZY7_USB_PORTSC_PTS_UTMI (0<<30)
+#define ZY7_USB_PORTSC_PTS_ULPI (2<<30)
+#define ZY7_USB_PORTSC_PTS_SERIAL (3<<30)
+#define ZY7_USB_PORTSC_PTW (1<<28)
+#define ZY7_USB_PORTSC_PTS2 (1<<25)
+#define ZY7_USB_OTGSC 0x01a4
+#define ZY7_USB_USBMODE 0x01a8
+#define ZY7_USB_ENDPTSETUPSTAT 0x01ac
+#define ZY7_USB_ENDPTPRIME 0x01b0
+#define ZY7_USB_ENDPTFLUSH 0x01b4
+#define ZY7_USB_ENDPTSTAT 0x01b8
+#define ZY7_USB_ENDPTCOMPLETE 0x01bc
+#define ZY7_USB_ENDPTCTRL(n) (0x01c0+4*(n))
+
+#define EHCI_REG_OFFSET ZY7_USB_CAPLENGTH_HCIVERSION
+#define EHCI_REG_SIZE 0x100
+
+static int
+zy7_phy_config(device_t dev, bus_space_tag_t io_tag, bus_space_handle_t bsh)
+{
+ phandle_t node;
+ char buf[64];
+ uint32_t portsc;
+ int tries;
+
+ node = ofw_bus_get_node(dev);
+
+ if (OF_getprop(node, "phy_type", buf, sizeof(buf)) > 0) {
+ portsc = bus_space_read_4(io_tag, bsh, ZY7_USB_PORTSC(1));
+ portsc &= ~(ZY7_USB_PORTSC_PTS_MASK | ZY7_USB_PORTSC_PTW |
+ ZY7_USB_PORTSC_PTS2);
+
+ if (strcmp(buf,"ulpi") == 0)
+ portsc |= ZY7_USB_PORTSC_PTS_ULPI;
+ else if (strcmp(buf,"utmi") == 0)
+ portsc |= ZY7_USB_PORTSC_PTS_UTMI;
+ else if (strcmp(buf,"utmi-wide") == 0)
+ portsc |= (ZY7_USB_PORTSC_PTS_UTMI |
+ ZY7_USB_PORTSC_PTW);
+ else if (strcmp(buf, "serial") == 0)
+ portsc |= ZY7_USB_PORTSC_PTS_SERIAL;
+
+ bus_space_write_4(io_tag, bsh, ZY7_USB_PORTSC(1), portsc);
+ }
+
+ if (OF_getprop(node, "phy_vbus_ext", buf, sizeof(buf)) >= 0) {
+
+ /* Tell PHY that VBUS is supplied externally. */
+ bus_space_write_4(io_tag, bsh, ZY7_USB_ULPI_VIEWPORT,
+ ZY7_USB_ULPI_VIEWPORT_RUN |
+ ZY7_USB_ULPI_VIEWPORT_RW |
+ (0 << ZY7_USB_ULPI_VIEWPORT_PORT_SHIFT) |
+ (0x0b << ZY7_USB_ULPI_VIEWPORT_ADDR_SHIFT) |
+ (0x60 << ZY7_USB_ULPI_VIEWPORT_DATAWR_SHIFT)
+ );
+
+ tries = 100;
+ while ((bus_space_read_4(io_tag, bsh, ZY7_USB_ULPI_VIEWPORT) &
+ ZY7_USB_ULPI_VIEWPORT_RUN) != 0) {
+ if (--tries < 0)
+ return (-1);
+ DELAY(1);
+ }
+ }
+
+ return (0);
+}
+
+static int
+zy7_ehci_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "xlnx,zy7_ehci"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Zynq-7000 EHCI USB 2.0 controller");
+ return (0);
+}
+
+static int zy7_ehci_detach(device_t dev);
+
+static int
+zy7_ehci_attach(device_t dev)
+{
+ ehci_softc_t *sc = device_get_softc(dev);
+ bus_space_handle_t bsh;
+ int err, rid;
+
+ /* initialize some bus fields */
+ sc->sc_bus.parent = dev;
+ sc->sc_bus.devices = sc->sc_devices;
+ sc->sc_bus.devices_max = EHCI_MAX_DEVICES;
+
+ /* get all DMA memory */
+ if (usb_bus_mem_alloc_all(&sc->sc_bus,
+ USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc))
+ return (ENOMEM);
+
+ /* Allocate memory. */
+ rid = 0;
+ sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &rid, RF_ACTIVE);
+ if (sc->sc_io_res == NULL) {
+ device_printf(dev, "Can't allocate memory");
+ zy7_ehci_detach(dev);
+ return (ENOMEM);
+ }
+
+ sc->sc_io_tag = rman_get_bustag(sc->sc_io_res);
+ bsh = rman_get_bushandle(sc->sc_io_res);
+ sc->sc_io_size = EHCI_REG_SIZE;
+
+ if (bus_space_subregion(sc->sc_io_tag, bsh, EHCI_REG_OFFSET,
+ sc->sc_io_size, &sc->sc_io_hdl) != 0)
+ panic("%s: unable to subregion USB host registers",
+ device_get_name(dev));
+
+ /* Allocate IRQ. */
+ rid = 0;
+ sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
+ RF_ACTIVE);
+ if (sc->sc_irq_res == NULL) {
+ device_printf(dev, "Can't allocate IRQ\n");
+ zy7_ehci_detach(dev);
+ return (ENOMEM);
+ }
+
+ /* Add USB device */
+ sc->sc_bus.bdev = device_add_child(dev, "usbus", -1);
+ if (!sc->sc_bus.bdev) {
+ device_printf(dev, "Could not add USB device\n");
+ zy7_ehci_detach(dev);
+ return (ENXIO);
+ }
+ device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus);
+ device_set_desc(sc->sc_bus.bdev, "Zynq-7000 ehci USB 2.0 controller");
+
+ strcpy(sc->sc_vendor, "Xilinx"); /* or IP vendor? */
+
+ /* Activate the interrupt */
+ err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
+ NULL, (driver_intr_t *)ehci_interrupt, sc,
+ &sc->sc_intr_hdl);
+ if (err) {
+ device_printf(dev, "Cannot setup IRQ\n");
+ zy7_ehci_detach(dev);
+ return (err);
+ }
+
+ /* Customization. */
+ sc->sc_flags |= EHCI_SCFLG_SETMODE | EHCI_SCFLG_TT |
+ EHCI_SCFLG_NORESTERM;
+
+ /* Modify FIFO burst threshold from 2 to 8. */
+ bus_space_write_4(sc->sc_io_tag, bsh,
+ ZY7_USB_TXFILLTUNING,
+ 8 << ZY7_USB_TXFILLTUNING_TXFIFOTHRES_SHFT);
+
+ /* Handle PHY options. */
+ if (zy7_phy_config(dev, sc->sc_io_tag, bsh) < 0) {
+ device_printf(dev, "Cannot config phy!\n");
+ zy7_ehci_detach(dev);
+ return (EIO);
+ }
+
+ /* Init ehci. */
+ err = ehci_init(sc);
+ if (!err) {
+ sc->sc_flags |= EHCI_SCFLG_DONEINIT;
+ err = device_probe_and_attach(sc->sc_bus.bdev);
+ }
+ if (err) {
+ device_printf(dev, "USB init failed err=%d\n", err);
+ zy7_ehci_detach(dev);
+ return (err);
+ }
+
+ return (0);
+}
+
+static int
+zy7_ehci_detach(device_t dev)
+{
+ ehci_softc_t *sc = device_get_softc(dev);
+
+ sc->sc_flags &= ~EHCI_SCFLG_DONEINIT;
+
+ if (device_is_attached(dev))
+ bus_generic_detach(dev);
+
+ if (sc->sc_irq_res && sc->sc_intr_hdl)
+ /* call ehci_detach() after ehci_init() called after
+ * successful bus_setup_intr().
+ */
+ ehci_detach(sc);
+ if (sc->sc_bus.bdev) {
+ device_detach(sc->sc_bus.bdev);
+ device_delete_child(dev, sc->sc_bus.bdev);
+ }
+ if (sc->sc_irq_res) {
+ if (sc->sc_intr_hdl != NULL)
+ bus_teardown_intr(dev, sc->sc_irq_res,
+ sc->sc_intr_hdl);
+ bus_release_resource(dev, SYS_RES_IRQ,
+ rman_get_rid(sc->sc_irq_res), sc->sc_irq_res);
+ }
+
+ if (sc->sc_io_res)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->sc_io_res), sc->sc_io_res);
+ usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc);
+
+ return (0);
+}
+
+static device_method_t ehci_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, zy7_ehci_probe),
+ DEVMETHOD(device_attach, zy7_ehci_attach),
+ DEVMETHOD(device_detach, zy7_ehci_detach),
+ DEVMETHOD(device_suspend, bus_generic_suspend),
+ DEVMETHOD(device_resume, bus_generic_resume),
+ DEVMETHOD(device_shutdown, bus_generic_shutdown),
+
+ /* Bus interface */
+ DEVMETHOD(bus_print_child, bus_generic_print_child),
+
+ DEVMETHOD_END
+};
+
+static driver_t ehci_driver = {
+ "ehci",
+ ehci_methods,
+ sizeof(struct ehci_softc),
+};
+static devclass_t ehci_devclass;
+
+DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, NULL, NULL);
+MODULE_DEPEND(ehci, usb, 1, 1, 1);
diff --git a/sys/arm/xilinx/zy7_gpio.c b/sys/arm/xilinx/zy7_gpio.c
new file mode 100644
index 0000000..5b6bb27
--- /dev/null
+++ b/sys/arm/xilinx/zy7_gpio.c
@@ -0,0 +1,384 @@
+/*-
+ * Copyright (C) 2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS 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.
+ *
+ */
+
+/* A GPIO driver for Xilinx Zynq-7000.
+ *
+ * The GPIO peripheral on Zynq allows controlling 114 general purpose I/Os.
+ *
+ * Pins 53-0 are sent to the MIO. Any MIO pins not used by a PS peripheral are
+ * available as a GPIO pin. Pins 64-127 are sent to the PL (FPGA) section of
+ * Zynq as EMIO signals.
+ *
+ * The hardware provides a way to use IOs as interrupt sources but the
+ * gpio framework doesn't seem to have hooks for this.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585. GPIO is covered in
+ * chater 14. Register definitions are in appendix B.19.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/gpio.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "gpio_if.h"
+
+#define NUMBANKS 4
+#define MAXPIN (32*NUMBANKS)
+
+#define MIO_PIN 0 /* pins 0-53 go to MIO */
+#define NUM_MIO_PINS 54
+#define EMIO_PIN 64 /* pins 64-127 go to PL */
+#define NUM_EMIO_PINS 64
+
+#define VALID_PIN(u) (((u) >= MIO_PIN && (u) < MIO_PIN + NUM_MIO_PINS) || \
+ ((u) >= EMIO_PIN && (u) < EMIO_PIN + NUM_EMIO_PINS))
+
+#define ZGPIO_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define ZGPIO_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define ZGPIO_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
+ "gpio", MTX_DEF)
+#define ZGPIO_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+
+struct zy7_gpio_softc {
+ device_t dev;
+ struct mtx sc_mtx;
+ struct resource *mem_res; /* Memory resource */
+};
+
+#define WR4(sc, off, val) bus_write_4((sc)->mem_res, (off), (val))
+#define RD4(sc, off) bus_read_4((sc)->mem_res, (off))
+
+
+/* Xilinx Zynq-7000 GPIO register definitions:
+ */
+#define ZY7_GPIO_MASK_DATA_LSW(b) (0x0000+8*(b)) /* maskable wr lo */
+#define ZY7_GPIO_MASK_DATA_MSW(b) (0x0004+8*(b)) /* maskable wr hi */
+#define ZY7_GPIO_DATA(b) (0x0040+4*(b)) /* in/out data */
+#define ZY7_GPIO_DATA_RO(b) (0x0060+4*(b)) /* input data */
+
+#define ZY7_GPIO_DIRM(b) (0x0204+0x40*(b)) /* direction mode */
+#define ZY7_GPIO_OEN(b) (0x0208+0x40*(b)) /* output enable */
+#define ZY7_GPIO_INT_MASK(b) (0x020c+0x40*(b)) /* int mask */
+#define ZY7_GPIO_INT_EN(b) (0x0210+0x40*(b)) /* int enable */
+#define ZY7_GPIO_INT_DIS(b) (0x0214+0x40*(b)) /* int disable */
+#define ZY7_GPIO_INT_STAT(b) (0x0218+0x40*(b)) /* int status */
+#define ZY7_GPIO_INT_TYPE(b) (0x021c+0x40*(b)) /* int type */
+#define ZY7_GPIO_INT_POLARITY(b) (0x0220+0x40*(b)) /* int polarity */
+#define ZY7_GPIO_INT_ANY(b) (0x0224+0x40*(b)) /* any edge */
+
+
+static int
+zy7_gpio_pin_max(device_t dev, int *maxpin)
+{
+
+ *maxpin = MAXPIN;
+ return (0);
+}
+
+/* Get a specific pin's capabilities. */
+static int
+zy7_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps)
+{
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ *caps = (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
+
+ return (0);
+}
+
+/* Get a specific pin's name. */
+static int
+zy7_gpio_pin_getname(device_t dev, uint32_t pin, char *name)
+{
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ if (pin < NUM_MIO_PINS) {
+ snprintf(name, GPIOMAXNAME, "MIO_%d", pin);
+ name[GPIOMAXNAME - 1] = '\0';
+ } else {
+ snprintf(name, GPIOMAXNAME, "EMIO_%d", pin - EMIO_PIN);
+ name[GPIOMAXNAME - 1] = '\0';
+ }
+
+ return (0);
+}
+
+/* Get a specific pin's current in/out/tri state. */
+static int
+zy7_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ ZGPIO_LOCK(sc);
+
+ if ((RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) & (1 << (pin & 31))) != 0) {
+ /* output */
+ if ((RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & (1 << (pin & 31))) == 0)
+ *flags = (GPIO_PIN_OUTPUT | GPIO_PIN_TRISTATE);
+ else
+ *flags = GPIO_PIN_OUTPUT;
+ } else
+ /* input */
+ *flags = GPIO_PIN_INPUT;
+
+ ZGPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/* Set a specific pin's in/out/tri state. */
+static int
+zy7_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ ZGPIO_LOCK(sc);
+
+ if ((flags & GPIO_PIN_OUTPUT) != 0) {
+ /* Output. Set or reset OEN too. */
+ WR4(sc, ZY7_GPIO_DIRM(pin >> 5),
+ RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) | (1 << (pin & 31)));
+
+ if ((flags & GPIO_PIN_TRISTATE) != 0)
+ WR4(sc, ZY7_GPIO_OEN(pin >> 5),
+ RD4(sc, ZY7_GPIO_OEN(pin >> 5)) &
+ ~(1 << (pin & 31)));
+ else
+ WR4(sc, ZY7_GPIO_OEN(pin >> 5),
+ RD4(sc, ZY7_GPIO_OEN(pin >> 5)) |
+ (1 << (pin & 31)));
+ } else {
+ /* Input. Turn off OEN. */
+ WR4(sc, ZY7_GPIO_DIRM(pin >> 5),
+ RD4(sc, ZY7_GPIO_DIRM(pin >> 5)) & ~(1 << (pin & 31)));
+ WR4(sc, ZY7_GPIO_OEN(pin >> 5),
+ RD4(sc, ZY7_GPIO_OEN(pin >> 5)) & ~(1 << (pin & 31)));
+ }
+
+ ZGPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+/* Set a specific output pin's value. */
+static int
+zy7_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+
+ if (!VALID_PIN(pin) || value > 1)
+ return (EINVAL);
+
+ /* Fancy register tricks allow atomic set or reset. */
+ if ((pin & 16) != 0)
+ WR4(sc, ZY7_GPIO_MASK_DATA_MSW(pin >> 5),
+ (0xffff0000 ^ (0x10000 << (pin & 15))) |
+ (value << (pin & 15)));
+ else
+ WR4(sc, ZY7_GPIO_MASK_DATA_LSW(pin >> 5),
+ (0xffff0000 ^ (0x10000 << (pin & 15))) |
+ (value << (pin & 15)));
+
+ return (0);
+}
+
+/* Get a specific pin's input value. */
+static int
+zy7_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ *value = (RD4(sc, ZY7_GPIO_DATA_RO(pin >> 5)) >> (pin & 31)) & 1;
+
+ return (0);
+}
+
+/* Toggle a pin's output value. */
+static int
+zy7_gpio_pin_toggle(device_t dev, uint32_t pin)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+
+ if (!VALID_PIN(pin))
+ return (EINVAL);
+
+ ZGPIO_LOCK(sc);
+
+ WR4(sc, ZY7_GPIO_DATA(pin >> 5),
+ RD4(sc, ZY7_GPIO_DATA(pin >> 5)) ^ (1 << (pin & 31)));
+
+ ZGPIO_UNLOCK(sc);
+
+ return (0);
+}
+
+static int
+zy7_gpio_probe(device_t dev)
+{
+
+ if (!ofw_bus_is_compatible(dev, "xlnx,zy7_gpio"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Zynq-7000 GPIO driver");
+ return (0);
+}
+
+static void
+zy7_gpio_hw_reset(struct zy7_gpio_softc *sc)
+{
+ int i;
+
+ for (i = 0; i < NUMBANKS; i++) {
+ WR4(sc, ZY7_GPIO_DATA(i), 0);
+ WR4(sc, ZY7_GPIO_DIRM(i), 0);
+ WR4(sc, ZY7_GPIO_OEN(i), 0);
+ WR4(sc, ZY7_GPIO_INT_DIS(i), 0xffffffff);
+ WR4(sc, ZY7_GPIO_INT_POLARITY(i), 0);
+ WR4(sc, ZY7_GPIO_INT_TYPE(i),
+ i == 1 ? 0x003fffff : 0xffffffff);
+ WR4(sc, ZY7_GPIO_INT_ANY(i), 0);
+ WR4(sc, ZY7_GPIO_INT_STAT(i), 0xffffffff);
+ }
+}
+
+static int zy7_gpio_detach(device_t dev);
+
+static int
+zy7_gpio_attach(device_t dev)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+ int rid;
+
+ sc->dev = dev;
+
+ ZGPIO_LOCK_INIT(sc);
+
+ /* Allocate memory. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev,
+ SYS_RES_MEMORY, &rid, RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "Can't allocate memory for device");
+ zy7_gpio_detach(dev);
+ return (ENOMEM);
+ }
+
+ /* Completely reset. */
+ zy7_gpio_hw_reset(sc);
+
+ device_add_child(dev, "gpioc", device_get_unit(dev));
+ device_add_child(dev, "gpiobus", device_get_unit(dev));
+
+ return (bus_generic_attach(dev));
+}
+
+static int
+zy7_gpio_detach(device_t dev)
+{
+ struct zy7_gpio_softc *sc = device_get_softc(dev);
+
+ bus_generic_detach(dev);
+
+ if (sc->mem_res != NULL) {
+ /* Release memory resource. */
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+ }
+
+ ZGPIO_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t zy7_gpio_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, zy7_gpio_probe),
+ DEVMETHOD(device_attach, zy7_gpio_attach),
+ DEVMETHOD(device_detach, zy7_gpio_detach),
+
+ /* GPIO protocol */
+ DEVMETHOD(gpio_pin_max, zy7_gpio_pin_max),
+ DEVMETHOD(gpio_pin_getname, zy7_gpio_pin_getname),
+ DEVMETHOD(gpio_pin_getflags, zy7_gpio_pin_getflags),
+ DEVMETHOD(gpio_pin_getcaps, zy7_gpio_pin_getcaps),
+ DEVMETHOD(gpio_pin_setflags, zy7_gpio_pin_setflags),
+ DEVMETHOD(gpio_pin_get, zy7_gpio_pin_get),
+ DEVMETHOD(gpio_pin_set, zy7_gpio_pin_set),
+ DEVMETHOD(gpio_pin_toggle, zy7_gpio_pin_toggle),
+
+ DEVMETHOD_END
+};
+
+static driver_t zy7_gpio_driver = {
+ "zy7_gpio",
+ zy7_gpio_methods,
+ sizeof(struct zy7_gpio_softc),
+};
+static devclass_t zy7_gpio_devclass;
+
+extern devclass_t gpiobus_devclass, gpioc_devclass;
+extern driver_t gpiobus_driver, gpioc_driver;
+
+DRIVER_MODULE(zy7_gpio, simplebus, zy7_gpio_driver, zy7_gpio_devclass, \
+ NULL, NULL);
+DRIVER_MODULE(gpiobus, zy7_gpio, gpiobus_driver, gpiobus_devclass, 0, 0);
+DRIVER_MODULE(gpioc, zy7_gpio, gpioc_driver, gpioc_devclass, 0, 0);
diff --git a/sys/arm/xilinx/zy7_l2cache.c b/sys/arm/xilinx/zy7_l2cache.c
new file mode 100644
index 0000000..f1ab181
--- /dev/null
+++ b/sys/arm/xilinx/zy7_l2cache.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (C) 2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/pl310.h>
+
+void
+platform_pl310_init(struct pl310_softc *softc)
+{
+}
+
+void
+platform_pl310_write_ctrl(struct pl310_softc *sc, uint32_t val)
+{
+
+ pl310_write4(sc, PL310_CTRL, val);
+}
+
+void
+platform_pl310_write_debug(struct pl310_softc *sc, uint32_t val)
+{
+
+ pl310_write4(sc, PL310_DEBUG_CTRL, val);
+}
diff --git a/sys/arm/xilinx/zy7_machdep.c b/sys/arm/xilinx/zy7_machdep.c
new file mode 100644
index 0000000..c50796d
--- /dev/null
+++ b/sys/arm/xilinx/zy7_machdep.c
@@ -0,0 +1,161 @@
+/*-
+ * Copyright (C) 2012-2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS 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 dependent code for Xilinx Zynq-7000 Soc.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585.
+ */
+
+#include "opt_global.h"
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#define _ARM32_BUS_DMA_PRIVATE
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <vm/vm.h>
+#include <vm/pmap.h>
+
+#include <dev/fdt/fdt_common.h>
+
+#include <machine/bus.h>
+#include <machine/pmap.h>
+#include <machine/frame.h>
+#include <machine/machdep.h>
+
+#include <arm/xilinx/zy7_reg.h>
+
+void (*zynq7_cpu_reset)(void);
+
+vm_offset_t
+initarm_lastaddr(void)
+{
+
+ return (ZYNQ7_PSIO_VBASE - ARM_NOCACHE_KVA_SIZE);
+}
+
+void
+initarm_gpio_init(void)
+{
+}
+
+void
+initarm_late_init(void)
+{
+}
+
+#define FDT_DEVMAP_SIZE 3
+static struct pmap_devmap fdt_devmap[FDT_DEVMAP_SIZE];
+
+/*
+ * Construct pmap_devmap[] with DT-derived config data.
+ */
+int
+platform_devmap_init(void)
+{
+ int i = 0;
+
+ fdt_devmap[i].pd_va = ZYNQ7_PSIO_VBASE;
+ fdt_devmap[i].pd_pa = ZYNQ7_PSIO_HWBASE;
+ fdt_devmap[i].pd_size = ZYNQ7_PSIO_SIZE;
+ fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+ fdt_devmap[i].pd_cache = PTE_DEVICE;
+ i++;
+
+ fdt_devmap[i].pd_va = ZYNQ7_PSCTL_VBASE;
+ fdt_devmap[i].pd_pa = ZYNQ7_PSCTL_HWBASE;
+ fdt_devmap[i].pd_size = ZYNQ7_PSCTL_SIZE;
+ fdt_devmap[i].pd_prot = VM_PROT_READ | VM_PROT_WRITE;
+ fdt_devmap[i].pd_cache = PTE_DEVICE;
+ i++;
+
+ /* end of table */
+ fdt_devmap[i].pd_va = 0;
+ fdt_devmap[i].pd_pa = 0;
+ fdt_devmap[i].pd_size = 0;
+ fdt_devmap[i].pd_prot = 0;
+ fdt_devmap[i].pd_cache = 0;
+
+ pmap_devmap_bootstrap_table = &fdt_devmap[0];
+ return (0);
+}
+
+
+struct fdt_fixup_entry fdt_fixup_table[] = {
+ { NULL, NULL }
+};
+
+static int
+fdt_gic_decode_ic(phandle_t node, pcell_t *intr, int *interrupt, int *trig,
+ int *pol)
+{
+
+ if (!fdt_is_compatible(node, "arm,gic"))
+ return (ENXIO);
+
+ *interrupt = fdt32_to_cpu(intr[0]);
+ *trig = INTR_TRIGGER_CONFORM;
+ *pol = INTR_POLARITY_CONFORM;
+
+ return (0);
+}
+
+fdt_pic_decode_t fdt_pic_table[] = {
+ &fdt_gic_decode_ic,
+ NULL
+};
+
+
+struct arm32_dma_range *
+bus_dma_get_range(void)
+{
+
+ return (NULL);
+}
+
+int
+bus_dma_get_range_nb(void)
+{
+
+ return (0);
+}
+
+void
+cpu_reset()
+{
+ if (zynq7_cpu_reset != NULL)
+ (*zynq7_cpu_reset)();
+
+ printf("cpu_reset: no platform cpu_reset. hanging.\n");
+ for (;;)
+ ;
+}
diff --git a/sys/arm/xilinx/zy7_reg.h b/sys/arm/xilinx/zy7_reg.h
new file mode 100644
index 0000000..b30c86d
--- /dev/null
+++ b/sys/arm/xilinx/zy7_reg.h
@@ -0,0 +1,78 @@
+/*-
+ * Copyright (C) 2012-2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL Thomas Skibo OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+/* $FreeBSD$ */
+
+/* Address regions of Zynq-7000.
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585.
+ */
+
+#ifndef _ZY7_REG_H_
+#define _ZY7_REG_H_
+
+/* PL AXI buses: General Purpose Port #0, M_AXI_GP0. */
+#define ZYNQ7_PLGP0_HWBASE 0x40000000
+#define ZYNQ7_PLGP0_SIZE 0x40000000
+
+/* PL AXI buses: General Purpose Port #1, M_AXI_GP1. */
+#define ZYNQ7_PLGP1_HWBASE 0x80000000
+#define ZYNQ7_PLGP1_SIZE 0x40000000
+
+/* I/O Peripheral registers. */
+#define ZYNQ7_PSIO_VBASE 0xE0000000
+#define ZYNQ7_PSIO_HWBASE 0xE0000000
+#define ZYNQ7_PSIO_SIZE 0x00300000
+
+/* UART0 and UART1 */
+#define ZYNQ7_UART0_VBASE (ZYNQ7_PSIO_VBASE)
+#define ZYNQ7_UART0_HWBASE (ZYNQ7_PSIO_HWBASE)
+#define ZYNQ7_UART0_SIZE 0x1000
+
+#define ZYNQ7_UART1_VBASE (ZYNQ7_PSIO_VBASE+0x1000)
+#define ZYNQ7_UART1_HWBASE (ZYNQ7_PSIO_HWBASE+0x1000)
+#define ZYNQ7_UART1_SIZE 0x1000
+
+
+/* SMC Memories not mapped for now. */
+#define ZYNQ7_SMC_HWBASE 0xE1000000
+#define ZYNQ7_SMC_SIZE 0x05000000
+
+/* SLCR, PS system, and CPU private registers combined in this region. */
+#define ZYNQ7_PSCTL_VBASE 0xF8000000
+#define ZYNQ7_PSCTL_HWBASE 0xF8000000
+#define ZYNQ7_PSCTL_SIZE 0x01000000
+
+#define ZYNQ7_SLCR_VBASE (ZYNQ7_PSCTL_VBASE)
+#define ZYNQ7_SLCR_HWBASE (ZYNQ7_PSCTL_HWBASE)
+#define ZYNQ7_SLCR_SIZE 0x1000
+
+#define ZYNQ7_DEVCFG_VBASE (ZYNQ7_PSCTL_VBASE+0x7000)
+#define ZYNQ7_DEVCFG_HWBASE (ZYNQ7_PSCTL_HWBASE+0x7000)
+#define ZYNQ7_DEVCFG_SIZE 0x1000
+
+#endif /* _ZY7_REG_H_ */
diff --git a/sys/arm/xilinx/zy7_slcr.c b/sys/arm/xilinx/zy7_slcr.c
new file mode 100644
index 0000000..048b768
--- /dev/null
+++ b/sys/arm/xilinx/zy7_slcr.c
@@ -0,0 +1,301 @@
+/*-
+ * Copyright (C) 2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS 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.
+ *
+ */
+
+/* Zynq-700 SLCR driver. Provides hooks for cpu_reset and PL control stuff.
+ * In the future, maybe MIO control, clock control, etc. could go here.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/resource.h>
+#include <sys/sysctl.h>
+#include <sys/rman.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/stdarg.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/xilinx/zy7_slcr.h>
+
+struct zy7_slcr_softc {
+ device_t dev;
+ struct mtx sc_mtx;
+ struct resource *mem_res;
+};
+
+static struct zy7_slcr_softc *zy7_slcr_softc_p;
+extern void (*zynq7_cpu_reset);
+
+#define ZSLCR_LOCK(sc) mtx_lock(&(sc)->sc_mtx)
+#define ZSLCR_UNLOCK(sc) mtx_unlock(&(sc)->sc_mtx)
+#define ZSLCR_LOCK_INIT(sc) \
+ mtx_init(&(sc)->sc_mtx, device_get_nameunit((sc)->dev), \
+ "zy7_slcr", MTX_SPIN)
+#define ZSLCR_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx);
+
+#define RD4(sc, off) (bus_read_4((sc)->mem_res, (off)))
+#define WR4(sc, off, val) (bus_write_4((sc)->mem_res, (off), (val)))
+
+
+SYSCTL_NODE(_hw, OID_AUTO, zynq, CTLFLAG_RD, 0, "Xilinx Zynq-7000");
+
+static char zynq_bootmode[64];
+SYSCTL_STRING(_hw_zynq, OID_AUTO, bootmode, CTLFLAG_RD, zynq_bootmode, 0,
+ "Zynq boot mode");
+
+static char zynq_pssid[80];
+SYSCTL_STRING(_hw_zynq, OID_AUTO, pssid, CTLFLAG_RD, zynq_pssid, 0,
+ "Zynq PSS IDCODE");
+
+static uint32_t zynq_reboot_status;
+SYSCTL_INT(_hw_zynq, OID_AUTO, reboot_status, CTLFLAG_RD, &zynq_reboot_status,
+ 0, "Zynq REBOOT_STATUS register");
+
+static void
+zy7_slcr_unlock(struct zy7_slcr_softc *sc)
+{
+
+ /* Unlock SLCR with magic number. */
+ WR4(sc, ZY7_SLCR_UNLOCK, ZY7_SLCR_UNLOCK_MAGIC);
+}
+
+static void
+zy7_slcr_lock(struct zy7_slcr_softc *sc)
+{
+
+ /* Lock SLCR with magic number. */
+ WR4(sc, ZY7_SLCR_LOCK, ZY7_SLCR_LOCK_MAGIC);
+}
+
+
+static void
+zy7_slcr_cpu_reset(void)
+{
+ struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
+
+ /* Unlock SLCR registers. */
+ zy7_slcr_unlock(sc);
+
+ /* This has something to do with a work-around so the fsbl will load
+ * the bitstream after soft-reboot. It's very important.
+ */
+ WR4(sc, ZY7_SLCR_REBOOT_STAT,
+ RD4(sc, ZY7_SLCR_REBOOT_STAT) & 0xf0ffffff);
+
+ /* Soft reset */
+ WR4(sc, ZY7_SLCR_PSS_RST_CTRL, ZY7_SLCR_PSS_RST_CTRL_SOFT_RESET);
+
+ for (;;)
+ ;
+}
+
+/* Assert PL resets and disable level shifters in preparation of programming
+ * the PL (FPGA) section. Called from zy7_devcfg.c.
+ */
+void
+zy7_slcr_preload_pl(void)
+{
+ struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
+
+ if (!sc)
+ return;
+
+ ZSLCR_LOCK(sc);
+
+ /* Unlock SLCR registers. */
+ zy7_slcr_unlock(sc);
+
+ /* Assert top level output resets. */
+ WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, ZY7_SLCR_FPGA_RST_CTRL_RST_ALL);
+
+ /* Disable all level shifters. */
+ WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, 0);
+
+ /* Lock SLCR registers. */
+ zy7_slcr_lock(sc);
+
+ ZSLCR_UNLOCK(sc);
+}
+
+/* After PL configuration, enable level shifters and deassert top-level
+ * PL resets. Called from zy7_devcfg.c. Optionally, the level shifters
+ * can be left disabled but that's rare of an FPGA application. That option
+ * is controled by a sysctl in the devcfg driver.
+ */
+void
+zy7_slcr_postload_pl(int en_level_shifters)
+{
+ struct zy7_slcr_softc *sc = zy7_slcr_softc_p;
+
+ if (!sc)
+ return;
+
+ ZSLCR_LOCK(sc);
+
+ /* Unlock SLCR registers. */
+ zy7_slcr_unlock(sc);
+
+ if (en_level_shifters)
+ /* Enable level shifters. */
+ WR4(sc, ZY7_SLCR_LVL_SHFTR_EN, ZY7_SLCR_LVL_SHFTR_EN_ALL);
+
+ /* Deassert top level output resets. */
+ WR4(sc, ZY7_SLCR_FPGA_RST_CTRL, 0);
+
+ /* Lock SLCR registers. */
+ zy7_slcr_lock(sc);
+
+ ZSLCR_UNLOCK(sc);
+}
+
+static int
+zy7_slcr_probe(device_t dev)
+{
+ if (!ofw_bus_is_compatible(dev, "xlnx,zy7_slcr"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Zynq-7000 slcr block");
+ return (0);
+}
+
+static int
+zy7_slcr_attach(device_t dev)
+{
+ struct zy7_slcr_softc *sc = device_get_softc(dev);
+ int rid;
+ uint32_t bootmode;
+ uint32_t pss_idcode;
+ static char *bootdev_names[] = {
+ "JTAG", "Quad-SPI", "NOR", "(3?)",
+ "NAND", "SD Card", "(6?)", "(7?)"
+ };
+
+ /* Allow only one attach. */
+ if (zy7_slcr_softc_p != NULL)
+ return (ENXIO);
+
+ sc->dev = dev;
+
+ ZSLCR_LOCK_INIT(sc);
+
+ /* Get memory resource. */
+ rid = 0;
+ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
+ RF_ACTIVE);
+ if (sc->mem_res == NULL) {
+ device_printf(dev, "could not allocate memory resources.\n");
+ return (ENOMEM);
+ }
+
+ /* Hook up cpu_reset. */
+ zy7_slcr_softc_p = sc;
+ zynq7_cpu_reset = zy7_slcr_cpu_reset;
+
+ /* Read info and set sysctls. */
+ bootmode = RD4(sc, ZY7_SLCR_BOOT_MODE);
+ snprintf(zynq_bootmode, sizeof(zynq_bootmode),
+ "0x%x: boot device: %s", bootmode,
+ bootdev_names[bootmode & ZY7_SLCR_BOOT_MODE_BOOTDEV_MASK]);
+
+ pss_idcode = RD4(sc, ZY7_SLCR_PSS_IDCODE);
+ snprintf(zynq_pssid, sizeof(zynq_pssid),
+ "0x%x: manufacturer: 0x%x device: 0x%x "
+ "family: 0x%x sub-family: 0x%x rev: 0x%x",
+ pss_idcode,
+ (pss_idcode & ZY7_SLCR_PSS_IDCODE_MNFR_ID_MASK) >>
+ ZY7_SLCR_PSS_IDCODE_MNFR_ID_SHIFT,
+ (pss_idcode & ZY7_SLCR_PSS_IDCODE_DEVICE_MASK) >>
+ ZY7_SLCR_PSS_IDCODE_DEVICE_SHIFT,
+ (pss_idcode & ZY7_SLCR_PSS_IDCODE_FAMILY_MASK) >>
+ ZY7_SLCR_PSS_IDCODE_FAMILY_SHIFT,
+ (pss_idcode & ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_MASK) >>
+ ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_SHIFT,
+ (pss_idcode & ZY7_SLCR_PSS_IDCODE_REVISION_MASK) >>
+ ZY7_SLCR_PSS_IDCODE_REVISION_SHIFT);
+
+ zynq_reboot_status = RD4(sc, ZY7_SLCR_REBOOT_STAT);
+
+ /* Lock SLCR registers. */
+ zy7_slcr_lock(sc);
+
+ return (0);
+}
+
+static int
+zy7_slcr_detach(device_t dev)
+{
+ struct zy7_slcr_softc *sc = device_get_softc(dev);
+
+ bus_generic_detach(dev);
+
+ /* Release memory resource. */
+ if (sc->mem_res != NULL)
+ bus_release_resource(dev, SYS_RES_MEMORY,
+ rman_get_rid(sc->mem_res), sc->mem_res);
+
+ zy7_slcr_softc_p = NULL;
+ zynq7_cpu_reset = NULL;
+
+ ZSLCR_LOCK_DESTROY(sc);
+
+ return (0);
+}
+
+static device_method_t zy7_slcr_methods[] = {
+ /* device_if */
+ DEVMETHOD(device_probe, zy7_slcr_probe),
+ DEVMETHOD(device_attach, zy7_slcr_attach),
+ DEVMETHOD(device_detach, zy7_slcr_detach),
+
+ DEVMETHOD_END
+};
+
+static driver_t zy7_slcr_driver = {
+ "zy7_slcr",
+ zy7_slcr_methods,
+ sizeof(struct zy7_slcr_softc),
+};
+static devclass_t zy7_slcr_devclass;
+
+DRIVER_MODULE(zy7_slcr, simplebus, zy7_slcr_driver, zy7_slcr_devclass, 0, 0);
+MODULE_VERSION(zy7_slcr, 1);
diff --git a/sys/arm/xilinx/zy7_slcr.h b/sys/arm/xilinx/zy7_slcr.h
new file mode 100644
index 0000000..ae6d03b
--- /dev/null
+++ b/sys/arm/xilinx/zy7_slcr.h
@@ -0,0 +1,280 @@
+/*-
+ * Copyright (C) 2013, Thomas Skibo.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * 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.
+ * * The names of contributors may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ */
+
+/* $FreeBSD$ */
+
+/* Defines for Zynq-7000 SLCR registers.
+ *
+ * Most of these registers are initialized by the First Stage Boot
+ * Loader and are not modified by the kernel.
+ *
+ * Reference: Zynq-7000 All Programmable SoC Technical Reference Manual.
+ * (v1.4) November 16, 2012. Xilinx doc UG585. SLCR register definitions
+ * are in appendix B.28.
+ */
+
+
+#ifndef _ZY7_SLCR_H_
+#define _ZY7_SLCR_H_
+
+#define ZY7_SCLR_SCL 0x0000
+#define ZY7_SLCR_LOCK 0x0004
+#define ZY7_SLCR_LOCK_MAGIC 0x767b
+#define ZY7_SLCR_UNLOCK 0x0008
+#define ZY7_SLCR_UNLOCK_MAGIC 0xdf0d
+#define ZY7_SLCR_LOCKSTA 0x000c
+
+/* PLL controls. */
+#define ZY7_SLCR_ARM_PLL_CTRL 0x0100
+#define ZY7_SLCR_DDR_PLL_CTRL 0x0104
+#define ZY7_SLCR_IO_PLL_CTRL 0x0108
+#define ZY7_SLCR_PLL_CTRL_RESET (1<<0)
+#define ZY7_SLCR_PLL_CTRL_PWRDWN (1<<1)
+#define ZY7_SLCR_PLL_CTRL_BYPASS_QUAL (1<<3)
+#define ZY7_SLCR_PLL_CTRL_BYPASS_FORCE (1<<4)
+#define ZY7_SLCR_PLL_CTRL_FDIV_SHIFT 12
+#define ZY7_SLCR_PLL_CTRL_FDIV_MASK (0x7f<<12)
+#define ZY7_SLCR_PLL_STATUS 0x010c
+#define ZY7_SLCR_PLL_STAT_ARM_PLL_LOCK (1<<0)
+#define ZY7_SLCR_PLL_STAT_DDR_PLL_LOCK (1<<1)
+#define ZY7_SLCR_PLL_STAT_IO_PLL_LOCK (1<<2)
+#define ZY7_SLCR_PLL_STAT_ARM_PLL_STABLE (1<<3)
+#define ZY7_SLCR_PLL_STAT_DDR_PLL_STABLE (1<<4)
+#define ZY7_SLCR_PLL_STAT_IO_PLL_STABLE (1<<5)
+#define ZY7_SLCR_ARM_PLL_CFG 0x0110
+#define ZY7_SLCR_DDR_PLL_CFG 0x0114
+#define ZY7_SLCR_IO_PLL_CFG 0x0118
+#define ZY7_SLCR_PLL_CFG_RES_SHIFT 4
+#define ZY7_SLCR_PLL_CFG_RES_MASK (0xf<<4)
+#define ZY7_SLCR_PLL_CFG_PLL_CP_SHIFT 8
+#define ZY7_SLCR_PLL_CFG_PLL_CP_MASK (0xf<<8)
+#define ZY7_SLCR_PLL_CFG_LOCK_CNT_SHIFT 12
+#define ZY7_SLCR_PLL_CFG_LOCK_CNT_MASK (0x3ff<<12)
+
+/* Clock controls. */
+#define ZY7_SLCR_ARM_CLK_CTRL 0x0120
+#define ZY7_SLCR_ARM_CLK_CTRL_CPU_PERI_CLKACT (1<<28)
+#define ZY7_SLCR_ARM_CLK_CTRL_CPU_1XCLKACT (1<<27)
+#define ZY7_SLCR_ARM_CLK_CTRL_CPU_2XCLKACT (1<<26)
+#define ZY7_SLCR_ARM_CLK_CTRL_CPU_3OR2XCLKACT (1<<25)
+#define ZY7_SLCR_ARM_CLK_CTRL_CPU_6OR4XCLKACT (1<<24)
+#define ZY7_SLCR_ARM_CLK_CTRL_SRCSEL_MASK (3<<4)
+#define ZY7_SLCR_ARM_CLK_CTRL_SRCSEL_ARM_PLL (0<<4)
+#define ZY7_SLCR_ARM_CLK_CTRL_SRCSEL_DDR_PLL (2<<4)
+#define ZY7_SLCR_ARM_CLK_CTRL_SRCSEL_IO_PLL (3<<4)
+#define ZY7_SLCR_ARM_CLK_CTRL_DIVISOR_SHIFT 8
+#define ZY7_SLCR_ARM_CLK_CTRL_DIVISOR_MASK (0x3f<<8)
+#define ZY7_SLCR_DDR_CLK_CTRL 0x0124
+#define ZY7_SLCR_DDR_CLK_CTRL_2XCLK_DIV_SHIFT 26
+#define ZY7_SLCR_DDR_CLK_CTRL_2XCLK_DIV_MASK (0x3f<<26)
+#define ZY7_SLCR_DDR_CLK_CTRL_3XCLK_DIV_SHIFT 20
+#define ZY7_SLCR_DDR_CLK_CTRL_3XCLK_DIV_MASK (0x3f<<20)
+#define ZY7_SLCR_DDR_CLK_CTRL_2XCLKACT (1<<1)
+#define ZY7_SLCR_DDR_CLK_CTRL_3XCLKACT (1<<0)
+#define ZY7_SLCR_DCI_CLK_CTRL 0x0128
+#define ZY7_SLCR_DCI_CLK_CTRL_DIVISOR1_SHIFT 20
+#define ZY7_SLCR_DCI_CLK_CTRL_DIVISOR1_MASK (0x3f<<20)
+#define ZY7_SLCR_DCI_CLK_CTRL_DIVISOR0_SHIFT 8
+#define ZY7_SLCR_DCI_CLK_CTRL_DIVISOR0_MASK (0x3f<<8)
+#define ZY7_SLCR_DCI_CLK_CTRL_CLKACT (1<<0)
+#define ZY7_SLCR_APER_CLK_CTRL 0x012c /* amba periph clk ctrl */
+#define ZY7_SLCR_APER_CLK_CTRL_SMC_CPU_1XCLKACT (1<<24)
+#define ZY7_SLCR_APER_CLK_CTRL_LQSPI_CPU_1XCLKACT (1<<23)
+#define ZY7_SLCR_APER_CLK_CTRL_GPIO_CPU_1XCLKACT (1<<22)
+#define ZY7_SLCR_APER_CLK_CTRL_UART1_CPU_1XCLKACT (1<<21)
+#define ZY7_SLCR_APER_CLK_CTRL_UART0_CPU_1XCLKACT (1<<20)
+#define ZY7_SLCR_APER_CLK_CTRL_I2C1_CPU_1XCLKACT (1<<19)
+#define ZY7_SLCR_APER_CLK_CTRL_I2C0_CPU_1XCLKACT (1<<18)
+#define ZY7_SLCR_APER_CLK_CTRL_CAN1_CPU_1XCLKACT (1<<17)
+#define ZY7_SLCR_APER_CLK_CTRL_CAN0_CPU_1XCLKACT (1<<16)
+#define ZY7_SLCR_APER_CLK_CTRL_SPI1_CPU_1XCLKACT (1<<15)
+#define ZY7_SLCR_APER_CLK_CTRL_SPI0_CPU_1XCLKACT (1<<14)
+#define ZY7_SLCR_APER_CLK_CTRL_SDI1_CPU_1XCLKACT (1<<11)
+#define ZY7_SLCR_APER_CLK_CTRL_SDI0_CPU_1XCLKACT (1<<10)
+#define ZY7_SLCR_APER_CLK_CTRL_GEM1_CPU_1XCLKACT (1<<7)
+#define ZY7_SLCR_APER_CLK_CTRL_GEM0_CPU_1XCLKACT (1<<6)
+#define ZY7_SLCR_APER_CLK_CTRL_USB1_CPU_1XCLKACT (1<<3)
+#define ZY7_SLCR_APER_CLK_CTRL_USB0_CPU_1XCLKACT (1<<2)
+#define ZY7_SLCR_APER_CLK_CTRL_DMA_CPU_1XCLKACT (1<<0)
+#define ZY7_SLCR_USB0_CLK_CTRL 0x0130
+#define ZY7_SLCR_USB1_CLK_CTRL 0x0134
+#define ZY7_SLCR_GEM0_RCLK_CTRL 0x0138
+#define ZY7_SLCR_GEM1_RCLK_CTRL 0x013c
+#define ZY7_SLCR_GEM0_CLK_CTRL 0x0140
+#define ZY7_SLCR_GEM1_CLK_CTRL 0x0144
+#define ZY7_SLCR_SMC_CLK_CTRL 0x0148
+#define ZY7_SLCR_LQSPI_CLK_CTRL 0x014c
+#define ZY7_SLCR_SDIO_CLK_CTRL 0x0150
+#define ZY7_SLCR_UART_CLK_CTRL 0x0154
+#define ZY7_SLCR_SPI_CLK_CTRL 0x0158
+#define ZY7_SLCR_CAN_CLK_CTRL 0x015c
+#define ZY7_SLCR_CAN_MIOCLK_CTRL 0x0160
+#define ZY7_SLCR_DBG_CLK_CTRL 0x0164
+#define ZY7_SLCR_PCAP_CLK_CTRL 0x0168
+#define ZY7_SLCR_TOPSW_CLK_CTRL 0x016c /* central intercnn clk ctrl */
+#define ZY7_SLCR_FPGA0_CLK_CTRL 0x0170
+#define ZY7_SLCR_FPGA1_CLK_CTRL 0x0180
+#define ZY7_SLCR_FPGA2_CLK_CTRL 0x0190
+#define ZY7_SLCR_FPGA3_CLK_CTRL 0x01a0
+#define ZY7_SLCR_CLK_621_TRUE 0x01c4 /* cpu clock ratio mode */
+
+/* Reset controls. */
+#define ZY7_SLCR_PSS_RST_CTRL 0x0200
+#define ZY7_SLCR_PSS_RST_CTRL_SOFT_RESET (1<<0)
+#define ZY7_SLCR_DDR_RST_CTRL 0x0204
+#define ZY7_SLCR_TOPSW_RST_CTRL 0x0208
+#define ZY7_SLCR_DMAC_RST_CTRL 0x020c
+#define ZY7_SLCR_USB_RST_CTRL 0x0210
+#define ZY7_SLCR_GEM_RST_CTRL 0x0214
+#define ZY7_SLCR_SDIO_RST_CTRL 0x0218
+#define ZY7_SLCR_SPI_RST_CTRL 0x021c
+#define ZY7_SLCR_CAN_RST_CTRL 0x0220
+#define ZY7_SLCR_I2C_RST_CTRL 0x0224
+#define ZY7_SLCR_UART_RST_CTRL 0x0228
+#define ZY7_SLCR_GPIO_RST_CTRL 0x022c
+#define ZY7_SLCR_LQSPI_RST_CTRL 0x0230
+#define ZY7_SLCR_SMC_RST_CTRL 0x0234
+#define ZY7_SLCR_OCM_RST_CTRL 0x0238
+#define ZY7_SLCR_DEVCI_RST_CTRL 0x023c
+#define ZY7_SLCR_FPGA_RST_CTRL 0x0240
+#define ZY7_SLCR_FPGA_RST_CTRL_FPGA3_OUT_RST (1<<3)
+#define ZY7_SLCR_FPGA_RST_CTRL_FPGA2_OUT_RST (1<<2)
+#define ZY7_SLCR_FPGA_RST_CTRL_FPGA1_OUT_RST (1<<1)
+#define ZY7_SLCR_FPGA_RST_CTRL_FPGA0_OUT_RST (1<<0)
+#define ZY7_SLCR_FPGA_RST_CTRL_RST_ALL 0xf
+#define ZY7_SLCR_A9_CPU_RST_CTRL 0x0244
+#define ZY7_SLCR_RS_AWDT_CTRL 0x024c
+
+#define ZY7_SLCR_REBOOT_STAT 0x0258
+#define ZY7_SLCR_REBOOT_STAT_STATE_MASK (0xff<<24)
+#define ZY7_SLCR_REBOOT_STAT_POR (1<<22)
+#define ZY7_SLCR_REBOOT_STAT_SRST_B (1<<21)
+#define ZY7_SLCR_REBOOT_STAT_DBG_RST (1<<20)
+#define ZY7_SLCR_REBOOT_STAT_SLC_RST (1<<19)
+#define ZY7_SLCR_REBOOT_STAT_AWDT1_RST (1<<18)
+#define ZY7_SLCR_REBOOT_STAT_AWDT0_RST (1<<17)
+#define ZY7_SLCR_REBOOT_STAT_SWDT_RST (1<<16)
+#define ZY7_SLCR_REBOOT_STAT_BOOTROM_ERR_CODE_MASK (0xffff)
+#define ZY7_SLCR_BOOT_MODE 0x025c
+#define ZY7_SLCR_BOOT_MODE_PLL_BYPASS (1<<4)
+#define ZY7_SLCR_BOOT_MODE_JTAG_INDEP (1<<3)
+#define ZY7_SLCR_BOOT_MODE_BOOTDEV_MASK 7
+#define ZY7_SLCR_BOOT_MODE_BOOTDEV_JTAG 0
+#define ZY7_SLCR_BOOT_MODE_BOOTDEV_QUAD_SPI 1
+#define ZY7_SLCR_BOOT_MODE_BOOTDEV_NOR 2
+#define ZY7_SLCR_BOOT_MODE_BOOTDEV_NAND 4
+#define ZY7_SLCR_BOOT_MODE_BOOTDEV_SD_CARD 5
+#define ZY7_SLCR_APU_CTRL 0x0300
+#define ZY7_SLCR_WDT_CLK_SEL 0x0304
+
+#define ZY7_SLCR_PSS_IDCODE 0x0530
+#define ZY7_SLCR_PSS_IDCODE_REVISION_MASK (0xf<<28)
+#define ZY7_SLCR_PSS_IDCODE_REVISION_SHIFT 28
+#define ZY7_SLCR_PSS_IDCODE_FAMILY_MASK (0x7f<<21)
+#define ZY7_SLCR_PSS_IDCODE_FAMILY_SHIFT 21
+#define ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_MASK (0xf<<17)
+#define ZY7_SLCR_PSS_IDCODE_SUB_FAMILY_SHIFT 17
+#define ZY7_SLCR_PSS_IDCODE_DEVICE_MASK (0x1f<<12)
+#define ZY7_SLCR_PSS_IDCODE_DEVICE_SHIFT 12
+#define ZY7_SLCR_PSS_IDCODE_MNFR_ID_MASK (0x7ff<<1)
+#define ZY7_SLCR_PSS_IDCODE_MNFR_ID_SHIFT 1
+
+#define ZY7_SLCR_DDR_URGENT 0x0600
+#define ZY7_SLCR_DDR_CAL_START 0x060c
+#define ZY7_SLCR_DDR_REF_START 0x0614
+#define ZY7_SLCR_DDR_CMD_STA 0x0618
+#define ZY7_SLCR_DDR_URGENT_SEL 0x061c
+#define ZY7_SLCR_DDR_DFI_STATUS 0x0620
+
+/* MIO Pin controls */
+#define ZY7_SLCR_MIO_PIN(n) (0x0700+(n)*4) /* 0-53 */
+#define ZY7_SLCR_MIO_PIN_RCVR_DIS (1<<13)
+#define ZY7_SLCR_MIO_PIN_PULLUP_EN (1<<12)
+#define ZY7_SLCR_MIO_PIN_IO_TYPE_MASK (7<<9)
+#define ZY7_SLCR_MIO_PIN_IO_TYPE_LVTTL (0<<9)
+#define ZY7_SLCR_MIO_PIN_IO_TYPE_LVCMOS18 (1<<9)
+#define ZY7_SLCR_MIO_PIN_IO_TYPE_LVCMOS25 (2<<9)
+#define ZY7_SLCR_MIO_PIN_IO_TYPE_LVCMOS33 (3<<9)
+#define ZY7_SLCR_MIO_PIN_IO_TYPE_HSTL (4<<9)
+#define ZY7_SLCR_MIO_PIN_L2_SEL_MASK (3<<3)
+#define ZY7_SLCR_MIO_PIN_L2_SEL_L3_MUX (0<<3)
+#define ZY7_SLCR_MIO_PIN_L2_SEL_SRAM_NOR_CS0 (1<<3)
+#define ZY7_SLCR_MIO_PIN_L2_SEL_NAND_CS (2<<3)
+#define ZY7_SLCR_MIO_PIN_L2_SEL_SDIO0_PC (3<<3)
+#define ZY7_SLCR_MIO_PIN_L1_SEL (1<<2)
+#define ZY7_SLCR_MIO_PIN_L0_SEL (1<<1)
+#define ZY7_SLCR_MIO_PIN_TRI_EN (1<<0)
+
+#define ZY7_SLCR_MIO_LOOPBACK 0x0804
+#define ZY7_SLCR_MIO_LOOPBACK_I2C0_I2C1 (1<<3)
+#define ZY7_SLCR_MIO_LOOPBACK_CAN0_CAN1 (1<<2)
+#define ZY7_SLCR_MIO_LOOPBACK_UA0_UA1 (1<<1)
+#define ZY7_SLCR_MIO_LOOPBACK_SPI0_SPI1 (1<<0)
+#define ZY7_SLCR_MIO_MST_TRI0 0x080c
+#define ZY7_SLCR_MIO_MST_TRI1 0x0810
+#define ZY7_SLCR_SD0_WP_CD_SEL 0x0830
+#define ZY7_SLCR_SD1_WP_CD_SEL 0x0834
+
+/* PS-PL level shifter control. */
+#define ZY7_SLCR_LVL_SHFTR_EN 0x900
+#define ZY7_SLCR_LVL_SHFTR_EN_USER_LVL_IN_EN_0 (1<<3) /* PL to PS */
+#define ZY7_SLCR_LVL_SHFTR_EN_USER_LVL_OUT_EN_0 (1<<2) /* PS to PL */
+#define ZY7_SLCR_LVL_SHFTR_EN_USER_LVL_IN_EN_1 (1<<1) /* PL to PS */
+#define ZY7_SLCR_LVL_SHFTR_EN_USER_LVL_OUT_EN_1 (1<<0) /* PS to PL */
+#define ZY7_SLCR_LVL_SHFTR_EN_ALL 0xf
+
+#define ZY7_SLCR_OCM_CFG 0x0910
+
+#define ZY7_SLCR_GPIOB_CTRL 0x0b00
+#define ZY7_SLCR_GPIOB_CFG_CMOS18 0x0b04
+#define ZY7_SLCR_GPIOB_CFG_CMOS25 0x0b08
+#define ZY7_SLCR_GPIOB_CFG_CMOS33 0x0b0c
+#define ZY7_SLCR_GPIOB_CFG_LVTTL 0x0b10
+#define ZY7_SLCR_GPIOB_CFG_HSTL 0x0b14
+#define ZY7_SLCR_GPIOB_DRVR_BIAS_CTRL 0x0b18
+
+#define ZY7_SLCR_DDRIOB_ADDR0 0x0b40
+#define ZY7_SLCR_DDRIOB_ADDR1 0x0b44
+#define ZY7_SLCR_DDRIOB_DATA0 0x0b48
+#define ZY7_SLCR_DDRIOB_DATA1 0x0b4c
+#define ZY7_SLCR_DDRIOB_DIFF0 0x0b50
+#define ZY7_SLCR_DDRIOB_DIFF1 0x0b54
+#define ZY7_SLCR_DDRIOB_CLK 0x0b58
+#define ZY7_SLCR_DDRIOB_DRIVE_SLEW_ADDR 0x0b5c
+#define ZY7_SLCR_DDRIOB_DRIVE_SLEW_DATA 0x0b60
+#define ZY7_SLCR_DDRIOB_DRIVE_SLEW_DIFF 0x0b64
+#define ZY7_SLCR_DDRIOB_DRIVE_SLEW_CLK 0x0b68
+#define ZY7_SLCR_DDRIOB_DDR_CTRL 0x0b6c
+#define ZY7_SLCR_DDRIOB_DCI_CTRL 0x0b70
+#define ZY7_SLCR_DDRIOB_DCI_STATUS 0x0b74
+
+#ifdef _KERNEL
+extern void zy7_slcr_preload_pl(void);
+extern void zy7_slcr_postload_pl(int);
+#endif
+#endif /* _ZY7_SLCR_H_ */
OpenPOWER on IntegriCloud